Actual source code: segbuffer.c

petsc-3.12.5 2020-03-29
Report Typos and Errors
  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: };

 21: static PetscErrorCode PetscSegBufferAlloc_Private(PetscSegBuffer seg,size_t count)
 22: {
 23:   PetscErrorCode     ierr;
 24:   size_t             alloc;
 25:   struct _PetscSegBufferLink *newlink,*s;

 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/seg->unitbytes+1,s->alloc+s->tailused));
 31:   PetscMalloc(offsetof(struct _PetscSegBufferLink,u)+alloc*seg->unitbytes,&newlink);
 32:   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:   return(0);
 39: }

 41: /*@C
 42:    PetscSegBufferCreate - create segmented buffer

 44:    Not Collective

 46:    Input Arguments:
 47: +  unitbytes - number of bytes that each entry will contain
 48: -  expected - expected/typical number of entries

 50:    Output Argument:
 51: .  seg - segmented buffer object

 53:    Level: developer

 55: .seealso: PetscSegBufferGet(), PetscSegBufferExtractAlloc(), PetscSegBufferExtractTo(), PetscSegBufferExtractInPlace(), PetscSegBufferDestroy()
 56: @*/
 57: PetscErrorCode PetscSegBufferCreate(size_t unitbytes,size_t expected,PetscSegBuffer *seg)
 58: {
 60:   struct _PetscSegBufferLink *head;

 63:   PetscNew(seg);
 64:   PetscMalloc(offsetof(struct _PetscSegBufferLink,u)+expected*unitbytes,&head);
 65:   PetscMemzero(head,offsetof(struct _PetscSegBufferLink,u));

 67:   head->alloc       = expected;
 68:   (*seg)->unitbytes = unitbytes;
 69:   (*seg)->head      = head;
 70:   return(0);
 71: }

 73: /*@C
 74:    PetscSegBufferGet - get new buffer space from a segmented buffer

 76:    Not Collective

 78:    Input Arguments:
 79: +  seg - address of segmented buffer
 80: -  count - number of entries needed

 82:    Output Argument:
 83: .  buf - address of new buffer for contiguous data

 85:    Level: developer

 87: .seealso: PetscSegBufferCreate(), PetscSegBufferExtractAlloc(), PetscSegBufferExtractTo(), PetscSegBufferExtractInPlace(), PetscSegBufferDestroy()
 88: @*/
 89: PetscErrorCode PetscSegBufferGet(PetscSegBuffer seg,size_t count,void *buf)
 90: {
 92:   struct _PetscSegBufferLink *s;

 95:   s = seg->head;
 96:   if (PetscUnlikely(s->used + count > s->alloc)) {PetscSegBufferAlloc_Private(seg,count);}
 97:   s = seg->head;
 98:   *(char**)buf = &s->u.array[s->used*seg->unitbytes];
 99:   s->used += count;
100:   return(0);
101: }

103: /*@C
104:    PetscSegBufferDestroy - destroy segmented buffer

106:    Not Collective

108:    Input Arguments:
109: .  seg - address of segmented buffer object

111:    Level: developer

113: .seealso: PetscSegBufferCreate()
114: @*/
115: PetscErrorCode PetscSegBufferDestroy(PetscSegBuffer *seg)
116: {
117:   PetscErrorCode             ierr;
118:   struct _PetscSegBufferLink *s;

121:   if (!*seg) return(0);
122:   for (s=(*seg)->head; s;) {
123:     struct _PetscSegBufferLink *tail = s->tail;
124:     PetscFree(s);
125:     s = tail;
126:   }
127:   PetscFree(*seg);
128:   return(0);
129: }

131: /*@C
132:    PetscSegBufferExtractTo - extract contiguous data to provided buffer and reset segmented buffer

134:    Not Collective

136:    Input Argument:
137: +  seg - segmented buffer
138: -  contig - allocated buffer to hold contiguous data

140:    Level: developer

142: .seealso: PetscSegBufferCreate(), PetscSegBufferGet(), PetscSegBufferDestroy(), PetscSegBufferExtractAlloc(), PetscSegBufferExtractInPlace()
143: @*/
144: PetscErrorCode PetscSegBufferExtractTo(PetscSegBuffer seg,void *contig)
145: {
146:   PetscErrorCode             ierr;
147:   size_t                     unitbytes;
148:   struct _PetscSegBufferLink *s,*t;
149:   char                       *ptr;

152:   unitbytes = seg->unitbytes;
153:   s = seg->head;
154:   ptr  = ((char*)contig) + s->tailused*unitbytes;
155:   PetscMemcpy(ptr,s->u.array,s->used*unitbytes);
156:   for (t=s->tail; t;) {
157:     struct _PetscSegBufferLink *tail = t->tail;
158:     ptr -= t->used*unitbytes;
159:     PetscMemcpy(ptr,t->u.array,t->used*unitbytes);
160:     PetscFree(t);
161:     t    = tail;
162:   }
163:   if (ptr != contig) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Tail count does not match");
164:   s->used             = 0;
165:   s->tailused         = 0;
166:   s->tail             = NULL;
167:   return(0);
168: }

170: /*@C
171:    PetscSegBufferExtractAlloc - extract contiguous data to new allocation and reset segmented buffer

173:    Not Collective

175:    Input Argument:
176: .  seg - segmented buffer

178:    Output Argument:
179: .  contiguous - address of new array containing contiguous data, caller frees with PetscFree()

181:    Level: developer

183:    Developer Notes: 'seg' argument is a pointer so that implementation could reallocate, though this is not currently done

185: .seealso: PetscSegBufferCreate(), PetscSegBufferGet(), PetscSegBufferDestroy(), PetscSegBufferExtractTo(), PetscSegBufferExtractInPlace()
186: @*/
187: PetscErrorCode PetscSegBufferExtractAlloc(PetscSegBuffer seg,void *contiguous)
188: {
189:   PetscErrorCode             ierr;
190:   struct _PetscSegBufferLink *s;
191:   void                       *contig;

194:   s = seg->head;

196:   PetscMalloc((s->used+s->tailused)*seg->unitbytes,&contig);
197:   PetscSegBufferExtractTo(seg,contig);
198:   *(void**)contiguous = contig;
199:   return(0);
200: }

202: /*@C
203:    PetscSegBufferExtractInPlace - extract in-place contiguous representation of data and reset segmented buffer for reuse

205:    Not Collective

207:    Input Arguments:
208: .  seg - segmented buffer object

210:    Output Arguments:
211: .  contig - address of pointer to contiguous memory

213:    Level: developer

215: .seealso: PetscSegBufferExtractAlloc(), PetscSegBufferExtractTo()
216: @*/
217: PetscErrorCode PetscSegBufferExtractInPlace(PetscSegBuffer seg,void *contig)
218: {
220:   struct _PetscSegBufferLink *head;

223:   head = seg->head;
224:   if (PetscUnlikely(head->tail)) {
225:     PetscSegBuffer newseg;

227:     PetscSegBufferCreate(seg->unitbytes,head->used+head->tailused,&newseg);
228:     PetscSegBufferExtractTo(seg,newseg->head->u.array);
229:     seg->head = newseg->head;
230:     newseg->head = head;
231:     PetscSegBufferDestroy(&newseg);
232:     head = seg->head;
233:   }
234:   *(char**)contig = head->u.array;
235:   head->used = 0;
236:   return(0);
237: }

239: /*@C
240:    PetscSegBufferGetSize - get currently used size of segmented buffer

242:    Not Collective

244:    Input Arguments:
245: .  seg - segmented buffer object

247:    Output Arguments:
248: .  usedsize - number of used units

250:    Level: developer

252: .seealso: PetscSegBufferExtractAlloc(), PetscSegBufferExtractTo(), PetscSegBufferCreate(), PetscSegBufferGet()
253: @*/
254: PetscErrorCode PetscSegBufferGetSize(PetscSegBuffer seg,size_t *usedsize)
255: {

258:   *usedsize = seg->head->tailused + seg->head->used;
259:   return(0);
260: }

262: /*@C
263:    PetscSegBufferUnuse - return some unused entries obtained with an overzealous PetscSegBufferGet()

265:    Not Collective

267:    Input Arguments:
268: +  seg - segmented buffer object
269: -  unused - number of unused units

271:    Level: developer

273: .seealso: PetscSegBufferCreate(), PetscSegBufferGet()
274: @*/
275: PetscErrorCode PetscSegBufferUnuse(PetscSegBuffer seg,size_t unused)
276: {
277:   struct _PetscSegBufferLink *head;

280:   head = seg->head;
281:   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);
282:   head->used -= unused;
283:   return(0);
284: }