Notcurses 3.0.16
a blingful library for TUIs and character graphics
Loading...
Searching...
No Matches
egcpool.c
Go to the documentation of this file.
1#include <lib/egcpool.h>
2
3// if we're inserting a EGC of |len| bytes, ought we proactively realloc?
4__attribute__ ((nonnull (1))) static inline bool
5egcpool_alloc_justified(const egcpool* pool, int len){
6 const int poolfree = pool->poolsize - pool->poolused;
7 // proactively get more space if we have less than 10% free. this doesn't
8 // guarantee that we'll have enough space to insert the string -- we could
9 // theoretically have every 10th byte free, and be unable to write even a
10 // two-byte egc -- so we might have to allocate after an expensive search :/.
11 if(poolfree >= len && poolfree * 10 > pool->poolsize){
12 return false;
13 }
14 return true;
15}
16
17__attribute__ ((nonnull (1, 2))) static inline int
18stash(egcpool* pool, const char* egc, int curpos, int len){
19 memcpy(pool->pool + curpos, egc, len - 1);
20 pool->pool[curpos + len - 1] = '\0';
21 pool->poolwrite = curpos + len;
22 pool->poolused += len;
23//fprintf(stderr, "Stashing AT %d\n", curpos);
24 return curpos;
25}
26
27__attribute__ ((nonnull (1, 2))) int
28egcpool_stash(egcpool* pool, const char* egc, size_t ulen){
29 int len = ulen + 1; // count the NUL terminator
30 if(len <= 2){ // should never be empty, nor a single byte + NUL
31 return -1;
32 }
33 // the first time through, we don't force a grow unless we expect ourselves
34 // to have too little space. once we've done a search, we do force the grow.
35 // we should thus never have more than two iterations of this loop.
36 bool searched = false;
37 // we might have to realloc our underlying pool. it is possible that this EGC
38 // is actually *in* that pool, in which case our pointer will be invalidated.
39 // to be safe, duplicate prior to a realloc, and free along all paths.
40 char* duplicated = NULL;
41 do{
42 if(egcpool_alloc_justified(pool, len) || searched){
43 if(!duplicated){
44 // cast (and avoidance of strndup) to facilitate c++ inclusions
45 if((duplicated = (char *)malloc(ulen + 1)) == NULL){
46 return -1;
47 }
48 memcpy(duplicated, egc, ulen);
49 duplicated[ulen] = '\0';
50 }
51 if(egcpool_grow(pool, len) && searched){
52 free(duplicated);
53 return -1;
54 }
55 egc = duplicated;
56 }
57 // we now look for a place to lay out this egc. we need |len| zeroes in a
58 // row. starting at pool->poolwrite, look for such a range of unused
59 // memory. if we find it, write it out, and update used count. if we come
60 // back to where we started, force a growth and try again.
61 int curpos = pool->poolwrite;
62//fprintf(stderr, "Stashing [%s] %d starting at %d\n", egc, len, curpos);
63 do{
64 if(curpos == pool->poolsize){
65 curpos = 0;
66 }
67 if(pool->pool[curpos]){ // can't write if there's stuff here
68 ++curpos;
69 }else if(curpos && pool->pool[curpos - 1]){ // don't kill someone's NUL
70 ++curpos;
71 }else if(pool->poolsize - curpos < len){ // can't wrap around
72 if(pool->poolwrite > curpos){
73 break;
74 }
75 curpos = 0; // can this skip pool->poolwrite?
76 }else{ // promising! let's see if there's enough space
77 int need = len;
78 size_t trial = curpos;
79 while(--need){
80 if(pool->pool[++trial]){ // alas, not enough space here
81 break;
82 }
83 }
84 if(need == 0){ // found a suitable space, copy it!
85 stash(pool, egc, curpos, len);
86 free(duplicated);
87 return curpos;
88 }
89 if(pool->poolwrite > curpos && pool->poolwrite - (len - need) < curpos){
90 break;
91 }
92 curpos += len - need;
93 }
94 }while(curpos != pool->poolwrite);
95 }while( (searched = !searched) );
96 free(duplicated);
97 logerror("error finding egcpool writepos (%zu)", ulen);
98 return -1; // should never get here
99}
__attribute__((nonnull(1)))
Definition egcpool.c:4
const char * egc
Definition egcpool.h:162
const char size_t ulen
Definition egcpool.h:162
#define logerror(fmt,...)
Definition logging.h:32
API int API int const nccell unsigned len
Definition notcurses.h:2592
return NULL
Definition termdesc.h:229