PyCyBase 0.1.10__cp315-cp315-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.
Files changed (105) hide show
  1. cbase/__infra__.pxd +6 -0
  2. cbase/__init__.pxd +6 -0
  3. cbase/__init__.py +31 -0
  4. cbase/allocator_protocol/__infra__.pxd +65 -0
  5. cbase/allocator_protocol/__init__.pxd +65 -0
  6. cbase/allocator_protocol/__init__.py +45 -0
  7. cbase/allocator_protocol/c_allocator_protocol.c +31874 -0
  8. cbase/allocator_protocol/c_allocator_protocol.cp315-win_amd64.pyd +0 -0
  9. cbase/allocator_protocol/c_allocator_protocol.h +352 -0
  10. cbase/allocator_protocol/c_allocator_protocol.pxd +66 -0
  11. cbase/allocator_protocol/c_allocator_protocol.pyi +144 -0
  12. cbase/allocator_protocol/c_allocator_protocol.pyx +209 -0
  13. cbase/allocator_protocol/c_heap_allocator.c +38225 -0
  14. cbase/allocator_protocol/c_heap_allocator.cp315-win_amd64.pyd +0 -0
  15. cbase/allocator_protocol/c_heap_allocator.h +554 -0
  16. cbase/allocator_protocol/c_heap_allocator.pxd +105 -0
  17. cbase/allocator_protocol/c_heap_allocator.pyi +161 -0
  18. cbase/allocator_protocol/c_heap_allocator.pyx +303 -0
  19. cbase/allocator_protocol/c_nt_shm_allocator.c +33455 -0
  20. cbase/allocator_protocol/c_nt_shm_allocator.cp315-win_amd64.pyd +0 -0
  21. cbase/allocator_protocol/c_nt_shm_allocator.h +1105 -0
  22. cbase/allocator_protocol/c_nt_shm_allocator.pxd +110 -0
  23. cbase/allocator_protocol/c_nt_shm_allocator.pyx +223 -0
  24. cbase/allocator_protocol/c_shm_allocator.h +1270 -0
  25. cbase/allocator_protocol/c_shm_allocator.pxd +150 -0
  26. cbase/allocator_protocol/c_shm_allocator.pyi +299 -0
  27. cbase/allocator_protocol/c_shm_allocator.pyx +445 -0
  28. cbase/allocator_protocol/c_shm_comp.c +4654 -0
  29. cbase/allocator_protocol/c_shm_comp.cp315-win_amd64.pyd +0 -0
  30. cbase/allocator_protocol/c_shm_comp.h +49 -0
  31. cbase/allocator_protocol/c_shm_comp.pxd +46 -0
  32. cbase/allocator_protocol/c_shm_comp.pyx +1 -0
  33. cbase/backports/__infra__.pxd +17 -0
  34. cbase/backports/__init__.pxd +17 -0
  35. cbase/backports/__init__.py +9 -0
  36. cbase/backports/pydict.h +55 -0
  37. cbase/backports/pydict.pxd +5 -0
  38. cbase/backports/pylong.c +9965 -0
  39. cbase/backports/pylong.cp315-win_amd64.pyd +0 -0
  40. cbase/backports/pylong.h +79 -0
  41. cbase/backports/pylong.pxd +23 -0
  42. cbase/backports/pylong.pyx +61 -0
  43. cbase/bytemap/__infra__.pxd +42 -0
  44. cbase/bytemap/__init__.pxd +42 -0
  45. cbase/bytemap/__init__.py +21 -0
  46. cbase/bytemap/c_bytemap.c +52151 -0
  47. cbase/bytemap/c_bytemap.cp315-win_amd64.pyd +0 -0
  48. cbase/bytemap/c_bytemap.h +867 -0
  49. cbase/bytemap/c_bytemap.pxd +370 -0
  50. cbase/bytemap/c_bytemap.pyx +1760 -0
  51. cbase/bytemap/xxh3.h +55 -0
  52. cbase/bytemap/xxhash.c +42 -0
  53. cbase/bytemap/xxhash.h +7487 -0
  54. cbase/config_view.c +7253 -0
  55. cbase/config_view.cp315-win_amd64.pyd +0 -0
  56. cbase/config_view.pyx +85 -0
  57. cbase/env.c +11120 -0
  58. cbase/env.cp315-win_amd64.pyd +0 -0
  59. cbase/env.pxd +8 -0
  60. cbase/env.pyi +48 -0
  61. cbase/env.pyx +46 -0
  62. cbase/includes/cbase/allocator_protocol/c_allocator_protocol.c +31874 -0
  63. cbase/includes/cbase/allocator_protocol/c_allocator_protocol.h +352 -0
  64. cbase/includes/cbase/allocator_protocol/c_heap_allocator.c +38225 -0
  65. cbase/includes/cbase/allocator_protocol/c_heap_allocator.h +554 -0
  66. cbase/includes/cbase/allocator_protocol/c_nt_shm_allocator.c +33455 -0
  67. cbase/includes/cbase/allocator_protocol/c_nt_shm_allocator.h +1105 -0
  68. cbase/includes/cbase/allocator_protocol/c_shm_allocator.h +1270 -0
  69. cbase/includes/cbase/allocator_protocol/c_shm_comp.c +4654 -0
  70. cbase/includes/cbase/allocator_protocol/c_shm_comp.h +49 -0
  71. cbase/includes/cbase/backports/pydict.h +55 -0
  72. cbase/includes/cbase/backports/pylong.c +9965 -0
  73. cbase/includes/cbase/backports/pylong.h +79 -0
  74. cbase/includes/cbase/bytemap/c_bytemap.c +52151 -0
  75. cbase/includes/cbase/bytemap/c_bytemap.h +867 -0
  76. cbase/includes/cbase/bytemap/xxh3.h +55 -0
  77. cbase/includes/cbase/bytemap/xxhash.c +42 -0
  78. cbase/includes/cbase/bytemap/xxhash.h +7487 -0
  79. cbase/includes/cbase/config_view.c +7253 -0
  80. cbase/includes/cbase/env.c +11120 -0
  81. cbase/includes/cbase/int128.h +81 -0
  82. cbase/includes/cbase/intern_string/c_intern_string.c +28138 -0
  83. cbase/includes/cbase/intern_string/c_intern_string.h +614 -0
  84. cbase/includes/cbase/nt/pthread_nt_compat.h +102 -0
  85. cbase/includes/cbase/nt/regex_nt_compat.h +133 -0
  86. cbase/includes/cbase/nt/time_sched_nt_compat.h +32 -0
  87. cbase/int128.h +81 -0
  88. cbase/int128.pxd +15 -0
  89. cbase/intern_string/BENCHMARK.md +157 -0
  90. cbase/intern_string/__infra__.pxd +13 -0
  91. cbase/intern_string/__init__.pxd +13 -0
  92. cbase/intern_string/__init__.py +19 -0
  93. cbase/intern_string/c_intern_string.c +28138 -0
  94. cbase/intern_string/c_intern_string.cp315-win_amd64.pyd +0 -0
  95. cbase/intern_string/c_intern_string.h +614 -0
  96. cbase/intern_string/c_intern_string.pxd +121 -0
  97. cbase/intern_string/c_intern_string.pyi +376 -0
  98. cbase/intern_string/c_intern_string.pyx +765 -0
  99. cbase/nt/pthread_nt_compat.h +102 -0
  100. cbase/nt/regex_nt_compat.h +133 -0
  101. cbase/nt/time_sched_nt_compat.h +32 -0
  102. pycybase-0.1.10.dist-info/METADATA +190 -0
  103. pycybase-0.1.10.dist-info/RECORD +105 -0
  104. pycybase-0.1.10.dist-info/WHEEL +5 -0
  105. pycybase-0.1.10.dist-info/top_level.txt +1 -0
@@ -0,0 +1,554 @@
1
+ #ifndef AP_HEAP_C_HEAP_ALLOCATOR_H
2
+ #define AP_HEAP_C_HEAP_ALLOCATOR_H
3
+
4
+ #include <errno.h>
5
+ #include <stddef.h>
6
+ #include <stdint.h>
7
+ #include <stdlib.h>
8
+ #include <string.h>
9
+
10
+ #ifdef _WIN32
11
+ #include "cbase/nt/pthread_nt_compat.h"
12
+ #include <intrin.h>
13
+ #else
14
+ #include <pthread.h>
15
+ #endif
16
+
17
+ // ========== Configuration ==========
18
+
19
+ #ifndef AP_HEAP_AUTOPAGE_CAPACITY
20
+ #define AP_HEAP_AUTOPAGE_CAPACITY (64 * 1024) /* 64 KiB */
21
+ #endif
22
+
23
+ #ifndef AP_HEAP_AUTOPAGE_CAPACITY_MAX
24
+ #define AP_HEAP_AUTOPAGE_CAPACITY_MAX (16 * 1024 * 1024) /* 16 MiB */
25
+ #endif
26
+
27
+ #ifndef AP_HEAP_AUTOPAGE_ALIGNMENT
28
+ #define AP_HEAP_AUTOPAGE_ALIGNMENT (4 * 1024) /* 4 KiB */
29
+ #endif
30
+
31
+ /* Size-binned free lists: exact 8-byte-granular bins for capacities up to
32
+ * AP_HEAP_EXACT_BIN_COUNT * 8 bytes, pow2-class bins above. */
33
+ #ifndef AP_HEAP_EXACT_BIN_COUNT
34
+ #define AP_HEAP_EXACT_BIN_COUNT 8192 /* capacity <= 64 KiB gets an exact bin */
35
+ #endif
36
+
37
+ #ifndef AP_HEAP_LARGE_BIN_COUNT
38
+ #define AP_HEAP_LARGE_BIN_COUNT 9 /* pow2-class bins for capacity > 64 KiB */
39
+ #endif
40
+
41
+ #define AP_HEAP_BIN_COUNT (AP_HEAP_EXACT_BIN_COUNT + AP_HEAP_LARGE_BIN_COUNT + 1)
42
+
43
+ /* Miss-path page scaling cap: page sizes double from the current page up
44
+ * to this cap; a request larger than the cap forces a bigger page.
45
+ * Used only when AP_HEAP_PAGE_FIT_TO_REQUEST is 0. */
46
+ #ifndef AP_HEAP_PAGE_EXTEND_MAX
47
+ #define AP_HEAP_PAGE_EXTEND_MAX (128 * 1024 * 1024) /* 128 MiB */
48
+ #endif
49
+
50
+ /* Miss-path page policy: 0 (default) = capped power-of-2 page scaling
51
+ * (see AP_HEAP_PAGE_EXTEND_MAX); 1 = fit the page to the request (floor
52
+ * = autopage_capacity) so rare bin misses never extend oversized pages. */
53
+ #ifndef AP_HEAP_PAGE_FIT_TO_REQUEST
54
+ #define AP_HEAP_PAGE_FIT_TO_REQUEST 0
55
+ #endif
56
+
57
+ /* On an exact-bin miss, probe up to this many LARGER exact bins before
58
+ * the page path. A slightly larger block satisfies the request; on free
59
+ * it returns to its own bin (recycling unaffected), and the fragmentation
60
+ * is bounded by the probe range. 0 disables the probe. */
61
+ #ifndef AP_HEAP_EXACT_BIN_PROBE_COUNT
62
+ #define AP_HEAP_EXACT_BIN_PROBE_COUNT 2
63
+ #endif
64
+
65
+ // ========== Heap Allocator Structs ==========
66
+
67
+ typedef struct heap_memory_block {
68
+ size_t capacity;
69
+ size_t size;
70
+ struct heap_memory_block* next_free;
71
+ struct heap_memory_block* next_allocated;
72
+ struct heap_page* parent_page;
73
+ char buffer[];
74
+ } heap_memory_block;
75
+
76
+ typedef struct heap_page {
77
+ size_t capacity;
78
+ size_t occupied;
79
+ struct heap_allocator* allocator;
80
+ struct heap_page* prev;
81
+ struct heap_memory_block* allocated;
82
+ char buffer[];
83
+ } heap_page;
84
+
85
+ typedef struct heap_allocator {
86
+ pthread_mutex_t lock;
87
+ size_t mapped_pages;
88
+ struct heap_page* active_page;
89
+ size_t autopage_capacity;
90
+ size_t autopage_capacity_max;
91
+ size_t autopage_alignment;
92
+ struct heap_memory_block* bins[AP_HEAP_BIN_COUNT];
93
+ } heap_allocator;
94
+
95
+ // ========== Utility Functions ==========
96
+
97
+ static inline size_t c_heap_page_roundup(heap_allocator* allocator, size_t size) {
98
+ return (size + allocator->autopage_alignment - 1) & ~(allocator->autopage_alignment - 1);
99
+ }
100
+
101
+ static inline size_t c_heap_block_roundup(size_t size) {
102
+ return (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
103
+ }
104
+
105
+ /* ceil(log2(v)) for 0 < v <= UINT32_MAX (portable; intrinsics on MSVC/GCC-Clang).
106
+ * 32-bit is sufficient: the bin structure caps block capacities well below
107
+ * 4 GiB, so a narrower parameter type truthfully advertises the domain. */
108
+ static inline size_t c_heap_block_ceil_log2(uint32_t v) {
109
+ size_t floor;
110
+ #if defined(_MSC_VER)
111
+ unsigned long idx = 0;
112
+ _BitScanReverse(&idx, (unsigned long) v);
113
+ floor = (size_t) idx;
114
+ #else
115
+ floor = (size_t) (31u - __builtin_clz((unsigned int) v));
116
+ #endif
117
+ return floor + (v != ((size_t) 1u << floor));
118
+ }
119
+
120
+ /* Size bin for a block capacity (always a multiple of 8).
121
+ * Exact bins: index = capacity / 8 (1..AP_HEAP_EXACT_BIN_COUNT), so any
122
+ * block in bin(cap_net) has capacity == cap_net and always fits.
123
+ * Larger capacities: pow2-class bins keyed by ceil(log2(capacity))
124
+ * (indices AP_HEAP_EXACT_BIN_COUNT+1..); the last bin is the overflow
125
+ * class. In-bin first-fit is used there (blocks can be up to one class
126
+ * smaller than the request). */
127
+ static inline size_t c_heap_block_bin(size_t capacity) {
128
+ if (capacity <= (size_t) AP_HEAP_EXACT_BIN_COUNT * 8u) {
129
+ return capacity >> 3;
130
+ }
131
+ size_t idx = (size_t) AP_HEAP_EXACT_BIN_COUNT + (c_heap_block_ceil_log2(capacity) - 16u);
132
+ if (idx > (size_t) AP_HEAP_EXACT_BIN_COUNT + AP_HEAP_LARGE_BIN_COUNT) {
133
+ idx = (size_t) AP_HEAP_EXACT_BIN_COUNT + AP_HEAP_LARGE_BIN_COUNT;
134
+ }
135
+ return idx;
136
+ }
137
+
138
+ static inline void c_heap_page_reclaim(heap_allocator* allocator, heap_page* page) {
139
+ if (!allocator || !page) {
140
+ errno = EINVAL;
141
+ return;
142
+ }
143
+
144
+ heap_memory_block** prevp = &page->allocated;
145
+ while (*prevp) {
146
+ heap_memory_block* block = *prevp;
147
+ if (block->size != 0) {
148
+ break;
149
+ }
150
+
151
+ *prevp = block->next_allocated;
152
+ block->next_allocated = NULL;
153
+
154
+ heap_memory_block** free_prev = &allocator->bins[c_heap_block_bin(block->capacity)];
155
+ while (*free_prev && *free_prev != block) {
156
+ free_prev = &(*free_prev)->next_free;
157
+ }
158
+ if (*free_prev == block) {
159
+ *free_prev = block->next_free;
160
+ }
161
+ block->next_free = NULL;
162
+
163
+ size_t cap_total = block->capacity + sizeof(heap_memory_block);
164
+ if (page->occupied >= cap_total) {
165
+ page->occupied -= cap_total;
166
+ }
167
+ }
168
+ }
169
+
170
+ // ========== Public API Functions ==========
171
+
172
+ static inline heap_page* c_heap_allocator_extend(heap_allocator* allocator, size_t capacity, pthread_mutex_t* lock) {
173
+ if (!allocator) {
174
+ errno = EINVAL;
175
+ return NULL;
176
+ }
177
+
178
+ uint8_t locked = 0;
179
+
180
+ if (lock) {
181
+ int ret = pthread_mutex_lock(lock);
182
+ if (ret != 0) {
183
+ errno = ret;
184
+ return NULL;
185
+ }
186
+ locked = 1;
187
+ }
188
+
189
+ if (capacity == 0) {
190
+ if (!allocator->active_page) {
191
+ capacity = allocator->autopage_capacity;
192
+ }
193
+ else {
194
+ size_t prev_cap = allocator->active_page->capacity;
195
+ capacity = prev_cap * 2;
196
+ if (capacity < allocator->autopage_capacity) {
197
+ capacity = allocator->autopage_capacity;
198
+ }
199
+ else if (capacity > allocator->autopage_capacity_max) {
200
+ capacity = allocator->autopage_capacity_max;
201
+ }
202
+ }
203
+ }
204
+
205
+ size_t total_capacity = c_heap_page_roundup(allocator, capacity);
206
+
207
+ heap_page* page = (heap_page*) calloc(1, total_capacity);
208
+
209
+ if (!page) {
210
+ if (locked) pthread_mutex_unlock(lock);
211
+ return NULL;
212
+ }
213
+
214
+ page->capacity = total_capacity;
215
+ page->occupied = sizeof(heap_page);
216
+ page->allocator = allocator;
217
+ page->allocated = NULL;
218
+ page->prev = allocator->active_page;
219
+ allocator->active_page = page;
220
+ allocator->mapped_pages++;
221
+
222
+ if (locked) pthread_mutex_unlock(lock);
223
+ return page;
224
+ }
225
+
226
+ static inline heap_allocator* c_heap_allocator_new() {
227
+ heap_allocator* allocator = (heap_allocator*) calloc(1, sizeof(heap_allocator));
228
+ if (!allocator) {
229
+ return NULL;
230
+ }
231
+
232
+ if (pthread_mutex_init(&allocator->lock, NULL) != 0) {
233
+ free(allocator);
234
+ return NULL;
235
+ }
236
+
237
+ allocator->mapped_pages = 0;
238
+ allocator->active_page = NULL;
239
+ allocator->autopage_capacity = AP_HEAP_AUTOPAGE_CAPACITY;
240
+ allocator->autopage_capacity_max = AP_HEAP_AUTOPAGE_CAPACITY_MAX;
241
+ allocator->autopage_alignment = AP_HEAP_AUTOPAGE_ALIGNMENT;
242
+
243
+ return allocator;
244
+ }
245
+
246
+ static inline void c_heap_allocator_free(heap_allocator* allocator) {
247
+ if (!allocator) {
248
+ return;
249
+ }
250
+
251
+ heap_page* page = allocator->active_page;
252
+ while (page) {
253
+ heap_page* prev = page->prev;
254
+ free(page);
255
+ page = prev;
256
+ }
257
+
258
+ pthread_mutex_destroy(&allocator->lock);
259
+ free(allocator);
260
+ }
261
+
262
+ static inline void* c_heap_calloc(heap_allocator* allocator, size_t size, pthread_mutex_t* lock) {
263
+ if (!allocator || size == 0) {
264
+ errno = EINVAL;
265
+ return NULL;
266
+ }
267
+
268
+ size_t cap_net = c_heap_block_roundup(size);
269
+ size_t overhead = sizeof(heap_memory_block);
270
+ size_t cap_total = cap_net + overhead;
271
+
272
+ uint8_t locked = 0;
273
+ pthread_mutex_t* builtin_lock = &allocator->lock;
274
+ pthread_mutex_t* child_lock = &allocator->lock;
275
+ if (lock) {
276
+ if (lock == builtin_lock) {
277
+ child_lock = NULL;
278
+ }
279
+ int ret = pthread_mutex_lock(lock);
280
+ if (ret != 0) {
281
+ errno = ret;
282
+ return NULL;
283
+ }
284
+ locked = 1;
285
+ }
286
+ else {
287
+ child_lock = NULL;
288
+ }
289
+
290
+ heap_page* page = allocator->active_page;
291
+ if (!page) {
292
+ size_t target_cap = allocator->autopage_capacity;
293
+ while (target_cap < cap_total + sizeof(heap_page)) {
294
+ target_cap *= 2;
295
+ }
296
+
297
+ page = c_heap_allocator_extend(allocator, target_cap, child_lock);
298
+ if (!page) {
299
+ if (locked) pthread_mutex_unlock(lock);
300
+ return NULL;
301
+ }
302
+ }
303
+
304
+ if (page->occupied + cap_total > page->capacity) {
305
+ size_t target_cap = page->capacity;
306
+
307
+ if (target_cap < allocator->autopage_capacity) {
308
+ target_cap = allocator->autopage_capacity;
309
+ }
310
+ else if (target_cap < allocator->autopage_capacity_max) {
311
+ target_cap *= 2;
312
+ }
313
+
314
+ while (target_cap < cap_total + sizeof(heap_page)) {
315
+ target_cap *= 2;
316
+ }
317
+ page = c_heap_allocator_extend(allocator, target_cap, child_lock);
318
+ if (!page) {
319
+ if (locked) pthread_mutex_unlock(lock);
320
+ return NULL;
321
+ }
322
+ }
323
+
324
+ size_t offset = page->occupied;
325
+ heap_memory_block* block = (heap_memory_block*) ((char*) page + offset);
326
+ block->capacity = cap_net;
327
+ block->size = size;
328
+ block->next_free = NULL;
329
+
330
+ block->parent_page = page;
331
+ block->next_allocated = page->allocated;
332
+ page->allocated = block;
333
+ page->occupied += cap_total;
334
+
335
+ if (locked) pthread_mutex_unlock(lock);
336
+
337
+ memset(block + 1, 0, cap_net);
338
+ return (void*) block->buffer;
339
+ }
340
+
341
+ static inline void* c_heap_request(heap_allocator* allocator, size_t size, int scan_all_pages, pthread_mutex_t* lock) {
342
+ if (!allocator || size == 0) {
343
+ errno = EINVAL;
344
+ return NULL;
345
+ }
346
+
347
+ size_t cap_net = c_heap_block_roundup(size);
348
+ size_t overhead = sizeof(heap_memory_block);
349
+ size_t cap_total = cap_net + overhead;
350
+
351
+ uint8_t locked = 0;
352
+ pthread_mutex_t* builtin_lock = &allocator->lock;
353
+ pthread_mutex_t* child_lock = &allocator->lock;
354
+ if (lock) {
355
+ if (lock == builtin_lock) {
356
+ child_lock = NULL;
357
+ }
358
+ int ret = pthread_mutex_lock(lock);
359
+ if (ret != 0) {
360
+ errno = ret;
361
+ return NULL;
362
+ }
363
+ locked = 1;
364
+ }
365
+ else {
366
+ child_lock = NULL;
367
+ }
368
+
369
+ /* Step 1: size-binned free-list reuse (see c_heap_block_bin).
370
+ * Exact bins always fit (capacity == cap_net) — O(1) head pop.
371
+ * Pow2-class bins use in-bin first-fit: bins are short and same-
372
+ * shaped, so the head is the common hit; larger-capacity blocks in
373
+ * the bin also satisfy smaller requests. */
374
+ size_t bin = c_heap_block_bin(cap_net);
375
+ heap_memory_block* free_blk;
376
+ if (bin <= (size_t) AP_HEAP_EXACT_BIN_COUNT) {
377
+ size_t found = bin;
378
+ free_blk = allocator->bins[bin];
379
+ if (!free_blk && AP_HEAP_EXACT_BIN_PROBE_COUNT > 0) {
380
+ size_t probe_end = bin + (size_t) AP_HEAP_EXACT_BIN_PROBE_COUNT;
381
+ if (probe_end > (size_t) AP_HEAP_EXACT_BIN_COUNT) {
382
+ probe_end = (size_t) AP_HEAP_EXACT_BIN_COUNT;
383
+ }
384
+ for (size_t b = bin + 1; b <= probe_end; b++) {
385
+ free_blk = allocator->bins[b];
386
+ if (free_blk) {
387
+ found = b;
388
+ break;
389
+ }
390
+ }
391
+ }
392
+ if (free_blk) {
393
+ allocator->bins[found] = free_blk->next_free;
394
+ free_blk->next_free = NULL;
395
+ free_blk->size = size;
396
+ if (locked) pthread_mutex_unlock(lock);
397
+ memset(free_blk + 1, 0, cap_net);
398
+ return (void*) free_blk->buffer;
399
+ }
400
+ }
401
+ else {
402
+ heap_memory_block** prevp = &allocator->bins[bin];
403
+ free_blk = *prevp;
404
+ while (free_blk) {
405
+ if (free_blk->capacity >= cap_net) {
406
+ *prevp = free_blk->next_free;
407
+ free_blk->next_free = NULL;
408
+ free_blk->size = size;
409
+ if (locked) pthread_mutex_unlock(lock);
410
+ memset(free_blk + 1, 0, cap_net);
411
+ return (void*) free_blk->buffer;
412
+ }
413
+ prevp = &free_blk->next_free;
414
+ free_blk = free_blk->next_free;
415
+ }
416
+ }
417
+
418
+ heap_page* target_page = NULL;
419
+ if (scan_all_pages) {
420
+ heap_page* iter = allocator->active_page;
421
+ while (iter) {
422
+ if (iter->occupied + cap_total <= iter->capacity) {
423
+ target_page = iter;
424
+ break;
425
+ }
426
+ iter = iter->prev;
427
+ }
428
+ }
429
+ else if (allocator->active_page) {
430
+ heap_page* meta = allocator->active_page;
431
+ if (meta && meta->occupied + cap_total <= meta->capacity) {
432
+ target_page = allocator->active_page;
433
+ }
434
+ }
435
+
436
+ if (!target_page) {
437
+ size_t target_cap;
438
+ #if AP_HEAP_PAGE_FIT_TO_REQUEST
439
+ /* Fit the page to the request (floor = autopage_capacity): rare
440
+ * bin misses must not extend oversized pages. */
441
+ target_cap = allocator->autopage_capacity;
442
+ #else
443
+ /* Page scaling with a cap: double from the current page size up to
444
+ * AP_HEAP_PAGE_EXTEND_MAX. A page larger than the cap (e.g. from
445
+ * a huge request) scales back down to the cap. Requests larger
446
+ * than the cap force a bigger page via the fit loop below. */
447
+ heap_page* current = allocator->active_page;
448
+ if (!current) {
449
+ target_cap = allocator->autopage_capacity;
450
+ }
451
+ else {
452
+ target_cap = current->capacity;
453
+ if (target_cap < allocator->autopage_capacity) {
454
+ target_cap = allocator->autopage_capacity;
455
+ }
456
+ else if (target_cap > (size_t) AP_HEAP_PAGE_EXTEND_MAX) {
457
+ target_cap = (size_t) AP_HEAP_PAGE_EXTEND_MAX;
458
+ }
459
+ else if (target_cap < (size_t) AP_HEAP_PAGE_EXTEND_MAX) {
460
+ target_cap *= 2;
461
+ if (target_cap > (size_t) AP_HEAP_PAGE_EXTEND_MAX) {
462
+ target_cap = (size_t) AP_HEAP_PAGE_EXTEND_MAX;
463
+ }
464
+ }
465
+ }
466
+ #endif
467
+ while (target_cap < cap_total + sizeof(heap_page)) {
468
+ target_cap *= 2;
469
+ }
470
+
471
+ target_page = c_heap_allocator_extend(allocator, target_cap, child_lock);
472
+ if (!target_page) {
473
+ if (locked) pthread_mutex_unlock(lock);
474
+ return NULL;
475
+ }
476
+ }
477
+
478
+ size_t offset = target_page->occupied;
479
+ heap_memory_block* block = (heap_memory_block*) ((char*) target_page + offset);
480
+ block->capacity = cap_net;
481
+ block->size = size;
482
+ block->next_free = NULL;
483
+
484
+ block->parent_page = target_page;
485
+ block->next_allocated = target_page->allocated;
486
+ target_page->allocated = block;
487
+
488
+ target_page->occupied += cap_total;
489
+
490
+ if (locked) pthread_mutex_unlock(lock);
491
+
492
+ memset(block + 1, 0, cap_net);
493
+ return (void*) block->buffer;
494
+ }
495
+
496
+ static inline void c_heap_free(void* ptr, pthread_mutex_t* lock) {
497
+ if (!ptr) {
498
+ errno = EINVAL;
499
+ return;
500
+ }
501
+
502
+ heap_memory_block* block = (heap_memory_block*) ((char*) ptr - sizeof(heap_memory_block));
503
+ heap_page* page = block->parent_page;
504
+ if (!page || !page->allocator) {
505
+ errno = EINVAL;
506
+ return;
507
+ }
508
+
509
+ heap_allocator* allocator = page->allocator;
510
+
511
+ uint8_t locked = 0;
512
+ if (lock) {
513
+ int ret = pthread_mutex_lock(lock);
514
+ if (ret != 0) {
515
+ errno = ret;
516
+ return;
517
+ }
518
+ locked = 1;
519
+ }
520
+
521
+ block->size = 0;
522
+ size_t bin = c_heap_block_bin(block->capacity);
523
+ block->next_free = allocator->bins[bin];
524
+ allocator->bins[bin] = block;
525
+
526
+ if (locked) pthread_mutex_unlock(lock);
527
+ }
528
+
529
+ static inline void c_heap_reclaim(heap_allocator* allocator, pthread_mutex_t* lock) {
530
+ if (!allocator) {
531
+ errno = EINVAL;
532
+ return;
533
+ }
534
+
535
+ uint8_t locked = 0;
536
+ if (lock) {
537
+ int ret = pthread_mutex_lock(lock);
538
+ if (ret != 0) {
539
+ errno = ret;
540
+ return;
541
+ }
542
+ locked = 1;
543
+ }
544
+
545
+ heap_page* page = allocator->active_page;
546
+ while (page) {
547
+ c_heap_page_reclaim(allocator, page);
548
+ page = page->prev;
549
+ }
550
+
551
+ if (locked) pthread_mutex_unlock(lock);
552
+ }
553
+
554
+ #endif /* AP_HEAP_C_HEAP_ALLOCATOR_H */
@@ -0,0 +1,105 @@
1
+
2
+ cdef extern from "cbase/allocator_protocol/c_heap_allocator.h":
3
+ const size_t AP_HEAP_AUTOPAGE_CAPACITY
4
+ const size_t AP_HEAP_AUTOPAGE_CAPACITY_MAX
5
+ const size_t AP_HEAP_AUTOPAGE_ALIGNMENT
6
+ const size_t AP_HEAP_EXACT_BIN_COUNT
7
+ const size_t AP_HEAP_LARGE_BIN_COUNT
8
+ const size_t AP_HEAP_BIN_COUNT
9
+ const size_t AP_HEAP_PAGE_EXTEND_MAX
10
+ const size_t AP_HEAP_PAGE_FIT_TO_REQUEST
11
+ const size_t AP_HEAP_EXACT_BIN_PROBE_COUNT
12
+
13
+ ctypedef struct pthread_mutex_t:
14
+ pass
15
+
16
+ ctypedef struct heap_memory_block:
17
+ size_t capacity
18
+ size_t size
19
+ heap_memory_block* next_free
20
+ heap_memory_block* next_allocated
21
+ heap_page* parent_page
22
+ char buffer[]
23
+
24
+ ctypedef struct heap_page:
25
+ size_t capacity
26
+ size_t occupied
27
+ heap_allocator* allocator
28
+ heap_page* prev
29
+ heap_memory_block* allocated
30
+ char buffer[]
31
+
32
+ ctypedef struct heap_allocator:
33
+ pthread_mutex_t lock
34
+ size_t mapped_pages
35
+ heap_page* active_page
36
+ size_t autopage_capacity
37
+ size_t autopage_capacity_max
38
+ size_t autopage_alignment
39
+ heap_memory_block* bins[AP_HEAP_BIN_COUNT]
40
+
41
+ int pthread_mutex_init(pthread_mutex_t* mutex, void* attr) noexcept nogil
42
+ int pthread_mutex_lock(pthread_mutex_t* mutex) noexcept nogil
43
+ int pthread_mutex_unlock(pthread_mutex_t* mutex) noexcept nogil
44
+ int pthread_mutex_destroy(pthread_mutex_t* mutex) noexcept nogil
45
+
46
+ size_t c_heap_page_roundup(heap_allocator* allocator, size_t size) noexcept nogil
47
+ size_t c_heap_block_roundup(size_t size) noexcept nogil
48
+ size_t c_heap_block_ceil_log2(unsigned int v) noexcept nogil
49
+ size_t c_heap_block_bin(size_t capacity) noexcept nogil
50
+ void c_heap_page_reclaim(heap_allocator* allocator, heap_page* page) noexcept nogil
51
+
52
+ heap_page* c_heap_allocator_extend(heap_allocator* allocator, size_t capacity, pthread_mutex_t* lock) noexcept nogil
53
+ heap_allocator* c_heap_allocator_new() noexcept nogil
54
+ void c_heap_allocator_free(heap_allocator* allocator) noexcept nogil
55
+ void* c_heap_calloc(heap_allocator* allocator, size_t size, pthread_mutex_t* lock) noexcept nogil
56
+ void* c_heap_request(heap_allocator* allocator, size_t size, int scan_all_pages, pthread_mutex_t* lock) noexcept nogil
57
+ void c_heap_free(void* ptr, pthread_mutex_t* lock) noexcept nogil
58
+ void c_heap_reclaim(heap_allocator* allocator, pthread_mutex_t* lock) noexcept nogil
59
+
60
+
61
+ cdef class HeapMemoryPage:
62
+ cdef heap_page* page
63
+
64
+ @staticmethod
65
+ cdef inline HeapMemoryPage c_from_header(heap_page* header)
66
+
67
+ cpdef void reclaim(self)
68
+
69
+
70
+ cdef class HeapMemoryBlock:
71
+ cdef heap_memory_block* block
72
+ cdef readonly bint owner
73
+
74
+ @staticmethod
75
+ cdef inline HeapMemoryBlock c_from_header(heap_memory_block* header, bint owner=?)
76
+
77
+
78
+ cdef class HeapAllocator:
79
+ cdef heap_allocator* allocator
80
+ cdef readonly bint owner
81
+
82
+ @staticmethod
83
+ cdef HeapAllocator c_from_header(heap_allocator* header, bint owner=?)
84
+
85
+ cdef inline heap_page* c_extend(self, size_t capacity=?, pthread_mutex_t* lock=?)
86
+
87
+ cdef inline void* c_calloc(self, size_t size, pthread_mutex_t* lock=?)
88
+
89
+ cdef inline void* c_request(self, size_t size, int scan_all_pages=?, pthread_mutex_t* lock=?)
90
+
91
+ cdef inline void c_free(self, void* ptr, pthread_mutex_t* lock=?)
92
+
93
+ cpdef HeapMemoryPage extend(self, size_t capacity=?, bint with_lock=?)
94
+
95
+ cpdef HeapMemoryBlock calloc(self, size_t size, bint with_lock=?)
96
+
97
+ cpdef HeapMemoryBlock request(self, size_t size, bint with_lock=?, bint scan_all_pages=?)
98
+
99
+ cpdef void free(self, HeapMemoryBlock buffer, bint with_lock=?)
100
+
101
+ cpdef void reclaim(self, bint with_lock=?)
102
+
103
+
104
+ cdef HeapAllocator ALLOCATOR
105
+ cdef heap_allocator* C_ALLOCATOR