1 /// @safe @nogc arrays 2 module mecca.containers.arrays; 3 4 // Licensed under the Boost license. Full copyright information in the AUTHORS file 5 6 import std.traits; 7 import mecca.lib.reflection: CapacityType; 8 import mecca.lib.exception; 9 10 /** 11 * A variable size array with a fixed maximal capacity 12 */ 13 struct FixedArray(T, size_t N, bool InitializeMembers = true) { 14 /// Alias for querying the array's element type 15 alias ElementType = T; 16 17 private: 18 alias L = CapacityType!N; 19 static if (InitializeMembers) { 20 T[N] data; 21 } else { 22 T[N] data = void; 23 } 24 L _length; 25 26 public: 27 /// Return the maximal capacity of the array 28 /// 29 /// Returns: 30 /// The capacity of the array, using the smallest unsigned type that can hold it. 31 @property L capacity() const nothrow pure @nogc { 32 return N; 33 } 34 35 /// Return the length of the array. 36 /// 37 /// This returns the same value as `length`, except it uses the narrowest type in which the length is guaranteed to 38 /// fit. 39 @property L len() const nothrow pure @safe @nogc { 40 return _length; 41 } 42 43 /// Property for getting and setting the length of the array. 44 @property size_t length() const nothrow pure @safe @nogc { 45 return len; 46 } 47 48 /// ditto 49 @property void length(size_t newLen) { 50 assert (newLen <= N); 51 static if (InitializeMembers) { 52 while (_length > newLen) { 53 destroy(data[_length-1]); 54 _length--; 55 } 56 } 57 58 _length = cast(L)newLen; 59 } 60 61 /// Returns a standard slice pointing at the array's data 62 @property inout(T)[] array() inout nothrow pure @safe @nogc { 63 return data[0 .. _length]; 64 } 65 66 auto ref opOpAssign(string op: "~", U)(U val) nothrow @safe @nogc if (is(Unqual!U == T) || isAssignable!(T, U)) { 67 ASSERT!"FixedArray is full. Capacity is %s"( _length < capacity, capacity ); 68 data[_length] = val; 69 ++_length; 70 return this; 71 } 72 73 /// FixedArray is implicitly convertible to its underlying array 74 alias array this; 75 76 static if( isAssignable!(T, const(T)) ) { 77 // If the type supports assignment from const(T) to T 78 79 /// Set the FixedArray to whatever fits from the beginning of arr2 80 void safeSetPrefix(const(T)[] arr2) { 81 length = arr2.length <= N ? arr2.length : N; 82 data[0 .. _length][] = arr2[0.._length][]; 83 } 84 /// Set the FixedArray to whatever fits from the end of arr2 85 void safeSetSuffix(const(T)[] arr2) { 86 length = arr2.length <= N ? arr2.length : N; 87 data[0 .. _length] = arr2[$ - _length .. $]; 88 } 89 } else { 90 // Only allow assignement from mutable types 91 92 /// Set the FixedArray to whatever fits from the beginning of arr2 93 void safeSetPrefix(T[] arr2) { 94 length = arr2.length <= N ? arr2.length : N; 95 data[0 .. _length][] = arr2[0.._length][]; 96 } 97 /// Set the FixedArray to whatever fits from the end of arr2 98 void safeSetSuffix(T[] arr2) { 99 length = arr2.length <= N ? arr2.length : N; 100 data[0 .. _length] = arr2[$ - _length .. $]; 101 } 102 } 103 } 104 105 /// A nogc mutable char array (string) 106 alias FixedString(size_t N) = FixedArray!(char, N, false); 107 108 /// Shorten a null terminated `FixedString` to be the size of the actual string (without the null) 109 /// 110 /// Will throw a RangeError if the string is not null terminated 111 void setStringzLength(size_t N)(ref FixedArray!(char, N, false) str) pure nothrow @safe @nogc { 112 import std..string : indexOf; 113 str.length = str.array.indexOf('\0'); 114 } 115 116 unittest { 117 FixedArray!(uint, 8) fa; 118 assert (fa.length == 0); 119 120 fa.length = 3; 121 fa[0] = 8; 122 fa[1] = 9; 123 fa[2] = 10; 124 assert (fa.length == 3); 125 } 126 127 unittest { 128 // Make sure values are initialized 129 FixedArray!(uint, 8) fa; 130 131 fa.length = 4; 132 assert (fa[2] == 0); 133 fa[3] = 4; 134 assert (fa[3] == 4); 135 fa.length = 1; 136 fa.length = 5; 137 assert (fa[3] == 0); 138 } 139 140 unittest { 141 // Make sure destructors are called 142 static struct S { 143 static uint count; 144 uint value = 3; 145 146 ~this() { 147 count++; 148 } 149 } 150 151 { 152 FixedArray!(S, 5) fa; 153 154 fa.length = 3; 155 156 assert (S.count==0); 157 158 assert(fa[2].value == 3); 159 fa[2].value = 2; 160 fa.length = 5; 161 assert (S.count==0); 162 assert(fa[2].value == 2); 163 164 fa.length = 1; 165 assert (S.count==4); 166 fa.length = 3; 167 assert (S.count==4); 168 assert(fa[2].value == 3); 169 } 170 } 171 172 unittest { 173 FixedString!5 str; 174 175 str.safeSetSuffix("123456789"); 176 assert(str[]=="56789"); 177 str.safeSetPrefix("123456789"); 178 assert(str[]=="12345"); 179 }