33 * This module provides functions to converting different values to const(ubyte)[]
44 *
55 * Copyright: Copyright Igor Stepanov 2013-2013.
6- * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
6+ * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
77 * Authors: Igor Stepanov
88 * Source: $(DRUNTIMESRC core/internal/_convert.d)
99 */
@@ -33,7 +33,7 @@ private ubyte[] ctfe_alloc()(size_t n)
3333 }
3434}
3535
36- @trusted pure nothrow
36+ @trusted pure nothrow @nogc
3737const (ubyte )[] toUbyte (T)(const ref T val) if (is (Unqual! T == float ) || is (Unqual! T == double ) || is (Unqual! T == real ) ||
3838 is (Unqual! T == ifloat ) || is (Unqual! T == idouble ) || is (Unqual! T == ireal ))
3939{
@@ -72,7 +72,7 @@ const(ubyte)[] toUbyte(T)(const ref T val) if (is(Unqual!T == float) || is(Unqua
7272 ulong mantissa2 = parsed.mantissa2;
7373 off_bytes-- ; // go back one, since mantissa only stored data in 56
7474 // bits, ie 7 bytes
75- for (; off_bytes < FloatTraits! T.MANTISSA / 8 ; ++ off_bytes)
75+ for (; off_bytes < FloatTraits! T.MANTISSA / 8 ; ++ off_bytes)
7676 {
7777 buff[off_bytes] = cast (ubyte )mantissa2;
7878 mantissa2 >>= 8 ;
@@ -114,13 +114,13 @@ const(ubyte)[] toUbyte(T)(const ref T val) if (is(Unqual!T == float) || is(Unqua
114114 }
115115}
116116
117- @safe pure nothrow
117+ @safe pure nothrow @nogc
118118private Float parse (bool is_denormalized = false , T)(T x) if (is (Unqual! T == ifloat ) || is (Unqual! T == idouble ) || is (Unqual! T == ireal ))
119119{
120120 return parse (x.im);
121121}
122122
123- @safe pure nothrow
123+ @safe pure nothrow @nogc
124124private Float parse (bool is_denormalized = false , T:real )(T x_) if (floatFormat! T != FloatFormat.Real80)
125125{
126126 Unqual! T x = x_;
@@ -178,7 +178,7 @@ private Float parse(bool is_denormalized = false, T:real)(T x_) if (floatFormat!
178178 }
179179}
180180
181- @safe pure nothrow
181+ @safe pure nothrow @nogc
182182private Float parse (bool _ = false , T:real )(T x_) if (floatFormat! T == FloatFormat.Real80)
183183{
184184 Unqual! T x = x_;
@@ -232,6 +232,7 @@ private struct Float
232232
233233private template FloatTraits (T) if (floatFormat! T == FloatFormat.Float)
234234{
235+ enum DATASIZE = 4 ;
235236 enum EXPONENT = 8 ;
236237 enum MANTISSA = 23 ;
237238 enum ZERO = Float(0 , 0 , 0 );
@@ -244,6 +245,7 @@ private template FloatTraits(T) if (floatFormat!T == FloatFormat.Float)
244245
245246private template FloatTraits (T) if (floatFormat! T == FloatFormat.Double)
246247{
248+ enum DATASIZE = 8 ;
247249 enum EXPONENT = 11 ;
248250 enum MANTISSA = 52 ;
249251 enum ZERO = Float(0 , 0 , 0 );
@@ -256,6 +258,7 @@ private template FloatTraits(T) if (floatFormat!T == FloatFormat.Double)
256258
257259private template FloatTraits (T) if (floatFormat! T == FloatFormat.Real80)
258260{
261+ enum DATASIZE = 10 ;
259262 enum EXPONENT = 15 ;
260263 enum MANTISSA = 64 ;
261264 enum ZERO = Float(0 , 0 , 0 );
@@ -268,6 +271,7 @@ private template FloatTraits(T) if (floatFormat!T == FloatFormat.Real80)
268271
269272private template FloatTraits (T) if (floatFormat! T == FloatFormat.DoubleDouble) // Unsupported in CTFE
270273{
274+ enum DATASIZE = 16 ;
271275 enum EXPONENT = 11 ;
272276 enum MANTISSA = 106 ;
273277 enum ZERO = Float(0 , 0 , 0 );
@@ -280,6 +284,7 @@ private template FloatTraits(T) if (floatFormat!T == FloatFormat.DoubleDouble) /
280284
281285private template FloatTraits (T) if (floatFormat! T == FloatFormat.Quadruple)
282286{
287+ enum DATASIZE = 16 ;
283288 enum EXPONENT = 15 ;
284289 enum MANTISSA = 112 ;
285290 enum ZERO = Float(0 , 0 , 0 );
@@ -291,10 +296,10 @@ private template FloatTraits(T) if (floatFormat!T == FloatFormat.Quadruple)
291296}
292297
293298
294- @safe pure nothrow
299+ @safe pure nothrow @nogc
295300private real binPow2 (int pow)
296301{
297- static real binPosPow2 (int pow) @safe pure nothrow
302+ static real binPosPow2 (int pow) @safe pure nothrow @nogc
298303 {
299304 assert (pow > 0 );
300305
@@ -319,14 +324,14 @@ private real binPow2(int pow)
319324
320325
321326// Need in CTFE, because CTFE float and double expressions computed more precisely that run-time expressions.
322- @safe pure nothrow
327+ @safe pure nothrow @nogc
323328private ulong shiftrRound (ulong x)
324329{
325330 return (x >> 1 ) + (x & 1 );
326331}
327332
328- @safe pure nothrow
329- private uint binLog2 (T)(T x)
333+ @safe pure nothrow @nogc
334+ private uint binLog2 (T)(const T x)
330335{
331336 assert (x > 0 );
332337 int max = 2 ^^ (FloatTraits! T.EXPONENT - 1 )- 1 ;
@@ -353,7 +358,7 @@ private uint binLog2(T)(T x)
353358 return max;
354359}
355360
356- @safe pure nothrow
361+ @safe pure nothrow @nogc
357362private Float denormalizedMantissa (T)(T x, uint sign) if (floatFormat! T == FloatFormat.Real80)
358363{
359364 x *= 2.0L ^^ FloatTraits! T.MANTISSA ;
@@ -362,7 +367,7 @@ private Float denormalizedMantissa(T)(T x, uint sign) if (floatFormat!T == Float
362367 return Float (fl.mantissa >> pow, 0 , sign);
363368}
364369
365- @safe pure nothrow
370+ @safe pure nothrow @nogc
366371private Float denormalizedMantissa (T)(T x, uint sign)
367372 if (floatFormat! T == FloatFormat.Float || floatFormat! T == FloatFormat.Double)
368373{
@@ -372,7 +377,7 @@ private Float denormalizedMantissa(T)(T x, uint sign)
372377 return Float (shiftrRound(mant), 0 , sign);
373378}
374379
375- @safe pure nothrow
380+ @safe pure nothrow @nogc
376381private Float denormalizedMantissa (T)(T x, uint sign) if (floatFormat! T == FloatFormat.Quadruple)
377382{
378383 x *= 2.0L ^^ FloatTraits! T.MANTISSA ;
@@ -496,17 +501,17 @@ version (unittest)
496501 testNumberConvert! (" real.min_normal/2UL^^63" );
497502 // check subnormal storage edge case for Quadruple
498503 testNumberConvert! (" real.min_normal/2UL^^56" );
499- // testNumberConvert!("real.min_normal/19"); // XGDC: ct[0] == 0, rt[0] == 27
500- // testNumberConvert!("real.min_normal/17"); // XGDC: ct[0= == 128, rt[0] == 136
504+ testNumberConvert! (" real.min_normal/19" );
505+ testNumberConvert! (" real.min_normal/17" );
501506
502507 /* *Test imaginary values: convert algorithm is same with real values*/
503508 testNumberConvert! (" 0.0Fi" );
504509 testNumberConvert! (" 0.0i" );
505510 testNumberConvert! (" 0.0Li" );
506511
507512 /* *True random values*/
508- // testNumberConvert!("-0x9.0f7ee55df77618fp-13829L"); //XGDC: ct[0,1] == [0,96], rt[0,1] == [143,97]
509- // testNumberConvert!("0x7.36e6e2640120d28p+8797L"); // XGDC: ct[0,1] == [0,24], rt[0,1] == [80,26]
513+ testNumberConvert! (" -0x9.0f7ee55df77618fp-13829L" );
514+ testNumberConvert! (" 0x7.36e6e2640120d28p+8797L" );
510515 testNumberConvert! (" -0x1.05df6ce4702ccf8p+15835L" );
511516 testNumberConvert! (" 0x9.54bb0d88806f714p-7088L" );
512517
@@ -567,22 +572,29 @@ template floatFormat(T) if (is(T:real) || is(T:ireal))
567572
568573}
569574
575+ package template floatSize(T) if (is (T:real ) || is (T:ireal ))
576+ {
577+ enum floatSize = FloatTraits! (T).DATASIZE ;
578+ }
579+
570580// all toUbyte functions must be evaluable at compile time
571- @trusted pure nothrow
572- const (ubyte )[] toUbyte (T)(T[] arr) if (T.sizeof == 1 )
581+ @trusted pure nothrow @nogc
582+ const (ubyte )[] toUbyte (T)(const T[] arr) if (T.sizeof == 1 )
573583{
574584 return cast (const (ubyte )[])arr;
575585}
576586
577- @trusted pure nothrow
578- const (ubyte )[] toUbyte (T)(T[] arr) if ((is (typeof (toUbyte(arr[0 ])) == const (ubyte )[])) && (T.sizeof > 1 ))
587+ @trusted pure nothrow @nogc
588+ const (ubyte )[] toUbyte (T)(const T[] arr) if ((is (typeof (toUbyte(arr[0 ])) == const (ubyte )[])) && (T.sizeof > 1 ))
579589{
580590 if (__ctfe)
581591 {
582- const (ubyte )[] ret;
592+ ubyte [] ret = ctfe_alloc(T.sizeof * arr.length);
593+ size_t offset = 0 ;
583594 foreach (cur; arr)
584595 {
585- ret ~= toUbyte(cur);
596+ ret[offset .. offset + T.sizeof] = toUbyte(cur)[0 .. T.sizeof];
597+ offset += T.sizeof;
586598 }
587599 return ret;
588600 }
@@ -592,14 +604,16 @@ const(ubyte)[] toUbyte(T)(T[] arr) if ((is(typeof(toUbyte(arr[0])) == const(ubyt
592604 }
593605}
594606
595- @trusted pure nothrow
596- const (ubyte )[] toUbyte (T)(ref T val) if (__traits(isIntegral, T) && ! is (T == enum ))
607+ @trusted pure nothrow @nogc
608+ const (ubyte )[] toUbyte (T)(const ref T val) if (__traits(isIntegral, T) && ! is (T == enum ) && ! is (T == __vector ))
597609{
598610 static if (T.sizeof == 1 )
599611 {
600612 if (__ctfe)
601613 {
602- return cast (const (ubyte )[])[val];
614+ ubyte [] result = ctfe_alloc(1 );
615+ result[0 ] = cast (ubyte ) val;
616+ return result;
603617 }
604618 else
605619 {
@@ -608,7 +622,7 @@ const(ubyte)[] toUbyte(T)(ref T val) if (__traits(isIntegral, T) && !is(T == enu
608622 }
609623 else if (__ctfe)
610624 {
611- ubyte [T.sizeof ] tmp;
625+ ubyte [] tmp = ctfe_alloc(T.sizeof) ;
612626 Unqual! T val_ = val;
613627 for (size_t i = 0 ; i < T.sizeof; ++ i)
614628 {
@@ -618,53 +632,91 @@ const(ubyte)[] toUbyte(T)(ref T val) if (__traits(isIntegral, T) && !is(T == enu
618632 tmp[idx] = cast (ubyte )(val_&0xff );
619633 val_ >>= 8 ;
620634 }
621- return tmp[]. dup ;
635+ return tmp;
622636 }
623637 else
624638 {
625639 return (cast (const (ubyte )* )(&val))[0 .. T.sizeof];
626640 }
627641}
628642
629- @trusted pure nothrow
630- const (ubyte )[] toUbyte (T)(ref T val) if (is (Unqual! T == cfloat ) || is (Unqual! T == cdouble ) || is (Unqual! T == creal ))
643+ @trusted pure nothrow @nogc
644+ const (ubyte )[] toUbyte (T)(const ref T val) if (is (T == __vector ))
645+ {
646+ if (! __ctfe)
647+ return (cast (const ubyte * ) &val)[0 .. T.sizeof];
648+ else static if (is (typeof (val[0 ]) : void ))
649+ assert (0 , " Unable to compute byte representation of " ~ T.stringof ~ " at compile time." );
650+ else
651+ {
652+ // This code looks like it should work in CTFE but it segfaults:
653+ // auto a = val.array;
654+ // return toUbyte(a);
655+ alias E = typeof (val[0 ]);
656+ ubyte [] result = ctfe_alloc(T.sizeof);
657+ for (size_t i = 0 , j = 0 ; i < T.sizeof; i += E.sizeof, ++ j)
658+ {
659+ result[i .. i + E.sizeof] = toUbyte(val[j]);
660+ }
661+ return result;
662+ }
663+ }
664+
665+ @trusted pure nothrow @nogc
666+ const (ubyte )[] toUbyte (T)(const ref T val) if (is (Unqual! T == cfloat ) || is (Unqual! T == cdouble ) || is (Unqual! T == creal ))
631667{
632668 if (__ctfe)
633669 {
634670 auto re = val.re;
635671 auto im = val.im;
636- return (re.toUbyte() ~ im.toUbyte());
672+ auto a = re.toUbyte();
673+ auto b = im.toUbyte();
674+ ubyte [] result = ctfe_alloc(a.length + b.length);
675+ result[0 .. a.length] = a[0 .. a.length];
676+ result[a.length .. $] = b[0 .. b.length];
677+ return result;
637678 }
638679 else
639680 {
640681 return (cast (const (ubyte )* )&val)[0 .. T.sizeof];
641682 }
642683}
643684
644- @trusted pure nothrow
645- const (ubyte )[] toUbyte (T)(ref T val) if (is (T == enum ) && is (typeof (toUbyte(cast (V)val)) == const (ubyte )[]))
685+ @trusted pure nothrow @nogc
686+ const (ubyte )[] toUbyte (T)(const ref T val) if (is (T V == enum ) && is (typeof (toUbyte(cast (const V)val)) == const (ubyte )[]))
646687{
647688 if (__ctfe)
648689 {
649690 static if (is (T V == enum )){}
650- V e_val = val;
651- return toUbyte (e_val);
691+ return toUbyte (cast (const V) val);
652692 }
653693 else
654694 {
655695 return (cast (const (ubyte )* )&val)[0 .. T.sizeof];
656696 }
657697}
658698
659- private bool isNonReference (T)()
699+ nothrow pure @safe unittest
700+ {
701+ // Issue 19008 - check toUbyte works on enums.
702+ enum Month : uint { jan = 1 }
703+ Month m = Month.jan;
704+ const bytes = toUbyte(m);
705+ enum ctfe_works = (() => { Month x = Month.jan; return toUbyte (x).length > 0 ; })();
706+ }
707+
708+ package (core.internal ) bool isNonReference(T)()
660709{
661710 static if (is (T == struct ) || is (T == union ))
662711 {
663712 return isNonReferenceStruct! T();
664713 }
665714 else static if (__traits(isStaticArray, T))
666715 {
667- return isNonReference! (typeof (T.init[0 ]))();
716+ static if (T.length > 0 )
717+ return isNonReference! (typeof (T.init[0 ]))();
718+ else
719+ return true ;
668720 }
669721 else static if (is (T E == enum ))
670722 {
@@ -698,12 +750,12 @@ private bool isNonReferenceStruct(T)() if (is(T == struct) || is(T == union))
698750 return true ;
699751}
700752
701- @trusted pure nothrow
702- const (ubyte )[] toUbyte (T)(ref T val) if (is (T == struct ) || is (T == union ))
753+ @trusted pure nothrow @nogc
754+ const (ubyte )[] toUbyte (T)(const ref T val) if (is (T == struct ) || is (T == union ))
703755{
704756 if (__ctfe)
705757 {
706- ubyte [T.sizeof ] bytes;
758+ ubyte [] bytes = ctfe_alloc(T.sizeof) ;
707759 foreach (key, cur; val.tupleof)
708760 {
709761 alias CUR_TYPE = typeof (cur);
@@ -722,7 +774,7 @@ const(ubyte)[] toUbyte(T)(ref T val) if (is(T == struct) || is(T == union))
722774 assert (0 , " Unable to compute byte representation of " ~ typeof (CUR_TYPE ).stringof~ " field at compile time" );
723775 }
724776 }
725- return bytes[]. dup ;
777+ return bytes;
726778 }
727779 else
728780 {
0 commit comments