Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.
/ druntime Public archive

Commit 48a4570

Browse files
committed
Consolidate versions of TypeInfoGeneric
1 parent b835543 commit 48a4570

File tree

1 file changed

+81
-95
lines changed

1 file changed

+81
-95
lines changed

src/rt/util/typeinfo.d

Lines changed: 81 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -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
/**
271277
TypeInfo 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

396382
unittest

0 commit comments

Comments
 (0)