aboutsummaryrefslogtreecommitdiffstats
path: root/cheesemap.h
blob: d49bfce5bdc7ee90de1b224006d24e88bda1fe8d (plain) (blame)
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
101
102
103
104
105
106
107
108
109
#ifndef CHEESEMAP
#define CHEESEMAP

////////////////////////////////
// options and includes
//

#include <stdbool.h>
#include <stdint.h>
#include <string.h>

#include CM_OPT_ASSERT_PATH
#ifndef assert
#error "assert is not defined"
#endif

enum {
  CM_GROUP_SIZE = 8,
};

////////////////////////////////
// cheesemap callback functions
//

typedef uint64_t cm_hash_t;

/* memory methods */
typedef void* (*cm_malloc_fn)(uintptr_t size, uintptr_t alignment,
                              uint8_t* user);
typedef void (*cm_free_fn)(void* ptr, uint8_t* user);

/* hash and compare methods */
typedef cm_hash_t (*cm_hash_fn)(const uint8_t* key, uint8_t* user);
typedef bool (*cm_compare_fn)(const uint8_t* key1, const uint8_t* key2,
                              uint8_t* user);

////////////////////////////////
// callback methods needed by cheesemap
//

struct cheesemap_fns {
  uint8_t *mem_usr, *map_usr;
  cm_malloc_fn malloc;
  cm_free_fn free;
  cm_hash_fn hash;
  cm_compare_fn compare;
};

////////////////////////////////
// raw cheesemap implementation
//
// layout:
// [entries...][control bits...][mirror first CM_GROUP_SIZE bits]

enum {
  CM_INITIAL_CAPACITY = CM_GROUP_SIZE,
  CM_CTRL_EMPTY = 0x80,
  CM_CTRL_DELETED = 0xFE,
  CM_H2_MASK = 0x7F,
  CM_FP_SIZE = 7
};

static inline uintptr_t cm_h1(cm_hash_t hash) {
  return (uintptr_t)(hash >> CM_FP_SIZE);
}

static inline uint8_t cm_h2(cm_hash_t hash) {
  return (uint8_t)(hash & CM_H2_MASK);
}

struct cheesemap_raw {
  // mask of the capacity
  uintptr_t cap_mask;
  // number of entries in the map
  uintptr_t entry_count;
  // number of entry left until resize
  uintptr_t growth_left;
  // pointer to the control bytes
  uint8_t* ctrl;
};

#define cm_raw_new() ((struct cheesemap_raw){0})

void cm_raw_drop(struct cheesemap_raw* map, uintptr_t entry_size,
                 struct cheesemap_fns* fns);

////////////////////////////////
// cheesemap implementation
//

struct cheesemap {
  uintptr_t entry_size;
  struct cheesemap_fns fns;
  struct cheesemap_raw raw;
};

void cm_new(struct cheesemap* map, uintptr_t entry_size,
                          uint8_t* mem_usr, cm_malloc_fn malloc, cm_free_fn free,
                          uint8_t* map_usr, cm_hash_fn hash,
                          cm_compare_fn compare);

static inline void cm_drop(struct cheesemap* map) {
  assert(map != NULL);

  cm_raw_drop(&map->raw, map->entry_size, &map->fns);
  memset(map, 0, sizeof(*map));
}

#endif