ddn.adam

Compact Dynamic Value Type

This module provides adam, a memory-efficient dynamic value type designed to match the semantics and API of ddn.var while minimizing memory footprint. It is suitable for applications where large numbers of dynamic values must be stored or transmitted with minimal overhead.

Features:

  • Compact representation: only 16 bytes on 64-bit platforms (vs. typical 24+ for variants).
  • Tagged-length encoding: type tag and collection length share a single size_t word.
  • Full numeric tower: supports bool, all D integer types, float, double, and dchar.
  • Composite types: arrays (adam[]) and objects (adam[string]) with JSON-like semantics.
  • Type normalization: realdouble, char/wchardchar to keep the tag space small.
  • GC-safe: pointer payloads are never tagged, preserving garbage collector reachability.
  • API compatibility: mirrors ddn.var operators and conversions; JSON-like

    serialization via toString().

Differences from ddn.var:

  • No temporal types: adam intentionally does not support DATE, TIME, DATETIME,

    SYSTIME, or DURATION types. This is a deliberate design choice to maintain compactness and simplicity. Applications requiring temporal values should use ddn.var instead, or encode temporal values as strings or numeric timestamps.

  • Type normalization: real is stored as double, and char/wchar are stored as dchar,

    reducing the number of type tags needed.

  • String ownership: adam copies string data on assignment (via .idup) to ensure

    memory safety, whereas some operations may differ from var.

Example:

import ddn.adam;

// Scalar values
adam i = 42;
adam d = 3.14;
adam s = "hello";

// Arrays
adam arr = [adam(1), adam(2), adam(3)];
assert(arr.length == 3);

// Objects
adam obj;
obj["name"] = "alice";
obj["age"] = 30;
assert(obj["name"].as!string == "alice");

// JSON-like serialization (compact, strings quoted and escaped)
string json = obj.toString();

Platform Notes:

  • On 64-bit systems: adam.sizeof == 16.
  • On 32-bit systems: adam.sizeof is 12 bytes with typical ABIs (an

    8-byte payload union plus the 4-byte tag word; platform alignment rules may pad this), and array/string lengths are limited to 28 bits.

See Also

ddn.var for a full-featured dynamic value type with richer semantics,

ddn.data.json5 for JSON5 parsing and serialization utilities.

Types 5

structadam

ddn.adam — a compact dynamic value type.

This implementation aims to match ddn.var semantics and API shape as closely as possible, while keeping the value representation very small.

Representation:

  • A scalar-or-pointer payload word (_data).
  • A tagged length word (_lenTag) that packs the Type tag into the high bits and (for STRING and ARRAY) the length into the low bits.

Type normalization (to keep the tag space small):

  • real values are stored as Type.DOUBLE (converted to double).
  • char and wchar values are stored as Type.DCHAR (converted to dchar).

On 64-bit platforms (size_t.sizeof == 8):

  • adam.sizeof == 16 (payload 8 bytes + tagged-length 8 bytes).

On 32-bit platforms (size_t.sizeof == 4):

  • the same tagged-length scheme is used, but the length field is smaller.
  • With the current TAG_BITS = 4, array/string lengths are limited to 28 bits (i.e., max length 2^28 - 1).

Important design rule:

  • The pointer payload is never tagged, to preserve GC reachability.
  • The tagged length is opaque; any time a real D slice is constructed, the length is masked before use.
Fields
private Data _data
private size_t _lenTag
private TAG_BITS
private size_t TAG_SHIFT
private size_t LEN_MASK
private size_t TAG_MASK
private size_t LENGTH_BITS
Methods
private Type _type() @property const nothrow @nogc pure @safe
private void _setType(Type t) nothrow @nogc pure @safe
private size_t _lengthBits() @property const nothrow @nogc pure @safe
private void _validateLength(size_t n) static @safeValidate that a length value fits in the tagged-length representation.
private void _setLengthBits(size_t n) nothrow @nogc pure @safeSet the length bits in the tagged-length word.
private void _clearPayload() nothrow @nogc pure @trusted
void clear() @safe nothrow @nogc pureReset this value to NULL.
Type type() @property const nothrow @nogc pure @safeGet the current type tag (property form like `var.type`).
adam opAssign(T)(T rhs) @safeAssign from an arbitrary value, setting tag and payload.
bool isNull() @property const nothrow @nogc pure @safe
bool isBool() @property const nothrow @nogc pure @safe`true` if the value is a `Type.BOOL`.
bool isArray() @property const nothrow @nogc pure @safe`true` if the value is a `Type.ARRAY`.
bool isString() @property const nothrow @nogc pure @safe`true` if the value is a `Type.STRING`.
bool isObject() @property const nothrow @nogc pure @safe`true` if the value is a `Type.OBJECT`.
bool isNumeric() @property const nothrow @nogc pure @safe`true` if the value holds a numeric type (integer or floating).
private bool _getBool() const @trusted
private byte _getByte() const @trusted
private ubyte _getUbyte() const @trusted
private short _getShort() const @trusted
private ushort _getUshort() const @trusted
private int _getInt() const @trusted
private uint _getUint() const @trusted
private long _getLong() const @trusted
private ulong _getUlong() const @trusted
private float _getFloat() const @trusted
private double _getDouble() const @trusted
private dchar _getDchar() const @trusted
private string _getString() const @trusted
private adam[] _getArray() const @trusted
private ObjectBox * _getObjectBox() const @trusted
T as(T)() const @trustedConvert to target type `T`. Returns `T.init` on failure (matches `var.as!T` behavior).
Nullable!T tryAs(T)() const @safe`tryAs!T` returns a `Nullable!T` that is null when conversion fails.
string toString() const @trustedJSON-like representation (matches `var.toString()` style).
size_t length() @property const @safeArray length (0 for NULL).
size_t opDollar() @property const @safeSupport `$` in slice expressions for arrays (0 for NULL).
private adam _arrayElemAt(size_t index) ref @trusted
private const(adam) _arrayElemAtConst(size_t index) ref const @trusted
adam opIndex(size_t index) ref @safeAccess an array element by index, returning a mutable reference.
const(adam) opIndex(size_t index) ref const @safeConst array element access by index.
void opIndexAssign(T)(T rhs, size_t index) @safeAssign a value to an array element at the given index.
adam opSlice(size_t start, size_t end) const @safeSlice an array and return a new ARRAY value (copies elements).
void append(T)(T rhs) @safeAppend to array (promotes NULL -> ARRAY).
void opOpAssign(string op, T)(T rhs) if (op == "~") @safeConcatenation assignment (`~=`): appends to arrays / concatenates strings, promoting NULL as documented for `append`.
bool insert(T)(size_t index, T rhs) @safeInsert `rhs` at position `index` (0..length). Returns false if index is out of range.
bool removeAt(size_t index) @safeRemove element at `index`. Returns false if out of range or NULL.
int opApply(scope int delegate(ref adam) dg)Foreach support over arrays.
int opApply(scope int delegate(ref const(adam)) @safe dg) const @safeConst foreach support over arrays.
private ObjectBox * _ensureObjectBox(string op) @trustedPromote NULL -> OBJECT and ensure a box exists.
adam opIndex(string key) ref @safeAccess a map entry by key, returning a mutable reference.
const(adam) opIndex(string key) ref const @safeConst member lookup by key (never inserts).
void opIndexAssign(T)(T rhs, string key) @safeStore `rhs` under `key`, promoting NULL to an OBJECT on first write.
adam opDispatch(string name)() ref @safeRoute unknown identifiers to map entries (autovivifying like opIndex(string)): `obj.foo = 1;` stores key `"foo"`, and `obj.foo` reads/creates it.
const(adam) opDispatch(string name)() ref const @safeNon-inserting member lookup: throws `AdamKeyException` for missing names.
bool contains(const string key) const @safeCheck whether the object contains `key`.
adam get(TDefault)(const string key, TDefault defaultValue) const @safe
bool remove(string key) @safeRemove `key` from the object.
size_t count() @property const @safeNumber of object entries (or array length). Returns 0 for NULL.
string[] keys() @property const @safeSorted list of the object's keys. Empty for NULL.
adam[] values() @property const @safeThe object's values in key order (matching `keys`). Empty for NULL.
int opApply(scope int delegate(const string, ref adam) dg)Foreach support over map entries.
int opApply(scope int delegate(const string, ref const(adam)) @safe dg) const @safeConst foreach support over map entries.
adam merge(const adam other, bool deepMerge = false) ref return @safeMerge another object into this one (like `var.merge`).
adam dup() const @safe
adam idup() const @safeAlias of `dup` (parity with `var.idup`).
adam getField(T)(const string key, T defaultValue) const @safe
adam path(const string[] pathParts) const @safeDeep-copy the value at `pathParts`, or NULL if any hop is missing.
adam path(const string pathStr) const @safeDeep-copy the value at the dot-separated `pathStr`, or NULL if missing.
auto visit(handlers...)() const @safe
private static auto _visitDispatch(R, T, handlers...)(T value) @safe
private bool _isNumericType(Type t) static nothrow @nogc pure @safe
private bool _isFloatingType(Type t) static nothrow @nogc pure @safe
private double _toDouble() const @trusted
private long _toLong() const @trustedConvert the stored value to `long` for arithmetic.
private ulong _toUlong() const @trustedConvert the stored value to `ulong` for arithmetic.
int opCmp(const adam rhs) const @safeThree-way comparison (parity with `var.opCmp`).
bool opEquals(const adam other) const @safe
size_t toHash() const @safeReturns a hash value for this `adam`.
adam makeArray() static @safeConstruct an empty ARRAY adam.
adam makeObject() static @safeConstruct an empty OBJECT adam.
Constructors
this(T arg)Construct from another value `arg` (mirrors `var.this(T)`).
Nested Templates
Type
ObjectBox
classAdamException : Exception

Base exception type for ddn.adam runtime misuse.

Constructors
this(string msg, string file = __FILE__, size_t line = __LINE__)

Thrown when an operation requires a specific runtime adam.Type.

Constructors
this(string op, adam.Type expected, adam.Type actual, string details = null, string file = __FILE__, size_t line = __LINE__)

Thrown when an object key is missing for an operation that requires it.

Constructors
this(string op, string key, string file = __FILE__, size_t line = __LINE__)

Thrown when an array index is out of range for an operation that requires it.

Constructors
this(string op, size_t index, size_t length, string file = __FILE__, size_t line = __LINE__)

Functions 1

private fnadam varLike() @safeHelper used by the clear test: a populated ARRAY adam.