init commit
This commit is contained in:
commit
6300e42bb2
28 files changed
+104005
No files matched your search
@@ -0,0 +1,367 @@
|
||||
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/
|
||||
Reference in new issue
Block a user