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 */