lqft-python-engine 1.0.6__tar.gz → 1.0.7__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lqft-python-engine
3
- Version: 1.0.6
3
+ Version: 1.0.7
4
4
  Summary: LQFT Engine: 14.3M Ops/sec O(1) Time | O(Σ) Space Data Structure
5
5
  Home-page: https://github.com/ParjadM/Log-Quantum-Fractal-Tree-LQFT-
6
6
  Author: Parjad Minooei
@@ -353,6 +353,24 @@ static ALIGN_64 PaddedRoot global_roots[NUM_ROOTS];
353
353
  static ALIGN_64 PaddedRWLock root_locks[NUM_ROOTS];
354
354
  static ALIGN_64 PaddedLock stripe_locks[NUM_STRIPES];
355
355
 
356
+ #define VALUE_POOL_BUCKETS 4096
357
+
358
+ typedef struct ValueEntry {
359
+ char* str;
360
+ uint64_t hash;
361
+ volatile long ref_count;
362
+ struct ValueEntry* next;
363
+ } ValueEntry;
364
+
365
+ static ValueEntry* value_pool[VALUE_POOL_BUCKETS] = {0};
366
+ static ALIGN_64 PaddedLock value_pool_locks[VALUE_POOL_BUCKETS];
367
+ static int64_t value_pool_entry_count = 0;
368
+ static int64_t value_pool_total_bytes = 0;
369
+
370
+ static const char* value_acquire(const char* value_ptr);
371
+ static void value_release(const char* value_ptr);
372
+ static void value_pool_clear_all(void);
373
+
356
374
  const uint64_t FNV_OFFSET_BASIS = 14695981039346656037ULL;
357
375
  const uint64_t FNV_PRIME = 1099511628211ULL;
358
376
 
@@ -591,7 +609,7 @@ void decref(LQFTNode* start_node) {
591
609
  local_ret_arr_count = 0;
592
610
  }
593
611
  }
594
- if (node->value) free(node->value);
612
+ if (node->value) value_release((const char*)node->value);
595
613
  node->children = (LQFTNode**)local_ret_node_head;
596
614
  local_ret_node_head = node;
597
615
  if (local_ret_node_count == 0) local_ret_node_tail = node;
@@ -659,7 +677,9 @@ LQFTNode* get_canonical_v2(const char* value_ptr, uint64_t key_hash, LQFTNode**
659
677
  }
660
678
  fast_unlock(&stripe_locks[stripe].flag);
661
679
 
662
- LQFTNode* new_node = create_node(value_ptr ? (void*)portable_strdup(value_ptr) : NULL, key_hash, children, full_hash);
680
+ const char* canonical_value = value_ptr ? value_acquire(value_ptr) : NULL;
681
+ if (value_ptr && !canonical_value) return NULL;
682
+ LQFTNode* new_node = create_node((void*)canonical_value, key_hash, children, full_hash);
663
683
  if (!new_node) return NULL;
664
684
  new_node->ref_count = 1;
665
685
 
@@ -675,7 +695,7 @@ LQFTNode* get_canonical_v2(const char* value_ptr, uint64_t key_hash, LQFTNode**
675
695
  else if (slot->full_hash_val == full_hash && node_matches_signature(slot, value_ptr, key_hash, children)) {
676
696
  ATOMIC_INC(&slot->ref_count);
677
697
  fast_unlock(&stripe_locks[stripe].flag);
678
- if (new_node->value) free(new_node->value);
698
+ if (new_node->value) value_release((const char*)new_node->value);
679
699
  if (new_node->children) {
680
700
  LQFTNode*** arr = (LQFTNode***)new_node->children;
681
701
  arr[0] = (LQFTNode**)local_ret_arr_head;
@@ -822,6 +842,33 @@ char* core_search(uint64_t h, LQFTNode* root) {
822
842
  return NULL;
823
843
  }
824
844
 
845
+ static inline uint64_t hash_key_string(const char* key_str) {
846
+ // One-pass FNV-1a for NUL-terminated UTF-8 keys (avoids strlen + second scan).
847
+ uint64_t h = FNV_OFFSET_BASIS;
848
+ const unsigned char* p = (const unsigned char*)key_str;
849
+ while (*p) {
850
+ h ^= (uint64_t)(*p++);
851
+ h *= FNV_PRIME;
852
+ }
853
+ return h;
854
+ }
855
+
856
+ static inline uint64_t fnv1a_update_u64_decimal(uint64_t hash, uint64_t value) {
857
+ // Append unsigned integer digits directly to FNV stream without heap allocation.
858
+ char rev[20];
859
+ int len = 0;
860
+ do {
861
+ rev[len++] = (char)('0' + (value % 10));
862
+ value /= 10;
863
+ } while (value != 0);
864
+
865
+ for (int i = len - 1; i >= 0; i--) {
866
+ hash ^= (uint64_t)(unsigned char)rev[i];
867
+ hash *= FNV_PRIME;
868
+ }
869
+ return hash;
870
+ }
871
+
825
872
  static void c_internal_insert_rw(uint64_t h, const char* val_str) {
826
873
  // Small TLS cache avoids repeated value hashing for hot constants (e.g. "x", "active").
827
874
  static THREAD_LOCAL const char* last_val_ptr = NULL;
@@ -966,19 +1013,101 @@ static PyObject* method_insert(PyObject* self, PyObject* const* args, Py_ssize_t
966
1013
  Py_RETURN_NONE;
967
1014
  }
968
1015
 
1016
+ static PyObject* method_insert_key_value(PyObject* self, PyObject* const* args, Py_ssize_t nargs) {
1017
+ if (nargs != 2) return NULL;
1018
+ const char* key_str = PyUnicode_AsUTF8(args[0]);
1019
+ const char* val_str = PyUnicode_AsUTF8(args[1]);
1020
+ if (!key_str || !val_str) return NULL;
1021
+ uint64_t h = hash_key_string(key_str);
1022
+ Py_BEGIN_ALLOW_THREADS
1023
+ c_internal_insert_rw(h, val_str);
1024
+ Py_END_ALLOW_THREADS
1025
+ Py_RETURN_NONE;
1026
+ }
1027
+
1028
+ static PyObject* method_bulk_insert_keys(PyObject* self, PyObject* const* args, Py_ssize_t nargs) {
1029
+ if (nargs != 2) return NULL;
1030
+ PyObject* seq = PySequence_Fast(args[0], "bulk_insert_keys expects a sequence of string keys");
1031
+ if (!seq) return NULL;
1032
+
1033
+ const char* val_str = PyUnicode_AsUTF8(args[1]);
1034
+ if (!val_str) {
1035
+ Py_DECREF(seq);
1036
+ return NULL;
1037
+ }
1038
+
1039
+ Py_ssize_t n = PySequence_Fast_GET_SIZE(seq);
1040
+ if (n <= 0) {
1041
+ Py_DECREF(seq);
1042
+ Py_RETURN_NONE;
1043
+ }
1044
+
1045
+ uint64_t* hashes = (uint64_t*)malloc((size_t)n * sizeof(uint64_t));
1046
+ if (!hashes) {
1047
+ Py_DECREF(seq);
1048
+ return PyErr_NoMemory();
1049
+ }
1050
+
1051
+ PyObject** items = PySequence_Fast_ITEMS(seq);
1052
+ for (Py_ssize_t i = 0; i < n; i++) {
1053
+ const char* key_str = PyUnicode_AsUTF8(items[i]);
1054
+ if (!key_str) {
1055
+ free(hashes);
1056
+ Py_DECREF(seq);
1057
+ return NULL;
1058
+ }
1059
+ hashes[i] = hash_key_string(key_str);
1060
+ }
1061
+
1062
+ Py_BEGIN_ALLOW_THREADS
1063
+ for (Py_ssize_t i = 0; i < n; i++) {
1064
+ c_internal_insert_rw(hashes[i], val_str);
1065
+ }
1066
+ Py_END_ALLOW_THREADS
1067
+
1068
+ free(hashes);
1069
+ Py_DECREF(seq);
1070
+ Py_RETURN_NONE;
1071
+ }
1072
+
1073
+ static PyObject* method_bulk_insert_range(PyObject* self, PyObject* const* args, Py_ssize_t nargs) {
1074
+ if (nargs != 4) return NULL;
1075
+ const char* prefix = PyUnicode_AsUTF8(args[0]);
1076
+ if (!prefix) return NULL;
1077
+ unsigned long long start = PyLong_AsUnsignedLongLong(args[1]);
1078
+ if (PyErr_Occurred()) return NULL;
1079
+ unsigned long long count = PyLong_AsUnsignedLongLong(args[2]);
1080
+ if (PyErr_Occurred()) return NULL;
1081
+ const char* val_str = PyUnicode_AsUTF8(args[3]);
1082
+ if (!val_str) return NULL;
1083
+
1084
+ uint64_t prefix_hash = fnv1a_update(FNV_OFFSET_BASIS, prefix, strlen(prefix));
1085
+
1086
+ Py_BEGIN_ALLOW_THREADS
1087
+ for (unsigned long long i = 0; i < count; i++) {
1088
+ uint64_t h = fnv1a_update_u64_decimal(prefix_hash, (uint64_t)(start + i));
1089
+ c_internal_insert_rw(h, val_str);
1090
+ }
1091
+ Py_END_ALLOW_THREADS
1092
+ Py_RETURN_NONE;
1093
+ }
1094
+
969
1095
  static PyObject* method_search(PyObject* self, PyObject* const* args, Py_ssize_t nargs) {
970
1096
  if (nargs != 1) return NULL;
971
1097
  uint64_t h = PyLong_AsUnsignedLongLongMask(args[0]);
972
1098
  uint32_t shard = (uint32_t)((h >> 48) & ROOT_MASK);
973
1099
  char* safe_copy = NULL;
974
- Py_BEGIN_ALLOW_THREADS
1100
+ Py_BEGIN_ALLOW_THREADS
1101
+ LQFTNode* current_root = NULL;
975
1102
  LQFT_RWLOCK_RDLOCK(&root_locks[shard].lock);
976
- LQFTNode* current_root = global_roots[shard].root;
1103
+ current_root = global_roots[shard].root;
1104
+ if (current_root) ATOMIC_INC(&current_root->ref_count);
1105
+ LQFT_RWLOCK_UNLOCK_RD(&root_locks[shard].lock);
977
1106
  if (current_root) {
978
- char* result = core_search(h, current_root);
979
- if (result) safe_copy = portable_strdup(result);
1107
+ char* result = core_search(h, current_root);
1108
+ if (result) safe_copy = portable_strdup(result);
1109
+ decref(current_root);
980
1110
  }
981
- LQFT_RWLOCK_UNLOCK_RD(&root_locks[shard].lock);
982
1111
  Py_END_ALLOW_THREADS
983
1112
  if (safe_copy) {
984
1113
  PyObject* py_res = PyUnicode_FromString(safe_copy);
@@ -987,6 +1116,160 @@ static PyObject* method_search(PyObject* self, PyObject* const* args, Py_ssize_t
987
1116
  Py_RETURN_NONE;
988
1117
  }
989
1118
 
1119
+ static PyObject* method_search_key(PyObject* self, PyObject* const* args, Py_ssize_t nargs) {
1120
+ if (nargs != 1) return NULL;
1121
+ const char* key_str = PyUnicode_AsUTF8(args[0]);
1122
+ if (!key_str) return NULL;
1123
+ uint64_t h = hash_key_string(key_str);
1124
+ uint32_t shard = (uint32_t)((h >> 48) & ROOT_MASK);
1125
+ char* safe_copy = NULL;
1126
+ Py_BEGIN_ALLOW_THREADS
1127
+ LQFTNode* current_root = NULL;
1128
+ LQFT_RWLOCK_RDLOCK(&root_locks[shard].lock);
1129
+ current_root = global_roots[shard].root;
1130
+ if (current_root) ATOMIC_INC(&current_root->ref_count);
1131
+ LQFT_RWLOCK_UNLOCK_RD(&root_locks[shard].lock);
1132
+ if (current_root) {
1133
+ char* result = core_search(h, current_root);
1134
+ if (result) safe_copy = portable_strdup(result);
1135
+ decref(current_root);
1136
+ }
1137
+ Py_END_ALLOW_THREADS
1138
+ if (safe_copy) {
1139
+ PyObject* py_res = PyUnicode_FromString(safe_copy);
1140
+ free(safe_copy);
1141
+ return py_res;
1142
+ }
1143
+ Py_RETURN_NONE;
1144
+ }
1145
+
1146
+ static PyObject* method_contains(PyObject* self, PyObject* const* args, Py_ssize_t nargs) {
1147
+ if (nargs != 1) return NULL;
1148
+ uint64_t h = PyLong_AsUnsignedLongLongMask(args[0]);
1149
+ uint32_t shard = (uint32_t)((h >> 48) & ROOT_MASK);
1150
+ int found = 0;
1151
+ Py_BEGIN_ALLOW_THREADS
1152
+ LQFTNode* current_root = NULL;
1153
+ LQFT_RWLOCK_RDLOCK(&root_locks[shard].lock);
1154
+ current_root = global_roots[shard].root;
1155
+ if (current_root) ATOMIC_INC(&current_root->ref_count);
1156
+ LQFT_RWLOCK_UNLOCK_RD(&root_locks[shard].lock);
1157
+ if (current_root) {
1158
+ if (core_search(h, current_root) != NULL) found = 1;
1159
+ decref(current_root);
1160
+ }
1161
+ Py_END_ALLOW_THREADS
1162
+ if (found) Py_RETURN_TRUE;
1163
+ Py_RETURN_FALSE;
1164
+ }
1165
+
1166
+ static PyObject* method_contains_key(PyObject* self, PyObject* const* args, Py_ssize_t nargs) {
1167
+ if (nargs != 1) return NULL;
1168
+ const char* key_str = PyUnicode_AsUTF8(args[0]);
1169
+ if (!key_str) return NULL;
1170
+ uint64_t h = hash_key_string(key_str);
1171
+ uint32_t shard = (uint32_t)((h >> 48) & ROOT_MASK);
1172
+ int found = 0;
1173
+ Py_BEGIN_ALLOW_THREADS
1174
+ LQFTNode* current_root = NULL;
1175
+ LQFT_RWLOCK_RDLOCK(&root_locks[shard].lock);
1176
+ current_root = global_roots[shard].root;
1177
+ if (current_root) ATOMIC_INC(&current_root->ref_count);
1178
+ LQFT_RWLOCK_UNLOCK_RD(&root_locks[shard].lock);
1179
+ if (current_root) {
1180
+ if (core_search(h, current_root) != NULL) found = 1;
1181
+ decref(current_root);
1182
+ }
1183
+ Py_END_ALLOW_THREADS
1184
+ if (found) Py_RETURN_TRUE;
1185
+ Py_RETURN_FALSE;
1186
+ }
1187
+
1188
+ static PyObject* method_bulk_contains_count(PyObject* self, PyObject* const* args, Py_ssize_t nargs) {
1189
+ if (nargs != 1) return NULL;
1190
+ PyObject* seq = PySequence_Fast(args[0], "bulk_contains_count expects a sequence of string keys");
1191
+ if (!seq) return NULL;
1192
+
1193
+ Py_ssize_t n = PySequence_Fast_GET_SIZE(seq);
1194
+ if (n <= 0) {
1195
+ Py_DECREF(seq);
1196
+ return PyLong_FromLong(0);
1197
+ }
1198
+
1199
+ uint64_t* hashes = (uint64_t*)malloc((size_t)n * sizeof(uint64_t));
1200
+ if (!hashes) {
1201
+ Py_DECREF(seq);
1202
+ return PyErr_NoMemory();
1203
+ }
1204
+
1205
+ PyObject** items = PySequence_Fast_ITEMS(seq);
1206
+ for (Py_ssize_t i = 0; i < n; i++) {
1207
+ const char* key_str = PyUnicode_AsUTF8(items[i]);
1208
+ if (!key_str) {
1209
+ free(hashes);
1210
+ Py_DECREF(seq);
1211
+ return NULL;
1212
+ }
1213
+ hashes[i] = hash_key_string(key_str);
1214
+ }
1215
+
1216
+ Py_ssize_t hit_count = 0;
1217
+ Py_BEGIN_ALLOW_THREADS
1218
+ for (Py_ssize_t i = 0; i < n; i++) {
1219
+ uint64_t h = hashes[i];
1220
+ uint32_t shard = (uint32_t)((h >> 48) & ROOT_MASK);
1221
+ LQFTNode* current_root = NULL;
1222
+
1223
+ LQFT_RWLOCK_RDLOCK(&root_locks[shard].lock);
1224
+ current_root = global_roots[shard].root;
1225
+ if (current_root) ATOMIC_INC(&current_root->ref_count);
1226
+ LQFT_RWLOCK_UNLOCK_RD(&root_locks[shard].lock);
1227
+
1228
+ if (current_root) {
1229
+ if (core_search(h, current_root) != NULL) hit_count++;
1230
+ decref(current_root);
1231
+ }
1232
+ }
1233
+ Py_END_ALLOW_THREADS
1234
+
1235
+ free(hashes);
1236
+ Py_DECREF(seq);
1237
+ return PyLong_FromSsize_t(hit_count);
1238
+ }
1239
+
1240
+ static PyObject* method_bulk_contains_range_count(PyObject* self, PyObject* const* args, Py_ssize_t nargs) {
1241
+ if (nargs != 3) return NULL;
1242
+ const char* prefix = PyUnicode_AsUTF8(args[0]);
1243
+ if (!prefix) return NULL;
1244
+ unsigned long long start = PyLong_AsUnsignedLongLong(args[1]);
1245
+ if (PyErr_Occurred()) return NULL;
1246
+ unsigned long long count = PyLong_AsUnsignedLongLong(args[2]);
1247
+ if (PyErr_Occurred()) return NULL;
1248
+
1249
+ uint64_t prefix_hash = fnv1a_update(FNV_OFFSET_BASIS, prefix, strlen(prefix));
1250
+ unsigned long long hit_count = 0;
1251
+
1252
+ Py_BEGIN_ALLOW_THREADS
1253
+ for (unsigned long long i = 0; i < count; i++) {
1254
+ uint64_t h = fnv1a_update_u64_decimal(prefix_hash, (uint64_t)(start + i));
1255
+ uint32_t shard = (uint32_t)((h >> 48) & ROOT_MASK);
1256
+ LQFTNode* current_root = NULL;
1257
+
1258
+ LQFT_RWLOCK_RDLOCK(&root_locks[shard].lock);
1259
+ current_root = global_roots[shard].root;
1260
+ if (current_root) ATOMIC_INC(&current_root->ref_count);
1261
+ LQFT_RWLOCK_UNLOCK_RD(&root_locks[shard].lock);
1262
+
1263
+ if (current_root) {
1264
+ if (core_search(h, current_root) != NULL) hit_count++;
1265
+ decref(current_root);
1266
+ }
1267
+ }
1268
+ Py_END_ALLOW_THREADS
1269
+
1270
+ return PyLong_FromUnsignedLongLong(hit_count);
1271
+ }
1272
+
990
1273
  static PyObject* method_delete(PyObject* self, PyObject* const* args, Py_ssize_t nargs) {
991
1274
  if (nargs != 1) return NULL;
992
1275
  uint64_t h = PyLong_AsUnsignedLongLongMask(args[0]);
@@ -1015,6 +1298,36 @@ static PyObject* method_delete(PyObject* self, PyObject* const* args, Py_ssize_t
1015
1298
  Py_RETURN_NONE;
1016
1299
  }
1017
1300
 
1301
+ static PyObject* method_delete_key(PyObject* self, PyObject* const* args, Py_ssize_t nargs) {
1302
+ if (nargs != 1) return NULL;
1303
+ const char* key_str = PyUnicode_AsUTF8(args[0]);
1304
+ if (!key_str) return NULL;
1305
+ uint64_t h = hash_key_string(key_str);
1306
+ uint32_t shard = (uint32_t)((h >> 48) & ROOT_MASK);
1307
+ Py_BEGIN_ALLOW_THREADS
1308
+ while(1) {
1309
+ LQFT_RWLOCK_RDLOCK(&root_locks[shard].lock);
1310
+ LQFTNode* old_root = global_roots[shard].root;
1311
+ if (old_root) ATOMIC_INC(&old_root->ref_count);
1312
+ LQFT_RWLOCK_UNLOCK_RD(&root_locks[shard].lock);
1313
+ LQFTNode* next = core_delete_internal(h, old_root);
1314
+ LQFT_RWLOCK_WRLOCK(&root_locks[shard].lock);
1315
+ if (global_roots[shard].root == old_root) {
1316
+ global_roots[shard].root = next;
1317
+ LQFT_RWLOCK_UNLOCK_WR(&root_locks[shard].lock);
1318
+ if (old_root) { decref(old_root); decref(old_root); }
1319
+ break;
1320
+ } else {
1321
+ LQFT_RWLOCK_UNLOCK_WR(&root_locks[shard].lock);
1322
+ if (next) decref(next);
1323
+ if (old_root) decref(old_root);
1324
+ for(volatile int s = 0; s < 16; s++) { CPU_PAUSE; }
1325
+ }
1326
+ }
1327
+ Py_END_ALLOW_THREADS
1328
+ Py_RETURN_NONE;
1329
+ }
1330
+
1018
1331
  static PyObject* method_get_metrics(PyObject* self, PyObject* args) {
1019
1332
  int64_t total_phys_added = 0;
1020
1333
  int64_t total_phys_freed = 0;
@@ -1026,19 +1339,30 @@ static PyObject* method_get_metrics(PyObject* self, PyObject* args) {
1026
1339
  }
1027
1340
  int64_t net_phys = total_phys_added - total_phys_freed;
1028
1341
  double deduplication_ratio = net_phys > 0 ? (double)total_logical / (double)net_phys : 0.0;
1029
- return Py_BuildValue("{s:L, s:L, s:d}", "physical_nodes", net_phys, "logical_inserts", total_logical, "deduplication_ratio", deduplication_ratio);
1342
+ double value_pool_bytes_per_logical_insert = total_logical > 0
1343
+ ? (double)value_pool_total_bytes / (double)total_logical
1344
+ : 0.0;
1345
+ return Py_BuildValue(
1346
+ "{s:L, s:L, s:d, s:L, s:L, s:d}",
1347
+ "physical_nodes", net_phys,
1348
+ "logical_inserts", total_logical,
1349
+ "deduplication_ratio", deduplication_ratio,
1350
+ "value_pool_entries", value_pool_entry_count,
1351
+ "value_pool_bytes", value_pool_total_bytes,
1352
+ "value_pool_bytes_per_logical_insert", value_pool_bytes_per_logical_insert
1353
+ );
1030
1354
  }
1031
1355
 
1032
1356
  static PyObject* method_free_all(PyObject* self, PyObject* args) {
1033
1357
  Py_BEGIN_ALLOW_THREADS
1034
1358
  for(int i = 0; i < NUM_ROOTS; i++) LQFT_RWLOCK_WRLOCK(&root_locks[i].lock);
1035
1359
  for(int i = 0; i < NUM_STRIPES; i++) fast_lock_backoff(&stripe_locks[i].flag);
1036
- if (registry) {
1360
+ if (registry) {
1037
1361
  for(int i = 0; i < NUM_STRIPES * STRIPE_SIZE; i++) {
1038
- if (registry[i] && registry[i] != TOMBSTONE) { if (registry[i]->value) free(registry[i]->value); }
1039
- registry[i] = NULL;
1362
+ registry[i] = NULL;
1040
1363
  }
1041
1364
  }
1365
+ value_pool_clear_all();
1042
1366
  fast_lock_backoff(&global_chunk_lock.flag);
1043
1367
  NodeChunk* nc = global_node_chunks;
1044
1368
  while(nc) { NodeChunk* n = nc->next_global; free_node_chunk(nc); nc = n; }
@@ -1082,8 +1406,17 @@ static PyObject* method_free_all(PyObject* self, PyObject* args) {
1082
1406
 
1083
1407
  static PyMethodDef LQFTMethods[] = {
1084
1408
  {"insert", (PyCFunction)method_insert, METH_FASTCALL, "Fast-path insert single key"},
1409
+ {"insert_key_value", (PyCFunction)method_insert_key_value, METH_FASTCALL, "Insert using string key/value fast path"},
1410
+ {"bulk_insert_keys", (PyCFunction)method_bulk_insert_keys, METH_FASTCALL, "Bulk insert string keys with one value"},
1411
+ {"bulk_insert_range", (PyCFunction)method_bulk_insert_range, METH_FASTCALL, "Bulk insert generated keys prefix+index range"},
1085
1412
  {"search", (PyCFunction)method_search, METH_FASTCALL, "Fast-path search single key"},
1413
+ {"search_key", (PyCFunction)method_search_key, METH_FASTCALL, "Search using string key fast path"},
1414
+ {"contains", (PyCFunction)method_contains, METH_FASTCALL, "Contains check by pre-hashed key"},
1415
+ {"contains_key", (PyCFunction)method_contains_key, METH_FASTCALL, "Contains check using string key fast path"},
1416
+ {"bulk_contains_count", (PyCFunction)method_bulk_contains_count, METH_FASTCALL, "Bulk contains checks, returns hit count"},
1417
+ {"bulk_contains_range_count", (PyCFunction)method_bulk_contains_range_count, METH_FASTCALL, "Bulk contains on generated keys prefix+index range"},
1086
1418
  {"delete", (PyCFunction)method_delete, METH_FASTCALL, "Fast-path delete single key"},
1419
+ {"delete_key", (PyCFunction)method_delete_key, METH_FASTCALL, "Delete using string key fast path"},
1087
1420
  {"internal_stress_test", (PyCFunction)method_internal_stress_test, METH_FASTCALL, "Run native C stress test"},
1088
1421
  {"get_metrics", method_get_metrics, METH_VARARGS, "Get stats"},
1089
1422
  {"free_all", method_free_all, METH_VARARGS, "Wipe memory"},
@@ -1099,6 +1432,7 @@ PyMODINIT_FUNC PyInit_lqft_c_engine(void) {
1099
1432
  }
1100
1433
  registry = (LQFTNode**)calloc(NUM_STRIPES * STRIPE_SIZE, sizeof(LQFTNode*));
1101
1434
  for(int i = 0; i < NUM_STRIPES; i++) stripe_locks[i].flag = 0;
1435
+ for(int i = 0; i < VALUE_POOL_BUCKETS; i++) value_pool_locks[i].flag = 0;
1102
1436
  for(int j = 0; j < 4; j++) {
1103
1437
  NodeChunk* nc = alloc_node_chunk();
1104
1438
  ChildChunk* cc = alloc_child_chunk();
@@ -1112,4 +1446,89 @@ PyMODINIT_FUNC PyInit_lqft_c_engine(void) {
1112
1446
  pthread_t bg_tid; pthread_create(&bg_tid, NULL, background_alloc_thread, NULL); pthread_detach(bg_tid);
1113
1447
  #endif
1114
1448
  return PyModule_Create(&lqftmodule);
1449
+ }
1450
+
1451
+ static const char* value_acquire(const char* value_ptr) {
1452
+ if (!value_ptr) return NULL;
1453
+
1454
+ uint64_t h = fnv1a_update(FNV_OFFSET_BASIS, value_ptr, strlen(value_ptr));
1455
+ uint32_t bucket = (uint32_t)(h & (VALUE_POOL_BUCKETS - 1));
1456
+
1457
+ fast_lock_backoff(&value_pool_locks[bucket].flag);
1458
+ ValueEntry* cur = value_pool[bucket];
1459
+ while (cur) {
1460
+ if (cur->hash == h && strcmp(cur->str, value_ptr) == 0) {
1461
+ ATOMIC_INC(&cur->ref_count);
1462
+ fast_unlock(&value_pool_locks[bucket].flag);
1463
+ return cur->str;
1464
+ }
1465
+ cur = cur->next;
1466
+ }
1467
+
1468
+ ValueEntry* e = (ValueEntry*)malloc(sizeof(ValueEntry));
1469
+ if (!e) {
1470
+ fast_unlock(&value_pool_locks[bucket].flag);
1471
+ return NULL;
1472
+ }
1473
+ size_t value_len = strlen(value_ptr);
1474
+ e->str = portable_strdup(value_ptr);
1475
+ if (!e->str) {
1476
+ free(e);
1477
+ fast_unlock(&value_pool_locks[bucket].flag);
1478
+ return NULL;
1479
+ }
1480
+ e->hash = h;
1481
+ e->ref_count = 1;
1482
+ e->next = value_pool[bucket];
1483
+ value_pool[bucket] = e;
1484
+ value_pool_entry_count += 1;
1485
+ value_pool_total_bytes += (int64_t)(value_len + 1);
1486
+ fast_unlock(&value_pool_locks[bucket].flag);
1487
+ return e->str;
1488
+ }
1489
+
1490
+ static void value_release(const char* value_ptr) {
1491
+ if (!value_ptr) return;
1492
+
1493
+ uint64_t h = fnv1a_update(FNV_OFFSET_BASIS, value_ptr, strlen(value_ptr));
1494
+ uint32_t bucket = (uint32_t)(h & (VALUE_POOL_BUCKETS - 1));
1495
+
1496
+ fast_lock_backoff(&value_pool_locks[bucket].flag);
1497
+ ValueEntry* prev = NULL;
1498
+ ValueEntry* cur = value_pool[bucket];
1499
+ while (cur) {
1500
+ if (cur->hash == h && (cur->str == value_ptr || strcmp(cur->str, value_ptr) == 0)) {
1501
+ long new_ref = ATOMIC_DEC(&cur->ref_count);
1502
+ if (new_ref == 0) {
1503
+ if (prev) prev->next = cur->next;
1504
+ else value_pool[bucket] = cur->next;
1505
+ value_pool_entry_count -= 1;
1506
+ value_pool_total_bytes -= (int64_t)(strlen(cur->str) + 1);
1507
+ free(cur->str);
1508
+ free(cur);
1509
+ }
1510
+ fast_unlock(&value_pool_locks[bucket].flag);
1511
+ return;
1512
+ }
1513
+ prev = cur;
1514
+ cur = cur->next;
1515
+ }
1516
+ fast_unlock(&value_pool_locks[bucket].flag);
1517
+ }
1518
+
1519
+ static void value_pool_clear_all(void) {
1520
+ for (uint32_t b = 0; b < VALUE_POOL_BUCKETS; b++) {
1521
+ fast_lock_backoff(&value_pool_locks[b].flag);
1522
+ ValueEntry* cur = value_pool[b];
1523
+ while (cur) {
1524
+ ValueEntry* next = cur->next;
1525
+ free(cur->str);
1526
+ free(cur);
1527
+ cur = next;
1528
+ }
1529
+ value_pool[b] = NULL;
1530
+ fast_unlock(&value_pool_locks[b].flag);
1531
+ }
1532
+ value_pool_entry_count = 0;
1533
+ value_pool_total_bytes = 0;
1115
1534
  }
@@ -0,0 +1,284 @@
1
+ import os
2
+ import sys
3
+ import hashlib
4
+ import threading
5
+
6
+ try:
7
+ import psutil
8
+ except Exception:
9
+ psutil = None
10
+
11
+ # ---------------------------------------------------------
12
+ # STRICT NATIVE ENTERPRISE WRAPPER (v1.0.5)
13
+ # ---------------------------------------------------------
14
+ # Architect: Parjad Minooei
15
+ # Target: McMaster B.Tech / UofT MScAC Portfolio
16
+
17
+ try:
18
+ import lqft_c_engine
19
+ except ImportError:
20
+ print("\n[!] CRITICAL FATAL ERROR: Native C-Engine not found.")
21
+ print("[!] The LQFT is now a strictly native database. Pure Python fallback is disabled.")
22
+ print("[!] Run: python setup.py build_ext --inplace\n")
23
+ sys.exit(1)
24
+
25
+ class LQFT:
26
+ _instance_lock = threading.Lock()
27
+ _live_instances = 0
28
+ __slots__ = (
29
+ "is_native",
30
+ "auto_purge_enabled",
31
+ "max_memory_mb",
32
+ "total_ops",
33
+ "migration_threshold",
34
+ "_process",
35
+ "_closed",
36
+ "_native_insert_kv",
37
+ "_native_search_key",
38
+ "_native_delete_key",
39
+ "_native_contains_key",
40
+ "_native_bulk_insert_keys",
41
+ "_native_bulk_contains_count",
42
+ "_native_bulk_insert_range",
43
+ "_native_bulk_contains_range_count",
44
+ )
45
+
46
+ # F-03 & F-04: Restored migration_threshold to sync API signatures across the suite
47
+ def __init__(self, migration_threshold=50000):
48
+ self.is_native = True
49
+ # Keep destructive purge opt-in; global C-engine state can be shared by multiple wrappers.
50
+ self.auto_purge_enabled = False
51
+ self.max_memory_mb = 1000.0
52
+ self.total_ops = 0
53
+ self.migration_threshold = migration_threshold
54
+ self._process = psutil.Process(os.getpid()) if psutil else None
55
+ self._closed = False
56
+ self._native_insert_kv = getattr(lqft_c_engine, "insert_key_value", None)
57
+ self._native_search_key = getattr(lqft_c_engine, "search_key", None)
58
+ self._native_delete_key = getattr(lqft_c_engine, "delete_key", None)
59
+ self._native_contains_key = getattr(lqft_c_engine, "contains_key", None)
60
+ self._native_bulk_insert_keys = getattr(lqft_c_engine, "bulk_insert_keys", None)
61
+ self._native_bulk_contains_count = getattr(lqft_c_engine, "bulk_contains_count", None)
62
+ self._native_bulk_insert_range = getattr(lqft_c_engine, "bulk_insert_range", None)
63
+ self._native_bulk_contains_range_count = getattr(lqft_c_engine, "bulk_contains_range_count", None)
64
+ with LQFT._instance_lock:
65
+ LQFT._live_instances += 1
66
+
67
+ def _validate_type(self, key, value=None):
68
+ if not isinstance(key, str):
69
+ raise TypeError(f"LQFT keys must be strings. Received: {type(key).__name__}")
70
+ if value is not None and not isinstance(value, str):
71
+ raise TypeError(f"LQFT values must be strings. Received: {type(value).__name__}")
72
+
73
+ def _get_64bit_hash(self, key):
74
+ # Deterministic 64-bit hash keeps key mapping stable across processes/runs.
75
+ return int.from_bytes(hashlib.blake2b(key.encode(), digest_size=8).digest(), "little")
76
+
77
+ def _current_memory_mb(self):
78
+ if self._process is None:
79
+ # Fallback for environments where psutil binary wheels are unavailable.
80
+ if os.name == "nt":
81
+ try:
82
+ import ctypes
83
+ from ctypes import wintypes
84
+
85
+ class PROCESS_MEMORY_COUNTERS(ctypes.Structure):
86
+ _fields_ = [
87
+ ("cb", wintypes.DWORD),
88
+ ("PageFaultCount", wintypes.DWORD),
89
+ ("PeakWorkingSetSize", ctypes.c_size_t),
90
+ ("WorkingSetSize", ctypes.c_size_t),
91
+ ("QuotaPeakPagedPoolUsage", ctypes.c_size_t),
92
+ ("QuotaPagedPoolUsage", ctypes.c_size_t),
93
+ ("QuotaPeakNonPagedPoolUsage", ctypes.c_size_t),
94
+ ("QuotaNonPagedPoolUsage", ctypes.c_size_t),
95
+ ("PagefileUsage", ctypes.c_size_t),
96
+ ("PeakPagefileUsage", ctypes.c_size_t),
97
+ ]
98
+
99
+ counters = PROCESS_MEMORY_COUNTERS()
100
+ counters.cb = ctypes.sizeof(PROCESS_MEMORY_COUNTERS)
101
+ handle = ctypes.windll.kernel32.GetCurrentProcess()
102
+ get_process_memory_info = ctypes.windll.psapi.GetProcessMemoryInfo
103
+ get_process_memory_info.argtypes = [
104
+ wintypes.HANDLE,
105
+ ctypes.POINTER(PROCESS_MEMORY_COUNTERS),
106
+ wintypes.DWORD,
107
+ ]
108
+ get_process_memory_info.restype = wintypes.BOOL
109
+ ok = get_process_memory_info(
110
+ handle,
111
+ ctypes.byref(counters),
112
+ counters.cb,
113
+ )
114
+ if ok:
115
+ return counters.WorkingSetSize / (1024 * 1024)
116
+ except Exception:
117
+ return 0.0
118
+ return 0.0
119
+ try:
120
+ return self._process.memory_info().rss / (1024 * 1024)
121
+ except Exception:
122
+ return 0.0
123
+
124
+ def set_auto_purge_threshold(self, threshold: float):
125
+ threshold = float(threshold)
126
+ if threshold <= 0:
127
+ raise ValueError("Auto-purge threshold must be > 0 MB.")
128
+ self.max_memory_mb = threshold
129
+ self.auto_purge_enabled = True
130
+
131
+ def disable_auto_purge(self):
132
+ self.auto_purge_enabled = False
133
+
134
+ def purge(self):
135
+ current_mb = self._current_memory_mb()
136
+ with LQFT._instance_lock:
137
+ live = LQFT._live_instances
138
+ if live > 1:
139
+ print(
140
+ f"\n[WARN CIRCUIT Breaker] Memory {current_mb:.1f} MB but purge skipped "
141
+ f"because {live} LQFT instances are active (shared global engine state)."
142
+ )
143
+ return
144
+ print(f"\n[WARN CIRCUIT Breaker] Engine exceeded limit (Currently {current_mb:.1f} MB). Auto-Purging!")
145
+ self.clear()
146
+
147
+ def get_stats(self):
148
+ return lqft_c_engine.get_metrics()
149
+
150
+ # F-02: Standardized Metric Mapping (Dunder Method)
151
+ def __len__(self):
152
+ """Allows native Python len() to fetch logical_inserts from the C-Engine."""
153
+ stats = self.get_stats()
154
+ # Maps directly to the sharded hardware counters in the C-kernel
155
+ return stats.get('logical_inserts', 0)
156
+
157
+ def clear(self):
158
+ # Global clear (shared native state). Keep explicit to avoid accidental data loss.
159
+ return lqft_c_engine.free_all()
160
+
161
+ def insert(self, key, value):
162
+ if type(key) is not str:
163
+ raise TypeError(f"LQFT keys must be strings. Received: {type(key).__name__}")
164
+ if type(value) is not str:
165
+ raise TypeError(f"LQFT values must be strings. Received: {type(value).__name__}")
166
+
167
+ # Heuristic Circuit Breaker check
168
+ if self.auto_purge_enabled:
169
+ self.total_ops += 1
170
+ if self.total_ops % 5000 == 0:
171
+ current_mb = self._current_memory_mb()
172
+ if current_mb >= self.max_memory_mb:
173
+ self.purge()
174
+
175
+ if self._native_insert_kv is not None:
176
+ self._native_insert_kv(key, value)
177
+ return
178
+
179
+ h = self._get_64bit_hash(key)
180
+ lqft_c_engine.insert(h, value)
181
+
182
+ def search(self, key):
183
+ if type(key) is not str:
184
+ raise TypeError(f"LQFT keys must be strings. Received: {type(key).__name__}")
185
+ if self._native_search_key is not None:
186
+ return self._native_search_key(key)
187
+
188
+ h = self._get_64bit_hash(key)
189
+ return lqft_c_engine.search(h)
190
+
191
+ def remove(self, key):
192
+ if type(key) is not str:
193
+ raise TypeError(f"LQFT keys must be strings. Received: {type(key).__name__}")
194
+ if self._native_delete_key is not None:
195
+ self._native_delete_key(key)
196
+ return
197
+
198
+ h = self._get_64bit_hash(key)
199
+ if hasattr(lqft_c_engine, 'delete'):
200
+ lqft_c_engine.delete(h)
201
+
202
+ def delete(self, key):
203
+ self.remove(key)
204
+
205
+ def contains(self, key):
206
+ if type(key) is not str:
207
+ raise TypeError(f"LQFT keys must be strings. Received: {type(key).__name__}")
208
+ if self._native_contains_key is not None:
209
+ return bool(self._native_contains_key(key))
210
+ return self.search(key) is not None
211
+
212
+ def bulk_insert(self, keys, value):
213
+ if type(value) is not str:
214
+ raise TypeError(f"LQFT values must be strings. Received: {type(value).__name__}")
215
+ if self._native_bulk_insert_keys is not None:
216
+ self._native_bulk_insert_keys(keys, value)
217
+ return
218
+ for key in keys:
219
+ self.insert(key, value)
220
+
221
+ def bulk_contains_count(self, keys):
222
+ if self._native_bulk_contains_count is not None:
223
+ return int(self._native_bulk_contains_count(keys))
224
+ count = 0
225
+ for key in keys:
226
+ if self.contains(key):
227
+ count += 1
228
+ return count
229
+
230
+ def bulk_insert_range(self, prefix, start, count, value):
231
+ if type(prefix) is not str:
232
+ raise TypeError(f"LQFT keys must be strings. Received: {type(prefix).__name__}")
233
+ if type(value) is not str:
234
+ raise TypeError(f"LQFT values must be strings. Received: {type(value).__name__}")
235
+ if self._native_bulk_insert_range is not None:
236
+ self._native_bulk_insert_range(prefix, int(start), int(count), value)
237
+ return
238
+ end = int(start) + int(count)
239
+ for i in range(int(start), end):
240
+ self.insert(f"{prefix}{i}", value)
241
+
242
+ def bulk_contains_range_count(self, prefix, start, count):
243
+ if type(prefix) is not str:
244
+ raise TypeError(f"LQFT keys must be strings. Received: {type(prefix).__name__}")
245
+ if self._native_bulk_contains_range_count is not None:
246
+ return int(self._native_bulk_contains_range_count(prefix, int(start), int(count)))
247
+ hit = 0
248
+ end = int(start) + int(count)
249
+ for i in range(int(start), end):
250
+ if self.contains(f"{prefix}{i}"):
251
+ hit += 1
252
+ return hit
253
+
254
+ def __setitem__(self, key, value):
255
+ self.insert(key, value)
256
+
257
+ def __getitem__(self, key):
258
+ res = self.search(key)
259
+ if res is None:
260
+ raise KeyError(key)
261
+ return res
262
+
263
+ def __delitem__(self, key):
264
+ self.delete(key)
265
+
266
+ def __del__(self):
267
+ try:
268
+ if not self._closed:
269
+ with LQFT._instance_lock:
270
+ LQFT._live_instances = max(0, LQFT._live_instances - 1)
271
+ self._closed = True
272
+ except Exception:
273
+ pass
274
+
275
+ def status(self):
276
+ return {
277
+ "mode": "Strict Native C-Engine (Arena Allocator)",
278
+ "items": lqft_c_engine.get_metrics().get('physical_nodes', 0),
279
+ "threshold": f"{self.max_memory_mb} MB Circuit Breaker",
280
+ "auto_purge_enabled": self.auto_purge_enabled,
281
+ }
282
+
283
+ # Retain AdaptiveLQFT alias to support legacy benchmark scripts gracefully
284
+ AdaptiveLQFT = LQFT
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lqft-python-engine
3
- Version: 1.0.6
3
+ Version: 1.0.7
4
4
  Summary: LQFT Engine: 14.3M Ops/sec O(1) Time | O(Σ) Space Data Structure
5
5
  Home-page: https://github.com/ParjadM/Log-Quantum-Fractal-Tree-LQFT-
6
6
  Author: Parjad Minooei
@@ -3,7 +3,7 @@ import os
3
3
  import sys
4
4
 
5
5
  # ---------------------------------------------------------
6
- # LQFT BUILD SYSTEM - V1.0.6 (Apple Silicon M3 Hotfix)
6
+ # LQFT BUILD SYSTEM - V1.0.7 (Apple Silicon M3 Hotfix)
7
7
  # Architect: Parjad Minooei
8
8
  # ---------------------------------------------------------
9
9
 
@@ -40,7 +40,7 @@ lqft_extension = Extension(
40
40
 
41
41
  setup(
42
42
  name="lqft-python-engine",
43
- version="1.0.6",
43
+ version="1.0.7",
44
44
  description="LQFT Engine: 14.3M Ops/sec O(1) Time | O(Σ) Space Data Structure",
45
45
  long_description=long_description,
46
46
  long_description_content_type="text/markdown",
@@ -1,146 +0,0 @@
1
- import os
2
- import sys
3
- import hashlib
4
- import threading
5
-
6
- try:
7
- import psutil
8
- except Exception:
9
- psutil = None
10
-
11
- # ---------------------------------------------------------
12
- # STRICT NATIVE ENTERPRISE WRAPPER (v1.0.5)
13
- # ---------------------------------------------------------
14
- # Architect: Parjad Minooei
15
- # Target: McMaster B.Tech / UofT MScAC Portfolio
16
-
17
- try:
18
- import lqft_c_engine
19
- except ImportError:
20
- print("\n[!] CRITICAL FATAL ERROR: Native C-Engine not found.")
21
- print("[!] The LQFT is now a strictly native database. Pure Python fallback is disabled.")
22
- print("[!] Run: python setup.py build_ext --inplace\n")
23
- sys.exit(1)
24
-
25
- class LQFT:
26
- _instance_lock = threading.Lock()
27
- _live_instances = 0
28
-
29
- # F-03 & F-04: Restored migration_threshold to sync API signatures across the suite
30
- def __init__(self, migration_threshold=50000):
31
- self.is_native = True
32
- # Keep destructive purge opt-in; global C-engine state can be shared by multiple wrappers.
33
- self.auto_purge_enabled = False
34
- self.max_memory_mb = 1000.0
35
- self.total_ops = 0
36
- self.migration_threshold = migration_threshold
37
- self._process = psutil.Process(os.getpid()) if psutil else None
38
- self._closed = False
39
- with LQFT._instance_lock:
40
- LQFT._live_instances += 1
41
-
42
- def _validate_type(self, key, value=None):
43
- if not isinstance(key, str):
44
- raise TypeError(f"LQFT keys must be strings. Received: {type(key).__name__}")
45
- if value is not None and not isinstance(value, str):
46
- raise TypeError(f"LQFT values must be strings. Received: {type(value).__name__}")
47
-
48
- def _get_64bit_hash(self, key):
49
- # Deterministic 64-bit hash keeps key mapping stable across processes/runs.
50
- return int.from_bytes(hashlib.blake2b(key.encode(), digest_size=8).digest(), "little")
51
-
52
- def _current_memory_mb(self):
53
- if self._process is None:
54
- return 0.0
55
- try:
56
- return self._process.memory_info().rss / (1024 * 1024)
57
- except Exception:
58
- return 0.0
59
-
60
- def set_auto_purge_threshold(self, threshold: float):
61
- self.max_memory_mb = threshold
62
-
63
- def purge(self):
64
- current_mb = self._current_memory_mb()
65
- with LQFT._instance_lock:
66
- live = LQFT._live_instances
67
- if live > 1:
68
- print(
69
- f"\n[⚠️ CIRCUIT Breaker] Memory {current_mb:.1f} MB but purge skipped "
70
- f"because {live} LQFT instances are active (shared global engine state)."
71
- )
72
- return
73
- print(f"\n[⚠️ CIRCUIT Breaker] Engine exceeded limit (Currently {current_mb:.1f} MB). Auto-Purging!")
74
- self.clear()
75
-
76
- def get_stats(self):
77
- return lqft_c_engine.get_metrics()
78
-
79
- # F-02: Standardized Metric Mapping (Dunder Method)
80
- def __len__(self):
81
- """Allows native Python len() to fetch logical_inserts from the C-Engine."""
82
- stats = self.get_stats()
83
- # Maps directly to the sharded hardware counters in the C-kernel
84
- return stats.get('logical_inserts', 0)
85
-
86
- def clear(self):
87
- # Global clear (shared native state). Keep explicit to avoid accidental data loss.
88
- return lqft_c_engine.free_all()
89
-
90
- def insert(self, key, value):
91
- self._validate_type(key, value)
92
- self.total_ops += 1
93
-
94
- # Heuristic Circuit Breaker check
95
- if self.auto_purge_enabled and self.total_ops % 5000 == 0:
96
- current_mb = self._current_memory_mb()
97
- if current_mb >= self.max_memory_mb:
98
- self.purge()
99
-
100
- h = self._get_64bit_hash(key)
101
- lqft_c_engine.insert(h, value)
102
-
103
- def search(self, key):
104
- self._validate_type(key)
105
- h = self._get_64bit_hash(key)
106
- return lqft_c_engine.search(h)
107
-
108
- def remove(self, key):
109
- self._validate_type(key)
110
- h = self._get_64bit_hash(key)
111
- if hasattr(lqft_c_engine, 'delete'):
112
- lqft_c_engine.delete(h)
113
-
114
- def delete(self, key):
115
- self.remove(key)
116
-
117
- def __setitem__(self, key, value):
118
- self.insert(key, value)
119
-
120
- def __getitem__(self, key):
121
- res = self.search(key)
122
- if res is None:
123
- raise KeyError(key)
124
- return res
125
-
126
- def __delitem__(self, key):
127
- self.delete(key)
128
-
129
- def __del__(self):
130
- try:
131
- if not self._closed:
132
- with LQFT._instance_lock:
133
- LQFT._live_instances = max(0, LQFT._live_instances - 1)
134
- self._closed = True
135
- except Exception:
136
- pass
137
-
138
- def status(self):
139
- return {
140
- "mode": "Strict Native C-Engine (Arena Allocator)",
141
- "items": lqft_c_engine.get_metrics().get('physical_nodes', 0),
142
- "threshold": f"{self.max_memory_mb} MB Circuit Breaker"
143
- }
144
-
145
- # Retain AdaptiveLQFT alias to support legacy benchmark scripts gracefully
146
- AdaptiveLQFT = LQFT