3
3
* This module provides functions to converting different values to const(ubyte)[]
4
4
*
5
5
* 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).
7
7
* Authors: Igor Stepanov
8
8
* Source: $(DRUNTIMESRC core/internal/_convert.d)
9
9
*/
@@ -33,7 +33,7 @@ private ubyte[] ctfe_alloc()(size_t n)
33
33
}
34
34
}
35
35
36
- @trusted pure nothrow
36
+ @trusted pure nothrow @nogc
37
37
const (ubyte )[] toUbyte (T)(const ref T val) if (is (Unqual! T == float ) || is (Unqual! T == double ) || is (Unqual! T == real ) ||
38
38
is (Unqual! T == ifloat ) || is (Unqual! T == idouble ) || is (Unqual! T == ireal ))
39
39
{
@@ -72,7 +72,7 @@ const(ubyte)[] toUbyte(T)(const ref T val) if (is(Unqual!T == float) || is(Unqua
72
72
ulong mantissa2 = parsed.mantissa2;
73
73
off_bytes-- ; // go back one, since mantissa only stored data in 56
74
74
// bits, ie 7 bytes
75
- for (; off_bytes < FloatTraits! T.MANTISSA / 8 ; ++ off_bytes)
75
+ for (; off_bytes < FloatTraits! T.MANTISSA / 8 ; ++ off_bytes)
76
76
{
77
77
buff[off_bytes] = cast (ubyte )mantissa2;
78
78
mantissa2 >>= 8 ;
@@ -114,13 +114,13 @@ const(ubyte)[] toUbyte(T)(const ref T val) if (is(Unqual!T == float) || is(Unqua
114
114
}
115
115
}
116
116
117
- @safe pure nothrow
117
+ @safe pure nothrow @nogc
118
118
private Float parse (bool is_denormalized = false , T)(T x) if (is (Unqual! T == ifloat ) || is (Unqual! T == idouble ) || is (Unqual! T == ireal ))
119
119
{
120
120
return parse (x.im);
121
121
}
122
122
123
- @safe pure nothrow
123
+ @safe pure nothrow @nogc
124
124
private Float parse (bool is_denormalized = false , T:real )(T x_) if (floatFormat! T != FloatFormat.Real80)
125
125
{
126
126
Unqual! T x = x_;
@@ -178,7 +178,7 @@ private Float parse(bool is_denormalized = false, T:real)(T x_) if (floatFormat!
178
178
}
179
179
}
180
180
181
- @safe pure nothrow
181
+ @safe pure nothrow @nogc
182
182
private Float parse (bool _ = false , T:real )(T x_) if (floatFormat! T == FloatFormat.Real80)
183
183
{
184
184
Unqual! T x = x_;
@@ -232,6 +232,7 @@ private struct Float
232
232
233
233
private template FloatTraits (T) if (floatFormat! T == FloatFormat.Float)
234
234
{
235
+ enum DATASIZE = 4 ;
235
236
enum EXPONENT = 8 ;
236
237
enum MANTISSA = 23 ;
237
238
enum ZERO = Float(0 , 0 , 0 );
@@ -244,6 +245,7 @@ private template FloatTraits(T) if (floatFormat!T == FloatFormat.Float)
244
245
245
246
private template FloatTraits (T) if (floatFormat! T == FloatFormat.Double)
246
247
{
248
+ enum DATASIZE = 8 ;
247
249
enum EXPONENT = 11 ;
248
250
enum MANTISSA = 52 ;
249
251
enum ZERO = Float(0 , 0 , 0 );
@@ -256,6 +258,7 @@ private template FloatTraits(T) if (floatFormat!T == FloatFormat.Double)
256
258
257
259
private template FloatTraits (T) if (floatFormat! T == FloatFormat.Real80)
258
260
{
261
+ enum DATASIZE = 10 ;
259
262
enum EXPONENT = 15 ;
260
263
enum MANTISSA = 64 ;
261
264
enum ZERO = Float(0 , 0 , 0 );
@@ -268,6 +271,7 @@ private template FloatTraits(T) if (floatFormat!T == FloatFormat.Real80)
268
271
269
272
private template FloatTraits (T) if (floatFormat! T == FloatFormat.DoubleDouble) // Unsupported in CTFE
270
273
{
274
+ enum DATASIZE = 16 ;
271
275
enum EXPONENT = 11 ;
272
276
enum MANTISSA = 106 ;
273
277
enum ZERO = Float(0 , 0 , 0 );
@@ -280,6 +284,7 @@ private template FloatTraits(T) if (floatFormat!T == FloatFormat.DoubleDouble) /
280
284
281
285
private template FloatTraits (T) if (floatFormat! T == FloatFormat.Quadruple)
282
286
{
287
+ enum DATASIZE = 16 ;
283
288
enum EXPONENT = 15 ;
284
289
enum MANTISSA = 112 ;
285
290
enum ZERO = Float(0 , 0 , 0 );
@@ -291,10 +296,10 @@ private template FloatTraits(T) if (floatFormat!T == FloatFormat.Quadruple)
291
296
}
292
297
293
298
294
- @safe pure nothrow
299
+ @safe pure nothrow @nogc
295
300
private real binPow2 (int pow)
296
301
{
297
- static real binPosPow2 (int pow) @safe pure nothrow
302
+ static real binPosPow2 (int pow) @safe pure nothrow @nogc
298
303
{
299
304
assert (pow > 0 );
300
305
@@ -319,14 +324,14 @@ private real binPow2(int pow)
319
324
320
325
321
326
// 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
323
328
private ulong shiftrRound (ulong x)
324
329
{
325
330
return (x >> 1 ) + (x & 1 );
326
331
}
327
332
328
- @safe pure nothrow
329
- private uint binLog2 (T)(T x)
333
+ @safe pure nothrow @nogc
334
+ private uint binLog2 (T)(const T x)
330
335
{
331
336
assert (x > 0 );
332
337
int max = 2 ^^ (FloatTraits! T.EXPONENT - 1 )- 1 ;
@@ -353,7 +358,7 @@ private uint binLog2(T)(T x)
353
358
return max;
354
359
}
355
360
356
- @safe pure nothrow
361
+ @safe pure nothrow @nogc
357
362
private Float denormalizedMantissa (T)(T x, uint sign) if (floatFormat! T == FloatFormat.Real80)
358
363
{
359
364
x *= 2.0L ^^ FloatTraits! T.MANTISSA ;
@@ -362,7 +367,7 @@ private Float denormalizedMantissa(T)(T x, uint sign) if (floatFormat!T == Float
362
367
return Float (fl.mantissa >> pow, 0 , sign);
363
368
}
364
369
365
- @safe pure nothrow
370
+ @safe pure nothrow @nogc
366
371
private Float denormalizedMantissa (T)(T x, uint sign)
367
372
if (floatFormat! T == FloatFormat.Float || floatFormat! T == FloatFormat.Double)
368
373
{
@@ -372,7 +377,7 @@ private Float denormalizedMantissa(T)(T x, uint sign)
372
377
return Float (shiftrRound(mant), 0 , sign);
373
378
}
374
379
375
- @safe pure nothrow
380
+ @safe pure nothrow @nogc
376
381
private Float denormalizedMantissa (T)(T x, uint sign) if (floatFormat! T == FloatFormat.Quadruple)
377
382
{
378
383
x *= 2.0L ^^ FloatTraits! T.MANTISSA ;
@@ -496,17 +501,17 @@ version (unittest)
496
501
testNumberConvert! (" real.min_normal/2UL^^63" );
497
502
// check subnormal storage edge case for Quadruple
498
503
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" );
501
506
502
507
/* *Test imaginary values: convert algorithm is same with real values*/
503
508
testNumberConvert! (" 0.0Fi" );
504
509
testNumberConvert! (" 0.0i" );
505
510
testNumberConvert! (" 0.0Li" );
506
511
507
512
/* *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" );
510
515
testNumberConvert! (" -0x1.05df6ce4702ccf8p+15835L" );
511
516
testNumberConvert! (" 0x9.54bb0d88806f714p-7088L" );
512
517
@@ -567,22 +572,29 @@ template floatFormat(T) if (is(T:real) || is(T:ireal))
567
572
568
573
}
569
574
575
+ package template floatSize(T) if (is (T:real ) || is (T:ireal ))
576
+ {
577
+ enum floatSize = FloatTraits! (T).DATASIZE ;
578
+ }
579
+
570
580
// 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 )
573
583
{
574
584
return cast (const (ubyte )[])arr;
575
585
}
576
586
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 ))
579
589
{
580
590
if (__ctfe)
581
591
{
582
- const (ubyte )[] ret;
592
+ ubyte [] ret = ctfe_alloc(T.sizeof * arr.length);
593
+ size_t offset = 0 ;
583
594
foreach (cur; arr)
584
595
{
585
- ret ~= toUbyte(cur);
596
+ ret[offset .. offset + T.sizeof] = toUbyte(cur)[0 .. T.sizeof];
597
+ offset += T.sizeof;
586
598
}
587
599
return ret;
588
600
}
@@ -592,14 +604,16 @@ const(ubyte)[] toUbyte(T)(T[] arr) if ((is(typeof(toUbyte(arr[0])) == const(ubyt
592
604
}
593
605
}
594
606
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 ))
597
609
{
598
610
static if (T.sizeof == 1 )
599
611
{
600
612
if (__ctfe)
601
613
{
602
- return cast (const (ubyte )[])[val];
614
+ ubyte [] result = ctfe_alloc(1 );
615
+ result[0 ] = cast (ubyte ) val;
616
+ return result;
603
617
}
604
618
else
605
619
{
@@ -608,7 +622,7 @@ const(ubyte)[] toUbyte(T)(ref T val) if (__traits(isIntegral, T) && !is(T == enu
608
622
}
609
623
else if (__ctfe)
610
624
{
611
- ubyte [T.sizeof ] tmp;
625
+ ubyte [] tmp = ctfe_alloc(T.sizeof) ;
612
626
Unqual! T val_ = val;
613
627
for (size_t i = 0 ; i < T.sizeof; ++ i)
614
628
{
@@ -618,53 +632,91 @@ const(ubyte)[] toUbyte(T)(ref T val) if (__traits(isIntegral, T) && !is(T == enu
618
632
tmp[idx] = cast (ubyte )(val_&0xff );
619
633
val_ >>= 8 ;
620
634
}
621
- return tmp[]. dup ;
635
+ return tmp;
622
636
}
623
637
else
624
638
{
625
639
return (cast (const (ubyte )* )(&val))[0 .. T.sizeof];
626
640
}
627
641
}
628
642
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 ))
631
667
{
632
668
if (__ctfe)
633
669
{
634
670
auto re = val.re;
635
671
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;
637
678
}
638
679
else
639
680
{
640
681
return (cast (const (ubyte )* )&val)[0 .. T.sizeof];
641
682
}
642
683
}
643
684
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 )[]))
646
687
{
647
688
if (__ctfe)
648
689
{
649
690
static if (is (T V == enum )){}
650
- V e_val = val;
651
- return toUbyte (e_val);
691
+ return toUbyte (cast (const V) val);
652
692
}
653
693
else
654
694
{
655
695
return (cast (const (ubyte )* )&val)[0 .. T.sizeof];
656
696
}
657
697
}
658
698
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)()
660
709
{
661
710
static if (is (T == struct ) || is (T == union ))
662
711
{
663
712
return isNonReferenceStruct! T();
664
713
}
665
714
else static if (__traits(isStaticArray, T))
666
715
{
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 ;
668
720
}
669
721
else static if (is (T E == enum ))
670
722
{
@@ -698,12 +750,12 @@ private bool isNonReferenceStruct(T)() if (is(T == struct) || is(T == union))
698
750
return true ;
699
751
}
700
752
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 ))
703
755
{
704
756
if (__ctfe)
705
757
{
706
- ubyte [T.sizeof ] bytes;
758
+ ubyte [] bytes = ctfe_alloc(T.sizeof) ;
707
759
foreach (key, cur; val.tupleof)
708
760
{
709
761
alias CUR_TYPE = typeof (cur);
@@ -722,7 +774,7 @@ const(ubyte)[] toUbyte(T)(ref T val) if (is(T == struct) || is(T == union))
722
774
assert (0 , " Unable to compute byte representation of " ~ typeof (CUR_TYPE ).stringof~ " field at compile time" );
723
775
}
724
776
}
725
- return bytes[]. dup ;
777
+ return bytes;
726
778
}
727
779
else
728
780
{
0 commit comments