1 module nxt.address;
2 
3 @safe pure nothrow @nogc:
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     enum byteAlignment = byteAlignment_; ///< Alignment in bytes.
17 
18     /// Null value.
19     static immutable typeof(this) nullValue = typeof(this).init;
20 
21     /// Hole/Deletion value. Prevent hole bitmap from being used.
22     static immutable typeof(this) holeValue = typeof(this)(_ptrValue.max);
23 
24     /** Get hash of `this`, with extra fast computation for the small case.
25      */
26     @property hash_t toHash() const scope @trusted
27     {
28         version(LDC) pragma(inline, true);
29         // TODO cativate import nxt.hash_functions : lemireHash64;
30         import core.internal.hash : hashOf;
31         static if (byteAlignment == 1)
32         {
33             return _ptrValue;   // as is
34         }
35         else static if (byteAlignment == 2)
36         {
37             assert((_ptrValue & 0x1) == 0); // 1 least significant bit cleared
38             return _ptrValue >> 1;
39         }
40         else static if (byteAlignment == 4)
41         {
42             assert((_ptrValue & 0x3) == 0); // 2 least significant bits cleared
43             return _ptrValue >> 2;
44         }
45         else static if (byteAlignment == 8)
46         {
47             assert((_ptrValue & 0x7) == 0); // 3 least significant bits cleared
48             return _ptrValue >> 3;
49         }
50         else
51         {
52             static assert(0, "Unsupported byteAlignment");
53         }
54     }
55 
56     size_t _ptrValue;           ///< Actual pointer value.
57     alias _ptrValue this;
58 }
59 alias Address1 = ByteAlignedAddress!(1);
60 alias Address2 = ByteAlignedAddress!(2);
61 alias Address4 = ByteAlignedAddress!(4);
62 alias Address8 = ByteAlignedAddress!(8);
63 
64 alias Address = Address1;
65 
66 ///
67 @safe pure unittest
68 {
69     import nxt.nullable_traits : hasNullValue, isNullable;
70     import nxt.open_hashmap : OpenHashMap;
71 
72     static assert(hasNullValue!Address);
73     static assert(isNullable!Address);
74 
75     OpenHashMap!(Address, Address) m;
76 
77     static assert(m.sizeof == 3*size_t.sizeof); // assure that hole bitmap is not used
78 
79     foreach (const address; 1 .. 0x1000)
80     {
81         const key = address;
82         const value = 2*address;
83 
84         assert(Address(key) !in m);
85 
86         m[Address(key)] = Address(value);
87 
88         assert(m[Address(key)] == Address(value));
89         assert(Address(key) in m);
90     }
91 }