init commit
This commit is contained in:
commit
6300e42bb2
28 files changed
+104005
No files matched your search
@@ -0,0 +1,298 @@
|
||||
ENSIFER 0.1.20
|
||||
============
|
||||
|
||||
A small Model-T-style enfilade in C with an S7 Scheme FFI.
|
||||
|
||||
The point of this package is to make the core mechanism usable without making
|
||||
the reader learn the whole Xanadu/Green vocabulary first.
|
||||
|
||||
Start with [`doc/USAGE`](doc/USAGE) if you are new to the code. Read
|
||||
[`doc/ensifer.7`](doc/ensifer.7) for the conceptual overview,
|
||||
[`doc/enfilade.3`](doc/enfilade.3) for the C API, and
|
||||
[`doc/enfilade-s7.7`](doc/enfilade-s7.7) for Scheme. The tumbler primitive is
|
||||
documented separately in [`doc/tumbler.3`](doc/tumbler.3) and
|
||||
[`doc/tumbler-s7.7`](doc/tumbler-s7.7).
|
||||
|
||||
THE IDEA
|
||||
--------
|
||||
|
||||
An enfilade is a tree indexed by tumbler fields.
|
||||
|
||||
A tumbler is written as a dotted sequence of unsigned integers:
|
||||
|
||||
1.2.3
|
||||
|
||||
Putting:
|
||||
|
||||
1.2.3 -> datum
|
||||
|
||||
creates the path automatically:
|
||||
|
||||
root
|
||||
|
|
||||
+-- 1
|
||||
|
|
||||
+-- 2
|
||||
|
|
||||
+-- 3 -> datum
|
||||
|
||||
A key may have both a datum and a child enfilade. Lookup returns the datum at
|
||||
that key first, then the contents of the child.
|
||||
|
||||
That is the whole basic mechanism.
|
||||
|
||||
QUICK START
|
||||
-----------
|
||||
|
||||
Configure and build the library, S7 module, and bundled REPL:
|
||||
|
||||
./configure
|
||||
make
|
||||
|
||||
Start the REPL; the enfilade functions are initialized automatically:
|
||||
|
||||
./build/bin/logan
|
||||
|
||||
Install under `/usr/local` (or set another prefix with
|
||||
`./configure --prefix=/path`):
|
||||
|
||||
make install
|
||||
|
||||
Stage an install for packaging or inspection with `DESTDIR`:
|
||||
|
||||
make install DESTDIR=/tmp/ensifer-stage
|
||||
|
||||
Run the regression suite with `make check`. `make clean` removes generated
|
||||
build files; `make distclean` also removes configure output.
|
||||
|
||||
To load the shared module into another S7 host:
|
||||
|
||||
(load "./build/lib/enfilade.so" (inlet 'init_func 'init_enfilade_s7))
|
||||
RANGE
|
||||
-----
|
||||
-----
|
||||
|
||||
`enfilade-get-range` is deliberately unchanged from the existing interface.
|
||||
It ranges over the numeric keys at the current enfilade level:
|
||||
|
||||
(enfilade-get-range e 1 3)
|
||||
|
||||
The bounds are inclusive. A negative end means "through the end".
|
||||
|
||||
This is not a dotted-tumbler interval expression.
|
||||
|
||||
TUMBLERS
|
||||
--------
|
||||
|
||||
The C layer now has a small standalone tumbler module.
|
||||
|
||||
The public primitive is:
|
||||
|
||||
#include "tumbler.h"
|
||||
|
||||
It supplies:
|
||||
|
||||
tumbler_parse()
|
||||
tumbler_free()
|
||||
tumbler_to_string()
|
||||
tumbler_compare()
|
||||
tumbler_add()
|
||||
tumbler_subtract_strong()
|
||||
tumbler_subtract_weak()
|
||||
tumbler_subtract()
|
||||
|
||||
The implementation uses `uint64_t` fields. It therefore has finite field
|
||||
width even though the historical Xanadu representation used arbitrary-precision
|
||||
Humbers. This is a deliberate boundary for the small reference build.
|
||||
|
||||
Whole-tumbler comparison follows the infinitesimal-style ordering used by the
|
||||
small tumbler implementations derived from Udanax work. Missing fields are
|
||||
compared as zero, giving the familiar ordering:
|
||||
|
||||
1 < 1.1 < 1.1.1 < 1.2 < 2
|
||||
|
||||
Arithmetic implements Xanadu's non-commutative tumbler addition and the strong,
|
||||
weak, and generalized difference operations. See `doc/tumbler.3` for the
|
||||
rules and examples.
|
||||
|
||||
C DATA LIFETIME
|
||||
---------------
|
||||
|
||||
`enfilade_t` never owns the datum pointer supplied to `put_enfilade()`.
|
||||
|
||||
For ordinary C code:
|
||||
|
||||
int value = 42;
|
||||
enfilade_t *e = create_enfilade();
|
||||
|
||||
put_enfilade(e, "1.2.3", &value);
|
||||
/* use e while value remains alive */
|
||||
|
||||
destroy_enfilade(e);
|
||||
|
||||
/* value may now go out of scope */
|
||||
|
||||
The enfilade frees its own index nodes, never the datum pointed to by an entry.
|
||||
The caller therefore controls datum lifetime.
|
||||
|
||||
For S7, the datum is an S7 object. The c-object mark function walks every
|
||||
stored datum and marks it, so Scheme objects remain reachable through the
|
||||
enfilade and are reclaimed normally after the enfilade itself is released.
|
||||
|
||||
C API
|
||||
-----
|
||||
|
||||
Create and destroy:
|
||||
|
||||
enfilade_t *create_enfilade(void);
|
||||
void destroy_enfilade(enfilade_t *enf);
|
||||
|
||||
Store and remove:
|
||||
|
||||
enf_result_t put_enfilade(enfilade_t *enf,
|
||||
const char *tumbler,
|
||||
void *datum);
|
||||
|
||||
enf_result_t remove_enfilade(enfilade_t *enf,
|
||||
const char *tumbler);
|
||||
|
||||
Lookup:
|
||||
|
||||
void *getXtumbler_enfilade(enfilade_t *enf, const char *tumbler);
|
||||
|
||||
enf_result_t getXtumbler_values_enfilade(enfilade_t *enf,
|
||||
const char *tumbler,
|
||||
void ***items,
|
||||
size_t *count);
|
||||
|
||||
Range:
|
||||
|
||||
enf_result_t getXrange_values_enfilade(enfilade_t *enf,
|
||||
int64_t start,
|
||||
int64_t end,
|
||||
void ***items,
|
||||
size_t *count);
|
||||
|
||||
Traversal:
|
||||
|
||||
void enfilade_visit_data(enfilade_t *enf,
|
||||
enfilade_datum_visitor visitor,
|
||||
void *context);
|
||||
|
||||
The two array-returning functions allocate the array of datum pointers. The
|
||||
caller frees that array with `free()`. The datum pointers are not transferred
|
||||
or freed.
|
||||
|
||||
`remove_enfilade()` removes only the datum at the exact final key. If that key
|
||||
also names a child enfilade, the child remains. Empty intermediate children
|
||||
are pruned.
|
||||
|
||||
S7 FFI
|
||||
------
|
||||
|
||||
The module defines the c-object type `<enfilade>` and these Scheme functions:
|
||||
|
||||
make-enfilade
|
||||
enfilade-put-data
|
||||
enfilade-remove
|
||||
enfilade-get-by-tumbler
|
||||
enfilade-get-range
|
||||
tumbler-compare
|
||||
tumbler-add
|
||||
tumbler-subtract
|
||||
|
||||
Load the shared object with:
|
||||
|
||||
(load "./build/lib/enfilade.so" (inlet 'init_func 'init_enfilade_s7))
|
||||
|
||||
The module does not depend on S7's `s7_repl()` startup path or on `cload.scm`.
|
||||
`build/bin/logan` is a direct small REPL with the module initialized at startup.
|
||||
|
||||
ERRORS
|
||||
------
|
||||
|
||||
Malformed tumbler text and a missing intermediate child are reported by the
|
||||
S7 binding as `TumblerAddressException`.
|
||||
|
||||
A valid tumbler whose final key has no datum or child returns `()`.
|
||||
|
||||
`enfilade-remove` returns `#t` when a datum was removed and `#f` when the exact
|
||||
final datum was not present. Malformed addresses and allocation failures are
|
||||
errors.
|
||||
|
||||
REFERENCE IMPLEMENTATION
|
||||
-------------------------
|
||||
|
||||
The immediate behavioral reference for the tree is:
|
||||
|
||||
https://raw.githubusercontent.com/enkiv2/ds-lib/refs/heads/master/Enfilade.py
|
||||
|
||||
The corresponding core operations are its `putValue`, `getByTumbler`, `get`,
|
||||
and `getRange` behavior.
|
||||
|
||||
The C implementation deliberately keeps `range` as the existing numeric-key
|
||||
range operation. Its ordered merge visits a key shared by a datum and child
|
||||
once; the Python reference can visit that key twice because it combines the two
|
||||
key lists before sorting.
|
||||
|
||||
WHAT THIS IS
|
||||
------------
|
||||
|
||||
This is a small reference enfilade: a useful, inspectable building block for
|
||||
other structures that need a tumbler-addressed index.
|
||||
|
||||
It is not the complete Udanax Green backend. The larger literature adds
|
||||
specialized enfilades and machinery for WIDs, DISPs, rearrangement, versioning,
|
||||
spans, virtual copies, persistent structures, and the Green storage model.
|
||||
Those are layers to build on top of this primitive, not requirements for using
|
||||
this one.
|
||||
|
||||
For a ZigZag cell catalogue, the natural simple pattern is:
|
||||
|
||||
cell ID (tumbler)
|
||||
|
|
||||
v
|
||||
enfilade
|
||||
|
|
||||
v
|
||||
cell pointer
|
||||
|
||||
New cells can therefore be catalogued under newly allocated tumbler IDs without
|
||||
making the catalogue itself understand the cell's internal representation.
|
||||
|
||||
FILES
|
||||
-----
|
||||
|
||||
inc/ public C and S7 headers
|
||||
src/ C implementation, bundled S7, and REPL sources
|
||||
test/ C regression tests and S7 smoke test
|
||||
scheme/ Scheme reference implementation and S7 support scripts
|
||||
doc/ usage guide and groff manual pages
|
||||
configure compiler and shared-library capability checks
|
||||
Makefile build, check, install, uninstall, and clean targets
|
||||
|
||||
TESTS
|
||||
-----
|
||||
|
||||
Run all regression checks with:
|
||||
|
||||
make check
|
||||
|
||||
This builds and runs the pure C tests and the bundled S7 smoke test.
|
||||
|
||||
HISTORICAL REFERENCES
|
||||
---------------------
|
||||
|
||||
* Xanadu Hypertext Documents, especially "Enfilade Theory" and "Tumblers and
|
||||
Humbers":
|
||||
https://sentido-labs.com/en/library/201904240732/Xanadu%20Hypertext%20Documents.html
|
||||
|
||||
* Udanax Green / Xanalogical Structure overview:
|
||||
https://www.mprove.de/visionreality/media/xuDation.html
|
||||
|
||||
* Ted Nelson and Udanax developer archive:
|
||||
https://www.xanadu.com.au/mail/udanax/
|
||||
|
||||
* Jeff Rush's `xanalogica.tumbler`, a Python implementation explicitly derived
|
||||
from Udanax Green's C source:
|
||||
https://pypi.org/project/xanalogica.tumbler/
|
||||
Reference in new issue
Block a user