@@ -4881,3 +4881,101 @@ void __ArrayDtor(T)(T[] a)
4881
4881
foreach_reverse (ref T e; a)
4882
4882
e.__xdtor();
4883
4883
}
4884
+
4885
+ /**
4886
+ Used by `__ArrayCast` to emit a descriptive error message.
4887
+
4888
+ It is a template so it can be used by `__ArrayCast` in -betterC
4889
+ builds. It is separate from `__ArrayCast` to minimize code
4890
+ bloat.
4891
+
4892
+ Params:
4893
+ fromType = name of the type being cast from
4894
+ fromSize = total size in bytes of the array being cast from
4895
+ toType = name of the type being cast o
4896
+ toSize = total size in bytes of the array being cast to
4897
+ */
4898
+ private void onArrayCastError ()(string fromType, size_t fromSize, string toType, size_t toSize) @trusted
4899
+ {
4900
+ import core.internal.string : unsignedToTempString;
4901
+ import core.stdc.stdlib : alloca;
4902
+
4903
+ const (char )[][8 ] msgComponents =
4904
+ [
4905
+ " Cannot cast `"
4906
+ , fromType
4907
+ , " ` to `"
4908
+ , toType
4909
+ , " `; an array of size "
4910
+ , unsignedToTempString(fromSize)
4911
+ , " does not align on an array of size "
4912
+ , unsignedToTempString(toSize)
4913
+ ];
4914
+
4915
+ // convert discontiguous `msgComponents` to contiguous string on the stack
4916
+ size_t length = 0 ;
4917
+ foreach (m ; msgComponents)
4918
+ length += m.length;
4919
+
4920
+ auto msg = (cast (char * )alloca(length))[0 .. length];
4921
+
4922
+ size_t index = 0 ;
4923
+ foreach (m ; msgComponents)
4924
+ foreach (c; m)
4925
+ msg[index++ ] = c;
4926
+
4927
+ // first argument must evaluate to `false` at compile-time to maintain memory safety in release builds
4928
+ assert (false , msg);
4929
+ }
4930
+
4931
+ /**
4932
+ The compiler lowers expressions of `cast(TTo[])TFrom[]` to
4933
+ this implementation.
4934
+
4935
+ Params:
4936
+ from = the array to reinterpret-cast
4937
+
4938
+ Returns:
4939
+ `from` reinterpreted as `TTo[]`
4940
+ */
4941
+ TTo[] __ArrayCast (TFrom, TTo)(TFrom[] from) @nogc pure @trusted
4942
+ {
4943
+ const fromSize = from.length * TFrom.sizeof;
4944
+ const toLength = fromSize / TTo.sizeof;
4945
+
4946
+ if ((fromSize % TTo.sizeof) != 0 )
4947
+ {
4948
+ onArrayCastError(TFrom.stringof, fromSize, TTo.stringof, toLength * TTo.sizeof);
4949
+ }
4950
+
4951
+ struct Array
4952
+ {
4953
+ size_t length;
4954
+ void * ptr;
4955
+ }
4956
+ auto a = cast (Array* )&from;
4957
+ a.length = toLength; // jam new length
4958
+ return * cast (TTo[]* )a;
4959
+ }
4960
+
4961
+ @safe @nogc pure nothrow unittest
4962
+ {
4963
+ byte [int .sizeof * 3 ] b = cast (byte ) 0xab ;
4964
+ int [] i;
4965
+ short [] s;
4966
+
4967
+ i = __ArrayCast! (byte , int )(b);
4968
+ assert (i.length == 3 );
4969
+ foreach (v; i)
4970
+ assert (v == cast (int ) 0xabab_abab);
4971
+
4972
+ s = __ArrayCast! (byte , short )(b);
4973
+ assert (s.length == 6 );
4974
+ foreach (v; s)
4975
+ assert (v == cast (short ) 0xabab );
4976
+
4977
+ s = __ArrayCast! (int , short )(i);
4978
+ assert (s.length == 6 );
4979
+ foreach (v; s)
4980
+ assert (v == cast (short ) 0xabab );
4981
+ }
0 commit comments