lqft-python-engine 0.2.0__tar.gz → 0.5.0__tar.gz
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.
- {lqft_python_engine-0.2.0 → lqft_python_engine-0.5.0}/PKG-INFO +2 -2
- lqft_python_engine-0.5.0/lqft_engine.c +490 -0
- {lqft_python_engine-0.2.0 → lqft_python_engine-0.5.0}/lqft_engine.py +80 -51
- {lqft_python_engine-0.2.0 → lqft_python_engine-0.5.0}/lqft_python_engine.egg-info/PKG-INFO +2 -2
- {lqft_python_engine-0.2.0 → lqft_python_engine-0.5.0}/setup.py +2 -2
- lqft_python_engine-0.2.0/lqft_engine.c +0 -282
- {lqft_python_engine-0.2.0 → lqft_python_engine-0.5.0}/LICENSE.md +0 -0
- {lqft_python_engine-0.2.0 → lqft_python_engine-0.5.0}/lqft_python_engine.egg-info/SOURCES.txt +0 -0
- {lqft_python_engine-0.2.0 → lqft_python_engine-0.5.0}/lqft_python_engine.egg-info/dependency_links.txt +0 -0
- {lqft_python_engine-0.2.0 → lqft_python_engine-0.5.0}/lqft_python_engine.egg-info/requires.txt +0 -0
- {lqft_python_engine-0.2.0 → lqft_python_engine-0.5.0}/lqft_python_engine.egg-info/top_level.txt +0 -0
- {lqft_python_engine-0.2.0 → lqft_python_engine-0.5.0}/pure_python_ds.py +0 -0
- {lqft_python_engine-0.2.0 → lqft_python_engine-0.5.0}/pyproject.toml +0 -0
- {lqft_python_engine-0.2.0 → lqft_python_engine-0.5.0}/setup.cfg +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lqft-python-engine
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: LQFT Engine:
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: LQFT Engine: Native Disk Persistence & Cold Start Deserialization (v5.0 Stable)
|
|
5
5
|
Home-page: https://github.com/ParjadM/Log-Quantum-Fractal-Tree-LQFT-
|
|
6
6
|
Author: Parjad Minooei
|
|
7
7
|
License: MIT
|
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
#define PY_SSIZE_T_CLEAN
|
|
2
|
+
#include <Python.h>
|
|
3
|
+
|
|
4
|
+
#ifndef _CRT_SECURE_NO_WARNINGS
|
|
5
|
+
#define _CRT_SECURE_NO_WARNINGS
|
|
6
|
+
#endif
|
|
7
|
+
|
|
8
|
+
#include <stdio.h>
|
|
9
|
+
#include <stdlib.h>
|
|
10
|
+
#include <string.h>
|
|
11
|
+
#include <stdint.h>
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* LQFT C-Engine - V0.5.0 (Native Disk Persistence)
|
|
15
|
+
* Architect: Parjad Minooei
|
|
16
|
+
* * CHANGE LOG:
|
|
17
|
+
* - Implemented Binary Serialization (save_to_disk).
|
|
18
|
+
* - Implemented O(1) Cold Start Deserialization (load_from_disk).
|
|
19
|
+
* - DAG Pointer Reconstruction Logic.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
#define BIT_PARTITION 5
|
|
23
|
+
#define MAX_BITS 64
|
|
24
|
+
#define MASK 0x1F
|
|
25
|
+
#define REGISTRY_SIZE 8000009
|
|
26
|
+
#define TOMBSTONE ((LQFTNode*)1)
|
|
27
|
+
|
|
28
|
+
typedef struct LQFTNode {
|
|
29
|
+
void* value;
|
|
30
|
+
uint64_t key_hash;
|
|
31
|
+
struct LQFTNode* children[32];
|
|
32
|
+
char struct_hash[17];
|
|
33
|
+
uint64_t full_hash_val;
|
|
34
|
+
int ref_count;
|
|
35
|
+
} LQFTNode;
|
|
36
|
+
|
|
37
|
+
static LQFTNode** registry = NULL;
|
|
38
|
+
static int physical_node_count = 0;
|
|
39
|
+
static LQFTNode* global_root = NULL;
|
|
40
|
+
|
|
41
|
+
const uint64_t FNV_OFFSET_BASIS = 14695981039346656037ULL;
|
|
42
|
+
const uint64_t FNV_PRIME = 1099511628211ULL;
|
|
43
|
+
|
|
44
|
+
// -------------------------------------------------------------------
|
|
45
|
+
// Utilities
|
|
46
|
+
// -------------------------------------------------------------------
|
|
47
|
+
uint64_t fnv1a_update(uint64_t hash, const void* data, size_t len) {
|
|
48
|
+
const uint8_t* p = (const uint8_t*)data;
|
|
49
|
+
for (size_t i = 0; i < len; i++) {
|
|
50
|
+
hash ^= p[i];
|
|
51
|
+
hash *= FNV_PRIME;
|
|
52
|
+
}
|
|
53
|
+
return hash;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
char* portable_strdup(const char* s) {
|
|
57
|
+
if (!s) return NULL;
|
|
58
|
+
#ifdef _WIN32
|
|
59
|
+
return _strdup(s);
|
|
60
|
+
#else
|
|
61
|
+
return strdup(s);
|
|
62
|
+
#endif
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static int init_registry() {
|
|
66
|
+
if (registry == NULL) {
|
|
67
|
+
registry = (LQFTNode**)calloc(REGISTRY_SIZE, sizeof(LQFTNode*));
|
|
68
|
+
if (registry == NULL) return 0;
|
|
69
|
+
}
|
|
70
|
+
return 1;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
LQFTNode* create_node(void* value, uint64_t key_hash) {
|
|
74
|
+
LQFTNode* node = (LQFTNode*)malloc(sizeof(LQFTNode));
|
|
75
|
+
if (!node) return NULL;
|
|
76
|
+
node->value = value;
|
|
77
|
+
node->key_hash = key_hash;
|
|
78
|
+
node->full_hash_val = 0;
|
|
79
|
+
node->ref_count = 0;
|
|
80
|
+
for (int i = 0; i < 32; i++) node->children[i] = NULL;
|
|
81
|
+
return node;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// -------------------------------------------------------------------
|
|
85
|
+
// Memory Management (ARC)
|
|
86
|
+
// -------------------------------------------------------------------
|
|
87
|
+
void decref(LQFTNode* node) {
|
|
88
|
+
if (!node) return;
|
|
89
|
+
node->ref_count--;
|
|
90
|
+
if (node->ref_count <= 0) {
|
|
91
|
+
for (int i = 0; i < 32; i++) {
|
|
92
|
+
if (node->children[i]) decref(node->children[i]);
|
|
93
|
+
}
|
|
94
|
+
uint32_t idx = node->full_hash_val % REGISTRY_SIZE;
|
|
95
|
+
uint32_t start_idx = idx;
|
|
96
|
+
while (registry[idx] != NULL) {
|
|
97
|
+
if (registry[idx] == node) {
|
|
98
|
+
registry[idx] = TOMBSTONE;
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
idx = (idx + 1) % REGISTRY_SIZE;
|
|
102
|
+
if (idx == start_idx) break;
|
|
103
|
+
}
|
|
104
|
+
if (node->value) free(node->value);
|
|
105
|
+
free(node);
|
|
106
|
+
physical_node_count--;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
static PyObject* method_free_all(PyObject* self, PyObject* args) {
|
|
111
|
+
if (registry != NULL) {
|
|
112
|
+
for (int i = 0; i < REGISTRY_SIZE; i++) {
|
|
113
|
+
if (registry[i] != NULL && registry[i] != TOMBSTONE) {
|
|
114
|
+
if (registry[i]->value) free(registry[i]->value);
|
|
115
|
+
free(registry[i]);
|
|
116
|
+
}
|
|
117
|
+
registry[i] = NULL;
|
|
118
|
+
}
|
|
119
|
+
free(registry);
|
|
120
|
+
registry = NULL;
|
|
121
|
+
}
|
|
122
|
+
physical_node_count = 0;
|
|
123
|
+
global_root = NULL;
|
|
124
|
+
Py_RETURN_NONE;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// -------------------------------------------------------------------
|
|
128
|
+
// Disk Persistence (Binary Serialization)
|
|
129
|
+
// -------------------------------------------------------------------
|
|
130
|
+
static PyObject* method_save_to_disk(PyObject* self, PyObject* args) {
|
|
131
|
+
const char* filepath;
|
|
132
|
+
if (!PyArg_ParseTuple(args, "s", &filepath)) return NULL;
|
|
133
|
+
if (!registry) Py_RETURN_NONE;
|
|
134
|
+
|
|
135
|
+
FILE* fp = fopen(filepath, "wb");
|
|
136
|
+
if (!fp) return PyErr_SetFromErrno(PyExc_IOError);
|
|
137
|
+
|
|
138
|
+
// Header: Magic Bytes, Count, Global Root Hash
|
|
139
|
+
char magic[4] = "LQFT";
|
|
140
|
+
fwrite(magic, 1, 4, fp);
|
|
141
|
+
fwrite(&physical_node_count, sizeof(int), 1, fp);
|
|
142
|
+
uint64_t root_hash = global_root ? global_root->full_hash_val : 0;
|
|
143
|
+
fwrite(&root_hash, sizeof(uint64_t), 1, fp);
|
|
144
|
+
|
|
145
|
+
// Dump Nodes
|
|
146
|
+
for (int i = 0; i < REGISTRY_SIZE; i++) {
|
|
147
|
+
LQFTNode* node = registry[i];
|
|
148
|
+
if (node != NULL && node != TOMBSTONE) {
|
|
149
|
+
fwrite(&node->full_hash_val, sizeof(uint64_t), 1, fp);
|
|
150
|
+
fwrite(&node->key_hash, sizeof(uint64_t), 1, fp);
|
|
151
|
+
fwrite(node->struct_hash, 1, 17, fp);
|
|
152
|
+
fwrite(&node->ref_count, sizeof(int), 1, fp);
|
|
153
|
+
|
|
154
|
+
// Payload
|
|
155
|
+
int has_val = (node->value != NULL) ? 1 : 0;
|
|
156
|
+
fwrite(&has_val, sizeof(int), 1, fp);
|
|
157
|
+
if (has_val) {
|
|
158
|
+
int v_len = (int)strlen((char*)node->value);
|
|
159
|
+
fwrite(&v_len, sizeof(int), 1, fp);
|
|
160
|
+
fwrite(node->value, 1, v_len, fp);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Children pointers (saved as full_hash_val references)
|
|
164
|
+
uint64_t child_refs[32] = {0};
|
|
165
|
+
for (int c = 0; c < 32; c++) {
|
|
166
|
+
if (node->children[c]) child_refs[c] = node->children[c]->full_hash_val;
|
|
167
|
+
}
|
|
168
|
+
fwrite(child_refs, sizeof(uint64_t), 32, fp);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
fclose(fp);
|
|
173
|
+
Py_RETURN_TRUE;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
LQFTNode* find_in_registry(uint64_t full_hash) {
|
|
177
|
+
if (full_hash == 0) return NULL;
|
|
178
|
+
uint32_t idx = full_hash % REGISTRY_SIZE;
|
|
179
|
+
uint32_t start_idx = idx;
|
|
180
|
+
while (registry[idx] != NULL) {
|
|
181
|
+
if (registry[idx] != TOMBSTONE && registry[idx]->full_hash_val == full_hash) {
|
|
182
|
+
return registry[idx];
|
|
183
|
+
}
|
|
184
|
+
idx = (idx + 1) % REGISTRY_SIZE;
|
|
185
|
+
if (idx == start_idx) break;
|
|
186
|
+
}
|
|
187
|
+
return NULL;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
static PyObject* method_load_from_disk(PyObject* self, PyObject* args) {
|
|
191
|
+
const char* filepath;
|
|
192
|
+
if (!PyArg_ParseTuple(args, "s", &filepath)) return NULL;
|
|
193
|
+
|
|
194
|
+
FILE* fp = fopen(filepath, "rb");
|
|
195
|
+
if (!fp) return PyErr_SetFromErrno(PyExc_IOError);
|
|
196
|
+
|
|
197
|
+
char magic[5] = {0};
|
|
198
|
+
fread(magic, 1, 4, fp);
|
|
199
|
+
if (strcmp(magic, "LQFT") != 0) {
|
|
200
|
+
fclose(fp);
|
|
201
|
+
PyErr_SetString(PyExc_ValueError, "Invalid LQFT binary file format.");
|
|
202
|
+
return NULL;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Clear current state safely
|
|
206
|
+
method_free_all(self, NULL);
|
|
207
|
+
init_registry();
|
|
208
|
+
|
|
209
|
+
int total_nodes;
|
|
210
|
+
uint64_t root_hash;
|
|
211
|
+
fread(&total_nodes, sizeof(int), 1, fp);
|
|
212
|
+
fread(&root_hash, sizeof(uint64_t), 1, fp);
|
|
213
|
+
|
|
214
|
+
// Parallel array to store child hashes for Pass 2 (Pointer Reconstruction)
|
|
215
|
+
uint64_t* all_child_refs = (uint64_t*)malloc(total_nodes * 32 * sizeof(uint64_t));
|
|
216
|
+
LQFTNode** loaded_nodes = (LQFTNode**)malloc(total_nodes * sizeof(LQFTNode*));
|
|
217
|
+
|
|
218
|
+
// PASS 1: Read physical nodes into memory
|
|
219
|
+
for (int i = 0; i < total_nodes; i++) {
|
|
220
|
+
LQFTNode* node = create_node(NULL, 0);
|
|
221
|
+
fread(&node->full_hash_val, sizeof(uint64_t), 1, fp);
|
|
222
|
+
fread(&node->key_hash, sizeof(uint64_t), 1, fp);
|
|
223
|
+
fread(node->struct_hash, 1, 17, fp);
|
|
224
|
+
fread(&node->ref_count, sizeof(int), 1, fp);
|
|
225
|
+
|
|
226
|
+
int has_val;
|
|
227
|
+
fread(&has_val, sizeof(int), 1, fp);
|
|
228
|
+
if (has_val) {
|
|
229
|
+
int v_len;
|
|
230
|
+
fread(&v_len, sizeof(int), 1, fp);
|
|
231
|
+
char* val_str = (char*)malloc(v_len + 1);
|
|
232
|
+
fread(val_str, 1, v_len, fp);
|
|
233
|
+
val_str[v_len] = '\0';
|
|
234
|
+
node->value = val_str;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
fread(&all_child_refs[i * 32], sizeof(uint64_t), 32, fp);
|
|
238
|
+
|
|
239
|
+
// Insert directly into registry
|
|
240
|
+
uint32_t idx = node->full_hash_val % REGISTRY_SIZE;
|
|
241
|
+
while (registry[idx] != NULL) idx = (idx + 1) % REGISTRY_SIZE;
|
|
242
|
+
registry[idx] = node;
|
|
243
|
+
|
|
244
|
+
loaded_nodes[i] = node;
|
|
245
|
+
physical_node_count++;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// PASS 2: Pointer Reconstruction (Relinking the DAG)
|
|
249
|
+
for (int i = 0; i < total_nodes; i++) {
|
|
250
|
+
for (int c = 0; c < 32; c++) {
|
|
251
|
+
uint64_t target_hash = all_child_refs[i * 32 + c];
|
|
252
|
+
if (target_hash != 0) {
|
|
253
|
+
loaded_nodes[i]->children[c] = find_in_registry(target_hash);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
global_root = find_in_registry(root_hash);
|
|
259
|
+
|
|
260
|
+
free(all_child_refs);
|
|
261
|
+
free(loaded_nodes);
|
|
262
|
+
fclose(fp);
|
|
263
|
+
|
|
264
|
+
Py_RETURN_TRUE;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// -------------------------------------------------------------------
|
|
268
|
+
// Merkle-DAG Core (Standard Operations)
|
|
269
|
+
// -------------------------------------------------------------------
|
|
270
|
+
LQFTNode* get_canonical(void* value, uint64_t key_hash, LQFTNode** children) {
|
|
271
|
+
if (!init_registry()) return NULL;
|
|
272
|
+
|
|
273
|
+
uint64_t full_hash = FNV_OFFSET_BASIS;
|
|
274
|
+
if (value != NULL) {
|
|
275
|
+
full_hash = fnv1a_update(full_hash, "leaf:", 5);
|
|
276
|
+
full_hash = fnv1a_update(full_hash, value, strlen((char*)value));
|
|
277
|
+
full_hash = fnv1a_update(full_hash, &key_hash, sizeof(uint64_t));
|
|
278
|
+
} else {
|
|
279
|
+
full_hash = fnv1a_update(full_hash, "branch:", 7);
|
|
280
|
+
if (children) {
|
|
281
|
+
for (int i = 0; i < 32; i++) {
|
|
282
|
+
if (children[i]) {
|
|
283
|
+
full_hash = fnv1a_update(full_hash, &i, sizeof(int));
|
|
284
|
+
full_hash = fnv1a_update(full_hash, children[i]->struct_hash, 16);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
char lookup_hash[17];
|
|
291
|
+
sprintf(lookup_hash, "%016llx", (unsigned long long)full_hash);
|
|
292
|
+
uint32_t idx = full_hash % REGISTRY_SIZE;
|
|
293
|
+
uint32_t start_idx = idx;
|
|
294
|
+
int first_tombstone = -1;
|
|
295
|
+
|
|
296
|
+
while (registry[idx] != NULL) {
|
|
297
|
+
if (registry[idx] == TOMBSTONE) {
|
|
298
|
+
if (first_tombstone == -1) first_tombstone = (int)idx;
|
|
299
|
+
} else if (registry[idx]->full_hash_val == full_hash && strcmp(registry[idx]->struct_hash, lookup_hash) == 0) {
|
|
300
|
+
if (value) free(value);
|
|
301
|
+
return registry[idx];
|
|
302
|
+
}
|
|
303
|
+
idx = (idx + 1) % REGISTRY_SIZE;
|
|
304
|
+
if (idx == start_idx) break;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
LQFTNode* new_node = create_node(value, key_hash);
|
|
308
|
+
if (!new_node) return NULL;
|
|
309
|
+
|
|
310
|
+
if (children) {
|
|
311
|
+
for (int i = 0; i < 32; i++) {
|
|
312
|
+
new_node->children[i] = children[i];
|
|
313
|
+
if (children[i]) children[i]->ref_count++;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
strcpy(new_node->struct_hash, lookup_hash);
|
|
318
|
+
new_node->full_hash_val = full_hash;
|
|
319
|
+
|
|
320
|
+
uint32_t insert_idx = (first_tombstone != -1) ? (uint32_t)first_tombstone : idx;
|
|
321
|
+
registry[insert_idx] = new_node;
|
|
322
|
+
physical_node_count++;
|
|
323
|
+
|
|
324
|
+
return new_node;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
static PyObject* method_insert(PyObject* self, PyObject* args) {
|
|
328
|
+
unsigned long long h;
|
|
329
|
+
char* val_str;
|
|
330
|
+
if (!PyArg_ParseTuple(args, "Ks", &h, &val_str)) return NULL;
|
|
331
|
+
|
|
332
|
+
if (!global_root) {
|
|
333
|
+
if (!init_registry()) return PyErr_NoMemory();
|
|
334
|
+
global_root = get_canonical(NULL, 0, NULL);
|
|
335
|
+
global_root->ref_count++;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
LQFTNode* old_root = global_root;
|
|
339
|
+
LQFTNode* path_nodes[20];
|
|
340
|
+
uint32_t path_segs[20];
|
|
341
|
+
int path_len = 0;
|
|
342
|
+
LQFTNode* curr = global_root;
|
|
343
|
+
int bit_depth = 0;
|
|
344
|
+
|
|
345
|
+
while (curr != NULL && curr->value == NULL) {
|
|
346
|
+
uint32_t segment = (h >> bit_depth) & MASK;
|
|
347
|
+
path_nodes[path_len] = curr;
|
|
348
|
+
path_segs[path_len] = segment;
|
|
349
|
+
path_len++;
|
|
350
|
+
if (curr->children[segment] == NULL) { curr = NULL; break; }
|
|
351
|
+
curr = curr->children[segment];
|
|
352
|
+
bit_depth += BIT_PARTITION;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
LQFTNode* new_sub_node = NULL;
|
|
356
|
+
if (curr == NULL) {
|
|
357
|
+
new_sub_node = get_canonical(portable_strdup(val_str), h, NULL);
|
|
358
|
+
} else if (curr->key_hash == h) {
|
|
359
|
+
new_sub_node = get_canonical(portable_strdup(val_str), h, curr->children);
|
|
360
|
+
} else {
|
|
361
|
+
unsigned long long old_h = curr->key_hash;
|
|
362
|
+
char* old_val = portable_strdup((char*)curr->value);
|
|
363
|
+
int temp_depth = bit_depth;
|
|
364
|
+
while (temp_depth < 64) {
|
|
365
|
+
uint32_t s_old = (old_h >> temp_depth) & MASK;
|
|
366
|
+
uint32_t s_new = (h >> temp_depth) & MASK;
|
|
367
|
+
if (s_old != s_new) {
|
|
368
|
+
LQFTNode* c_old = get_canonical(old_val, old_h, curr->children);
|
|
369
|
+
LQFTNode* c_new = get_canonical(portable_strdup(val_str), h, NULL);
|
|
370
|
+
LQFTNode* new_children[32] = {NULL};
|
|
371
|
+
new_children[s_old] = c_old;
|
|
372
|
+
new_children[s_new] = c_new;
|
|
373
|
+
new_sub_node = get_canonical(NULL, 0, new_children);
|
|
374
|
+
break;
|
|
375
|
+
} else {
|
|
376
|
+
path_nodes[path_len] = NULL;
|
|
377
|
+
path_segs[path_len] = s_old;
|
|
378
|
+
path_len++;
|
|
379
|
+
temp_depth += BIT_PARTITION;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
if (new_sub_node == NULL) new_sub_node = get_canonical(portable_strdup(val_str), h, curr->children);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
for (int i = path_len - 1; i >= 0; i--) {
|
|
386
|
+
if (path_nodes[i] == NULL) {
|
|
387
|
+
LQFTNode* new_children[32] = {NULL};
|
|
388
|
+
new_children[path_segs[i]] = new_sub_node;
|
|
389
|
+
new_sub_node = get_canonical(NULL, 0, new_children);
|
|
390
|
+
} else {
|
|
391
|
+
LQFTNode* p_node = path_nodes[i];
|
|
392
|
+
uint32_t segment = path_segs[i];
|
|
393
|
+
LQFTNode* new_children[32];
|
|
394
|
+
for (int j = 0; j < 32; j++) new_children[j] = p_node->children[j];
|
|
395
|
+
new_children[segment] = new_sub_node;
|
|
396
|
+
new_sub_node = get_canonical(p_node->value, p_node->key_hash, new_children);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
global_root = new_sub_node;
|
|
401
|
+
global_root->ref_count++;
|
|
402
|
+
if (old_root) decref(old_root);
|
|
403
|
+
|
|
404
|
+
Py_RETURN_NONE;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
static PyObject* method_search(PyObject* self, PyObject* args) {
|
|
408
|
+
unsigned long long h;
|
|
409
|
+
if (!PyArg_ParseTuple(args, "K", &h)) return NULL;
|
|
410
|
+
if (!global_root) Py_RETURN_NONE;
|
|
411
|
+
|
|
412
|
+
LQFTNode* curr = global_root;
|
|
413
|
+
int bit_depth = 0;
|
|
414
|
+
while (curr != NULL && curr->value == NULL) {
|
|
415
|
+
uint32_t segment = (h >> bit_depth) & MASK;
|
|
416
|
+
curr = curr->children[segment];
|
|
417
|
+
bit_depth += BIT_PARTITION;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (curr != NULL && curr->key_hash == h) return PyUnicode_FromString((char*)curr->value);
|
|
421
|
+
Py_RETURN_NONE;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
static PyObject* method_delete(PyObject* self, PyObject* args) {
|
|
425
|
+
unsigned long long h;
|
|
426
|
+
if (!PyArg_ParseTuple(args, "K", &h)) return NULL;
|
|
427
|
+
if (!global_root) Py_RETURN_NONE;
|
|
428
|
+
|
|
429
|
+
LQFTNode* path_nodes[20];
|
|
430
|
+
uint32_t path_segs[20];
|
|
431
|
+
int path_len = 0;
|
|
432
|
+
LQFTNode* curr = global_root;
|
|
433
|
+
int bit_depth = 0;
|
|
434
|
+
|
|
435
|
+
while (curr != NULL && curr->value == NULL) {
|
|
436
|
+
uint32_t segment = (h >> bit_depth) & MASK;
|
|
437
|
+
path_nodes[path_len] = curr;
|
|
438
|
+
path_segs[path_len] = segment;
|
|
439
|
+
path_len++;
|
|
440
|
+
curr = curr->children[segment];
|
|
441
|
+
bit_depth += BIT_PARTITION;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (curr == NULL || curr->key_hash != h) Py_RETURN_NONE;
|
|
445
|
+
|
|
446
|
+
LQFTNode* old_root = global_root;
|
|
447
|
+
LQFTNode* new_sub_node = NULL;
|
|
448
|
+
|
|
449
|
+
for (int i = path_len - 1; i >= 0; i--) {
|
|
450
|
+
LQFTNode* p_node = path_nodes[i];
|
|
451
|
+
uint32_t segment = path_segs[i];
|
|
452
|
+
LQFTNode* new_children[32];
|
|
453
|
+
int has_other_children = 0;
|
|
454
|
+
|
|
455
|
+
for (uint32_t j = 0; j < 32; j++) {
|
|
456
|
+
if (j == segment) new_children[j] = new_sub_node;
|
|
457
|
+
else {
|
|
458
|
+
new_children[j] = p_node->children[j];
|
|
459
|
+
if (new_children[j]) has_other_children = 1;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
if (!has_other_children && i > 0) new_sub_node = NULL;
|
|
464
|
+
else new_sub_node = get_canonical(NULL, 0, new_children);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
global_root = (new_sub_node) ? new_sub_node : get_canonical(NULL, 0, NULL);
|
|
468
|
+
if (global_root) global_root->ref_count++;
|
|
469
|
+
if (old_root) decref(old_root);
|
|
470
|
+
|
|
471
|
+
Py_RETURN_NONE;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
static PyObject* method_get_metrics(PyObject* self, PyObject* args) {
|
|
475
|
+
return Py_BuildValue("{s:i}", "physical_nodes", physical_node_count);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
static PyMethodDef LQFTMethods[] = {
|
|
479
|
+
{"insert", method_insert, METH_VARARGS, "Insert key-value"},
|
|
480
|
+
{"delete", method_delete, METH_VARARGS, "Delete key"},
|
|
481
|
+
{"search", method_search, METH_VARARGS, "Search key"},
|
|
482
|
+
{"save_to_disk", method_save_to_disk, METH_VARARGS, "Serialize to .bin"},
|
|
483
|
+
{"load_from_disk", method_load_from_disk, METH_VARARGS, "Deserialize from .bin"},
|
|
484
|
+
{"get_metrics", method_get_metrics, METH_VARARGS, "Get stats"},
|
|
485
|
+
{"free_all", method_free_all, METH_VARARGS, "Total memory wipe"},
|
|
486
|
+
{NULL, NULL, 0, NULL}
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
static struct PyModuleDef lqftmodule = { PyModuleDef_HEAD_INIT, "lqft_c_engine", NULL, -1, LQFTMethods };
|
|
490
|
+
PyMODINIT_FUNC PyInit_lqft_c_engine(void) { return PyModule_Create(&lqftmodule); }
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import hashlib
|
|
2
2
|
import weakref
|
|
3
|
+
import psutil
|
|
4
|
+
import os
|
|
5
|
+
import json
|
|
3
6
|
|
|
4
7
|
# ---------------------------------------------------------
|
|
5
|
-
# LEGACY PURE PYTHON LQFT (For reference/fallback
|
|
8
|
+
# LEGACY PURE PYTHON LQFT (For reference/fallback)
|
|
6
9
|
# ---------------------------------------------------------
|
|
7
10
|
class LQFTNode:
|
|
8
11
|
__slots__ = ['children', 'value', 'key_hash', 'struct_hash', '__weakref__']
|
|
@@ -39,7 +42,6 @@ class LQFTNode:
|
|
|
39
42
|
return cls._null_cache['null']
|
|
40
43
|
|
|
41
44
|
class LQFT:
|
|
42
|
-
"""Legacy Pure Python Iterative Implementation."""
|
|
43
45
|
def __init__(self, bit_partition=5, max_bits=256):
|
|
44
46
|
self.partition = bit_partition
|
|
45
47
|
self.max_bits = max_bits
|
|
@@ -62,7 +64,7 @@ class LQFT:
|
|
|
62
64
|
break
|
|
63
65
|
curr = curr.children[segment]
|
|
64
66
|
bit_depth += self.partition
|
|
65
|
-
|
|
67
|
+
|
|
66
68
|
new_sub_node = None
|
|
67
69
|
if curr is null_node:
|
|
68
70
|
new_sub_node = LQFTNode.get_canonical(value, None, h)
|
|
@@ -82,7 +84,7 @@ class LQFT:
|
|
|
82
84
|
temp_depth += self.partition
|
|
83
85
|
if new_sub_node is None:
|
|
84
86
|
new_sub_node = LQFTNode.get_canonical(value, curr.children, h)
|
|
85
|
-
|
|
87
|
+
|
|
86
88
|
for entry in reversed(path):
|
|
87
89
|
if entry[0] == "split":
|
|
88
90
|
new_sub_node = LQFTNode.get_canonical(None, {entry[1]: new_sub_node}, None)
|
|
@@ -104,7 +106,7 @@ class LQFT:
|
|
|
104
106
|
return None
|
|
105
107
|
|
|
106
108
|
# ---------------------------------------------------------
|
|
107
|
-
#
|
|
109
|
+
# ADAPTIVE ENTERPRISE ENGINE (v0.5.0 - Disk Persistence)
|
|
108
110
|
# ---------------------------------------------------------
|
|
109
111
|
try:
|
|
110
112
|
import lqft_c_engine
|
|
@@ -113,63 +115,92 @@ except ImportError:
|
|
|
113
115
|
C_ENGINE_READY = False
|
|
114
116
|
|
|
115
117
|
class AdaptiveLQFT:
|
|
116
|
-
"""
|
|
117
|
-
A polymorphic, heuristic-driven data structure wrapper.
|
|
118
|
-
- Scale < threshold: Acts as an ultra-lightweight C-Hash (Python Dict).
|
|
119
|
-
- Scale > threshold: Automatically migrates to the Native C-Engine LQFT
|
|
120
|
-
for Merkle-DAG deduplication and folding.
|
|
121
|
-
"""
|
|
122
118
|
def __init__(self, migration_threshold=50000):
|
|
123
119
|
self.threshold = migration_threshold
|
|
124
120
|
self.size = 0
|
|
125
121
|
self.is_native = False
|
|
126
|
-
|
|
127
|
-
# The "Mini Version": Python's highly optimized built-in dictionary
|
|
128
122
|
self._light_store = {}
|
|
123
|
+
|
|
124
|
+
self.auto_purge_enabled = True
|
|
125
|
+
self.max_memory_mb = 1000.0
|
|
126
|
+
self.total_ops = 0
|
|
127
|
+
self._process = psutil.Process(os.getpid())
|
|
128
|
+
|
|
129
|
+
def _validate_type(self, key, value=None):
|
|
130
|
+
if not isinstance(key, str):
|
|
131
|
+
raise TypeError(f"LQFT keys must be strings. Received: {type(key).__name__}")
|
|
132
|
+
if value is not None and not isinstance(value, str):
|
|
133
|
+
raise TypeError(f"LQFT values must be strings. Received: {type(value).__name__}")
|
|
129
134
|
|
|
130
135
|
def _get_64bit_hash(self, key):
|
|
131
|
-
|
|
132
|
-
|
|
136
|
+
return int(hashlib.md5(key.encode()).hexdigest()[:16], 16)
|
|
137
|
+
|
|
138
|
+
def set_auto_purge_threshold(self, threshold: float):
|
|
139
|
+
self.purge_threshold = threshold
|
|
140
|
+
|
|
141
|
+
def purge(self):
|
|
142
|
+
current_mb = self._process.memory_info().rss / (1024 * 1024)
|
|
143
|
+
if current_mb >= self.max_memory_mb:
|
|
144
|
+
print(f"\n[⚠️ CIRCUIT Breaker] Engine exceeded {self.max_memory_mb} MB limit (Currently {current_mb:.1f} MB). Auto-Purging!")
|
|
145
|
+
self.clear()
|
|
146
|
+
|
|
147
|
+
# --- Phase 1: Native Disk Persistence ---
|
|
148
|
+
def save_to_disk(self, filepath: str):
|
|
149
|
+
"""Serializes the engine state to disk (O(1) Time context scaling)."""
|
|
150
|
+
if not self.is_native:
|
|
151
|
+
with open(filepath, 'w') as f:
|
|
152
|
+
json.dump(self._light_store, f)
|
|
153
|
+
else:
|
|
154
|
+
lqft_c_engine.save_to_disk(filepath)
|
|
155
|
+
|
|
156
|
+
def load_from_disk(self, filepath: str):
|
|
157
|
+
"""Instantly reconstructs C-Pointers from a binary file."""
|
|
158
|
+
if not os.path.exists(filepath):
|
|
159
|
+
raise FileNotFoundError(f"Missing LQFT database file: {filepath}")
|
|
160
|
+
|
|
161
|
+
if not self.is_native:
|
|
162
|
+
# Check if it's a C-Engine binary file (magic bytes "LQFT")
|
|
163
|
+
with open(filepath, 'rb') as f:
|
|
164
|
+
if f.read(4) == b'LQFT':
|
|
165
|
+
self._migrate_to_native()
|
|
166
|
+
lqft_c_engine.load_from_disk(filepath)
|
|
167
|
+
return
|
|
168
|
+
with open(filepath, 'r') as f:
|
|
169
|
+
self._light_store = json.load(f)
|
|
170
|
+
self.size = len(self._light_store)
|
|
171
|
+
else:
|
|
172
|
+
lqft_c_engine.load_from_disk(filepath)
|
|
133
173
|
|
|
134
174
|
def _migrate_to_native(self):
|
|
135
|
-
"""The 'Curve Flip' mechanism: moves all data to the Heavy Engine."""
|
|
136
175
|
if not C_ENGINE_READY:
|
|
137
|
-
|
|
138
|
-
self.threshold = float('inf') # Prevent continuous upgrade attempts
|
|
176
|
+
self.threshold = float('inf')
|
|
139
177
|
return
|
|
140
|
-
|
|
141
178
|
for key, val in self._light_store.items():
|
|
142
179
|
h = self._get_64bit_hash(key)
|
|
143
|
-
lqft_c_engine.insert(h,
|
|
144
|
-
|
|
145
|
-
# Clear the lightweight store to free up memory
|
|
180
|
+
lqft_c_engine.insert(h, val)
|
|
146
181
|
self._light_store.clear()
|
|
147
182
|
self.is_native = True
|
|
148
183
|
|
|
149
184
|
def insert(self, key, value):
|
|
185
|
+
self._validate_type(key, value)
|
|
186
|
+
self.total_ops += 1
|
|
187
|
+
if self.auto_purge_enabled and self.total_ops % 5000 == 0:
|
|
188
|
+
current_mb = self._process.memory_info().rss / (1024 * 1024)
|
|
189
|
+
if current_mb >= self.max_memory_mb:
|
|
190
|
+
self.purge()
|
|
191
|
+
|
|
150
192
|
if not self.is_native:
|
|
151
|
-
|
|
152
|
-
if key not in self._light_store:
|
|
193
|
+
if key not in self._light_store:
|
|
153
194
|
self.size += 1
|
|
154
195
|
self._light_store[key] = value
|
|
155
|
-
|
|
156
|
-
# Check for migration threshold
|
|
157
|
-
if self.size >= self.threshold:
|
|
196
|
+
if self.size >= self.threshold:
|
|
158
197
|
self._migrate_to_native()
|
|
159
|
-
else:
|
|
160
|
-
# Phase 2: Massive Data Operations (Native C-Heap)
|
|
161
|
-
h = self._get_64bit_hash(key)
|
|
162
|
-
lqft_c_engine.insert(h, str(value))
|
|
163
|
-
|
|
164
|
-
def search(self, key):
|
|
165
|
-
if not self.is_native:
|
|
166
|
-
return self._light_store.get(key, None)
|
|
167
198
|
else:
|
|
168
199
|
h = self._get_64bit_hash(key)
|
|
169
|
-
|
|
200
|
+
lqft_c_engine.insert(h, value)
|
|
170
201
|
|
|
171
202
|
def remove(self, key):
|
|
172
|
-
|
|
203
|
+
self._validate_type(key)
|
|
173
204
|
if not self.is_native:
|
|
174
205
|
if key in self._light_store:
|
|
175
206
|
del self._light_store[key]
|
|
@@ -179,35 +210,33 @@ class AdaptiveLQFT:
|
|
|
179
210
|
lqft_c_engine.delete(h)
|
|
180
211
|
|
|
181
212
|
def delete(self, key):
|
|
182
|
-
"""Alias for remove to satisfy all testing suites."""
|
|
183
213
|
self.remove(key)
|
|
184
214
|
|
|
215
|
+
def search(self, key):
|
|
216
|
+
self._validate_type(key)
|
|
217
|
+
if not self.is_native:
|
|
218
|
+
return self._light_store.get(key, None)
|
|
219
|
+
else:
|
|
220
|
+
h = self._get_64bit_hash(key)
|
|
221
|
+
return lqft_c_engine.search(h)
|
|
222
|
+
|
|
185
223
|
def clear(self):
|
|
186
|
-
"""
|
|
187
|
-
Memory Reclamation: Manually trigger heap cleanup.
|
|
188
|
-
In the Adaptive model, this handles both the Python dict and the C-Registry.
|
|
189
|
-
"""
|
|
190
224
|
self._light_store.clear()
|
|
191
225
|
self.size = 0
|
|
192
|
-
if C_ENGINE_READY:
|
|
226
|
+
if C_ENGINE_READY:
|
|
193
227
|
return lqft_c_engine.free_all()
|
|
194
228
|
return 0
|
|
195
229
|
|
|
196
230
|
def get_stats(self):
|
|
197
|
-
|
|
198
|
-
if self.is_native and C_ENGINE_READY:
|
|
231
|
+
if self.is_native and C_ENGINE_READY:
|
|
199
232
|
return lqft_c_engine.get_metrics()
|
|
200
233
|
return {"physical_nodes": 0}
|
|
201
234
|
|
|
202
235
|
def __del__(self):
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
self.clear()
|
|
206
|
-
except:
|
|
207
|
-
pass
|
|
236
|
+
try: self.clear()
|
|
237
|
+
except: pass
|
|
208
238
|
|
|
209
239
|
def status(self):
|
|
210
|
-
"""Returns the current state of the engine."""
|
|
211
240
|
return {
|
|
212
241
|
"mode": "Native Merkle-DAG" if self.is_native else "Lightweight C-Hash",
|
|
213
242
|
"items": self.size if not self.is_native else lqft_c_engine.get_metrics().get('physical_nodes', self.size),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lqft-python-engine
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: LQFT Engine:
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: LQFT Engine: Native Disk Persistence & Cold Start Deserialization (v5.0 Stable)
|
|
5
5
|
Home-page: https://github.com/ParjadM/Log-Quantum-Fractal-Tree-LQFT-
|
|
6
6
|
Author: Parjad Minooei
|
|
7
7
|
License: MIT
|
|
@@ -27,8 +27,8 @@ lqft_extension = Extension(
|
|
|
27
27
|
|
|
28
28
|
setup(
|
|
29
29
|
name="lqft-python-engine",
|
|
30
|
-
version="0.
|
|
31
|
-
description="LQFT Engine:
|
|
30
|
+
version="0.5.0",
|
|
31
|
+
description="LQFT Engine: Native Disk Persistence & Cold Start Deserialization (v5.0 Stable)",
|
|
32
32
|
long_description=long_description,
|
|
33
33
|
long_description_content_type="text/markdown",
|
|
34
34
|
author="Parjad Minooei",
|
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
#define PY_SSIZE_T_CLEAN
|
|
2
|
-
#include <Python.h>
|
|
3
|
-
|
|
4
|
-
#ifndef _CRT_SECURE_NO_WARNINGS
|
|
5
|
-
#define _CRT_SECURE_NO_WARNINGS
|
|
6
|
-
#endif
|
|
7
|
-
|
|
8
|
-
#include <stdio.h>
|
|
9
|
-
#include <stdlib.h>
|
|
10
|
-
#include <string.h>
|
|
11
|
-
#include <stdint.h>
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* LQFT C-Engine - V4.5 (Full CRUD & Large Payload)
|
|
15
|
-
* Architect: Parjad Minooei
|
|
16
|
-
* * CHANGE LOG:
|
|
17
|
-
* - Added 'delete' method with bottom-up path reconstruction.
|
|
18
|
-
* - Maintains Incremental FNV-1a Hashing for large payloads.
|
|
19
|
-
* - Fixed Stack-to-Heap collision for multi-MB data.
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
#define BIT_PARTITION 5
|
|
23
|
-
#define MAX_BITS 64
|
|
24
|
-
#define MASK 0x1F
|
|
25
|
-
#define REGISTRY_SIZE 8000009
|
|
26
|
-
|
|
27
|
-
typedef struct LQFTNode {
|
|
28
|
-
void* value;
|
|
29
|
-
uint64_t key_hash;
|
|
30
|
-
struct LQFTNode* children[32];
|
|
31
|
-
char struct_hash[17];
|
|
32
|
-
} LQFTNode;
|
|
33
|
-
|
|
34
|
-
static LQFTNode** registry = NULL;
|
|
35
|
-
static int physical_node_count = 0;
|
|
36
|
-
static LQFTNode* global_root = NULL;
|
|
37
|
-
|
|
38
|
-
const uint64_t FNV_OFFSET_BASIS = 14695981039346656037ULL;
|
|
39
|
-
const uint64_t FNV_PRIME = 1099511628211ULL;
|
|
40
|
-
|
|
41
|
-
uint64_t fnv1a_update(uint64_t hash, const void* data, size_t len) {
|
|
42
|
-
const uint8_t* p = (const uint8_t*)data;
|
|
43
|
-
for (size_t i = 0; i < len; i++) {
|
|
44
|
-
hash ^= p[i];
|
|
45
|
-
hash *= FNV_PRIME;
|
|
46
|
-
}
|
|
47
|
-
return hash;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
char* portable_strdup(const char* s) {
|
|
51
|
-
if (!s) return NULL;
|
|
52
|
-
#ifdef _WIN32
|
|
53
|
-
return _strdup(s);
|
|
54
|
-
#else
|
|
55
|
-
return strdup(s);
|
|
56
|
-
#endif
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
static int init_registry() {
|
|
60
|
-
if (registry == NULL) {
|
|
61
|
-
registry = (LQFTNode**)calloc(REGISTRY_SIZE, sizeof(LQFTNode*));
|
|
62
|
-
if (registry == NULL) return 0;
|
|
63
|
-
}
|
|
64
|
-
return 1;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
LQFTNode* create_node(void* value, uint64_t key_hash) {
|
|
68
|
-
LQFTNode* node = (LQFTNode*)malloc(sizeof(LQFTNode));
|
|
69
|
-
if (!node) return NULL;
|
|
70
|
-
node->value = value;
|
|
71
|
-
node->key_hash = key_hash;
|
|
72
|
-
for (int i = 0; i < 32; i++) node->children[i] = NULL;
|
|
73
|
-
return node;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
LQFTNode* get_canonical(void* value, uint64_t key_hash, LQFTNode** children) {
|
|
77
|
-
if (!init_registry()) return NULL;
|
|
78
|
-
|
|
79
|
-
uint64_t full_hash = FNV_OFFSET_BASIS;
|
|
80
|
-
if (value != NULL) {
|
|
81
|
-
full_hash = fnv1a_update(full_hash, "leaf:", 5);
|
|
82
|
-
full_hash = fnv1a_update(full_hash, value, strlen((char*)value));
|
|
83
|
-
full_hash = fnv1a_update(full_hash, &key_hash, sizeof(uint64_t));
|
|
84
|
-
} else {
|
|
85
|
-
full_hash = fnv1a_update(full_hash, "branch:", 7);
|
|
86
|
-
if (children) {
|
|
87
|
-
for (int i = 0; i < 32; i++) {
|
|
88
|
-
if (children[i]) {
|
|
89
|
-
full_hash = fnv1a_update(full_hash, &i, sizeof(int));
|
|
90
|
-
full_hash = fnv1a_update(full_hash, children[i]->struct_hash, 16);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
char lookup_hash[17];
|
|
97
|
-
sprintf(lookup_hash, "%016llx", (unsigned long long)full_hash);
|
|
98
|
-
uint32_t idx = full_hash % REGISTRY_SIZE;
|
|
99
|
-
uint32_t start_idx = idx;
|
|
100
|
-
|
|
101
|
-
while (registry[idx] != NULL) {
|
|
102
|
-
if (strcmp(registry[idx]->struct_hash, lookup_hash) == 0) {
|
|
103
|
-
if (value) free(value);
|
|
104
|
-
return registry[idx];
|
|
105
|
-
}
|
|
106
|
-
idx = (idx + 1) % REGISTRY_SIZE;
|
|
107
|
-
if (idx == start_idx) break;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
LQFTNode* new_node = create_node(value, key_hash);
|
|
111
|
-
if (!new_node) return NULL;
|
|
112
|
-
if (children) {
|
|
113
|
-
for (int i = 0; i < 32; i++) new_node->children[i] = children[i];
|
|
114
|
-
}
|
|
115
|
-
strcpy(new_node->struct_hash, lookup_hash);
|
|
116
|
-
registry[idx] = new_node;
|
|
117
|
-
physical_node_count++;
|
|
118
|
-
return new_node;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
static PyObject* method_delete(PyObject* self, PyObject* args) {
|
|
122
|
-
unsigned long long h;
|
|
123
|
-
if (!PyArg_ParseTuple(args, "K", &h)) return NULL;
|
|
124
|
-
if (!global_root) Py_RETURN_NONE;
|
|
125
|
-
|
|
126
|
-
LQFTNode* path_nodes[20];
|
|
127
|
-
uint32_t path_segs[20];
|
|
128
|
-
int path_len = 0;
|
|
129
|
-
LQFTNode* curr = global_root;
|
|
130
|
-
int bit_depth = 0;
|
|
131
|
-
|
|
132
|
-
// Trace path to target
|
|
133
|
-
while (curr != NULL && curr->value == NULL) {
|
|
134
|
-
uint32_t segment = (h >> bit_depth) & MASK;
|
|
135
|
-
path_nodes[path_len] = curr;
|
|
136
|
-
path_segs[path_len] = segment;
|
|
137
|
-
path_len++;
|
|
138
|
-
curr = curr->children[segment];
|
|
139
|
-
bit_depth += BIT_PARTITION;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// If not found, exit
|
|
143
|
-
if (curr == NULL || curr->key_hash != h) Py_RETURN_NONE;
|
|
144
|
-
|
|
145
|
-
// Rebuild bottom-up: start with NULL (the deleted leaf)
|
|
146
|
-
LQFTNode* new_sub_node = NULL;
|
|
147
|
-
|
|
148
|
-
for (int i = path_len - 1; i >= 0; i--) {
|
|
149
|
-
LQFTNode* p_node = path_nodes[i];
|
|
150
|
-
uint32_t segment = path_segs[i];
|
|
151
|
-
LQFTNode* new_children[32];
|
|
152
|
-
int has_other_children = 0;
|
|
153
|
-
|
|
154
|
-
for (int j = 0; j < 32; j++) {
|
|
155
|
-
if (j == segment) new_children[j] = new_sub_node;
|
|
156
|
-
else {
|
|
157
|
-
new_children[j] = p_node->children[j];
|
|
158
|
-
if (new_children[j]) has_other_children = 1;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if (!has_other_children && i > 0) {
|
|
163
|
-
new_sub_node = NULL; // Contract empty branch
|
|
164
|
-
} else {
|
|
165
|
-
new_sub_node = get_canonical(NULL, 0, new_children);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
global_root = (new_sub_node) ? new_sub_node : get_canonical(NULL, 0, NULL);
|
|
170
|
-
Py_RETURN_NONE;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
static PyObject* method_free_all(PyObject* self, PyObject* args) {
|
|
174
|
-
if (registry != NULL) {
|
|
175
|
-
for (int i = 0; i < REGISTRY_SIZE; i++) {
|
|
176
|
-
if (registry[i] != NULL) {
|
|
177
|
-
if (registry[i]->value) free(registry[i]->value);
|
|
178
|
-
free(registry[i]);
|
|
179
|
-
registry[i] = NULL;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
free(registry);
|
|
183
|
-
registry = NULL;
|
|
184
|
-
}
|
|
185
|
-
physical_node_count = 0;
|
|
186
|
-
global_root = NULL;
|
|
187
|
-
Py_RETURN_NONE;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
static PyObject* method_insert(PyObject* self, PyObject* args) {
|
|
191
|
-
unsigned long long h;
|
|
192
|
-
char* val_str;
|
|
193
|
-
if (!PyArg_ParseTuple(args, "Ks", &h, &val_str)) return NULL;
|
|
194
|
-
if (!global_root) {
|
|
195
|
-
if (!init_registry()) return PyErr_NoMemory();
|
|
196
|
-
global_root = get_canonical(NULL, 0, NULL);
|
|
197
|
-
}
|
|
198
|
-
LQFTNode* path_nodes[20];
|
|
199
|
-
uint32_t path_segs[20];
|
|
200
|
-
int path_len = 0;
|
|
201
|
-
LQFTNode* curr = global_root;
|
|
202
|
-
int bit_depth = 0;
|
|
203
|
-
while (curr != NULL && curr->value == NULL) {
|
|
204
|
-
uint32_t segment = (h >> bit_depth) & MASK;
|
|
205
|
-
path_nodes[path_len] = curr;
|
|
206
|
-
path_segs[path_len] = segment;
|
|
207
|
-
path_len++;
|
|
208
|
-
if (curr->children[segment] == NULL) { curr = NULL; break; }
|
|
209
|
-
curr = curr->children[segment];
|
|
210
|
-
bit_depth += BIT_PARTITION;
|
|
211
|
-
}
|
|
212
|
-
LQFTNode* new_sub_node = NULL;
|
|
213
|
-
if (curr == NULL) { new_sub_node = get_canonical(portable_strdup(val_str), h, NULL); }
|
|
214
|
-
else if (curr->key_hash == h) { new_sub_node = get_canonical(portable_strdup(val_str), h, curr->children); }
|
|
215
|
-
else {
|
|
216
|
-
unsigned long long old_h = curr->key_hash;
|
|
217
|
-
char* old_val = portable_strdup((char*)curr->value);
|
|
218
|
-
int temp_depth = bit_depth;
|
|
219
|
-
while (temp_depth < 64) {
|
|
220
|
-
uint32_t s_old = (old_h >> temp_depth) & MASK;
|
|
221
|
-
uint32_t s_new = (h >> temp_depth) & MASK;
|
|
222
|
-
if (s_old != s_new) {
|
|
223
|
-
LQFTNode* c_old = get_canonical(old_val, old_h, curr->children);
|
|
224
|
-
LQFTNode* c_new = get_canonical(portable_strdup(val_str), h, NULL);
|
|
225
|
-
LQFTNode* new_children[32] = {NULL};
|
|
226
|
-
new_children[s_old] = c_old;
|
|
227
|
-
new_children[s_new] = c_new;
|
|
228
|
-
new_sub_node = get_canonical(NULL, 0, new_children);
|
|
229
|
-
break;
|
|
230
|
-
} else { path_nodes[path_len] = NULL; path_segs[path_len] = s_old; path_len++; temp_depth += BIT_PARTITION; }
|
|
231
|
-
}
|
|
232
|
-
if (new_sub_node == NULL) new_sub_node = get_canonical(portable_strdup(val_str), h, curr->children);
|
|
233
|
-
}
|
|
234
|
-
for (int i = path_len - 1; i >= 0; i--) {
|
|
235
|
-
if (path_nodes[i] == NULL) {
|
|
236
|
-
LQFTNode* new_children[32] = {NULL};
|
|
237
|
-
new_children[path_segs[i]] = new_sub_node;
|
|
238
|
-
new_sub_node = get_canonical(NULL, 0, new_children);
|
|
239
|
-
} else {
|
|
240
|
-
LQFTNode* p_node = path_nodes[i];
|
|
241
|
-
uint32_t segment = path_segs[i];
|
|
242
|
-
LQFTNode* new_children[32];
|
|
243
|
-
for (int j = 0; j < 32; j++) new_children[j] = p_node->children[j];
|
|
244
|
-
new_children[segment] = new_sub_node;
|
|
245
|
-
new_sub_node = get_canonical(p_node->value, p_node->key_hash, new_children);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
global_root = new_sub_node;
|
|
249
|
-
Py_RETURN_NONE;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
static PyObject* method_search(PyObject* self, PyObject* args) {
|
|
253
|
-
unsigned long long h;
|
|
254
|
-
if (!PyArg_ParseTuple(args, "K", &h)) return NULL;
|
|
255
|
-
if (!global_root) Py_RETURN_NONE;
|
|
256
|
-
LQFTNode* curr = global_root;
|
|
257
|
-
int bit_depth = 0;
|
|
258
|
-
while (curr != NULL && curr->value == NULL) {
|
|
259
|
-
uint32_t segment = (h >> bit_depth) & MASK;
|
|
260
|
-
curr = curr->children[segment];
|
|
261
|
-
bit_depth += BIT_PARTITION;
|
|
262
|
-
}
|
|
263
|
-
if (curr != NULL && curr->key_hash == h) return PyUnicode_FromString((char*)curr->value);
|
|
264
|
-
Py_RETURN_NONE;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
static PyObject* method_get_metrics(PyObject* self, PyObject* args) {
|
|
268
|
-
return Py_BuildValue("{s:i}", "physical_nodes", physical_node_count);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
static PyMethodDef LQFTMethods[] = {
|
|
272
|
-
{"insert", method_insert, METH_VARARGS, "Insert key-value"},
|
|
273
|
-
{"delete", method_delete, METH_VARARGS, "Delete key"},
|
|
274
|
-
{"search", method_search, METH_VARARGS, "Search key"},
|
|
275
|
-
{"get_metrics", method_get_metrics, METH_VARARGS, "Get engine stats"},
|
|
276
|
-
{"free_all", method_free_all, METH_VARARGS, "Total memory wipe"},
|
|
277
|
-
{NULL, NULL, 0, NULL}
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
static struct PyModuleDef lqftmodule = { PyModuleDef_HEAD_INIT, "lqft_c_engine", NULL, -1, LQFTMethods };
|
|
281
|
-
|
|
282
|
-
PyMODINIT_FUNC PyInit_lqft_c_engine(void) { return PyModule_Create(&lqftmodule); }
|
|
File without changes
|
{lqft_python_engine-0.2.0 → lqft_python_engine-0.5.0}/lqft_python_engine.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{lqft_python_engine-0.2.0 → lqft_python_engine-0.5.0}/lqft_python_engine.egg-info/requires.txt
RENAMED
|
File without changes
|
{lqft_python_engine-0.2.0 → lqft_python_engine-0.5.0}/lqft_python_engine.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|