1 module anansi.traits;
2 
3 import std.range, std.traits, std.typecons;
4 import anansi.container : List, Array;
5 
6 // ----------------------------------------------------------------------------
7 // Graph concepts
8 // ----------------------------------------------------------------------------
9 
10 template isGraph (G) {
11     enum bool isGraph = is(typeof(
12     (inout int = 0) {
13         G g = G.init;         // We can create a graph
14         G.VertexDescriptor v; // T defines a vertex descriptor type
15         G.EdgeDescriptor e;   // T defines an eddge descriptor type
16     }));
17 }
18 
19 template isIncidenceGraph (G) {
20     enum bool isIncidenceGraph = isGraph!G && is(typeof(
21     (inout int = 0) {
22         G g;
23         G.VertexDescriptor v;
24         size_t x = g.outDegree(v);                // Can query vertex degree
25         foreach(e; g.outEdges(v)) {               // Can enumerate vertex edges
26             G.EdgeDescriptor e2 = e;              // Edge values are EdgeDescriptors
27             G.VertexDescriptor src = g.source(e); // Can query edge source
28             G.VertexDescriptor dst = g.target(e); // Can query edge target
29         }
30     }));
31 }
32 
33 // ----------------------------------------------------------------------------
34 // Property map
35 // ----------------------------------------------------------------------------
36 
37 template isReadablePropertyMap (T, IndexT, ValueT) {
38     enum bool isReadablePropertyMap = is(typeof(
39     (ref T t, IndexT idx) {
40         ValueT v = t[idx]; // can query
41     }));
42 }
43 
44 template isPropertyMap (T, IndexT, ValueT) {
45     enum bool isPropertyMap = is(typeof(
46     (ref T t, IndexT idx) {
47         ValueT v = t[idx]; // can query
48         t[idx] = v;        // can set
49     }));
50 }
51 
52 // ----------------------------------------------------------------------------
53 // Queue concept
54 // ----------------------------------------------------------------------------
55 
56 /**
57  *
58  */
59 template isQueue(T, ValueT) {
60     enum bool isQueue = is(typeof(
61     (ref T t) {
62         bool e = t.empty;
63         ValueT v = t.front;
64         t.push(v);
65         t.pop();
66     }));
67 }
68 
69 // ----------------------------------------------------------------------------
70 // Container specifiers
71 // ----------------------------------------------------------------------------
72 
73 final struct VecS {
74     alias IndexType = size_t;
75     enum IndexesAreStable = false;
76 
77     static struct Store(ValueType) {
78         auto push(ValueType value) {
79             auto rval = _store.insertBack(value);
80             return PushResult!(typeof(rval))(rval, true);
81         }
82 
83         void erase(IndexType index) {
84             _store.erase(index);
85         }
86 
87         auto indexRange() const {
88             return iota(0, _store.length);
89         }
90 
91         ref inout(ValueType) get_value(IndexType index) inout {
92             return _store[index];
93         }
94 
95         IndexType rewriteIndex(IndexType removedIndex, IndexType target) {
96             if (target > removedIndex) {
97                 return target - 1;
98             }
99             else {
100                 return target;
101             }
102         }
103 
104         @property auto dup() {
105             return Store(_store.dup);
106         }
107 
108         alias _store this;
109         Array!ValueType _store;
110     }
111 }
112 
113 final struct ListS {
114     alias IndexType = void*;
115     enum IndexesAreStable = true;
116 
117     static struct Store(ValueType) {
118         auto push(ValueType value) {
119             auto rval = _store.insertBack(value);
120             return PushResult!(typeof(rval))(rval, true);
121         }
122 
123         void erase(IndexType index) {
124             auto node = cast(List!(ValueType).Node*) index;
125             _store.remove(node);
126         }
127 
128         void eraseFrontOfRange(List!(ValueType).Range range)
129         in {
130             assert (!range.empty, "Range must not be empty.");
131         }
132         body {
133             _store.remove(range.frontNode);
134         }
135 
136         auto indexRange() const {
137             static struct IndexRange {
138                 alias Node = List!(ValueType).Node;
139 
140                 this(const(Node)* front, const(Node)* back) {
141                     _front = front;
142                     _back = back;
143                 }
144 
145                 @property bool empty() const { return _front is null; }
146                 @property void* front() const { return cast(void*) _front; }
147                 void popFront() {
148                     if (_front is _back)
149                         _front = _back = null;
150                     else
151                         _front = _front.nextNode;
152                 }
153 
154             private:
155                 const(Node)* _front;
156                 const(Node)* _back;
157             }
158 
159             static assert(isInputRange!IndexRange);
160             static assert(is(ElementType!IndexRange == void*));
161 
162             return IndexRange(_store.frontNode, _store.backNode);
163         }
164 
165         ref inout(ValueType) get_value(IndexType index) inout {
166             auto node = cast(inout(List!(ValueType).Node)*) index;
167             return node.value;
168         }
169 
170         @property auto dup() {
171             return Store(_store.dup);
172         }
173 
174         alias _store this;
175 
176         List!ValueType _store;
177     }
178 }
179 
180 struct PushResult(IndexType) {
181     IndexType index;
182     bool addedNew;
183 }
184 
185 // ----------------------------------------------------------------------------
186 //
187 // ----------------------------------------------------------------------------
188 
189 final struct DirectedS {};
190 final struct UndirectedS {};
191 final struct BidirectionalS {};
192 
193 // ----------------------------------------------------------------------------
194 //
195 // ----------------------------------------------------------------------------
196 
197 final static struct NoProperty {};
198 
199 template isNone(T) {
200   enum isNone = false;
201 }
202 
203 template isNone(T: NoProperty) {
204   enum isNone = true;
205 }
206 
207 template isNotNone(T) {
208   enum isNotNone = !(isNone!T);
209 }