155 lines
4.6 KiB
Plaintext
155 lines
4.6 KiB
Plaintext
.Dd September 24, 2026
|
|||
|
|
.Dt ENFILADE 3
|
||
|
|
.Os
|
||
|
|
.Sh NAME
|
||
|
|
.Nm enfilade
|
||
|
|
.Nd small Model-T-style tumbler-addressed enfilade
|
||
|
|
.Sh SYNOPSIS
|
||
|
|
.In enfilade.h
|
||
|
|
.Ft enfilade_t *
|
||
|
|
.Fn create_enfilade void
|
||
|
|
.Ft void
|
||
|
|
.Fn destroy_enfilade "enfilade_t *enf"
|
||
|
|
.Ft enf_result_t
|
||
|
|
.Fn put_enfilade "enfilade_t *enf" "const char *tumbler" "void *datum"
|
||
|
|
.Ft enf_result_t
|
||
|
|
.Fn remove_enfilade "enfilade_t *enf" "const char *tumbler"
|
||
|
|
.Ft void *
|
||
|
|
.Fn getXtumbler_enfilade "enfilade_t *enf" "const char *tumbler"
|
||
|
|
.Ft enf_result_t
|
||
|
|
.Fn getXtumbler_values_enfilade "enfilade_t *enf" "const char *tumbler" "void ***items" "size_t *count"
|
||
|
|
.Ft enf_result_t
|
||
|
|
.Fn getXrange_values_enfilade "enfilade_t *enf" "int64_t start" "int64_t end" "void ***items" "size_t *count"
|
||
|
|
.Ft void
|
||
|
|
.Fn enfilade_visit_data "enfilade_t *enf" "enfilade_datum_visitor visitor" "void *context"
|
||
|
|
.Sh DESCRIPTION
|
||
|
|
An
|
||
|
|
.Nm
|
||
|
|
is a tree whose local keys are unsigned integer tumbler fields.
|
||
|
|
Each node can contain terminal datum values and child enfilades at the same
|
||
|
|
numeric keys.
|
||
|
|
.Pp
|
||
|
|
Putting
|
||
|
|
.Ql 1.2.3
|
||
|
|
creates the path through keys 1, 2, and 3. The datum is stored at the final
|
||
|
|
key.
|
||
|
|
.Pp
|
||
|
|
The interface is intentionally small and follows the behavior of the
|
||
|
|
Model-T-style Python reference implementation used by this project.
|
||
|
|
.Sh CREATION AND LIFETIME
|
||
|
|
.Fn create_enfilade
|
||
|
|
returns an empty enfilade or NULL on allocation failure.
|
||
|
|
.Fn destroy_enfilade
|
||
|
|
recursively frees the enfilade tree.
|
||
|
|
.Pp
|
||
|
|
The enfilade owns its tree nodes but does not own datum pointers supplied by
|
||
|
|
the caller. The caller must keep every datum alive for as long as it may be
|
||
|
|
returned by a lookup and must destroy the enfilade before those datum objects
|
||
|
|
are destroyed.
|
||
|
|
.Sh INSERTION
|
||
|
|
.Fn put_enfilade
|
||
|
|
stores
|
||
|
|
.Fa datum
|
||
|
|
at the exact final field of
|
||
|
|
.Fa tumbler .
|
||
|
|
Missing intermediate child enfilades are created automatically.
|
||
|
|
.Pp
|
||
|
|
A second insertion at the same final key replaces the existing datum.
|
||
|
|
.Pp
|
||
|
|
If a final key already contains a datum and a child subtree, insertion replaces
|
||
|
|
only the datum.
|
||
|
|
.Sh REMOVAL
|
||
|
|
.Fn remove_enfilade
|
||
|
|
removes only the datum stored at the exact final key.
|
||
|
|
.Pp
|
||
|
|
A child subtree at that same key is retained.
|
||
|
|
Empty intermediate child enfilades are pruned after successful removal.
|
||
|
|
The datum pointer itself is never freed.
|
||
|
|
.Pp
|
||
|
|
A missing exact datum returns
|
||
|
|
.Dv ENF_ERR_NOT_FOUND .
|
||
|
|
.Sh EXACT LOOKUP
|
||
|
|
.Fn getXtumbler_enfilade
|
||
|
|
returns only the datum stored at the exact final key, or NULL if none exists or
|
||
|
|
the path is invalid.
|
||
|
|
.Pp
|
||
|
|
For callers that need reference-style flattened lookup,
|
||
|
|
.Fn getXtumbler_values_enfilade
|
||
|
|
walks every component except the last as a child path, then returns a newly
|
||
|
|
allocated array containing the datum at the final key followed by all data in
|
||
|
|
its child subtree.
|
||
|
|
.Pp
|
||
|
|
The caller owns the returned array and releases it with
|
||
|
|
.Xr free 3 .
|
||
|
|
The datum pointers remain owned by the caller.
|
||
|
|
.Sh RANGE
|
||
|
|
.Fn getXrange_values_enfilade
|
||
|
|
walks numeric keys at the current enfilade level from
|
||
|
|
.Fa start
|
||
|
|
through
|
||
|
|
.Fa end ,
|
||
|
|
inclusive, and recursively flattens their contents.
|
||
|
|
A negative
|
||
|
|
.Fa end
|
||
|
|
means there is no upper bound.
|
||
|
|
.Pp
|
||
|
|
This operation deliberately remains the existing
|
||
|
|
.Dq range
|
||
|
|
interface. It is not a parser for dotted tumbler intervals.
|
||
|
|
.Sh TRAVERSAL
|
||
|
|
.Fn enfilade_visit_data
|
||
|
|
visits every stored datum. The visitor callback is not retained after the
|
||
|
|
call.
|
||
|
|
The callback must not be assumed to outlive the traversal call.
|
||
|
|
.Sh EXAMPLE
|
||
|
|
.Bd -literal -offset indent
|
||
|
|
#include "enfilade.h"
|
||
|
|
#include <stdio.h>
|
||
|
|
|
||
|
|
int main(void)
|
||
|
|
{
|
||
|
|
enfilade_t *e = create_enfilade();
|
||
|
|
int value = 42;
|
||
|
|
void *found;
|
||
|
|
|
||
|
|
if (!e) return 1;
|
||
|
|
if (put_enfilade(e, "1.2.3", &value).code != ENF_OK)
|
||
|
|
return 1;
|
||
|
|
|
||
|
|
found = getXtumbler_enfilade(e, "1.2.3");
|
||
|
|
if (found)
|
||
|
|
printf("%d\\n", *(int *)found);
|
||
|
|
|
||
|
|
destroy_enfilade(e);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
.Ed
|
||
|
|
.Sh ERRORS
|
||
|
|
.Bl -tag -width ENF_ERR_NOT_FOUND
|
||
|
|
.It Dv ENF_OK
|
||
|
|
Success.
|
||
|
|
.It Dv ENF_ERR_NULL
|
||
|
|
A required pointer was null.
|
||
|
|
.It Dv ENF_ERR_ADDR
|
||
|
|
The tumbler text is malformed.
|
||
|
|
.It Dv ENF_ERR_NOT_FOUND
|
||
|
|
A requested datum or intermediate child was absent.
|
||
|
|
.It Dv ENF_ERR_NOMEM
|
||
|
|
An allocation failed.
|
||
|
|
.El
|
||
|
|
.Sh THREADING
|
||
|
|
The enfilade structure does not provide internal locking.
|
||
|
|
External synchronization is required if multiple threads may access the same
|
||
|
|
instance concurrently.
|
||
|
|
.Sh SCOPE
|
||
|
|
This package implements the small tumbler-keyed tree only. It does not
|
||
|
|
implement the broader Green machinery such as WIDs, DISPs, orgls, POOMs,
|
||
|
|
Spanfilades, persistent CRUM storage, rearrangement, or version management.
|
||
|
|
.Sh SEE ALSO
|
||
|
|
.Xr tumbler 3 ,
|
||
|
|
.Xr enfilade-s7 7 ,
|
||
|
|
.Xr ensifer 7
|
||
|
|
.Sh REFERENCES
|
||
|
|
.Lk https://raw.githubusercontent.com/enkiv2/ds-lib/refs/heads/master/Enfilade.py
|
||
|
|
.Pp
|
||
|
|
.Lk https://sentido-labs.com/en/library/201904240732/Xanadu%20Hypertext%20Documents.html
|