1 /// An event structure representing a one-to-many function/delegate relationship. 2 module subscribed.slist; 3 4 import std.experimental.allocator; 5 import std.exception : enforce, basicExceptionCtors; 6 7 /// 8 class SListException : Exception 9 { 10 /// 11 mixin basicExceptionCtors; 12 } 13 14 /** 15 * A singly linked list based on theAllocator from std.experimental.allocator. 16 * 17 * Params: 18 * T = The type of the list items. 19 */ 20 struct SList(T) 21 { 22 private 23 { 24 SListNode!T* payload; 25 void assertNonEmpty() const 26 { 27 if (empty) 28 throw new SListException("The list is empty"); 29 } 30 31 struct SListNode(T) 32 { 33 SListNode!T* next; 34 T value; 35 } 36 } 37 38 this(this) 39 { 40 if (payload is null) 41 return; 42 43 SListNode!T* srcNode = payload; 44 SListNode!T* destNode = null; 45 payload = null; 46 47 while (srcNode !is null) 48 { 49 auto newNode = theAllocator.make!(SListNode!T); 50 newNode.value = srcNode.value; 51 52 if (destNode !is null) 53 destNode.next = newNode; 54 55 destNode = newNode; 56 srcNode = srcNode.next; 57 58 if (payload is null) 59 payload = destNode; 60 } 61 } 62 63 ~this() 64 { 65 auto node = payload; 66 67 while (node !is null) 68 { 69 auto nextNode = node.next; 70 theAllocator.dispose(node); 71 node = nextNode; 72 } 73 } 74 75 /** 76 * A boolean property indicating whether there are list items. 77 * Part of the bidirectional range interface. 78 */ 79 bool empty() const 80 { 81 return payload is null; 82 } 83 84 /** 85 * Get the front element or throw an error if the list is empty. 86 * Part of the bidirectional range interface. 87 */ 88 T front() const 89 { 90 assertNonEmpty(); 91 return payload.value; 92 } 93 94 /** 95 * Pop the front element or throw an error if the list is empty. 96 * Part of the bidirectional range interface. 97 */ 98 void popFront() 99 { 100 assertNonEmpty(); 101 auto newNode = payload.next; 102 theAllocator.dispose(payload); 103 payload = newNode; 104 } 105 106 /// 107 void insertFront(T value) 108 { 109 auto node = theAllocator.make!(SListNode!T); 110 node.value = value; 111 node.next = payload; 112 payload = node; 113 } 114 115 /** 116 * Get the back element or throw an error if the list is empty. 117 * Part of the bidirectional range interface. 118 */ 119 T back() const 120 { 121 assertNonEmpty(); 122 SListNode!T* last = cast(SListNode!T*)payload; 123 124 while (last.next !is null) 125 last = last.next; 126 127 return last.value; 128 } 129 130 /** 131 * Pop the back element or throw an error if the list is empty. 132 * Part of the bidirectional range interface. 133 */ 134 void popBack() 135 { 136 assertNonEmpty(); 137 auto last = payload; 138 139 while (last.next !is null && last.next.next !is null) 140 last = last.next; 141 142 theAllocator.dispose(last.next); 143 last.next = null; 144 } 145 146 /// 147 void insertBack(T value) 148 { 149 auto newNode = theAllocator.make!(SListNode!T); 150 newNode.value = value; 151 152 if (payload is null) 153 { 154 payload = newNode; 155 } 156 else 157 { 158 auto last = payload; 159 160 while (last.next !is null) 161 last = last.next; 162 163 last.next = newNode; 164 } 165 } 166 167 /** 168 * Remove all occurrences of a given value. 169 * 170 * Params: 171 * value = the value to remove. 172 * 173 * Returns: 174 * The number of items removed from the list. 175 */ 176 size_t removeAll(T value) 177 { 178 SListNode!T* node = payload; 179 SListNode!T* prev = null; 180 size_t removedCount = 0; 181 182 while (node !is null) 183 { 184 auto next = node.next; 185 186 if (node.value == value) 187 { 188 if (node == payload) 189 payload = next; 190 else 191 prev.next = next; 192 193 theAllocator.dispose(node); 194 removedCount++; 195 } 196 else 197 prev = node; 198 199 node = next; 200 } 201 202 return removedCount; 203 } 204 205 /// 206 void clear() 207 { 208 while (!empty) 209 popFront(); 210 } 211 212 /** 213 * Copies the list to allow multiple range-like iteration. 214 * Part of the bidirectional range interface. 215 */ 216 auto save() 217 { 218 return this; 219 } 220 221 /// 222 auto opSlice() 223 { 224 return this; 225 } 226 }