@@ -827,30 +827,37 @@ if (isInputRange!R && !isInfinite!R)
827827 if (! length) return null ;
828828 auto m = alloc.allocate(T.sizeof * length);
829829 if (! m.ptr) return null ;
830- auto result = cast (T[]) m;
830+ auto result = () @trusted { return cast (T[]) m; } () ;
831831
832832 size_t i = 0 ;
833833 scope (failure)
834834 {
835835 foreach (j; 0 .. i)
836836 {
837- destroy (* cast (Unqual! T* ) (result.ptr + j));
837+ auto p = () @trusted { return cast (Unqual! T* ) &result[j]; }();
838+ destroy (p);
838839 }
839- alloc.deallocate(m);
840+
841+ static if (canSafelyDeallocPostRewind! T)
842+ () @trusted { alloc.deallocate(m); } ();
843+ else
844+ alloc.deallocate(m);
840845 }
841846
842- import std.conv : emplace ;
847+ import std.conv : emplaceRef ;
843848 static if (isNarrowString! R || isRandomAccessRange! R)
844849 {
845850 foreach (j; 0 .. range.length)
846851 {
847- cast ( void ) emplace ! T(result.ptr + i++ , range[j]);
852+ emplaceRef ! T(result[ i++ ] , range[j]);
848853 }
849854 }
850855 else
851856 {
852857 for (; ! range.empty; range.popFront, ++ i)
853- cast (void ) emplace! T(result.ptr + i, range.front);
858+ {
859+ emplaceRef! T(result[i], range.front);
860+ }
854861 }
855862
856863 return result;
@@ -861,16 +868,20 @@ if (isInputRange!R && !isInfinite!R)
861868 size_t estimated = 8 ;
862869 auto m = alloc.allocate(T.sizeof * estimated);
863870 if (! m.ptr) return null ;
864- auto result = cast (T[]) m;
871+ auto result = () @trusted { return cast (T[]) m; } () ;
865872
866873 size_t initialized = 0 ;
867874 void bailout ()
868875 {
869- foreach (i; 0 .. initialized)
876+ foreach (i; 0 .. initialized + 1 )
870877 {
871878 destroy (result[i]);
872879 }
873- alloc.deallocate(m);
880+
881+ static if (canSafelyDeallocPostRewind! T)
882+ () @trusted { alloc.deallocate(m); } ();
883+ else
884+ alloc.deallocate(m);
874885 }
875886 scope (failure) bailout;
876887
@@ -879,22 +890,30 @@ if (isInputRange!R && !isInfinite!R)
879890 if (initialized == estimated)
880891 {
881892 // Need to reallocate
882- if (! alloc.reallocate(m, T.sizeof * (estimated *= 2 )))
893+ static if (hasPurePostblit! T)
894+ auto success = () @trusted { return alloc.reallocate(m, T.sizeof * (estimated *= 2 )); } ();
895+ else
896+ auto success = alloc.reallocate(m, T.sizeof * (estimated *= 2 ));
897+ if (! success)
883898 {
884899 bailout;
885900 return null ;
886901 }
887- result = cast (T[]) m;
902+ result = () @trusted { return cast (T[]) m; } () ;
888903 }
889- import std.conv : emplace ;
890- emplace ! T (result.ptr + initialized, range.front);
904+ import std.conv : emplaceRef ;
905+ emplaceRef (result[ initialized] , range.front);
891906 }
892907
893- // Try to shrink memory, no harm if not possible
894- if (initialized < estimated
895- && alloc.reallocate(m, T.sizeof * initialized))
908+ if (initialized < estimated)
896909 {
897- result = cast (T[]) m;
910+ // Try to shrink memory, no harm if not possible
911+ static if (hasPurePostblit! T)
912+ auto success = () @trusted { return alloc.reallocate(m, T.sizeof * initialized); } ();
913+ else
914+ auto success = alloc.reallocate(m, T.sizeof * initialized);
915+ if (success)
916+ result = () @trusted { return cast (T[]) m; } ();
898917 }
899918
900919 return result[0 .. initialized];
@@ -917,7 +936,7 @@ unittest
917936 assert (b == [4.0 , 2.0 ]);
918937 }
919938 import std.experimental.allocator.gc_allocator : GCAllocator;
920- test(GCAllocator.instance);
939+ (alloc) pure nothrow @safe { test(alloc); } (GCAllocator.instance);
921940 test(theAllocator);
922941}
923942
@@ -940,15 +959,141 @@ unittest
940959 }
941960
942961 import std.experimental.allocator.gc_allocator : GCAllocator;
943- test(GCAllocator.instance);
962+ (alloc) pure nothrow @safe { test(alloc); } (GCAllocator.instance);
944963 test(theAllocator);
945964}
946965
966+ /* pure*/ nothrow @safe unittest
967+ {
968+ import std.algorithm.comparison : equal;
969+ import std.internal.test.dummyrange ;
970+ import std.experimental.allocator.gc_allocator : GCAllocator;
971+ import std.range : iota;
972+ foreach (DummyType; AllDummyRanges)
973+ {
974+ (alloc) pure nothrow @safe
975+ {
976+ DummyType d;
977+ auto arr = alloc.makeArray(d);
978+ assert (arr.length == 10 );
979+ assert (arr.equal(iota(1 , 11 )));
980+ } (GCAllocator.instance);
981+ }
982+ }
983+
984+ // test failure with a pure, failing struct
985+ @safe unittest
986+ {
987+ import std.exception : assertThrown, enforce;
988+
989+ struct NoCopy
990+ {
991+ int b;
992+
993+ @disable this ();
994+
995+ this (int b)
996+ {
997+ this .b = b;
998+ }
999+
1000+ // can't be copied
1001+ this (this )
1002+ {
1003+ enforce(b < 3 , " there can only be three elements" );
1004+ }
1005+ }
1006+ import std.experimental.allocator.mallocator : Mallocator;
1007+ auto arr = [NoCopy(1 ), NoCopy(2 ), NoCopy(3 )];
1008+ assertThrown(makeArray! NoCopy(Mallocator.instance, arr));
1009+
1010+ struct NoCopyRange
1011+ {
1012+ static j = 0 ;
1013+ bool empty ()
1014+ {
1015+ return j > 5 ;
1016+ }
1017+
1018+ auto front ()
1019+ {
1020+ return NoCopy (j);
1021+ }
1022+
1023+ void popFront ()
1024+ {
1025+ j++ ;
1026+ }
1027+ }
1028+ assertThrown(makeArray! NoCopy(Mallocator.instance, NoCopyRange ()));
1029+ }
1030+
1031+ // test failure with an impure, failing struct
1032+ @system unittest
1033+ {
1034+ import std.exception : assertThrown, enforce;
1035+
1036+ static i = 0 ;
1037+ static maxElements = 2 ;
1038+ struct NoCopy
1039+ {
1040+ int val;
1041+ @disable this ();
1042+
1043+ this (int b){
1044+ this .val = i++ ;
1045+ }
1046+
1047+ // can't be copied
1048+ this (this )
1049+ {
1050+ enforce(i++ < maxElements, " there can only be four elements" );
1051+ }
1052+ }
1053+
1054+ import std.experimental.allocator.mallocator : Mallocator;
1055+ auto arr = [NoCopy(1 ), NoCopy(2 )];
1056+ assertThrown(makeArray! NoCopy(Mallocator.instance, arr));
1057+
1058+ // allow more copies and thus force reallocation
1059+ i = 0 ;
1060+ maxElements = 30 ;
1061+ static j = 0 ;
1062+
1063+ struct NoCopyRange
1064+ {
1065+ bool empty ()
1066+ {
1067+ return j > 100 ;
1068+ }
1069+
1070+ auto front ()
1071+ {
1072+ return NoCopy (1 );
1073+ }
1074+
1075+ void popFront ()
1076+ {
1077+ j++ ;
1078+ }
1079+ }
1080+ assertThrown(makeArray! NoCopy(Mallocator.instance, NoCopyRange ()));
1081+
1082+ maxElements = 300 ;
1083+ auto arr2 = makeArray! NoCopy(Mallocator.instance, NoCopyRange());
1084+
1085+ import std.algorithm.comparison : equal;
1086+ import std.algorithm.iteration : map;
1087+ import std.range : iota;
1088+ assert (arr2.map! ` a.val` .equal(iota(32 , 204 , 2 )));
1089+ }
1090+
9471091version (unittest )
9481092{
9491093 private struct ForcedInputRange
9501094 {
9511095 int []* array;
1096+ pure nothrow @safe @nogc :
9521097 bool empty () { return ! array || (* array).empty; }
9531098 ref int front () { return (* array)[0 ]; }
9541099 void popFront () { * array = (* array)[1 .. $]; }
@@ -967,13 +1112,13 @@ unittest
9671112 long [] a = alloc.makeArray! long (r);
9681113 assert (a.length == 0 && a.ptr is null );
9691114 auto arr2 = arr;
970- r.array = &arr2;
1115+ r.array = () @trusted { return &arr2; } () ;
9711116 a = alloc.makeArray! long (r);
9721117 assert (a.length == 10 );
9731118 assert (a == iota(10 ).array);
9741119 }
9751120 import std.experimental.allocator.gc_allocator : GCAllocator;
976- test(GCAllocator.instance);
1121+ (alloc) pure nothrow @safe { test(alloc); } (GCAllocator.instance);
9771122 test(theAllocator);
9781123}
9791124
0 commit comments