LCOV - code coverage report
Current view: top level - include/flatcc - flatcc_emitter.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 4 6 66.7 %
Date: 2016-11-30 13:12:14 Functions: 0 0 -
Branches: 3 6 50.0 %

           Branch data     Line data    Source code
       1                 :            : #ifndef FLATCC_EMITTER_H
       2                 :            : #define FLATCC_EMITTER_H
       3                 :            : 
       4                 :            : /*
       5                 :            :  * Default implementation of a flatbuilder emitter.
       6                 :            :  *
       7                 :            :  * This may be used as a starting point for more advanced emitters,
       8                 :            :  * for example writing completed pages to disk or network and
       9                 :            :  * the recycling those pages.
      10                 :            :  */
      11                 :            : 
      12                 :            : #include <stdlib.h>
      13                 :            : #include <string.h>
      14                 :            : 
      15                 :            : #include "flatcc/flatcc_types.h"
      16                 :            : #include "flatcc/flatcc_iov.h"
      17                 :            : 
      18                 :            : /*
      19                 :            :  * The buffer steadily grows during emission but the design allows for
      20                 :            :  * an extension where individual pages can recycled before the buffer
      21                 :            :  * is complete, for example because they have been transmitted.
      22                 :            :  *
      23                 :            :  * When done, the buffer can be cleared to free all memory, or reset to
      24                 :            :  * maintain an adaptive page pool for next buffer construction.
      25                 :            :  *
      26                 :            :  * Unlike an exponentially growing buffer, each buffer page remains
      27                 :            :  * stable in memory until reset, clear or recycle is called.
      28                 :            :  *
      29                 :            :  * Design notes for possible extensions:
      30                 :            :  *
      31                 :            :  * The buffer is a ring buffer marked by a front and a back page. The
      32                 :            :  * front and back may be the same page and may initially be absent.
      33                 :            :  * Anything outside these pages are unallocated pages for recycling.
      34                 :            :  * Any page between (but excluding) the front and back pages may be
      35                 :            :  * recycled by unlinking and relinking outside the front and back pages
      36                 :            :  * but then copy operations no longer makes sense. Each page stores the
      37                 :            :  * logical offset within the buffer but isn't otherwise used by the
      38                 :            :  * implemention - it might be used for network transmission.  The buffer
      39                 :            :  * is not explicitly designed for multithreaded access but any page
      40                 :            :  * strictly between front and back is not touched unless recycled and in
      41                 :            :  * this case aligned allocation is useful to prevent cache line sharing.
      42                 :            :  */
      43                 :            : 
      44                 :            : /*
      45                 :            :  * Memory is allocated in fixed size page units - the first page is
      46                 :            :  * split between front and back so each get half the page size. If the
      47                 :            :  * size is a multiple of 128 then each page offset will be a multiple of
      48                 :            :  * 64, which may be useful for sequencing etc.
      49                 :            :  */
      50                 :            : #ifndef FLATCC_EMITTER_PAGE_SIZE
      51                 :            : #define FLATCC_EMITTER_MAX_PAGE_SIZE 3000
      52                 :            : #define FLATCC_EMITTER_PAGE_MULTIPLE 64
      53                 :            : #define FLATCC_EMITTER_PAGE_SIZE ((FLATCC_EMITTER_MAX_PAGE_SIZE) &\
      54                 :            :     ~(2 * (FLATCC_EMITTER_PAGE_MULTIPLE) - 1))
      55                 :            : #endif
      56                 :            : 
      57                 :            : #ifndef FLATCC_EMITTER_ALLOC
      58                 :            : #ifdef FLATCC_EMITTER_USE_ALIGNED_ALLOC
      59                 :            : /*
      60                 :            :  * <stdlib.h> does not always provide aligned_alloc, so include whatever
      61                 :            :  * is required when enabling this feature.
      62                 :            :  */
      63                 :            : #define FLATCC_EMITTER_ALLOC(n) aligned_alloc(FLATCC_EMITTER_PAGE_MULTIPLE,\
      64                 :            :         (((n) + FLATCC_EMITTER_PAGE_MULTIPLE - 1) & ~(FLATCC_EMITTER_PAGE_MULTIPLE - 1)))
      65                 :            : #else
      66                 :            : #define FLATCC_EMITTER_ALLOC malloc
      67                 :            : #endif
      68                 :            : #endif
      69                 :            : 
      70                 :            : typedef struct flatcc_emitter_page flatcc_emitter_page_t;
      71                 :            : typedef struct flatcc_emitter flatcc_emitter_t;
      72                 :            : 
      73                 :            : struct flatcc_emitter_page {
      74                 :            :     uint8_t page[FLATCC_EMITTER_PAGE_SIZE];
      75                 :            :     flatcc_emitter_page_t *next;
      76                 :            :     flatcc_emitter_page_t *prev;
      77                 :            :     /*
      78                 :            :      * The offset is relative to page start, but not necessarily
      79                 :            :      * to any present content if part of front or back page,
      80                 :            :      * and undefined for unused pages.
      81                 :            :      */
      82                 :            :     flatbuffers_soffset_t page_offset;
      83                 :            : };
      84                 :            : 
      85                 :            : /*
      86                 :            :  * Must be allocated and zeroed externally, e.g. on the stack
      87                 :            :  * then provided as emit_context to the flatbuilder along
      88                 :            :  * with the `flatcc_emitter` function.
      89                 :            :  */
      90                 :            : struct flatcc_emitter {
      91                 :            :     flatcc_emitter_page_t *front, *back;
      92                 :            :     uint8_t *front_cursor;
      93                 :            :     size_t front_left;
      94                 :            :     uint8_t *back_cursor;
      95                 :            :     size_t back_left;
      96                 :            :     size_t used;
      97                 :            :     size_t capacity;
      98                 :            :     size_t used_average;
      99                 :            : };
     100                 :            : 
     101                 :            : /* Optional helper to ensure emitter is zeroed initially. */
     102                 :            : static inline void flatcc_emitter_init(flatcc_emitter_t *E)
     103                 :            : {
     104                 :            :     memset(E, 0, sizeof(*E));
     105                 :            : }
     106                 :            : 
     107                 :            : /* Deallocates all buffer memory making the emitter ready for next use. */
     108                 :            : void flatcc_emitter_clear(flatcc_emitter_t *E);
     109                 :            : 
     110                 :            : /*
     111                 :            :  * Similar to `clear_flatcc_emitter` but heuristacally keeps some allocated
     112                 :            :  * memory between uses while gradually reducing peak allocations.
     113                 :            :  * For small buffers, a single page will remain available with no
     114                 :            :  * additional allocations or deallocations after first use.
     115                 :            :  */
     116                 :            : void flatcc_emitter_reset(flatcc_emitter_t *E);
     117                 :            : 
     118                 :            : /*
     119                 :            :  * Helper function that allows a page between front and back to be
     120                 :            :  * recycled while the buffer is still being constructed - most likely as part
     121                 :            :  * of partial copy or transmission. Attempting to recycle front or back
     122                 :            :  * pages will result will result in an error. Recycling pages outside the
     123                 :            :  * front and back will be valid but pointless. After recycling and copy
     124                 :            :  * operations are no longer well-defined and should be replaced with
     125                 :            :  * whatever logic is recycling the pages.  The reset operation
     126                 :            :  * automatically recycles all (remaining) pages when emission is
     127                 :            :  * complete. After recycling, the `flatcc_emitter_size` function will
     128                 :            :  * return as if recycle was not called, but will only represent the
     129                 :            :  * logical size, not the size of the active buffer. Because a recycled
     130                 :            :  * page is fully utilized, it is fairly easy to compensate for this if
     131                 :            :  * required.
     132                 :            :  *
     133                 :            :  * Returns 0 on success.
     134                 :            :  */
     135                 :            : int flatcc_emitter_recycle_page(flatcc_emitter_t *E, flatcc_emitter_page_t *p);
     136                 :            : 
     137                 :            : /*
     138                 :            :  * The amount of data copied with `flatcc_emitter_copy_buffer` and related
     139                 :            :  * functions. Normally called at end of buffer construction but is
     140                 :            :  * always valid, as is the copy functions. The size is a direct
     141                 :            :  * function of the amount emitted data so the flatbuilder itself can
     142                 :            :  * also provide this information.
     143                 :            :  */
     144                 :            : static inline size_t flatcc_emitter_get_buffer_size(flatcc_emitter_t *E)
     145                 :            : {
     146                 :            :     return E->used;
     147                 :            : }
     148                 :            : 
     149                 :            : /*
     150                 :            :  * Returns buffer start iff the buffer fits on a single internal page.
     151                 :            :  * Only useful for fairly small buffers - about half the page size since
     152                 :            :  * one half of first page goes to vtables that likely use little space.
     153                 :            :  * Returns null if request could not be served.
     154                 :            :  *
     155                 :            :  * If `size_out` is not null, it is set to the buffer size, or 0 if
     156                 :            :  * operation failed.
     157                 :            :  */
     158                 :            : static inline void *flatcc_emitter_get_direct_buffer(flatcc_emitter_t *E, size_t *size_out)
     159                 :            : {
     160         [ +  - ]:         10 :     if (E->front == E->back) {
     161         [ +  + ]:         10 :         if (size_out) {
     162                 :          9 :             *size_out = E->used;
     163                 :            :         }
     164                 :         10 :         return E->front_cursor;
     165                 :            :     }
     166         [ #  # ]:          0 :     if (size_out) {
     167                 :          0 :         *size_out = 0;
     168                 :            :     }
     169                 :            :     return 0;
     170                 :            : }
     171                 :            : 
     172                 :            : /*
     173                 :            :  * Copies the internal flatcc_emitter representation to an externally
     174                 :            :  * provided linear buffer that must have size `flatcc_emitter_get_size`.
     175                 :            :  *
     176                 :            :  * If pages have been recycled, only the remaining pages will be copied
     177                 :            :  * and thus less data than what `flatcc_emitter_get_size` would suggest. It
     178                 :            :  * makes more sense to provide a customized copy operation when
     179                 :            :  * recycling pages.
     180                 :            :  *
     181                 :            :  * If the buffer is too small, nothing is copied, otherwise the
     182                 :            :  * full buffer is copied and the input buffer is returned.
     183                 :            :  */
     184                 :            : void *flatcc_emitter_copy_buffer(flatcc_emitter_t *E, void *buf, size_t size);
     185                 :            : 
     186                 :            : /*
     187                 :            :  * The emitter interface function to the flatbuilder API.
     188                 :            :  * `emit_context` should be of type `flatcc_emitter_t` for this
     189                 :            :  * particular implementation.
     190                 :            :  *
     191                 :            :  * This function is compatible with the `flatbuilder_emit_fun`
     192                 :            :  * type defined in "flatbuilder.h".
     193                 :            :  */
     194                 :            : int flatcc_emitter(void *emit_context,
     195                 :            :         const flatcc_iovec_t *iov, int iov_count,
     196                 :            :         flatbuffers_soffset_t offset, size_t len);
     197                 :            : 
     198                 :            : #endif /* FLATCC_EMITTER_H */

Generated by: LCOV version 1.12