@@ -267,130 +267,116 @@ unittest
267267 }();
268268}
269269
270+ private template Select (bool cond, T, U)
271+ {
272+ static if (cond) alias Select = T;
273+ else alias Select = U;
274+ }
275+
270276/**
271277TypeInfo information for built-in types.
278+
279+ Type `T` has the same layout and alignment as type `Base`, but slightly different behavior.
280+ Example: `float` and `ifloat` or `char` and `ubyte`.
281+ We assume the two types hash the same, swap the same, have the same ABI flags, and compare the same for
282+ equality. For ordering comparisons, we detect during compilation whether they have different min and max
283+ values (e.g. signed vs. unsigned) and override appropriately. For initializer, we detect if we need to
284+ override. The overriding initializer should be nonzero.
272285*/
273- private class TypeInfoGeneric (T) : TypeInfo
286+ private class TypeInfoGeneric (T, Base = T) : Select !(is(T == Base), TypeInfo, TypeInfoGeneric!Base)
287+ if (T.sizeof == Base.sizeof && T.alignof == Base.alignof)
274288{
275289 const : nothrow : pure : @trusted :
276290
291+ // Returns the type name.
277292 override string toString () const pure nothrow @safe { return T.stringof; }
278293
279- override size_t getHash (scope const void * p)
280- {
281- static if (__traits(isFloating, T))
282- return Floating! T.hashOf(* cast (T* )p);
283- else
284- return hashOf (* cast (const T * )p);
285- }
286-
287- override bool equals (in void * p1, in void * p2)
288- {
289- static if (__traits(isFloating, T))
290- return Floating! T.equals(* cast (T* )p1, * cast (T* )p2);
291- else
292- return * cast (T * )p1 == * cast (T * )p2;
293- }
294-
295- override int compare (in void * p1, in void * p2)
296- {
297- static if (__traits(isFloating, T))
294+ // `getHash` is the same for `Base` and `T`, introduce it just once.
295+ static if (is (T == Base))
296+ override size_t getHash (scope const void * p)
298297 {
299- return Floating! T.compare(* cast (T* )p1, * cast (T* )p2);
298+ static if (__traits(isFloating, T))
299+ return Floating! T.hashOf(* cast (T* )p);
300+ else
301+ return hashOf (* cast (const T * )p);
300302 }
301- else static if (T.sizeof < int .sizeof)
303+
304+ // `equals` is the same for `Base` and `T`, introduce it just once.
305+ static if (is (T == Base))
306+ override bool equals (in void * p1, in void * p2)
302307 {
303- return * cast (T * )p1 - * cast (T * )p2;
308+ static if (__traits(isFloating, T))
309+ return Floating! T.equals(* cast (T* )p1, * cast (T* )p2);
310+ else
311+ return * cast (T * )p1 == * cast (T * )p2;
304312 }
305- else
313+
314+ // `T` and `Base` may have different signedness, so this function is introduced conditionally.
315+ static if (is (T == Base) || (__traits(isIntegral, T) && T.max != Base.max))
316+ override int compare (in void * p1, in void * p2)
306317 {
307- if (* cast (T * )p1 < * cast (T * )p2)
308- return - 1 ;
309- if (* cast (T * )p1 > * cast (T * )p2)
310- return 1 ;
311- return 0 ;
318+ static if (__traits(isFloating, T))
319+ {
320+ return Floating! T.compare(* cast (T* )p1, * cast (T* )p2);
321+ }
322+ else static if (T.sizeof < int .sizeof)
323+ {
324+ // Taking the difference will always fit in an int.
325+ return int (* cast (T * ) p1) - int (* cast (T * ) p2);
326+ }
327+ else
328+ {
329+ auto lhs = * cast (T * ) p1, rhs = * cast (T * ) p2;
330+ return (lhs > rhs) - (lhs < rhs);
331+ }
312332 }
313- }
314-
315- override @property size_t tsize() nothrow pure
316- {
317- return T.sizeof;
318- }
319333
320- override @property size_t talign() nothrow pure
321- {
322- return T.alignof;
323- }
324-
325- override const (void )[] initializer () @trusted
326- {
327- static if (__traits(isZeroInit, T))
334+ static if (is (T == Base))
335+ override @property size_t tsize() nothrow pure
328336 {
329- return ( cast ( void * ) null )[ 0 .. T.sizeof] ;
337+ return T.sizeof;
330338 }
331- else
339+
340+ static if (is (T == Base))
341+ override @property size_t talign() nothrow pure
332342 {
333- static immutable T[1 ] c;
334- return c;
343+ return T.alignof;
335344 }
336- }
337345
338- override void swap (void * p1, void * p2)
339- {
340- auto t = * cast (T * ) p1;
341- * cast (T * )p1 = * cast (T * )p2;
342- * cast (T * )p2 = t;
343- }
344-
345- override @property immutable (void )* rtInfo() nothrow pure const @safe
346- {
347- return RTInfo ! T;
348- }
349-
350- static if (__traits(isFloating, T))
351- static if (is (immutable T == immutable real ) && T.mant_dig != 64 ) // exclude 80-bit X87
352- // passed in SIMD register
353- override @property uint flags() const { return 2 ; }
354- }
355-
356- /**
357- Type `T` has the same layout and alignment as type `Base`, but slightly different behavior.
358- Example: `float` and `ifloat` or `char` and `ubyte`.
359- We assume the two types hash the same, swap the same, have the same ABI flags, and compare the same for
360- equality. For ordering comparisons, we detect during compilation whether they have different min and max
361- values (e.g. signed vs. unsigned) and override appropriately. For initializer, we detect if we need to
362- override. The overriding initializer should be nonzero.
363- */
364- private class TypeInfoGeneric (T, Base) : TypeInfoGeneric !Base
365- if (T.sizeof == Base.sizeof && T.alignof == Base.alignof)
366- {
367- const : nothrow : pure : @trusted :
368- override string toString () { return T.stringof; }
369- static if (T.max != Base.max)
370- // Must override comparison, signedness is different
371- override int compare (in void * p1, in void * p2)
346+ // Override initializer only if necessary.
347+ static if (is (T == Base) || T.init != Base.init)
348+ override const (void )[] initializer () @trusted
372349 {
373- static if (T.sizeof < int .sizeof )
350+ static if (__traits(isZeroInit, T) )
374351 {
375- return * cast (T * )p1 - * cast (T * )p2 ;
352+ return ( cast (void * )null )[ 0 .. T.sizeof] ;
376353 }
377354 else
378355 {
379- if (* cast (T * )p1 < * cast (T * )p2)
380- return - 1 ;
381- if (* cast (T * )p1 > * cast (T * )p2)
382- return 1 ;
383- return 0 ;
356+ static immutable T[1 ] c;
357+ return c;
384358 }
385359 }
386- static if (T.init != Base.init)
387- // Must override initializer.
388- override const (void )[] initializer () @trusted
360+
361+ // `swap` is the same for `Base` and `T`, so introduce only once.
362+ static if (is (T == Base))
363+ override void swap (void * p1, void * p2)
364+ {
365+ auto t = * cast (T * ) p1;
366+ * cast (T * )p1 = * cast (T * )p2;
367+ * cast (T * )p2 = t;
368+ }
369+
370+ static if (is (T == Base) || RTInfo ! T != RTInfo ! Base)
371+ override @property immutable (void )* rtInfo() nothrow pure const @safe
389372 {
390- static assert (! __traits(isZeroInit, T), " Please inherit the other way" );
391- static immutable T[1 ] c;
392- return c;
373+ return RTInfo ! T;
393374 }
375+
376+ static if (is (T == Base) && __traits(isFloating, T))
377+ static if (is (immutable T == immutable real ) && T.mant_dig != 64 ) // exclude 80-bit X87
378+ // passed in SIMD register
379+ override @property uint flags() const { return 2 ; }
394380}
395381
396382unittest
0 commit comments