ENSIFER ENFILADE — BEGINNER'S GUIDE =================================== This guide assumes you have never worked with an enfilade before. The shortest description is: A tumbler is an address. An enfilade is the tree that stores things at those addresses. For example: 1.2.3 is one tumbler address. If we store: 1.2.3 -> 42 the enfilade creates this path automatically: root | +-- 1 | +-- 2 | +-- 3 -> 42 You do not construct those intermediate nodes yourself. 1. BUILD AND RUN IT ------------------- From the Ensifer directory, configure and build: ./configure make Then start the REPL: ./build/bin/logan To load the module into a different S7 host: (load "./build/lib/enfilade.so" (inlet 'init_func 'init_enfilade_s7)) 2. CREATE ONE ------------- (define e (make-enfilade)) `e` is now the enfilade. 3. PUT SOMETHING IN IT ---------------------- (enfilade-put-data e "1.2.3" 42) There is now a datum at address `1.2.3`. 4. GET IT BACK -------------- (enfilade-get-by-tumbler e "1.2.3") Result: (42) The result is a Scheme list because a tumbler lookup can produce more than one datum. 5. PUT MORE IN -------------- (enfilade-put-data e "1.2.4" 43) (enfilade-put-data e "1.3.1" 99) Now: (enfilade-get-by-tumbler e "1.2.3") ; => (42) (enfilade-get-by-tumbler e "1.2") ; => (42 43) The second lookup stops at key `2` inside the `1` branch and returns the data at that key followed by the data beneath its child enfilade. 6. A KEY MAY HAVE BOTH A DATUM AND CHILDREN -------------------------------------------- This is important. (enfilade-put-data e "1.2" 99) (enfilade-put-data e "1.2.5" 50) Now key `1.2` has both: datum = 99 child = 5 -> 50 So: (enfilade-get-by-tumbler e "1.2") ; => (99 42 43 50) The datum at the exact key comes first. The child is then flattened in numeric key order. 7. REPLACE A DATUM ------------------ A final key contains one datum. Putting another datum at the same final key replaces the old one: (enfilade-put-data e "1.2.3" 500) (enfilade-get-by-tumbler e "1.2.3") ; => (500) 8. REMOVE A DATUM ----------------- (enfilade-remove e "1.2.3") ; => #t That removes only the datum stored exactly at `1.2.3`. It does not delete an unrelated child at that key. Removing a nonexistent final datum returns `#f`: (enfilade-remove e "1.2.3") ; => #f If an intermediate child does not exist, the operation reports a `TumblerAddressException` instead. 9. RANGE -------- Keep this distinction in mind: tumbler lookup = dotted address range = numeric keys at one enfilade level For example: (enfilade-get-range e 1 3) means “visit numeric keys 1, 2, and 3 at this level, inclusive, and flatten their contents.” A negative end means “through the end”: (enfilade-get-range e 2 -1) The `range` interface is intentionally kept exactly as the existing API. 10. TUMBLERS ARE MORE THAN STRINGS ----------------------------------- The external notation is a string: "1.2.3" but the package now has a real C tumbler primitive underneath it. The S7 side exposes the useful basic operations too. Compare: (tumbler-compare "1" "1.1") ; => -1 (tumbler-compare "1.1" "1.1.1") ; => -1 (tumbler-compare "1.2" "1.1.9") ; => 1 Add: (tumbler-add "3" "2.16.3") ; => "5.16.3" (tumbler-add "25.6.46.93" "0.0.3.1.21") ; => "25.6.49.1.21" Subtract / difference: (tumbler-subtract "1.4.3" "1.1.1") ; => "0.3.3" These are the historical tumbler operations, not ordinary decimal-number addition and subtraction. 11. WHY THIS MATTERS FOR ZIGZAG ------------------------------- An enfilade does not need to understand what a datum means. That is useful when the datum is a ZigZag cell pointer. Conceptually: cell ID | v tumbler | v enfilade | v cell The catalogue can therefore answer: “What cell is stored at this ID?” without embedding ZigZag cell structure into the indexing mechanism. 12. THE C VERSION ----------------- Include: #include "enfilade.h" Create: enfilade_t *e = create_enfilade(); Store a pointer: int value = 42; put_enfilade(e, "1.2.3", &value); Use it while the pointed-to object is alive: int *found = getXtumbler_enfilade(e, "1.2.3"); printf("%d\n", *found); Destroy the index before destroying the object it points to: destroy_enfilade(e); The enfilade never frees `value`. The important rule is therefore: the enfilade owns its tree; the caller owns its datum. 13. TUMBLER C API ----------------- Include: #include "tumbler.h" Parse a tumbler string: tumbler_t t = {0}; tumbler_result_t r = tumbler_parse("1.2.3", &t); Use it: int cmp = tumbler_compare(&t, &t); Release it: tumbler_free(&t); Arithmetic produces another heap-owned tumbler whose storage the caller must also release: tumbler_t a = {0}, b = {0}, out = {0}; tumbler_parse("25.6.46.93", &a); tumbler_parse("0.0.3.1.21", &b); tumbler_add(&a, &b, &out); tumbler_free(&a); tumbler_free(&b); tumbler_free(&out); 14. VALID TUMBLERS ------------------ The current C representation accepts one or more unsigned decimal fields: 1 1.2 1.2.3 0 1.0.3 100.0.7 Malformed examples: .1 1. 1..2 1.a.2 -1.2 The zero field is legal. Historical Xanadu addressing uses zero fields as delimiters in some larger address formats; this small enfilade does not assign zero any additional structural meaning. 15. ERRORS ---------- Malformed tumbler text: TumblerAddressException Missing intermediate child during lookup/removal: TumblerAddressException Valid final key with no datum or descendants: () Allocation failure: memory-error 16. WHAT YOU DO NOT NEED TO LEARN YET -------------------------------------- You do not need CRUM, POOM, Granfilade, Spanfilade, WID, DISP, orgl, loaf, or Green's virtual-memory machinery to use this object. Those names describe the larger historical system and specialized data structures built around enfilades. They are important when implementing those higher layers, but they are not prerequisites for understanding this small primitive. The right mental model for this package is simply: tumbler -> path through an enfilade -> datum(s) 17. REFERENCES -------------- Immediate behavioral reference: https://raw.githubusercontent.com/enkiv2/ds-lib/refs/heads/master/Enfilade.py Historical Xanadu technical material: https://sentido-labs.com/en/library/201904240732/Xanadu%20Hypertext%20Documents.html Udanax Green / Xanalogical Structure: https://www.mprove.de/visionreality/media/xuDation.html Jeff Rush's tumbler implementation: https://pypi.org/project/xanalogica.tumbler/