1 module nxt.address;
2 
3 @safe pure:
4 
5 /** Address as an unsigned integer.
6  *
7  * Used as key, value or element instead of a pointer `OpenHashMap` to
8  * prevent triggering of `gc_addRange` and `gc_removeRange`.
9  *
10  * TODO: is `holeValue` suitably chosen?
11  *
12  * See_Also: https://en.wikipedia.org/wiki/Data_structure_alignment
13  */
14 struct ByteAlignedAddress(uint byteAlignment_) // TODO: adjust alignment here
15 {
16 @safe pure nothrow @nogc:
17     enum byteAlignment = byteAlignment_; ///< Alignment in bytes.
18 
19     /// Null value.
20     static immutable typeof(this) nullValue = typeof(this).init;
21 
22     /// Hole/Deletion value. Prevent hole bitmap from being used.
23     static immutable typeof(this) holeValue = typeof(this)(_ptrValue.max);
24 
25     /** Get hash of `this`, with extra fast computation for the small case.
26      */
27     @property hash_t toHash() const scope @trusted
28     {
29         pragma(inline, true);
30         debug checkAlignment();
31         static if (byteAlignment == 1)
32             const hash = _ptrValue; // as is
33         else static if (byteAlignment == 2)
34             const hash = _ptrValue >> 1;
35         else static if (byteAlignment == 4)
36             const hash = _ptrValue >> 2;
37         else static if (byteAlignment == 8)
38             const hash = _ptrValue >> 3;
39         else
40             static assert(0, "Unsupported byteAlignment");
41         // TODO: activate import nxt.hash_functions : lemireHash64;
42         import core.internal.hash : hashOf;
43         return hashOf(cast(void*)hash); // TODO: is `cast(void*)` preferred here?
44     }
45 
46     private debug void checkAlignment() const scope
47     {
48         assert((_ptrValue & (byteAlignment-1)) == 0,
49                "Address is not aligned to " ~ byteAlignment.stringof);
50     }
51 
52     size_t _ptrValue;           ///< Actual pointer value.
53     alias _ptrValue this;
54 }
55 alias Address1 = ByteAlignedAddress!(1);
56 alias Address2 = ByteAlignedAddress!(2);
57 alias Address4 = ByteAlignedAddress!(4);
58 alias Address8 = ByteAlignedAddress!(8);
59 
60 alias Address = Address1;
61 
62 ///
63 @safe pure unittest             // cannot be @nogc when `opIndex` may throw
64 {
65     import nxt.nullable_traits : hasNullValue, isNullable;
66     import nxt.open_hashmap : OpenHashMap;
67 
68     static assert(hasNullValue!Address);
69     static assert(isNullable!Address);
70 
71     OpenHashMap!(Address, Address) m;
72 
73     static assert(m.sizeof == 3*size_t.sizeof); // assure that hole bitmap is not used
74 
75     foreach (const address; 1 .. 0x1000)
76     {
77         const key = address;
78         const value = 2*address;
79 
80         assert(Address(key) !in m);
81 
82         m[Address(key)] = Address(value);
83 
84         assert(m[Address(key)] == Address(value));
85         assert(Address(key) in m);
86     }
87 }