Files

367 lines
6.9 KiB
Plaintext
Raw Permalink Normal View History

2026-09-30 19:27:45 -04:00
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/