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