Last active
August 30, 2022 22:20
-
-
Save ryuukk/53c133f29da5a8326c359a6bb1063207 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module object; | |
alias size_t = typeof(int.sizeof); | |
alias ptrdiff_t = typeof(cast(void*)0 - cast(void*)0); | |
alias sizediff_t = ptrdiff_t; // For backwards compatibility only. | |
/** | |
* Bottom type. | |
* See $(DDSUBLINK spec/type, noreturn). | |
*/ | |
alias noreturn = typeof(*null); | |
alias hash_t = size_t; // For backwards compatibility only. | |
alias equals_t = bool; // For backwards compatibility only. | |
alias string = immutable(char)[]; | |
alias wstring = immutable(wchar)[]; | |
alias dstring = immutable(dchar)[]; | |
void fuck_you(){} | |
// version(Windows) | |
// { | |
// import core.sys.windows.windows; | |
// extern(C) int _Dmain(string[] args); | |
// extern (Windows) | |
// int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, | |
// LPSTR lpCmdLine, int nCmdShow) | |
// { | |
// int result; | |
// try | |
// { | |
// // Runtime.initialize(); | |
// result = myWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow); | |
// // Runtime.terminate(); | |
// } | |
// catch (Throwable e) | |
// { | |
// MessageBoxA(null, e.toString().toStringz(), null, | |
// MB_ICONEXCLAMATION); | |
// result = 0; // failed | |
// } | |
// return result; | |
// } | |
// int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, | |
// LPSTR lpCmdLine, int nCmdShow) | |
// { | |
// _Dmain(null); | |
// return 0; | |
// } | |
// } | |
struct Interface | |
{ | |
TypeInfo_Class classinfo; | |
void*[] vtbl; | |
size_t offset; | |
} | |
class Object | |
{ | |
/// Convert Object to human readable string | |
string toString() { return "Object"; } | |
/// Compute hash function for Object | |
size_t toHash() @trusted nothrow | |
{ | |
auto addr = cast(size_t)cast(void*)this; | |
return addr ^ (addr >>> 4); | |
} | |
/// Compare against another object. NOT IMPLEMENTED! | |
int opCmp(Object o) { assert(false, "not implemented"); } | |
/// Check equivalence againt another object | |
bool opEquals(Object o) { return this is o; } | |
} | |
/// Compare to objects | |
bool opEquals(Object lhs, Object rhs) | |
{ | |
// If aliased to the same object or both null => equal | |
if (lhs is rhs) return true; | |
// If either is null => non-equal | |
if (lhs is null || rhs is null) return false; | |
if (!lhs.opEquals(rhs)) return false; | |
// If same exact type => one call to method opEquals | |
if (typeid(lhs) is typeid(rhs) || | |
!__ctfe && typeid(lhs).opEquals(typeid(rhs))) | |
/* CTFE doesn't like typeid much. 'is' works, but opEquals doesn't | |
(issue 7147). But CTFE also guarantees that equal TypeInfos are | |
always identical. So, no opEquals needed during CTFE. */ | |
{ | |
return true; | |
} | |
// General case => symmetric calls to method opEquals | |
return rhs.opEquals(lhs); | |
} | |
/************************ | |
* Returns true if lhs and rhs are equal. | |
*/ | |
bool opEquals(const Object lhs, const Object rhs) | |
{ | |
// A hack for the moment. | |
return opEquals(cast()lhs, cast()rhs); | |
} | |
// fucks | |
bool __equals(T1, T2)(scope const T1[] lhs, scope const T2[] rhs) | |
@nogc nothrow pure @trusted | |
if (__traits(isScalar, T1) && __traits(isScalar, T2)) | |
{ | |
if (lhs.length != rhs.length) | |
return false; | |
static if (T1.sizeof == T2.sizeof | |
// Signedness needs to match for types that promote to int. | |
// (Actually it would be okay to memcmp bool[] and byte[] but that is | |
// probably too uncommon to be worth checking for.) | |
&& (T1.sizeof >= 4 || __traits(isUnsigned, T1) == __traits(isUnsigned, T2)) | |
&& !__traits(isFloating, T1) && !__traits(isFloating, T2)) | |
{ | |
if (!__ctfe) | |
{ | |
// This would improperly allow equality of integers and pointers | |
// but the CTFE branch will stop this function from compiling then. | |
import core.stdc.string : memcmp; | |
return lhs.length == 0 || | |
0 == memcmp(cast(const void*) lhs.ptr, cast(const void*) rhs.ptr, lhs.length * T1.sizeof); | |
} | |
} | |
foreach (const i; 0 .. lhs.length) | |
{ | |
static if (__traits(isStaticArray, at(lhs, 0))) // "Fix" for -betterC | |
{ | |
if (at(lhs, i)[] != at(rhs, i)[]) // T1[N] != T2[N] doesn't compile with -betterC. | |
return false; | |
} | |
else | |
{ | |
if (at(lhs, i) != at(rhs, i)) | |
return false; | |
} | |
} | |
return true; | |
} | |
bool __equals(T1, T2)(scope T1[] lhs, scope T2[] rhs) | |
if (!__traits(isScalar, T1) || !__traits(isScalar, T2)) | |
{ | |
if (lhs.length != rhs.length) | |
{ | |
return false; | |
} | |
if (lhs.length == 0) | |
return true; | |
static if (useMemcmp!(T1, T2)) | |
{ | |
if (!__ctfe) | |
{ | |
static bool trustedMemcmp(scope T1[] lhs, scope T2[] rhs) @trusted @nogc nothrow pure | |
{ | |
pragma(inline, true); | |
import core.stdc.string : memcmp; | |
return memcmp(cast(void*) lhs.ptr, cast(void*) rhs.ptr, lhs.length * T1.sizeof) == 0; | |
} | |
return trustedMemcmp(lhs, rhs); | |
} | |
else | |
{ | |
foreach (const i; 0 .. lhs.length) | |
{ | |
static if (__traits(isStaticArray, at(lhs, 0))) // "Fix" for -betterC | |
{ | |
if (at(lhs, i)[] != at(rhs, i)[]) // T1[N] != T2[N] doesn't compile with -betterC. | |
return false; | |
} | |
else | |
{ | |
if (at(lhs, i) != at(rhs, i)) | |
return false; | |
} | |
} | |
return true; | |
} | |
} | |
else | |
{ | |
foreach (const i; 0 .. lhs.length) | |
{ | |
static if (__traits(isStaticArray, at(lhs, 0))) // "Fix" for -betterC | |
{ | |
if (at(lhs, i)[] != at(rhs, i)[]) // T1[N] != T2[N] doesn't compile with -betterC. | |
return false; | |
} | |
else | |
{ | |
if (at(lhs, i) != at(rhs, i)) | |
return false; | |
} | |
} | |
return true; | |
} | |
} | |
pragma(inline, true) | |
ref at(T)(T[] r, size_t i) @trusted | |
// exclude opaque structs due to https://issues.dlang.org/show_bug.cgi?id=20959 | |
if (!(is(T == struct) && !is(typeof(T.sizeof)))) | |
{ | |
static if (is(immutable T == immutable void)) | |
return (cast(ubyte*) r.ptr)[i]; | |
else | |
return r.ptr[i]; | |
} | |
template BaseType(T) | |
{ | |
static if (__traits(isStaticArray, T)) | |
alias BaseType = BaseType!(typeof(T.init[0])); | |
else static if (is(immutable T == immutable void)) | |
alias BaseType = ubyte; | |
else static if (is(T == E*, E)) | |
alias BaseType = size_t; | |
else | |
alias BaseType = T; | |
} | |
template useMemcmp(T1, T2) | |
{ | |
static if (T1.sizeof != T2.sizeof) | |
enum useMemcmp = false; | |
else | |
{ | |
alias B1 = BaseType!T1; | |
alias B2 = BaseType!T2; | |
enum useMemcmp = __traits(isIntegral, B1) && __traits(isIntegral, B2) | |
&& !( (B1.sizeof < 4 || B2.sizeof < 4) && __traits(isUnsigned, B1) != __traits(isUnsigned, B2) ); | |
} | |
} | |
TTo[] __ArrayCast(TFrom, TTo)(return scope TFrom[] from) | |
{ | |
const fromSize = from.length * TFrom.sizeof; | |
const toLength = fromSize / TTo.sizeof; | |
if ((fromSize % TTo.sizeof) != 0) | |
{ | |
//onArrayCastError(TFrom.stringof, fromSize, TTo.stringof, toLength * TTo.sizeof); | |
assert(0); | |
} | |
struct Array | |
{ | |
size_t length; | |
void* ptr; | |
} | |
auto a = cast(Array*)&from; | |
a.length = toLength; // jam new length | |
return *cast(TTo[]*)a; | |
} | |
// switch | |
extern(C) void __switch_error()(string file = __FILE__, size_t line = __LINE__) | |
{ | |
//__switch_errorT(file, line); | |
// assert(0, "No appropriate switch clause found"); | |
} | |
extern(C) int __switch(T, caseLabels...)(/*in*/ const scope T[] condition) pure nothrow @safe @nogc | |
{ | |
// This closes recursion for other cases. | |
static if (caseLabels.length == 0) | |
{ | |
return int.min; | |
} | |
else static if (caseLabels.length == 1) | |
{ | |
return __cmp(condition, caseLabels[0]) == 0 ? 0 : int.min; | |
} | |
// To be adjusted after measurements | |
// Compile-time inlined binary search. | |
else static if (caseLabels.length < 7) | |
{ | |
int r = void; | |
enum mid = cast(int)caseLabels.length / 2; | |
if (condition.length == caseLabels[mid].length) | |
{ | |
r = __cmp(condition, caseLabels[mid]); | |
if (r == 0) return mid; | |
} | |
else | |
{ | |
// Equivalent to (but faster than) condition.length > caseLabels[$ / 2].length ? 1 : -1 | |
r = ((condition.length > caseLabels[mid].length) << 1) - 1; | |
} | |
if (r < 0) | |
{ | |
// Search the left side | |
return __switch!(T, caseLabels[0 .. mid])(condition); | |
} | |
else | |
{ | |
// Search the right side | |
return __switch!(T, caseLabels[mid + 1 .. $])(condition) + mid + 1; | |
} | |
} | |
else | |
{ | |
// Need immutable array to be accessible in pure code, but case labels are | |
// currently coerced to the switch condition type (e.g. const(char)[]). | |
pure @trusted nothrow @nogc asImmutable(scope const(T[])[] items) | |
{ | |
assert(__ctfe); // only @safe for CTFE | |
immutable T[][caseLabels.length] result = cast(immutable)(items[]); | |
return result; | |
} | |
static immutable T[][caseLabels.length] cases = asImmutable([caseLabels]); | |
// Run-time binary search in a static array of labels. | |
return __switchSearch!T(cases[], condition); | |
} | |
} | |
extern(C) int __cmp(T)(scope const T[] lhs, scope const T[] rhs) @trusted | |
if (__traits(isScalar, T)) | |
{ | |
// Compute U as the implementation type for T | |
static if (is(T == ubyte) || is(T == void) || is(T == bool)) | |
alias U = char; | |
else static if (is(T == wchar)) | |
alias U = ushort; | |
else static if (is(T == dchar)) | |
alias U = uint; | |
else static if (is(T == ifloat)) | |
alias U = float; | |
else static if (is(T == idouble)) | |
alias U = double; | |
else static if (is(T == ireal)) | |
alias U = real; | |
else | |
alias U = T; | |
static if (is(U == char)) | |
{ | |
import core.internal.string : dstrcmp; | |
return dstrcmp(cast(char[]) lhs, cast(char[]) rhs); | |
} | |
else static if (!is(U == T)) | |
{ | |
// Reuse another implementation | |
return __cmp(cast(U[]) lhs, cast(U[]) rhs); | |
} | |
else | |
{ | |
version (BigEndian) | |
static if (__traits(isUnsigned, T) ? !is(T == __vector) : is(T : P*, P)) | |
{ | |
if (!__ctfe) | |
{ | |
int c = mem.memcmp(lhs.ptr, rhs.ptr, (lhs.length <= rhs.length ? lhs.length : rhs.length) * T.sizeof); | |
if (c) | |
return c; | |
static if (size_t.sizeof <= uint.sizeof && T.sizeof >= 2) | |
return cast(int) lhs.length - cast(int) rhs.length; | |
else | |
return int(lhs.length > rhs.length) - int(lhs.length < rhs.length); | |
} | |
} | |
immutable len = lhs.length <= rhs.length ? lhs.length : rhs.length; | |
foreach (const u; 0 .. len) | |
{ | |
static if (__traits(isFloating, T)) | |
{ | |
immutable a = lhs.ptr[u], b = rhs.ptr[u]; | |
static if (is(T == cfloat) || is(T == cdouble) | |
|| is(T == creal)) | |
{ | |
// Use rt.cmath2._Ccmp instead ? | |
auto r = (a.re > b.re) - (a.re < b.re); | |
if (!r) r = (a.im > b.im) - (a.im < b.im); | |
} | |
else | |
{ | |
const r = (a > b) - (a < b); | |
} | |
if (r) return r; | |
} | |
else if (lhs.ptr[u] != rhs.ptr[u]) | |
return lhs.ptr[u] < rhs.ptr[u] ? -1 : 1; | |
} | |
return (lhs.length > rhs.length) - (lhs.length < rhs.length); | |
} | |
} | |
// This function is called by the compiler when dealing with array | |
// comparisons in the semantic analysis phase of CmpExp. The ordering | |
// comparison is lowered to a call to this template. | |
extern(C) int __cmp(T1, T2)(T1[] s1, T2[] s2) | |
if (!__traits(isScalar, T1) && !__traits(isScalar, T2)) | |
{ | |
alias U1 = Unqual!T1; | |
alias U2 = Unqual!T2; | |
static if (is(U1 == void) && is(U2 == void)) | |
static @trusted ref inout(ubyte) at(inout(void)[] r, size_t i) { return (cast(inout(ubyte)*) r.ptr)[i]; } | |
else | |
static @trusted ref R at(R)(R[] r, size_t i) { return r.ptr[i]; } | |
// All unsigned byte-wide types = > dstrcmp | |
immutable len = s1.length <= s2.length ? s1.length : s2.length; | |
foreach (const u; 0 .. len) | |
{ | |
static if (__traits(compiles, __cmp(at(s1, u), at(s2, u)))) | |
{ | |
auto c = __cmp(at(s1, u), at(s2, u)); | |
if (c != 0) | |
return c; | |
} | |
else static if (__traits(compiles, at(s1, u).opCmp(at(s2, u)))) | |
{ | |
auto c = at(s1, u).opCmp(at(s2, u)); | |
if (c != 0) | |
return c; | |
} | |
else static if (__traits(compiles, at(s1, u) < at(s2, u))) | |
{ | |
if (at(s1, u) != at(s2, u)) | |
return at(s1, u) < at(s2, u) ? -1 : 1; | |
} | |
else | |
{ | |
// TODO: fix this legacy bad behavior, see | |
// https://issues.dlang.org/show_bug.cgi?id=17244 | |
static assert(is(U1 == U2), "Internal error."); | |
auto c = (() @trusted => mem.memcmp(&at(s1, u), &at(s2, u), U1.sizeof))(); | |
if (c != 0) | |
return c; | |
} | |
} | |
return (s1.length > s2.length) - (s1.length < s2.length); | |
} | |
template Unqual(T : const U, U) | |
{ | |
static if (is(U == shared V, V)) | |
alias Unqual = V; | |
else | |
alias Unqual = U; | |
} | |
// binary search in sorted string cases, also see `__switch`. | |
private int __switchSearch(T)(/*in*/ const scope T[][] cases, /*in*/ const scope T[] condition) pure nothrow @safe @nogc | |
{ | |
size_t low = 0; | |
size_t high = cases.length; | |
do | |
{ | |
auto mid = (low + high) / 2; | |
int r = void; | |
if (condition.length == cases[mid].length) | |
{ | |
r = __cmp(condition, cases[mid]); | |
if (r == 0) return cast(int) mid; | |
} | |
else | |
{ | |
// Generates better code than "expr ? 1 : -1" on dmd and gdc, same with ldc | |
r = ((condition.length > cases[mid].length) << 1) - 1; | |
} | |
if (r > 0) low = mid + 1; | |
else high = mid; | |
} | |
while (low < high); | |
// Not found | |
return -1; | |
} | |
class TypeInfo | |
{ | |
const(TypeInfo) next() const | |
{ | |
return this; | |
} | |
size_t size() const | |
{ | |
return 1; | |
} | |
bool equals(void* a, void* b) | |
{ | |
return false; | |
} | |
int compare(in void* p1, in void* p2) const | |
{ | |
return 0; | |
} | |
void swap(void* p1, void* p2) const | |
{ | |
assert(0); | |
} | |
abstract const(void)[] initializer() nothrow pure const @safe @nogc; | |
} | |
class TypeInfo_Const : TypeInfo | |
{ | |
size_t getHash(in void*) nothrow | |
{ | |
return 0; | |
} | |
TypeInfo base; | |
override size_t size() const | |
{ | |
return base.size(); | |
} | |
override const(TypeInfo) next() const | |
{ | |
return base.next(); | |
} | |
override bool equals(void* p1, void* p2) | |
{ | |
return base.equals(p1, p2); | |
} | |
} | |
class TypeInfo_Pointer : TypeInfo | |
{ | |
TypeInfo m_next; | |
override size_t size() const | |
{ | |
return (void*).sizeof; | |
} | |
override bool equals(in void* p1, in void* p2) | |
{ | |
return *cast(void**) p1 == *cast(void**) p2; | |
} | |
override const(TypeInfo) next() const | |
{ | |
return m_next; | |
} | |
override const(void)[] initializer() const @trusted { return (cast(void *)null)[0 .. (void*).sizeof]; } | |
} | |
class TypeInfo_Array : TypeInfo | |
{ | |
TypeInfo value; | |
override size_t size() const | |
{ | |
return (void[]).sizeof; | |
} | |
override const(TypeInfo) next() const | |
{ | |
return value; | |
} | |
override bool equals(void* p1, void* p2) | |
{ | |
void[] a1 = *cast(void[]*) p1; | |
void[] a2 = *cast(void[]*) p2; | |
if (a1.length != a2.length) | |
return false; | |
size_t sz = value.size; | |
for (size_t i = 0; i < a1.length; i++) | |
{ | |
if (!value.equals(a1.ptr + i * sz, a2.ptr + i * sz)) | |
return false; | |
} | |
return true; | |
} | |
} | |
class TypeInfo_StaticArray : TypeInfo | |
{ | |
TypeInfo value; | |
size_t len; | |
override size_t size() const | |
{ | |
return value.size() * len; | |
} | |
override const(TypeInfo) next() const | |
{ | |
return value; | |
} | |
override bool equals(void* p1, void* p2) | |
{ | |
size_t sz = value.size; | |
for (size_t u = 0; u < len; u++) | |
{ | |
if (!value.equals(p1 + u * sz, p2 + u * sz)) | |
return false; | |
} | |
return true; | |
} | |
} | |
class TypeInfo_Enum : TypeInfo | |
{ | |
TypeInfo base; | |
string name; | |
void[] m_init; | |
override bool equals(void* p1, void* p2) | |
{ | |
return base.equals(p1, p2); | |
} | |
override size_t size() const | |
{ | |
return base.size(); | |
} | |
override const(TypeInfo) next() const | |
{ | |
return base.next(); | |
} | |
} | |
class TypeInfo_Function : TypeInfo | |
{ | |
TypeInfo next; | |
string deco; | |
override size_t size() const | |
{ | |
return 0; | |
} | |
} | |
class TypeInfo_Struct : TypeInfo | |
{ | |
string name; | |
void[] m_init; | |
void* xtohash; | |
bool function(in void*, in void*) xopEquals; | |
int function(in void*, in void*) xopCmp; | |
void* xtostring; | |
uint flags; | |
union | |
{ | |
void function(void*) dtor; | |
void function(void*, const TypeInfo_Struct) xdtor; | |
} | |
void function(void*) postblit; | |
uint align_; | |
version (DigitalMars) | |
{ | |
// override int argTypes(out TypeInfo arg1, out TypeInfo arg2) | |
// { | |
// arg1 = m_arg1; | |
// arg2 = m_arg2; | |
// return 0; | |
// } | |
TypeInfo m_arg1; | |
TypeInfo m_arg2; | |
} | |
immutable(void)* rtinfo; | |
override size_t size() const | |
{ | |
return m_init.length; | |
} | |
override bool equals(in void* p1, in void* p2) | |
{ | |
if (!p1 || !p2) | |
return false; | |
else if (xopEquals) | |
return (*xopEquals)(p1, p2); | |
else if (p1 == p2) | |
return true; | |
else | |
{ | |
assert(0); | |
// BUG: relies on the GC not moving objects | |
// return mem.memcmp(p1, p2, m_init.length) == 0; | |
} | |
} | |
} | |
class TypeInfo_Class : TypeInfo | |
{ | |
ubyte[] m_init; | |
string name; | |
void*[] vtbl; | |
Interface*[] interfaces; | |
TypeInfo_Class base; | |
void* dtor; | |
void function(Object) ci; | |
uint flags; | |
void* deallocator; | |
void*[] offti; | |
void function(Object) dctor; | |
immutable(void)* rtInfo; | |
override size_t size() const | |
{ | |
return size_t.sizeof; | |
} | |
override bool equals(in void* p1, in void* p2) const | |
{ | |
Object o1 = *cast(Object*)p1; | |
Object o2 = *cast(Object*)p2; | |
return (o1 is o2) || (o1 && o1.opEquals(o2)); | |
} | |
override const(void)[] initializer() nothrow pure const @safe | |
{ | |
return m_init; | |
} | |
} | |
class TypeInfo_Delegate : TypeInfo | |
{ | |
TypeInfo next; | |
string deco; | |
override size_t size() const | |
{ | |
alias dg = int delegate(); | |
return dg.sizeof; | |
} | |
override bool equals(in void* p1, in void* p2) | |
{ | |
auto dg1 = *cast(void delegate()*) p1; | |
auto dg2 = *cast(void delegate()*) p2; | |
return dg1 == dg2; | |
} | |
} | |
class TypeInfo_Tuple : TypeInfo | |
{ | |
TypeInfo[] elements; | |
override size_t size() const | |
{ | |
assert(0); | |
} | |
override bool equals(in void* p1, in void* p2) | |
{ | |
assert(0); | |
} | |
} | |
class TypeInfo_Invariant : TypeInfo | |
{ | |
size_t getHash(in void*) nothrow | |
{ | |
return 0; | |
} | |
TypeInfo base; | |
override size_t size() const | |
{ | |
return base.size; | |
} | |
override const(TypeInfo) next() const | |
{ | |
return base; | |
} | |
} | |
class TypeInfo_Shared : TypeInfo | |
{ | |
size_t getHash(in void*) nothrow | |
{ | |
return 0; | |
} | |
TypeInfo base; | |
override size_t size() const | |
{ | |
return base.size; | |
} | |
override const(TypeInfo) next() const | |
{ | |
return base; | |
} | |
} | |
class TypeInfo_Inout : TypeInfo | |
{ | |
size_t getHash(in void*) nothrow | |
{ | |
return 0; | |
} | |
TypeInfo base; | |
override size_t size() const | |
{ | |
return base.size; | |
} | |
override const(TypeInfo) next() const | |
{ | |
return base; | |
} | |
} | |
class TypeInfo_Interface : TypeInfo | |
{ | |
TypeInfo_Class info; | |
override bool equals(in void* p1, in void* p2) const | |
{ | |
Interface* pi = **cast(Interface ***)*cast(void**)p1; | |
Object o1 = cast(Object)(*cast(void**)p1 - pi.offset); | |
pi = **cast(Interface ***)*cast(void**)p2; | |
Object o2 = cast(Object)(*cast(void**)p2 - pi.offset); | |
return o1 == o2 || (o1 && o1.opCmp(o2) == 0); | |
} | |
override const(void)[] initializer() const @trusted | |
{ | |
return (cast(void *)null)[0 .. Object.sizeof]; | |
} | |
override @property size_t size() nothrow pure const | |
{ | |
return Object.sizeof; | |
} | |
} | |
extern(C) bool _xopEquals(in void*, in void*) | |
{ | |
assert(0, "not implemented"); | |
} | |
extern(C) bool _xopCmp(in void*, in void*) | |
{ | |
assert(0, "not implemented"); | |
//return false; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment