1 /** Hybrid array containers.
2  */
3 module nxt.hybrid_array;
4 
5 import std.traits : isIntegral;
6 import nxt.filters : isDynamicDenseSetFilterable;
7 import std.experimental.allocator.mallocator : Mallocator;
8 
9 /** Hybrid container combining `DynamicDenseSetFilter` growable into `DynamicArray`.
10  *
11  * Has O(1) unordered element access via slicing.
12  *
13  * For use in graph algorithms with limited index ranges.
14  *
15  * TODO: better name?
16  */
17 struct DynamicDenseSetFilterGrowableArray(E, Allocator = Mallocator)
18 if (isDynamicDenseSetFilterable!E) {
19 	import nxt.filters : DynamicDenseSetFilter, Growable, Copyable;
20 	import nxt.container.dynamic_array : DynamicArray;
21 
22 	alias ElementType = E;
23 
24 	this(this) @disable;
25 
26 	pragma(inline, true):
27 
28 	/** Insert element `e`.
29 		Returns: precense status of element before insertion.
30 	*/
31 	bool insert()(E e) /*tlm*/ {
32 		/+ TODO: this doesn’t seem right: +/
33 		const hit = _set.insert(e);
34 		if (!hit)
35 			_array.insertBack(e);
36 		return hit;
37 	}
38 	alias put = insert;		 // OutputRange compatibility
39 
40 	/// Check if element `e` is stored/contained.
41 	bool contains()(E e) const => _set.contains(e); /*tlm*/
42 	/// ditto
43 	bool opBinaryRight(string op)(E e) const if (op == "in") => contains(e);
44 
45 	/// Get length.
46 	@property size_t length() const => _array.length;
47 
48 	/// Non-mutable slicing.
49 	auto opSlice() const => _array.opSlice; /*tlm*/
50 
51 	/// Clear contents.
52 	void clear()() /*tlm*/ {
53 		_set.clear();
54 		_array.clear();
55 	}
56 
57 private:
58 	/+ TODO: merge into store with only one length and capcity +/
59 	DynamicDenseSetFilter!(E, Growable.yes, Copyable.no) _set;
60 	DynamicArray!(E, Allocator) _array;
61 }
62 
63 pure nothrow @safe @nogc:
64 
65 unittest {
66 	DynamicDenseSetFilterGrowableArray!uint x;
67 
68 	assert(!x.insert(42));
69 	assert(x.contains(42));
70 	assert(x[] == [42].s);
71 
72 	assert(x.insert(42));
73 	assert(x.contains(42));
74 	assert(x[] == [42].s);
75 
76 	assert(!x.insert(43));
77 	assert(x.contains(43));
78 	assert(x[] == [42, 43].s);
79 
80 	x.clear();
81 	assert(x.length == 0);
82 
83 	assert(!x.insert(44));
84 	assert(x.contains(44));
85 	assert(x[] == [44].s);
86 }
87 
88 version (unittest) {
89 	import nxt.array_help : s;
90 }