aboutsummaryrefslogtreecommitdiff
path: root/listpool/include/listpool.h
blob: 85a3b273e47e2bb576ebc37bdda57b81ed13dce2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#pragma once

#include "list.h"

#include <assert.h>
#include <stddef.h>
#include <stdint.h>

/// Define a typed listpool of a given size.
#define DEF_LISTPOOL(POOL, TYPE, NUM_BLOCKS) \
  typedef struct POOL {                      \
    listpool pool;                           \
    list     nodes[NUM_BLOCKS];              \
    TYPE     blocks[NUM_BLOCKS];             \
  } POOL;

/// Creates a new listpool.
#define listpool_make(POOL)                                                    \
  {                                                                            \
    assert(POOL);                                                              \
    const size_t block_size = sizeof((POOL)->blocks[0]);                       \
    const size_t num_blocks = sizeof((POOL)->blocks) / block_size;             \
    listpool_make_(                                                            \
        &(POOL)->pool, (POOL)->nodes, (POOL)->blocks, num_blocks, block_size); \
  }

/// Allocate a new block.
/// Return 0 if there is no memory left.
#define listpool_alloc(POOL) listpool_alloc_(&(POOL)->pool)

/// Free the block.
/// The block pointer is conveniently set to 0.
#define listpool_free(POOL, ITEM) listpool_free_(&(POOL)->pool, (void**)ITEM)

/// Remove a value from the list.
/// Defined here instead of DEF_LISTPOOL_IMPL() because not all types may have
/// an operator==.
#define listpool_remove(POOL, VAL)  \
  {                                 \
    listpool_foreach(POOL, iter, {  \
      if (*iter == VAL) {           \
        listpool_free(POOL, &iter); \
        break;                      \
      }                             \
    });                             \
  }

/// Return the ith block.
/// The block must have been allocated.
#define listpool_get_block(POOL, INDEX) \
  ((typeof((POOL)->blocks[0])*)listpool_get_block_(&(POOL)->pool, INDEX))

/// Get the index to the given block.
#define listpool_get_block_index(POOL, BLOCK_PTR) \
  listpool_get_block_index_(&(POOL)->pool, BLOCK_PTR)

/// Iterate over the used items of the pool.
///
/// The caller can use 'i' as the index of the current block.
///
/// It is valid to mempool_free() the object at each step of the iteration.
#define listpool_foreach(POOL, ITER, BODY)                      \
  for (list* it_ = (POOL)->pool.used; it_; it_ = it_->next) {   \
    const size_t               i    = it_ - (POOL)->pool.nodes; \
    typeof((POOL)->blocks[0])* ITER = &(POOL)->blocks[i];       \
    (void)ITER;                                                 \
    BODY;                                                       \
  }

typedef struct listpool {
  size_t   block_size_bytes;
  size_t   num_blocks;
  list*    free;   // Head of the free list.
  list*    used;   // Head of the used list.
  list*    nodes;  // Array of nodes.
  uint8_t* blocks; // Array of blocks;
} listpool;

/// Create a new list pool from a user-provided array of memory.
/// `nodes` must have at least `num_blocks` nodes.
/// `blocks` must be at least `num_blocks` * `block_size_bytes` bytes.
/// All blocks are zeroed out for convenience.
void listpool_make_(
    listpool* pool, list* nodes, void* blocks, size_t num_blocks,
    size_t block_size_bytes);

/// Allocate a new block.
/// Return 0 if there is no memory left.
void* listpool_alloc_(listpool* pool);

/// Free the block.
/// The block pointer is conveniently set to 0.
void listpool_free_(listpool* pool, void** block_ptr);

/// Return the ith block.
/// The block must have been allocated.
void* listpool_get_block_(const listpool*, size_t block_index);

/// Get the index to the given block.
size_t listpool_get_block_index_(const listpool*, const void* block);