1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 /** 6 * $(D_PSYMBOL tanya.range.array) implements range primitives for built-in arrays. 7 * 8 * This module is a submodule of 9 * $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/range/package.d, tanya.range). 10 * 11 * After importing of 12 * $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/range/array.d, tanya/range/array.d) 13 * built-in arrays can act as bidirectional ranges. For that to work the module 14 * defines a set of functions that accept a built-in array of any type as their 15 * first argument, so thanks to UFCS (Uniform Function Call Syntax) they can be 16 * called as if they were array member functions. For example the arrays the 17 * `.length`-property, but no `.empty` property. So here can be find the 18 * $(D_PSYMBOL empty) function. Since $(D_INLINECODE empty(array)) and 19 * $(D_INLINECODE array.empty) are equal for the arrays, arrays get a faked 20 * property `empty`. 21 * 22 * The functions in this module don't change array elements or its underlying 23 * storage, but some functions alter the slice. Each array maintains a pointer 24 * to its data and the length and there can be several pointers which point to 25 * the same data. Array pointer can be advanced and the length can be reduced 26 * without changing the underlying storage. So slices offer the possibility to 27 * have multiple views into the same array, point to different positions inside 28 * it. 29 * 30 * Strings ($(D_INLINECODE char[]), (D_INLINECODE wchar[]) and 31 * (D_INLINECODE dchar[])) are treated as any other normal array, they aren't 32 * auto-decoded. 33 * 34 * Copyright: Eugene Wissner 2017-2020. 35 * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, 36 * Mozilla Public License, v. 2.0). 37 * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) 38 * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/range/array.d, 39 * tanya/range/array.d) 40 */ 41 module tanya.range.array; 42 43 /** 44 * Returns the first element of the $(D_PARAM array). 45 * 46 * The element is returned by reference, so $(D_PSYMBOL front) can be also used 47 * to change the first element of $(D_PARAM array) if it is mutable. 48 * 49 * Params: 50 * T = Element type of $(D_PARAM array). 51 * array = Built-in array. 52 * 53 * Returns: First element. 54 * 55 * Precondition: $(D_INLINECODE array.length > 0). 56 */ 57 @property ref inout(T) front(T)(return scope inout(T)[] array) 58 in 59 { 60 assert(array.length > 0); 61 } 62 do 63 { 64 return array[0]; 65 } 66 67 /// 68 @nogc nothrow pure @safe unittest 69 { 70 string s = "Wenn die Wunde nicht mehr wehtut, schmerzt die Narbe"; 71 static assert(is(typeof(s.front) == immutable char)); 72 assert(s.front == 'W'); 73 74 wstring w = "Волны несутся, гремя и сверкая"; 75 static assert(is(typeof(w.front) == immutable wchar)); 76 assert(w.front == 'В'); 77 78 dstring d = "Для писателя память - это почти все"; 79 static assert(is(typeof(d.front) == immutable dchar)); 80 assert(d.front == 'Д'); 81 } 82 83 /** 84 * Returns the last element of the $(D_PARAM array). 85 * 86 * The element is returned by reference, so $(D_PSYMBOL back) can be also used 87 * to change the last element of $(D_PARAM array) if it is mutable. 88 * 89 * Params: 90 * T = Element type of $(D_PARAM array). 91 * array = Built-in array. 92 * 93 * Returns: Last element. 94 * 95 * Precondition: $(D_INLINECODE array.length > 0). 96 */ 97 @property ref inout(T) back(T)(return scope inout(T)[] array) 98 in 99 { 100 assert(array.length > 0); 101 } 102 do 103 { 104 return array[$ - 1]; 105 } 106 107 /// 108 @nogc nothrow pure @safe unittest 109 { 110 string s = "Brecht"; 111 static assert(is(typeof(s.back) == immutable char)); 112 assert(s.back == 't'); 113 114 wstring w = "Тютчев"; 115 static assert(is(typeof(w.back) == immutable wchar)); 116 assert(w.back == 'в'); 117 118 dstring d = "Паустовский"; 119 static assert(is(typeof(d.back) == immutable dchar)); 120 assert(d.back == 'й'); 121 } 122 123 /** 124 * $(D_PSYMBOL popFront) and $(D_PSYMBOL popBack) advance the $(D_PARAM array) 125 * and remove one element from its back, respectively. 126 * 127 * $(D_PSYMBOL popFront) and $(D_PSYMBOL popBack) don't alter the array 128 * storage, they only narrow the view into the array. 129 * 130 * Params: 131 * T = Element type of $(D_PARAM array). 132 * array = Built-in array. 133 * 134 * Precondition: $(D_INLINECODE array.length > 0). 135 */ 136 void popFront(T)(ref inout(T)[] array) 137 in 138 { 139 assert(array.length > 0); 140 } 141 do 142 { 143 array = array[1 .. $]; 144 } 145 146 /// ditto 147 void popBack(T)(ref inout(T)[] array) 148 in 149 { 150 assert(array.length > 0); 151 } 152 do 153 { 154 array = array[0 .. $ - 1]; 155 } 156 157 /// 158 @nogc nothrow pure @safe unittest 159 { 160 wstring array = "Der finstere Ozean der Metaphysik. Nietzsche"; 161 162 array.popFront(); 163 assert(array.length == 43); 164 assert(array.front == 'e'); 165 166 array.popBack(); 167 assert(array.length == 42); 168 assert(array.back == 'h'); 169 } 170 171 /** 172 * Tests whether $(D_PARAM array) is empty. 173 * 174 * Params: 175 * T = Element type of $(D_PARAM array). 176 * array = Built-in array. 177 * 178 * Returns: $(D_KEYWORD true) if $(D_PARAM array) has no elements, 179 * $(D_KEYWORD false) otherwise. 180 */ 181 @property bool empty(T)(scope const T[] array) 182 { 183 return array.length == 0; 184 } 185 186 /// 187 @nogc nothrow pure @safe unittest 188 { 189 int[1] array; 190 assert(!array.empty); 191 assert(array[1 .. 1].empty); 192 } 193 194 /** 195 * Returns a copy of the slice $(D_PARAM array). 196 * 197 * $(D_PSYMBOL save) doesn't copy the array itself, but only the data pointer 198 * and the length. 199 * 200 * Params: 201 * T = Element type of $(D_PARAM array). 202 * array = Built-in array. 203 * 204 * Returns: A copy of the slice $(D_PARAM array). 205 */ 206 @property inout(T)[] save(T)(return scope inout(T)[] array) 207 { 208 return array; 209 } 210 211 /// 212 @nogc nothrow pure @safe unittest 213 { 214 ubyte[8] array; 215 auto slice = array.save; 216 217 assert(slice.length == array.length); 218 slice.popFront(); 219 assert(slice.length < array.length); 220 }