1 module nxt.container.array_store;
2 
3 import std.experimental.allocator.common : isAllocator;
4 
5 @safe:
6 
7 /++ Array storage.
8  +/
9 struct ArrayStore(T, Allocator = GCAllocator, Capacity = size_t)
10 if (!is(immutable T == immutable bool) && // use `BitArray` instead for now
11 	(is(Capacity == ulong) || // three 64-bit words
12 	 is(Capacity == uint)) && // two 64-bit words
13 	isAllocator!Allocator) { /+ TODO: extract to separate D module ArrayStore +/
14 pragma(inline, true):
15 
16 	this(T[] slice, in Capacity length) @trusted pure nothrow @nogc { // construct from slice
17 		static if (__traits(hasMember, this, "_slice"))
18 			_slice = slice;
19 		else {
20 			_ptr = slice.ptr;
21 			assert(slice.length <= Capacity.max);
22 			_capacity = cast(Capacity)slice.length; // trusted within this module. TODO: try to get rid of this
23 		}
24 		_length = length;
25 	}
26 
27 	this(T* ptr, in Capacity capacityAndLength) @trusted pure nothrow @nogc {
28 		version (DigitalMars) pragma(inline, false);
29 		static if (__traits(hasMember, this, "_slice"))
30 			_slice = ptr[0 .. capacityAndLength];
31 		else {
32 			_ptr = ptr;
33 			_capacity = capacityAndLength;
34 		}
35 		_length = capacityAndLength;
36 	}
37 
38 	this(T* ptr, in Capacity capacity, in Capacity length) @trusted pure nothrow @nogc {
39 		version (DigitalMars) pragma(inline, false);
40 		static if (__traits(hasMember, this, "_slice"))
41 			_slice = ptr[0 .. capacity];
42 		else {
43 			_ptr = ptr;
44 			_capacity = capacity;
45 		}
46 		_length = length;
47 	}
48 
49 	inout(T)* ptr() inout @trusted pure nothrow @nogc {
50 		static if (__traits(hasMember, this, "_slice"))
51 			return _slice.ptr;
52 		else
53 			return _ptr;
54 	}
55 
56 	Capacity capacity() const @trusted pure nothrow @nogc {
57 		static if (__traits(hasMember, this, "_slice"))
58 			return _slice.length;
59 		else
60 			return _capacity;
61 	}
62 
63 	Capacity length() const @trusted pure nothrow @nogc {
64 		return _length;
65 	}
66 
67 	inout(T)[] opSlice() inout @trusted pure nothrow @nogc {
68 		static if (__traits(hasMember, this, "_slice"))
69 			return _slice;
70 		else
71 			return _ptr[0 .. _capacity];
72 	}
73 
74 package:
75 	import std.traits : hasFunctionAttributes;
76 	enum isNoGc = hasFunctionAttributes!(Allocator.allocate, "@nogc");
77 	static if (isNoGc)
78 		import nxt.gc_traits : NoGc;
79 	static if (is(Capacity == size_t)) {
80 		static if (isNoGc) {
81 			@NoGc T[] _slice; // non-GC-allocated
82 			/+ TODO: static assert(!mustAddGCRange!(typeof(slice))); +/
83 		} else
84 			T[] _slice; // GC-allocated
85 		Capacity _length;
86 	} else {
87 		static if (isNoGc)
88 			@NoGc T* _ptr; // non-GC-allocated
89 		else
90 			T* _ptr; // GC-allocated
91 		Capacity _capacity;
92 		Capacity _length;
93 	}
94 }