10f453b92SJed Brown #include <petscsys.h> 20f453b92SJed Brown 3137cf7b6SJed Brown struct _PetscSegBufferLink { 4137cf7b6SJed Brown struct _PetscSegBufferLink *tail; 513e3f751SJed Brown size_t alloc; 613e3f751SJed Brown size_t used; 713e3f751SJed Brown size_t tailused; 8*9371c9d4SSatish Balay union 9*9371c9d4SSatish Balay { /* Dummy types to ensure alignment */ 100f453b92SJed Brown PetscReal dummy_real; 110f453b92SJed Brown PetscInt dummy_int; 12137cf7b6SJed Brown char array[1]; /* This array is over-allocated for the size of the link */ 130f453b92SJed Brown } u; 140f453b92SJed Brown }; 150f453b92SJed Brown 16137cf7b6SJed Brown /* Segmented (extendable) array implementation */ 17137cf7b6SJed Brown struct _n_PetscSegBuffer { 18137cf7b6SJed Brown struct _PetscSegBufferLink *head; 1913e3f751SJed Brown size_t unitbytes; 20137cf7b6SJed Brown }; 21137cf7b6SJed Brown 22*9371c9d4SSatish Balay static PetscErrorCode PetscSegBufferAlloc_Private(PetscSegBuffer seg, size_t count) { 2313e3f751SJed Brown size_t alloc; 24137cf7b6SJed Brown struct _PetscSegBufferLink *newlink, *s; 250f453b92SJed Brown 260f453b92SJed Brown PetscFunctionBegin; 27137cf7b6SJed Brown s = seg->head; 280f453b92SJed Brown /* Grow at least fast enough to hold next item, like Fibonacci otherwise (up to 1MB chunks) */ 29137cf7b6SJed Brown alloc = PetscMax(s->used + count, PetscMin(1000000 / seg->unitbytes + 1, s->alloc + s->tailused)); 309566063dSJacob Faibussowitsch PetscCall(PetscMalloc(offsetof(struct _PetscSegBufferLink, u) + alloc * seg->unitbytes, &newlink)); 319566063dSJacob Faibussowitsch PetscCall(PetscMemzero(newlink, offsetof(struct _PetscSegBufferLink, u))); 320f453b92SJed Brown 33137cf7b6SJed Brown newlink->tailused = s->used + s->tailused; 34137cf7b6SJed Brown newlink->tail = s; 35137cf7b6SJed Brown newlink->alloc = alloc; 36137cf7b6SJed Brown seg->head = newlink; 370f453b92SJed Brown PetscFunctionReturn(0); 380f453b92SJed Brown } 390f453b92SJed Brown 400f453b92SJed Brown /*@C 410f453b92SJed Brown PetscSegBufferCreate - create segmented buffer 420f453b92SJed Brown 430f453b92SJed Brown Not Collective 440f453b92SJed Brown 454165533cSJose E. Roman Input Parameters: 460f453b92SJed Brown + unitbytes - number of bytes that each entry will contain 470f453b92SJed Brown - expected - expected/typical number of entries 480f453b92SJed Brown 494165533cSJose E. Roman Output Parameter: 500f453b92SJed Brown . seg - segmented buffer object 510f453b92SJed Brown 520f453b92SJed Brown Level: developer 530f453b92SJed Brown 54db781477SPatrick Sanan .seealso: `PetscSegBufferGet()`, `PetscSegBufferExtractAlloc()`, `PetscSegBufferExtractTo()`, `PetscSegBufferExtractInPlace()`, `PetscSegBufferDestroy()` 550f453b92SJed Brown @*/ 56*9371c9d4SSatish Balay PetscErrorCode PetscSegBufferCreate(size_t unitbytes, size_t expected, PetscSegBuffer *seg) { 57137cf7b6SJed Brown struct _PetscSegBufferLink *head; 580f453b92SJed Brown 590f453b92SJed Brown PetscFunctionBegin; 609566063dSJacob Faibussowitsch PetscCall(PetscNew(seg)); 619566063dSJacob Faibussowitsch PetscCall(PetscMalloc(offsetof(struct _PetscSegBufferLink, u) + expected * unitbytes, &head)); 629566063dSJacob Faibussowitsch PetscCall(PetscMemzero(head, offsetof(struct _PetscSegBufferLink, u))); 630f453b92SJed Brown 64137cf7b6SJed Brown head->alloc = expected; 650f453b92SJed Brown (*seg)->unitbytes = unitbytes; 66137cf7b6SJed Brown (*seg)->head = head; 670f453b92SJed Brown PetscFunctionReturn(0); 680f453b92SJed Brown } 690f453b92SJed Brown 700f453b92SJed Brown /*@C 710f453b92SJed Brown PetscSegBufferGet - get new buffer space from a segmented buffer 720f453b92SJed Brown 730f453b92SJed Brown Not Collective 740f453b92SJed Brown 754165533cSJose E. Roman Input Parameters: 760f453b92SJed Brown + seg - address of segmented buffer 770f453b92SJed Brown - count - number of entries needed 780f453b92SJed Brown 794165533cSJose E. Roman Output Parameter: 800f453b92SJed Brown . buf - address of new buffer for contiguous data 810f453b92SJed Brown 820f453b92SJed Brown Level: developer 830f453b92SJed Brown 84db781477SPatrick Sanan .seealso: `PetscSegBufferCreate()`, `PetscSegBufferExtractAlloc()`, `PetscSegBufferExtractTo()`, `PetscSegBufferExtractInPlace()`, `PetscSegBufferDestroy()` 850f453b92SJed Brown @*/ 86*9371c9d4SSatish Balay PetscErrorCode PetscSegBufferGet(PetscSegBuffer seg, size_t count, void *buf) { 87137cf7b6SJed Brown struct _PetscSegBufferLink *s; 880f453b92SJed Brown 890f453b92SJed Brown PetscFunctionBegin; 90137cf7b6SJed Brown s = seg->head; 919566063dSJacob Faibussowitsch if (PetscUnlikely(s->used + count > s->alloc)) PetscCall(PetscSegBufferAlloc_Private(seg, count)); 92137cf7b6SJed Brown s = seg->head; 93137cf7b6SJed Brown *(char **)buf = &s->u.array[s->used * seg->unitbytes]; 940f453b92SJed Brown s->used += count; 950f453b92SJed Brown PetscFunctionReturn(0); 960f453b92SJed Brown } 970f453b92SJed Brown 980f453b92SJed Brown /*@C 990f453b92SJed Brown PetscSegBufferDestroy - destroy segmented buffer 1000f453b92SJed Brown 1010f453b92SJed Brown Not Collective 1020f453b92SJed Brown 1034165533cSJose E. Roman Input Parameter: 1040f453b92SJed Brown . seg - address of segmented buffer object 1050f453b92SJed Brown 1060f453b92SJed Brown Level: developer 1070f453b92SJed Brown 108db781477SPatrick Sanan .seealso: `PetscSegBufferCreate()` 1090f453b92SJed Brown @*/ 110*9371c9d4SSatish Balay PetscErrorCode PetscSegBufferDestroy(PetscSegBuffer *seg) { 111137cf7b6SJed Brown struct _PetscSegBufferLink *s; 1120f453b92SJed Brown 1130f453b92SJed Brown PetscFunctionBegin; 1145d7c30b2SJed Brown if (!*seg) PetscFunctionReturn(0); 115137cf7b6SJed Brown for (s = (*seg)->head; s;) { 116137cf7b6SJed Brown struct _PetscSegBufferLink *tail = s->tail; 1179566063dSJacob Faibussowitsch PetscCall(PetscFree(s)); 1180f453b92SJed Brown s = tail; 1190f453b92SJed Brown } 1209566063dSJacob Faibussowitsch PetscCall(PetscFree(*seg)); 1210f453b92SJed Brown PetscFunctionReturn(0); 1220f453b92SJed Brown } 1230f453b92SJed Brown 1240f453b92SJed Brown /*@C 12547452e7bSJed Brown PetscSegBufferExtractTo - extract contiguous data to provided buffer and reset segmented buffer 12647452e7bSJed Brown 12747452e7bSJed Brown Not Collective 12847452e7bSJed Brown 1294165533cSJose E. Roman Input Parameters: 13047452e7bSJed Brown + seg - segmented buffer 13147452e7bSJed Brown - contig - allocated buffer to hold contiguous data 13247452e7bSJed Brown 13347452e7bSJed Brown Level: developer 13447452e7bSJed Brown 135db781477SPatrick Sanan .seealso: `PetscSegBufferCreate()`, `PetscSegBufferGet()`, `PetscSegBufferDestroy()`, `PetscSegBufferExtractAlloc()`, `PetscSegBufferExtractInPlace()` 13647452e7bSJed Brown @*/ 137*9371c9d4SSatish Balay PetscErrorCode PetscSegBufferExtractTo(PetscSegBuffer seg, void *contig) { 13813e3f751SJed Brown size_t unitbytes; 139137cf7b6SJed Brown struct _PetscSegBufferLink *s, *t; 14047452e7bSJed Brown char *ptr; 14147452e7bSJed Brown 14247452e7bSJed Brown PetscFunctionBegin; 143137cf7b6SJed Brown unitbytes = seg->unitbytes; 144137cf7b6SJed Brown s = seg->head; 14547452e7bSJed Brown ptr = ((char *)contig) + s->tailused * unitbytes; 1469566063dSJacob Faibussowitsch PetscCall(PetscMemcpy(ptr, s->u.array, s->used * unitbytes)); 14747452e7bSJed Brown for (t = s->tail; t;) { 148137cf7b6SJed Brown struct _PetscSegBufferLink *tail = t->tail; 14947452e7bSJed Brown ptr -= t->used * unitbytes; 1509566063dSJacob Faibussowitsch PetscCall(PetscMemcpy(ptr, t->u.array, t->used * unitbytes)); 1519566063dSJacob Faibussowitsch PetscCall(PetscFree(t)); 15247452e7bSJed Brown t = tail; 15347452e7bSJed Brown } 15408401ef6SPierre Jolivet PetscCheck(ptr == contig, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Tail count does not match"); 15547452e7bSJed Brown s->used = 0; 15647452e7bSJed Brown s->tailused = 0; 15747452e7bSJed Brown s->tail = NULL; 15847452e7bSJed Brown PetscFunctionReturn(0); 15947452e7bSJed Brown } 16047452e7bSJed Brown 16147452e7bSJed Brown /*@C 16247452e7bSJed Brown PetscSegBufferExtractAlloc - extract contiguous data to new allocation and reset segmented buffer 1630f453b92SJed Brown 1640f453b92SJed Brown Not Collective 1650f453b92SJed Brown 1664165533cSJose E. Roman Input Parameter: 1670f453b92SJed Brown . seg - segmented buffer 1680f453b92SJed Brown 1694165533cSJose E. Roman Output Parameter: 1700f453b92SJed Brown . contiguous - address of new array containing contiguous data, caller frees with PetscFree() 1710f453b92SJed Brown 1720f453b92SJed Brown Level: developer 1730f453b92SJed Brown 17447452e7bSJed Brown Developer Notes: 'seg' argument is a pointer so that implementation could reallocate, though this is not currently done 17547452e7bSJed Brown 176db781477SPatrick Sanan .seealso: `PetscSegBufferCreate()`, `PetscSegBufferGet()`, `PetscSegBufferDestroy()`, `PetscSegBufferExtractTo()`, `PetscSegBufferExtractInPlace()` 1770f453b92SJed Brown @*/ 178*9371c9d4SSatish Balay PetscErrorCode PetscSegBufferExtractAlloc(PetscSegBuffer seg, void *contiguous) { 179137cf7b6SJed Brown struct _PetscSegBufferLink *s; 18047452e7bSJed Brown void *contig; 1810f453b92SJed Brown 1820f453b92SJed Brown PetscFunctionBegin; 183137cf7b6SJed Brown s = seg->head; 1840f453b92SJed Brown 1859566063dSJacob Faibussowitsch PetscCall(PetscMalloc((s->used + s->tailused) * seg->unitbytes, &contig)); 1869566063dSJacob Faibussowitsch PetscCall(PetscSegBufferExtractTo(seg, contig)); 18747452e7bSJed Brown *(void **)contiguous = contig; 18847452e7bSJed Brown PetscFunctionReturn(0); 1890f453b92SJed Brown } 19047452e7bSJed Brown 19147452e7bSJed Brown /*@C 19247452e7bSJed Brown PetscSegBufferExtractInPlace - extract in-place contiguous representation of data and reset segmented buffer for reuse 19347452e7bSJed Brown 19401d09641SJed Brown Not Collective 19547452e7bSJed Brown 1964165533cSJose E. Roman Input Parameter: 19747452e7bSJed Brown . seg - segmented buffer object 19847452e7bSJed Brown 1994165533cSJose E. Roman Output Parameter: 200d2b3fd65SBarry Smith . contig - address of pointer to contiguous memory, may be NULL 20147452e7bSJed Brown 20247452e7bSJed Brown Level: developer 20347452e7bSJed Brown 204db781477SPatrick Sanan .seealso: `PetscSegBufferExtractAlloc()`, `PetscSegBufferExtractTo()` 20547452e7bSJed Brown @*/ 206*9371c9d4SSatish Balay PetscErrorCode PetscSegBufferExtractInPlace(PetscSegBuffer seg, void *contig) { 207137cf7b6SJed Brown struct _PetscSegBufferLink *head; 20847452e7bSJed Brown 20947452e7bSJed Brown PetscFunctionBegin; 210137cf7b6SJed Brown head = seg->head; 211137cf7b6SJed Brown if (PetscUnlikely(head->tail)) { 212137cf7b6SJed Brown PetscSegBuffer newseg; 21347452e7bSJed Brown 2149566063dSJacob Faibussowitsch PetscCall(PetscSegBufferCreate(seg->unitbytes, head->used + head->tailused, &newseg)); 2159566063dSJacob Faibussowitsch PetscCall(PetscSegBufferExtractTo(seg, newseg->head->u.array)); 216137cf7b6SJed Brown seg->head = newseg->head; 217137cf7b6SJed Brown newseg->head = head; 2189566063dSJacob Faibussowitsch PetscCall(PetscSegBufferDestroy(&newseg)); 219137cf7b6SJed Brown head = seg->head; 22047452e7bSJed Brown } 221d2b3fd65SBarry Smith if (contig) *(char **)contig = head->u.array; 222137cf7b6SJed Brown head->used = 0; 2230f453b92SJed Brown PetscFunctionReturn(0); 2240f453b92SJed Brown } 22501d09641SJed Brown 22601d09641SJed Brown /*@C 22701d09641SJed Brown PetscSegBufferGetSize - get currently used size of segmented buffer 22801d09641SJed Brown 22901d09641SJed Brown Not Collective 23001d09641SJed Brown 2314165533cSJose E. Roman Input Parameter: 23201d09641SJed Brown . seg - segmented buffer object 23301d09641SJed Brown 2344165533cSJose E. Roman Output Parameter: 23501d09641SJed Brown . usedsize - number of used units 23601d09641SJed Brown 23701d09641SJed Brown Level: developer 23801d09641SJed Brown 239db781477SPatrick Sanan .seealso: `PetscSegBufferExtractAlloc()`, `PetscSegBufferExtractTo()`, `PetscSegBufferCreate()`, `PetscSegBufferGet()` 24001d09641SJed Brown @*/ 241*9371c9d4SSatish Balay PetscErrorCode PetscSegBufferGetSize(PetscSegBuffer seg, size_t *usedsize) { 24201d09641SJed Brown PetscFunctionBegin; 243137cf7b6SJed Brown *usedsize = seg->head->tailused + seg->head->used; 24401d09641SJed Brown PetscFunctionReturn(0); 24501d09641SJed Brown } 24601d09641SJed Brown 24701d09641SJed Brown /*@C 24801d09641SJed Brown PetscSegBufferUnuse - return some unused entries obtained with an overzealous PetscSegBufferGet() 24901d09641SJed Brown 25001d09641SJed Brown Not Collective 25101d09641SJed Brown 2524165533cSJose E. Roman Input Parameters: 25301d09641SJed Brown + seg - segmented buffer object 25401d09641SJed Brown - unused - number of unused units 25501d09641SJed Brown 25601d09641SJed Brown Level: developer 25701d09641SJed Brown 258db781477SPatrick Sanan .seealso: `PetscSegBufferCreate()`, `PetscSegBufferGet()` 25901d09641SJed Brown @*/ 260*9371c9d4SSatish Balay PetscErrorCode PetscSegBufferUnuse(PetscSegBuffer seg, size_t unused) { 261137cf7b6SJed Brown struct _PetscSegBufferLink *head; 26201d09641SJed Brown 26301d09641SJed Brown PetscFunctionBegin; 264137cf7b6SJed Brown head = seg->head; 26508401ef6SPierre Jolivet 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); 266137cf7b6SJed Brown head->used -= unused; 26701d09641SJed Brown PetscFunctionReturn(0); 26801d09641SJed Brown } 269