aboutsummaryrefslogtreecommitdiff
path: root/listpool/src/listpool.c
blob: 758062c877f89945b6d62956bd44f23a6e8a6a60 (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
#include "listpool.h"

#include <string.h>

void listpool_make_(
    listpool* pool, list* nodes, void* blocks, size_t num_blocks,
    size_t block_size_bytes) {
  assert(pool);
  pool->block_size_bytes = block_size_bytes;
  pool->num_blocks       = num_blocks;
  pool->free             = &nodes[0];
  pool->used             = 0;
  pool->nodes            = nodes;
  pool->blocks           = blocks;
  list_make(nodes, num_blocks);
  memset(blocks, 0, num_blocks * block_size_bytes);
}

void* listpool_alloc_(listpool* pool) {
  assert(pool);
  if (!pool->free) {
    return 0;
  }

  const size_t index = pool->free - pool->nodes;
  assert(index < pool->num_blocks);

  list* free = pool->free;
  pool->free = pool->free->next;

  // pool->used is always the head of the used list, so prepend the new item to
  // the list.
  list* new_used = free;
  new_used->prev = 0;
  new_used->next = pool->used;
  if (pool->used) {
    pool->used->prev = new_used;
  }
  pool->used = new_used;

  return pool->blocks + index * pool->block_size_bytes;
}

void listpool_free_(listpool* pool, void** block_ptr) {
  assert(pool);
  assert(block_ptr);

  memset(*block_ptr, 0, pool->block_size_bytes);

  const size_t index =
      ((uint8_t*)*block_ptr - pool->blocks) / pool->block_size_bytes;
  assert(index < pool->num_blocks);

  list* item = &pool->nodes[index];

  // We must remove the item from the used list first.
  if (item->prev) {
    item->prev->next = item->next;
  }
  if (item->next) {
    item->next->prev = item->prev;
  }
  if (item == pool->used) {
    pool->used = item->next;
  }

  // pool->free is always the head of the free list, so prepend the new item to
  // the list. The item is now free to wire after removing it from the used
  // list.
  if (!pool->free) {
    pool->free = item;
  } else {
    item->next       = pool->free;
    pool->free->prev = item;
    pool->free       = item;
  }

  *block_ptr = 0;
}

void* listpool_get_block_(const listpool* pool, size_t block_index) {
  assert(pool);
  assert(block_index < pool->num_blocks);
  return pool->blocks + block_index * pool->block_size_bytes;
}

size_t listpool_get_block_index_(const listpool* pool, const void* block) {
  assert(pool);
  const size_t block_byte_index = (const uint8_t*)block - pool->blocks;
  assert(block_byte_index % pool->block_size_bytes == 0);
  return block_byte_index / pool->block_size_bytes;
}