1 /** 2 Functions and types that manipulate built-in arrays and associative arrays. 3 4 This module provides all kinds of functions to create, manipulate or convert arrays: 5 6 $(SCRIPT inhibitQuickIndex = 1;) 7 $(BOOKTABLE , 8 $(TR $(TH Function Name) $(TH Description) 9 ) 10 $(TR $(TD $(LREF _array)) 11 $(TD Returns a copy of the input in a newly allocated dynamic _array. 12 )) 13 ) 14 15 Copyright: 2020 Ilya Yaroshenko, Kaleidic Associates Advisory Limited, Symmetry Investments 16 17 License: $(HTTP www.apache.org/licenses/LICENSE-2.0, Apache-2.0) 18 19 Authors: $(HTTP erdani.org, Andrei Alexandrescu) and Jonathan M Davis 20 21 Source: $(PHOBOSSRC std/_array.d) 22 */ 23 module mir.array.allocation; 24 25 import mir.functional; 26 import mir.primitives; 27 import std.traits; 28 29 /** 30 * Allocates an array and initializes it with copies of the elements 31 * of range $(D r). 32 * 33 * Narrow strings are handled as a special case in an overload. 34 * 35 * Params: 36 * r = range (or aggregate with $(D opApply) function) whose elements are copied into the allocated array 37 * Returns: 38 * allocated and initialized array 39 */ 40 auto array(Range)(Range r) 41 if ((isInputRange!Range || isIterable!Range) && !isInfinite!Range && !__traits(isStaticArray, Range) || isPointer!Range && (isInputRange!(PointerTarget!Range) || isIterable!(PointerTarget!Range))) 42 { 43 static if (isIterable!Range) 44 alias E = ForeachType!Range; 45 else 46 static if (isPointer!Range && isIterable!(PointerTarget!Range)) 47 alias E = ForeachType!(PointerTarget!Range); 48 else 49 alias E = ElementType!Range; 50 51 if (__ctfe) 52 { 53 // Compile-time version to avoid memcpy calls. 54 // Also used to infer attributes of array(). 55 E[] result; 56 static if (isInputRange!Range) 57 for (; !r.empty; r.popFront) 58 result ~= r.front; 59 else 60 static if (isPointer!Range) 61 foreach (e; *r) 62 result ~= e; 63 else 64 foreach (e; r) 65 result ~= e; 66 return result; 67 } 68 69 import mir.primitives: hasLength; 70 71 static if (hasLength!Range) 72 { 73 auto length = r.length; 74 if (length == 0) 75 return null; 76 77 import mir.conv : emplaceRef; 78 import std.array: uninitializedArray; 79 80 auto result = (() @trusted => uninitializedArray!(Unqual!E[])(length))(); 81 82 static if (isInputRange!Range) 83 { 84 foreach(ref e; result) 85 { 86 emplaceRef!E(e, r.front); 87 r.popFront; 88 } 89 } 90 else 91 static if (isPointer!Range) 92 { 93 auto it = result; 94 foreach(ref f; *r) 95 { 96 emplaceRef!E(it[0], f); 97 it = it[1 .. $]; 98 } 99 } 100 else 101 { 102 auto it = result; 103 foreach (f; r) 104 { 105 import mir.functional: forward; 106 emplaceRef!E(it[0], forward!f); 107 it = it[1 .. $]; 108 } 109 } 110 111 return (() @trusted => cast(E[]) result)(); 112 } 113 else 114 { 115 import mir.appender: scopedBuffer; 116 import std.array: uninitializedArray; 117 118 auto a = scopedBuffer!(Unqual!E); 119 120 static if (isInputRange!Range) 121 for (; !r.empty; r.popFront) 122 a.put(r.front); 123 else 124 static if (isPointer!Range) 125 { 126 foreach (e; *r) 127 a.put(forward!e); 128 } 129 else 130 { 131 foreach (e; r) 132 a.put(forward!e); 133 } 134 135 return () @trusted { 136 auto ret = uninitializedArray!(Unqual!E[])(a.length); 137 a.moveDataAndEmplaceTo(ret); 138 return ret; 139 } (); 140 } 141 } 142 143 /// 144 @safe pure nothrow version(mir_test) unittest 145 { 146 auto a = array([1, 2, 3, 4, 5][]); 147 assert(a == [ 1, 2, 3, 4, 5 ]); 148 } 149 150 @safe pure nothrow version(mir_test) unittest 151 { 152 import mir.algorithm.iteration : equal; 153 struct Foo 154 { 155 int a; 156 } 157 auto a = array([Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)][]); 158 assert(equal(a, [Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)])); 159 } 160 161 @safe pure nothrow version(mir_test) unittest 162 { 163 struct MyRange 164 { 165 enum front = 123; 166 enum empty = true; 167 void popFront() {} 168 } 169 170 auto arr = (new MyRange).array; 171 assert(arr.empty); 172 } 173 174 @system pure nothrow version(mir_test) unittest 175 { 176 immutable int[] a = [1, 2, 3, 4]; 177 auto b = (&a).array; 178 assert(b == a); 179 } 180 181 @system version(mir_test) unittest 182 { 183 import mir.algorithm.iteration : equal; 184 struct Foo 185 { 186 int a; 187 void opAssign(Foo) 188 { 189 assert(0); 190 } 191 auto opEquals(Foo foo) 192 { 193 return a == foo.a; 194 } 195 } 196 auto a = array([Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)][]); 197 assert(equal(a, [Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)])); 198 } 199 200 @safe version(mir_test) unittest 201 { 202 // Issue 12315 203 static struct Bug12315 { immutable int i; } 204 enum bug12315 = [Bug12315(123456789)].array(); 205 static assert(bug12315[0].i == 123456789); 206 } 207 208 @safe version(mir_test) unittest 209 { 210 import mir.ndslice.topology: repeat; 211 static struct S{int* p;} 212 auto a = array(immutable(S).init.repeat(5)); 213 assert(a.length == 5); 214 } 215 216 /// 217 @safe version(mir_test) unittest 218 { 219 assert("Hello D".array == "Hello D"); 220 assert("Hello D"w.array == "Hello D"w); 221 assert("Hello D"d.array == "Hello D"d); 222 } 223 224 @system version(mir_test) unittest 225 { 226 // @system due to array!string 227 import std.conv : to; 228 229 static struct TestArray { int x; string toString() @safe { return to!string(x); } } 230 231 static struct OpAssign 232 { 233 uint num; 234 this(uint num) { this.num = num; } 235 236 // Templating opAssign to make sure the bugs with opAssign being 237 // templated are fixed. 238 void opAssign(T)(T rhs) { this.num = rhs.num; } 239 } 240 241 static struct OpApply 242 { 243 int opApply(scope int delegate(ref int) dg) 244 { 245 int res; 246 foreach (i; 0 .. 10) 247 { 248 res = dg(i); 249 if (res) break; 250 } 251 252 return res; 253 } 254 } 255 256 auto a = array([1, 2, 3, 4, 5][]); 257 assert(a == [ 1, 2, 3, 4, 5 ]); 258 259 auto b = array([TestArray(1), TestArray(2)][]); 260 assert(b == [TestArray(1), TestArray(2)]); 261 262 class C 263 { 264 int x; 265 this(int y) { x = y; } 266 override string toString() const @safe { return to!string(x); } 267 } 268 auto c = array([new C(1), new C(2)][]); 269 assert(c[0].x == 1); 270 assert(c[1].x == 2); 271 272 auto d = array([1.0, 2.2, 3][]); 273 assert(is(typeof(d) == double[])); 274 assert(d == [1.0, 2.2, 3]); 275 276 auto e = [OpAssign(1), OpAssign(2)]; 277 auto f = array(e); 278 assert(e == f); 279 280 assert(array(OpApply.init) == [0,1,2,3,4,5,6,7,8,9]); 281 assert(array("ABC") == "ABC"); 282 assert(array("ABC".dup) == "ABC"); 283 } 284 285 //Bug# 8233 286 @safe version(mir_test) unittest 287 { 288 assert(array("hello world"d) == "hello world"d); 289 immutable a = [1, 2, 3, 4, 5]; 290 assert(array(a) == a); 291 const b = a; 292 assert(array(b) == a); 293 294 //To verify that the opAssign branch doesn't get screwed up by using Unqual. 295 //EDIT: array no longer calls opAssign. 296 struct S 297 { 298 ref S opAssign(S)(const ref S rhs) 299 { 300 assert(0); 301 } 302 303 int i; 304 } 305 306 alias AliasSeq(T...) = T; 307 foreach (T; AliasSeq!(S, const S, immutable S)) 308 { 309 auto arr = [T(1), T(2), T(3), T(4)]; 310 assert(array(arr) == arr); 311 } 312 } 313 314 @safe version(mir_test) unittest 315 { 316 //9824 317 static struct S 318 { 319 @disable void opAssign(S); 320 int i; 321 } 322 auto arr = [S(0), S(1), S(2)]; 323 arr.array; 324 } 325 326 // Bugzilla 10220 327 @safe version(mir_test) unittest 328 { 329 import mir.algorithm.iteration : equal; 330 import std.exception; 331 import mir.ndslice.topology: repeat; 332 333 static struct S 334 { 335 int val; 336 337 @disable this(); 338 this(int v) { val = v; } 339 } 340 static immutable r = S(1).repeat(2).array(); 341 assert(equal(r, [S(1), S(1)])); 342 } 343 344 @safe version(mir_test) unittest 345 { 346 //Turn down infinity: 347 static assert(!is(typeof( 348 repeat(1).array() 349 ))); 350 }