@tty-pt/islet 0.0.0-stage → 1.3.1
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.
- package/LICENSE +24 -0
- package/README.md +98 -2
- package/assets/logo.png +0 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +110 -0
- package/dist/islet.wasm +0 -0
- package/include/ttypt/islet.h +1187 -0
- package/include/ttypt/morton.h +536 -0
- package/include/ttypt/point.h +696 -0
- package/include/ttypt/pointcfg.h +200 -0
- package/islet.pc +10 -0
- package/package.json +50 -4
|
@@ -0,0 +1,1187 @@
|
|
|
1
|
+
#ifndef ISLET_H
|
|
2
|
+
#define ISLET_H
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @file islet.h
|
|
6
|
+
* @brief Public API for libislet — spatial indexing with Morton codes.
|
|
7
|
+
*
|
|
8
|
+
* Islet provides efficient spatial database operations using Morton codes
|
|
9
|
+
* (Z-order space-filling curves) for multi-dimensional coordinate indexing.
|
|
10
|
+
* Built on top of libcorm for persistence and hash table operations.
|
|
11
|
+
*
|
|
12
|
+
* Coordinates are signed 16-bit integers (int16_t) ranging from -32768 to 32767,
|
|
13
|
+
* suitable for game worlds, voxel engines, and spatial simulations.
|
|
14
|
+
*
|
|
15
|
+
* @note Depends on libcorm >= 0.8.0 (per-key multi-value chains,
|
|
16
|
+
* corm_get_multi, rec.h) and libstele.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
#include <stdint.h>
|
|
20
|
+
#include <ttypt/corm.h>
|
|
21
|
+
|
|
22
|
+
/* Optimization tunable — a 0/1 flag. ISLET_SIMD_MORTON gates the batch
|
|
23
|
+
* encoders (morton_set_bulk / morton_set_bulk4); it defaults to 1.
|
|
24
|
+
* Override with -DISLET_SIMD_MORTON=0/1 (note: -U does NOT work — this
|
|
25
|
+
* block re-defines an undefined macro to its default). The former
|
|
26
|
+
* per-path tunables (INLINE/HOIST/CLZ/UNROLL) were promoted to
|
|
27
|
+
* unconditional after measurement showed the generic fallbacks never
|
|
28
|
+
* win; see docs/PERF.md. */
|
|
29
|
+
#ifndef ISLET_SIMD_MORTON
|
|
30
|
+
#define ISLET_SIMD_MORTON 1
|
|
31
|
+
#endif
|
|
32
|
+
|
|
33
|
+
#include "morton.h"
|
|
34
|
+
|
|
35
|
+
/** @defgroup islet_core Islet core API
|
|
36
|
+
* @brief Spatial map operations using Morton code indexing.
|
|
37
|
+
*
|
|
38
|
+
* Islet provides a spatial database that maps multi-dimensional coordinates
|
|
39
|
+
* to arbitrary uint32_t values. Internally, coordinates are converted to
|
|
40
|
+
* Morton codes (Z-order) for efficient spatial queries and storage.
|
|
41
|
+
*
|
|
42
|
+
* Value Semantics (multi-value cells):
|
|
43
|
+
* - A grid cell may hold MULTIPLE values (CM_MULTIVALUE map). islet_put_N()
|
|
44
|
+
* appends; islet_get_N() returns the first value; islet_get_multi_N()
|
|
45
|
+
* iterates all values in insertion order; islet_del_N() removes the
|
|
46
|
+
* first value; islet_del_all_N() removes every value; islet_set_N()
|
|
47
|
+
* replaces all values with a single new one (N = 1..4).
|
|
48
|
+
*
|
|
49
|
+
* Coordinate System:
|
|
50
|
+
* - Type: int16_t (signed 16-bit integers)
|
|
51
|
+
* - Range: -32768 to 32767 per dimension
|
|
52
|
+
* - Dimensions 1..4 supported; optimized for 3D (dim=3) with 4D
|
|
53
|
+
* (dim=4) support. 1D/2D/3D codes are bit-identical to v0.5.0;
|
|
54
|
+
* 4D codes densely fill all 64 key bits.
|
|
55
|
+
*
|
|
56
|
+
* The 2D x 32-bit config (int32_t lanes, islet_*_2_32 / morton_*_2_32)
|
|
57
|
+
* is a second dense family member: 2 x 32 = 64 key bits, no reserved
|
|
58
|
+
* bits, lane range -2147483648..2147483647.
|
|
59
|
+
*
|
|
60
|
+
* @note Keyspace: all dimensions and configs share the uint64 Morton
|
|
61
|
+
* key space. Use one dimension AND one config per database, and
|
|
62
|
+
* never reopen a database with a different config's functions:
|
|
63
|
+
* the file carries no config tag, so a cross-config reopen
|
|
64
|
+
* silently decodes garbage.
|
|
65
|
+
*
|
|
66
|
+
* @note islet_ops[] covers the int16-lane configs (1..4) only; the
|
|
67
|
+
* 2D x 32-bit config is reached through its suffixed monomorphs
|
|
68
|
+
* (islet_put_2_32(), islet_iter_2_32(), ...) directly.
|
|
69
|
+
*
|
|
70
|
+
* @note Preferred surface: the config objects in pointcfg.h
|
|
71
|
+
* (Point1_2..Point4_2, Point2_4) group everything above per
|
|
72
|
+
* config as static-method structs. This header's flat functions
|
|
73
|
+
* remain the ABI and the tight-loop fast path.
|
|
74
|
+
*
|
|
75
|
+
* @note Thread Safety: Islet inherits libcorm's thread-safety properties.
|
|
76
|
+
* It uses global state and is NOT thread-safe. Use external
|
|
77
|
+
* synchronization if accessing from multiple threads.
|
|
78
|
+
*
|
|
79
|
+
* @note Capacity: The mask parameter sizes the initial hash table
|
|
80
|
+
* (capacity = mask + 1). The map AUTO-GROWS by doubling when it
|
|
81
|
+
* fills (inherited from libcorm; libislet never passes CM_NOGROW),
|
|
82
|
+
* so exceeding the initial capacity is safe. Choose a mask near
|
|
83
|
+
* your expected entry count to avoid early regrows.
|
|
84
|
+
*
|
|
85
|
+
* @note Memory: Malloc failures terminate the process immediately via CBUG().
|
|
86
|
+
* There is no graceful error handling for out-of-memory conditions.
|
|
87
|
+
*
|
|
88
|
+
* @note ID-uniformity contract (see RECALL-KERNEL.md): the per-cell
|
|
89
|
+
* stored value ("thing"/"ref") is intentionally `uint32_t`, not
|
|
90
|
+
* the wider `rec_ref_t` — which is itself `uint32_t` (from
|
|
91
|
+
* rec.h), matching what libsepal/liblemma use natively and
|
|
92
|
+
* libjoint widens to at its fill boundary, so the fill widen is
|
|
93
|
+
* now an identity cast. Islet's storage/SIMD paths are
|
|
94
|
+
* tuned around the 4-byte value; doubling it is a real cost, not
|
|
95
|
+
* a free uniformity win. The uniformity boundary is enforced only
|
|
96
|
+
* at rec_axis_fill_bbox_N(), which already widens every stored
|
|
97
|
+
* uint32_t to rec_ref_t before pushing it into the caller's
|
|
98
|
+
* rec_set_t. Do not assume ids above UINT32_MAX round-trip through
|
|
99
|
+
* islet_put_N()/islet_get_N().
|
|
100
|
+
*
|
|
101
|
+
* @warning File Persistence: File-backed databases are automatically saved
|
|
102
|
+
* at process exit via libcorm. Explicit corm_save() calls are only
|
|
103
|
+
* needed for mid-execution checkpointing.
|
|
104
|
+
*
|
|
105
|
+
* @see islet_morton
|
|
106
|
+
* @see islet_point
|
|
107
|
+
* @{
|
|
108
|
+
*/
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Sentinel value returned by islet_get when no entry exists.
|
|
112
|
+
*/
|
|
113
|
+
#define ISLET_MISS UINT32_MAX
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Maximum bounding-box volume (in cells) accepted by the rec_axis_fill_bbox
|
|
117
|
+
* family (including rec_axis_fill_bbox_2_32).
|
|
118
|
+
* Boxes whose volume exceeds this are rejected with -1: they are almost
|
|
119
|
+
* certainly a caller bug, and the sealed set would be huge. Raw
|
|
120
|
+
* islet_iter_N() carries no such cap — it only allocates for entries found.
|
|
121
|
+
*/
|
|
122
|
+
#define ISLET_FILL_MAX_VOL 1048576u
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Maximum point count accepted by the phase-2A `rec_axis_store` value
|
|
126
|
+
* grammar (`"x,y[,z];x2,y2"`). A value listing more points is rejected
|
|
127
|
+
* with -1 (`errno` = `ERANGE`): almost certainly a caller bug, and the
|
|
128
|
+
* grid + `rev` writes would be large. The point count is the number of
|
|
129
|
+
* `;`-separated points, whatever their dimension.
|
|
130
|
+
*/
|
|
131
|
+
#define ISLET_AXIS_MAX_POINTS 1024u
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @brief Initialize the islet subsystem.
|
|
135
|
+
*
|
|
136
|
+
* Registers custom types with libcorm (uint64_t for Morton codes, uint32_t
|
|
137
|
+
* for values) and sets up the Morton code comparator for sorted iteration.
|
|
138
|
+
* Also initializes the internal IDM (ID Manager) for iterator handles.
|
|
139
|
+
*
|
|
140
|
+
* @warning Must be called before any other islet functions. Calling other
|
|
141
|
+
* functions without initialization results in undefined behavior.
|
|
142
|
+
*
|
|
143
|
+
* @note This function can be called multiple times safely (idempotent if
|
|
144
|
+
* corm types are already registered).
|
|
145
|
+
*
|
|
146
|
+
* Example:
|
|
147
|
+
* @code
|
|
148
|
+
* int main() {
|
|
149
|
+
* islet_init(); // Always call first
|
|
150
|
+
* uint32_t db = islet_open(NULL, NULL, 0xFF);
|
|
151
|
+
* // ... use database
|
|
152
|
+
* return 0;
|
|
153
|
+
* }
|
|
154
|
+
* @endcode
|
|
155
|
+
*
|
|
156
|
+
* @see islet_open
|
|
157
|
+
*/
|
|
158
|
+
void islet_init(void);
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* @brief Open or create a spatial database.
|
|
162
|
+
*
|
|
163
|
+
* Creates a spatial map backed by libcorm with CM_SORTED for efficient
|
|
164
|
+
* range queries. Internally uses Morton codes (uint64_t) as keys and
|
|
165
|
+
* uint32_t for values. If a filename is provided, data is automatically
|
|
166
|
+
* loaded from disk if the file exists.
|
|
167
|
+
*
|
|
168
|
+
* @param[in] filename File path for persistence, or NULL for in-memory only.
|
|
169
|
+
* Example: "world.db"
|
|
170
|
+
* @param[in] database Logical database name within the file, or NULL to
|
|
171
|
+
* skip file association. Multiple databases can share
|
|
172
|
+
* one file. Example: "main", "players", "chunks"
|
|
173
|
+
* @param[in] mask Hash table mask (initial capacity = mask + 1).
|
|
174
|
+
* Must be 2^n - 1 for optimal performance. Examples:
|
|
175
|
+
* 0xFF (256 entries), 0xFFF (4096 entries),
|
|
176
|
+
* 0xFFFF (65536 entries). The map auto-grows past this;
|
|
177
|
+
* pick a mask near your expected entry count.
|
|
178
|
+
*
|
|
179
|
+
* @return Database handle for use with other islet functions.
|
|
180
|
+
*
|
|
181
|
+
* @note File Persistence: File-backed databases automatically load existing
|
|
182
|
+
* data when opened. Data is automatically saved at process exit via
|
|
183
|
+
* libcorm's destructor. Call corm_save() explicitly only if you need
|
|
184
|
+
* mid-execution checkpointing.
|
|
185
|
+
*
|
|
186
|
+
* @note Capacity: The mask sizes the initial table; the map auto-grows
|
|
187
|
+
* by doubling when it fills. Nothing terminates on growth.
|
|
188
|
+
*
|
|
189
|
+
* @note The database is created with CM_SORTED | CM_MULTIVALUE: ordered
|
|
190
|
+
* iteration by Morton code for efficient spatial range queries,
|
|
191
|
+
* with multi-value cells (see the Value Semantics note above).
|
|
192
|
+
*
|
|
193
|
+
* @warning The filename and database parameters are not copied. If providing
|
|
194
|
+
* string literals, they must remain valid for the database lifetime.
|
|
195
|
+
*
|
|
196
|
+
* Example (in-memory):
|
|
197
|
+
* @code
|
|
198
|
+
* islet_init();
|
|
199
|
+
* uint32_t db = islet_open(NULL, NULL, 0xFF); // 256-entry initial table
|
|
200
|
+
* @endcode
|
|
201
|
+
*
|
|
202
|
+
* Example (persistent):
|
|
203
|
+
* @code
|
|
204
|
+
* islet_init();
|
|
205
|
+
* uint32_t db = islet_open("world.db", "main", 0xFFF); // 4096-entry initial table
|
|
206
|
+
* @endcode
|
|
207
|
+
*
|
|
208
|
+
* @see islet_init
|
|
209
|
+
* @see corm_open
|
|
210
|
+
* @see corm_save
|
|
211
|
+
* @see corm_close
|
|
212
|
+
*/
|
|
213
|
+
uint32_t islet_open(char *filename, char *database, uint32_t mask);
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* @brief Create an iterator for all points within a rectangular bounding box.
|
|
217
|
+
*
|
|
218
|
+
* Queries the spatial database for all entries within the axis-aligned
|
|
219
|
+
* bounding box defined by start point 's' and lengths 'l'. The iterator
|
|
220
|
+
* pre-allocates and collects all matching results using Morton code range
|
|
221
|
+
* queries internally.
|
|
222
|
+
*
|
|
223
|
+
* @param[in] pdb_hd Database handle from islet_open().
|
|
224
|
+
* @param[in] s Start point (minimum corner of bounding box).
|
|
225
|
+
* Array of int16_t with at least the dimension count
|
|
226
|
+
* of the function used.
|
|
227
|
+
* @param[in] l Lengths of bounding box per dimension (unsigned).
|
|
228
|
+
* Array of uint16_t with at least the dimension count
|
|
229
|
+
* of the function used.
|
|
230
|
+
* The box covers s[i]..s[i]+l[i] inclusive per dimension.
|
|
231
|
+
*
|
|
232
|
+
* @note Per-dimension variants islet_iter_1..4; the function name carries
|
|
233
|
+
* the dimension count (1..4).
|
|
234
|
+
*
|
|
235
|
+
* @return Iterator handle for use with islet_next(). The handle is
|
|
236
|
+
* automatically freed when islet_next() returns 0.
|
|
237
|
+
*
|
|
238
|
+
* @note Results are collected in Morton code order (Z-order space-filling
|
|
239
|
+
* curve), NOT spatial order. Nearby points may not be adjacent in
|
|
240
|
+
* iteration sequence.
|
|
241
|
+
*
|
|
242
|
+
* @note Every stored (point, value) pair is returned exactly once, including
|
|
243
|
+
* multiple values stored at the same cell. Results are NOT deduplicated.
|
|
244
|
+
*
|
|
245
|
+
* @note Memory: Allocates a flat list that grows with the number of matching
|
|
246
|
+
* entries (not the bounding box volume), so sparse queries over large
|
|
247
|
+
* boxes stay cheap.
|
|
248
|
+
*
|
|
249
|
+
* @warning The volume calculation can overflow for very large boxes.
|
|
250
|
+
* Reasonable box sizes are recommended (< 1 million points).
|
|
251
|
+
*
|
|
252
|
+
* Example (2D region):
|
|
253
|
+
* @code
|
|
254
|
+
* int16_t start[2] = {0, 0};
|
|
255
|
+
* uint16_t lengths[2] = {100, 100}; // 100x100 region
|
|
256
|
+
* uint32_t iter = islet_iter_2(db, start, lengths);
|
|
257
|
+
* @endcode
|
|
258
|
+
*
|
|
259
|
+
* Example (3D region):
|
|
260
|
+
* @code
|
|
261
|
+
* int16_t start[3] = {-10, -10, -10};
|
|
262
|
+
* uint16_t lengths[3] = {20, 20, 20}; // 20x20x20 cube (8000 points)
|
|
263
|
+
* uint32_t iter = islet_iter_3(db, start, lengths);
|
|
264
|
+
* @endcode
|
|
265
|
+
*
|
|
266
|
+
* @see islet_next
|
|
267
|
+
* @see morton_set_1 morton_set_2 morton_set_3 morton_set_4
|
|
268
|
+
*/
|
|
269
|
+
uint32_t islet_iter_1(uint32_t pdb_hd, int16_t *s, uint16_t *l);
|
|
270
|
+
uint32_t islet_iter_2(uint32_t pdb_hd, int16_t *s, uint16_t *l);
|
|
271
|
+
uint32_t islet_iter_3(uint32_t pdb_hd, int16_t *s, uint16_t *l);
|
|
272
|
+
uint32_t islet_iter_4(uint32_t pdb_hd, int16_t *s, uint16_t *l);
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* @brief 2D x 32-bit box iterator. Same contract as islet_iter_N(),
|
|
276
|
+
* on int32_t lanes (start AND lengths). Use with islet_next32().
|
|
277
|
+
*/
|
|
278
|
+
uint32_t islet_iter_2_32(uint32_t pdb_hd, int32_t *s, int32_t *l);
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* @brief Advance iterator and retrieve the next point/value pair.
|
|
282
|
+
*
|
|
283
|
+
* Retrieves the next entry from the iterator created by islet_iter_N().
|
|
284
|
+
* Skips empty cells in the bounding box. When all entries have been
|
|
285
|
+
* returned (or the box was empty), returns 0 and automatically frees
|
|
286
|
+
* the iterator's internal memory.
|
|
287
|
+
*
|
|
288
|
+
* @param[out] p Output point array. Must have space for the dimension
|
|
289
|
+
* count of the matching islet_iter_N() call. Filled with
|
|
290
|
+
* the coordinates of the next point.
|
|
291
|
+
* @param[out] ref Output pointer for the stored value (uint32_t).
|
|
292
|
+
* Filled with the value stored at this point.
|
|
293
|
+
* @param[in] cur Iterator handle from islet_iter_N().
|
|
294
|
+
*
|
|
295
|
+
* @return 1 if a point/value pair was retrieved (output written to p and ref).
|
|
296
|
+
* 0 when iteration is complete (no more entries). The iterator is
|
|
297
|
+
* automatically freed on return 0.
|
|
298
|
+
*
|
|
299
|
+
* @note The iterator is stateful and maintains position. Each call advances
|
|
300
|
+
* to the next entry.
|
|
301
|
+
*
|
|
302
|
+
* @note Empty cells in the bounding box are automatically skipped.
|
|
303
|
+
* Only coordinates with stored values are returned.
|
|
304
|
+
*
|
|
305
|
+
* @warning After this function returns 0, the iterator handle becomes invalid.
|
|
306
|
+
* Do not call islet_next() again with the same handle.
|
|
307
|
+
*
|
|
308
|
+
* @warning The iterator's internal memory is freed when this returns 0.
|
|
309
|
+
* There is no separate "close" or "free" function.
|
|
310
|
+
*
|
|
311
|
+
* Typical usage pattern:
|
|
312
|
+
* @code
|
|
313
|
+
* int16_t start[3] = {0, 0, 0};
|
|
314
|
+
* uint16_t lengths[3] = {10, 10, 10};
|
|
315
|
+
* uint32_t iter = islet_iter(db, start, lengths, 3);
|
|
316
|
+
*
|
|
317
|
+
* int16_t point[3];
|
|
318
|
+
* uint32_t value;
|
|
319
|
+
* while (islet_next(point, &value, iter)) {
|
|
320
|
+
* printf("Point (%d,%d,%d) = %u\n",
|
|
321
|
+
* point[0], point[1], point[2], value);
|
|
322
|
+
* }
|
|
323
|
+
* // Iterator is automatically freed after loop
|
|
324
|
+
* @endcode
|
|
325
|
+
*
|
|
326
|
+
* @see islet_iter
|
|
327
|
+
*/
|
|
328
|
+
int islet_next(int16_t *p, uint32_t *ref, uint32_t cur);
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* @brief Advance a 2D x 32-bit iterator (islet_iter_2_32 handle).
|
|
332
|
+
*
|
|
333
|
+
* Same contract as islet_next(), on int32_t lanes. Iterators from
|
|
334
|
+
* islet_iter_1..4 use islet_next(); 2D x 32-bit iterators use this.
|
|
335
|
+
*
|
|
336
|
+
* @param[out] p Output point array (int32_t[2]).
|
|
337
|
+
* @param[out] ref Output pointer for the stored value (uint32_t).
|
|
338
|
+
* @param[in] cur Iterator handle from islet_iter_2_32().
|
|
339
|
+
*
|
|
340
|
+
* @return 1 on entry, 0 when complete (handle freed).
|
|
341
|
+
*/
|
|
342
|
+
int islet_next32(int32_t *p, uint32_t *ref, uint32_t cur);
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* @brief Delete the first value stored at a spatial coordinate.
|
|
346
|
+
*
|
|
347
|
+
* Per-dimension variants (islet_del_1..4); the function name carries the
|
|
348
|
+
* dimension count. Removes the first value stored at the given point
|
|
349
|
+
* from the database. Internally converts the coordinate to a Morton
|
|
350
|
+
* code and calls corm_del(). If no entry exists at the coordinate, this
|
|
351
|
+
* is a no-op (safe to call). When several values share the cell, only
|
|
352
|
+
* the earliest-inserted one is removed; use islet_del_all_3() to clear
|
|
353
|
+
* the cell.
|
|
354
|
+
*
|
|
355
|
+
* @param[in] pdb_hd Database handle from islet_open().
|
|
356
|
+
* @param[in] p Point coordinate. Array of int16_t with at least the
|
|
357
|
+
* dimension count of the function used.
|
|
358
|
+
*
|
|
359
|
+
* @note This operation invalidates any pointers obtained from islet_get_3()
|
|
360
|
+
* or islet_next() that refer to this coordinate.
|
|
361
|
+
*
|
|
362
|
+
* @note Safe to call on non-existent coordinates (no error, no effect).
|
|
363
|
+
*
|
|
364
|
+
* Example:
|
|
365
|
+
* @code
|
|
366
|
+
* int16_t pos[3] = {10, 20, 30};
|
|
367
|
+
* islet_del_3(db, pos); // Remove entry at (10,20,30)
|
|
368
|
+
* @endcode
|
|
369
|
+
*
|
|
370
|
+
* @see islet_get_3
|
|
371
|
+
* @see islet_put_3
|
|
372
|
+
* @see corm_del
|
|
373
|
+
*/
|
|
374
|
+
static inline void
|
|
375
|
+
islet_del_1(uint32_t pdb_hd, int16_t *p)
|
|
376
|
+
{
|
|
377
|
+
uint64_t at = morton_set_1(p);
|
|
378
|
+
corm_del(pdb_hd, &at);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* @brief 2D delete. See islet_del_1() for the family docs.
|
|
383
|
+
*/
|
|
384
|
+
static inline void
|
|
385
|
+
islet_del_2(uint32_t pdb_hd, int16_t *p)
|
|
386
|
+
{
|
|
387
|
+
uint64_t at = morton_set_2(p);
|
|
388
|
+
corm_del(pdb_hd, &at);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* @brief 3D delete. See islet_del_1() for the family docs.
|
|
393
|
+
*/
|
|
394
|
+
static inline void
|
|
395
|
+
islet_del_3(uint32_t pdb_hd, int16_t *p)
|
|
396
|
+
{
|
|
397
|
+
uint64_t at = morton_set_3(p);
|
|
398
|
+
corm_del(pdb_hd, &at);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* @brief 4D delete. See islet_del_1() for the family docs.
|
|
403
|
+
*/
|
|
404
|
+
static inline void
|
|
405
|
+
islet_del_4(uint32_t pdb_hd, int16_t *p)
|
|
406
|
+
{
|
|
407
|
+
uint64_t at = morton_set_4(p);
|
|
408
|
+
corm_del(pdb_hd, &at);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* @brief 2D x 32-bit delete. See islet_del_1() for the family docs.
|
|
413
|
+
*/
|
|
414
|
+
static inline void
|
|
415
|
+
islet_del_2_32(uint32_t pdb_hd, int32_t *p)
|
|
416
|
+
{
|
|
417
|
+
uint64_t at = morton_set_2_32(p);
|
|
418
|
+
corm_del(pdb_hd, &at);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* @brief Delete every value stored at a spatial coordinate.
|
|
423
|
+
*
|
|
424
|
+
* Per-dimension variants (islet_del_all_1..4). Removes all values stored
|
|
425
|
+
* at the given point from the database. Internally converts the
|
|
426
|
+
* coordinate to a Morton code and calls corm_del_all(). If no entry
|
|
427
|
+
* exists at the coordinate, this is a no-op (safe to call, returns 0).
|
|
428
|
+
*
|
|
429
|
+
* @param[in] pdb_hd Database handle from islet_open().
|
|
430
|
+
* @param[in] p Point coordinate. Array of int16_t with at least the
|
|
431
|
+
* dimension count of the function used.
|
|
432
|
+
*
|
|
433
|
+
* @return Number of values removed (0 if the cell was empty).
|
|
434
|
+
*
|
|
435
|
+
* Example:
|
|
436
|
+
* @code
|
|
437
|
+
* int16_t pos[3] = {10, 20, 30};
|
|
438
|
+
* uint32_t n = islet_del_all_3(db, pos); // Clear the cell
|
|
439
|
+
* @endcode
|
|
440
|
+
*
|
|
441
|
+
* @see islet_del_3
|
|
442
|
+
* @see islet_set_3
|
|
443
|
+
* @see corm_del_all
|
|
444
|
+
*/
|
|
445
|
+
static inline uint32_t
|
|
446
|
+
islet_del_all_1(uint32_t pdb_hd, int16_t *p)
|
|
447
|
+
{
|
|
448
|
+
uint64_t at = morton_set_1(p);
|
|
449
|
+
uint32_t n = corm_count(pdb_hd, &at);
|
|
450
|
+
|
|
451
|
+
if (n)
|
|
452
|
+
corm_del_all(pdb_hd, &at);
|
|
453
|
+
|
|
454
|
+
return n;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* @brief 2D delete-all. See islet_del_all_1() for the family docs.
|
|
459
|
+
*/
|
|
460
|
+
static inline uint32_t
|
|
461
|
+
islet_del_all_2(uint32_t pdb_hd, int16_t *p)
|
|
462
|
+
{
|
|
463
|
+
uint64_t at = morton_set_2(p);
|
|
464
|
+
uint32_t n = corm_count(pdb_hd, &at);
|
|
465
|
+
|
|
466
|
+
if (n)
|
|
467
|
+
corm_del_all(pdb_hd, &at);
|
|
468
|
+
|
|
469
|
+
return n;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* @brief 3D delete-all. See islet_del_all_1() for the family docs.
|
|
474
|
+
*/
|
|
475
|
+
static inline uint32_t
|
|
476
|
+
islet_del_all_3(uint32_t pdb_hd, int16_t *p)
|
|
477
|
+
{
|
|
478
|
+
uint64_t at = morton_set_3(p);
|
|
479
|
+
uint32_t n = corm_count(pdb_hd, &at);
|
|
480
|
+
|
|
481
|
+
if (n)
|
|
482
|
+
corm_del_all(pdb_hd, &at);
|
|
483
|
+
|
|
484
|
+
return n;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* @brief 4D delete-all. See islet_del_all_1() for the family docs.
|
|
489
|
+
*/
|
|
490
|
+
static inline uint32_t
|
|
491
|
+
islet_del_all_4(uint32_t pdb_hd, int16_t *p)
|
|
492
|
+
{
|
|
493
|
+
uint64_t at = morton_set_4(p);
|
|
494
|
+
uint32_t n = corm_count(pdb_hd, &at);
|
|
495
|
+
|
|
496
|
+
if (n)
|
|
497
|
+
corm_del_all(pdb_hd, &at);
|
|
498
|
+
|
|
499
|
+
return n;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* @brief 2D x 32-bit delete-all. See islet_del_all_1() for the
|
|
504
|
+
* family docs.
|
|
505
|
+
*/
|
|
506
|
+
static inline uint32_t
|
|
507
|
+
islet_del_all_2_32(uint32_t pdb_hd, int32_t *p)
|
|
508
|
+
{
|
|
509
|
+
uint64_t at = morton_set_2_32(p);
|
|
510
|
+
uint32_t n = corm_count(pdb_hd, &at);
|
|
511
|
+
|
|
512
|
+
if (n)
|
|
513
|
+
corm_del_all(pdb_hd, &at);
|
|
514
|
+
|
|
515
|
+
return n;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* @brief 2D x 32-bit delete-by-value. See islet_del_value_1() for the
|
|
520
|
+
* family docs.
|
|
521
|
+
*/
|
|
522
|
+
uint32_t islet_del_value_2_32(uint32_t pdb_hd, int32_t *p, uint32_t thing);
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* @brief Retrieve the value stored at a spatial coordinate.
|
|
526
|
+
*
|
|
527
|
+
* Per-dimension variants (islet_get_1..4). Looks up the value at the given
|
|
528
|
+
* point in the database. Internally converts the coordinate to a Morton
|
|
529
|
+
* code and calls corm_get().
|
|
530
|
+
*
|
|
531
|
+
* @param[in] pdb_hd Database handle from islet_open().
|
|
532
|
+
* @param[in] p Point coordinate. Array of int16_t with at least the
|
|
533
|
+
* dimension count of the function used. Coordinates are
|
|
534
|
+
* signed 16-bit integers ranging from -32768 to 32767.
|
|
535
|
+
*
|
|
536
|
+
* @return The first stored uint32_t value at this coordinate, or ISLET_MISS
|
|
537
|
+
* (UINT32_MAX) if no entry exists at this point. When several
|
|
538
|
+
* values share the cell, the earliest-inserted one is returned;
|
|
539
|
+
* use islet_get_multi_3() to retrieve them all.
|
|
540
|
+
*
|
|
541
|
+
* @note ISLET_MISS equals UINT32_MAX (0xFFFFFFFF), the same as CM_MISS.
|
|
542
|
+
* This is the standard sentinel value for missing entries.
|
|
543
|
+
*
|
|
544
|
+
* @note The returned value is a copy, not a pointer. Unlike corm_get()
|
|
545
|
+
* which returns a pointer, islet_get_3() returns the actual uint32_t
|
|
546
|
+
* value.
|
|
547
|
+
*
|
|
548
|
+
* Example:
|
|
549
|
+
* @code
|
|
550
|
+
* int16_t pos[3] = {10, 20, 30};
|
|
551
|
+
* uint32_t value = islet_get_3(db, pos);
|
|
552
|
+
* if (value == ISLET_MISS) {
|
|
553
|
+
* printf("No entry at (10,20,30)\n");
|
|
554
|
+
* } else {
|
|
555
|
+
* printf("Value at (10,20,30) = %u\n", value);
|
|
556
|
+
* }
|
|
557
|
+
* @endcode
|
|
558
|
+
*
|
|
559
|
+
* @see islet_put_3
|
|
560
|
+
* @see islet_del_3
|
|
561
|
+
* @see ISLET_MISS
|
|
562
|
+
* @see corm_get
|
|
563
|
+
*/
|
|
564
|
+
static inline uint32_t
|
|
565
|
+
islet_get_1(uint32_t pdb_hd, int16_t *p)
|
|
566
|
+
{
|
|
567
|
+
uint64_t at = morton_set_1(p);
|
|
568
|
+
const void *ref = corm_get(pdb_hd, &at);
|
|
569
|
+
|
|
570
|
+
if (ref)
|
|
571
|
+
return * (uint32_t *) ref;
|
|
572
|
+
|
|
573
|
+
return ISLET_MISS;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* @brief 2D retrieve. See islet_get_1() for the family docs.
|
|
578
|
+
*/
|
|
579
|
+
static inline uint32_t
|
|
580
|
+
islet_get_2(uint32_t pdb_hd, int16_t *p)
|
|
581
|
+
{
|
|
582
|
+
uint64_t at = morton_set_2(p);
|
|
583
|
+
const void *ref = corm_get(pdb_hd, &at);
|
|
584
|
+
|
|
585
|
+
if (ref)
|
|
586
|
+
return * (uint32_t *) ref;
|
|
587
|
+
|
|
588
|
+
return ISLET_MISS;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* @brief 3D retrieve. See islet_get_1() for the family docs.
|
|
593
|
+
*/
|
|
594
|
+
static inline uint32_t
|
|
595
|
+
islet_get_3(uint32_t pdb_hd, int16_t *p)
|
|
596
|
+
{
|
|
597
|
+
uint64_t at = morton_set_3(p);
|
|
598
|
+
const void *ref = corm_get(pdb_hd, &at);
|
|
599
|
+
|
|
600
|
+
if (ref)
|
|
601
|
+
return * (uint32_t *) ref;
|
|
602
|
+
|
|
603
|
+
return ISLET_MISS;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* @brief 4D retrieve. See islet_get_1() for the family docs.
|
|
608
|
+
*/
|
|
609
|
+
static inline uint32_t
|
|
610
|
+
islet_get_4(uint32_t pdb_hd, int16_t *p)
|
|
611
|
+
{
|
|
612
|
+
uint64_t at = morton_set_4(p);
|
|
613
|
+
const void *ref = corm_get(pdb_hd, &at);
|
|
614
|
+
|
|
615
|
+
if (ref)
|
|
616
|
+
return * (uint32_t *) ref;
|
|
617
|
+
|
|
618
|
+
return ISLET_MISS;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* @brief 2D x 32-bit retrieve. See islet_get_1() for the family docs.
|
|
623
|
+
*/
|
|
624
|
+
static inline uint32_t
|
|
625
|
+
islet_get_2_32(uint32_t pdb_hd, int32_t *p)
|
|
626
|
+
{
|
|
627
|
+
uint64_t at = morton_set_2_32(p);
|
|
628
|
+
const void *ref = corm_get(pdb_hd, &at);
|
|
629
|
+
|
|
630
|
+
if (ref)
|
|
631
|
+
return * (uint32_t *) ref;
|
|
632
|
+
|
|
633
|
+
return ISLET_MISS;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* @brief Count the values stored at a spatial coordinate.
|
|
638
|
+
*
|
|
639
|
+
* @param[in] pdb_hd Database handle from islet_open().
|
|
640
|
+
* @param[in] p Point coordinate. Array of int16_t with at least the
|
|
641
|
+
* dimension count of the function used.
|
|
642
|
+
*
|
|
643
|
+
* @return Number of values stored at this coordinate (0 if empty).
|
|
644
|
+
*
|
|
645
|
+
* @see islet_get_1 islet_get_2 islet_get_3 islet_get_4
|
|
646
|
+
* @see islet_get_multi_1 islet_get_multi_2 islet_get_multi_3 islet_get_multi_4
|
|
647
|
+
* @see corm_count
|
|
648
|
+
*/
|
|
649
|
+
static inline uint32_t
|
|
650
|
+
islet_cell_count_1(uint32_t pdb_hd, int16_t *p)
|
|
651
|
+
{
|
|
652
|
+
uint64_t at = morton_set_1(p);
|
|
653
|
+
|
|
654
|
+
return corm_count(pdb_hd, &at);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* @brief 2D cell count. See islet_cell_count_1() for the family docs.
|
|
659
|
+
*/
|
|
660
|
+
static inline uint32_t
|
|
661
|
+
islet_cell_count_2(uint32_t pdb_hd, int16_t *p)
|
|
662
|
+
{
|
|
663
|
+
uint64_t at = morton_set_2(p);
|
|
664
|
+
|
|
665
|
+
return corm_count(pdb_hd, &at);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* @brief 3D cell count. See islet_cell_count_1() for the family docs.
|
|
670
|
+
*/
|
|
671
|
+
static inline uint32_t
|
|
672
|
+
islet_cell_count_3(uint32_t pdb_hd, int16_t *p)
|
|
673
|
+
{
|
|
674
|
+
uint64_t at = morton_set_3(p);
|
|
675
|
+
|
|
676
|
+
return corm_count(pdb_hd, &at);
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* @brief 4D cell count. See islet_cell_count_1() for the family docs.
|
|
681
|
+
*/
|
|
682
|
+
static inline uint32_t
|
|
683
|
+
islet_cell_count_4(uint32_t pdb_hd, int16_t *p)
|
|
684
|
+
{
|
|
685
|
+
uint64_t at = morton_set_4(p);
|
|
686
|
+
|
|
687
|
+
return corm_count(pdb_hd, &at);
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* @brief 2D x 32-bit cell count. See islet_cell_count_1() for the
|
|
692
|
+
* family docs.
|
|
693
|
+
*/
|
|
694
|
+
static inline uint32_t
|
|
695
|
+
islet_cell_count_2_32(uint32_t pdb_hd, int32_t *p)
|
|
696
|
+
{
|
|
697
|
+
uint64_t at = morton_set_2_32(p);
|
|
698
|
+
|
|
699
|
+
return corm_count(pdb_hd, &at);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* @brief Diagnostic: index entries examined by the last box walk.
|
|
704
|
+
*
|
|
705
|
+
* Returns the number of index entries examined by the most recent
|
|
706
|
+
* islet_iter_N()/rec_axis_fill_bbox_N() box walk in this process. Tests and
|
|
707
|
+
* benchmarks use it to prove the Z-interval skip engages (entries
|
|
708
|
+
* examined well below the morton-interval width on sparse boxes).
|
|
709
|
+
*
|
|
710
|
+
* @return Entry-examination count of the last box walk (0 if none ran yet).
|
|
711
|
+
*/
|
|
712
|
+
uint32_t islet_last_scan_count(void);
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* @brief Create an iterator for all values stored at one coordinate.
|
|
716
|
+
*
|
|
717
|
+
* Opens a chain-aware cursor over every value stored at the given point,
|
|
718
|
+
* in insertion order. Use islet_cell_next() to retrieve the values.
|
|
719
|
+
*
|
|
720
|
+
* @param[in] pdb_hd Database handle from islet_open().
|
|
721
|
+
* @param[in] p Point coordinate. Array of int16_t with at least the
|
|
722
|
+
* dimension count of the function used.
|
|
723
|
+
*
|
|
724
|
+
* @note Per-dimension variants islet_get_multi_1..4.
|
|
725
|
+
*
|
|
726
|
+
* @return Iterator handle for use with islet_cell_next(), or CM_MISS when
|
|
727
|
+
* the cell holds no values.
|
|
728
|
+
*
|
|
729
|
+
* Example:
|
|
730
|
+
* @code
|
|
731
|
+
* int16_t pos[3] = {10, 20, 30};
|
|
732
|
+
* uint32_t cur = islet_get_multi_3(db, pos);
|
|
733
|
+
* if (cur != CM_MISS) {
|
|
734
|
+
* uint32_t value;
|
|
735
|
+
* while (islet_cell_next(&value, cur))
|
|
736
|
+
* printf("value %u\n", value);
|
|
737
|
+
* }
|
|
738
|
+
* @endcode
|
|
739
|
+
*
|
|
740
|
+
* @see islet_cell_next
|
|
741
|
+
* @see islet_cell_count_1 islet_cell_count_2 islet_cell_count_3 islet_cell_count_4
|
|
742
|
+
*/
|
|
743
|
+
uint32_t islet_get_multi_1(uint32_t pdb_hd, int16_t *p);
|
|
744
|
+
uint32_t islet_get_multi_2(uint32_t pdb_hd, int16_t *p);
|
|
745
|
+
uint32_t islet_get_multi_3(uint32_t pdb_hd, int16_t *p);
|
|
746
|
+
uint32_t islet_get_multi_4(uint32_t pdb_hd, int16_t *p);
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* @brief 2D x 32-bit cell iterator. Same contract as islet_get_multi_N()
|
|
750
|
+
* (use the shared islet_cell_next() to read values).
|
|
751
|
+
*/
|
|
752
|
+
uint32_t islet_get_multi_2_32(uint32_t pdb_hd, int32_t *p);
|
|
753
|
+
|
|
754
|
+
/**
|
|
755
|
+
* @brief Advance a cell iterator and retrieve the next value.
|
|
756
|
+
*
|
|
757
|
+
* Retrieves the next value from the iterator created by
|
|
758
|
+
* islet_get_multi_N().
|
|
759
|
+
* When all values have been returned, returns 0 and automatically frees
|
|
760
|
+
* the iterator.
|
|
761
|
+
*
|
|
762
|
+
* @param[out] ref Output pointer for the stored value (uint32_t).
|
|
763
|
+
* @param[in] cur Iterator handle from islet_get_multi_N().
|
|
764
|
+
*
|
|
765
|
+
* @return 1 if a value was retrieved. 0 when iteration is complete; the
|
|
766
|
+
* iterator is automatically freed on return 0.
|
|
767
|
+
*
|
|
768
|
+
* @warning After this function returns 0, the iterator handle becomes invalid.
|
|
769
|
+
*
|
|
770
|
+
* @see islet_get_multi_1 islet_get_multi_2 islet_get_multi_3 islet_get_multi_4
|
|
771
|
+
*/
|
|
772
|
+
int islet_cell_next(uint32_t *ref, uint32_t cur);
|
|
773
|
+
|
|
774
|
+
/**
|
|
775
|
+
* @brief Delete one value from a spatial coordinate (phase-2A adapter
|
|
776
|
+
* primitive).
|
|
777
|
+
*
|
|
778
|
+
* Per-dimension variants (islet_del_value_1..4). Removes every entry
|
|
779
|
+
* holding `thing` from the cell at the given point, leaving the cell's
|
|
780
|
+
* other values untouched (in their relative order). Where islet_del_N()
|
|
781
|
+
* removes the first value and islet_del_all_N() clears the cell, this one
|
|
782
|
+
* removes by value — exactly what `rec_axis_unstore` needs when several
|
|
783
|
+
* refs share one cell.
|
|
784
|
+
*
|
|
785
|
+
* @param[in] pdb_hd Database handle from islet_open().
|
|
786
|
+
* @param[in] p Point coordinate. Array of int16_t with at least the
|
|
787
|
+
* dimension count of the function used.
|
|
788
|
+
* @param[in] thing Value to remove (uint32_t).
|
|
789
|
+
*
|
|
790
|
+
* @return Number of entries removed (0 when the cell is empty or holds
|
|
791
|
+
* no such value).
|
|
792
|
+
*
|
|
793
|
+
* @note A pure cell primitive: it knows nothing of the phase-2A `rev`
|
|
794
|
+
* manifest. The `rec_axis_unstore` adapter (the rev-aware path) keeps
|
|
795
|
+
* cell and manifest in sync; callers manipulating the grid directly
|
|
796
|
+
* own that sync themselves.
|
|
797
|
+
*
|
|
798
|
+
* Example:
|
|
799
|
+
* @code
|
|
800
|
+
* int16_t pos[3] = {10, 20, 30};
|
|
801
|
+
* islet_put_3(db, pos, 7);
|
|
802
|
+
* islet_put_3(db, pos, 9);
|
|
803
|
+
* islet_del_value_3(db, pos, 9); // Cell now holds exactly {7}
|
|
804
|
+
* @endcode
|
|
805
|
+
*
|
|
806
|
+
* @see islet_del_1 islet_del_all_1 islet_cell_count_1
|
|
807
|
+
*/
|
|
808
|
+
uint32_t islet_del_value_1(uint32_t pdb_hd, int16_t *p, uint32_t thing);
|
|
809
|
+
uint32_t islet_del_value_2(uint32_t pdb_hd, int16_t *p, uint32_t thing);
|
|
810
|
+
uint32_t islet_del_value_3(uint32_t pdb_hd, int16_t *p, uint32_t thing);
|
|
811
|
+
uint32_t islet_del_value_4(uint32_t pdb_hd, int16_t *p, uint32_t thing);
|
|
812
|
+
|
|
813
|
+
/**
|
|
814
|
+
* @brief Store a value at a spatial coordinate (append).
|
|
815
|
+
*
|
|
816
|
+
* Per-dimension variants (islet_put_1..4). Appends the value at the given
|
|
817
|
+
* point in the database. Internally converts the coordinate to a Morton
|
|
818
|
+
* code and calls corm_put(). If entries already exist at this coordinate,
|
|
819
|
+
* the new value is ADDED alongside them (multi-value cell) - nothing is
|
|
820
|
+
* replaced. Use islet_set_N() for replace semantics, islet_get_multi_N()
|
|
821
|
+
* to read all values back.
|
|
822
|
+
*
|
|
823
|
+
* @param[in] pdb_hd Database handle from islet_open().
|
|
824
|
+
* @param[in] p Point coordinate. Array of int16_t with at least the
|
|
825
|
+
* dimension count of the function used. Coordinates are
|
|
826
|
+
* signed 16-bit integers ranging from -32768 to 32767.
|
|
827
|
+
* @param[in] thing Value to store (uint32_t). Can be any 32-bit value
|
|
828
|
+
* including 0. Avoid using CM_MISS (0xFFFFFFFF) as it
|
|
829
|
+
* may cause confusion, though it's technically valid.
|
|
830
|
+
*
|
|
831
|
+
* @note If the database is file-backed (filename provided to islet_open()),
|
|
832
|
+
* changes are automatically saved at process exit. Call corm_save()
|
|
833
|
+
* explicitly for mid-execution persistence.
|
|
834
|
+
*
|
|
835
|
+
* Example (store single value):
|
|
836
|
+
* @code
|
|
837
|
+
* int16_t pos[3] = {10, 20, 30};
|
|
838
|
+
* islet_put_3(db, pos, 42); // Store value 42 at (10,20,30)
|
|
839
|
+
* @endcode
|
|
840
|
+
*
|
|
841
|
+
* Example (update existing value):
|
|
842
|
+
* @code
|
|
843
|
+
* int16_t pos[3] = {10, 20, 30};
|
|
844
|
+
* uint32_t old = islet_get_3(db, pos);
|
|
845
|
+
* if (old != ISLET_MISS) {
|
|
846
|
+
* islet_set_3(db, pos, old + 1); // Increment (replace)
|
|
847
|
+
* }
|
|
848
|
+
* @endcode
|
|
849
|
+
*
|
|
850
|
+
* Example (populate a 2D grid):
|
|
851
|
+
* @code
|
|
852
|
+
* for (int16_t x = 0; x < 10; x++) {
|
|
853
|
+
* for (int16_t y = 0; y < 10; y++) {
|
|
854
|
+
* int16_t pos[2] = {x, y};
|
|
855
|
+
* islet_put_2(db, pos, x * 10 + y);
|
|
856
|
+
* }
|
|
857
|
+
* }
|
|
858
|
+
* @endcode
|
|
859
|
+
*
|
|
860
|
+
* @see islet_get_3
|
|
861
|
+
* @see islet_del_3
|
|
862
|
+
* @see corm_put
|
|
863
|
+
* @see corm_save
|
|
864
|
+
*/
|
|
865
|
+
static inline void
|
|
866
|
+
islet_put_1(uint32_t pdb_hd, int16_t *p, uint32_t thing)
|
|
867
|
+
{
|
|
868
|
+
uint64_t code = morton_set_1(p);
|
|
869
|
+
corm_put(pdb_hd, &code, &thing);
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
/**
|
|
873
|
+
* @brief 2D append. See islet_put_1() for the family docs.
|
|
874
|
+
*/
|
|
875
|
+
static inline void
|
|
876
|
+
islet_put_2(uint32_t pdb_hd, int16_t *p, uint32_t thing)
|
|
877
|
+
{
|
|
878
|
+
uint64_t code = morton_set_2(p);
|
|
879
|
+
corm_put(pdb_hd, &code, &thing);
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
/**
|
|
883
|
+
* @brief 3D append. See islet_put_1() for the family docs.
|
|
884
|
+
*/
|
|
885
|
+
static inline void
|
|
886
|
+
islet_put_3(uint32_t pdb_hd, int16_t *p, uint32_t thing)
|
|
887
|
+
{
|
|
888
|
+
uint64_t code = morton_set_3(p);
|
|
889
|
+
corm_put(pdb_hd, &code, &thing);
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
/**
|
|
893
|
+
* @brief 4D append. See islet_put_1() for the family docs.
|
|
894
|
+
*/
|
|
895
|
+
static inline void
|
|
896
|
+
islet_put_4(uint32_t pdb_hd, int16_t *p, uint32_t thing)
|
|
897
|
+
{
|
|
898
|
+
uint64_t code = morton_set_4(p);
|
|
899
|
+
corm_put(pdb_hd, &code, &thing);
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
/**
|
|
903
|
+
* @brief 2D x 32-bit append. See islet_put_1() for the family docs.
|
|
904
|
+
*/
|
|
905
|
+
static inline void
|
|
906
|
+
islet_put_2_32(uint32_t pdb_hd, int32_t *p, uint32_t thing)
|
|
907
|
+
{
|
|
908
|
+
uint64_t code = morton_set_2_32(p);
|
|
909
|
+
corm_put(pdb_hd, &code, &thing);
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
/**
|
|
913
|
+
* @brief Store a value at a spatial coordinate (replace).
|
|
914
|
+
*
|
|
915
|
+
* Per-dimension variants (islet_set_1..4). Replaces every value at the
|
|
916
|
+
* given point with a single new value: islet_del_all_N() followed by
|
|
917
|
+
* islet_put_N(). This preserves the historical single-value overwrite
|
|
918
|
+
* convenience on top of multi-value cells.
|
|
919
|
+
*
|
|
920
|
+
* @param[in] pdb_hd Database handle from islet_open().
|
|
921
|
+
* @param[in] p Point coordinate. Array of int16_t with at least the
|
|
922
|
+
* dimension count of the function used.
|
|
923
|
+
* @param[in] thing Value to store (uint32_t).
|
|
924
|
+
*
|
|
925
|
+
* Example:
|
|
926
|
+
* @code
|
|
927
|
+
* int16_t pos[3] = {10, 20, 30};
|
|
928
|
+
* islet_put_3(db, pos, 42);
|
|
929
|
+
* islet_set_3(db, pos, 99); // Cell now holds exactly {99}
|
|
930
|
+
* @endcode
|
|
931
|
+
*
|
|
932
|
+
* @see islet_put_3
|
|
933
|
+
* @see islet_del_all_3
|
|
934
|
+
* @see islet_get_3
|
|
935
|
+
*/
|
|
936
|
+
static inline void
|
|
937
|
+
islet_set_1(uint32_t pdb_hd, int16_t *p, uint32_t thing)
|
|
938
|
+
{
|
|
939
|
+
uint64_t code = morton_set_1(p);
|
|
940
|
+
corm_del_all(pdb_hd, &code);
|
|
941
|
+
corm_put(pdb_hd, &code, &thing);
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
/**
|
|
945
|
+
* @brief 2D replace. See islet_set_1() for the family docs.
|
|
946
|
+
*/
|
|
947
|
+
static inline void
|
|
948
|
+
islet_set_2(uint32_t pdb_hd, int16_t *p, uint32_t thing)
|
|
949
|
+
{
|
|
950
|
+
uint64_t code = morton_set_2(p);
|
|
951
|
+
corm_del_all(pdb_hd, &code);
|
|
952
|
+
corm_put(pdb_hd, &code, &thing);
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
/**
|
|
956
|
+
* @brief 3D replace. See islet_set_1() for the family docs.
|
|
957
|
+
*/
|
|
958
|
+
static inline void
|
|
959
|
+
islet_set_3(uint32_t pdb_hd, int16_t *p, uint32_t thing)
|
|
960
|
+
{
|
|
961
|
+
uint64_t code = morton_set_3(p);
|
|
962
|
+
corm_del_all(pdb_hd, &code);
|
|
963
|
+
corm_put(pdb_hd, &code, &thing);
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
/**
|
|
967
|
+
* @brief 4D replace. See islet_set_1() for the family docs.
|
|
968
|
+
*/
|
|
969
|
+
static inline void
|
|
970
|
+
islet_set_4(uint32_t pdb_hd, int16_t *p, uint32_t thing)
|
|
971
|
+
{
|
|
972
|
+
uint64_t code = morton_set_4(p);
|
|
973
|
+
corm_del_all(pdb_hd, &code);
|
|
974
|
+
corm_put(pdb_hd, &code, &thing);
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
/**
|
|
978
|
+
* @brief 2D x 32-bit replace. See islet_set_1() for the family docs.
|
|
979
|
+
*/
|
|
980
|
+
static inline void
|
|
981
|
+
islet_set_2_32(uint32_t pdb_hd, int32_t *p, uint32_t thing)
|
|
982
|
+
{
|
|
983
|
+
uint64_t code = morton_set_2_32(p);
|
|
984
|
+
corm_del_all(pdb_hd, &code);
|
|
985
|
+
corm_put(pdb_hd, &code, &thing);
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
/**
|
|
989
|
+
* @brief Fill a recall candidate set with the values in a bounding box.
|
|
990
|
+
*
|
|
991
|
+
* Per-dimension variants (rec_axis_fill_bbox_1..4). Kernel-form
|
|
992
|
+
* space-axis adapter: streams every value stored in the axis-aligned
|
|
993
|
+
* box [s, s+l] into a recall candidate set, then seals it (sort +
|
|
994
|
+
* dedup). Multiple values sharing one cell each enter the set; sealing
|
|
995
|
+
* collapses exact duplicates. The walk never materializes the box
|
|
996
|
+
* volume — sparse queries over large boxes stay cheap.
|
|
997
|
+
*
|
|
998
|
+
* @param[in] pdb_hd Database handle from islet_open().
|
|
999
|
+
* @param[in] s Start point (minimum corner). Array of int16_t.
|
|
1000
|
+
* @param[in] l Lengths per dimension. Array of uint16_t.
|
|
1001
|
+
* @param[out] out Caller-owned candidate set; appended to, then sealed.
|
|
1002
|
+
* May already hold refs (result is the union, sealed).
|
|
1003
|
+
*
|
|
1004
|
+
* @return 0 on success (out sealed). -1 when out is NULL, or the box
|
|
1005
|
+
* volume exceeds ISLET_FILL_MAX_VOL (note: 4D volumes are 4-way
|
|
1006
|
+
* products, so keep each side small).
|
|
1007
|
+
*
|
|
1008
|
+
* Example:
|
|
1009
|
+
* @code
|
|
1010
|
+
* rec_set_t *cands = rec_set_new();
|
|
1011
|
+
* int16_t s[3] = {0, 0, 0};
|
|
1012
|
+
* uint16_t l[3] = {16, 16, 16};
|
|
1013
|
+
* if (rec_axis_fill_bbox_3(db, s, l, cands) == 0) {
|
|
1014
|
+
* // rec_set_count(cands) distinct refs, sorted
|
|
1015
|
+
* }
|
|
1016
|
+
* rec_set_free(cands);
|
|
1017
|
+
* @endcode
|
|
1018
|
+
*
|
|
1019
|
+
* @see ISLET_FILL_MAX_VOL
|
|
1020
|
+
* @see islet_iter_1 islet_iter_2 islet_iter_3 islet_iter_4
|
|
1021
|
+
*/
|
|
1022
|
+
int rec_axis_fill_bbox_1(uint32_t pdb_hd, int16_t *s,
|
|
1023
|
+
uint16_t *l, rec_set_t *out);
|
|
1024
|
+
int rec_axis_fill_bbox_2(uint32_t pdb_hd, int16_t *s,
|
|
1025
|
+
uint16_t *l, rec_set_t *out);
|
|
1026
|
+
int rec_axis_fill_bbox_3(uint32_t pdb_hd, int16_t *s,
|
|
1027
|
+
uint16_t *l, rec_set_t *out);
|
|
1028
|
+
int rec_axis_fill_bbox_4(uint32_t pdb_hd, int16_t *s,
|
|
1029
|
+
uint16_t *l, rec_set_t *out);
|
|
1030
|
+
|
|
1031
|
+
/*
|
|
1032
|
+
* rec_axis_open convention (RECALL-KERNEL.md "rec_axis_open convention", optional CLI-open
|
|
1033
|
+
* convention, not part of libcorm's core rec_query registry API): opens an islet
|
|
1034
|
+
* store from an opaque "filename:database:mask" spec string (`:`-
|
|
1035
|
+
* separated; any/all fields may be empty for islet_open()'s NULL/0
|
|
1036
|
+
* defaults) and returns the ctx a caller then passes to
|
|
1037
|
+
* rec_axis_set_ctx() (the uint32_t db handle widened to a pointer via
|
|
1038
|
+
* uintptr_t).
|
|
1039
|
+
*/
|
|
1040
|
+
void *rec_axis_open(const char *spec);
|
|
1041
|
+
|
|
1042
|
+
/*
|
|
1043
|
+
* rec_axis_store / rec_axis_unstore / rec_axis_readback (phase-2A store
|
|
1044
|
+
* contract, RECALL-KERNEL.md "rec_axis_store convention", optional
|
|
1045
|
+
* CLI-specific — not libcorm core API). The consumer passes (ref, value)
|
|
1046
|
+
* blindly — one opaque string, never split; each axis parses the whole
|
|
1047
|
+
* string in its own grammar.
|
|
1048
|
+
*
|
|
1049
|
+
* Grammar: a point list "x,y[,z];x2,y2" (`;`-separated points,
|
|
1050
|
+
* `,`-separated int16 coords; dim = first point's coord count, 1..4;
|
|
1051
|
+
* int16 lanes only). store is replace-in-place (parse-first, then
|
|
1052
|
+
* unstore-then-put, in-call dups deduped; over ISLET_AXIS_MAX_POINTS →
|
|
1053
|
+
* ERANGE, else EINVAL). Cells are recorded in the rev manifest (the
|
|
1054
|
+
* grid's own single-map <fname>.ridx sidecar, opened by rec_axis_open for
|
|
1055
|
+
* non-empty fname; in-memory rev otherwise) — unstore walks it backwards,
|
|
1056
|
+
* O(cells-of-ref), never a scan; readback is the ref's cells NUL-joined
|
|
1057
|
+
* in the store grammar (round-trippable). Different refs may share a
|
|
1058
|
+
* cell; del_value removes only the target. ctx == NULL → -1.
|
|
1059
|
+
*/
|
|
1060
|
+
int rec_axis_store(void *ctx, const char *spec, rec_ref_t ref,
|
|
1061
|
+
const char *value);
|
|
1062
|
+
int rec_axis_unstore(void *ctx, rec_ref_t ref);
|
|
1063
|
+
int rec_axis_readback(void *ctx, rec_ref_t ref, char **blob_out,
|
|
1064
|
+
size_t *n_out);
|
|
1065
|
+
|
|
1066
|
+
/**
|
|
1067
|
+
* @brief 2D x 32-bit box fill. Same contract as
|
|
1068
|
+
* rec_axis_fill_bbox_N(), on int32_t lanes (start AND
|
|
1069
|
+
* lengths). ISLET_FILL_MAX_VOL caps every config alike.
|
|
1070
|
+
*/
|
|
1071
|
+
int rec_axis_fill_bbox_2_32(uint32_t pdb_hd, int32_t *s,
|
|
1072
|
+
int32_t *l, rec_set_t *out);
|
|
1073
|
+
|
|
1074
|
+
/**
|
|
1075
|
+
* @brief Per-dimension operation table.
|
|
1076
|
+
*
|
|
1077
|
+
* A single global, indexed by dimension count (1..4), giving the
|
|
1078
|
+
* per-dimension implementation of each core op. Each function pointer
|
|
1079
|
+
* takes NO dimension argument — the index into islet_ops[] is the dim.
|
|
1080
|
+
* This is the runtime-dim mechanism: when `dim` is a variable, call
|
|
1081
|
+
* `islet_ops[dim].morton_set(p)` instead of switching on the value
|
|
1082
|
+
* yourself. The type-safe alternative is to call the per-dimension
|
|
1083
|
+
* function directly (morton_set_3(), etc.), which the compiler fully
|
|
1084
|
+
* unrolls.
|
|
1085
|
+
*
|
|
1086
|
+
* islet_ops[0] is all-NULL (dimension 0 is invalid); islet_ops[1..4] are
|
|
1087
|
+
* initialized by the library.
|
|
1088
|
+
*
|
|
1089
|
+
* Example (runtime dimension):
|
|
1090
|
+
* @code
|
|
1091
|
+
* islet_ops[dim].morton_set(p); // dim in 1..4
|
|
1092
|
+
* islet_ops[dim].iter(db, s, l); // box-iterate the runtime dim
|
|
1093
|
+
* @endcode
|
|
1094
|
+
*
|
|
1095
|
+
* @see morton_set_1 morton_set_2 morton_set_3 morton_set_4
|
|
1096
|
+
* @see islet_iter_1 islet_iter_2 islet_iter_3 islet_iter_4
|
|
1097
|
+
*/
|
|
1098
|
+
typedef struct {
|
|
1099
|
+
uint64_t (*morton_set)(int16_t *p);
|
|
1100
|
+
void (*morton_get)(int16_t *p, uint64_t code);
|
|
1101
|
+
void (*point_add)(int16_t *tar, int16_t *a, int16_t *b);
|
|
1102
|
+
void (*point_copy)(int16_t *tar, int16_t *src);
|
|
1103
|
+
void (*put)(uint32_t pdb_hd, int16_t *p, uint32_t thing);
|
|
1104
|
+
uint32_t (*get)(uint32_t pdb_hd, int16_t *p);
|
|
1105
|
+
void (*set)(uint32_t pdb_hd, int16_t *p, uint32_t thing);
|
|
1106
|
+
void (*del)(uint32_t pdb_hd, int16_t *p);
|
|
1107
|
+
uint32_t (*del_all)(uint32_t pdb_hd, int16_t *p);
|
|
1108
|
+
uint32_t (*cell_count)(uint32_t pdb_hd, int16_t *p);
|
|
1109
|
+
uint32_t (*iter)(uint32_t pdb_hd, int16_t *s, uint16_t *l);
|
|
1110
|
+
uint32_t (*get_multi)(uint32_t pdb_hd, int16_t *p);
|
|
1111
|
+
int (*fill)(uint32_t pdb_hd, int16_t *s, uint16_t *l,
|
|
1112
|
+
rec_set_t *out);
|
|
1113
|
+
} islet_ops_t;
|
|
1114
|
+
|
|
1115
|
+
/**
|
|
1116
|
+
* @brief The per-dimension operation table (islet_ops[0] = all NULL).
|
|
1117
|
+
*
|
|
1118
|
+
* NOTE: literal 5 (MAX_DIM + 1) here — MAX_DIM lives in libislet.c and
|
|
1119
|
+
* this header stays standalone. Keep the two in sync.
|
|
1120
|
+
*/
|
|
1121
|
+
extern const islet_ops_t islet_ops[5];
|
|
1122
|
+
|
|
1123
|
+
#if ISLET_SIMD_MORTON
|
|
1124
|
+
/**
|
|
1125
|
+
* @brief Batch-encode multiple 3D points to Morton codes using SIMD.
|
|
1126
|
+
*
|
|
1127
|
+
* Encodes up to 4 points (AVX2) or 2 points (NEON) in parallel,
|
|
1128
|
+
* falling back to scalar for remaining points. The output array must
|
|
1129
|
+
* have space for at least @p n elements.
|
|
1130
|
+
*
|
|
1131
|
+
* @param[out] out Output Morton codes. Array of uint64_t with 'n' elements.
|
|
1132
|
+
* @param[in] points Input points. Array of int16_t[3] with 'n' entries.
|
|
1133
|
+
* @param[in] n Number of points to encode (0..UINT32_MAX).
|
|
1134
|
+
*
|
|
1135
|
+
* @return Number of points encoded (always == n).
|
|
1136
|
+
*/
|
|
1137
|
+
uint32_t morton_set_bulk(uint64_t *out, int16_t points[][3], uint32_t n);
|
|
1138
|
+
|
|
1139
|
+
/**
|
|
1140
|
+
* @brief Batch-encode multiple 4D points to Morton codes using SIMD.
|
|
1141
|
+
*
|
|
1142
|
+
* 4D analogue of morton_set_bulk(): encodes 4 points at a time under
|
|
1143
|
+
* AVX2 (dense stride-4 packing), scalar tail + fallback otherwise.
|
|
1144
|
+
* Output codes match morton_set_4() exactly.
|
|
1145
|
+
*
|
|
1146
|
+
* @param[out] out Output Morton codes. Array of uint64_t with 'n' elements.
|
|
1147
|
+
* @param[in] points Input points. Array of int16_t[4] with 'n' entries.
|
|
1148
|
+
* @param[in] n Number of points to encode (0..UINT32_MAX).
|
|
1149
|
+
*
|
|
1150
|
+
* @return Number of points encoded (always == n).
|
|
1151
|
+
*/
|
|
1152
|
+
uint32_t morton_set_bulk4(uint64_t *out, int16_t points[][4], uint32_t n);
|
|
1153
|
+
|
|
1154
|
+
/**
|
|
1155
|
+
* @brief Batch-decode multiple 3D Morton codes to points using SIMD.
|
|
1156
|
+
*
|
|
1157
|
+
* Inverse of morton_set_bulk(): decodes 4 codes at a time under AVX2
|
|
1158
|
+
* (dense compact, scalar tail + fallback otherwise). Output points
|
|
1159
|
+
* match morton_get_3() exactly.
|
|
1160
|
+
*
|
|
1161
|
+
* @param[out] points Output points. Array of int16_t[3] with 'n' entries.
|
|
1162
|
+
* @param[in] codes Input Morton codes. Array of uint64_t with 'n' elements.
|
|
1163
|
+
* @param[in] n Number of codes to decode (0..UINT32_MAX).
|
|
1164
|
+
*
|
|
1165
|
+
* @return Number of points decoded (always == n).
|
|
1166
|
+
*/
|
|
1167
|
+
uint32_t morton_get_bulk(int16_t points[][3], const uint64_t *codes, uint32_t n);
|
|
1168
|
+
|
|
1169
|
+
/**
|
|
1170
|
+
* @brief Batch-decode multiple 4D Morton codes to points using SIMD.
|
|
1171
|
+
*
|
|
1172
|
+
* 4D analogue of morton_get_bulk(): decodes 4 codes at a time under
|
|
1173
|
+
* AVX2 (dense stride-4 compact), scalar tail + fallback otherwise.
|
|
1174
|
+
* Output points match morton_get_4() exactly.
|
|
1175
|
+
*
|
|
1176
|
+
* @param[out] points Output points. Array of int16_t[4] with 'n' entries.
|
|
1177
|
+
* @param[in] codes Input Morton codes. Array of uint64_t with 'n' elements.
|
|
1178
|
+
* @param[in] n Number of codes to decode (0..UINT32_MAX).
|
|
1179
|
+
*
|
|
1180
|
+
* @return Number of points decoded (always == n).
|
|
1181
|
+
*/
|
|
1182
|
+
uint32_t morton_get_bulk4(int16_t points[][4], const uint64_t *codes, uint32_t n);
|
|
1183
|
+
#endif
|
|
1184
|
+
|
|
1185
|
+
/** @} */
|
|
1186
|
+
|
|
1187
|
+
#endif
|