PyCyBase 0.1.8.post4__cp313-cp313-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cbase/__infra__.pxd +6 -0
- cbase/__init__.pxd +6 -0
- cbase/__init__.py +28 -0
- cbase/allocator_protocol/__infra__.pxd +58 -0
- cbase/allocator_protocol/__init__.pxd +58 -0
- cbase/allocator_protocol/__init__.py +45 -0
- cbase/allocator_protocol/c_allocator_protocol.c +31818 -0
- cbase/allocator_protocol/c_allocator_protocol.cp313-win_amd64.pyd +0 -0
- cbase/allocator_protocol/c_allocator_protocol.h +352 -0
- cbase/allocator_protocol/c_allocator_protocol.pxd +64 -0
- cbase/allocator_protocol/c_allocator_protocol.pyi +144 -0
- cbase/allocator_protocol/c_allocator_protocol.pyx +209 -0
- cbase/allocator_protocol/c_heap_allocator.c +38144 -0
- cbase/allocator_protocol/c_heap_allocator.cp313-win_amd64.pyd +0 -0
- cbase/allocator_protocol/c_heap_allocator.h +444 -0
- cbase/allocator_protocol/c_heap_allocator.pxd +97 -0
- cbase/allocator_protocol/c_heap_allocator.pyi +161 -0
- cbase/allocator_protocol/c_heap_allocator.pyx +300 -0
- cbase/allocator_protocol/c_nt_shm_allocator.c +33399 -0
- cbase/allocator_protocol/c_nt_shm_allocator.cp313-win_amd64.pyd +0 -0
- cbase/allocator_protocol/c_nt_shm_allocator.h +996 -0
- cbase/allocator_protocol/c_nt_shm_allocator.pxd +102 -0
- cbase/allocator_protocol/c_nt_shm_allocator.pyx +223 -0
- cbase/allocator_protocol/c_shm_allocator.h +1168 -0
- cbase/allocator_protocol/c_shm_allocator.pxd +142 -0
- cbase/allocator_protocol/c_shm_allocator.pyi +299 -0
- cbase/allocator_protocol/c_shm_allocator.pyx +442 -0
- cbase/allocator_protocol/c_shm_comp.c +4643 -0
- cbase/allocator_protocol/c_shm_comp.cp313-win_amd64.pyd +0 -0
- cbase/allocator_protocol/c_shm_comp.h +49 -0
- cbase/allocator_protocol/c_shm_comp.pxd +38 -0
- cbase/allocator_protocol/c_shm_comp.pyx +1 -0
- cbase/backports/__infra__.pxd +17 -0
- cbase/backports/__init__.pxd +17 -0
- cbase/backports/__init__.py +9 -0
- cbase/backports/pydict.h +55 -0
- cbase/backports/pydict.pxd +5 -0
- cbase/backports/pylong.c +9946 -0
- cbase/backports/pylong.cp313-win_amd64.pyd +0 -0
- cbase/backports/pylong.h +79 -0
- cbase/backports/pylong.pxd +23 -0
- cbase/backports/pylong.pyx +61 -0
- cbase/bytemap/__infra__.pxd +42 -0
- cbase/bytemap/__init__.pxd +42 -0
- cbase/bytemap/__init__.py +21 -0
- cbase/bytemap/c_bytemap.c +52076 -0
- cbase/bytemap/c_bytemap.cp313-win_amd64.pyd +0 -0
- cbase/bytemap/c_bytemap.h +867 -0
- cbase/bytemap/c_bytemap.pxd +370 -0
- cbase/bytemap/c_bytemap.pyx +1758 -0
- cbase/bytemap/xxh3.h +55 -0
- cbase/bytemap/xxhash.c +42 -0
- cbase/bytemap/xxhash.h +7487 -0
- cbase/env.c +11109 -0
- cbase/env.cp313-win_amd64.pyd +0 -0
- cbase/env.pxd +8 -0
- cbase/env.pyi +48 -0
- cbase/env.pyx +46 -0
- cbase/includes/cbase/allocator_protocol/c_allocator_protocol.c +31818 -0
- cbase/includes/cbase/allocator_protocol/c_allocator_protocol.h +352 -0
- cbase/includes/cbase/allocator_protocol/c_heap_allocator.c +38144 -0
- cbase/includes/cbase/allocator_protocol/c_heap_allocator.h +444 -0
- cbase/includes/cbase/allocator_protocol/c_nt_shm_allocator.c +33399 -0
- cbase/includes/cbase/allocator_protocol/c_nt_shm_allocator.h +996 -0
- cbase/includes/cbase/allocator_protocol/c_shm_allocator.h +1168 -0
- cbase/includes/cbase/allocator_protocol/c_shm_comp.c +4643 -0
- cbase/includes/cbase/allocator_protocol/c_shm_comp.h +49 -0
- cbase/includes/cbase/backports/pydict.h +55 -0
- cbase/includes/cbase/backports/pylong.c +9946 -0
- cbase/includes/cbase/backports/pylong.h +79 -0
- cbase/includes/cbase/bytemap/c_bytemap.c +52076 -0
- cbase/includes/cbase/bytemap/c_bytemap.h +867 -0
- cbase/includes/cbase/bytemap/xxh3.h +55 -0
- cbase/includes/cbase/bytemap/xxhash.c +42 -0
- cbase/includes/cbase/bytemap/xxhash.h +7487 -0
- cbase/includes/cbase/env.c +11109 -0
- cbase/includes/cbase/int128.h +81 -0
- cbase/includes/cbase/intern_string/c_intern_string.c +28081 -0
- cbase/includes/cbase/intern_string/c_intern_string.h +614 -0
- cbase/includes/cbase/nt/pthread_nt_compat.h +102 -0
- cbase/includes/cbase/nt/regex_nt_compat.h +133 -0
- cbase/includes/cbase/nt/time_sched_nt_compat.h +32 -0
- cbase/int128.h +81 -0
- cbase/int128.pxd +15 -0
- cbase/intern_string/BENCHMARK.md +157 -0
- cbase/intern_string/__infra__.pxd +11 -0
- cbase/intern_string/__init__.pxd +11 -0
- cbase/intern_string/__init__.py +19 -0
- cbase/intern_string/c_intern_string.c +28081 -0
- cbase/intern_string/c_intern_string.cp313-win_amd64.pyd +0 -0
- cbase/intern_string/c_intern_string.h +614 -0
- cbase/intern_string/c_intern_string.pxd +118 -0
- cbase/intern_string/c_intern_string.pyi +376 -0
- cbase/intern_string/c_intern_string.pyx +765 -0
- cbase/nt/pthread_nt_compat.h +102 -0
- cbase/nt/regex_nt_compat.h +133 -0
- cbase/nt/time_sched_nt_compat.h +32 -0
- pycybase-0.1.8.post4.dist-info/METADATA +180 -0
- pycybase-0.1.8.post4.dist-info/RECORD +101 -0
- pycybase-0.1.8.post4.dist-info/WHEEL +5 -0
- pycybase-0.1.8.post4.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,867 @@
|
|
|
1
|
+
#ifndef C_CBASE_BYTEMAP_H
|
|
2
|
+
#define C_CBASE_BYTEMAP_H
|
|
3
|
+
|
|
4
|
+
#include <stdbool.h>
|
|
5
|
+
#include <stddef.h>
|
|
6
|
+
#include <stdint.h>
|
|
7
|
+
#include <stdlib.h>
|
|
8
|
+
#include <string.h>
|
|
9
|
+
#include <time.h>
|
|
10
|
+
#ifdef _WIN32
|
|
11
|
+
#include <process.h>
|
|
12
|
+
#define getpid _getpid
|
|
13
|
+
#else
|
|
14
|
+
#include <unistd.h>
|
|
15
|
+
#endif
|
|
16
|
+
|
|
17
|
+
#include <cbase/allocator_protocol/c_allocator_protocol.h>
|
|
18
|
+
#include <cbase/bytemap/xxh3.h>
|
|
19
|
+
|
|
20
|
+
// ========== Constants ==========
|
|
21
|
+
|
|
22
|
+
#ifndef MIN_BYTEMAP_CAPACITY
|
|
23
|
+
#define MIN_BYTEMAP_CAPACITY 16U
|
|
24
|
+
#endif
|
|
25
|
+
|
|
26
|
+
#ifndef DEFAULT_BYTEMAP_CAPACITY
|
|
27
|
+
#define DEFAULT_BYTEMAP_CAPACITY 64U
|
|
28
|
+
#endif
|
|
29
|
+
|
|
30
|
+
#ifndef BYTEMAP_GROWTH_FACTOR
|
|
31
|
+
#define BYTEMAP_GROWTH_FACTOR 2U
|
|
32
|
+
#endif
|
|
33
|
+
|
|
34
|
+
#if BYTEMAP_GROWTH_FACTOR < 2U
|
|
35
|
+
#error "BYTEMAP_GROWTH_FACTOR must be >= 2"
|
|
36
|
+
#endif
|
|
37
|
+
|
|
38
|
+
#ifndef MAX_BYTEMAP_CAPACITY
|
|
39
|
+
#define MAX_BYTEMAP_CAPACITY ((size_t) (SIZE_MAX / sizeof(bytemap_entry) / BYTEMAP_GROWTH_FACTOR))
|
|
40
|
+
#endif
|
|
41
|
+
|
|
42
|
+
#ifndef BYTEMAP_SALT_MAGIC
|
|
43
|
+
#define BYTEMAP_SALT_MAGIC 0x9E3779B97F4A7C15ULL
|
|
44
|
+
#endif
|
|
45
|
+
|
|
46
|
+
// ========== Structs ==========
|
|
47
|
+
|
|
48
|
+
// clang-format off
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @brief A single open-addressing table slot with inline value storage.
|
|
52
|
+
*
|
|
53
|
+
* The value is stored as raw bytes in the flexible array member `value[]`.
|
|
54
|
+
* The actual entry size on the table is `sizeof(bytemap_entry) + slot_capacity`.
|
|
55
|
+
*/
|
|
56
|
+
typedef struct bytemap_entry {
|
|
57
|
+
uint64_t hash; // Cached hash of key for faster probing/rehash.
|
|
58
|
+
size_t key_length; // Length of key (excludes NUL).
|
|
59
|
+
const char* key; // Cloned key bytes (owned by the map, NUL-terminated).
|
|
60
|
+
size_t value_length; // Length of value stored in `value[]`.
|
|
61
|
+
bool occupied; // true if slot holds a live entry.
|
|
62
|
+
bool removed; // true if slot is a tombstone (keeps probe chains intact).
|
|
63
|
+
struct bytemap_entry* prev; // Previous entry in insertion-order list.
|
|
64
|
+
struct bytemap_entry* next; // Next entry in insertion-order list.
|
|
65
|
+
char value[]; // Inline value storage (flexible array member).
|
|
66
|
+
} bytemap_entry;
|
|
67
|
+
|
|
68
|
+
// bytemap_entry_ex is an alias for the unified entry type.
|
|
69
|
+
typedef bytemap_entry bytemap_entry_ex;
|
|
70
|
+
|
|
71
|
+
typedef enum bytemap_callback_event {
|
|
72
|
+
BYTEMAP_CALLBACK_EVENT_MODIFIED = 0,
|
|
73
|
+
BYTEMAP_CALLBACK_EVENT_ADDED = 1,
|
|
74
|
+
BYTEMAP_CALLBACK_EVENT_POPPED = 2,
|
|
75
|
+
BYTEMAP_CALLBACK_EVENT_CLEARED = 3,
|
|
76
|
+
BYTEMAP_CALLBACK_EVENT_REHASH = 4,
|
|
77
|
+
BYTEMAP_CALLBACK_EVENT_FREED = 5
|
|
78
|
+
} bytemap_callback_event;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @brief Unified callback signature for both bytemap and bytemap_ex.
|
|
82
|
+
*
|
|
83
|
+
* @param event Mutation event type.
|
|
84
|
+
* @param key Key involved (NULL for clear/rehash/freed events).
|
|
85
|
+
* @param key_len Length of key.
|
|
86
|
+
* @param value Pointer to raw value bytes (NULL for pop/clear/rehash/freed).
|
|
87
|
+
* @param value_len Length of value bytes.
|
|
88
|
+
* @param seq_id Sequence ID of the caller (for self-suppression in bound views).
|
|
89
|
+
* @param user_data Opaque user data pointer passed at registration.
|
|
90
|
+
*/
|
|
91
|
+
typedef void (*bytemap_callback_func)(bytemap_callback_event event, const char* key, size_t key_len, const char* value, size_t value_len, uint64_t seq_id, void* user_data);
|
|
92
|
+
|
|
93
|
+
// Legacy alias -- single unified callback type.
|
|
94
|
+
typedef bytemap_callback_func bytemap_ex_callback_func;
|
|
95
|
+
|
|
96
|
+
typedef struct bytemap_callback_ctx {
|
|
97
|
+
bytemap_callback_func fn;
|
|
98
|
+
void* user_data;
|
|
99
|
+
uintptr_t id;
|
|
100
|
+
struct bytemap_callback_ctx* next;
|
|
101
|
+
} bytemap_callback_ctx;
|
|
102
|
+
|
|
103
|
+
// Legacy alias -- single unified callback context.
|
|
104
|
+
typedef bytemap_callback_ctx bytemap_ex_callback_ctx;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @brief String-keyed hash map with open addressing, tombstones, and inline value storage.
|
|
108
|
+
*
|
|
109
|
+
* This is the unified map struct. bytemap_ex is a typedef alias.
|
|
110
|
+
* For the traditional void* variant (bytemap), slot_capacity == sizeof(void*)
|
|
111
|
+
* and the value bytes are read/written as a pointer.
|
|
112
|
+
*/
|
|
113
|
+
typedef struct bytemap {
|
|
114
|
+
bytemap_entry* table; // Backing array of slots.
|
|
115
|
+
bytemap_entry* first; // Head of insertion-order doubly linked list.
|
|
116
|
+
bytemap_entry* last; // Tail of insertion-order doubly linked list.
|
|
117
|
+
bytemap_callback_ctx* callbacks; // Optional linked list of mutation callbacks.
|
|
118
|
+
size_t capacity; // Number of slots in `table`.
|
|
119
|
+
size_t size; // Number of live entries.
|
|
120
|
+
size_t occupied; // Used-slot count since last rehash (live + tombstones).
|
|
121
|
+
uint64_t salt; // Per-map hash salt for XXH3.
|
|
122
|
+
size_t slot_capacity; // Size of the value slot for each entry (fixed for all entries).
|
|
123
|
+
size_t entry_size; // sizeof(bytemap_entry) + slot_capacity.
|
|
124
|
+
void* table_end; // Pointer to the end of the allocated table for bounds checking.
|
|
125
|
+
} bytemap;
|
|
126
|
+
|
|
127
|
+
// bytemap_ex is an alias for the same unified struct.
|
|
128
|
+
typedef bytemap bytemap_ex;
|
|
129
|
+
|
|
130
|
+
typedef enum bytemap_ret_code {
|
|
131
|
+
BYTEMAP_OK = 0,
|
|
132
|
+
BYTEMAP_ERR_INVALID_BUF = -1,
|
|
133
|
+
BYTEMAP_ERR_INVALID_KEY = -2,
|
|
134
|
+
BYTEMAP_ERR_INVALID_VALUE = -3,
|
|
135
|
+
BYTEMAP_ERR_NOT_FOUND = -4,
|
|
136
|
+
BYTEMAP_ERR_FULL = -5,
|
|
137
|
+
BYTEMAP_ERR_EMPTY = -6,
|
|
138
|
+
BYTEMAP_ERR_OOM = -7
|
|
139
|
+
} bytemap_ret_code;
|
|
140
|
+
|
|
141
|
+
// clang-format on
|
|
142
|
+
|
|
143
|
+
// ========== Forward Declaration ==========
|
|
144
|
+
|
|
145
|
+
static inline int c_bytemap_hash(const bytemap* map, const char* key, size_t key_len, uint64_t* out);
|
|
146
|
+
static inline const char* c_bytemap_clone_key(const bytemap* map, const char* key, size_t key_len);
|
|
147
|
+
static inline void c_bytemap_free_key(const bytemap* map, char* key);
|
|
148
|
+
static inline uint64_t c_bytemap_gen_seq_id(const void* ptr);
|
|
149
|
+
static inline bytemap_entry* c_bytemap_entry_at(const bytemap* map, size_t idx);
|
|
150
|
+
static inline bytemap_entry* c_bytemap_entry_next(const bytemap* map, bytemap_entry* entry);
|
|
151
|
+
static inline bytemap_entry* c_bytemap_entry_first(const bytemap* map);
|
|
152
|
+
static inline void c_bytemap_invoke_callbacks(bytemap_callback_event event, const bytemap* map, const char* key, size_t key_len, const char* value, size_t value_len, uint64_t seq_id);
|
|
153
|
+
|
|
154
|
+
static inline int c_bytemap_ex_init(bytemap* map, size_t capacity, size_t slot_capacity, allocator_protocol* allocator);
|
|
155
|
+
static inline void c_bytemap_ex_dealloc(bytemap* map);
|
|
156
|
+
static inline bytemap* c_bytemap_ex_new(size_t capacity, size_t slot_capacity, allocator_protocol* allocator);
|
|
157
|
+
static inline void c_bytemap_ex_clear(bytemap* map);
|
|
158
|
+
static inline void c_bytemap_ex_free(bytemap* map);
|
|
159
|
+
static inline int c_bytemap_ex_register_callback(bytemap* map, bytemap_callback_func callback, void* user_data, uintptr_t* out_id);
|
|
160
|
+
static inline int c_bytemap_ex_unregister_callback(bytemap* map, uintptr_t callback_id);
|
|
161
|
+
static inline int c_bytemap_ex_get(const bytemap* map, const char* key, size_t key_len, char* out, size_t* out_len);
|
|
162
|
+
static inline int c_bytemap_ex_get_ptr(const bytemap* map, const char* key, size_t key_len, char** out, size_t* out_len);
|
|
163
|
+
static inline int c_bytemap_ex_contains(const bytemap* map, const char* key, size_t key_len);
|
|
164
|
+
static inline int c_bytemap_ex_rehash(bytemap* map, size_t new_capacity, uint64_t seq_id);
|
|
165
|
+
static inline int c_bytemap_ex_set(bytemap* map, const char* key, size_t key_len, const char* value, size_t value_len, uint64_t seq_id, bytemap_entry** out);
|
|
166
|
+
static inline int c_bytemap_ex_pop(bytemap* map, const char* key, size_t key_len, uint64_t seq_id, char* out, size_t* out_len);
|
|
167
|
+
static inline int c_bytemap_ex_pop_ptr(bytemap* map, const char* key, size_t key_len, uint64_t seq_id, char** out, size_t* out_len);
|
|
168
|
+
static inline size_t c_bytemap_ex_len(const bytemap* map);
|
|
169
|
+
static inline bytemap* c_bytemap_ex_clone(const bytemap* src, allocator_protocol* allocator);
|
|
170
|
+
|
|
171
|
+
static inline int c_bytemap_ex_set_double(bytemap* map, const char* key, size_t key_len, double value, uint64_t seq_id);
|
|
172
|
+
static inline int c_bytemap_ex_get_double(const bytemap* map, const char* key, size_t key_len, double* out);
|
|
173
|
+
static inline int c_bytemap_ex_pop_double(bytemap* map, const char* key, size_t key_len, uint64_t seq_id, double* out);
|
|
174
|
+
|
|
175
|
+
static inline bytemap* c_bytemap_new(size_t capacity, allocator_protocol* allocator);
|
|
176
|
+
static inline void c_bytemap_clear(bytemap* map);
|
|
177
|
+
static inline void c_bytemap_free(bytemap* map);
|
|
178
|
+
static inline int c_bytemap_register_callback(bytemap* map, bytemap_callback_func callback, void* user_data, uintptr_t* out_id);
|
|
179
|
+
static inline int c_bytemap_unregister_callback(bytemap* map, uintptr_t callback_id);
|
|
180
|
+
static inline int c_bytemap_get(const bytemap* map, const char* key, size_t key_len, void** out);
|
|
181
|
+
static inline int c_bytemap_contains(const bytemap* map, const char* key, size_t key_len);
|
|
182
|
+
static inline int c_bytemap_rehash(bytemap* map, size_t new_capacity);
|
|
183
|
+
static inline int c_bytemap_set(bytemap* map, const char* key, size_t key_len, void* value, bytemap_entry** out);
|
|
184
|
+
static inline int c_bytemap_pop(bytemap* map, const char* key, size_t key_len, void** out);
|
|
185
|
+
static inline size_t c_bytemap_len(const bytemap* map);
|
|
186
|
+
static inline bytemap* c_bytemap_clone(const bytemap* src, allocator_protocol* allocator);
|
|
187
|
+
static inline bytemap_entry* c_bytemap_first(const bytemap* map);
|
|
188
|
+
static inline bytemap_entry* c_bytemap_last(const bytemap* map);
|
|
189
|
+
static inline bytemap_entry* c_bytemap_next(const bytemap_entry* entry);
|
|
190
|
+
static inline bytemap_entry* c_bytemap_prev(const bytemap_entry* entry);
|
|
191
|
+
static inline void* c_bytemap_entry_value(const bytemap_entry* entry);
|
|
192
|
+
static inline void* c_bytemap_entry_value_as_ptr(const bytemap_entry* entry);
|
|
193
|
+
static inline uintptr_t c_bytemap_entry_value_as_uintptr(const bytemap_entry* entry);
|
|
194
|
+
static inline double c_bytemap_entry_value_as_double(const bytemap_entry* entry);
|
|
195
|
+
|
|
196
|
+
// ========== Utility Functions ==========
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* @brief Compute the hash of a key string for the given map.
|
|
200
|
+
*/
|
|
201
|
+
static inline int c_bytemap_hash(const bytemap* map, const char* key, size_t key_len, uint64_t* out) {
|
|
202
|
+
if (!key) return BYTEMAP_ERR_INVALID_KEY;
|
|
203
|
+
if (!key_len) key_len = strlen(key);
|
|
204
|
+
if (!key_len) return BYTEMAP_ERR_INVALID_KEY;
|
|
205
|
+
*out = map && map->salt ? XXH3_64bits_withSeed(key, key_len, map->salt) : XXH3_64bits(key, key_len);
|
|
206
|
+
return BYTEMAP_OK;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* @brief Clone a key string for storage in the map.
|
|
211
|
+
*/
|
|
212
|
+
static inline const char* c_bytemap_clone_key(const bytemap* map, const char* key, size_t key_len) {
|
|
213
|
+
if (!map || !key) return NULL;
|
|
214
|
+
if (!key_len) key_len = strlen(key);
|
|
215
|
+
if (!key_len) return NULL;
|
|
216
|
+
allocator_protocol* allocator = map->table ? c_ap_protocol_from_ptr((void*) map->table) : c_ap_protocol_from_ptr((void*) map);
|
|
217
|
+
char* buf = (char*) c_ap_alloc(key_len + 1, allocator);
|
|
218
|
+
if (!buf) return NULL;
|
|
219
|
+
memcpy(buf, key, key_len);
|
|
220
|
+
return buf;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* @brief Free a cloned key string.
|
|
225
|
+
*/
|
|
226
|
+
static inline void c_bytemap_free_key(const bytemap* map, char* key) {
|
|
227
|
+
(void) map;
|
|
228
|
+
c_ap_free((void*) key);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* @brief Generate a unique seq_id bound to (pointer address, PID).
|
|
233
|
+
*
|
|
234
|
+
* Mixing the PID ensures that in multiprocessing scenarios with shared
|
|
235
|
+
* memory (AP_SHARED), different processes operating on the same bytemap
|
|
236
|
+
* get distinct seq_ids, so cross-process callback suppression works correctly.
|
|
237
|
+
*
|
|
238
|
+
* @param ptr Opaque pointer (typically the owning Python object).
|
|
239
|
+
* @return A seq_id suitable for callback self-suppression.
|
|
240
|
+
*/
|
|
241
|
+
static inline uint64_t c_bytemap_gen_seq_id(const void* ptr) {
|
|
242
|
+
uint64_t addr = (uint64_t) (uintptr_t) ptr;
|
|
243
|
+
uint64_t pid = (uint64_t) getpid();
|
|
244
|
+
return XXH3_64bits_withSeed(&addr, sizeof(addr), pid);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// ========== Entry Access Helpers ==========
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* @brief Get a pointer to the entry at a given index in the table.
|
|
251
|
+
*/
|
|
252
|
+
static inline bytemap_entry* c_bytemap_entry_at(const bytemap* map, size_t idx) {
|
|
253
|
+
return (bytemap_entry*) (((char*) map->table) + (idx * map->entry_size));
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* @brief Get the next entry in the table (wraps around at table_end).
|
|
258
|
+
*/
|
|
259
|
+
static inline bytemap_entry* c_bytemap_entry_next(const bytemap* map, bytemap_entry* entry) {
|
|
260
|
+
void* next_addr = (void*) ((char*) entry + map->entry_size);
|
|
261
|
+
if (next_addr >= map->table_end) return map->table;
|
|
262
|
+
return (bytemap_entry*) next_addr;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* @brief Get the first live entry in insertion order.
|
|
267
|
+
*/
|
|
268
|
+
static inline bytemap_entry* c_bytemap_entry_first(const bytemap* map) {
|
|
269
|
+
return map ? map->first : NULL;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// ========== Callback Helpers ==========
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* @brief Invoke registered callbacks for a mutation event (unified signature).
|
|
276
|
+
*/
|
|
277
|
+
static inline void c_bytemap_invoke_callbacks(bytemap_callback_event event, const bytemap* map, const char* key, size_t key_len, const char* value, size_t value_len, uint64_t seq_id) {
|
|
278
|
+
if (!map || !map->callbacks) return;
|
|
279
|
+
|
|
280
|
+
bytemap_callback_ctx* cb = map->callbacks;
|
|
281
|
+
while (cb) {
|
|
282
|
+
bytemap_callback_ctx* next = cb->next;
|
|
283
|
+
if (cb->fn) cb->fn(event, key, key_len, value, value_len, seq_id, cb->user_data);
|
|
284
|
+
cb = next;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// ========== Core bytemap_ex APIs (primary implementations) ==========
|
|
289
|
+
|
|
290
|
+
static inline int c_bytemap_ex_init(bytemap* map, size_t capacity, size_t slot_capacity, allocator_protocol* allocator) {
|
|
291
|
+
if (!map) return BYTEMAP_ERR_INVALID_BUF;
|
|
292
|
+
// if (!c_ap_is_allocator_buf(map)) return BYTEMAP_ERR_INVALID_BUF;
|
|
293
|
+
|
|
294
|
+
if (capacity == 0) capacity = DEFAULT_BYTEMAP_CAPACITY;
|
|
295
|
+
if (capacity < MIN_BYTEMAP_CAPACITY) capacity = MIN_BYTEMAP_CAPACITY;
|
|
296
|
+
if (capacity > MAX_BYTEMAP_CAPACITY) return BYTEMAP_ERR_INVALID_BUF;
|
|
297
|
+
if (slot_capacity == 0) return BYTEMAP_ERR_INVALID_BUF;
|
|
298
|
+
|
|
299
|
+
size_t entry_size = sizeof(bytemap_entry) + slot_capacity;
|
|
300
|
+
bytemap_entry* table = (bytemap_entry*) c_ap_alloc(capacity * entry_size, allocator);
|
|
301
|
+
if (!table) return BYTEMAP_ERR_OOM;
|
|
302
|
+
|
|
303
|
+
memset(map, 0, sizeof(bytemap));
|
|
304
|
+
map->table = table;
|
|
305
|
+
map->table_end = (void*) ((char*) table + (capacity * entry_size));
|
|
306
|
+
map->capacity = capacity;
|
|
307
|
+
map->slot_capacity = slot_capacity;
|
|
308
|
+
map->entry_size = entry_size;
|
|
309
|
+
uint64_t seed = (uint64_t) (uintptr_t) map ^ (uint64_t) capacity;
|
|
310
|
+
map->salt = XXH3_64bits(&seed, sizeof(seed)) ^ BYTEMAP_SALT_MAGIC;
|
|
311
|
+
return BYTEMAP_OK;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
static inline void c_bytemap_ex_dealloc(bytemap* map) {
|
|
315
|
+
if (!map) return;
|
|
316
|
+
|
|
317
|
+
c_bytemap_ex_clear(map);
|
|
318
|
+
c_bytemap_invoke_callbacks(BYTEMAP_CALLBACK_EVENT_FREED, map, NULL, 0, NULL, 0, (uint64_t) -1);
|
|
319
|
+
|
|
320
|
+
// Free callback list
|
|
321
|
+
bytemap_callback_ctx* cb = map->callbacks;
|
|
322
|
+
while (cb) {
|
|
323
|
+
bytemap_callback_ctx* next = cb->next;
|
|
324
|
+
free(cb);
|
|
325
|
+
cb = next;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (map->table) c_ap_free(map->table);
|
|
329
|
+
|
|
330
|
+
// Zero out the struct but do NOT free the struct itself
|
|
331
|
+
memset(map, 0, sizeof(bytemap));
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
static inline bytemap* c_bytemap_ex_new(size_t capacity, size_t slot_capacity, allocator_protocol* allocator) {
|
|
335
|
+
if (capacity == 0) capacity = DEFAULT_BYTEMAP_CAPACITY;
|
|
336
|
+
if (capacity < MIN_BYTEMAP_CAPACITY) capacity = MIN_BYTEMAP_CAPACITY;
|
|
337
|
+
if (capacity > MAX_BYTEMAP_CAPACITY) return NULL;
|
|
338
|
+
if (slot_capacity == 0) return NULL;
|
|
339
|
+
|
|
340
|
+
bytemap* map = (bytemap*) c_ap_alloc(sizeof(bytemap), allocator);
|
|
341
|
+
if (!map) return NULL;
|
|
342
|
+
|
|
343
|
+
int ret = c_bytemap_ex_init(map, capacity, slot_capacity, allocator);
|
|
344
|
+
if (ret != BYTEMAP_OK) {
|
|
345
|
+
c_ap_free(map);
|
|
346
|
+
return NULL;
|
|
347
|
+
}
|
|
348
|
+
return map;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
static inline void c_bytemap_ex_clear(bytemap* map) {
|
|
352
|
+
if (!map || !map->table) return;
|
|
353
|
+
|
|
354
|
+
bytemap_entry* e = map->table;
|
|
355
|
+
size_t entry_size = map->entry_size;
|
|
356
|
+
|
|
357
|
+
for (size_t i = 0; i < map->capacity; ++i) {
|
|
358
|
+
if (e->occupied) c_bytemap_free_key(map, (char*) e->key);
|
|
359
|
+
memset(e, 0, entry_size);
|
|
360
|
+
e = c_bytemap_entry_next(map, e);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
map->first = map->last = NULL;
|
|
364
|
+
map->size = 0;
|
|
365
|
+
map->occupied = 0;
|
|
366
|
+
c_bytemap_invoke_callbacks(BYTEMAP_CALLBACK_EVENT_CLEARED, map, NULL, 0, NULL, 0, (uint64_t) -1);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
static inline void c_bytemap_ex_free(bytemap* map) {
|
|
370
|
+
if (!map) return;
|
|
371
|
+
c_bytemap_ex_dealloc(map);
|
|
372
|
+
c_ap_free(map);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
static inline int c_bytemap_ex_register_callback(bytemap* map, bytemap_callback_func callback, void* user_data, uintptr_t* out_id) {
|
|
376
|
+
if (!map || !callback) return BYTEMAP_ERR_INVALID_BUF;
|
|
377
|
+
|
|
378
|
+
bytemap_callback_ctx* node = (bytemap_callback_ctx*) calloc(1, sizeof(bytemap_callback_ctx));
|
|
379
|
+
if (!node) return BYTEMAP_ERR_OOM;
|
|
380
|
+
|
|
381
|
+
node->fn = callback;
|
|
382
|
+
node->user_data = user_data;
|
|
383
|
+
node->id = (uintptr_t) node;
|
|
384
|
+
|
|
385
|
+
if (!map->callbacks) {
|
|
386
|
+
map->callbacks = node;
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
bytemap_callback_ctx* tail = map->callbacks;
|
|
390
|
+
while (tail->next) tail = tail->next;
|
|
391
|
+
tail->next = node;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if (out_id) *out_id = node->id;
|
|
395
|
+
return BYTEMAP_OK;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
static inline int c_bytemap_ex_unregister_callback(bytemap* map, uintptr_t callback_id) {
|
|
399
|
+
if (!map) return BYTEMAP_ERR_INVALID_BUF;
|
|
400
|
+
|
|
401
|
+
bytemap_callback_ctx* prev = NULL;
|
|
402
|
+
bytemap_callback_ctx* curr = map->callbacks;
|
|
403
|
+
|
|
404
|
+
while (curr) {
|
|
405
|
+
if (curr->id == callback_id) {
|
|
406
|
+
if (prev) prev->next = curr->next;
|
|
407
|
+
else map->callbacks = curr->next;
|
|
408
|
+
free(curr);
|
|
409
|
+
return BYTEMAP_OK;
|
|
410
|
+
}
|
|
411
|
+
prev = curr;
|
|
412
|
+
curr = curr->next;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
return BYTEMAP_ERR_NOT_FOUND;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
static inline int c_bytemap_ex_get(const bytemap* map, const char* key, size_t key_len, char* out, size_t* out_len) {
|
|
419
|
+
if (!map || !map->table || !key) return BYTEMAP_ERR_INVALID_BUF;
|
|
420
|
+
if (key_len == 0) key_len = strlen(key);
|
|
421
|
+
if (key_len == 0) return BYTEMAP_ERR_INVALID_KEY;
|
|
422
|
+
|
|
423
|
+
uint64_t hash;
|
|
424
|
+
c_bytemap_hash(map, key, key_len, &hash);
|
|
425
|
+
size_t idx = hash % map->capacity;
|
|
426
|
+
size_t start = idx;
|
|
427
|
+
bytemap_entry* entry = c_bytemap_entry_at(map, idx);
|
|
428
|
+
|
|
429
|
+
while (entry->occupied || entry->removed) {
|
|
430
|
+
if (entry->occupied && entry->key_length == key_len && memcmp(entry->key, key, key_len) == 0) {
|
|
431
|
+
if (out) memcpy(out, entry->value, entry->value_length);
|
|
432
|
+
if (out_len) *out_len = entry->value_length;
|
|
433
|
+
return BYTEMAP_OK;
|
|
434
|
+
}
|
|
435
|
+
idx = (idx + 1) % map->capacity;
|
|
436
|
+
entry = c_bytemap_entry_next(map, entry);
|
|
437
|
+
if (idx == start) break;
|
|
438
|
+
}
|
|
439
|
+
return BYTEMAP_ERR_NOT_FOUND;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
static inline int c_bytemap_ex_get_ptr(const bytemap* map, const char* key, size_t key_len, char** out, size_t* out_len) {
|
|
443
|
+
if (!map || !map->table || !key) return BYTEMAP_ERR_INVALID_BUF;
|
|
444
|
+
if (key_len == 0) key_len = strlen(key);
|
|
445
|
+
if (key_len == 0) return BYTEMAP_ERR_INVALID_KEY;
|
|
446
|
+
|
|
447
|
+
uint64_t hash;
|
|
448
|
+
c_bytemap_hash(map, key, key_len, &hash);
|
|
449
|
+
size_t idx = hash % map->capacity;
|
|
450
|
+
size_t start = idx;
|
|
451
|
+
bytemap_entry* entry = c_bytemap_entry_at(map, idx);
|
|
452
|
+
|
|
453
|
+
while (entry->occupied || entry->removed) {
|
|
454
|
+
if (entry->occupied && entry->key_length == key_len && memcmp(entry->key, key, key_len) == 0) {
|
|
455
|
+
if (out) *out = entry->value;
|
|
456
|
+
if (out_len) *out_len = entry->value_length;
|
|
457
|
+
return BYTEMAP_OK;
|
|
458
|
+
}
|
|
459
|
+
idx = (idx + 1) % map->capacity;
|
|
460
|
+
entry = c_bytemap_entry_next(map, entry);
|
|
461
|
+
if (idx == start) break;
|
|
462
|
+
}
|
|
463
|
+
return BYTEMAP_ERR_NOT_FOUND;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
static inline int c_bytemap_ex_contains(const bytemap* map, const char* key, size_t key_len) {
|
|
467
|
+
if (!map || !map->table || !key) return BYTEMAP_ERR_INVALID_BUF;
|
|
468
|
+
if (key_len == 0) key_len = strlen(key);
|
|
469
|
+
if (key_len == 0) return BYTEMAP_ERR_INVALID_KEY;
|
|
470
|
+
|
|
471
|
+
uint64_t hash;
|
|
472
|
+
c_bytemap_hash(map, key, key_len, &hash);
|
|
473
|
+
size_t idx = hash % map->capacity;
|
|
474
|
+
size_t start = idx;
|
|
475
|
+
bytemap_entry* entry = c_bytemap_entry_at(map, idx);
|
|
476
|
+
|
|
477
|
+
while (entry->occupied || entry->removed) {
|
|
478
|
+
if (entry->occupied && entry->key_length == key_len && memcmp(entry->key, key, key_len) == 0)
|
|
479
|
+
return BYTEMAP_OK;
|
|
480
|
+
idx = (idx + 1) % map->capacity;
|
|
481
|
+
entry = c_bytemap_entry_next(map, entry);
|
|
482
|
+
if (idx == start) break;
|
|
483
|
+
}
|
|
484
|
+
return BYTEMAP_ERR_NOT_FOUND;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
static inline int c_bytemap_ex_rehash(bytemap* map, size_t new_capacity, uint64_t seq_id) {
|
|
488
|
+
if (!map || new_capacity == 0 || new_capacity > MAX_BYTEMAP_CAPACITY) return BYTEMAP_ERR_INVALID_BUF;
|
|
489
|
+
|
|
490
|
+
allocator_protocol* allocator = map->table ? c_ap_protocol_from_ptr((void*) map->table) : c_ap_protocol_from_ptr((void*) map);
|
|
491
|
+
size_t entry_size = map->entry_size;
|
|
492
|
+
bytemap_entry* new_table = (bytemap_entry*) c_ap_alloc(new_capacity * entry_size, allocator);
|
|
493
|
+
if (!new_table) return BYTEMAP_ERR_OOM;
|
|
494
|
+
|
|
495
|
+
bytemap_entry* new_first = NULL;
|
|
496
|
+
bytemap_entry* new_last = NULL;
|
|
497
|
+
|
|
498
|
+
for (bytemap_entry* e = map->first; e; e = e->next) {
|
|
499
|
+
size_t idx = e->hash % new_capacity;
|
|
500
|
+
bytemap_entry* entry = (bytemap_entry*) (((char*) new_table) + (idx * entry_size));
|
|
501
|
+
while (entry->occupied) {
|
|
502
|
+
idx = (idx + 1) % new_capacity;
|
|
503
|
+
entry = (bytemap_entry*) (((char*) new_table) + (idx * entry_size));
|
|
504
|
+
}
|
|
505
|
+
memcpy(entry, e, entry_size);
|
|
506
|
+
entry->prev = new_last;
|
|
507
|
+
entry->next = NULL;
|
|
508
|
+
if (new_last) new_last->next = entry;
|
|
509
|
+
else new_first = entry;
|
|
510
|
+
new_last = entry;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
c_ap_free(map->table);
|
|
514
|
+
map->table = new_table;
|
|
515
|
+
map->table_end = (void*) ((char*) new_table + (new_capacity * entry_size));
|
|
516
|
+
map->capacity = new_capacity;
|
|
517
|
+
map->occupied = map->size;
|
|
518
|
+
map->first = new_first;
|
|
519
|
+
map->last = new_last;
|
|
520
|
+
c_bytemap_invoke_callbacks(BYTEMAP_CALLBACK_EVENT_REHASH, map, NULL, 0, NULL, 0, seq_id);
|
|
521
|
+
return BYTEMAP_OK;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
static inline int c_bytemap_ex_set(bytemap* map, const char* key, size_t key_len, const char* value, size_t value_len, uint64_t seq_id, bytemap_entry** out) {
|
|
525
|
+
if (!map) return BYTEMAP_ERR_INVALID_BUF;
|
|
526
|
+
if (!key) return BYTEMAP_ERR_INVALID_KEY;
|
|
527
|
+
if (!value || value_len > map->slot_capacity) return BYTEMAP_ERR_INVALID_VALUE;
|
|
528
|
+
if (key_len == 0) key_len = strlen(key);
|
|
529
|
+
if (key_len == 0) return BYTEMAP_ERR_INVALID_KEY;
|
|
530
|
+
|
|
531
|
+
probe:
|
|
532
|
+
size_t capacity = map->capacity;
|
|
533
|
+
uint64_t hash;
|
|
534
|
+
c_bytemap_hash(map, key, key_len, &hash);
|
|
535
|
+
size_t idx = hash % capacity;
|
|
536
|
+
size_t start = idx;
|
|
537
|
+
bytemap_entry* tombstone = NULL;
|
|
538
|
+
bytemap_entry* entry = c_bytemap_entry_at(map, idx);
|
|
539
|
+
|
|
540
|
+
while (entry->occupied || entry->removed) {
|
|
541
|
+
if (!entry->occupied && !tombstone) tombstone = entry;
|
|
542
|
+
else if (entry->occupied && entry->key_length == key_len && memcmp(entry->key, key, key_len) == 0) {
|
|
543
|
+
memcpy(entry->value, value, value_len);
|
|
544
|
+
entry->value_length = value_len;
|
|
545
|
+
if (out) *out = entry;
|
|
546
|
+
c_bytemap_invoke_callbacks(BYTEMAP_CALLBACK_EVENT_MODIFIED, map, entry->key, key_len, entry->value, value_len, seq_id);
|
|
547
|
+
return BYTEMAP_OK;
|
|
548
|
+
}
|
|
549
|
+
idx = (idx + 1) % capacity;
|
|
550
|
+
entry = c_bytemap_entry_next(map, entry);
|
|
551
|
+
if (idx == start) {
|
|
552
|
+
if (tombstone) {
|
|
553
|
+
entry = tombstone;
|
|
554
|
+
break;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
size_t new_cap;
|
|
558
|
+
if (capacity == 0) new_cap = MIN_BYTEMAP_CAPACITY;
|
|
559
|
+
else if (capacity > MAX_BYTEMAP_CAPACITY / BYTEMAP_GROWTH_FACTOR) new_cap = MAX_BYTEMAP_CAPACITY;
|
|
560
|
+
else new_cap = capacity * BYTEMAP_GROWTH_FACTOR;
|
|
561
|
+
if (new_cap == capacity) return BYTEMAP_ERR_FULL;
|
|
562
|
+
int ret_code = c_bytemap_ex_rehash(map, new_cap, seq_id);
|
|
563
|
+
if (ret_code != BYTEMAP_OK) return ret_code;
|
|
564
|
+
goto probe;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
if (tombstone) entry = tombstone;
|
|
569
|
+
else {
|
|
570
|
+
if (map->occupied * 2 >= capacity) {
|
|
571
|
+
size_t new_cap;
|
|
572
|
+
if (capacity == 0) new_cap = MIN_BYTEMAP_CAPACITY;
|
|
573
|
+
else if (capacity > MAX_BYTEMAP_CAPACITY / BYTEMAP_GROWTH_FACTOR) new_cap = MAX_BYTEMAP_CAPACITY;
|
|
574
|
+
else new_cap = capacity * BYTEMAP_GROWTH_FACTOR;
|
|
575
|
+
|
|
576
|
+
if (new_cap != capacity) {
|
|
577
|
+
int ret_code = c_bytemap_ex_rehash(map, new_cap, seq_id);
|
|
578
|
+
if (ret_code != BYTEMAP_OK) return ret_code;
|
|
579
|
+
goto probe;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
map->occupied++;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
const char* key_copy = c_bytemap_clone_key(map, key, key_len);
|
|
587
|
+
if (!key_copy) return BYTEMAP_ERR_OOM;
|
|
588
|
+
|
|
589
|
+
entry->key = key_copy;
|
|
590
|
+
entry->key_length = key_len;
|
|
591
|
+
memcpy(entry->value, value, value_len);
|
|
592
|
+
entry->value_length = value_len;
|
|
593
|
+
entry->hash = hash;
|
|
594
|
+
entry->occupied = true;
|
|
595
|
+
entry->removed = false;
|
|
596
|
+
|
|
597
|
+
entry->prev = map->last;
|
|
598
|
+
entry->next = NULL;
|
|
599
|
+
if (map->last) map->last->next = entry;
|
|
600
|
+
else map->first = entry;
|
|
601
|
+
map->last = entry;
|
|
602
|
+
map->size++;
|
|
603
|
+
if (out) *out = entry;
|
|
604
|
+
c_bytemap_invoke_callbacks(BYTEMAP_CALLBACK_EVENT_ADDED, map, entry->key, key_len, entry->value, value_len, seq_id);
|
|
605
|
+
return BYTEMAP_OK;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
static inline int c_bytemap_ex_pop(bytemap* map, const char* key, size_t key_len, uint64_t seq_id, char* out, size_t* out_len) {
|
|
609
|
+
if (!map || !key) return BYTEMAP_ERR_INVALID_BUF;
|
|
610
|
+
if (key_len == 0) key_len = strlen(key);
|
|
611
|
+
if (key_len == 0) return BYTEMAP_ERR_INVALID_KEY;
|
|
612
|
+
|
|
613
|
+
size_t entry_size = map->entry_size;
|
|
614
|
+
size_t capacity = map->capacity;
|
|
615
|
+
uint64_t hash;
|
|
616
|
+
c_bytemap_hash(map, key, key_len, &hash);
|
|
617
|
+
size_t idx = hash % capacity;
|
|
618
|
+
size_t start = idx;
|
|
619
|
+
|
|
620
|
+
while (1) {
|
|
621
|
+
bytemap_entry* entry = c_bytemap_entry_at(map, idx);
|
|
622
|
+
if (!entry->occupied && !entry->removed) break;
|
|
623
|
+
if (entry->occupied && entry->key_length == key_len && memcmp(entry->key, key, key_len) == 0) {
|
|
624
|
+
if (out) memcpy(out, entry->value, entry->value_length);
|
|
625
|
+
if (out_len) *out_len = entry->value_length;
|
|
626
|
+
|
|
627
|
+
if (entry->prev) entry->prev->next = entry->next;
|
|
628
|
+
else map->first = entry->next;
|
|
629
|
+
if (entry->next) entry->next->prev = entry->prev;
|
|
630
|
+
else map->last = entry->prev;
|
|
631
|
+
|
|
632
|
+
c_bytemap_free_key(map, (char*) entry->key);
|
|
633
|
+
memset(entry, 0, entry_size);
|
|
634
|
+
entry->removed = 1;
|
|
635
|
+
map->size--;
|
|
636
|
+
c_bytemap_invoke_callbacks(BYTEMAP_CALLBACK_EVENT_POPPED, map, key, key_len, NULL, 0, seq_id);
|
|
637
|
+
return BYTEMAP_OK;
|
|
638
|
+
}
|
|
639
|
+
idx = (idx + 1) % capacity;
|
|
640
|
+
if (idx == start) break;
|
|
641
|
+
}
|
|
642
|
+
return BYTEMAP_ERR_NOT_FOUND;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
static inline int c_bytemap_ex_pop_ptr(bytemap* map, const char* key, size_t key_len, uint64_t seq_id, char** out, size_t* out_len) {
|
|
646
|
+
if (!map || !key) return BYTEMAP_ERR_INVALID_BUF;
|
|
647
|
+
if (key_len == 0) key_len = strlen(key);
|
|
648
|
+
if (key_len == 0) return BYTEMAP_ERR_INVALID_KEY;
|
|
649
|
+
|
|
650
|
+
size_t entry_size = map->entry_size;
|
|
651
|
+
size_t capacity = map->capacity;
|
|
652
|
+
uint64_t hash;
|
|
653
|
+
c_bytemap_hash(map, key, key_len, &hash);
|
|
654
|
+
size_t idx = hash % capacity;
|
|
655
|
+
size_t start = idx;
|
|
656
|
+
|
|
657
|
+
while (1) {
|
|
658
|
+
bytemap_entry* entry = c_bytemap_entry_at(map, idx);
|
|
659
|
+
if (!entry->occupied && !entry->removed) break;
|
|
660
|
+
if (entry->occupied && entry->key_length == key_len && memcmp(entry->key, key, key_len) == 0) {
|
|
661
|
+
if (out) *out = entry->value;
|
|
662
|
+
if (out_len) *out_len = entry->value_length;
|
|
663
|
+
|
|
664
|
+
if (entry->prev) entry->prev->next = entry->next;
|
|
665
|
+
else map->first = entry->next;
|
|
666
|
+
if (entry->next) entry->next->prev = entry->prev;
|
|
667
|
+
else map->last = entry->prev;
|
|
668
|
+
|
|
669
|
+
c_bytemap_free_key(map, (char*) entry->key);
|
|
670
|
+
memset(entry, 0, entry_size);
|
|
671
|
+
entry->removed = 1;
|
|
672
|
+
map->size--;
|
|
673
|
+
c_bytemap_invoke_callbacks(BYTEMAP_CALLBACK_EVENT_POPPED, map, key, key_len, NULL, 0, seq_id);
|
|
674
|
+
return BYTEMAP_OK;
|
|
675
|
+
}
|
|
676
|
+
idx = (idx + 1) % capacity;
|
|
677
|
+
if (idx == start) break;
|
|
678
|
+
}
|
|
679
|
+
return BYTEMAP_ERR_NOT_FOUND;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
static inline size_t c_bytemap_ex_len(const bytemap* map) {
|
|
683
|
+
return map ? map->size : 0;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
static inline bytemap* c_bytemap_ex_clone(const bytemap* src, allocator_protocol* allocator) {
|
|
687
|
+
if (!src) return NULL;
|
|
688
|
+
|
|
689
|
+
bytemap* dst = c_bytemap_ex_new(src->capacity, src->slot_capacity, allocator);
|
|
690
|
+
if (!dst) return NULL;
|
|
691
|
+
|
|
692
|
+
dst->salt = src->salt;
|
|
693
|
+
|
|
694
|
+
for (bytemap_entry* e = src->first; e; e = e->next) {
|
|
695
|
+
if (!e->occupied) continue;
|
|
696
|
+
int ret = c_bytemap_ex_set(dst, e->key, e->key_length, e->value, e->value_length, 0, NULL);
|
|
697
|
+
if (ret != BYTEMAP_OK) {
|
|
698
|
+
c_bytemap_ex_free(dst);
|
|
699
|
+
return NULL;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
return dst;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// ========== Predefined typed helpers (double) ==========
|
|
707
|
+
|
|
708
|
+
static inline int c_bytemap_ex_set_double(bytemap* map, const char* key, size_t key_len, double value, uint64_t seq_id) {
|
|
709
|
+
return c_bytemap_ex_set(map, key, key_len, (const char*) &value, sizeof(double), seq_id, NULL);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
static inline int c_bytemap_ex_get_double(const bytemap* map, const char* key, size_t key_len, double* out) {
|
|
713
|
+
return c_bytemap_ex_get(map, key, key_len, (char*) out, NULL);
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
static inline int c_bytemap_ex_pop_double(bytemap* map, const char* key, size_t key_len, uint64_t seq_id, double* out) {
|
|
717
|
+
return c_bytemap_ex_pop(map, key, key_len, seq_id, (char*) out, NULL);
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
// ========== bytemap void* convenience wrappers ==========
|
|
721
|
+
// These call the bytemap_ex (primary) functions with slot_capacity=sizeof(void*)
|
|
722
|
+
// and perform void* <-> raw bytes conversion.
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* @brief Create a new bytemap (void* variant).
|
|
726
|
+
* Equivalent to c_bytemap_ex_new(capacity, sizeof(void*), allocator).
|
|
727
|
+
*/
|
|
728
|
+
static inline bytemap* c_bytemap_new(size_t capacity, allocator_protocol* allocator) {
|
|
729
|
+
return c_bytemap_ex_new(capacity, sizeof(void*), allocator);
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* @brief Clear all entries from a bytemap (void* variant).
|
|
734
|
+
*/
|
|
735
|
+
static inline void c_bytemap_clear(bytemap* map) {
|
|
736
|
+
c_bytemap_ex_clear(map);
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
/**
|
|
740
|
+
* @brief Free a bytemap (void* variant).
|
|
741
|
+
*/
|
|
742
|
+
static inline void c_bytemap_free(bytemap* map) {
|
|
743
|
+
c_bytemap_ex_free(map);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* @brief Register a callback on a bytemap (void* variant).
|
|
748
|
+
*/
|
|
749
|
+
static inline int c_bytemap_register_callback(bytemap* map, bytemap_callback_func callback, void* user_data, uintptr_t* out_id) {
|
|
750
|
+
return c_bytemap_ex_register_callback(map, callback, user_data, out_id);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
/**
|
|
754
|
+
* @brief Unregister a callback from a bytemap (void* variant).
|
|
755
|
+
*/
|
|
756
|
+
static inline int c_bytemap_unregister_callback(bytemap* map, uintptr_t callback_id) {
|
|
757
|
+
return c_bytemap_ex_unregister_callback(map, callback_id);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/**
|
|
761
|
+
* @brief Get a void* value from a bytemap by key.
|
|
762
|
+
*/
|
|
763
|
+
static inline int c_bytemap_get(const bytemap* map, const char* key, size_t key_len, void** out) {
|
|
764
|
+
return c_bytemap_ex_get(map, key, key_len, (char*) out, NULL);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* @brief Test whether a key exists in a bytemap.
|
|
769
|
+
*/
|
|
770
|
+
static inline int c_bytemap_contains(const bytemap* map, const char* key, size_t key_len) {
|
|
771
|
+
return c_bytemap_ex_contains(map, key, key_len);
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
/**
|
|
775
|
+
* @brief Rehash a bytemap to a new capacity.
|
|
776
|
+
*/
|
|
777
|
+
static inline int c_bytemap_rehash(bytemap* map, size_t new_capacity) {
|
|
778
|
+
return c_bytemap_ex_rehash(map, new_capacity, 0);
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
/**
|
|
782
|
+
* @brief Insert or update a key/value pair in a bytemap (void* variant).
|
|
783
|
+
*
|
|
784
|
+
* @param seq_id Sequence ID for callback self-suppression.
|
|
785
|
+
*/
|
|
786
|
+
static inline int c_bytemap_set(bytemap* map, const char* key, size_t key_len, void* value, bytemap_entry** out) {
|
|
787
|
+
return c_bytemap_ex_set(map, key, key_len, (const char*) &value, sizeof(void*), 0, out);
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
/**
|
|
791
|
+
* @brief Remove a key from a bytemap, returning its void* value.
|
|
792
|
+
*/
|
|
793
|
+
static inline int c_bytemap_pop(bytemap* map, const char* key, size_t key_len, void** out) {
|
|
794
|
+
return c_bytemap_ex_pop(map, key, key_len, 0, (char*) out, NULL);
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* @brief Get the number of live entries.
|
|
799
|
+
*/
|
|
800
|
+
static inline size_t c_bytemap_len(const bytemap* map) {
|
|
801
|
+
return c_bytemap_ex_len(map);
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
/**
|
|
805
|
+
* @brief Deep-clone a bytemap instance (void* variant).
|
|
806
|
+
*/
|
|
807
|
+
static inline bytemap* c_bytemap_clone(const bytemap* src, allocator_protocol* allocator) {
|
|
808
|
+
return c_bytemap_ex_clone(src, allocator);
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
// ========== Iteration helpers (void* variant) ==========
|
|
812
|
+
|
|
813
|
+
static inline bytemap_entry* c_bytemap_first(const bytemap* map) {
|
|
814
|
+
return c_bytemap_entry_first(map);
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
static inline bytemap_entry* c_bytemap_last(const bytemap* map) {
|
|
818
|
+
return map ? map->last : NULL;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
static inline bytemap_entry* c_bytemap_next(const bytemap_entry* entry) {
|
|
822
|
+
return entry ? entry->next : NULL;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
static inline bytemap_entry* c_bytemap_prev(const bytemap_entry* entry) {
|
|
826
|
+
return entry ? entry->prev : NULL;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
/**
|
|
830
|
+
* @brief Convenience: get the void* value from an entry.
|
|
831
|
+
*/
|
|
832
|
+
static inline void* c_bytemap_entry_value(const bytemap_entry* entry) {
|
|
833
|
+
if (!entry || !entry->occupied) return NULL;
|
|
834
|
+
return *(void**) entry->value;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
/**
|
|
838
|
+
* @brief Raw unchecked extraction of void* value from an entry.
|
|
839
|
+
*
|
|
840
|
+
* No NULL or occupancy checks — caller must ensure the entry is valid.
|
|
841
|
+
* Intended for tight inner loops where safety is guaranteed by context.
|
|
842
|
+
*/
|
|
843
|
+
static inline void* c_bytemap_entry_value_as_ptr(const bytemap_entry* entry) {
|
|
844
|
+
return *(void**) entry->value;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
static inline uintptr_t c_bytemap_entry_value_as_uintptr(const bytemap_entry* entry) {
|
|
848
|
+
return (uintptr_t) *(void**) entry->value;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
static inline double c_bytemap_entry_value_as_double(const bytemap_entry* entry) {
|
|
852
|
+
return *(double*) entry->value;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
static inline void c_bytemap_entry_value_from_ptr(bytemap_entry* entry, const void* ptr) {
|
|
856
|
+
memcpy(entry->value, &ptr, sizeof(void*));
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
static inline void c_bytemap_entry_value_from_uintptr(bytemap_entry* entry, uintptr_t val) {
|
|
860
|
+
c_bytemap_entry_value_from_ptr(entry, (const void*) val);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
static inline void c_bytemap_entry_value_from_double(bytemap_entry* entry, double val) {
|
|
864
|
+
memcpy(entry->value, &val, sizeof(double));
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
#endif // C_CBASE_BYTEMAP_H
|