1 module m3.List; 2 3 private: 4 5 static import m3.m3; 6 7 static import std.traits; 8 alias isArray = std.traits.isArray; 9 10 public: 11 12 struct DoubleLinkedList(T) { 13 static assert(!isArray!(T), "Double Linked List cannot be used with an array"); 14 15 static struct Node { 16 T value; 17 Node* next = null; 18 Node* previous = null; 19 } 20 21 private: 22 Node* _front; 23 Node* _end; 24 25 size_t _length; 26 27 public: 28 @nogc 29 ~this() { 30 Node* cur = _front; 31 while (cur) { 32 Node* tmp = cur; 33 cur = tmp.next; 34 m3.m3.destruct(tmp); 35 } 36 } 37 38 @safe 39 @nogc 40 @property 41 size_t length() const pure nothrow { 42 return _length; 43 } 44 45 @nogc 46 @property 47 inout(Node*) front() inout pure nothrow { 48 return _front; 49 } 50 51 @nogc 52 @property 53 inout(Node*) end() inout pure nothrow { 54 return _end; 55 } 56 57 @nogc 58 void pushBack(U : T)(auto ref U item) nothrow { 59 Node* newEnd = m3.m3.make!(Node); 60 newEnd.value = item; 61 newEnd.previous = _end; 62 63 if (_end) 64 _end.next = newEnd; 65 66 _end = newEnd; 67 68 if (_length == 0) 69 _front = _end; 70 71 _length++; 72 } 73 74 @nogc 75 void pushFront(U : T)(auto ref U item) nothrow { 76 Node* newFront = m3.m3.make!(Node); 77 newFront.value = item; 78 newFront.next = _front; 79 80 if (_front) 81 _front.previous = newFront; 82 83 _front = newFront; 84 85 if (_length == 0) 86 _end = _front; 87 88 _length++; 89 } 90 91 @nogc 92 void popBack() nothrow { 93 if (_end) { 94 Node* oldEnd = _end; 95 96 _end = _end.previous; 97 if (_end) 98 _end.next = null; 99 100 m3.m3.destruct(oldEnd); 101 _length--; 102 } 103 } 104 105 @nogc 106 void popFront() nothrow { 107 if (_front) { 108 Node* oldFront = _front; 109 110 _front = _front.next; 111 if (_front) 112 _front.previous = null; 113 114 m3.m3.destruct(oldFront); 115 _length--; 116 } 117 } 118 119 @nogc 120 void erase(Node* node) { 121 if (!node) 122 return; 123 124 if (node is _end) 125 return this.popBack(); 126 if (node is _front) 127 return this.popFront(); 128 129 Node* next = node.next; 130 Node* prev = node.previous; 131 132 next.previous = prev; 133 prev.next = next; 134 135 m3.m3.destruct(node); 136 _length--; 137 } 138 } 139 140 @nogc 141 unittest { 142 DoubleLinkedList!(char) dll; 143 dll.pushBack('a'); 144 dll.pushFront('H'); 145 dll.pushBack('y'); 146 147 auto cur = dll.front; 148 assert(cur.value == 'H'); 149 assert(cur.next.value == 'a'); 150 assert(cur.next.next.value == 'y'); 151 152 dll.popBack(); 153 cur = dll.front; 154 155 assert(cur.value == 'H'); 156 assert(cur.next.value == 'a'); 157 158 dll.popBack(); 159 cur = dll.front; 160 161 assert(cur.value == 'H'); 162 163 dll.pushBack('a'); 164 dll.pushBack('y'); 165 166 cur = dll.front; 167 168 assert(cur.value == 'H'); 169 assert(cur.next.value == 'a'); 170 assert(cur.next.next.value == 'y'); 171 172 dll.popFront(); 173 cur = dll.front; 174 175 assert(cur.value == 'a'); 176 assert(cur.next.value == 'y'); 177 178 dll.popFront(); 179 cur = dll.front; 180 181 assert(cur.value == 'y'); 182 183 dll.pushBack('a'); 184 dll.pushBack('y'); 185 186 cur = dll.front; 187 188 assert(cur.value == 'y'); 189 assert(cur.next.value == 'a'); 190 assert(cur.next.next.value == 'y'); 191 192 dll.erase(cur.next); 193 cur = dll.front; 194 195 assert(cur.value == 'y'); 196 assert(cur.next.value == 'y'); 197 }