Files
xomb-bare-bones/kernel/runtime/dstubs.d

1015 lines
22 KiB
D

// This is the stubbed out runtime for D.
// It is magical and full of nondescriptive mystical creatures.
module kernel.core.dstubs;
// some utility functions and routines for the runtime
import kernel.runtime.util;
// for printing out runtime errors
import kernel.core.kprintf;
// magical gcc business (BEWARE THE MAGICAL EMPTY FILE!!!)
static import gcc.builtins;
extern(C)
{
alias gcc.builtins.__builtin_alloca alloca;
private
{
struct Array
{
size_t length;
byte *data;
}
struct aaA
{
aaA *left;
aaA *right;
hash_t hash;
/* key */
/* value */
}
struct BB
{
aaA*[] b;
size_t nodes;
}
struct AA
{
BB* a;
}
alias long ArrayRet_t;
extern(D) typedef int delegate(void *) aa_dg_t;
extern(D) typedef int delegate(void *, void *) aa_dg2_t;
extern(D) typedef int delegate(void *) array_dg_t;
extern(D) typedef int delegate(void *, void *) array_dg2_t;
enum BlkAttr : uint
{
FINALIZE = 0b0000_0001,
NO_SCAN = 0b0000_0010,
NO_MOVE = 0b0000_0100,
ALL_BITS = 0b1111_1111
}
template Stub(char[] signature)
{
const char[] Stub = signature ~ " { assert(false, \"Undefined runtime stub executed: " ~ signature ~ "\"); }";
}
}
/**************************************************
Random stubs (they'll go somewhere eventually)
**************************************************/
mixin(Stub!("void abort()"));
mixin(Stub!("bool rt_isHalting()"));
mixin(Stub!("bool runModuleUnitTests()"));
mixin(Stub!("void _d_monitordelete(Object h, bool det = true)"));
/******************************************
* Given a pointer:
* If it is an Object, return that Object.
* If it is an interface, return the Object implementing the interface.
* If it is null, return null.
* Else, undefined crash
*/
Object _d_toObject(void* p)
{ Object o;
if (p)
{
o = cast(Object)p;
ClassInfo oc = o.classinfo;
Interface *pi = **cast(Interface ***)p;
/* Interface.offset lines up with ClassInfo.name.ptr,
* so we rely on pointers never being less than 64K,
* and Objects never being greater.
*/
if (pi.offset < 0x10000)
{
//printf("\tpi.offset = %d\n", pi.offset);
o = cast(Object)(p - pi.offset);
}
}
return o;
}
/*************************************
* Attempts to cast Object o to class c.
* Returns o if successful, null if not.
*/
Object _d_interface_cast(void* p, ClassInfo c)
{ Object o;
//printf("_d_interface_cast(p = %p, c = '%.*s')\n", p, c.name);
if (p)
{
Interface *pi = **cast(Interface ***)p;
//printf("\tpi.offset = %d\n", pi.offset);
o = cast(Object)(p - pi.offset);
return _d_dynamic_cast(o, c);
}
return o;
}
Object _d_dynamic_cast(Object o, ClassInfo c)
{ ClassInfo oc;
size_t offset = 0;
//printf("_d_dynamic_cast(o = %p, c = '%.*s')\n", o, c.name);
if (o)
{
oc = o.classinfo;
if (_d_isbaseof2(oc, c, offset))
{
//printf("\toffset = %d\n", offset);
o = cast(Object)(cast(void*)o + offset);
}
else
o = null;
}
//printf("\tresult = %p\n", o);
return o;
}
int _d_isbaseof2(ClassInfo oc, ClassInfo c, inout size_t offset)
{ int i;
if (oc is c)
return 1;
do
{
if (oc.base is c)
return 1;
for (i = 0; i < oc.interfaces.length; i++)
{
ClassInfo ic;
ic = oc.interfaces[i].classinfo;
if (ic is c)
{ offset = oc.interfaces[i].offset;
return 1;
}
}
for (i = 0; i < oc.interfaces.length; i++)
{
ClassInfo ic;
ic = oc.interfaces[i].classinfo;
if (_d_isbaseof2(ic, c, offset))
{ offset = oc.interfaces[i].offset;
return 1;
}
}
oc = oc.base;
} while (oc);
return 0;
}
int _d_isbaseof(ClassInfo oc, ClassInfo c)
{ int i;
if (oc is c)
return 1;
do
{
if (oc.base is c)
return 1;
for (i = 0; i < oc.interfaces.length; i++)
{
ClassInfo ic;
ic = oc.interfaces[i].classinfo;
if (ic is c || _d_isbaseof(ic, c))
return 1;
}
oc = oc.base;
} while (oc);
return 0;
}
/*********************************
* Find the vtbl[] associated with Interface ic.
*/
void *_d_interface_vtbl(ClassInfo ic, Object o)
{ int i;
ClassInfo oc;
//printf("__d_interface_vtbl(o = %p, ic = %p)\n", o, ic);
assert(o);
oc = o.classinfo;
for (i = 0; i < oc.interfaces.length; i++)
{
ClassInfo oic;
oic = oc.interfaces[i].classinfo;
if (oic is ic)
{
return cast(void *)oc.interfaces[i].vtbl;
}
}
assert(0);
}
int _d_obj_eq(Object o1, Object o2)
{
return o1 is o2 || (o1 && o1.opEquals(o2));
}
int _d_obj_cmp(Object o1, Object o2)
{
return o1.opCmp(o2);
}
int _d_switch_string(char[][] table, char[] ca)
{
int low;
int high;
int mid;
int c;
char[] pca;
low = 0;
high = table.length;
if (high &&
ca.length >= table[0].length &&
ca.length <= table[high - 1].length)
{
// Looking for 0 length string, which would only be at the beginning
if (ca.length == 0)
return 0;
char c1 = ca[0];
// Do binary search
while (low < high)
{
mid = (low + high) >> 1;
pca = table[mid];
c = ca.length - pca.length;
if (c == 0)
{
c = cast(ubyte)c1 - cast(ubyte)pca[0];
if (c == 0)
{
c = memcmp(ca.ptr, pca.ptr, ca.length);
if (c == 0)
{
return mid;
}
}
}
if (c < 0)
{
high = mid;
}
else
{
low = mid + 1;
}
}
}
return -1; // not found
}
int _d_switch_ustring(wchar[][] table, wchar[] ca)
{
int low;
int high;
int mid;
int c;
wchar[] pca;
low = 0;
high = table.length;
// Do binary search
while (low < high)
{
mid = (low + high) >> 1;
pca = table[mid];
c = ca.length - pca.length;
if (c == 0)
{
c = memcmp(ca.ptr, pca.ptr, ca.length * wchar.sizeof);
if (c == 0)
{
return mid;
}
}
if (c < 0)
{
high = mid;
}
else
{
low = mid + 1;
}
}
return -1; // not found
}
int _d_switch_dstring(dchar[][] table, dchar[] ca)
{
int low;
int high;
int mid;
int c;
dchar[] pca;
low = 0;
high = table.length;
// Do binary search
while (low < high)
{
mid = (low + high) >> 1;
pca = table[mid];
c = ca.length - pca.length;
if (c == 0)
{
c = memcmp(ca.ptr, pca.ptr, ca.length * dchar.sizeof);
if (c == 0)
{
return mid;
}
}
if (c < 0)
{
high = mid;
}
else
{
low = mid + 1;
}
}
return -1; // not found
}
/**************************************************
Lifetime stubs
**************************************************/
mixin(Stub!("Object _d_newclass(ClassInfo ci)"));
mixin(Stub!("void _d_delinterface(void** p)"));
mixin(Stub!("void _d_delclass(Object* p)"));
mixin(Stub!("Array _d_newarrayT(TypeInfo ti, size_t length)"));
mixin(Stub!("Array _d_newarrayiT(TypeInfo ti, size_t length)"));
mixin(Stub!("void[] _d_newarraymTp(TypeInfo ti, int ndims, size_t* pdim)"));
mixin(Stub!("void[] _d_newarraymiTp(TypeInfo ti, int ndims, size_t* pdim)"));
mixin(Stub!("void _d_delarray(Array *p)"));
mixin(Stub!("void _d_delmemory(void* *p)"));
mixin(Stub!("void _d_callfinalizer(void* p)"));
mixin(Stub!("void rt_finalize(void* p, bool det = true)"));
mixin(Stub!("byte[] _d_arraysetlengthT(TypeInfo ti, size_t newlength, Array *p)"));
mixin(Stub!("byte[] _d_arraysetlengthiT(TypeInfo ti, size_t newlength, Array *p)"));
mixin(Stub!("Array _d_arrayappendT(TypeInfo ti, Array *px, byte[] y)"));
mixin(Stub!("byte[] _d_arrayappendcTp(TypeInfo ti, inout byte[] x, void *argp)"));
mixin(Stub!("byte[] _d_arraycatT(TypeInfo ti, byte[] x, byte[] y)"));
mixin(Stub!("byte[] _d_arraycatnT(TypeInfo ti, uint n, ...)"));
mixin(Stub!("Array _adDupT(TypeInfo ti, Array a)"));
/**************************************************
GC stubs
**************************************************/
mixin(Stub!("void gc_init()"));
mixin(Stub!("void gc_term()"));
mixin(Stub!("void gc_enable()"));
mixin(Stub!("void gc_disable()"));
mixin(Stub!("void gc_collect()"));
mixin(Stub!("uint gc_getAttr( void* p )"));
mixin(Stub!("uint gc_setAttr( void* p, uint a )"));
mixin(Stub!("uint gc_clrAttr( void* p, uint a )"));
mixin(Stub!("void* gc_malloc( size_t sz, uint ba = 0 )"));
mixin(Stub!("void* gc_calloc( size_t sz, uint ba = 0 )"));
mixin(Stub!("void* gc_realloc( void* p, size_t sz, uint ba = 0 )"));
mixin(Stub!("size_t gc_extend( void* p, size_t mx, size_t sz )"));
mixin(Stub!("void gc_free( void* p )"));
mixin(Stub!("size_t gc_sizeOf( void* p )"));
mixin(Stub!("void gc_addRoot( void* p )"));
mixin(Stub!("void gc_addRange( void* p, size_t sz )"));
mixin(Stub!("void gc_removeRoot( void *p )"));
mixin(Stub!("void gc_removeRange( void *p )"));
mixin(Stub!("bool onCollectResource( Object obj )"));
/**************************************************
Exception stubs
**************************************************/
void _d_assert( char[] file, uint line )
{
onAssertError( file, line );
}
void _d_assert_msg( char[] msg, char[] file, uint line )
{
onAssertErrorMsg( file, line, msg );
}
void _d_array_bounds( char[] file, uint line )
{
onArrayBoundsError( file, line );
}
void _d_switch_error( char[] file, uint line )
{
onSwitchError( file, line );
}
private void onAssertError(char[] file, size_t line)
{
kprintfln!("Error in {}, line {}: assertion failed.")(file, line);
asm { l: hlt; jmp l; }
}
private void onAssertErrorMsg(char[] file, size_t line, char[] msg)
{
kprintfln!("Error in {}, line {}: assertion failed: \"{}\"")(file, line, msg);
asm { l: hlt; jmp l; }
}
private void onArrayBoundsError(char[] file, size_t line)
{
kprintfln!("Error in {}, line {}: array index out of bounds.")(file, line);
asm { l: hlt; jmp l; }
}
private void onSwitchError(char[] file, size_t line)
{
kprintfln!("Error in {}, line {}: switch has no case or default to handle the switched-upon value.")(file, line);
asm { l: hlt; jmp l; }
}
mixin(Stub!("void onFinalizeError( ClassInfo info, Exception ex )"));
mixin(Stub!("void onOutOfMemoryError()"));
mixin(Stub!("void onUnicodeError( char[] msg, size_t idx )"));
/**************************************************
DEH and Unwind stubs
**************************************************/
mixin(Stub!("void _gdc_cleanupException()"));
mixin(Stub!("void _d_throw(Object obj)"));
mixin(Stub!("int __gdc_personality_v0()"));
mixin(Stub!("void _Unwind_RaiseException ()"));
mixin(Stub!("void _Unwind_ForcedUnwind ()"));
mixin(Stub!("void _Unwind_DeleteException ()"));
mixin(Stub!("void _Unwind_Resume()"));
mixin(Stub!("void _Unwind_Resume_or_Rethrow ()"));
mixin(Stub!("void _Unwind_Backtrace ()"));
mixin(Stub!("void _Unwind_GetGR ()"));
mixin(Stub!("void _Unwind_SetGR ()"));
mixin(Stub!("void _Unwind_GetIP ()"));
mixin(Stub!("void _Unwind_SetIP ()"));
mixin(Stub!("void _Unwind_GetCFA ()"));
mixin(Stub!("void *_Unwind_GetLanguageSpecificData ()"));
mixin(Stub!("void _Unwind_GetRegionStart ()"));
mixin(Stub!("void _Unwind_SjLj_RaiseException()"));
mixin(Stub!("void _Unwind_SjLj_ForcedUnwind()"));
mixin(Stub!("void _Unwind_SjLj_Resume ()"));
mixin(Stub!("void _Unwind_GetDataRelBase ()"));
mixin(Stub!("void _Unwind_GetTextRelBase ()"));
mixin(Stub!("uint size_of_encoded_value (ubyte encoding)"));
mixin(Stub!("void base_of_encoded_value ()"));
mixin(Stub!("void read_uleb128()"));
mixin(Stub!("void read_sleb128()"));
mixin(Stub!("void read_encoded_value_with_base()"));
mixin(Stub!("void read_encoded_value()"));
/**************************************************
AA stubs
**************************************************/
mixin(Stub!("size_t _aaLen(AA aa)"));
mixin(Stub!("void *_aaGetp(AA* aa, TypeInfo keyti, size_t valuesize, void *pkey)"));
mixin(Stub!("void *_aaGetRvaluep(AA aa, TypeInfo keyti, size_t valuesize, void *pkey)"));
mixin(Stub!("void* _aaInp(AA aa, TypeInfo keyti, void *pkey)"));
mixin(Stub!("void _aaDelp(AA aa, TypeInfo keyti, void *pkey)"));
mixin(Stub!("Array _aaValues(AA aa, size_t keysize, size_t valuesize)"));
mixin(Stub!("AA _aaRehash(AA* paa, TypeInfo keyti)"));
mixin(Stub!("Array _aaKeys(AA aa, size_t keysize)"));
mixin(Stub!("int _aaApply(AA aa, size_t keysize, aa_dg_t dg)"));
mixin(Stub!("int _aaApply2(AA aa, size_t keysize, aa_dg2_t dg)"));
mixin(Stub!("BB* _d_assocarrayliteralTp(TypeInfo_AssociativeArray ti, size_t length, void *keys, void *values)"));
/**************************************************
Array stubs
**************************************************/
mixin(Stub!("int _aApplycw1(char[] aa, array_dg_t dg)"));
mixin(Stub!("int _aApplycd1(char[] aa, array_dg_t dg)"));
mixin(Stub!("int _aApplywc1(wchar[] aa, array_dg_t dg)"));
mixin(Stub!("int _aApplywd1(wchar[] aa, array_dg_t dg)"));
mixin(Stub!("int _aApplydc1(dchar[] aa, array_dg_t dg)"));
mixin(Stub!("int _aApplydw1(dchar[] aa, array_dg_t dg)"));
mixin(Stub!("int _aApplycw2(char[] aa, array_dg2_t dg)"));
mixin(Stub!("int _aApplycd2(char[] aa, array_dg2_t dg)"));
mixin(Stub!("int _aApplywc2(wchar[] aa, array_dg2_t dg)"));
mixin(Stub!("int _aApplywd2(wchar[] aa, array_dg2_t dg)"));
mixin(Stub!("int _aApplydc2(dchar[] aa, array_dg2_t dg)"));
mixin(Stub!("int _aApplydw2(dchar[] aa, array_dg2_t dg)"));
mixin(Stub!("int _aApplyRcw1(char[] aa, array_dg_t dg)"));
mixin(Stub!("int _aApplyRcd1(char[] aa, array_dg_t dg)"));
mixin(Stub!("int _aApplyRwc1(wchar[] aa, array_dg_t dg)"));
mixin(Stub!("int _aApplyRwd1(wchar[] aa, array_dg_t dg)"));
mixin(Stub!("int _aApplyRdc1(dchar[] aa, array_dg_t dg)"));
mixin(Stub!("int _aApplyRdw1(dchar[] aa, array_dg_t dg)"));
mixin(Stub!("int _aApplyRcw2(char[] aa, array_dg2_t dg)"));
mixin(Stub!("int _aApplyRcd2(char[] aa, array_dg2_t dg)"));
mixin(Stub!("int _aApplyRwc2(wchar[] aa, array_dg2_t dg)"));
mixin(Stub!("int _aApplyRwd2(wchar[] aa, array_dg2_t dg)"));
mixin(Stub!("int _aApplyRdc2(dchar[] aa, array_dg2_t dg)"));
mixin(Stub!("int _aApplyRdw2(dchar[] aa, array_dg2_t dg)"));
mixin(Stub!("char[] _adSortChar(char[] a)"));
mixin(Stub!("wchar[] _adSortWchar(wchar[] a)"));
const ubyte[256] UTF8stride =
[
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
4,4,4,4,4,4,4,4,5,5,5,5,6,6,0xFF,0xFF,
];
Array _adReverseChar(char[] a)
{
if(a.length > 1)
{
char[6] tmp;
char[6] tmplo;
char* lo = a.ptr;
char* hi = &a[length - 1];
while (lo < hi)
{ auto clo = *lo;
auto chi = *hi;
if (clo <= 0x7F && chi <= 0x7F)
{
*lo = chi;
*hi = clo;
lo++;
hi--;
continue;
}
uint stridelo = UTF8stride[clo];
uint stridehi = 1;
while ((chi & 0xC0) == 0x80)
{
chi = *--hi;
stridehi++;
assert(hi >= lo);
}
if (lo == hi)
break;
if (stridelo == stridehi)
{
memcpy(tmp.ptr, lo, stridelo);
memcpy(lo, hi, stridelo);
memcpy(hi, tmp.ptr, stridelo);
lo += stridelo;
hi--;
continue;
}
/* Shift the whole array. This is woefully inefficient
*/
memcpy(tmp.ptr, hi, stridehi);
memcpy(tmplo.ptr, lo, stridelo);
memmove(lo + stridehi, lo + stridelo , (hi - lo) - stridelo);
memcpy(lo, tmp.ptr, stridehi);
memcpy(hi + cast(int) stridehi - cast(int) stridelo, tmplo.ptr, stridelo);
lo += stridehi;
hi = hi - 1 + (cast(int) stridehi - cast(int) stridelo);
}
}
Array aaa = *cast(Array*)(&a);
return aaa;
}
Array _adReverseWchar(wchar[] a)
{
if (a.length > 1)
{
wchar[2] tmp;
wchar* lo = a.ptr;
wchar* hi = &a[length - 1];
while (lo < hi)
{ auto clo = *lo;
auto chi = *hi;
if ((clo < 0xD800 || clo > 0xDFFF) &&
(chi < 0xD800 || chi > 0xDFFF))
{
*lo = chi;
*hi = clo;
lo++;
hi--;
continue;
}
int stridelo = 1 + (clo >= 0xD800 && clo <= 0xDBFF);
int stridehi = 1;
if (chi >= 0xDC00 && chi <= 0xDFFF)
{
chi = *--hi;
stridehi++;
assert(hi >= lo);
}
if (lo == hi)
break;
if (stridelo == stridehi)
{ int stmp;
assert(stridelo == 2);
assert(stmp.sizeof == 2 * (*lo).sizeof);
stmp = *cast(int*)lo;
*cast(int*)lo = *cast(int*)hi;
*cast(int*)hi = stmp;
lo += stridelo;
hi--;
continue;
}
/* Shift the whole array. This is woefully inefficient
*/
memcpy(tmp.ptr, hi, stridehi * wchar.sizeof);
memcpy(hi + cast(int) stridehi - cast(int) stridelo, lo, stridelo * wchar.sizeof);
memmove(lo + stridehi, lo + stridelo , (hi - (lo + stridelo)) * wchar.sizeof);
memcpy(lo, tmp.ptr, stridehi * wchar.sizeof);
lo += stridehi;
hi = hi - 1 + (cast(int) stridehi - cast(int) stridelo);
}
}
Array aaa = *cast(Array*)(&a);
return aaa;
}
int _adCmpChar(Array a1, Array a2)
{
version (Asm86)
{
asm
{ naked ;
push EDI ;
push ESI ;
mov ESI,a1+4[4+ESP] ;
mov EDI,a2+4[4+ESP] ;
mov ECX,a1[4+ESP] ;
mov EDX,a2[4+ESP] ;
cmp ECX,EDX ;
jb GotLength ;
mov ECX,EDX ;
GotLength:
cmp ECX,4 ;
jb DoBytes ;
// Do alignment if neither is dword aligned
test ESI,3 ;
jz Aligned ;
test EDI,3 ;
jz Aligned ;
DoAlign:
mov AL,[ESI] ; //align ESI to dword bounds
mov DL,[EDI] ;
cmp AL,DL ;
jnz Unequal ;
inc ESI ;
inc EDI ;
test ESI,3 ;
lea ECX,[ECX-1] ;
jnz DoAlign ;
Aligned:
mov EAX,ECX ;
// do multiple of 4 bytes at a time
shr ECX,2 ;
jz TryOdd ;
repe ;
cmpsd ;
jnz UnequalQuad ;
TryOdd:
mov ECX,EAX ;
DoBytes:
// if still equal and not end of string, do up to 3 bytes slightly
// slower.
and ECX,3 ;
jz Equal ;
repe ;
cmpsb ;
jnz Unequal ;
Equal:
mov EAX,a1[4+ESP] ;
mov EDX,a2[4+ESP] ;
sub EAX,EDX ;
pop ESI ;
pop EDI ;
ret ;
UnequalQuad:
mov EDX,[EDI-4] ;
mov EAX,[ESI-4] ;
cmp AL,DL ;
jnz Unequal ;
cmp AH,DH ;
jnz Unequal ;
shr EAX,16 ;
shr EDX,16 ;
cmp AL,DL ;
jnz Unequal ;
cmp AH,DH ;
Unequal:
sbb EAX,EAX ;
pop ESI ;
or EAX,1 ;
pop EDI ;
ret ;
}
}
else
{
int len;
int c;
len = a1.length;
if (a2.length < len)
len = a2.length;
c = memcmp(cast(char *)a1.data, cast(char *)a2.data, len);
if (!c)
c = cast(int)a1.length - cast(int)a2.length;
return c;
}
}
Array _adReverse(Array a, size_t szelem)
{
if (a.length >= 2)
{
byte* tmp;
byte[16] buffer;
void* lo = a.data;
void* hi = a.data + (a.length - 1) * szelem;
tmp = buffer.ptr;
if (szelem > 16)
tmp = cast(byte*)alloca(szelem);
for (; lo < hi; lo += szelem, hi -= szelem)
{
memcpy(tmp, lo, szelem);
memcpy(lo, hi, szelem);
memcpy(hi, tmp, szelem);
}
}
return a;
}
int _adEq(Array a1, Array a2, TypeInfo ti)
{
if(a1.length != a2.length)
return 0; // not equal
auto sz = ti.tsize();
auto p1 = a1.data;
auto p2 = a2.data;
if(sz == 1)
// We should really have a ti.isPOD() check for this
return (memcmp(p1, p2, a1.length) == 0);
for(size_t i = 0; i < a1.length; i++)
{
if(!ti.equals(p1 + i * sz, p2 + i * sz))
return 0; // not equal
}
return 1; // equal
}
int _adCmp(Array a1, Array a2, TypeInfo ti)
{
//printf("adCmp()\n");
auto len = a1.length;
if (a2.length < len)
len = a2.length;
auto sz = ti.tsize();
void *p1 = a1.data;
void *p2 = a2.data;
if (sz == 1)
{ // We should really have a ti.isPOD() check for this
auto c = memcmp(p1, p2, len);
if (c)
return c;
}
else
{
for (size_t i = 0; i < len; i++)
{
auto c = ti.compare(p1 + i * sz, p2 + i * sz);
if (c)
return c;
}
}
if (a1.length == a2.length)
return 0;
return (a1.length > a2.length) ? 1 : -1;
}
Array _adSort(Array a, TypeInfo ti)
{
static const uint Qsort_Threshold = 7;
struct StackEntry {
byte *l;
byte *r;
}
size_t elem_size = ti.tsize();
size_t qsort_limit = elem_size * Qsort_Threshold;
static assert(ubyte.sizeof == 1);
static assert(ubyte.max == 255);
StackEntry[size_t.sizeof * 8] stack; // log2( size_t.max )
StackEntry * sp = stack.ptr;
byte* lbound = cast(byte *) a.data;
byte* rbound = cast(byte *) a.data + a.length * elem_size;
byte* li = void;
byte* ri = void;
while (1)
{
if (rbound - lbound > qsort_limit)
{
ti.swap(lbound,
lbound + (
((rbound - lbound) >>> 1) -
(((rbound - lbound) >>> 1) % elem_size)
));
li = lbound + elem_size;
ri = rbound - elem_size;
if (ti.compare(li, ri) > 0)
ti.swap(li, ri);
if (ti.compare(lbound, ri) > 0)
ti.swap(lbound, ri);
if (ti.compare(li, lbound) > 0)
ti.swap(li, lbound);
while (1)
{
do
li += elem_size;
while (ti.compare(li, lbound) < 0);
do
ri -= elem_size;
while (ti.compare(ri, lbound) > 0);
if (li > ri)
break;
ti.swap(li, ri);
}
ti.swap(lbound, ri);
if (ri - lbound > rbound - li)
{
sp.l = lbound;
sp.r = ri;
lbound = li;
}
else
{
sp.l = li;
sp.r = rbound;
rbound = ri;
}
++sp;
} else {
// Use insertion sort
for (ri = lbound, li = lbound + elem_size;
li < rbound;
ri = li, li += elem_size)
{
for ( ; ti.compare(ri, ri + elem_size) > 0;
ri -= elem_size)
{
ti.swap(ri, ri + elem_size);
if (ri == lbound)
break;
}
}
if (sp != stack.ptr)
{
--sp;
lbound = sp.l;
rbound = sp.r;
}
else
return a;
}
}
}
void[] _d_arraycast(size_t tsize, size_t fsize, void[] a)
{
auto length = a.length;
auto nbytes = length * fsize;
if(nbytes % tsize != 0)
throw new Exception("array cast misalignment");
length = nbytes / tsize;
*cast(size_t *)&a = length; // jam new length
return a;
}
byte[] _d_arraycopy(size_t size, byte[] from, byte[] to)
{
if(to.length != from.length)
throw new Exception("lengths don't match for array copy");
else if(cast(byte *)to + to.length * size <= cast(byte *)from || cast(byte *)from + from.length * size <= cast(byte *)to)
memcpy(cast(byte *)to, cast(byte *)from, to.length * size);
else
throw new Exception("overlapping array copy");
return to;
}
}