Actual source code: segbuffer.c
1: #include <petscsys.h>
3: struct _PetscSegBufferLink {
4: struct _PetscSegBufferLink *tail;
5: PetscCount alloc; /* number of units allocated */
6: PetscCount used;
7: PetscCount tailused;
8: union
9: { /* Dummy types to ensure alignment */
10: PetscReal dummy_real;
11: PetscInt dummy_int;
12: char array[1]; /* This array is over-allocated for the size of the link */
13: } u;
14: };
16: /* Segmented (extendable) array implementation */
17: struct _n_PetscSegBuffer {
18: struct _PetscSegBufferLink *head;
19: size_t unitbytes;
20: };
22: static PetscErrorCode PetscSegBufferAlloc_Private(PetscSegBuffer seg, PetscCount count)
23: {
24: PetscCount alloc;
25: struct _PetscSegBufferLink *newlink, *s;
27: PetscFunctionBegin;
28: s = seg->head;
29: /* Grow at least fast enough to hold next item, like Fibonacci otherwise (up to 1MB chunks) */
30: alloc = PetscMax(s->used + count, PetscMin(1000000 / ((PetscCount)seg->unitbytes) + 1, s->alloc + s->tailused));
31: PetscCall(PetscMalloc(offsetof(struct _PetscSegBufferLink, u) + alloc * seg->unitbytes, &newlink));
32: PetscCall(PetscMemzero(newlink, offsetof(struct _PetscSegBufferLink, u)));
34: newlink->tailused = s->used + s->tailused;
35: newlink->tail = s;
36: newlink->alloc = alloc;
37: seg->head = newlink;
38: PetscFunctionReturn(PETSC_SUCCESS);
39: }
41: /*@C
42: PetscSegBufferCreate - create a segmented buffer
44: Not Collective, No Fortran Support
46: Input Parameters:
47: + unitbytes - number of bytes that each entry will contain
48: - expected - expected/typical number of entries
50: Output Parameter:
51: . seg - `PetscSegBuffer` object
53: Level: developer
55: .seealso: `PetscSegBufferGet()`, `PetscSegBufferExtractAlloc()`, `PetscSegBufferExtractTo()`, `PetscSegBufferExtractInPlace()`, `PetscSegBufferDestroy()`,
56: `PetscSegBuffer`
57: @*/
58: PetscErrorCode PetscSegBufferCreate(size_t unitbytes, PetscCount expected, PetscSegBuffer *seg)
59: {
60: struct _PetscSegBufferLink *head;
62: PetscFunctionBegin;
63: PetscCall(PetscNew(seg));
64: PetscCall(PetscMalloc(offsetof(struct _PetscSegBufferLink, u) + expected * unitbytes, &head));
65: PetscCall(PetscMemzero(head, offsetof(struct _PetscSegBufferLink, u)));
67: head->alloc = expected;
68: (*seg)->unitbytes = unitbytes;
69: (*seg)->head = head;
70: PetscFunctionReturn(PETSC_SUCCESS);
71: }
73: /*@C
74: PetscSegBufferGet - get new buffer space from a segmented buffer
76: Not Collective, No Fortran Support
78: Input Parameters:
79: + seg - `PetscSegBuffer` buffer
80: - count - number of entries needed
82: Output Parameter:
83: . buf - address of new buffer for contiguous data
85: Level: developer
87: .seealso: `PetscSegBufferCreate()`, `PetscSegBufferExtractAlloc()`, `PetscSegBufferExtractTo()`, `PetscSegBufferExtractInPlace()`, `PetscSegBufferDestroy()`,
88: `PetscSegBuffer`, `PetscSegBufferGetInts()`
89: @*/
90: PetscErrorCode PetscSegBufferGet(PetscSegBuffer seg, PetscCount count, void *buf)
91: {
92: struct _PetscSegBufferLink *s;
94: PetscFunctionBegin;
95: s = seg->head;
96: if (PetscUnlikely(s->used + count > s->alloc)) PetscCall(PetscSegBufferAlloc_Private(seg, count));
97: s = seg->head;
98: *(char **)buf = &s->u.array[s->used * seg->unitbytes];
99: s->used += count;
100: PetscFunctionReturn(PETSC_SUCCESS);
101: }
103: /*@C
104: PetscSegBufferDestroy - destroy segmented buffer
106: Not Collective, No Fortran Support
108: Input Parameter:
109: . seg - address of segmented buffer object
111: Level: developer
113: .seealso: `PetscSegBuffer`, `PetscSegBufferCreate()`
114: @*/
115: PetscErrorCode PetscSegBufferDestroy(PetscSegBuffer *seg)
116: {
117: struct _PetscSegBufferLink *s;
119: PetscFunctionBegin;
120: if (!*seg) PetscFunctionReturn(PETSC_SUCCESS);
121: for (s = (*seg)->head; s;) {
122: struct _PetscSegBufferLink *tail = s->tail;
123: PetscCall(PetscFree(s));
124: s = tail;
125: }
126: PetscCall(PetscFree(*seg));
127: PetscFunctionReturn(PETSC_SUCCESS);
128: }
130: /*@C
131: PetscSegBufferExtractTo - extract contiguous data to provided buffer and reset segmented buffer
133: Not Collective, No Fortran Support
135: Input Parameters:
136: + seg - segmented buffer
137: - contig - allocated buffer to hold contiguous data
139: Level: developer
141: .seealso: `PetscSegBufferCreate()`, `PetscSegBufferGet()`, `PetscSegBufferDestroy()`, `PetscSegBufferExtractAlloc()`, `PetscSegBufferExtractInPlace()`,
142: `PetscSegBuffer`
143: @*/
144: PetscErrorCode PetscSegBufferExtractTo(PetscSegBuffer seg, void *contig)
145: {
146: size_t unitbytes;
147: struct _PetscSegBufferLink *s, *t;
148: char *ptr;
150: PetscFunctionBegin;
151: unitbytes = seg->unitbytes;
152: s = seg->head;
153: ptr = PetscSafePointerPlusOffset((char *)contig, s->tailused * unitbytes);
154: PetscCall(PetscMemcpy(ptr, s->u.array, s->used * unitbytes));
155: for (t = s->tail; t;) {
156: struct _PetscSegBufferLink *tail = t->tail;
157: ptr -= t->used * unitbytes;
158: PetscCall(PetscMemcpy(ptr, t->u.array, t->used * unitbytes));
159: PetscCall(PetscFree(t));
160: t = tail;
161: }
162: PetscCheck(ptr == contig, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Tail count does not match");
163: s->used = 0;
164: s->tailused = 0;
165: s->tail = NULL;
166: PetscFunctionReturn(PETSC_SUCCESS);
167: }
169: /*@C
170: PetscSegBufferExtractAlloc - extract contiguous data to new allocation and reset segmented buffer
172: Not Collective, No Fortran Support
174: Input Parameter:
175: . seg - `PetscSegBuffer` buffer
177: Output Parameter:
178: . contiguous - address of new array containing contiguous data, caller frees with `PetscFree()`
180: Level: developer
182: Developer Notes:
183: 'seg' argument is a pointer so that implementation could reallocate, though this is not currently done
185: .seealso: `PetscSegBufferCreate()`, `PetscSegBufferGet()`, `PetscSegBufferDestroy()`, `PetscSegBufferExtractTo()`, `PetscSegBufferExtractInPlace()`,
186: `PetscSegBuffer`
187: @*/
188: PetscErrorCode PetscSegBufferExtractAlloc(PetscSegBuffer seg, void *contiguous)
189: {
190: struct _PetscSegBufferLink *s;
191: void *contig;
193: PetscFunctionBegin;
194: s = seg->head;
196: PetscCall(PetscMalloc((s->used + s->tailused) * seg->unitbytes, &contig));
197: PetscCall(PetscSegBufferExtractTo(seg, contig));
198: *(void **)contiguous = contig;
199: PetscFunctionReturn(PETSC_SUCCESS);
200: }
202: /*@C
203: PetscSegBufferExtractInPlace - extract in-place contiguous representation of data and reset segmented buffer for reuse
205: Not Collective, No Fortran Support
207: Input Parameter:
208: . seg - `PetscSegBuffer` object
210: Output Parameter:
211: . contig - address of pointer to contiguous memory, may be `NULL`
213: Level: developer
215: .seealso: `PetscSegBuffer`, `PetscSegBufferExtractAlloc()`, `PetscSegBufferExtractTo()`
216: @*/
217: PetscErrorCode PetscSegBufferExtractInPlace(PetscSegBuffer seg, void *contig)
218: {
219: struct _PetscSegBufferLink *head;
221: PetscFunctionBegin;
222: head = seg->head;
223: if (PetscUnlikely(head->tail)) {
224: PetscSegBuffer newseg;
226: PetscCall(PetscSegBufferCreate(seg->unitbytes, head->used + head->tailused, &newseg));
227: PetscCall(PetscSegBufferExtractTo(seg, newseg->head->u.array));
228: seg->head = newseg->head;
229: newseg->head = head;
230: PetscCall(PetscSegBufferDestroy(&newseg));
231: head = seg->head;
232: }
233: if (contig) *(char **)contig = head->u.array;
234: head->used = 0;
235: PetscFunctionReturn(PETSC_SUCCESS);
236: }
238: /*@C
239: PetscSegBufferGetSize - get currently used number of entries of a `PetscSegBuffer`
241: Not Collective, No Fortran Support
243: Input Parameter:
244: . seg - `PetscSegBuffer` object
246: Output Parameter:
247: . usedsize - number of used units
249: Level: developer
251: .seealso: `PetscSegBuffer`, `PetscSegBufferExtractAlloc()`, `PetscSegBufferExtractTo()`, `PetscSegBufferCreate()`, `PetscSegBufferGet()`
252: @*/
253: PetscErrorCode PetscSegBufferGetSize(PetscSegBuffer seg, PetscCount *usedsize)
254: {
255: PetscFunctionBegin;
256: *usedsize = seg->head->tailused + seg->head->used;
257: PetscFunctionReturn(PETSC_SUCCESS);
258: }
260: /*@C
261: PetscSegBufferUnuse - return some unused entries obtained with an overzealous `PetscSegBufferGet()`
263: Not Collective, No Fortran Support
265: Input Parameters:
266: + seg - `PetscSegBuffer` object
267: - unused - number of unused units to return
269: Level: developer
271: .seealso: `PetscSegBuffer`, `PetscSegBufferCreate()`, `PetscSegBufferGet()`
272: @*/
273: PetscErrorCode PetscSegBufferUnuse(PetscSegBuffer seg, PetscCount unused)
274: {
275: struct _PetscSegBufferLink *head;
277: PetscFunctionBegin;
278: head = seg->head;
279: PetscCheck(head->used >= unused, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Attempt to return more unused entries (%zu) than previously gotten (%zu)", unused, head->used);
280: head->used -= unused;
281: PetscFunctionReturn(PETSC_SUCCESS);
282: }