1 /** 2 Copyright: Copyright (c) 2020, Joakim Brännström. All rights reserved. 3 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 6 A RAII vector that uses GC memory. It is not meant to be performant but rather 7 convenient. The intention is to support put/pop for front and back and 8 convenient range operations. 9 */ 10 module my.container.vector; 11 12 import std.array : array; 13 import std.range : isForwardRange; 14 15 auto vector(T)(T[] data) { 16 return Vector!T(data); 17 } 18 19 struct Vector(T) { 20 T[] data; 21 22 void putFront(T a) { 23 data = [a] ~ data; 24 } 25 26 void put(T a) { 27 data ~= a; 28 } 29 30 void put(T[] a) { 31 data ~= a; 32 } 33 34 void popBack() { 35 data = data[0 .. $ - 1]; 36 } 37 38 T back() { 39 return data[$ - 1]; 40 } 41 42 T front() { 43 assert(!empty, "Can't get front of an empty range"); 44 return data[0]; 45 } 46 47 void popFront() { 48 assert(!empty, "Can't pop front of an empty range"); 49 data = data[1 .. $]; 50 } 51 52 void clear() { 53 data = null; 54 } 55 56 bool empty() const { 57 return data.length == 0; 58 } 59 60 size_t length() const { 61 return data.length; 62 } 63 64 Vector!T range() { 65 return Vector!T(data); 66 } 67 68 ref inout(T) opIndex(long index) return inout { 69 return data[index]; 70 } 71 72 /// Returns a new vector after appending to the given vector. 73 Vector opBinary(string s, T)(auto ref T other) const 74 if (s == "~" && is(Unqual!T == Vector)) { 75 return vector(data ~ other.data); 76 } 77 78 /// Assigns from a range. 79 void opAssign(R)(R range) scope if (isForwardRange!(R)) { 80 data = range.array; 81 } 82 83 void opOpAssign(string op)(T other) scope if (op == "~") { 84 put(other); 85 } 86 87 /// Append to the vector from a range 88 void opOpAssign(string op, R)(scope R range) scope 89 if (op == "~" && isForwardRange!(R)) { 90 data ~= range.array; 91 } 92 93 size_t opDollar() const { 94 return length; 95 } 96 97 T[] opSlice() { 98 return data; 99 } 100 101 /** 102 Returns a slice. 103 @system because the pointer in the slice might dangle. 104 */ 105 T[] opSlice(size_t start, size_t end) { 106 return data[start .. end]; 107 } 108 109 void opSliceAssign(T value) { 110 data[] = value; 111 } 112 113 /// Assign all elements in the given range to the given value 114 void opSliceAssign(T value, size_t start, size_t end) { 115 data[start .. end] = value; 116 } 117 118 /// Assign all elements using the given operation and the given value 119 void opSliceOpAssign(string op)(E value) scope { 120 foreach (ref elt; data) 121 mixin(`elt ` ~ op ~ `= value;`); 122 } 123 124 /// Assign all elements in the given range using the given operation and the given value 125 void opSliceOpAssign(string op)(E value, long start, long end) scope { 126 foreach (ref elt; data[start .. end]) 127 mixin(`elt ` ~ op ~ `= value;`); 128 } 129 130 bool opCast(U)() const scope if (is(U == bool)) { 131 return data.length > 0; 132 } 133 134 bool opEquals(ref scope const(Vector!(T)) other) const { 135 return data == other.data; 136 } 137 } 138 139 @("shall put/pop") 140 unittest { 141 Vector!int v; 142 v.put(1); 143 v.put(2); 144 145 assert(v.front == 1); 146 assert(v.back == 2); 147 v.popBack; 148 assert(v.front == 1); 149 assert(v.back == 1); 150 } 151 152 @("shall put/pop") 153 unittest { 154 Vector!int v; 155 v.put(1); 156 v.put(2); 157 158 assert(v.front == 1); 159 assert(v.back == 2); 160 v.popFront; 161 assert(v.front == 2); 162 assert(v.back == 2); 163 }