Actual source code: segbuffer.c
petsc-3.4.5 2014-06-29
1: #include <petscsys.h>
3: struct _PetscSegBufferLink {
4: struct _PetscSegBufferLink *tail;
5: size_t alloc;
6: size_t used;
7: size_t tailused;
8: union { /* Dummy types to ensure alignment */
9: PetscReal dummy_real;
10: PetscInt dummy_int;
11: char array[1]; /* This array is over-allocated for the size of the link */
12: } u;
13: };
15: /* Segmented (extendable) array implementation */
16: struct _n_PetscSegBuffer {
17: struct _PetscSegBufferLink *head;
18: size_t unitbytes;
19: };
23: static PetscErrorCode PetscSegBufferAlloc_Private(PetscSegBuffer seg,size_t count)
24: {
25: PetscErrorCode ierr;
26: size_t alloc;
27: struct _PetscSegBufferLink *newlink,*s;
30: s = seg->head;
31: /* Grow at least fast enough to hold next item, like Fibonacci otherwise (up to 1MB chunks) */
32: alloc = PetscMax(s->used+count,PetscMin(1000000/seg->unitbytes+1,s->alloc+s->tailused));
33: PetscMalloc(offsetof(struct _PetscSegBufferLink,u)+alloc*seg->unitbytes,&newlink);
34: PetscMemzero(newlink,offsetof(struct _PetscSegBufferLink,u));
36: newlink->tailused = s->used + s->tailused;
37: newlink->tail = s;
38: newlink->alloc = alloc;
39: seg->head = newlink;
40: return(0);
41: }
45: /*@C
46: PetscSegBufferCreate - create segmented buffer
48: Not Collective
50: Input Arguments:
51: + unitbytes - number of bytes that each entry will contain
52: - expected - expected/typical number of entries
54: Output Argument:
55: . seg - segmented buffer object
57: Level: developer
59: .seealso: PetscSegBufferGet(), PetscSegBufferExtractAlloc(), PetscSegBufferExtractTo(), PetscSegBufferExtractInPlace(), PetscSegBufferDestroy()
60: @*/
61: PetscErrorCode PetscSegBufferCreate(size_t unitbytes,size_t expected,PetscSegBuffer *seg)
62: {
64: struct _PetscSegBufferLink *head;
67: PetscMalloc(sizeof(struct _n_PetscSegBuffer),seg);
68: PetscMalloc(offsetof(struct _PetscSegBufferLink,u)+expected*unitbytes,&head);
69: PetscMemzero(head,offsetof(struct _PetscSegBufferLink,u));
71: head->alloc = expected;
72: (*seg)->unitbytes = unitbytes;
73: (*seg)->head = head;
74: return(0);
75: }
79: /*@C
80: PetscSegBufferGet - get new buffer space from a segmented buffer
82: Not Collective
84: Input Arguments:
85: + seg - address of segmented buffer
86: - count - number of entries needed
88: Output Argument:
89: . buf - address of new buffer for contiguous data
91: Level: developer
93: .seealso: PetscSegBufferCreate(), PetscSegBufferExtractAlloc(), PetscSegBufferExtractTo(), PetscSegBufferExtractInPlace(), PetscSegBufferDestroy()
94: @*/
95: PetscErrorCode PetscSegBufferGet(PetscSegBuffer seg,size_t count,void *buf)
96: {
98: struct _PetscSegBufferLink *s;
101: s = seg->head;
102: if (PetscUnlikely(s->used + count > s->alloc)) {PetscSegBufferAlloc_Private(seg,count);}
103: s = seg->head;
104: *(char**)buf = &s->u.array[s->used*seg->unitbytes];
105: s->used += count;
106: return(0);
107: }
111: /*@C
112: PetscSegBufferDestroy - destroy segmented buffer
114: Not Collective
116: Input Arguments:
117: . seg - address of segmented buffer object
119: Level: developer
121: .seealso: PetscSegBufferCreate()
122: @*/
123: PetscErrorCode PetscSegBufferDestroy(PetscSegBuffer *seg)
124: {
125: PetscErrorCode ierr;
126: struct _PetscSegBufferLink *s;
129: for (s=(*seg)->head; s;) {
130: struct _PetscSegBufferLink *tail = s->tail;
131: PetscFree(s);
132: s = tail;
133: }
134: PetscFree(*seg);
135: return(0);
136: }
140: /*@C
141: PetscSegBufferExtractTo - extract contiguous data to provided buffer and reset segmented buffer
143: Not Collective
145: Input Argument:
146: + seg - segmented buffer
147: - contig - allocated buffer to hold contiguous data
149: Level: developer
151: .seealso: PetscSegBufferCreate(), PetscSegBufferGet(), PetscSegBufferDestroy(), PetscSegBufferExtractAlloc(), PetscSegBufferExtractInPlace()
152: @*/
153: PetscErrorCode PetscSegBufferExtractTo(PetscSegBuffer seg,void *contig)
154: {
155: PetscErrorCode ierr;
156: size_t unitbytes;
157: struct _PetscSegBufferLink *s,*t;
158: char *ptr;
161: unitbytes = seg->unitbytes;
162: s = seg->head;
163: ptr = ((char*)contig) + s->tailused*unitbytes;
164: PetscMemcpy(ptr,s->u.array,s->used*unitbytes);
165: for (t=s->tail; t;) {
166: struct _PetscSegBufferLink *tail = t->tail;
167: ptr -= t->used*unitbytes;
168: PetscMemcpy(ptr,t->u.array,t->used*unitbytes);
169: PetscFree(t);
170: t = tail;
171: }
172: if (ptr != contig) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Tail count does not match");
173: s->used = 0;
174: s->tailused = 0;
175: s->tail = NULL;
176: return(0);
177: }
181: /*@C
182: PetscSegBufferExtractAlloc - extract contiguous data to new allocation and reset segmented buffer
184: Not Collective
186: Input Argument:
187: . seg - segmented buffer
189: Output Argument:
190: . contiguous - address of new array containing contiguous data, caller frees with PetscFree()
192: Level: developer
194: Developer Notes: 'seg' argument is a pointer so that implementation could reallocate, though this is not currently done
196: .seealso: PetscSegBufferCreate(), PetscSegBufferGet(), PetscSegBufferDestroy(), PetscSegBufferExtractTo(), PetscSegBufferExtractInPlace()
197: @*/
198: PetscErrorCode PetscSegBufferExtractAlloc(PetscSegBuffer seg,void *contiguous)
199: {
200: PetscErrorCode ierr;
201: struct _PetscSegBufferLink *s;
202: void *contig;
205: s = seg->head;
207: PetscMalloc((s->used+s->tailused)*seg->unitbytes,&contig);
208: PetscSegBufferExtractTo(seg,contig);
209: *(void**)contiguous = contig;
210: return(0);
211: }
215: /*@C
216: PetscSegBufferExtractInPlace - extract in-place contiguous representation of data and reset segmented buffer for reuse
218: Not Collective
220: Input Arguments:
221: . seg - segmented buffer object
223: Output Arguments:
224: . contig - address of pointer to contiguous memory
226: Level: developer
228: .seealso: PetscSegBufferExtractAlloc(), PetscSegBufferExtractTo()
229: @*/
230: PetscErrorCode PetscSegBufferExtractInPlace(PetscSegBuffer seg,void *contig)
231: {
233: struct _PetscSegBufferLink *head;
236: head = seg->head;
237: if (PetscUnlikely(head->tail)) {
238: PetscSegBuffer newseg;
240: PetscSegBufferCreate(seg->unitbytes,head->used+head->tailused,&newseg);
241: PetscSegBufferExtractTo(seg,newseg->head->u.array);
242: seg->head = newseg->head;
243: newseg->head = head;
244: PetscSegBufferDestroy(&newseg);
245: head = seg->head;
246: }
247: *(char**)contig = head->u.array;
248: head->used = 0;
249: return(0);
250: }
254: /*@C
255: PetscSegBufferGetSize - get currently used size of segmented buffer
257: Not Collective
259: Input Arguments:
260: . seg - segmented buffer object
262: Output Arguments:
263: . usedsize - number of used units
265: Level: developer
267: .seealso: PetscSegBufferExtractAlloc(), PetscSegBufferExtractTo(), PetscSegBufferCreate(), PetscSegBufferGet()
268: @*/
269: PetscErrorCode PetscSegBufferGetSize(PetscSegBuffer seg,size_t *usedsize)
270: {
273: *usedsize = seg->head->tailused + seg->head->used;
274: return(0);
275: }
279: /*@C
280: PetscSegBufferUnuse - return some unused entries obtained with an overzealous PetscSegBufferGet()
282: Not Collective
284: Input Arguments:
285: + seg - segmented buffer object
286: - unused - number of unused units
288: Level: developer
290: .seealso: PetscSegBufferCreate(), PetscSegBufferGet()
291: @*/
292: PetscErrorCode PetscSegBufferUnuse(PetscSegBuffer seg,size_t unused)
293: {
294: struct _PetscSegBufferLink *head;
297: head = seg->head;
298: if (PetscUnlikely(head->used < unused)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Attempt to return more unused entries (%D) than previously gotten (%D)",unused,head->used);
299: head->used -= unused;
300: return(0);
301: }