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