damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

emitter.c (7061B)


      1 #include <stdlib.h>
      2 
      3 #include "flatcc_rtconfig.h"
      4 #include "flatcc_emitter.h"
      5 
      6 static int advance_front(flatcc_emitter_t *E)
      7 {
      8     flatcc_emitter_page_t *p = 0;
      9 
     10     if (E->front && E->front->prev != E->back) {
     11         E->front->prev->page_offset = E->front->page_offset - FLATCC_EMITTER_PAGE_SIZE;
     12         E->front = E->front->prev;
     13         goto done;
     14     }
     15     if (!(p = FLATCC_EMITTER_ALLOC(sizeof(flatcc_emitter_page_t)))) {
     16         return -1;
     17     }
     18     E->capacity += FLATCC_EMITTER_PAGE_SIZE;
     19     if (E->front) {
     20         p->prev = E->back;
     21         p->next = E->front;
     22         E->front->prev = p;
     23         E->back->next = p;
     24         E->front = p;
     25         goto done;
     26     }
     27     /*
     28      * The first page is shared between front and back to avoid
     29      * double unecessary extra allocation.
     30      */
     31     E->front = p;
     32     E->back = p;
     33     p->next = p;
     34     p->prev = p;
     35     E->front_cursor = E->front->page + FLATCC_EMITTER_PAGE_SIZE / 2;
     36     E->back_cursor = E->front_cursor;
     37     E->front_left = FLATCC_EMITTER_PAGE_SIZE / 2;
     38     E->back_left = FLATCC_EMITTER_PAGE_SIZE - E->front_left;
     39     p->page_offset = -(flatbuffers_soffset_t)E->front_left;
     40     return 0;
     41 done:
     42     E->front_cursor = E->front->page + FLATCC_EMITTER_PAGE_SIZE;
     43     E->front_left = FLATCC_EMITTER_PAGE_SIZE;
     44     E->front->page_offset = E->front->next->page_offset - FLATCC_EMITTER_PAGE_SIZE;
     45     return 0;
     46 }
     47 
     48 static int advance_back(flatcc_emitter_t *E)
     49 {
     50     flatcc_emitter_page_t *p = 0;
     51 
     52     if (E->back && E->back->next != E->front) {
     53         E->back = E->back->next;
     54         goto done;
     55     }
     56     if (!(p = FLATCC_EMITTER_ALLOC(sizeof(flatcc_emitter_page_t)))) {
     57         return -1;
     58     }
     59     E->capacity += FLATCC_EMITTER_PAGE_SIZE;
     60     if (E->back) {
     61         p->prev = E->back;
     62         p->next = E->front;
     63         E->front->prev = p;
     64         E->back->next = p;
     65         E->back = p;
     66         goto done;
     67     }
     68     /*
     69      * The first page is shared between front and back to avoid
     70      * double unecessary extra allocation.
     71      */
     72     E->front = p;
     73     E->back = p;
     74     p->next = p;
     75     p->prev = p;
     76     E->front_cursor = E->front->page + FLATCC_EMITTER_PAGE_SIZE / 2;
     77     E->back_cursor = E->front_cursor;
     78     E->front_left = FLATCC_EMITTER_PAGE_SIZE / 2;
     79     E->back_left = FLATCC_EMITTER_PAGE_SIZE - E->front_left;
     80     p->page_offset = -(flatbuffers_soffset_t)E->front_left;
     81     return 0;
     82 done:
     83     E->back_cursor = E->back->page;
     84     E->back_left = FLATCC_EMITTER_PAGE_SIZE;
     85     E->back->page_offset = E->back->prev->page_offset + FLATCC_EMITTER_PAGE_SIZE;
     86     return 0;
     87 }
     88 
     89 static int copy_front(flatcc_emitter_t *E, uint8_t *data, size_t size)
     90 {
     91     size_t k;
     92 
     93     data += size;
     94     while (size) {
     95         k = size;
     96         if (k > E->front_left) {
     97             k = E->front_left;
     98             if (k == 0) {
     99                 if (advance_front(E)) {
    100                     return -1;
    101                 }
    102                 continue;
    103             }
    104         }
    105         E->front_cursor -= k;
    106         E->front_left -= k;
    107         data -= k;
    108         size -= k;
    109         memcpy(E->front_cursor, data, k);
    110     };
    111     return 0;
    112 }
    113 
    114 static int copy_back(flatcc_emitter_t *E, uint8_t *data, size_t size)
    115 {
    116     size_t k;
    117 
    118     while (size) {
    119         k = size;
    120         if (k > E->back_left) {
    121             k = E->back_left;
    122             if (k == 0) {
    123                 if (advance_back(E)) {
    124                     return -1;
    125                 }
    126                 continue;
    127             }
    128         }
    129         memcpy(E->back_cursor, data, k);
    130         size -= k;
    131         data += k;
    132         E->back_cursor += k;
    133         E->back_left -= k;
    134     }
    135     return 0;
    136 }
    137 
    138 int flatcc_emitter_recycle_page(flatcc_emitter_t *E, flatcc_emitter_page_t *p)
    139 {
    140     if (p == E->front || p == E->back) {
    141         return -1;
    142     }
    143     p->next->prev = p->prev;
    144     p->prev->next = p->next;
    145     p->prev = E->front->prev;
    146     p->next = E->front;
    147     p->prev->next = p;
    148     p->next->prev = p;
    149     return 0;
    150 }
    151 
    152 void flatcc_emitter_reset(flatcc_emitter_t *E)
    153 {
    154     flatcc_emitter_page_t *p = E->front;
    155 
    156     if (!E->front) {
    157         return;
    158     }
    159     E->back = E->front;
    160     E->front_cursor = E->front->page + FLATCC_EMITTER_PAGE_SIZE / 2;
    161     E->back_cursor = E->front_cursor;
    162     E->front_left = FLATCC_EMITTER_PAGE_SIZE / 2;
    163     E->back_left = FLATCC_EMITTER_PAGE_SIZE - FLATCC_EMITTER_PAGE_SIZE / 2;
    164     E->front->page_offset = -(flatbuffers_soffset_t)E->front_left;
    165     /* Heuristic to reduce peak allocation over time. */
    166     if (E->used_average == 0) {
    167         E->used_average = E->used;
    168     }
    169     E->used_average = E->used_average * 3 / 4 + E->used / 4;
    170     E->used = 0;
    171     while (E->used_average * 2 < E->capacity && E->back->next != E->front) {
    172         /* We deallocate the page after back since it is less likely to be hot in cache. */
    173         p = E->back->next;
    174         E->back->next = p->next;
    175         p->next->prev = E->back;
    176         FLATCC_EMITTER_FREE(p);
    177         E->capacity -= FLATCC_EMITTER_PAGE_SIZE;
    178     }
    179 }
    180 
    181 void flatcc_emitter_clear(flatcc_emitter_t *E)
    182 {
    183     flatcc_emitter_page_t *p = E->front;
    184 
    185     if (!p) {
    186         return;
    187     }
    188     p->prev->next = 0;
    189     while (p->next) {
    190         p = p->next;
    191         FLATCC_EMITTER_FREE(p->prev);
    192     }
    193     FLATCC_EMITTER_FREE(p);
    194     memset(E, 0, sizeof(*E));
    195 }
    196 
    197 int flatcc_emitter(void *emit_context,
    198         const flatcc_iovec_t *iov, int iov_count,
    199         flatbuffers_soffset_t offset, size_t len)
    200 {
    201     flatcc_emitter_t *E = emit_context;
    202     uint8_t *p;
    203 
    204     E->used += len;
    205     if (offset < 0) {
    206         if (len <= E->front_left) {
    207             E->front_cursor -= len;
    208             E->front_left -= len;
    209             p = E->front_cursor;
    210             goto copy;
    211         }
    212         iov += iov_count;
    213         while (iov_count--) {
    214             --iov;
    215             if (copy_front(E, iov->iov_base, iov->iov_len)) {
    216                 return -1;
    217             }
    218         }
    219     } else {
    220         if (len <= E->back_left) {
    221             p = E->back_cursor;
    222             E->back_cursor += len;
    223             E->back_left -= len;
    224             goto copy;
    225         }
    226         while (iov_count--) {
    227             if (copy_back(E, iov->iov_base, iov->iov_len)) {
    228                 return -1;
    229             }
    230             ++iov;
    231         }
    232     }
    233     return 0;
    234 copy:
    235     while (iov_count--) {
    236         memcpy(p, iov->iov_base, iov->iov_len);
    237         p += iov->iov_len;
    238         ++iov;
    239     }
    240     return 0;
    241 }
    242 
    243 void *flatcc_emitter_copy_buffer(flatcc_emitter_t *E, void *buf, size_t size)
    244 {
    245     flatcc_emitter_page_t *p;
    246     size_t len;
    247 
    248     if (size < E->used) {
    249         return 0;
    250     }
    251     if (!E->front) {
    252         return 0;
    253     }
    254     if (E->front == E->back) {
    255         memcpy(buf, E->front_cursor, E->used);
    256         return buf;
    257     }
    258     len = FLATCC_EMITTER_PAGE_SIZE - E->front_left;
    259     memcpy(buf, E->front_cursor, len);
    260     buf = (uint8_t *)buf + len;
    261     p = E->front->next;
    262     while (p != E->back) {
    263         memcpy(buf, p->page, FLATCC_EMITTER_PAGE_SIZE);
    264         buf = (uint8_t *)buf + FLATCC_EMITTER_PAGE_SIZE;
    265         p = p->next;
    266     }
    267     memcpy(buf, p->page, FLATCC_EMITTER_PAGE_SIZE - E->back_left);
    268     return buf;
    269 }