| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #ifndef BLOCK_H | ||
| 2 | #define BLOCK_H | ||
| 3 | |||
| 4 | #include <stddef.h> | ||
| 5 | #include "util/debug.h" | ||
| 6 | #include "util/list.h" | ||
| 7 | #include "util/macros.h" | ||
| 8 | |||
| 9 | // Blocks always contain whole lines. | ||
| 10 | // There's one zero-sized block for an empty file. | ||
| 11 | // Otherwise zero-sized blocks are forbidden. | ||
| 12 | typedef struct { | ||
| 13 | ListHead node; | ||
| 14 | char NONSTRING *data; | ||
| 15 | size_t size; | ||
| 16 | size_t alloc; | ||
| 17 | size_t nl; | ||
| 18 | } Block; | ||
| 19 | |||
| 20 | enum { | ||
| 21 | BLOCK_ALLOC_MULTIPLE = 64, | ||
| 22 | }; | ||
| 23 | |||
| 24 | #define block_for_each(block_, list_head_) \ | ||
| 25 | for ( \ | ||
| 26 | block_ = BLOCK((list_head_)->next); \ | ||
| 27 | &block_->node != (list_head_); \ | ||
| 28 | block_ = BLOCK(block_->node.next) \ | ||
| 29 | ) | ||
| 30 | |||
| 31 | // NOLINTNEXTLINE(readability-identifier-naming) | ||
| 32 | 2421 | static inline Block *BLOCK(ListHead *item) | |
| 33 | { | ||
| 34 | 2421 | static_assert(offsetof(Block, node) == 0); | |
| 35 | 2421 | return (Block*)item; | |
| 36 | } | ||
| 37 | |||
| 38 | 472 | static inline void block_sanity_check(const Block *blk) | |
| 39 | { | ||
| 40 | 472 | BUG_ON(!blk); | |
| 41 | 472 | BUG_ON(blk->size > blk->alloc); | |
| 42 | 472 | BUG_ON(blk->nl > blk->size); | |
| 43 | |||
| 44 | // block_new() forbids `alloc == 0` and thus always allocates | ||
| 45 | // at least BLOCK_ALLOC_MULTIPLE bytes | ||
| 46 | 472 | BUG_ON(blk->alloc < BLOCK_ALLOC_MULTIPLE); | |
| 47 | 472 | BUG_ON(!blk->data); | |
| 48 | 472 | } | |
| 49 | |||
| 50 | Block *block_new(size_t alloc) RETURNS_NONNULL; | ||
| 51 | void block_grow(Block *blk, size_t alloc) NONNULL_ARGS; | ||
| 52 | void block_free(Block *blk) NONNULL_ARGS; | ||
| 53 | |||
| 54 | #endif | ||
| 55 |