Added copy of druntime from DMD 2.020 modified for LDC.

This commit is contained in:
Tomas Lindquist Olsen
2008-11-11 01:52:37 +01:00
parent c4c1c1d72e
commit d56f952a84
175 changed files with 48069 additions and 0 deletions

View File

@@ -0,0 +1,408 @@
/**
* Part of the D programming language runtime library.
*/
/*
* Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
* Written by Walter Bright
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, in both source and binary form, subject to the following
* restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
/*
* Modified by Sean Kelly for use with the D Runtime Project
*/
module rt.aApply;
/* This code handles decoding UTF strings for foreach loops.
* There are 6 combinations of conversions between char, wchar,
* and dchar, and 2 of each of those.
*/
private import util.utf;
/**********************************************
*/
// dg is D, but _aApplycd() is C
extern (D) typedef int delegate(void *) dg_t;
extern (C) int _aApplycd1(char[] aa, dg_t dg)
{ int result;
size_t i;
size_t len = aa.length;
debug(apply) printf("_aApplycd1(), len = %d\n", len);
for (i = 0; i < len; )
{ dchar d;
d = aa[i];
if (d & 0x80)
d = decode(aa, i);
else
i++;
result = dg(cast(void *)&d);
if (result)
break;
}
return result;
}
extern (C) int _aApplywd1(wchar[] aa, dg_t dg)
{ int result;
size_t i;
size_t len = aa.length;
debug(apply) printf("_aApplywd1(), len = %d\n", len);
for (i = 0; i < len; )
{ dchar d;
d = aa[i];
if (d & ~0x7F)
d = decode(aa, i);
else
i++;
result = dg(cast(void *)&d);
if (result)
break;
}
return result;
}
extern (C) int _aApplycw1(char[] aa, dg_t dg)
{ int result;
size_t i;
size_t len = aa.length;
debug(apply) printf("_aApplycw1(), len = %d\n", len);
for (i = 0; i < len; )
{ dchar d;
wchar w;
w = aa[i];
if (w & 0x80)
{ d = decode(aa, i);
if (d <= 0xFFFF)
w = cast(wchar) d;
else
{
w = cast(wchar)((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
result = dg(cast(void *)&w);
if (result)
break;
w = cast(wchar)(((d - 0x10000) & 0x3FF) + 0xDC00);
}
}
else
i++;
result = dg(cast(void *)&w);
if (result)
break;
}
return result;
}
extern (C) int _aApplywc1(wchar[] aa, dg_t dg)
{ int result;
size_t i;
size_t len = aa.length;
debug(apply) printf("_aApplywc1(), len = %d\n", len);
for (i = 0; i < len; )
{ dchar d;
wchar w;
char c;
w = aa[i];
if (w & ~0x7F)
{
char[4] buf;
d = decode(aa, i);
auto b = toUTF8(buf, d);
foreach (char c2; b)
{
result = dg(cast(void *)&c2);
if (result)
return result;
}
continue;
}
else
{ c = cast(char)w;
i++;
}
result = dg(cast(void *)&c);
if (result)
break;
}
return result;
}
extern (C) int _aApplydc1(dchar[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplydc1(), len = %d\n", aa.length);
foreach (dchar d; aa)
{
char c;
if (d & ~0x7F)
{
char[4] buf;
auto b = toUTF8(buf, d);
foreach (char c2; b)
{
result = dg(cast(void *)&c2);
if (result)
return result;
}
continue;
}
else
{
c = cast(char)d;
}
result = dg(cast(void *)&c);
if (result)
break;
}
return result;
}
extern (C) int _aApplydw1(dchar[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplydw1(), len = %d\n", aa.length);
foreach (dchar d; aa)
{
wchar w;
if (d <= 0xFFFF)
w = cast(wchar) d;
else
{
w = cast(wchar)((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
result = dg(cast(void *)&w);
if (result)
break;
w = cast(wchar)(((d - 0x10000) & 0x3FF) + 0xDC00);
}
result = dg(cast(void *)&w);
if (result)
break;
}
return result;
}
/****************************************************************************/
// dg is D, but _aApplycd2() is C
extern (D) typedef int delegate(void *, void *) dg2_t;
extern (C) int _aApplycd2(char[] aa, dg2_t dg)
{ int result;
size_t i;
size_t n;
size_t len = aa.length;
debug(apply) printf("_aApplycd2(), len = %d\n", len);
for (i = 0; i < len; i += n)
{ dchar d;
d = aa[i];
if (d & 0x80)
{
n = i;
d = decode(aa, n);
n -= i;
}
else
n = 1;
result = dg(&i, cast(void *)&d);
if (result)
break;
}
return result;
}
extern (C) int _aApplywd2(wchar[] aa, dg2_t dg)
{ int result;
size_t i;
size_t n;
size_t len = aa.length;
debug(apply) printf("_aApplywd2(), len = %d\n", len);
for (i = 0; i < len; i += n)
{ dchar d;
d = aa[i];
if (d & ~0x7F)
{
n = i;
d = decode(aa, n);
n -= i;
}
else
n = 1;
result = dg(&i, cast(void *)&d);
if (result)
break;
}
return result;
}
extern (C) int _aApplycw2(char[] aa, dg2_t dg)
{ int result;
size_t i;
size_t n;
size_t len = aa.length;
debug(apply) printf("_aApplycw2(), len = %d\n", len);
for (i = 0; i < len; i += n)
{ dchar d;
wchar w;
w = aa[i];
if (w & 0x80)
{ n = i;
d = decode(aa, n);
n -= i;
if (d <= 0xFFFF)
w = cast(wchar) d;
else
{
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
result = dg(&i, cast(void *)&w);
if (result)
break;
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
}
}
else
n = 1;
result = dg(&i, cast(void *)&w);
if (result)
break;
}
return result;
}
extern (C) int _aApplywc2(wchar[] aa, dg2_t dg)
{ int result;
size_t i;
size_t n;
size_t len = aa.length;
debug(apply) printf("_aApplywc2(), len = %d\n", len);
for (i = 0; i < len; i += n)
{ dchar d;
wchar w;
char c;
w = aa[i];
if (w & ~0x7F)
{
char[4] buf;
n = i;
d = decode(aa, n);
n -= i;
auto b = toUTF8(buf, d);
foreach (char c2; b)
{
result = dg(&i, cast(void *)&c2);
if (result)
return result;
}
continue;
}
else
{ c = cast(char)w;
n = 1;
}
result = dg(&i, cast(void *)&c);
if (result)
break;
}
return result;
}
extern (C) int _aApplydc2(dchar[] aa, dg2_t dg)
{ int result;
size_t i;
size_t len = aa.length;
debug(apply) printf("_aApplydc2(), len = %d\n", len);
for (i = 0; i < len; i++)
{ dchar d;
char c;
d = aa[i];
if (d & ~0x7F)
{
char[4] buf;
auto b = toUTF8(buf, d);
foreach (char c2; b)
{
result = dg(&i, cast(void *)&c2);
if (result)
return result;
}
continue;
}
else
{ c = cast(char)d;
}
result = dg(&i, cast(void *)&c);
if (result)
break;
}
return result;
}
extern (C) int _aApplydw2(dchar[] aa, dg2_t dg)
{ int result;
debug(apply) printf("_aApplydw2(), len = %d\n", aa.length);
foreach (size_t i, dchar d; aa)
{
wchar w;
auto j = i;
if (d <= 0xFFFF)
w = cast(wchar) d;
else
{
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
result = dg(&j, cast(void *)&w);
if (result)
break;
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
}
result = dg(&j, cast(void *)&w);
if (result)
break;
}
return result;
}

View File

@@ -0,0 +1,974 @@
/**
* Part of the D programming language runtime library.
*/
/*
* Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
* Written by Walter Bright
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, in both source and binary form, subject to the following
* restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
/*
* Modified by Sean Kelly for use with the D Runtime Project
*/
module rt.aApplyR;
/* This code handles decoding UTF strings for foreach_reverse loops.
* There are 6 combinations of conversions between char, wchar,
* and dchar, and 2 of each of those.
*/
private import util.utf;
/**********************************************/
/* 1 argument versions */
// dg is D, but _aApplyRcd() is C
extern (D) typedef int delegate(void *) dg_t;
extern (C) int _aApplyRcd1(in char[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplyRcd1(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
i--;
d = aa[i];
if (d & 0x80)
{ char c = cast(char)d;
uint j;
uint m = 0x3F;
d = 0;
while ((c & 0xC0) != 0xC0)
{ if (i == 0)
onUnicodeError("Invalid UTF-8 sequence", 0);
i--;
d |= (c & 0x3F) << j;
j += 6;
m >>= 1;
c = aa[i];
}
d |= (c & m) << j;
}
result = dg(cast(void *)&d);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRcd1.unittest\n");
auto s = "hello"c;
int i;
foreach_reverse(dchar d; s)
{
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(dchar d; s)
{
//printf("i = %d, d = %x\n", i, d);
switch (i)
{
case 0: assert(d == 'b'); break;
case 1: assert(d == '\U00100456'); break;
case 2: assert(d == '\u1234'); break;
case 3: assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 4);
}
/*****************************/
extern (C) int _aApplyRwd1(in wchar[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplyRwd1(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
i--;
d = aa[i];
if (d >= 0xDC00 && d <= 0xDFFF)
{ if (i == 0)
onUnicodeError("Invalid UTF-16 sequence", 0);
i--;
d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
}
result = dg(cast(void *)&d);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRwd1.unittest\n");
auto s = "hello"w;
int i;
foreach_reverse(dchar d; s)
{
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(dchar d; s)
{
//printf("i = %d, d = %x\n", i, d);
switch (i)
{
case 0: assert(d == 'b'); break;
case 1: assert(d == '\U00100456'); break;
case 2: assert(d == '\u1234'); break;
case 3: assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 4);
}
/*****************************/
extern (C) int _aApplyRcw1(in char[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplyRcw1(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
wchar w;
i--;
w = aa[i];
if (w & 0x80)
{ char c = cast(char)w;
uint j;
uint m = 0x3F;
d = 0;
while ((c & 0xC0) != 0xC0)
{ if (i == 0)
onUnicodeError("Invalid UTF-8 sequence", 0);
i--;
d |= (c & 0x3F) << j;
j += 6;
m >>= 1;
c = aa[i];
}
d |= (c & m) << j;
if (d <= 0xFFFF)
w = cast(wchar) d;
else
{
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
result = dg(cast(void *)&w);
if (result)
break;
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
}
}
result = dg(cast(void *)&w);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRcw1.unittest\n");
auto s = "hello"c;
int i;
foreach_reverse(wchar d; s)
{
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(wchar d; s)
{
//printf("i = %d, d = %x\n", i, d);
switch (i)
{
case 0: assert(d == 'b'); break;
case 1: assert(d == 0xDBC1); break;
case 2: assert(d == 0xDC56); break;
case 3: assert(d == 0x1234); break;
case 4: assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
}
/*****************************/
extern (C) int _aApplyRwc1(in wchar[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplyRwc1(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
char c;
i--;
d = aa[i];
if (d >= 0xDC00 && d <= 0xDFFF)
{ if (i == 0)
onUnicodeError("Invalid UTF-16 sequence", 0);
i--;
d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
}
if (d & ~0x7F)
{
char[4] buf;
auto b = toUTF8(buf, d);
foreach (char c2; b)
{
result = dg(cast(void *)&c2);
if (result)
return result;
}
continue;
}
c = cast(char)d;
result = dg(cast(void *)&c);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRwc1.unittest\n");
auto s = "hello"w;
int i;
foreach_reverse(char d; s)
{
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(char d; s)
{
//printf("i = %d, d = %x\n", i, d);
switch (i)
{
case 0: assert(d == 'b'); break;
case 1: assert(d == 0xF4); break;
case 2: assert(d == 0x80); break;
case 3: assert(d == 0x91); break;
case 4: assert(d == 0x96); break;
case 5: assert(d == 0xE1); break;
case 6: assert(d == 0x88); break;
case 7: assert(d == 0xB4); break;
case 8: assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 9);
}
/*****************************/
extern (C) int _aApplyRdc1(in dchar[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplyRdc1(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0;)
{ dchar d = aa[--i];
char c;
if (d & ~0x7F)
{
char[4] buf;
auto b = toUTF8(buf, d);
foreach (char c2; b)
{
result = dg(cast(void *)&c2);
if (result)
return result;
}
continue;
}
else
{
c = cast(char)d;
}
result = dg(cast(void *)&c);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRdc1.unittest\n");
auto s = "hello"d;
int i;
foreach_reverse(char d; s)
{
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(char d; s)
{
//printf("i = %d, d = %x\n", i, d);
switch (i)
{
case 0: assert(d == 'b'); break;
case 1: assert(d == 0xF4); break;
case 2: assert(d == 0x80); break;
case 3: assert(d == 0x91); break;
case 4: assert(d == 0x96); break;
case 5: assert(d == 0xE1); break;
case 6: assert(d == 0x88); break;
case 7: assert(d == 0xB4); break;
case 8: assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 9);
}
/*****************************/
extern (C) int _aApplyRdw1(in dchar[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplyRdw1(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d = aa[--i];
wchar w;
if (d <= 0xFFFF)
w = cast(wchar) d;
else
{
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
result = dg(cast(void *)&w);
if (result)
break;
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
}
result = dg(cast(void *)&w);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRdw1.unittest\n");
auto s = "hello"d;
int i;
foreach_reverse(wchar d; s)
{
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(wchar d; s)
{
//printf("i = %d, d = %x\n", i, d);
switch (i)
{
case 0: assert(d == 'b'); break;
case 1: assert(d == 0xDBC1); break;
case 2: assert(d == 0xDC56); break;
case 3: assert(d == 0x1234); break;
case 4: assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
}
/****************************************************************************/
/* 2 argument versions */
// dg is D, but _aApplyRcd2() is C
extern (D) typedef int delegate(void *, void *) dg2_t;
extern (C) int _aApplyRcd2(in char[] aa, dg2_t dg)
{ int result;
size_t i;
size_t len = aa.length;
debug(apply) printf("_aApplyRcd2(), len = %d\n", len);
for (i = len; i != 0; )
{ dchar d;
i--;
d = aa[i];
if (d & 0x80)
{ char c = cast(char)d;
uint j;
uint m = 0x3F;
d = 0;
while ((c & 0xC0) != 0xC0)
{ if (i == 0)
onUnicodeError("Invalid UTF-8 sequence", 0);
i--;
d |= (c & 0x3F) << j;
j += 6;
m >>= 1;
c = aa[i];
}
d |= (c & m) << j;
}
result = dg(&i, cast(void *)&d);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRcd2.unittest\n");
auto s = "hello"c;
int i;
foreach_reverse(k, dchar d; s)
{
assert(k == 4 - i);
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(k, dchar d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
switch (i)
{
case 0: assert(d == 'b'); assert(k == 8); break;
case 1: assert(d == '\U00100456'); assert(k == 4); break;
case 2: assert(d == '\u1234'); assert(k == 1); break;
case 3: assert(d == 'a'); assert(k == 0); break;
default: assert(0);
}
i++;
}
assert(i == 4);
}
/*****************************/
extern (C) int _aApplyRwd2(in wchar[] aa, dg2_t dg)
{ int result;
debug(apply) printf("_aApplyRwd2(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
i--;
d = aa[i];
if (d >= 0xDC00 && d <= 0xDFFF)
{ if (i == 0)
onUnicodeError("Invalid UTF-16 sequence", 0);
i--;
d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
}
result = dg(&i, cast(void *)&d);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRwd2.unittest\n");
auto s = "hello"w;
int i;
foreach_reverse(k, dchar d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
assert(k == 4 - i);
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(k, dchar d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
switch (i)
{
case 0: assert(k == 4); assert(d == 'b'); break;
case 1: assert(k == 2); assert(d == '\U00100456'); break;
case 2: assert(k == 1); assert(d == '\u1234'); break;
case 3: assert(k == 0); assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 4);
}
/*****************************/
extern (C) int _aApplyRcw2(in char[] aa, dg2_t dg)
{ int result;
debug(apply) printf("_aApplyRcw2(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
wchar w;
i--;
w = aa[i];
if (w & 0x80)
{ char c = cast(char)w;
uint j;
uint m = 0x3F;
d = 0;
while ((c & 0xC0) != 0xC0)
{ if (i == 0)
onUnicodeError("Invalid UTF-8 sequence", 0);
i--;
d |= (c & 0x3F) << j;
j += 6;
m >>= 1;
c = aa[i];
}
d |= (c & m) << j;
if (d <= 0xFFFF)
w = cast(wchar) d;
else
{
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
result = dg(&i, cast(void *)&w);
if (result)
break;
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
}
}
result = dg(&i, cast(void *)&w);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRcw2.unittest\n");
auto s = "hello"c;
int i;
foreach_reverse(k, wchar d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
assert(k == 4 - i);
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(k, wchar d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
switch (i)
{
case 0: assert(k == 8); assert(d == 'b'); break;
case 1: assert(k == 4); assert(d == 0xDBC1); break;
case 2: assert(k == 4); assert(d == 0xDC56); break;
case 3: assert(k == 1); assert(d == 0x1234); break;
case 4: assert(k == 0); assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
}
/*****************************/
extern (C) int _aApplyRwc2(in wchar[] aa, dg2_t dg)
{ int result;
debug(apply) printf("_aApplyRwc2(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
char c;
i--;
d = aa[i];
if (d >= 0xDC00 && d <= 0xDFFF)
{ if (i == 0)
onUnicodeError("Invalid UTF-16 sequence", 0);
i--;
d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
}
if (d & ~0x7F)
{
char[4] buf;
auto b = toUTF8(buf, d);
foreach (char c2; b)
{
result = dg(&i, cast(void *)&c2);
if (result)
return result;
}
continue;
}
c = cast(char)d;
result = dg(&i, cast(void *)&c);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRwc2.unittest\n");
auto s = "hello"w;
int i;
foreach_reverse(k, char d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
assert(k == 4 - i);
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(k, char d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
switch (i)
{
case 0: assert(k == 4); assert(d == 'b'); break;
case 1: assert(k == 2); assert(d == 0xF4); break;
case 2: assert(k == 2); assert(d == 0x80); break;
case 3: assert(k == 2); assert(d == 0x91); break;
case 4: assert(k == 2); assert(d == 0x96); break;
case 5: assert(k == 1); assert(d == 0xE1); break;
case 6: assert(k == 1); assert(d == 0x88); break;
case 7: assert(k == 1); assert(d == 0xB4); break;
case 8: assert(k == 0); assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 9);
}
/*****************************/
extern (C) int _aApplyRdc2(in dchar[] aa, dg2_t dg)
{ int result;
debug(apply) printf("_aApplyRdc2(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d = aa[--i];
char c;
if (d & ~0x7F)
{
char[4] buf;
auto b = toUTF8(buf, d);
foreach (char c2; b)
{
result = dg(&i, cast(void *)&c2);
if (result)
return result;
}
continue;
}
else
{ c = cast(char)d;
}
result = dg(&i, cast(void *)&c);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRdc2.unittest\n");
auto s = "hello"d;
int i;
foreach_reverse(k, char d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
assert(k == 4 - i);
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(k, char d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
switch (i)
{
case 0: assert(k == 3); assert(d == 'b'); break;
case 1: assert(k == 2); assert(d == 0xF4); break;
case 2: assert(k == 2); assert(d == 0x80); break;
case 3: assert(k == 2); assert(d == 0x91); break;
case 4: assert(k == 2); assert(d == 0x96); break;
case 5: assert(k == 1); assert(d == 0xE1); break;
case 6: assert(k == 1); assert(d == 0x88); break;
case 7: assert(k == 1); assert(d == 0xB4); break;
case 8: assert(k == 0); assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 9);
}
/*****************************/
extern (C) int _aApplyRdw2(in dchar[] aa, dg2_t dg)
{ int result;
debug(apply) printf("_aApplyRdw2(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d = aa[--i];
wchar w;
if (d <= 0xFFFF)
w = cast(wchar) d;
else
{
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
result = dg(&i, cast(void *)&w);
if (result)
break;
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
}
result = dg(&i, cast(void *)&w);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRdw2.unittest\n");
auto s = "hello"d;
int i;
foreach_reverse(k, wchar d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
assert(k == 4 - i);
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(k, wchar d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
switch (i)
{
case 0: assert(k == 3); assert(d == 'b'); break;
case 1: assert(k == 2); assert(d == 0xDBC1); break;
case 2: assert(k == 2); assert(d == 0xDC56); break;
case 3: assert(k == 1); assert(d == 0x1234); break;
case 4: assert(k == 0); assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
}

View File

@@ -0,0 +1,886 @@
//_ aaA.d
/**
* Part of the D programming language runtime library.
* Implementation of associative arrays.
*/
/*
* Copyright (C) 2000-2008 by Digital Mars, http://www.digitalmars.com
* Written by Walter Bright
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
/*
* Modified by Sean Kelly for use with the D Runtime Project
*/
module rt.aaA;
private
{
import stdc.stdarg;
import stdc.string;
enum BlkAttr : uint
{
FINALIZE = 0b0000_0001,
NO_SCAN = 0b0000_0010,
NO_MOVE = 0b0000_0100,
ALL_BITS = 0b1111_1111
}
extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
extern (C) void gc_free( void* p );
}
// Auto-rehash and pre-allocate - Dave Fladebo
static size_t[] prime_list = [
97UL, 389UL,
1_543UL, 6_151UL,
24_593UL, 98_317UL,
393_241UL, 1_572_869UL,
6_291_469UL, 25_165_843UL,
100_663_319UL, 402_653_189UL,
1_610_612_741UL, 4_294_967_291UL,
// 8_589_934_513UL, 17_179_869_143UL
];
/* This is the type of the return value for dynamic arrays.
* It should be a type that is returned in registers.
* Although DMD will return types of Array in registers,
* gcc will not, so we instead use a 'long'.
*/
alias long ArrayRet_t;
struct Array
{
size_t length;
void* ptr;
}
struct aaA
{
aaA *left;
aaA *right;
hash_t hash;
/* key */
/* value */
}
struct BB
{
aaA*[] b;
size_t nodes; // total number of aaA nodes
TypeInfo keyti; // TODO: replace this with TypeInfo_AssociativeArray when available in _aaGet()
}
/* This is the type actually seen by the programmer, although
* it is completely opaque.
*/
struct AA
{
BB* a;
}
/**********************************
* Align to next pointer boundary, so that
* GC won't be faced with misaligned pointers
* in value.
*/
size_t aligntsize(size_t tsize)
{
// Is pointer alignment on the x64 4 bytes or 8?
return (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
}
extern (C):
/*************************************************
* Invariant for aa.
*/
/+
void _aaInvAh(aaA*[] aa)
{
for (size_t i = 0; i < aa.length; i++)
{
if (aa[i])
_aaInvAh_x(aa[i]);
}
}
private int _aaCmpAh_x(aaA *e1, aaA *e2)
{ int c;
c = e1.hash - e2.hash;
if (c == 0)
{
c = e1.key.length - e2.key.length;
if (c == 0)
c = memcmp((char *)e1.key, (char *)e2.key, e1.key.length);
}
return c;
}
private void _aaInvAh_x(aaA *e)
{
hash_t key_hash;
aaA *e1;
aaA *e2;
key_hash = getHash(e.key);
assert(key_hash == e.hash);
while (1)
{ int c;
e1 = e.left;
if (e1)
{
_aaInvAh_x(e1); // ordinary recursion
do
{
c = _aaCmpAh_x(e1, e);
assert(c < 0);
e1 = e1.right;
} while (e1 != null);
}
e2 = e.right;
if (e2)
{
do
{
c = _aaCmpAh_x(e, e2);
assert(c < 0);
e2 = e2.left;
} while (e2 != null);
e = e.right; // tail recursion
}
else
break;
}
}
+/
/****************************************************
* Determine number of entries in associative array.
*/
size_t _aaLen(AA aa)
in
{
//printf("_aaLen()+\n");
//_aaInv(aa);
}
out (result)
{
size_t len = 0;
void _aaLen_x(aaA* ex)
{
auto e = ex;
len++;
while (1)
{
if (e.right)
_aaLen_x(e.right);
e = e.left;
if (!e)
break;
len++;
}
}
if (aa.a)
{
foreach (e; aa.a.b)
{
if (e)
_aaLen_x(e);
}
}
assert(len == result);
//printf("_aaLen()-\n");
}
body
{
return aa.a ? aa.a.nodes : 0;
}
/*************************************************
* Get pointer to value in associative array indexed by key.
* Add entry for key if it is not already there.
*/
void* _aaGet(AA* aa, TypeInfo keyti, size_t valuesize, ...)
in
{
assert(aa);
}
out (result)
{
assert(result);
assert(aa.a);
assert(aa.a.b.length);
//assert(_aaInAh(*aa.a, key));
}
body
{
auto pkey = cast(void *)(&valuesize + 1);
size_t i;
aaA *e;
auto keysize = aligntsize(keyti.tsize());
if (!aa.a)
aa.a = new BB();
aa.a.keyti = keyti;
if (!aa.a.b.length)
{
alias aaA *pa;
auto len = prime_list[0];
aa.a.b = new pa[len];
}
auto key_hash = keyti.getHash(pkey);
//printf("hash = %d\n", key_hash);
i = key_hash % aa.a.b.length;
auto pe = &aa.a.b[i];
while ((e = *pe) !is null)
{
if (key_hash == e.hash)
{
auto c = keyti.compare(pkey, e + 1);
if (c == 0)
goto Lret;
pe = (c < 0) ? &e.left : &e.right;
}
else
pe = (key_hash < e.hash) ? &e.left : &e.right;
}
// Not found, create new elem
//printf("create new one\n");
size_t size = aaA.sizeof + keysize + valuesize;
e = cast(aaA *) gc_calloc(size);
memcpy(e + 1, pkey, keysize);
e.hash = key_hash;
*pe = e;
auto nodes = ++aa.a.nodes;
//printf("length = %d, nodes = %d\n", (*aa.a).length, nodes);
if (nodes > aa.a.b.length * 4)
{
_aaRehash(aa,keyti);
}
Lret:
return cast(void *)(e + 1) + keysize;
}
/*************************************************
* Get pointer to value in associative array indexed by key.
* Returns null if it is not already there.
*/
void* _aaGetRvalue(AA aa, TypeInfo keyti, size_t valuesize, ...)
{
//printf("_aaGetRvalue(valuesize = %u)\n", valuesize);
if (!aa.a)
return null;
auto pkey = cast(void *)(&valuesize + 1);
auto keysize = aligntsize(keyti.tsize());
auto len = aa.a.b.length;
if (len)
{
auto key_hash = keyti.getHash(pkey);
//printf("hash = %d\n", key_hash);
size_t i = key_hash % len;
auto e = aa.a.b[i];
while (e !is null)
{
if (key_hash == e.hash)
{
auto c = keyti.compare(pkey, e + 1);
if (c == 0)
return cast(void *)(e + 1) + keysize;
e = (c < 0) ? e.left : e.right;
}
else
e = (key_hash < e.hash) ? e.left : e.right;
}
}
return null; // not found, caller will throw exception
}
/*************************************************
* Determine if key is in aa.
* Returns:
* null not in aa
* !=null in aa, return pointer to value
*/
void* _aaIn(AA aa, TypeInfo keyti, ...)
in
{
}
out (result)
{
//assert(result == 0 || result == 1);
}
body
{
if (aa.a)
{
auto pkey = cast(void *)(&keyti + 1);
//printf("_aaIn(), .length = %d, .ptr = %x\n", aa.a.length, cast(uint)aa.a.ptr);
auto len = aa.a.b.length;
if (len)
{
auto key_hash = keyti.getHash(pkey);
//printf("hash = %d\n", key_hash);
size_t i = key_hash % len;
auto e = aa.a.b[i];
while (e !is null)
{
if (key_hash == e.hash)
{
auto c = keyti.compare(pkey, e + 1);
if (c == 0)
return cast(void *)(e + 1) + aligntsize(keyti.tsize());
e = (c < 0) ? e.left : e.right;
}
else
e = (key_hash < e.hash) ? e.left : e.right;
}
}
}
// Not found
return null;
}
/*************************************************
* Delete key entry in aa[].
* If key is not in aa[], do nothing.
*/
void _aaDel(AA aa, TypeInfo keyti, ...)
{
auto pkey = cast(void *)(&keyti + 1);
aaA *e;
if (aa.a && aa.a.b.length)
{
auto key_hash = keyti.getHash(pkey);
//printf("hash = %d\n", key_hash);
size_t i = key_hash % aa.a.b.length;
auto pe = &aa.a.b[i];
while ((e = *pe) !is null) // null means not found
{
if (key_hash == e.hash)
{
auto c = keyti.compare(pkey, e + 1);
if (c == 0)
{
if (!e.left && !e.right)
{
*pe = null;
}
else if (e.left && !e.right)
{
*pe = e.left;
e.left = null;
}
else if (!e.left && e.right)
{
*pe = e.right;
e.right = null;
}
else
{
*pe = e.left;
e.left = null;
do
pe = &(*pe).right;
while (*pe);
*pe = e.right;
e.right = null;
}
aa.a.nodes--;
gc_free(e);
break;
}
pe = (c < 0) ? &e.left : &e.right;
}
else
pe = (key_hash < e.hash) ? &e.left : &e.right;
}
}
}
/********************************************
* Produce array of values from aa.
*/
ArrayRet_t _aaValues(AA aa, size_t keysize, size_t valuesize)
in
{
assert(keysize == aligntsize(keysize));
}
body
{
size_t resi;
Array a;
void _aaValues_x(aaA* e)
{
do
{
memcpy(a.ptr + resi * valuesize,
cast(byte*)e + aaA.sizeof + keysize,
valuesize);
resi++;
if (e.left)
{ if (!e.right)
{ e = e.left;
continue;
}
_aaValues_x(e.left);
}
e = e.right;
} while (e !is null);
}
if (aa.a)
{
a.length = _aaLen(aa);
a.ptr = cast(byte*) gc_malloc(a.length * valuesize,
valuesize < (void*).sizeof ? BlkAttr.NO_SCAN : 0);
resi = 0;
foreach (e; aa.a.b)
{
if (e)
_aaValues_x(e);
}
assert(resi == a.length);
}
return *cast(ArrayRet_t*)(&a);
}
/********************************************
* Rehash an array.
*/
void* _aaRehash(AA* paa, TypeInfo keyti)
in
{
//_aaInvAh(paa);
}
out (result)
{
//_aaInvAh(result);
}
body
{
BB newb;
void _aaRehash_x(aaA* olde)
{
while (1)
{
auto left = olde.left;
auto right = olde.right;
olde.left = null;
olde.right = null;
aaA *e;
//printf("rehash %p\n", olde);
auto key_hash = olde.hash;
size_t i = key_hash % newb.b.length;
auto pe = &newb.b[i];
while ((e = *pe) !is null)
{
//printf("\te = %p, e.left = %p, e.right = %p\n", e, e.left, e.right);
assert(e.left != e);
assert(e.right != e);
if (key_hash == e.hash)
{
auto c = keyti.compare(olde + 1, e + 1);
assert(c != 0);
pe = (c < 0) ? &e.left : &e.right;
}
else
pe = (key_hash < e.hash) ? &e.left : &e.right;
}
*pe = olde;
if (right)
{
if (!left)
{ olde = right;
continue;
}
_aaRehash_x(right);
}
if (!left)
break;
olde = left;
}
}
//printf("Rehash\n");
if (paa.a)
{
auto aa = paa.a;
auto len = _aaLen(*paa);
if (len)
{ size_t i;
for (i = 0; i < prime_list.length - 1; i++)
{
if (len <= prime_list[i])
break;
}
len = prime_list[i];
newb.b = new aaA*[len];
foreach (e; aa.b)
{
if (e)
_aaRehash_x(e);
}
newb.nodes = aa.nodes;
newb.keyti = aa.keyti;
}
*paa.a = newb;
_aaBalance(paa);
}
return (*paa).a;
}
/********************************************
* Balance an array.
*/
void _aaBalance(AA* paa)
{
//printf("_aaBalance()\n");
if (paa.a)
{
aaA*[16] tmp;
aaA*[] array = tmp;
auto aa = paa.a;
foreach (j, e; aa.b)
{
/* Temporarily store contents of bucket in array[]
*/
size_t k = 0;
void addToArray(aaA* e)
{
while (e)
{ addToArray(e.left);
if (k == array.length)
array.length = array.length * 2;
array[k++] = e;
e = e.right;
}
}
addToArray(e);
/* The contents of the bucket are now sorted into array[].
* Rebuild the tree.
*/
void buildTree(aaA** p, size_t x1, size_t x2)
{
if (x1 >= x2)
*p = null;
else
{ auto mid = (x1 + x2) >> 1;
*p = array[mid];
buildTree(&(*p).left, x1, mid);
buildTree(&(*p).right, mid + 1, x2);
}
}
auto p = &aa.b[j];
buildTree(p, 0, k);
}
}
}
/********************************************
* Produce array of N byte keys from aa.
*/
ArrayRet_t _aaKeys(AA aa, size_t keysize)
{
byte[] res;
size_t resi;
void _aaKeys_x(aaA* e)
{
do
{
memcpy(&res[resi * keysize], cast(byte*)(e + 1), keysize);
resi++;
if (e.left)
{ if (!e.right)
{ e = e.left;
continue;
}
_aaKeys_x(e.left);
}
e = e.right;
} while (e !is null);
}
auto len = _aaLen(aa);
if (!len)
return 0;
res = (cast(byte*) gc_malloc(len * keysize,
!(aa.a.keyti.flags() & 1) ? BlkAttr.NO_SCAN : 0))[0 .. len * keysize];
resi = 0;
foreach (e; aa.a.b)
{
if (e)
_aaKeys_x(e);
}
assert(resi == len);
Array a;
a.length = len;
a.ptr = res.ptr;
return *cast(ArrayRet_t*)(&a);
}
/**********************************************
* 'apply' for associative arrays - to support foreach
*/
// dg is D, but _aaApply() is C
extern (D) typedef int delegate(void *) dg_t;
int _aaApply(AA aa, size_t keysize, dg_t dg)
in
{
assert(aligntsize(keysize) == keysize);
}
body
{ int result;
//printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa.a, keysize, dg);
int treewalker(aaA* e)
{ int result;
do
{
//printf("treewalker(e = %p, dg = x%llx)\n", e, dg);
result = dg(cast(void *)(e + 1) + keysize);
if (result)
break;
if (e.right)
{ if (!e.left)
{
e = e.right;
continue;
}
result = treewalker(e.right);
if (result)
break;
}
e = e.left;
} while (e);
return result;
}
if (aa.a)
{
foreach (e; aa.a.b)
{
if (e)
{
result = treewalker(e);
if (result)
break;
}
}
}
return result;
}
// dg is D, but _aaApply2() is C
extern (D) typedef int delegate(void *, void *) dg2_t;
int _aaApply2(AA aa, size_t keysize, dg2_t dg)
in
{
assert(aligntsize(keysize) == keysize);
}
body
{ int result;
//printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa.a, keysize, dg);
int treewalker(aaA* e)
{ int result;
do
{
//printf("treewalker(e = %p, dg = x%llx)\n", e, dg);
result = dg(cast(void *)(e + 1), cast(void *)(e + 1) + keysize);
if (result)
break;
if (e.right)
{ if (!e.left)
{
e = e.right;
continue;
}
result = treewalker(e.right);
if (result)
break;
}
e = e.left;
} while (e);
return result;
}
if (aa.a)
{
foreach (e; aa.a.b)
{
if (e)
{
result = treewalker(e);
if (result)
break;
}
}
}
return result;
}
/***********************************
* Construct an associative array of type ti from
* length pairs of key/value pairs.
*/
extern (C)
BB* _d_assocarrayliteralT(TypeInfo_AssociativeArray ti, size_t length, ...)
{
auto valuesize = ti.next.tsize(); // value size
auto keyti = ti.key;
auto keysize = keyti.tsize(); // key size
BB* result;
//printf("_d_assocarrayliteralT(keysize = %d, valuesize = %d, length = %d)\n", keysize, valuesize, length);
//printf("tivalue = %.*s\n", ti.next.classinfo.name);
if (length == 0 || valuesize == 0 || keysize == 0)
{
;
}
else
{
va_list q;
va_start!(size_t)(q, length);
result = new BB();
result.keyti = keyti;
size_t i;
for (i = 0; i < prime_list.length - 1; i++)
{
if (length <= prime_list[i])
break;
}
auto len = prime_list[i];
result.b = new aaA*[len];
size_t keystacksize = (keysize + int.sizeof - 1) & ~(int.sizeof - 1);
size_t valuestacksize = (valuesize + int.sizeof - 1) & ~(int.sizeof - 1);
size_t keytsize = aligntsize(keysize);
for (size_t j = 0; j < length; j++)
{ void* pkey = q;
q += keystacksize;
void* pvalue = q;
q += valuestacksize;
aaA* e;
auto key_hash = keyti.getHash(pkey);
//printf("hash = %d\n", key_hash);
i = key_hash % len;
auto pe = &result.b[i];
while (1)
{
e = *pe;
if (!e)
{
// Not found, create new elem
//printf("create new one\n");
e = cast(aaA *) cast(void*) new void[aaA.sizeof + keytsize + valuesize];
memcpy(e + 1, pkey, keysize);
e.hash = key_hash;
*pe = e;
result.nodes++;
break;
}
if (key_hash == e.hash)
{
auto c = keyti.compare(pkey, e + 1);
if (c == 0)
break;
pe = (c < 0) ? &e.left : &e.right;
}
else
pe = (key_hash < e.hash) ? &e.left : &e.right;
}
memcpy(cast(void *)(e + 1) + keytsize, pvalue, valuesize);
}
va_end(q);
}
return result;
}

View File

@@ -0,0 +1,625 @@
//_ adi.d
/**
* Part of the D programming language runtime library.
* Dynamic array property support routines
*/
/*
* Copyright (C) 2000-2006 by Digital Mars, www.digitalmars.com
* Written by Walter Bright
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, in both source and binary form, subject to the following
* restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
/*
* Modified by Sean Kelly for use with the D Runtime Project
*/
module rt.adi;
//debug=adi; // uncomment to turn on debugging printf's
private
{
debug(adi) import stdc.stdio;
import stdc.string;
import stdc.stdlib;
import util.utf;
enum BlkAttr : uint
{
FINALIZE = 0b0000_0001,
NO_SCAN = 0b0000_0010,
NO_MOVE = 0b0000_0100,
ALL_BITS = 0b1111_1111
}
extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
extern (C) void gc_free( void* p );
}
struct Array
{
size_t length;
void* ptr;
}
/**********************************************
* Reverse array of chars.
* Handled separately because embedded multibyte encodings should not be
* reversed.
*/
extern (C) long _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;
debug(adi) printf("lo = %d, hi = %d\n", lo, hi);
if (clo <= 0x7F && chi <= 0x7F)
{
debug(adi) printf("\tascii\n");
*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;
debug(adi) printf("\tstridelo = %d, stridehi = %d\n", stridelo, stridehi);
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 + stridehi - stridelo, tmplo.ptr, stridelo);
lo += stridehi;
hi = hi - 1 + (stridehi - stridelo);
}
}
return *cast(long*)(&a);
}
unittest
{
auto a = "abcd"c;
auto r = a.dup.reverse;
//writefln(r);
assert(r == "dcba");
a = "a\u1235\u1234c";
//writefln(a);
r = a.dup.reverse;
//writefln(r);
assert(r == "c\u1234\u1235a");
a = "ab\u1234c";
//writefln(a);
r = a.dup.reverse;
//writefln(r);
assert(r == "c\u1234ba");
a = "\u3026\u2021\u3061\n";
r = a.dup.reverse;
assert(r == "\n\u3061\u2021\u3026");
}
/**********************************************
* Reverse array of wchars.
* Handled separately because embedded multiword encodings should not be
* reversed.
*/
extern (C) long _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 + stridehi - 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 + (stridehi - stridelo);
}
}
return *cast(long*)(&a);
}
unittest
{
wstring a = "abcd";
auto r = a.dup.reverse;
assert(r == "dcba");
a = "a\U00012356\U00012346c";
r = a.dup.reverse;
assert(r == "c\U00012346\U00012356a");
a = "ab\U00012345c";
r = a.dup.reverse;
assert(r == "c\U00012345ba");
}
/**********************************************
* Support for array.reverse property.
*/
extern (C) long _adReverse(Array a, size_t szelem)
out (result)
{
assert(result is *cast(long*)(&a));
}
body
{
if (a.length >= 2)
{
byte* tmp;
byte[16] buffer;
void* lo = a.ptr;
void* hi = a.ptr + (a.length - 1) * szelem;
tmp = buffer.ptr;
if (szelem > 16)
{
//version (Windows)
tmp = cast(byte*) alloca(szelem);
//else
//tmp = gc_malloc(szelem);
}
for (; lo < hi; lo += szelem, hi -= szelem)
{
memcpy(tmp, lo, szelem);
memcpy(lo, hi, szelem);
memcpy(hi, tmp, szelem);
}
version (Windows)
{
}
else
{
//if (szelem > 16)
// BUG: bad code is generate for delete pointer, tries
// to call delclass.
//gc_free(tmp);
}
}
return *cast(long*)(&a);
}
unittest
{
debug(adi) printf("array.reverse.unittest\n");
int[] a = new int[5];
int[] b;
size_t i;
for (i = 0; i < 5; i++)
a[i] = i;
b = a.reverse;
assert(b is a);
for (i = 0; i < 5; i++)
assert(a[i] == 4 - i);
struct X20
{ // More than 16 bytes in size
int a;
int b, c, d, e;
}
X20[] c = new X20[5];
X20[] d;
for (i = 0; i < 5; i++)
{ c[i].a = i;
c[i].e = 10;
}
d = c.reverse;
assert(d is c);
for (i = 0; i < 5; i++)
{
assert(c[i].a == 4 - i);
assert(c[i].e == 10);
}
}
/**********************************************
* Sort array of chars.
*/
extern (C) long _adSortChar(char[] a)
{
if (a.length > 1)
{
dstring da = toUTF32(a);
da.sort;
size_t i = 0;
foreach (dchar d; da)
{ char[4] buf;
auto t = toUTF8(buf, d);
a[i .. i + t.length] = t[];
i += t.length;
}
delete da;
}
return *cast(long*)(&a);
}
/**********************************************
* Sort array of wchars.
*/
extern (C) long _adSortWchar(wchar[] a)
{
if (a.length > 1)
{
dstring da = toUTF32(a);
da.sort;
size_t i = 0;
foreach (dchar d; da)
{ wchar[2] buf;
auto t = toUTF16(buf, d);
a[i .. i + t.length] = t[];
i += t.length;
}
delete da;
}
return *cast(long*)(&a);
}
/***************************************
* Support for array equality test.
* Returns:
* 1 equal
* 0 not equal
*/
extern (C) int _adEq(Array a1, Array a2, TypeInfo ti)
{
debug(adi) printf("_adEq(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
if (a1.length != a2.length)
return 0; // not equal
auto sz = ti.tsize();
auto p1 = a1.ptr;
auto p2 = a2.ptr;
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
}
extern (C) int _adEq2(Array a1, Array a2, TypeInfo ti)
{
debug(adi) printf("_adEq2(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
if (a1.length != a2.length)
return 0; // not equal
if (!ti.equals(&a1, &a2))
return 0;
return 1;
}
unittest
{
debug(adi) printf("array.Eq unittest\n");
auto a = "hello"c;
assert(a != "hel");
assert(a != "helloo");
assert(a != "betty");
assert(a == "hello");
assert(a != "hxxxx");
}
/***************************************
* Support for array compare test.
*/
extern (C) int _adCmp(Array a1, Array a2, TypeInfo ti)
{
debug(adi) printf("adCmp()\n");
auto len = a1.length;
if (a2.length < len)
len = a2.length;
auto sz = ti.tsize();
void *p1 = a1.ptr;
void *p2 = a2.ptr;
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;
}
extern (C) int _adCmp2(Array a1, Array a2, TypeInfo ti)
{
debug(adi) printf("_adCmp2(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
return ti.compare(&a1, &a2);
}
unittest
{
debug(adi) printf("array.Cmp unittest\n");
auto a = "hello"c;
assert(a > "hel");
assert(a >= "hel");
assert(a < "helloo");
assert(a <= "helloo");
assert(a > "betty");
assert(a >= "betty");
assert(a == "hello");
assert(a <= "hello");
assert(a >= "hello");
}
/***************************************
* Support for array compare test.
*/
extern (C) int _adCmpChar(Array a1, Array a2)
{
version (X86)
{
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;
debug(adi) printf("adCmpChar()\n");
len = a1.length;
if (a2.length < len)
len = a2.length;
c = memcmp(cast(char *)a1.ptr, cast(char *)a2.ptr, len);
if (!c)
c = cast(int)a1.length - cast(int)a2.length;
return c;
}
}
unittest
{
debug(adi) printf("array.CmpChar unittest\n");
auto a = "hello"c;
assert(a > "hel");
assert(a >= "hel");
assert(a < "helloo");
assert(a <= "helloo");
assert(a > "betty");
assert(a >= "betty");
assert(a == "hello");
assert(a <= "hello");
assert(a >= "hello");
}

View File

@@ -0,0 +1,110 @@
/*_ _alloca.d
* Copyright (C) 1990-2003 by Digital Mars, www.digitalmars.com
* All Rights Reserved
* Written by Walter Bright
*/
module rt.alloca;
/+
#if DOS386
extern size_t _x386_break;
#else
extern size_t _pastdata;
#endif
+/
/*******************************************
* Allocate data from the caller's stack frame.
* This is a 'magic' function that needs help from the compiler to
* work right, do not change its name, do not call it from other compilers.
* Input:
* nbytes number of bytes to allocate
* ECX address of variable with # of bytes in locals
* This is adjusted upon return to reflect the additional
* size of the stack frame.
* Returns:
* EAX allocated data, null if stack overflows
*/
extern (C) void* __alloca(int nbytes)
{
asm
{
naked ;
mov EDX,ECX ;
mov EAX,4[ESP] ; // get nbytes
push EBX ;
push EDI ;
push ESI ;
add EAX,3 ;
and EAX,0xFFFFFFFC ; // round up to dword
jnz Abegin ;
mov EAX,4 ; // allow zero bytes allocation, 0 rounded to dword is 4..
Abegin:
mov ESI,EAX ; // ESI = nbytes
neg EAX ;
add EAX,ESP ; // EAX is now what the new ESP will be.
jae Aoverflow ;
}
version (Windows)
{
asm
{
// We need to be careful about the guard page
// Thus, for every 4k page, touch it to cause the OS to load it in.
mov ECX,EAX ; // ECX is new location for stack
mov EBX,ESI ; // EBX is size to "grow" stack
L1:
test [ECX+EBX],EBX ; // bring in page
sub EBX,0x1000 ; // next 4K page down
jae L1 ; // if more pages
test [ECX],EBX ; // bring in last page
}
}
version (DOS386)
{
asm
{
// is ESP off bottom?
cmp EAX,_x386_break ;
jbe Aoverflow ;
}
}
version (Unix)
{
asm
{
cmp EAX,_pastdata ;
jbe Aoverflow ; // Unlikely - ~2 Gbytes under UNIX
}
}
asm
{
// Copy down to [ESP] the temps on the stack.
// The number of temps is (EBP - ESP - locals).
mov ECX,EBP ;
sub ECX,ESP ;
sub ECX,[EDX] ; // ECX = number of temps (bytes) to move.
add [EDX],ESI ; // adjust locals by nbytes for next call to alloca()
mov ESP,EAX ; // Set up new stack pointer.
add EAX,ECX ; // Return value = ESP + temps.
mov EDI,ESP ; // Destination of copy of temps.
add ESI,ESP ; // Source of copy.
shr ECX,2 ; // ECX to count of dwords in temps
// Always at least 4 (nbytes, EIP, ESI,and EDI).
rep ;
movsd ;
jmp done ;
Aoverflow:
// Overflowed the stack. Return null
xor EAX,EAX ;
done:
pop ESI ;
pop EDI ;
pop EBX ;
ret ;
}
}

View File

@@ -0,0 +1,180 @@
/**
* Part of the D programming language runtime library.
* http://www.digitalmars.com
* Written by Walter Bright
* Placed in the Public Domain
*/
module rt.arrayassign;
private
{
import util.string;
import stdc.string;
import stdc.stdlib;
debug(PRINTF) import stdc.stdio;
}
/**
* Does array assignment (not construction) from another
* array of the same element type.
* ti is the element type.
* Handles overlapping copies.
*/
extern (C) void[] _d_arrayassign(TypeInfo ti, void[] from, void[] to)
{
debug(PRINTF) printf("_d_arrayassign(from = %p,%d, to = %p,%d) size = %d\n", from.ptr, from.length, to.ptr, to.length, ti.tsize());
if (to.length != from.length)
{
char[10] tmp = void;
string msg = "lengths don't match for array copy,"c;
msg ~= tmp.intToString(to.length) ~ " = " ~ tmp.intToString(from.length);
throw new Exception(msg);
}
auto element_size = ti.tsize();
/* Need a temporary buffer tmp[] big enough to hold one element
*/
void[16] buf = void;
void[] tmp;
if (element_size > buf.sizeof)
tmp = alloca(element_size)[0 .. element_size];
else
tmp = buf;
if (to.ptr <= from.ptr)
{
foreach (i; 0 .. to.length)
{
void* pto = to.ptr + i * element_size;
void* pfrom = from.ptr + i * element_size;
memcpy(tmp.ptr, pto, element_size);
memcpy(pto, pfrom, element_size);
ti.postblit(pto);
ti.destroy(tmp.ptr);
}
}
else
{
for (int i = to.length; i--; )
{
void* pto = to.ptr + i * element_size;
void* pfrom = from.ptr + i * element_size;
memcpy(tmp.ptr, pto, element_size);
memcpy(pto, pfrom, element_size);
ti.postblit(pto);
ti.destroy(tmp.ptr);
}
}
return to;
}
/**
* Does array initialization (not assignment) from another
* array of the same element type.
* ti is the element type.
*/
extern (C) void[] _d_arrayctor(TypeInfo ti, void[] from, void[] to)
{
debug(PRINTF) printf("_d_arrayctor(from = %p,%d, to = %p,%d) size = %d\n", from.ptr, from.length, to.ptr, to.length, ti.tsize());
if (to.length != from.length)
{
char[10] tmp = void;
string msg = "lengths don't match for array initialization,"c;
msg ~= tmp.intToString(to.length) ~ " = " ~ tmp.intToString(from.length);
throw new Exception(msg);
}
auto element_size = ti.tsize();
int i;
try
{
for (i = 0; i < to.length; i++)
{
// Copy construction is defined as bit copy followed by postblit.
memcpy(to.ptr + i * element_size, from.ptr + i * element_size, element_size);
ti.postblit(to.ptr + i * element_size);
}
}
catch (Object o)
{
/* Destroy, in reverse order, what we've constructed so far
*/
while (i--)
{
ti.destroy(to.ptr + i * element_size);
}
throw o;
}
return to;
}
/**
* Do assignment to an array.
* p[0 .. count] = value;
*/
extern (C) void* _d_arraysetassign(void* p, void* value, int count, TypeInfo ti)
{
void* pstart = p;
auto element_size = ti.tsize();
//Need a temporary buffer tmp[] big enough to hold one element
void[16] buf = void;
void[] tmp;
if (element_size > buf.sizeof)
{
tmp = alloca(element_size)[0 .. element_size];
}
else
tmp = buf;
foreach (i; 0 .. count)
{
memcpy(tmp.ptr, p, element_size);
memcpy(p, value, element_size);
ti.postblit(p);
ti.destroy(tmp.ptr);
p += element_size;
}
return pstart;
}
/**
* Do construction of an array.
* ti[count] p = value;
*/
extern (C) void* _d_arraysetctor(void* p, void* value, int count, TypeInfo ti)
{
void* pstart = p;
auto element_size = ti.tsize();
try
{
foreach (i; 0 .. count)
{
// Copy construction is defined as bit copy followed by postblit.
memcpy(p, value, element_size);
ti.postblit(p);
p += element_size;
}
}
catch (Object o)
{
// Destroy, in reverse order, what we've constructed so far
while (p > pstart)
{
p -= element_size;
ti.destroy(p);
}
throw o;
}
return pstart;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,109 @@
/*
* Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com
* Written by Walter Bright
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, in both source and binary form, subject to the following
* restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
/*
* Modified by Sean Kelly for use with the D Runtime Project
*/
module rt.arraycast;
/******************************************
* Runtime helper to convert dynamic array of one
* type to dynamic array of another.
* Adjusts the length of the array.
* Throws exception if new length is not aligned.
*/
extern (C)
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;
}
unittest
{
byte[int.sizeof * 3] b;
int[] i;
short[] s;
i = cast(int[])b;
assert(i.length == 3);
s = cast(short[])b;
assert(s.length == 6);
s = cast(short[])i;
assert(s.length == 6);
}
/******************************************
* Runtime helper to convert dynamic array of bits
* dynamic array of another.
* Adjusts the length of the array.
* Throws exception if new length is not aligned.
*/
version (none)
{
extern (C)
void[] _d_arraycast_frombit(uint tsize, void[] a)
{
uint length = a.length;
if (length & 7)
{
throw new Exception("bit[] array cast misalignment");
}
length /= 8 * tsize;
*cast(size_t *)&a = length; // jam new length
return a;
}
unittest
{
version (D_Bits)
{
bit[int.sizeof * 3 * 8] b;
int[] i;
short[] s;
i = cast(int[])b;
assert(i.length == 3);
s = cast(short[])b;
assert(s.length == 6);
}
}
}

View File

@@ -0,0 +1,61 @@
/**
* Part of the D programming language runtime library.
*/
/*
* Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com
* Written by Walter Bright
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, in both source and binary form, subject to the following
* restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
/*
* Modified by Sean Kelly for use with the D Runtime Project
*/
module rt.arraycat;
private
{
import stdc.string;
debug import stdc.stdio;
}
extern (C):
byte[] _d_arraycopy(size_t size, byte[] from, byte[] to)
{
debug printf("f = %p,%d, t = %p,%d, size = %d\n",
from.ptr, from.length, to.ptr, to.length, size);
if (to.length != from.length)
{
throw new Exception("lengths don't match for array copy");
}
else if (to.ptr + to.length * size <= from.ptr ||
from.ptr + from.length * size <= to.ptr)
{
memcpy(to.ptr, from.ptr, to.length * size);
}
else
{
throw new Exception("overlapping array copy");
}
return to;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,234 @@
/***************************
* D programming language http://www.digitalmars.com/d/
* Runtime support for double array operations.
* Placed in public domain.
*/
module rt.arrayreal;
import util.cpuid;
version (Unittest)
{
/* This is so unit tests will test every CPU variant
*/
int cpuid;
const int CPUID_MAX = 1;
bool mmx() { return cpuid == 1 && util.cpuid.mmx(); }
bool sse() { return cpuid == 2 && util.cpuid.sse(); }
bool sse2() { return cpuid == 3 && util.cpuid.sse2(); }
bool amd3dnow() { return cpuid == 4 && util.cpuid.amd3dnow(); }
}
else
{
alias util.cpuid.mmx mmx;
alias util.cpuid.sse sse;
alias util.cpuid.sse2 sse2;
alias util.cpuid.amd3dnow amd3dnow;
}
//version = log;
bool disjoint(T)(T[] a, T[] b)
{
return (a.ptr + a.length <= b.ptr || b.ptr + b.length <= a.ptr);
}
alias real T;
extern (C):
/* ======================================================================== */
/***********************
* Computes:
* a[] = b[] + c[]
*/
T[] _arraySliceSliceAddSliceAssign_r(T[] a, T[] c, T[] b)
in
{
assert(a.length == b.length && b.length == c.length);
assert(disjoint(a, b));
assert(disjoint(a, c));
assert(disjoint(b, c));
}
body
{
for (int i = 0; i < a.length; i++)
a[i] = b[i] + c[i];
return a;
}
unittest
{
printf("_arraySliceSliceAddSliceAssign_r unittest\n");
for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
{
version (log) printf(" cpuid %d\n", cpuid);
for (int j = 0; j < 2; j++)
{
const int dim = 67;
T[] a = new T[dim + j]; // aligned on 16 byte boundary
a = a[j .. dim + j]; // misalign for second iteration
T[] b = new T[dim + j];
b = b[j .. dim + j];
T[] c = new T[dim + j];
c = c[j .. dim + j];
for (int i = 0; i < dim; i++)
{ a[i] = cast(T)i;
b[i] = cast(T)(i + 7);
c[i] = cast(T)(i * 2);
}
c[] = a[] + b[];
for (int i = 0; i < dim; i++)
{
if (c[i] != cast(T)(a[i] + b[i]))
{
printf("[%d]: %Lg != %Lg + %Lg\n", i, c[i], a[i], b[i]);
assert(0);
}
}
}
}
}
/* ======================================================================== */
/***********************
* Computes:
* a[] = b[] - c[]
*/
T[] _arraySliceSliceMinSliceAssign_r(T[] a, T[] c, T[] b)
in
{
assert(a.length == b.length && b.length == c.length);
assert(disjoint(a, b));
assert(disjoint(a, c));
assert(disjoint(b, c));
}
body
{
for (int i = 0; i < a.length; i++)
a[i] = b[i] - c[i];
return a;
}
unittest
{
printf("_arraySliceSliceMinSliceAssign_r unittest\n");
for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
{
version (log) printf(" cpuid %d\n", cpuid);
for (int j = 0; j < 2; j++)
{
const int dim = 67;
T[] a = new T[dim + j]; // aligned on 16 byte boundary
a = a[j .. dim + j]; // misalign for second iteration
T[] b = new T[dim + j];
b = b[j .. dim + j];
T[] c = new T[dim + j];
c = c[j .. dim + j];
for (int i = 0; i < dim; i++)
{ a[i] = cast(T)i;
b[i] = cast(T)(i + 7);
c[i] = cast(T)(i * 2);
}
c[] = a[] - b[];
for (int i = 0; i < dim; i++)
{
if (c[i] != cast(T)(a[i] - b[i]))
{
printf("[%d]: %Lg != %Lg - %Lg\n", i, c[i], a[i], b[i]);
assert(0);
}
}
}
}
}
/* ======================================================================== */
/***********************
* Computes:
* a[] -= b[] * value
*/
T[] _arraySliceExpMulSliceMinass_r(T[] a, T value, T[] b)
{
return _arraySliceExpMulSliceAddass_r(a, -value, b);
}
/***********************
* Computes:
* a[] += b[] * value
*/
T[] _arraySliceExpMulSliceAddass_r(T[] a, T value, T[] b)
in
{
assert(a.length == b.length);
assert(disjoint(a, b));
}
body
{
auto aptr = a.ptr;
auto aend = aptr + a.length;
auto bptr = b.ptr;
// Handle remainder
while (aptr < aend)
*aptr++ += *bptr++ * value;
return a;
}
unittest
{
printf("_arraySliceExpMulSliceAddass_r unittest\n");
cpuid = 1;
{
version (log) printf(" cpuid %d\n", cpuid);
for (int j = 0; j < 1; j++)
{
const int dim = 67;
T[] a = new T[dim + j]; // aligned on 16 byte boundary
a = a[j .. dim + j]; // misalign for second iteration
T[] b = new T[dim + j];
b = b[j .. dim + j];
T[] c = new T[dim + j];
c = c[j .. dim + j];
for (int i = 0; i < dim; i++)
{ a[i] = cast(T)i;
b[i] = cast(T)(i + 7);
c[i] = cast(T)(i * 2);
}
b[] = c[];
c[] += a[] * 6;
for (int i = 0; i < dim; i++)
{
//printf("[%d]: %Lg ?= %Lg + %Lg * 6\n", i, c[i], b[i], a[i]);
if (c[i] != cast(T)(b[i] + a[i] * 6))
{
printf("[%d]: %Lg ?= %Lg + %Lg * 6\n", i, c[i], b[i], a[i]);
assert(0);
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,184 @@
/*
* Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
* Written by Walter Bright
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, in both source and binary form, subject to the following
* restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
/*
* Modified by Sean Kelly for use with the D Runtime Project
*/
module rt.cast_;
extern (C):
/******************************************
* 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);
}

View File

@@ -0,0 +1,218 @@
// Copyright (C) 2001-2003 by Digital Mars
// All Rights Reserved
// www.digitalmars.com
// Runtime support for complex arithmetic code generation
// (for linux)
/*
* Modified by Sean Kelly for use with the D Runtime Project
*/
module rt.cmath2;
private import stdc.math;
extern (C):
/****************************
* Multiply two complex floating point numbers, x and y.
* Input:
* x.re ST3
* x.im ST2
* y.re ST1
* y.im ST0
* Output:
* ST1 real part
* ST0 imaginary part
*/
void _Cmul()
{
// p.re = x.re * y.re - x.im * y.im;
// p.im = x.im * y.re + x.re * y.im;
asm
{ naked ;
fld ST(1) ; // x.re
fmul ST,ST(4) ; // ST0 = x.re * y.re
fld ST(1) ; // y.im
fmul ST,ST(4) ; // ST0 = x.im * y.im
fsubp ST(1),ST ; // ST0 = x.re * y.re - x.im * y.im
fld ST(3) ; // x.im
fmul ST,ST(3) ; // ST0 = x.im * y.re
fld ST(5) ; // x.re
fmul ST,ST(3) ; // ST0 = x.re * y.im
faddp ST(1),ST ; // ST0 = x.im * y.re + x.re * y.im
fxch ST(4),ST ;
fstp ST(0) ;
fxch ST(4),ST ;
fstp ST(0) ;
fstp ST(0) ;
fstp ST(0) ;
ret ;
}
/+
if (isnan(x) && isnan(y))
{
// Recover infinities that computed as NaN+ iNaN ...
int recalc = 0;
if ( isinf( a) || isinf( b) )
{ // z is infinite
// "Box" the infinity and change NaNs in the other factor to 0
a = copysignl( isinf( a) ? 1.0 : 0.0, a);
b = copysignl( isinf( b) ? 1.0 : 0.0, b);
if (isnan( c)) c = copysignl( 0.0, c);
if (isnan( d)) d = copysignl( 0.0, d);
recalc = 1;
}
if (isinf(c) || isinf(d))
{ // w is infinite
// "Box" the infinity and change NaNs in the other factor to 0
c = copysignl( isinf( c) ? 1.0 : 0.0, c);
d = copysignl( isinf( d) ? 1.0 : 0.0, d);
if (isnan( a)) a = copysignl( 0.0, a);
if (isnan( b)) b = copysignl( 0.0, b);
recalc = 1;
}
if (!recalc && (isinf(ac) || isinf(bd) ||
isinf(ad) || isinf(bc)))
{
// Recover infinities from overflow by changing NaNs to 0 ...
if (isnan( a)) a = copysignl( 0.0, a);
if (isnan( b)) b = copysignl( 0.0, b);
if (isnan( c)) c = copysignl( 0.0, c);
if (isnan( d)) d = copysignl( 0.0, d);
recalc = 1;
}
if (recalc)
{
x = INFINITY * (a * c - b * d);
y = INFINITY * (a * d + b * c);
}
}
+/
}
/****************************
* Divide two complex floating point numbers, x / y.
* Input:
* x.re ST3
* x.im ST2
* y.re ST1
* y.im ST0
* Output:
* ST1 real part
* ST0 imaginary part
*/
void _Cdiv()
{
real x_re, x_im;
real y_re, y_im;
real q_re, q_im;
real r;
real den;
asm
{
fstp y_im ;
fstp y_re ;
fstp x_im ;
fstp x_re ;
}
if (fabs(y_re) < fabs(y_im))
{
r = y_re / y_im;
den = y_im + r * y_re;
q_re = (x_re * r + x_im) / den;
q_im = (x_im * r - x_re) / den;
}
else
{
r = y_im / y_re;
den = y_re + r * y_im;
q_re = (x_re + r * x_im) / den;
q_im = (x_im - r * x_re) / den;
}
//printf("q.re = %g, q.im = %g\n", (double)q_re, (double)q_im);
/+
if (isnan(q_re) && isnan(q_im))
{
real denom = y_re * y_re + y_im * y_im;
// non-zero / zero
if (denom == 0.0 && (!isnan(x_re) || !isnan(x_im)))
{
q_re = copysignl(INFINITY, y_re) * x_re;
q_im = copysignl(INFINITY, y_re) * x_im;
}
// infinite / finite
else if ((isinf(x_re) || isinf(x_im)) && isfinite(y_re) && isfinite(y_im))
{
x_re = copysignl(isinf(x_re) ? 1.0 : 0.0, x_re);
x_im = copysignl(isinf(x_im) ? 1.0 : 0.0, x_im);
q_re = INFINITY * (x_re * y_re + x_im * y_im);
q_im = INFINITY * (x_im * y_re - x_re * y_im);
}
// finite / infinite
else if (isinf(logbw) && isfinite(x_re) && isfinite(x_im))
{
y_re = copysignl(isinf(y_re) ? 1.0 : 0.0, y_re);
y_im = copysignl(isinf(y_im) ? 1.0 : 0.0, y_im);
q_re = 0.0 * (x_re * y_re + x_im * y_im);
q_im = 0.0 * (x_im * y_re - x_re * y_im);
}
}
return q_re + q_im * 1.0i;
+/
asm
{
fld q_re;
fld q_im;
}
}
/****************************
* Compare two complex floating point numbers, x and y.
* Input:
* x.re ST3
* x.im ST2
* y.re ST1
* y.im ST0
* Output:
* 8087 stack is cleared
* flags set
*/
void _Ccmp()
{
asm
{ naked ;
fucomp ST(2) ; // compare x.im and y.im
fstsw AX ;
sahf ;
jne L1 ;
jp L1 ; // jmp if NAN
fucomp ST(2) ; // compare x.re and y.re
fstsw AX ;
sahf ;
fstp ST(0) ; // pop
fstp ST(0) ; // pop
ret ;
L1:
fstp ST(0) ; // pop
fstp ST(0) ; // pop
fstp ST(0) ; // pop
ret ;
}
}

View File

@@ -0,0 +1,36 @@
/* Written by Walter Bright
* www.digitalmars.com
* Placed into Public Domain
*/
module rt.compiler;
// Identify the compiler used and its various features.
const
{
// Vendor specific string naming the compiler
char[] name = "Digital Mars D";
// Master list of D compiler vendors
enum Vendor
{
DigitalMars = 1
}
// Which vendor we are
Vendor vendor = Vendor.DigitalMars;
// The vendor specific version number, as in
// version_major.version_minor
uint version_major = 0;
uint version_minor = 0;
// The version of the D Programming Language Specification
// Supported by the compiler
uint D_major = 0;
uint D_minor = 0;
}

View File

@@ -0,0 +1,107 @@
/*
* Placed into the public domain.
* Written by Walter Bright
* www.digitalmars.com
*/
#include <math.h>
typedef struct Complex
{
long double re;
long double im;
} Complex;
Complex _complex_div(Complex x, Complex y)
{
Complex q;
long double r;
long double den;
if (fabs(y.re) < fabs(y.im))
{
r = y.re / y.im;
den = y.im + r * y.re;
q.re = (x.re * r + x.im) / den;
q.im = (x.im * r - x.re) / den;
}
else
{
r = y.im / y.re;
den = y.re + r * y.im;
q.re = (x.re + r * x.im) / den;
q.im = (x.im - r * x.re) / den;
}
return q;
}
Complex _complex_mul(Complex x, Complex y)
{
Complex p;
p.re = x.re * y.re - x.im * y.im;
p.im = x.im * y.re + x.re * y.im;
return p;
}
long double _complex_abs(Complex z)
{
long double x,y,ans,temp;
x = fabs(z.re);
y = fabs(z.im);
if (x == 0)
ans = y;
else if (y == 0)
ans = x;
else if (x > y)
{
temp = y / x;
ans = x * sqrt(1 + temp * temp);
}
else
{
temp = x / y;
ans = y * sqrt(1 + temp * temp);
}
return ans;
}
Complex _complex_sqrt(Complex z)
{
Complex c;
long double x,y,w,r;
if (z.re == 0 && z.im == 0)
{
c.re = 0;
c.im = 0;
}
else
{
x = fabs(z.re);
y = fabs(z.im);
if (x >= y)
{
r = y / x;
w = sqrt(x) * sqrt(0.5 * (1 + sqrt(1 + r * r)));
}
else
{
r = x / y;
w = sqrt(y) * sqrt(0.5 * (r + sqrt(1 + r * r)));
}
if (z.re >= 0)
{
c.re = w;
c.im = z.im / (w + w);
}
else
{
c.im = (z.im >= 0) ? w : -w;
c.re = z.im / (c.im + c.im);
}
}
return c;
}

View File

@@ -0,0 +1,373 @@
/**
* Code coverage analyzer.
*
* Bugs:
* $(UL
* $(LI the execution counters are 32 bits in size, and can overflow)
* $(LI inline asm statements are not counted)
* )
*
* Copyright: Copyright (C) 2005-2006 Digital Mars, www.digitalmars.com. All rights reserved.
* License: BSD style: $(LICENSE)
* Authors: Walter Bright, Sean Kelly
*/
module rt.cover;
private
{
version( Windows )
import sys.windows.windows;
else version( Posix )
{
import stdc.posix.fcntl;
import stdc.posix.unistd;
}
import core.bitmanip;
import stdc.stdio;
import util.utf;
struct BitArray
{
size_t len;
uint* ptr;
bool opIndex( size_t i )
in
{
assert( i < len );
}
body
{
return cast(bool) bt( ptr, i );
}
}
struct Cover
{
char[] filename;
BitArray valid;
uint[] data;
}
Cover[] gdata;
char[] srcpath;
char[] dstpath;
bool merge;
}
/**
* Set path to where source files are located.
*
* Params:
* pathname = The new path name.
*/
extern (C) void dmd_coverSourcePath( char[] pathname )
{
srcpath = pathname;
}
/**
* Set path to where listing files are to be written.
*
* Params:
* pathname = The new path name.
*/
extern (C) void dmd_coverDestPath( char[] pathname )
{
dstpath = pathname;
}
/**
* Set merge mode.
*
* Params:
* flag = true means new data is summed with existing data in the listing
* file; false means a new listing file is always created.
*/
extern (C) void dmd_coverSetMerge( bool flag )
{
merge = flag;
}
/**
* The coverage callback.
*
* Params:
* filename = The name of the coverage file.
* valid = ???
* data = ???
*/
extern (C) void _d_cover_register( char[] filename, BitArray valid, uint[] data )
{
Cover c;
c.filename = filename;
c.valid = valid;
c.data = data;
gdata ~= c;
}
static ~this()
{
const NUMLINES = 16384 - 1;
const NUMCHARS = 16384 * 16 - 1;
char[] srcbuf = new char[NUMCHARS];
char[][] srclines = new char[][NUMLINES];
char[] lstbuf = new char[NUMCHARS];
char[][] lstlines = new char[][NUMLINES];
foreach( Cover c; gdata )
{
if( !readFile( appendFN( srcpath, c.filename ), srcbuf ) )
continue;
splitLines( srcbuf, srclines );
if( merge )
{
if( !readFile( c.filename ~ ".lst", lstbuf ) )
break;
splitLines( lstbuf, lstlines );
for( size_t i = 0; i < lstlines.length; ++i )
{
if( i >= c.data.length )
break;
int count = 0;
foreach( char c2; lstlines[i] )
{
switch( c2 )
{
case ' ':
continue;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
count = count * 10 + c2 - '0';
continue;
default:
break;
}
}
c.data[i] += count;
}
}
FILE* flst = fopen( (c.filename ~ ".lst").ptr, "wb" );
if( !flst )
continue; //throw new Exception( "Error opening file for write: " ~ lstfn );
uint nno;
uint nyes;
for( int i = 0; i < c.data.length; i++ )
{
if( i < srclines.length )
{
uint n = c.data[i];
char[] line = srclines[i];
line = expandTabs( line );
if( n == 0 )
{
if( c.valid[i] )
{
nno++;
fprintf( flst, "0000000|%.*s\n", line );
}
else
{
fprintf( flst, " |%.*s\n", line );
}
}
else
{
nyes++;
fprintf( flst, "%7u|%.*s\n", n, line );
}
}
}
if( nyes + nno ) // no divide by 0 bugs
{
fprintf( flst, "%.*s is %d%% covered\n", c.filename, ( nyes * 100 ) / ( nyes + nno ) );
}
fclose( flst );
}
}
char[] appendFN( char[] path, char[] name )
{
version( Windows )
const char sep = '\\';
else
const char sep = '/';
char[] dest = path;
if( dest && dest[$ - 1] != sep )
dest ~= sep;
dest ~= name;
return dest;
}
bool readFile( char[] name, inout char[] buf )
{
version( Windows )
{
auto wnamez = toUTF16z( name );
HANDLE file = CreateFileW( wnamez,
GENERIC_READ,
FILE_SHARE_READ,
null,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
cast(HANDLE) null );
delete wnamez;
if( file == INVALID_HANDLE_VALUE )
return false;
scope( exit ) CloseHandle( file );
DWORD num = 0;
DWORD pos = 0;
buf.length = 4096;
while( true )
{
if( !ReadFile( file, &buf[pos], cast(DWORD)( buf.length - pos ), &num, null ) )
return false;
if( !num )
break;
pos += num;
buf.length = pos * 2;
}
buf.length = pos;
return true;
}
else version( linux )
{
char[] namez = new char[name.length + 1];
namez[0 .. name.length] = name;
namez[$ - 1] = 0;
int file = open( namez.ptr, O_RDONLY );
delete namez;
if( file == -1 )
return false;
scope( exit ) close( file );
int num = 0;
uint pos = 0;
buf.length = 4096;
while( true )
{
num = read( file, &buf[pos], cast(uint)( buf.length - pos ) );
if( num == -1 )
return false;
if( !num )
break;
pos += num;
buf.length = pos * 2;
}
buf.length = pos;
return true;
}
}
void splitLines( char[] buf, inout char[][] lines )
{
size_t beg = 0,
pos = 0;
lines.length = 0;
for( ; pos < buf.length; ++pos )
{
char c = buf[pos];
switch( buf[pos] )
{
case '\r':
case '\n':
lines ~= buf[beg .. pos];
beg = pos + 1;
if( buf[pos] == '\r' && pos < buf.length - 1 && buf[pos + 1] == '\n' )
++pos, ++beg;
default:
continue;
}
}
if( beg != pos )
{
lines ~= buf[beg .. pos];
}
}
char[] expandTabs( char[] string, int tabsize = 8 )
{
const dchar LS = '\u2028'; // UTF line separator
const dchar PS = '\u2029'; // UTF paragraph separator
bool changes = false;
char[] result = string;
int column;
int nspaces;
foreach( size_t i, dchar c; string )
{
switch( c )
{
case '\t':
nspaces = tabsize - (column % tabsize);
if( !changes )
{
changes = true;
result = null;
result.length = string.length + nspaces - 1;
result.length = i + nspaces;
result[0 .. i] = string[0 .. i];
result[i .. i + nspaces] = ' ';
}
else
{ int j = result.length;
result.length = j + nspaces;
result[j .. j + nspaces] = ' ';
}
column += nspaces;
break;
case '\r':
case '\n':
case PS:
case LS:
column = 0;
goto L1;
default:
column++;
L1:
if (changes)
{
if (c <= 0x7F)
result ~= c;
else
encode(result, c);
}
break;
}
}
return result;
}

View File

@@ -0,0 +1,159 @@
/*
* Placed into the Public Domain
* written by Walter Bright, Digital Mars
* www.digitalmars.com
*/
/* ================================= Win32 ============================ */
#if _WIN32
#include <windows.h>
/******************************************
* Enter/exit critical section.
*/
/* We don't initialize critical sections unless we actually need them.
* So keep a linked list of the ones we do use, and in the static destructor
* code, walk the list and release them.
*/
typedef struct D_CRITICAL_SECTION
{
struct D_CRITICAL_SECTION *next;
CRITICAL_SECTION cs;
} D_CRITICAL_SECTION;
static D_CRITICAL_SECTION *dcs_list;
static D_CRITICAL_SECTION critical_section;
static volatile int inited;
void _d_criticalenter(D_CRITICAL_SECTION *dcs)
{
if (!dcs->next)
{
EnterCriticalSection(&critical_section.cs);
if (!dcs->next) // if, in the meantime, another thread didn't set it
{
dcs->next = dcs_list;
dcs_list = dcs;
InitializeCriticalSection(&dcs->cs);
}
LeaveCriticalSection(&critical_section.cs);
}
EnterCriticalSection(&dcs->cs);
}
void _d_criticalexit(D_CRITICAL_SECTION *dcs)
{
LeaveCriticalSection(&dcs->cs);
}
void _STI_critical_init()
{
if (!inited)
{ InitializeCriticalSection(&critical_section.cs);
dcs_list = &critical_section;
inited = 1;
}
}
void _STD_critical_term()
{
if (inited)
{ inited = 0;
while (dcs_list)
{
DeleteCriticalSection(&dcs_list->cs);
dcs_list = dcs_list->next;
}
}
}
#endif
/* ================================= linux ============================ */
#if linux
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
/******************************************
* Enter/exit critical section.
*/
/* We don't initialize critical sections unless we actually need them.
* So keep a linked list of the ones we do use, and in the static destructor
* code, walk the list and release them.
*/
typedef struct D_CRITICAL_SECTION
{
struct D_CRITICAL_SECTION *next;
pthread_mutex_t cs;
} D_CRITICAL_SECTION;
static D_CRITICAL_SECTION *dcs_list;
static D_CRITICAL_SECTION critical_section;
static pthread_mutexattr_t _criticals_attr;
void _STI_critical_init(void);
void _STD_critical_term(void);
void _d_criticalenter(D_CRITICAL_SECTION *dcs)
{
if (!dcs_list)
{ _STI_critical_init();
atexit(_STD_critical_term);
}
//printf("_d_criticalenter(dcs = x%x)\n", dcs);
if (!dcs->next)
{
pthread_mutex_lock(&critical_section.cs);
if (!dcs->next) // if, in the meantime, another thread didn't set it
{
dcs->next = dcs_list;
dcs_list = dcs;
pthread_mutex_init(&dcs->cs, &_criticals_attr);
}
pthread_mutex_unlock(&critical_section.cs);
}
pthread_mutex_lock(&dcs->cs);
}
void _d_criticalexit(D_CRITICAL_SECTION *dcs)
{
//printf("_d_criticalexit(dcs = x%x)\n", dcs);
pthread_mutex_unlock(&dcs->cs);
}
void _STI_critical_init()
{
if (!dcs_list)
{ //printf("_STI_critical_init()\n");
pthread_mutexattr_init(&_criticals_attr);
pthread_mutexattr_settype(&_criticals_attr, PTHREAD_MUTEX_RECURSIVE_NP);
// The global critical section doesn't need to be recursive
pthread_mutex_init(&critical_section.cs, 0);
dcs_list = &critical_section;
}
}
void _STD_critical_term()
{
if (dcs_list)
{ //printf("_STI_critical_term()\n");
while (dcs_list)
{
//printf("\tlooping... %x\n", dcs_list);
pthread_mutex_destroy(&dcs_list->cs);
dcs_list = dcs_list->next;
}
}
}
#endif

View File

@@ -0,0 +1,662 @@
//
// Copyright (c) 1999-2003 by Digital Mars, www.digitalmars.com
// All Rights Reserved
// Written by Walter Bright
// Exception handling support
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
/* ======================== Win32 =============================== */
#if _WIN32
#include <excpt.h>
#include <windows.h>
//#include "\sc\src\include\ehsup.h"
/*** From Digital Mars C runtime library ***/
EXCEPTION_DISPOSITION __cdecl _local_except_handler (EXCEPTION_RECORD *ExceptionRecord,
void* EstablisherFrame,
void *ContextRecord,
void *DispatcherContext
);
void __cdecl _global_unwind(void *frame,EXCEPTION_RECORD *eRecord);
#define EXCEPTION_UNWIND 6 // Flag to indicate if the system is unwinding
extern DWORD _except_list;
/*** ***/
#include "mars.h"
extern ClassInfo D6object9Throwable7__ClassZ;
#define _Class_9Throwable D6object9Throwable7__ClassZ;
extern ClassInfo D6object5Error7__ClassZ;
#define _Class_5Error D6object5Error7__ClassZ
typedef int (__pascal *fp_t)(); // function pointer in ambient memory model
// The layout of DEstablisherFrame is the same for C++
struct DEstablisherFrame
{
void *prev; // pointer to previous exception list
void *handler; // pointer to routine for exception handler
DWORD table_index; // current index into handler_info[]
DWORD ebp; // this is EBP of routine
};
struct DHandlerInfo
{
int prev_index; // previous table index
unsigned cioffset; // offset to DCatchInfo data from start of table (!=0 if try-catch)
void *finally_code; // pointer to finally code to execute
// (!=0 if try-finally)
};
// Address of DHandlerTable is passed in EAX to _d_framehandler()
struct DHandlerTable
{
void *fptr; // pointer to start of function
unsigned espoffset; // offset of ESP from EBP
unsigned retoffset; // offset from start of function to return code
struct DHandlerInfo handler_info[1];
};
struct DCatchBlock
{
ClassInfo *type; // catch type
unsigned bpoffset; // EBP offset of catch var
void *code; // catch handler code
};
// Create one of these for each try-catch
struct DCatchInfo
{
unsigned ncatches; // number of catch blocks
struct DCatchBlock catch_block[1]; // data for each catch block
};
// Macro to make our own exception code
#define MAKE_EXCEPTION_CODE(severity, facility, exception) \
(((severity) << 30) | (1 << 29) | (0 << 28) | ((facility) << 16) | (exception))
#define STATUS_DIGITAL_MARS_D_EXCEPTION MAKE_EXCEPTION_CODE(3,'D',1)
Object *_d_translate_se_to_d_exception(EXCEPTION_RECORD *exception_record);
void __cdecl _d_local_unwind(struct DHandlerTable *handler_table, struct DEstablisherFrame *frame, int stop_index);
/***********************************
* The frame handler, this is called for each frame that has been registered
* in the OS except_list.
* Input:
* EAX the handler table for the frame
*/
EXCEPTION_DISPOSITION _d_framehandler(
EXCEPTION_RECORD *exception_record,
struct DEstablisherFrame *frame,
CONTEXT context,
void *dispatcher_context)
{
struct DHandlerTable *handler_table;
__asm { mov handler_table,EAX }
if (exception_record->ExceptionFlags & EXCEPTION_UNWIND)
{
// Call all the finally blocks in this frame
_d_local_unwind(handler_table, frame, -1);
}
else
{
// Jump to catch block if matching one is found
int ndx,prev_ndx,i;
struct DHandlerInfo *phi;
struct DCatchInfo *pci;
struct DCatchBlock *pcb;
unsigned ncatches; // number of catches in the current handler
Object *pti;
ClassInfo *ci;
ci = NULL; // only compute it if we need it
// walk through handler table, checking each handler
// with an index smaller than the current table_index
for (ndx = frame->table_index; ndx != -1; ndx = prev_ndx)
{
phi = &handler_table->handler_info[ndx];
prev_ndx = phi->prev_index;
if (phi->cioffset)
{
// this is a catch handler (no finally)
pci = (struct DCatchInfo *)((char *)handler_table + phi->cioffset);
ncatches = pci->ncatches;
for (i = 0; i < ncatches; i++)
{
pcb = &pci->catch_block[i];
if (!ci)
{
// This code must match the translation code
if (exception_record->ExceptionCode == STATUS_DIGITAL_MARS_D_EXCEPTION)
{
//printf("ei[0] = %p\n", exception_record->ExceptionInformation[0]);
ci = **(ClassInfo ***)(exception_record->ExceptionInformation[0]);
}
else
ci = &_Class_9Throwable;
}
if (_d_isbaseof(ci, pcb->type))
{
// Matched the catch type, so we've found the handler.
int regebp;
pti = _d_translate_se_to_d_exception(exception_record);
// Initialize catch variable
regebp = (int)&frame->ebp; // EBP for this frame
*(void **)(regebp + (pcb->bpoffset)) = pti;
// Have system call all finally blocks in intervening frames
_global_unwind(frame, exception_record);
// Call all the finally blocks skipped in this frame
_d_local_unwind(handler_table, frame, ndx);
frame->table_index = prev_ndx; // we are out of this handler
// Jump to catch block. Does not return.
{
unsigned catch_esp;
fp_t catch_addr;
catch_addr = (fp_t)(pcb->code);
catch_esp = regebp - handler_table->espoffset - sizeof(fp_t);
_asm
{
mov EAX,catch_esp
mov ECX,catch_addr
mov [EAX],ECX
mov EBP,regebp
mov ESP,EAX // reset stack
ret // jump to catch block
}
}
}
}
}
}
}
return ExceptionContinueSearch;
}
/***********************************
* Exception filter for use in __try..__except block
* surrounding call to Dmain()
*/
int _d_exception_filter(struct _EXCEPTION_POINTERS *eptrs,
int retval,
Object **exception_object)
{
*exception_object = _d_translate_se_to_d_exception(eptrs->ExceptionRecord);
return retval;
}
/***********************************
* Throw a D object.
*/
void __stdcall _d_throw(Object *h)
{
//printf("_d_throw(h = %p, &h = %p)\n", h, &h);
//printf("\tvptr = %p\n", *(void **)h);
RaiseException(STATUS_DIGITAL_MARS_D_EXCEPTION,
EXCEPTION_NONCONTINUABLE,
1, (DWORD *)&h);
}
/***********************************
* Create an exception object
*/
Object *_d_create_exception_object(ClassInfo *ci, char *msg)
{
Throwable *exc;
exc = (Throwable *)_d_newclass(ci);
// BUG: what if _d_newclass() throws an out of memory exception?
if (msg)
{
exc->msglen = strlen(msg);
exc->msg = msg;
}
return (Object *)exc;
}
/***********************************
* Converts a Windows Structured Exception code to a D Exception Object.
*/
Object *_d_translate_se_to_d_exception(EXCEPTION_RECORD *exception_record)
{
Object *pti;
switch (exception_record->ExceptionCode) {
case STATUS_DIGITAL_MARS_D_EXCEPTION:
// Generated D exception
pti = (Object *)(exception_record->ExceptionInformation[0]);
break;
case STATUS_INTEGER_DIVIDE_BY_ZERO:
pti = _d_create_exception_object(&_Class_5Error, "Integer Divide by Zero");
break;
case STATUS_FLOAT_DIVIDE_BY_ZERO:
pti = _d_create_exception_object(&_Class_5Error, "Float Divide by Zero");
break;
case STATUS_ACCESS_VIOLATION:
pti = _d_create_exception_object(&_Class_5Error, "Access Violation");
break;
case STATUS_STACK_OVERFLOW:
pti = _d_create_exception_object(&_Class_5Error, "Stack Overflow");
break;
// convert all other exception codes into a Win32Exception
default:
pti = _d_create_exception_object(&_Class_5Error, "Win32 Exception");
break;
}
return pti;
}
/**************************************
* Call finally blocks in the current stack frame until stop_index.
* This is roughly equivalent to _local_unwind() for C in \src\win32\ehsup.c
*/
void __cdecl _d_local_unwind(struct DHandlerTable *handler_table,
struct DEstablisherFrame *frame, int stop_index)
{
struct DHandlerInfo *phi;
struct DCatchInfo *pci;
int i;
// Set up a special exception handler to catch double-fault exceptions.
__asm
{
push dword ptr -1
push dword ptr 0
push offset _local_except_handler // defined in src\win32\ehsup.c
push dword ptr fs:_except_list
mov FS:_except_list,ESP
}
for (i = frame->table_index; i != -1 && i != stop_index; i = phi->prev_index)
{
phi = &handler_table->handler_info[i];
if (phi->finally_code)
{
// Note that it is unnecessary to adjust the ESP, as the finally block
// accesses all items on the stack as relative to EBP.
DWORD *catch_ebp = &frame->ebp;
void *blockaddr = phi->finally_code;
_asm
{
push EBX
mov EBX,blockaddr
push EBP
mov EBP,catch_ebp
call EBX
pop EBP
pop EBX
}
}
}
_asm
{
pop FS:_except_list
add ESP,12
}
}
/***********************************
* external version of the unwinder
*/
__declspec(naked) void __cdecl _d_local_unwind2()
{
__asm
{
jmp _d_local_unwind
}
}
/***********************************
* The frame handler, this is called for each frame that has been registered
* in the OS except_list.
* Input:
* EAX the handler table for the frame
*/
EXCEPTION_DISPOSITION _d_monitor_handler(
EXCEPTION_RECORD *exception_record,
struct DEstablisherFrame *frame,
CONTEXT context,
void *dispatcher_context)
{
if (exception_record->ExceptionFlags & EXCEPTION_UNWIND)
{
_d_monitorexit((Object *)frame->table_index);
}
else
{
}
return ExceptionContinueSearch;
}
/***********************************
*/
void _d_monitor_prolog(void *x, void *y, Object *h)
{
__asm
{
push EAX
}
//printf("_d_monitor_prolog(x=%p, y=%p, h=%p)\n", x, y, h);
_d_monitorenter(h);
__asm
{
pop EAX
}
}
/***********************************
*/
void _d_monitor_epilog(void *x, void *y, Object *h)
{
//printf("_d_monitor_epilog(x=%p, y=%p, h=%p)\n", x, y, h);
__asm
{
push EAX
push EDX
}
_d_monitorexit(h);
__asm
{
pop EDX
pop EAX
}
}
#endif
/* ======================== linux =============================== */
#if linux
#include "mars.h"
extern ClassInfo D6object9Throwable7__ClassZ;
#define _Class_9Throwable D6object9Throwable7__ClassZ;
extern ClassInfo D6object5Error7__ClassZ;
#define _Class_5Error D6object5Error7__ClassZ
typedef int (*fp_t)(); // function pointer in ambient memory model
struct DHandlerInfo
{
unsigned offset; // offset from function address to start of guarded section
int prev_index; // previous table index
unsigned cioffset; // offset to DCatchInfo data from start of table (!=0 if try-catch)
void *finally_code; // pointer to finally code to execute
// (!=0 if try-finally)
};
// Address of DHandlerTable, searched for by eh_finddata()
struct DHandlerTable
{
void *fptr; // pointer to start of function
unsigned espoffset; // offset of ESP from EBP
unsigned retoffset; // offset from start of function to return code
unsigned nhandlers; // dimension of handler_info[]
struct DHandlerInfo handler_info[1];
};
struct DCatchBlock
{
ClassInfo *type; // catch type
unsigned bpoffset; // EBP offset of catch var
void *code; // catch handler code
};
// Create one of these for each try-catch
struct DCatchInfo
{
unsigned ncatches; // number of catch blocks
struct DCatchBlock catch_block[1]; // data for each catch block
};
// One of these is generated for each function with try-catch or try-finally
struct FuncTable
{
void *fptr; // pointer to start of function
struct DHandlerTable *handlertable; // eh data for this function
unsigned size; // size of function in bytes
};
extern struct FuncTable *table_start;
extern struct FuncTable *table_end;
void terminate()
{
// _asm
// {
// hlt
// }
}
/*******************************************
* Given address that is inside a function,
* figure out which function it is in.
* Return DHandlerTable if there is one, NULL if not.
*/
struct DHandlerTable *__eh_finddata(void *address)
{
struct FuncTable *ft;
for (ft = (struct FuncTable *)table_start;
ft < (struct FuncTable *)table_end;
ft++)
{
if (ft->fptr <= address &&
address < (void *)((char *)ft->fptr + ft->size))
{
return ft->handlertable;
}
}
return NULL;
}
/******************************
* Given EBP, find return address to caller, and caller's EBP.
* Input:
* regbp Value of EBP for current function
* *pretaddr Return address
* Output:
* *pretaddr return address to caller
* Returns:
* caller's EBP
*/
unsigned __eh_find_caller(unsigned regbp, unsigned *pretaddr)
{
unsigned bp = *(unsigned *)regbp;
if (bp) // if not end of call chain
{
// Perform sanity checks on new EBP.
// If it is screwed up, terminate() hopefully before we do more damage.
if (bp <= regbp)
// stack should grow to smaller values
terminate();
*pretaddr = *(unsigned *)(regbp + sizeof(int));
}
return bp;
}
/***********************************
* Throw a D object.
*/
void __stdcall _d_throw(Object *h)
{
unsigned regebp;
//printf("_d_throw(h = %p, &h = %p)\n", h, &h);
//printf("\tvptr = %p\n", *(void **)h);
regebp = _EBP;
while (1) // for each function on the stack
{
struct DHandlerTable *handler_table;
struct FuncTable *pfunc;
struct DHandlerInfo *phi;
unsigned retaddr;
unsigned funcoffset;
unsigned spoff;
unsigned retoffset;
int index;
int dim;
int ndx;
int prev_ndx;
regebp = __eh_find_caller(regebp,&retaddr);
if (!regebp)
// if end of call chain
break;
handler_table = __eh_finddata((void *)retaddr); // find static data associated with function
if (!handler_table) // if no static data
{
continue;
}
funcoffset = (unsigned)handler_table->fptr;
spoff = handler_table->espoffset;
retoffset = handler_table->retoffset;
#ifdef DEBUG
printf("retaddr = x%x\n",(unsigned)retaddr);
printf("regebp=x%04x, funcoffset=x%04x, spoff=x%x, retoffset=x%x\n",
regebp,funcoffset,spoff,retoffset);
#endif
// Find start index for retaddr in static data
dim = handler_table->nhandlers;
index = -1;
for (int i = 0; i < dim; i++)
{
phi = &handler_table->handler_info[i];
if ((unsigned)retaddr >= funcoffset + phi->offset)
index = i;
}
// walk through handler table, checking each handler
// with an index smaller than the current table_index
for (ndx = index; ndx != -1; ndx = prev_ndx)
{
phi = &handler_table->handler_info[ndx];
prev_ndx = phi->prev_index;
if (phi->cioffset)
{
// this is a catch handler (no finally)
struct DCatchInfo *pci;
int ncatches;
int i;
pci = (struct DCatchInfo *)((char *)handler_table + phi->cioffset);
ncatches = pci->ncatches;
for (i = 0; i < ncatches; i++)
{
struct DCatchBlock *pcb;
ClassInfo *ci = **(ClassInfo ***)h;
pcb = &pci->catch_block[i];
if (_d_isbaseof(ci, pcb->type))
{ // Matched the catch type, so we've found the handler.
// Initialize catch variable
*(void **)(regebp + (pcb->bpoffset)) = h;
// Jump to catch block. Does not return.
{
unsigned catch_esp;
fp_t catch_addr;
catch_addr = (fp_t)(pcb->code);
catch_esp = regebp - handler_table->espoffset - sizeof(fp_t);
_asm
{
mov EAX,catch_esp
mov ECX,catch_addr
mov [EAX],ECX
mov EBP,regebp
mov ESP,EAX // reset stack
ret // jump to catch block
}
}
}
}
}
else if (phi->finally_code)
{ // Call finally block
// Note that it is unnecessary to adjust the ESP, as the finally block
// accesses all items on the stack as relative to EBP.
void *blockaddr = phi->finally_code;
_asm
{
push EBX
mov EBX,blockaddr
push EBP
mov EBP,regebp
call EBX
pop EBP
pop EBX
}
}
}
}
}
#endif

View File

@@ -0,0 +1,308 @@
/*
* Copyright (C) 1999-2005 by Digital Mars, www.digitalmars.com
* Written by Walter Bright
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, in both source and binary form, subject to the following
* restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
module rt.deh2;
// Exception handling support for linux
//debug=1;
extern (C)
{
extern void* _deh_beg;
extern void* _deh_end;
int _d_isbaseof(ClassInfo oc, ClassInfo c);
}
alias int (*fp_t)(); // function pointer in ambient memory model
struct DHandlerInfo
{
uint offset; // offset from function address to start of guarded section
uint endoffset; // offset of end of guarded section
int prev_index; // previous table index
uint cioffset; // offset to DCatchInfo data from start of table (!=0 if try-catch)
void *finally_code; // pointer to finally code to execute
// (!=0 if try-finally)
}
// Address of DHandlerTable, searched for by eh_finddata()
struct DHandlerTable
{
void *fptr; // pointer to start of function
uint espoffset; // offset of ESP from EBP
uint retoffset; // offset from start of function to return code
uint nhandlers; // dimension of handler_info[]
DHandlerInfo handler_info[1];
}
struct DCatchBlock
{
ClassInfo type; // catch type
uint bpoffset; // EBP offset of catch var
void *code; // catch handler code
}
// Create one of these for each try-catch
struct DCatchInfo
{
uint ncatches; // number of catch blocks
DCatchBlock catch_block[1]; // data for each catch block
}
// One of these is generated for each function with try-catch or try-finally
struct FuncTable
{
void *fptr; // pointer to start of function
DHandlerTable *handlertable; // eh data for this function
uint fsize; // size of function in bytes
}
void terminate()
{
asm
{
hlt ;
}
}
/*******************************************
* Given address that is inside a function,
* figure out which function it is in.
* Return DHandlerTable if there is one, NULL if not.
*/
DHandlerTable *__eh_finddata(void *address)
{
FuncTable *ft;
// debug printf("__eh_finddata(address = x%x)\n", address);
// debug printf("_deh_beg = x%x, _deh_end = x%x\n", &_deh_beg, &_deh_end);
for (ft = cast(FuncTable *)&_deh_beg;
ft < cast(FuncTable *)&_deh_end;
ft++)
{
// debug printf("\tfptr = x%x, fsize = x%03x, handlertable = x%x\n",
// ft.fptr, ft.fsize, ft.handlertable);
if (ft.fptr <= address &&
address < cast(void *)(cast(char *)ft.fptr + ft.fsize))
{
// debug printf("\tfound handler table\n");
return ft.handlertable;
}
}
// debug printf("\tnot found\n");
return null;
}
/******************************
* Given EBP, find return address to caller, and caller's EBP.
* Input:
* regbp Value of EBP for current function
* *pretaddr Return address
* Output:
* *pretaddr return address to caller
* Returns:
* caller's EBP
*/
uint __eh_find_caller(uint regbp, uint *pretaddr)
{
uint bp = *cast(uint *)regbp;
if (bp) // if not end of call chain
{
// Perform sanity checks on new EBP.
// If it is screwed up, terminate() hopefully before we do more damage.
if (bp <= regbp)
// stack should grow to smaller values
terminate();
*pretaddr = *cast(uint *)(regbp + int.sizeof);
}
return bp;
}
/***********************************
* Throw a D object.
*/
extern (Windows) void _d_throw(Object *h)
{
uint regebp;
debug
{
printf("_d_throw(h = %p, &h = %p)\n", h, &h);
printf("\tvptr = %p\n", *cast(void **)h);
}
asm
{
mov regebp,EBP ;
}
//static uint abc;
//if (++abc == 2) *(char *)0=0;
//int count = 0;
while (1) // for each function on the stack
{
DHandlerTable *handler_table;
FuncTable *pfunc;
DHandlerInfo *phi;
uint retaddr;
uint funcoffset;
uint spoff;
uint retoffset;
int index;
int dim;
int ndx;
int prev_ndx;
regebp = __eh_find_caller(regebp,&retaddr);
if (!regebp)
{ // if end of call chain
debug printf("end of call chain\n");
break;
}
debug printf("found caller, EBP = x%x, retaddr = x%x\n", regebp, retaddr);
//if (++count == 12) *(char*)0=0;
handler_table = __eh_finddata(cast(void *)retaddr); // find static data associated with function
if (!handler_table) // if no static data
{
debug printf("no handler table\n");
continue;
}
funcoffset = cast(uint)handler_table.fptr;
spoff = handler_table.espoffset;
retoffset = handler_table.retoffset;
debug
{
printf("retaddr = x%x\n",cast(uint)retaddr);
printf("regebp=x%04x, funcoffset=x%04x, spoff=x%x, retoffset=x%x\n",
regebp,funcoffset,spoff,retoffset);
}
// Find start index for retaddr in static data
dim = handler_table.nhandlers;
debug
{
printf("handler_info[]:\n");
for (int i = 0; i < dim; i++)
{
phi = &handler_table.handler_info[i];
printf("\t[%d]: offset = x%04x, endoffset = x%04x, prev_index = %d, cioffset = x%04x, finally_code = %x\n",
i, phi.offset, phi.endoffset, phi.prev_index, phi.cioffset, phi.finally_code);
}
}
index = -1;
for (int i = 0; i < dim; i++)
{
phi = &handler_table.handler_info[i];
debug printf("i = %d, phi.offset = %04x\n", i, funcoffset + phi.offset);
if (cast(uint)retaddr > funcoffset + phi.offset &&
cast(uint)retaddr <= funcoffset + phi.endoffset)
index = i;
}
debug printf("index = %d\n", index);
// walk through handler table, checking each handler
// with an index smaller than the current table_index
for (ndx = index; ndx != -1; ndx = prev_ndx)
{
phi = &handler_table.handler_info[ndx];
prev_ndx = phi.prev_index;
if (phi.cioffset)
{
// this is a catch handler (no finally)
DCatchInfo *pci;
int ncatches;
int i;
pci = cast(DCatchInfo *)(cast(char *)handler_table + phi.cioffset);
ncatches = pci.ncatches;
for (i = 0; i < ncatches; i++)
{
DCatchBlock *pcb;
ClassInfo ci = **cast(ClassInfo **)h;
pcb = &pci.catch_block[i];
if (_d_isbaseof(ci, pcb.type))
{ // Matched the catch type, so we've found the handler.
// Initialize catch variable
*cast(void **)(regebp + (pcb.bpoffset)) = h;
// Jump to catch block. Does not return.
{
uint catch_esp;
fp_t catch_addr;
catch_addr = cast(fp_t)(pcb.code);
catch_esp = regebp - handler_table.espoffset - fp_t.sizeof;
asm
{
mov EAX,catch_esp ;
mov ECX,catch_addr ;
mov [EAX],ECX ;
mov EBP,regebp ;
mov ESP,EAX ; // reset stack
ret ; // jump to catch block
}
}
}
}
}
else if (phi.finally_code)
{ // Call finally block
// Note that it is unnecessary to adjust the ESP, as the finally block
// accesses all items on the stack as relative to EBP.
void *blockaddr = phi.finally_code;
asm
{
push EBX ;
mov EBX,blockaddr ;
push EBP ;
mov EBP,regebp ;
call EBX ;
pop EBP ;
pop EBX ;
}
}
}
}
}

View File

@@ -0,0 +1,315 @@
/*
* Placed into the Public Domain.
* written by Walter Bright
* www.digitalmars.com
*/
/*
* Modified by Sean Kelly for use with the D Runtime Project
*/
module rt.dmain2;
private
{
import util.console;
import stdc.stddef;
import stdc.stdlib;
import stdc.string;
}
version(Windows)
{
extern (Windows) void* LocalFree(void*);
extern (Windows) wchar_t* GetCommandLineW();
extern (Windows) wchar_t** CommandLineToArgvW(wchar_t*, int*);
extern (Windows) export int WideCharToMultiByte(uint, uint, wchar_t*, int, char*, int, char*, int);
pragma(lib, "shell32.lib"); // needed for CommandLineToArgvW
}
extern (C) void _STI_monitor_staticctor();
extern (C) void _STD_monitor_staticdtor();
extern (C) void _STI_critical_init();
extern (C) void _STD_critical_term();
extern (C) void gc_init();
extern (C) void gc_term();
extern (C) void _minit();
extern (C) void _moduleCtor();
extern (C) void _moduleDtor();
extern (C) void thread_joinAll();
/***********************************
* These functions must be defined for any D program linked
* against this library.
*/
extern (C) void onAssertError(string file, size_t line);
extern (C) void onAssertErrorMsg(string file, size_t line, string msg);
extern (C) void onArrayBoundsError(string file, size_t line);
extern (C) void onHiddenFuncError(Object o);
extern (C) void onSwitchError(string file, size_t line);
extern (C) bool runModuleUnitTests();
// this function is called from the utf module
//extern (C) void onUnicodeError(string msg, size_t idx);
/***********************************
* These are internal callbacks for various language errors.
*/
extern (C) void _d_assert(string file, uint line)
{
onAssertError(file, line);
}
extern (C) static void _d_assert_msg(string msg, string file, uint line)
{
onAssertErrorMsg(file, line, msg);
}
extern (C) void _d_array_bounds(string file, uint line)
{
onArrayBoundsError(file, line);
}
extern (C) void _d_switch_error(string file, uint line)
{
onSwitchError(file, line);
}
extern (C) void _d_hidden_func()
{
Object o;
asm
{
mov o, EAX;
}
onHiddenFuncError(o);
}
bool _d_isHalting = false;
extern (C) bool rt_isHalting()
{
return _d_isHalting;
}
extern (C) bool rt_trapExceptions = true;
void _d_criticalInit()
{
version (linux)
{
_STI_monitor_staticctor();
_STI_critical_init();
}
}
alias void delegate(Throwable) ExceptionHandler;
extern (C) bool rt_init(ExceptionHandler dg = null)
{
_d_criticalInit();
try
{
gc_init();
version (Windows)
_minit();
_moduleCtor();
return true;
}
catch (Throwable e)
{
if (dg)
dg(e);
}
catch
{
}
_d_criticalTerm();
return false;
}
void _d_criticalTerm()
{
version (linux)
{
_STD_critical_term();
_STD_monitor_staticdtor();
}
}
extern (C) bool rt_term(ExceptionHandler dg = null)
{
try
{
thread_joinAll();
_d_isHalting = true;
_moduleDtor();
gc_term();
return true;
}
catch (Throwable e)
{
if (dg)
dg(e);
}
catch
{
}
finally
{
_d_criticalTerm();
}
return false;
}
/***********************************
* The D main() function supplied by the user's program
*/
int main(char[][] args);
/***********************************
* Substitutes for the C main() function.
* It's purpose is to wrap the call to the D main()
* function and catch any unhandled exceptions.
*/
extern (C) int main(int argc, char **argv)
{
char[][] args;
int result;
version (linux)
{
_STI_monitor_staticctor();
_STI_critical_init();
}
version (Windows)
{
wchar_t* wcbuf = GetCommandLineW();
size_t wclen = wcslen(wcbuf);
int wargc = 0;
wchar_t** wargs = CommandLineToArgvW(wcbuf, &wargc);
assert(wargc == argc);
char* cargp = null;
size_t cargl = WideCharToMultiByte(65001, 0, wcbuf, wclen, null, 0, null, 0);
cargp = cast(char*) alloca(cargl);
args = ((cast(char[]*) alloca(wargc * (char[]).sizeof)))[0 .. wargc];
for (size_t i = 0, p = 0; i < wargc; i++)
{
int wlen = wcslen(wargs[i]);
int clen = WideCharToMultiByte(65001, 0, &wargs[i][0], wlen, null, 0, null, 0);
args[i] = cargp[p .. p+clen];
p += clen; assert(p <= cargl);
WideCharToMultiByte(65001, 0, &wargs[i][0], wlen, &args[i][0], clen, null, 0);
}
LocalFree(wargs);
wargs = null;
wargc = 0;
}
else version (linux)
{
char[]* am = cast(char[]*) malloc(argc * (char[]).sizeof);
scope(exit) free(am);
for (size_t i = 0; i < argc; i++)
{
auto len = strlen(argv[i]);
am[i] = argv[i][0 .. len];
}
args = am[0 .. argc];
}
bool trapExceptions = rt_trapExceptions;
void tryExec(void delegate() dg)
{
if (trapExceptions)
{
try
{
dg();
}
catch (Throwable e)
{
while (e)
{
if (e.file)
{
// fprintf(stderr, "%.*s(%u): %.*s\n", e.file, e.line, e.msg);
console (e.classinfo.name)("@")(e.file)("(")(e.line)("): ")(e.msg)("\n");
}
else
{
// fprintf(stderr, "%.*s\n", e.toString());
console (e.toString)("\n");
}
if (e.info)
{
console ("----------------\n");
foreach (t; e.info)
console (t)("\n");
}
if (e.next)
console ("\n");
e = e.next;
}
result = EXIT_FAILURE;
}
catch (Object o)
{
// fprintf(stderr, "%.*s\n", o.toString());
console (o.toString)("\n");
result = EXIT_FAILURE;
}
}
else
{
dg();
}
}
// NOTE: The lifetime of a process is much like the lifetime of an object:
// it is initialized, then used, then destroyed. If initialization
// fails, the successive two steps are never reached. However, if
// initialization succeeds, then cleanup will occur even if the use
// step fails in some way. Here, the use phase consists of running
// the user's main function. If main terminates with an exception,
// the exception is handled and then cleanup begins. An exception
// thrown during cleanup, however, will abort the cleanup process.
void runMain()
{
result = main(args);
}
void runAll()
{
gc_init();
version (Windows)
_minit();
_moduleCtor();
if (runModuleUnitTests())
tryExec(&runMain);
thread_joinAll();
_d_isHalting = true;
_moduleDtor();
gc_term();
}
tryExec(&runAll);
version (linux)
{
_STD_critical_term();
_STD_monitor_staticdtor();
}
return result;
}

View File

@@ -0,0 +1,24 @@
/*
* Placed into the Public Domain
* written by Walter Bright
* www.digitalmars.com
*/
void _d_invariant(Object o)
{ ClassInfo c;
//printf("__d_invariant(%p)\n", o);
// BUG: needs to be filename/line of caller, not library routine
assert(o !is null); // just do null check, not invariant check
c = o.classinfo;
do
{
if (c.classInvariant)
{
(*c.classInvariant)(o);
}
c = c.base;
} while (c);
}

View File

@@ -0,0 +1,25 @@
/*
* Placed into the Public Domain
* written by Walter Bright
* www.digitalmars.com
*/
module rt.invariant_;
extern (C) void _d_invariant(Object o)
{ ClassInfo c;
//printf("__d_invariant(%p)\n", o);
// BUG: needs to be filename/line of caller, not library routine
assert(o !is null); // just do null check, not invariant check
c = o.classinfo;
do
{
if (c.classInvariant)
{
(*c.classInvariant)(o);
}
c = c.base;
} while (c);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,295 @@
// llmath.d
// Copyright (C) 1993-2003 by Digital Mars, www.digitalmars.com
// All Rights Reserved
// Written by Walter Bright
module rt.llmath;
// Compiler runtime support for 64 bit longs
extern (C):
/***************************************
* Unsigned long divide.
* Input:
* [EDX,EAX],[ECX,EBX]
* Output:
* [EDX,EAX] = [EDX,EAX] / [ECX,EBX]
* [ECX,EBX] = [EDX,EAX] % [ECX,EBX]
* ESI,EDI destroyed
*/
void __ULDIV__()
{
asm
{
naked ;
test ECX,ECX ;
jz uldiv ;
push EBP ;
// left justify [ECX,EBX] and leave count of shifts + 1 in EBP
mov EBP,1 ; // at least 1 shift
test ECX,ECX ; // left justified?
js L1 ; // yes
jnz L2 ;
add EBP,8 ;
mov CH,CL ;
mov CL,BH ;
mov BH,BL ;
xor BL,BL ; // [ECX,EBX] <<= 8
test ECX,ECX ;
js L1 ;
even ;
L2: inc EBP ; // another shift
shl EBX,1 ;
rcl ECX,1 ; // [ECX,EBX] <<= 1
jno L2 ; // not left justified yet
L1: mov ESI,ECX ;
mov EDI,EBX ; // [ESI,EDI] = divisor
mov ECX,EDX ;
mov EBX,EAX ; // [ECX,EBX] = [EDX,EAX]
xor EAX,EAX ;
cdq ; // [EDX,EAX] = 0
even ;
L4: cmp ESI,ECX ; // is [ECX,EBX] > [ESI,EDI]?
ja L3 ; // yes
jb L5 ; // definitely less than
cmp EDI,EBX ; // check low order word
ja L3 ;
L5: sub EBX,EDI ;
sbb ECX,ESI ; // [ECX,EBX] -= [ESI,EDI]
stc ; // rotate in a 1
L3: rcl EAX,1 ;
rcl EDX,1 ; // [EDX,EAX] = ([EDX,EAX] << 1) + C
shr ESI,1 ;
rcr EDI,1 ; // [ESI,EDI] >>= 1
dec EBP ; // control count
jne L4 ;
pop EBP ;
ret ;
div0: mov EAX,-1 ;
cwd ; // quotient is -1
// xor ECX,ECX ;
// mov EBX,ECX ; // remainder is 0 (ECX and EBX already 0)
pop EBP ;
ret ;
uldiv: test EDX,EDX ;
jnz D3 ;
// Both high words are 0, we can use the DIV instruction
div EBX ;
mov EBX,EDX ;
mov EDX,ECX ; // EDX = ECX = 0
ret ;
even ;
D3: // Divide [EDX,EAX] by EBX
mov ECX,EAX ;
mov EAX,EDX ;
xor EDX,EDX ;
div EBX ;
xchg ECX,EAX ;
div EBX ;
// ECX,EAX = result
// EDX = remainder
mov EBX,EDX ;
mov EDX,ECX ;
xor ECX,ECX ;
ret ;
}
}
/***************************************
* Signed long divide.
* Input:
* [EDX,EAX],[ECX,EBX]
* Output:
* [EDX,EAX] = [EDX,EAX] / [ECX,EBX]
* [ECX,EBX] = [EDX,EAX] % [ECX,EBX]
* ESI,EDI destroyed
*/
void __LDIV__()
{
asm
{
naked ;
test EDX,EDX ; // [EDX,EAX] negative?
jns L10 ; // no
//neg64 EDX,EAX ; // [EDX,EAX] = -[EDX,EAX]
neg EDX ;
neg EAX ;
sbb EDX,0 ;
test ECX,ECX ; // [ECX,EBX] negative?
jns L11 ; // no
//neg64 ECX,EBX ;
neg ECX ;
neg EBX ;
sbb ECX,0 ;
call __ULDIV__ ;
//neg64 ECX,EBX ; // remainder same sign as dividend
neg ECX ;
neg EBX ;
sbb ECX,0 ;
ret ;
L11: call __ULDIV__ ;
//neg64 ECX,EBX ; // remainder same sign as dividend
neg ECX ;
neg EBX ;
sbb ECX,0 ;
//neg64 EDX,EAX ; // quotient is negative
neg EDX ;
neg EAX ;
sbb EDX,0 ;
ret ;
L10: test ECX,ECX ; // [ECX,EBX] negative?
jns L12 ; // no (all is positive)
//neg64 ECX,EBX ;
neg ECX ;
neg EBX ;
sbb ECX,0 ;
call __ULDIV__ ;
//neg64 EDX,EAX ; // quotient is negative
neg EDX ;
neg EAX ;
sbb EDX,0 ;
ret ;
L12: jmp __ULDIV__ ;
}
}
/***************************************
* Compare [EDX,EAX] with [ECX,EBX]
* Signed
* Returns result in flags
*/
void __LCMP__()
{
asm
{
naked ;
cmp EDX,ECX ;
jne C1 ;
push EDX ;
xor EDX,EDX ;
cmp EAX,EBX ;
jz C2 ;
ja C3 ;
dec EDX ;
pop EDX ;
ret ;
C3: inc EDX ;
C2: pop EDX ;
C1: ret ;
}
}
// Convert ulong to real
private real adjust = cast(real)0x800_0000_0000_0000 * 0x10;
real __U64_LDBL()
{
asm
{ naked ;
push EDX ;
push EAX ;
and dword ptr 4[ESP], 0x7FFFFFFF ;
fild qword ptr [ESP] ;
test EDX,EDX ;
jns L1 ;
fld real ptr adjust ;
faddp ST(1), ST ;
L1: ;
add ESP, 8 ;
ret ;
}
}
// Same as __U64_LDBL, but return result as double in [EDX,EAX]
ulong __ULLNGDBL()
{
asm
{ naked ;
call __U64_LDBL ;
sub ESP,8 ;
fstp double ptr [ESP] ;
pop EAX ;
pop EDX ;
ret ;
}
}
// Convert double to ulong
private short roundTo0 = 0xFBF;
ulong __DBLULLNG()
{
// BUG: should handle NAN's and overflows
asm
{ naked ;
push EDX ;
push EAX ;
fld double ptr [ESP] ;
sub ESP,8 ;
fld real ptr adjust ;
fcomp ;
fstsw AX ;
fstcw 8[ESP] ;
fldcw roundTo0 ;
sahf ;
jae L1 ;
fld real ptr adjust ;
fsubp ST(1), ST ;
fistp qword ptr [ESP] ;
pop EAX ;
pop EDX ;
fldcw [ESP] ;
add ESP,8 ;
add EDX,0x8000_0000 ;
ret ;
L1: ;
fistp qword ptr [ESP] ;
pop EAX ;
pop EDX ;
fldcw [ESP] ;
add ESP,8 ;
ret ;
}
}
// Convert double in ST0 to uint
uint __DBLULNG()
{
// BUG: should handle NAN's and overflows
asm
{ naked ;
sub ESP,16 ;
fstcw 8[ESP] ;
fldcw roundTo0 ;
fistp qword ptr [ESP] ;
fldcw 8[ESP] ;
pop EAX ;
add ESP,12 ;
ret ;
}
}

View File

@@ -0,0 +1,104 @@
/*
* Placed into the Public Domain
* written by Walter Bright, Digital Mars
* www.digitalmars.com
*/
/*
* Modified by Sean Kelly <sean@f4.ca> for use with Tango.
*/
#include <stddef.h>
#if __cplusplus
extern "C" {
#endif
struct ClassInfo;
struct Vtbl;
typedef struct Vtbl
{
size_t len;
void **vptr;
} Vtbl;
typedef struct Interface
{
struct ClassInfo *classinfo;
struct Vtbl vtbl;
int offset;
} Interface;
typedef struct Object
{
void **vptr;
void *monitor;
} Object;
typedef struct ClassInfo
{
Object object;
size_t initlen;
void *init;
size_t namelen;
char *name;
Vtbl vtbl;
size_t interfacelen;
Interface *interfaces;
struct ClassInfo *baseClass;
void *destructor;
void *invariant;
int flags;
} ClassInfo;
typedef struct Throwable
{
Object object;
size_t msglen;
char* msg;
size_t filelen;
char* file;
size_t line;
struct Interface *info;
struct Throwable *next;
} Throwable;
typedef struct Array
{
size_t length;
void *ptr;
} Array;
typedef struct Delegate
{
void *thisptr;
void (*funcptr)();
} Delegate;
void _d_monitorenter(Object *h);
void _d_monitorexit(Object *h);
int _d_isbaseof(ClassInfo *b, ClassInfo *c);
Object *_d_dynamic_cast(Object *o, ClassInfo *ci);
Object * _d_newclass(ClassInfo *ci);
void _d_delclass(Object **p);
void _d_OutOfMemory();
#if __cplusplus
}
#endif

View File

@@ -0,0 +1,184 @@
/**
* This module exposes functionality for inspecting and manipulating memory.
*
* Copyright: Copyright (C) 2005-2006 Digital Mars, www.digitalmars.com.
* All rights reserved.
* License:
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, in both source and binary form, subject to the following
* restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
* Authors: Walter Bright, Sean Kelly
*/
module rt.memory;
private
{
version( linux )
{
version = SimpleLibcStackEnd;
version( SimpleLibcStackEnd )
{
extern (C) extern void* __libc_stack_end;
}
}
}
/**
*
*/
extern (C) void* rt_stackBottom()
{
version( Windows )
{
asm
{
naked;
mov EAX,FS:4;
ret;
}
}
else version( linux )
{
version( SimpleLibcStackEnd )
{
return __libc_stack_end;
}
else
{
// See discussion: http://autopackage.org/forums/viewtopic.php?t=22
static void** libc_stack_end;
if( libc_stack_end == libc_stack_end.init )
{
void* handle = dlopen( null, RTLD_NOW );
libc_stack_end = cast(void**) dlsym( handle, "__libc_stack_end" );
dlclose( handle );
}
return *libc_stack_end;
}
}
else
{
static assert( false, "Operating system not supported." );
}
}
/**
*
*/
extern (C) void* rt_stackTop()
{
version( D_InlineAsm_X86 )
{
asm
{
naked;
mov EAX, ESP;
ret;
}
}
else
{
static assert( false, "Architecture not supported." );
}
}
private
{
version( Windows )
{
extern (C)
{
extern int _xi_a; // &_xi_a just happens to be start of data segment
extern int _edata; // &_edata is start of BSS segment
extern int _end; // &_end is past end of BSS
}
}
else version( linux )
{
extern (C)
{
extern int _data;
extern int __data_start;
extern int _end;
extern int _data_start__;
extern int _data_end__;
extern int _bss_start__;
extern int _bss_end__;
extern int __fini_array_end;
}
alias __data_start Data_Start;
alias _end Data_End;
}
alias void delegate( void*, void* ) scanFn;
}
/**
*
*/
extern (C) void rt_scanStaticData( scanFn scan )
{
scan(rt_staticDataBottom(), rt_staticDataTop());
}
/**
*
*/
extern (C) void* rt_staticDataBottom()
{
version( Windows )
{
return &_xi_a;
}
else version( linux )
{
return &__data_start;
}
else
{
static assert( false, "Operating system not supported." );
}
}
/**
*
*/
extern (C) void* rt_staticDataTop()
{
version( Windows )
{
return &_end;
}
else version( linux )
{
return &_end;
}
else
{
static assert( false, "Operating system not supported." );
}
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright (C) 2004 by Digital Mars, www.digitalmars.com
* Written by Walter Bright
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, in both source and binary form, subject to the following
* restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
module rt.memset;
extern (C)
{
// Functions from the C library.
void *memcpy(void *, void *, size_t);
}
extern (C):
short *_memset16(short *p, short value, size_t count)
{
short *pstart = p;
short *ptop;
for (ptop = &p[count]; p < ptop; p++)
*p = value;
return pstart;
}
int *_memset32(int *p, int value, size_t count)
{
version (X86)
{
asm
{
mov EDI,p ;
mov EAX,value ;
mov ECX,count ;
mov EDX,EDI ;
rep ;
stosd ;
mov EAX,EDX ;
}
}
else
{
int *pstart = p;
int *ptop;
for (ptop = &p[count]; p < ptop; p++)
*p = value;
return pstart;
}
}
long *_memset64(long *p, long value, size_t count)
{
long *pstart = p;
long *ptop;
for (ptop = &p[count]; p < ptop; p++)
*p = value;
return pstart;
}
cdouble *_memset128(cdouble *p, cdouble value, size_t count)
{
cdouble *pstart = p;
cdouble *ptop;
for (ptop = &p[count]; p < ptop; p++)
*p = value;
return pstart;
}
real *_memset80(real *p, real value, size_t count)
{
real *pstart = p;
real *ptop;
for (ptop = &p[count]; p < ptop; p++)
*p = value;
return pstart;
}
creal *_memset160(creal *p, creal value, size_t count)
{
creal *pstart = p;
creal *ptop;
for (ptop = &p[count]; p < ptop; p++)
*p = value;
return pstart;
}
void *_memsetn(void *p, void *value, int count, size_t sizelem)
{ void *pstart = p;
int i;
for (i = 0; i < count; i++)
{
memcpy(p, value, sizelem);
p = cast(void *)(cast(char *)p + sizelem);
}
return pstart;
}

View File

@@ -0,0 +1,79 @@
;_ minit.asm
; Written by Walter Bright
; Digital Mars
; http://www.digitalmars.com/d/
; Placed into the Public Domain
include macros.asm
ifdef _WIN32
DATAGRP EQU FLAT
else
DATAGRP EQU DGROUP
endif
; Provide a default resolution for weak extern records, no way in C
; to define an omf symbol with a specific value
public __nullext
__nullext equ 0
extrn __moduleinfo_array:near
; This bit of assembler is needed because, from C or D, one cannot
; specify the names of data segments. Why does this matter?
; All the ModuleInfo pointers are placed into a segment named 'FM'.
; The order in which they are placed in 'FM' is arbitrarily up to the linker.
; In order to walk all the pointers, we need to be able to find the
; beginning and the end of the 'FM' segment.
; This is done by bracketing the 'FM' segment with two other, empty,
; segments named 'FMB' and 'FME'. Since this module is the only one that
; ever refers to 'FMB' and 'FME', we get to control the order in which
; these segments appear relative to 'FM' by using a GROUP statement.
; So, we have in memory:
; FMB empty segment
; FM contains all the pointers
; FME empty segment
; and finding the limits of FM is as easy as taking the address of FMB
; and the address of FME.
; These segments bracket FM, which contains the list of ModuleInfo pointers
FMB segment dword use32 public 'DATA'
FMB ends
FM segment dword use32 public 'DATA'
FM ends
FME segment dword use32 public 'DATA'
FME ends
; This leaves room in the _fatexit() list for _moduleDtor()
XOB segment dword use32 public 'BSS'
XOB ends
XO segment dword use32 public 'BSS'
dd ?
XO ends
XOE segment dword use32 public 'BSS'
XOE ends
DGROUP group FMB,FM,FME
begcode minit
; extern (C) void _minit();
; Converts array of ModuleInfo pointers to a D dynamic array of them,
; so they can be accessed via D.
; Result is written to:
; extern (C) ModuleInfo[] _moduleinfo_array;
public __minit
__minit proc near
mov EDX,offset DATAGRP:FMB
mov EAX,offset DATAGRP:FME
mov dword ptr __moduleinfo_array+4,EDX
sub EAX,EDX ; size in bytes of FM segment
shr EAX,2 ; convert to array length
mov dword ptr __moduleinfo_array,EAX
ret
__minit endp
endcode minit
end

Binary file not shown.

View File

@@ -0,0 +1,208 @@
// D programming language runtime library
// Public Domain
// written by Walter Bright, Digital Mars
// www.digitalmars.com
// This is written in C because nobody has written a pthreads interface
// to D yet.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#if _WIN32
#elif linux
#define USE_PTHREADS 1
#else
#endif
#if _WIN32
#include <windows.h>
#endif
#if USE_PTHREADS
#include <pthread.h>
#endif
#include "mars.h"
// This is what the monitor reference in Object points to
typedef struct Monitor
{
void* impl; // for user-level monitors
Array devt; // for internal monitors
#if _WIN32
CRITICAL_SECTION mon;
#endif
#if USE_PTHREADS
pthread_mutex_t mon;
#endif
} Monitor;
#define MONPTR(h) (&((Monitor *)(h)->monitor)->mon)
static volatile int inited;
/* =============================== Win32 ============================ */
#if _WIN32
static CRITICAL_SECTION _monitor_critsec;
void _STI_monitor_staticctor()
{
if (!inited)
{ InitializeCriticalSection(&_monitor_critsec);
inited = 1;
}
}
void _STD_monitor_staticdtor()
{
if (inited)
{ inited = 0;
DeleteCriticalSection(&_monitor_critsec);
}
}
void _d_monitor_create(Object *h)
{
/*
* NOTE: Assume this is only called when h->monitor is null prior to the
* call. However, please note that another thread may call this function
* at the same time, so we can not assert this here. Instead, try and
* create a lock, and if one already exists then forget about it.
*/
//printf("+_d_monitor_create(%p)\n", h);
assert(h);
Monitor *cs = NULL;
EnterCriticalSection(&_monitor_critsec);
if (!h->monitor)
{
cs = (Monitor *)calloc(sizeof(Monitor), 1);
assert(cs);
InitializeCriticalSection(&cs->mon);
h->monitor = (void *)cs;
cs = NULL;
}
LeaveCriticalSection(&_monitor_critsec);
if (cs)
free(cs);
//printf("-_d_monitor_create(%p)\n", h);
}
void _d_monitor_destroy(Object *h)
{
//printf("+_d_monitor_destroy(%p)\n", h);
assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
DeleteCriticalSection(MONPTR(h));
free((void *)h->monitor);
h->monitor = NULL;
//printf("-_d_monitor_destroy(%p)\n", h);
}
int _d_monitor_lock(Object *h)
{
//printf("+_d_monitor_acquire(%p)\n", h);
assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
EnterCriticalSection(MONPTR(h));
//printf("-_d_monitor_acquire(%p)\n", h);
}
void _d_monitor_unlock(Object *h)
{
//printf("+_d_monitor_release(%p)\n", h);
assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
LeaveCriticalSection(MONPTR(h));
//printf("-_d_monitor_release(%p)\n", h);
}
#endif
/* =============================== linux ============================ */
#if USE_PTHREADS
// Includes attribute fixes from David Friedman's GDC port
static pthread_mutex_t _monitor_critsec;
static pthread_mutexattr_t _monitors_attr;
void _STI_monitor_staticctor()
{
if (!inited)
{
pthread_mutexattr_init(&_monitors_attr);
pthread_mutexattr_settype(&_monitors_attr, PTHREAD_MUTEX_RECURSIVE_NP);
pthread_mutex_init(&_monitor_critsec, 0);
inited = 1;
}
}
void _STD_monitor_staticdtor()
{
if (inited)
{ inited = 0;
pthread_mutex_destroy(&_monitor_critsec);
pthread_mutexattr_destroy(&_monitors_attr);
}
}
void _d_monitor_create(Object *h)
{
/*
* NOTE: Assume this is only called when h->monitor is null prior to the
* call. However, please note that another thread may call this function
* at the same time, so we can not assert this here. Instead, try and
* create a lock, and if one already exists then forget about it.
*/
//printf("+_d_monitor_create(%p)\n", h);
assert(h);
Monitor *cs = NULL;
pthread_mutex_lock(&_monitor_critsec);
if (!h->monitor)
{
cs = (Monitor *)calloc(sizeof(Monitor), 1);
assert(cs);
pthread_mutex_init(&cs->mon, & _monitors_attr);
h->monitor = (void *)cs;
cs = NULL;
}
pthread_mutex_unlock(&_monitor_critsec);
if (cs)
free(cs);
//printf("-_d_monitor_create(%p)\n", h);
}
void _d_monitor_destroy(Object *h)
{
//printf("+_d_monitor_destroy(%p)\n", h);
assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
pthread_mutex_destroy(MONPTR(h));
free((void *)h->monitor);
h->monitor = NULL;
//printf("-_d_monitor_destroy(%p)\n", h);
}
int _d_monitor_lock(Object *h)
{
//printf("+_d_monitor_acquire(%p)\n", h);
assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
pthread_mutex_lock(MONPTR(h));
//printf("-_d_monitor_acquire(%p)\n", h);
}
void _d_monitor_unlock(Object *h)
{
//printf("+_d_monitor_release(%p)\n", h);
assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
pthread_mutex_unlock(MONPTR(h));
//printf("-_d_monitor_release(%p)\n", h);
}
#endif

View File

@@ -0,0 +1,27 @@
// Copyright (c) 2002 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// www.digitalmars.com
module rt.obj;
extern (C):
/********************************
* Compiler helper for operator == for class objects.
*/
int _d_obj_eq(Object o1, Object o2)
{
return o1 is o2 || (o1 && o1.opEquals(o2));
}
/********************************
* Compiler helper for operator <, <=, >, >= for class objects.
*/
int _d_obj_cmp(Object o1, Object o2)
{
return o1.opCmp(o2);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,178 @@
# Makefile to build the compiler runtime D library for Linux
# Designed to work with GNU make
# Targets:
# make
# Same as make all
# make lib
# Build the compiler runtime library
# make doc
# Generate documentation
# make clean
# Delete unneeded files created by build process
LIB_TARGET=libdruntime-rt-dmd.a
LIB_MASK=libdruntime-rt-dmd*.a
CP=cp -f
RM=rm -f
MD=mkdir -p
CFLAGS=-O $(ADD_CFLAGS)
#CFLAGS=-g $(ADD_CFLAGS)
DFLAGS=-release -O -inline -w -nofloat $(ADD_DFLAGS)
#DFLAGS=-g -w -nofloat $(ADD_DFLAGS)
TFLAGS=-O -inline -w -nofloat $(ADD_DFLAGS)
#TFLAGS=-g -w -nofloat $(ADD_DFLAGS)
DOCFLAGS=-version=DDoc
CC=gcc
LC=$(AR) -qsv
DC=dmd
LIB_DEST=../../../lib
.SUFFIXES: .s .S .c .cpp .d .html .o
.s.o:
$(CC) -c $(CFLAGS) $< -o$@
.S.o:
$(CC) -c $(CFLAGS) $< -o$@
.c.o:
$(CC) -c $(CFLAGS) $< -o$@
.cpp.o:
g++ -c $(CFLAGS) $< -o$@
.d.o:
$(DC) -c $(DFLAGS) $< -of$@
.d.html:
$(DC) -c -o- $(DOCFLAGS) -Df$*.html dmd.ddoc $<
targets : lib doc
all : lib doc
lib : dmd.lib
doc : dmd.doc
######################################################
OBJ_BASE= \
aaA.o \
aApply.o \
aApplyR.o \
adi.o \
alloca.o \
arrayassign.o \
arraybyte.o \
arraycast.o \
arraycat.o \
arraydouble.o \
arrayfloat.o \
arrayint.o \
arrayreal.o \
arrayshort.o \
cast_.o \
cmath2.o \
complex.o \
cover.o \
critical.o \
deh2.o \
dmain2.o \
invariant.o \
invariant_.o \
lifetime.o \
llmath.o \
memory.o \
memset.o \
monitor.o \
obj.o \
object_.o \
qsort.o \
switch_.o \
trace.o
# NOTE: trace.obj and cover.obj are not necessary for a successful build
# as both are used for debugging features (profiling and coverage)
# NOTE: a pre-compiled minit.obj has been provided in dmd for Win32 and
# minit.asm is not used by dmd for linux
# NOTE: deh.o is only needed for Win32, linux uses deh2.o
OBJ_UTIL= \
util/console.o \
util/cpuid.o \
util/ctype.o \
util/string.o \
util/utf.o
OBJ_TI= \
typeinfo/ti_AC.o \
typeinfo/ti_Acdouble.o \
typeinfo/ti_Acfloat.o \
typeinfo/ti_Acreal.o \
typeinfo/ti_Adouble.o \
typeinfo/ti_Afloat.o \
typeinfo/ti_Ag.o \
typeinfo/ti_Aint.o \
typeinfo/ti_Along.o \
typeinfo/ti_Areal.o \
typeinfo/ti_Ashort.o \
typeinfo/ti_byte.o \
typeinfo/ti_C.o \
typeinfo/ti_cdouble.o \
typeinfo/ti_cfloat.o \
typeinfo/ti_char.o \
typeinfo/ti_creal.o \
typeinfo/ti_dchar.o \
typeinfo/ti_delegate.o \
typeinfo/ti_double.o \
typeinfo/ti_float.o \
typeinfo/ti_idouble.o \
typeinfo/ti_ifloat.o \
typeinfo/ti_int.o \
typeinfo/ti_ireal.o \
typeinfo/ti_long.o \
typeinfo/ti_ptr.o \
typeinfo/ti_real.o \
typeinfo/ti_short.o \
typeinfo/ti_ubyte.o \
typeinfo/ti_uint.o \
typeinfo/ti_ulong.o \
typeinfo/ti_ushort.o \
typeinfo/ti_void.o \
typeinfo/ti_wchar.o
ALL_OBJS= \
$(OBJ_BASE) \
$(OBJ_UTIL) \
$(OBJ_TI)
######################################################
ALL_DOCS=
######################################################
dmd.lib : $(LIB_TARGET)
$(LIB_TARGET) : $(ALL_OBJS)
$(RM) $@
$(LC) $@ $(ALL_OBJS)
dmd.doc : $(ALL_DOCS)
echo No documentation available.
######################################################
clean :
find . -name "*.di" | xargs $(RM)
$(RM) $(ALL_OBJS)
$(RM) $(ALL_DOCS)
$(RM) $(LIB_MASK)
install :
$(MD) $(LIB_DEST)
$(CP) $(LIB_MASK) $(LIB_DEST)/.

View File

@@ -0,0 +1,158 @@
/*
Portions of this file are:
Copyright Prototronics, 1987
Totem Lake P.O. 8117
Kirkland, Washington 98034
(206) 820-1972
Licensed to Digital Mars.
June 11, 1987 from Ray Gardner's
Denver, Colorado) public domain version
Use qsort2.d instead of this file if a redistributable version of
_adSort() is required.
*/
module rt.qsort;
/*
** Sorts an array starting at base, of length nbr_elements, each
** element of size width_bytes, ordered via compare_function; which
** is called as (*comp_fp)(ptr_to_element1, ptr_to_element2)
** and returns < 0 if element1 < element2, 0 if element1 = element2,
** > 0 if element1 > element2. Most of the refinements are due to
** R. Sedgewick. See "Implementing Quicksort Programs", Comm. ACM,
** Oct. 1978, and Corrigendum, Comm. ACM, June 1979.
*/
//debug=qsort; // uncomment to turn on debugging printf's
struct Array
{
size_t length;
void* ptr;
}
private const int _maxspan = 7; // subarrays of _maxspan or fewer elements
// will be sorted by a simple insertion sort
/* Adjust _maxspan according to relative cost of a swap and a compare. Reduce
_maxspan (not less than 1) if a swap is very expensive such as when you have
an array of large structures to be sorted, rather than an array of pointers to
structures. The default value is optimized for a high cost for compares. */
extern (C) long _adSort(Array a, TypeInfo ti)
{
byte* base;
byte*[40] stack; // stack
byte** sp; // stack pointer
byte* i, j, limit; // scan and limit pointers
uint thresh; // size of _maxspan elements in bytes
uint width = ti.tsize();
base = cast(byte *)a.ptr;
thresh = _maxspan * width; // init threshold
sp = stack.ptr; // init stack pointer
limit = base + a.length * width; // pointer past end of array
while (1) // repeat until done then return
{
while (limit - base > thresh) // if more than _maxspan elements
{
//swap middle, base
ti.swap((cast(uint)(limit - base) >> 1) -
(((cast(uint)(limit - base) >> 1)) % width) + base, base);
i = base + width; // i scans from left to right
j = limit - width; // j scans from right to left
if (ti.compare(i, j) > 0) // Sedgewick's
ti.swap(i, j); // three-element sort
if (ti.compare(base, j) > 0) // sets things up
ti.swap(base, j); // so that
if (ti.compare(i, base) > 0) // *i <= *base <= *j
ti.swap(i, base); // *base is the pivot element
while (1)
{
do // move i right until *i >= pivot
i += width;
while (ti.compare(i, base) < 0);
do // move j left until *j <= pivot
j -= width;
while (ti.compare(j, base) > 0);
if (i > j) // break loop if pointers crossed
break;
ti.swap(i, j); // else swap elements, keep scanning
}
ti.swap(base, j); // move pivot into correct place
if (j - base > limit - i) // if left subarray is larger...
{
sp[0] = base; // stack left subarray base
sp[1] = j; // and limit
base = i; // sort the right subarray
}
else // else right subarray is larger
{
sp[0] = i; // stack right subarray base
sp[1] = limit; // and limit
limit = j; // sort the left subarray
}
sp += 2; // increment stack pointer
assert(sp < cast(byte**)stack + stack.length);
}
// Insertion sort on remaining subarray
i = base + width;
while (i < limit)
{
j = i;
while (j > base && ti.compare(j - width, j) > 0)
{
ti.swap(j - width, j);
j -= width;
}
i += width;
}
if (sp > stack.ptr) // if any entries on stack...
{
sp -= 2; // pop the base and limit
base = sp[0];
limit = sp[1];
}
else // else stack empty, all done
return *cast(long*)(&a);
}
assert(0);
}
unittest
{
debug(qsort) printf("array.sort.unittest()\n");
int a[] = new int[10];
a[0] = 23;
a[1] = 1;
a[2] = 64;
a[3] = 5;
a[4] = 6;
a[5] = 5;
a[6] = 17;
a[7] = 3;
a[8] = 0;
a[9] = -1;
a.sort;
for (int i = 0; i < a.length - 1; i++)
{
//printf("i = %d", i);
//printf(" %d %d\n", a[i], a[i + 1]);
assert(a[i] <= a[i + 1]);
}
}

View File

@@ -0,0 +1,72 @@
/*
* Placed into Public Domain
* written by Walter Bright
* www.digitalmars.com
*
* This is a public domain version of qsort.d.
* All it does is call C's qsort(), but runs a little slower since
* it needs to synchronize a global variable.
*/
/*
* Modified by Sean Kelly for use with the D Runtime Project
*/
module rt.qsort2;
//debug=qsort;
private import stdc.stdlib;
struct Array
{
size_t length;
void* ptr;
}
private TypeInfo tiglobal;
extern (C) int cmp(void* p1, void* p2)
{
return tiglobal.compare(p1, p2);
}
extern (C) long _adSort(Array a, TypeInfo ti)
{
synchronized
{
tiglobal = ti;
qsort(a.ptr, a.length, cast(size_t)ti.tsize(), &cmp);
}
return *cast(long*)(&a);
}
unittest
{
debug(qsort) printf("array.sort.unittest()\n");
int a[] = new int[10];
a[0] = 23;
a[1] = 1;
a[2] = 64;
a[3] = 5;
a[4] = 6;
a[5] = 5;
a[6] = 17;
a[7] = 3;
a[8] = 0;
a[9] = -1;
a.sort;
for (int i = 0; i < a.length - 1; i++)
{
//printf("i = %d", i);
//printf(" %d %d\n", a[i], a[i + 1]);
assert(a[i] <= a[i + 1]);
}
}

View File

@@ -0,0 +1,426 @@
/*
* Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com
* Written by Walter Bright
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, in both source and binary form, subject to the following
* restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
/*
* Modified by Sean Kelly for use with the D Runtime Project
*/
module rt.switch_;
private import stdc.string;
/******************************************************
* Support for switch statements switching on strings.
* Input:
* table[] sorted array of strings generated by compiler
* ca string to look up in table
* Output:
* result index of match in table[]
* -1 if not in table
*/
extern (C):
int _d_switch_string(char[][] table, char[] ca)
in
{
//printf("in _d_switch_string()\n");
assert(table.length >= 0);
assert(ca.length >= 0);
// Make sure table[] is sorted correctly
int j;
for (j = 1; j < table.length; j++)
{
int len1 = table[j - 1].length;
int len2 = table[j].length;
assert(len1 <= len2);
if (len1 == len2)
{
int ci;
ci = memcmp(table[j - 1].ptr, table[j].ptr, len1);
assert(ci < 0); // ci==0 means a duplicate
}
}
}
out (result)
{
int i;
int cj;
//printf("out _d_switch_string()\n");
if (result == -1)
{
// Not found
for (i = 0; i < table.length; i++)
{
if (table[i].length == ca.length)
{ cj = memcmp(table[i].ptr, ca.ptr, ca.length);
assert(cj != 0);
}
}
}
else
{
assert(0 <= result && result < table.length);
for (i = 0; 1; i++)
{
assert(i < table.length);
if (table[i].length == ca.length)
{
cj = memcmp(table[i].ptr, ca.ptr, ca.length);
if (cj == 0)
{
assert(i == result);
break;
}
}
}
}
}
body
{
//printf("body _d_switch_string(%.*s)\n", ca);
int low;
int high;
int mid;
int c;
char[] pca;
low = 0;
high = table.length;
version (none)
{
// Print table
printf("ca[] = '%s'\n", cast(char *)ca);
for (mid = 0; mid < high; mid++)
{
pca = table[mid];
printf("table[%d] = %d, '%.*s'\n", mid, pca.length, pca);
}
}
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)
{ //printf("found %d\n", mid);
return mid;
}
}
}
if (c < 0)
{
high = mid;
}
else
{
low = mid + 1;
}
}
}
//printf("not found\n");
return -1; // not found
}
unittest
{
switch (cast(char []) "c")
{
case "coo":
default:
break;
}
}
/**********************************
* Same thing, but for wide chars.
*/
int _d_switch_ustring(wchar[][] table, wchar[] ca)
in
{
//printf("in _d_switch_ustring()\n");
assert(table.length >= 0);
assert(ca.length >= 0);
// Make sure table[] is sorted correctly
int j;
for (j = 1; j < table.length; j++)
{
int len1 = table[j - 1].length;
int len2 = table[j].length;
assert(len1 <= len2);
if (len1 == len2)
{
int c;
c = memcmp(table[j - 1].ptr, table[j].ptr, len1 * wchar.sizeof);
assert(c < 0); // c==0 means a duplicate
}
}
}
out (result)
{
int i;
int c;
//printf("out _d_switch_string()\n");
if (result == -1)
{
// Not found
for (i = 0; i < table.length; i++)
{
if (table[i].length == ca.length)
{ c = memcmp(table[i].ptr, ca.ptr, ca.length * wchar.sizeof);
assert(c != 0);
}
}
}
else
{
assert(0 <= result && result < table.length);
for (i = 0; 1; i++)
{
assert(i < table.length);
if (table[i].length == ca.length)
{
c = memcmp(table[i].ptr, ca.ptr, ca.length * wchar.sizeof);
if (c == 0)
{
assert(i == result);
break;
}
}
}
}
}
body
{
//printf("body _d_switch_ustring()\n");
int low;
int high;
int mid;
int c;
wchar[] pca;
low = 0;
high = table.length;
/*
// Print table
wprintf("ca[] = '%.*s'\n", ca);
for (mid = 0; mid < high; mid++)
{
pca = table[mid];
wprintf("table[%d] = %d, '%.*s'\n", mid, pca.length, pca);
}
*/
// 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)
{ //printf("found %d\n", mid);
return mid;
}
}
if (c < 0)
{
high = mid;
}
else
{
low = mid + 1;
}
}
//printf("not found\n");
return -1; // not found
}
unittest
{
switch (cast(wchar []) "c")
{
case "coo":
default:
break;
}
}
/**********************************
* Same thing, but for wide chars.
*/
int _d_switch_dstring(dchar[][] table, dchar[] ca)
in
{
//printf("in _d_switch_dstring()\n");
assert(table.length >= 0);
assert(ca.length >= 0);
// Make sure table[] is sorted correctly
int j;
for (j = 1; j < table.length; j++)
{
int len1 = table[j - 1].length;
int len2 = table[j].length;
assert(len1 <= len2);
if (len1 == len2)
{
int c;
c = memcmp(table[j - 1].ptr, table[j].ptr, len1 * dchar.sizeof);
assert(c < 0); // c==0 means a duplicate
}
}
}
out (result)
{
int i;
int c;
//printf("out _d_switch_string()\n");
if (result == -1)
{
// Not found
for (i = 0; i < table.length; i++)
{
if (table[i].length == ca.length)
{ c = memcmp(table[i].ptr, ca.ptr, ca.length * dchar.sizeof);
assert(c != 0);
}
}
}
else
{
assert(0 <= result && result < table.length);
for (i = 0; 1; i++)
{
assert(i < table.length);
if (table[i].length == ca.length)
{
c = memcmp(table[i].ptr, ca.ptr, ca.length * dchar.sizeof);
if (c == 0)
{
assert(i == result);
break;
}
}
}
}
}
body
{
//printf("body _d_switch_ustring()\n");
int low;
int high;
int mid;
int c;
dchar[] pca;
low = 0;
high = table.length;
/*
// Print table
wprintf("ca[] = '%.*s'\n", ca);
for (mid = 0; mid < high; mid++)
{
pca = table[mid];
wprintf("table[%d] = %d, '%.*s'\n", mid, pca.length, pca);
}
*/
// 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)
{ //printf("found %d\n", mid);
return mid;
}
}
if (c < 0)
{
high = mid;
}
else
{
low = mid + 1;
}
}
//printf("not found\n");
return -1; // not found
}
unittest
{
switch (cast(dchar []) "c")
{
case "coo":
default:
break;
}
}

View File

@@ -0,0 +1,867 @@
/* Trace dynamic profiler.
* For use with the Digital Mars DMD compiler.
* Copyright (C) 1995-2006 by Digital Mars
* All Rights Reserved
* Written by Walter Bright
* www.digitalmars.com
*/
/*
* Modified by Sean Kelly for use with the D Runtime Project
*/
module rt.trace;
private
{
import util.string;
import stdc.ctype;
import stdc.stdio;
import stdc.string;
import stdc.stdlib;
}
extern (C):
char* unmangle_ident(char*); // from DMC++ runtime library
alias long timer_t;
/////////////////////////////////////
//
struct SymPair
{
SymPair* next;
Symbol* sym; // function that is called
uint count; // number of times sym is called
}
/////////////////////////////////////
// A Symbol for each function name.
struct Symbol
{
Symbol* Sl, Sr; // left, right children
SymPair* Sfanin; // list of calling functions
SymPair* Sfanout; // list of called functions
timer_t totaltime; // aggregate time
timer_t functime; // time excluding subfunction calls
ubyte Sflags;
char[] Sident; // name of symbol
}
const ubyte SFvisited = 1; // visited
static Symbol* root; // root of symbol table
//////////////////////////////////
// Build a linked list of these.
struct Stack
{
Stack* prev;
Symbol* sym;
timer_t starttime; // time when function was entered
timer_t ohd; // overhead of all the bookkeeping code
timer_t subtime; // time used by all subfunctions
}
static Stack* stack_freelist;
static Stack* trace_tos; // top of stack
static int trace_inited; // !=0 if initialized
static timer_t trace_ohd;
static Symbol** psymbols;
static uint nsymbols; // number of symbols
static string trace_logfilename = "trace.log";
static FILE* fplog;
static string trace_deffilename = "trace.def";
static FILE* fpdef;
////////////////////////////////////////
// Set file name for output.
// A file name of "" means write results to stdout.
// Returns:
// 0 success
// !=0 failure
int trace_setlogfilename(string name)
{
trace_logfilename = name;
return 0;
}
////////////////////////////////////////
// Set file name for output.
// A file name of "" means write results to stdout.
// Returns:
// 0 success
// !=0 failure
int trace_setdeffilename(string name)
{
trace_deffilename = name;
return 0;
}
////////////////////////////////////////
// Output optimal function link order.
static void trace_order(Symbol *s)
{
while (s)
{
trace_place(s,0);
if (s.Sl)
trace_order(s.Sl);
s = s.Sr;
}
}
//////////////////////////////////////////////
//
static Stack* stack_malloc()
{ Stack *s;
if (stack_freelist)
{ s = stack_freelist;
stack_freelist = s.prev;
}
else
s = cast(Stack *)trace_malloc(Stack.sizeof);
return s;
}
//////////////////////////////////////////////
//
static void stack_free(Stack *s)
{
s.prev = stack_freelist;
stack_freelist = s;
}
//////////////////////////////////////
// Qsort() comparison routine for array of pointers to SymPair's.
static int sympair_cmp(in void* e1, in void* e2)
{ SymPair** psp1;
SymPair** psp2;
psp1 = cast(SymPair**)e1;
psp2 = cast(SymPair**)e2;
return (*psp2).count - (*psp1).count;
}
//////////////////////////////////////
// Place symbol s, and then place any fan ins or fan outs with
// counts greater than count.
static void trace_place(Symbol *s, uint count)
{ SymPair* sp;
SymPair** base;
if (!(s.Sflags & SFvisited))
{ size_t num;
uint u;
//printf("\t%.*s\t%u\n", s.Sident, count);
fprintf(fpdef,"\t%.*s\n", s.Sident);
s.Sflags |= SFvisited;
// Compute number of items in array
num = 0;
for (sp = s.Sfanin; sp; sp = sp.next)
num++;
for (sp = s.Sfanout; sp; sp = sp.next)
num++;
if (!num)
return;
// Allocate and fill array
base = cast(SymPair**)trace_malloc(SymPair.sizeof * num);
u = 0;
for (sp = s.Sfanin; sp; sp = sp.next)
base[u++] = sp;
for (sp = s.Sfanout; sp; sp = sp.next)
base[u++] = sp;
// Sort array
qsort(base, num, (SymPair *).sizeof, &sympair_cmp);
//for (u = 0; u < num; u++)
//printf("\t\t%.*s\t%u\n", base[u].sym.Sident, base[u].count);
// Place symbols
for (u = 0; u < num; u++)
{
if (base[u].count >= count)
{ uint u2;
uint c2;
u2 = (u + 1 < num) ? u + 1 : u;
c2 = base[u2].count;
if (c2 < count)
c2 = count;
trace_place(base[u].sym,c2);
}
else
break;
}
// Clean up
trace_free(base);
}
}
/////////////////////////////////////
// Initialize and terminate.
static this()
{
trace_init();
}
static ~this()
{
trace_term();
}
///////////////////////////////////
// Report results.
// Also compute nsymbols.
static void trace_report(Symbol* s)
{ SymPair* sp;
uint count;
//printf("trace_report()\n");
while (s)
{ nsymbols++;
if (s.Sl)
trace_report(s.Sl);
fprintf(fplog,"------------------\n");
count = 0;
for (sp = s.Sfanin; sp; sp = sp.next)
{
fprintf(fplog,"\t%5d\t%.*s\n", sp.count, sp.sym.Sident);
count += sp.count;
}
fprintf(fplog,"%.*s\t%u\t%lld\t%lld\n",s.Sident,count,s.totaltime,s.functime);
for (sp = s.Sfanout; sp; sp = sp.next)
{
fprintf(fplog,"\t%5d\t%.*s\n",sp.count,sp.sym.Sident);
}
s = s.Sr;
}
}
////////////////////////////////////
// Allocate and fill array of symbols.
static void trace_array(Symbol *s)
{ static uint u;
if (!psymbols)
{ u = 0;
psymbols = cast(Symbol **)trace_malloc((Symbol *).sizeof * nsymbols);
}
while (s)
{
psymbols[u++] = s;
trace_array(s.Sl);
s = s.Sr;
}
}
//////////////////////////////////////
// Qsort() comparison routine for array of pointers to Symbol's.
static int symbol_cmp(in void* e1, in void* e2)
{ Symbol** ps1;
Symbol** ps2;
timer_t diff;
ps1 = cast(Symbol **)e1;
ps2 = cast(Symbol **)e2;
diff = (*ps2).functime - (*ps1).functime;
return (diff == 0) ? 0 : ((diff > 0) ? 1 : -1);
}
///////////////////////////////////
// Report function timings
static void trace_times(Symbol* root)
{ uint u;
timer_t freq;
// Sort array
qsort(psymbols, nsymbols, (Symbol *).sizeof, &symbol_cmp);
// Print array
QueryPerformanceFrequency(&freq);
fprintf(fplog,"\n======== Timer Is %lld Ticks/Sec, Times are in Microsecs ========\n\n",freq);
fprintf(fplog," Num Tree Func Per\n");
fprintf(fplog," Calls Time Time Call\n\n");
for (u = 0; u < nsymbols; u++)
{ Symbol* s = psymbols[u];
timer_t tl,tr;
timer_t fl,fr;
timer_t pl,pr;
timer_t percall;
SymPair* sp;
uint calls;
char[] id;
version (Windows)
{
char* p = (s.Sident ~ '\0').ptr;
p = unmangle_ident(p);
if (p)
id = p[0 .. strlen(p)];
}
if (!id)
id = s.Sident;
calls = 0;
for (sp = s.Sfanin; sp; sp = sp.next)
calls += sp.count;
if (calls == 0)
calls = 1;
version (all)
{
tl = (s.totaltime * 1000000) / freq;
fl = (s.functime * 1000000) / freq;
percall = s.functime / calls;
pl = (s.functime * 1000000) / calls / freq;
fprintf(fplog,"%7d%12lld%12lld%12lld %.*s\n",
calls,tl,fl,pl,id);
}
else
{
tl = s.totaltime / freq;
tr = ((s.totaltime - tl * freq) * 10000000) / freq;
fl = s.functime / freq;
fr = ((s.functime - fl * freq) * 10000000) / freq;
percall = s.functime / calls;
pl = percall / freq;
pr = ((percall - pl * freq) * 10000000) / freq;
fprintf(fplog,"%7d\t%3lld.%07lld\t%3lld.%07lld\t%3lld.%07lld\t%.*s\n",
calls,tl,tr,fl,fr,pl,pr,id);
}
if (id !is s.Sident)
free(id.ptr);
}
}
///////////////////////////////////
// Initialize.
static void trace_init()
{
if (!trace_inited)
{
trace_inited = 1;
{ // See if we can determine the overhead.
uint u;
timer_t starttime;
timer_t endtime;
Stack *st;
st = trace_tos;
trace_tos = null;
QueryPerformanceCounter(&starttime);
for (u = 0; u < 100; u++)
{
asm
{
call _trace_pro_n ;
db 0 ;
call _trace_epi_n ;
}
}
QueryPerformanceCounter(&endtime);
trace_ohd = (endtime - starttime) / u;
//printf("trace_ohd = %lld\n",trace_ohd);
if (trace_ohd > 0)
trace_ohd--; // round down
trace_tos = st;
}
}
}
/////////////////////////////////
// Terminate.
void trace_term()
{
//printf("trace_term()\n");
if (trace_inited == 1)
{ Stack *n;
trace_inited = 2;
// Free remainder of the stack
while (trace_tos)
{
n = trace_tos.prev;
stack_free(trace_tos);
trace_tos = n;
}
while (stack_freelist)
{
n = stack_freelist.prev;
stack_free(stack_freelist);
stack_freelist = n;
}
// Merge in data from any existing file
trace_merge();
// Report results
fplog = fopen(trace_logfilename.ptr, "w");
if (fplog)
{ nsymbols = 0;
trace_report(root);
trace_array(root);
trace_times(root);
fclose(fplog);
}
// Output function link order
fpdef = fopen(trace_deffilename.ptr,"w");
if (fpdef)
{ fprintf(fpdef,"\nFUNCTIONS\n");
trace_order(root);
fclose(fpdef);
}
trace_free(psymbols);
psymbols = null;
}
}
/////////////////////////////////
// Our storage allocator.
static void *trace_malloc(size_t nbytes)
{ void *p;
p = malloc(nbytes);
if (!p)
exit(EXIT_FAILURE);
return p;
}
static void trace_free(void *p)
{
free(p);
}
//////////////////////////////////////////////
//
static Symbol* trace_addsym(char[] id)
{
Symbol** parent;
Symbol* rover;
Symbol* s;
int cmp;
char c;
//printf("trace_addsym('%s',%d)\n",p,len);
parent = &root;
rover = *parent;
while (rover !is null) // while we haven't run out of tree
{
cmp = dstrcmp(id, rover.Sident);
if (cmp == 0)
{
return rover;
}
parent = (cmp < 0) ? /* if we go down left side */
&(rover.Sl) : /* then get left child */
&(rover.Sr); /* else get right child */
rover = *parent; /* get child */
}
/* not in table, so insert into table */
s = cast(Symbol *)trace_malloc(Symbol.sizeof);
memset(s,0,Symbol.sizeof);
s.Sident = id;
*parent = s; // link new symbol into tree
return s;
}
/***********************************
* Add symbol s with count to SymPair list.
*/
static void trace_sympair_add(SymPair** psp, Symbol* s, uint count)
{ SymPair* sp;
for (; 1; psp = &sp.next)
{
sp = *psp;
if (!sp)
{
sp = cast(SymPair *)trace_malloc(SymPair.sizeof);
sp.sym = s;
sp.count = 0;
sp.next = null;
*psp = sp;
break;
}
else if (sp.sym == s)
{
break;
}
}
sp.count += count;
}
//////////////////////////////////////////////
//
static void trace_pro(char[] id)
{
Stack* n;
Symbol* s;
timer_t starttime;
timer_t t;
QueryPerformanceCounter(&starttime);
if (id.length == 0)
return;
if (!trace_inited)
trace_init(); // initialize package
n = stack_malloc();
n.prev = trace_tos;
trace_tos = n;
s = trace_addsym(id);
trace_tos.sym = s;
if (trace_tos.prev)
{
Symbol* prev;
int i;
// Accumulate Sfanout and Sfanin
prev = trace_tos.prev.sym;
trace_sympair_add(&prev.Sfanout,s,1);
trace_sympair_add(&s.Sfanin,prev,1);
}
QueryPerformanceCounter(&t);
trace_tos.starttime = starttime;
trace_tos.ohd = trace_ohd + t - starttime;
trace_tos.subtime = 0;
//printf("trace_tos.ohd=%lld, trace_ohd=%lld + t=%lld - starttime=%lld\n",
// trace_tos.ohd,trace_ohd,t,starttime);
}
/////////////////////////////////////////
//
static void trace_epi()
{ Stack* n;
timer_t endtime;
timer_t t;
timer_t ohd;
//printf("trace_epi()\n");
if (trace_tos)
{
timer_t starttime;
timer_t totaltime;
QueryPerformanceCounter(&endtime);
starttime = trace_tos.starttime;
totaltime = endtime - starttime - trace_tos.ohd;
if (totaltime < 0)
{ //printf("endtime=%lld - starttime=%lld - trace_tos.ohd=%lld < 0\n",
// endtime,starttime,trace_tos.ohd);
totaltime = 0; // round off error, just make it 0
}
// totaltime is time spent in this function + all time spent in
// subfunctions - bookkeeping overhead.
trace_tos.sym.totaltime += totaltime;
//if (totaltime < trace_tos.subtime)
//printf("totaltime=%lld < trace_tos.subtime=%lld\n",totaltime,trace_tos.subtime);
trace_tos.sym.functime += totaltime - trace_tos.subtime;
ohd = trace_tos.ohd;
n = trace_tos.prev;
stack_free(trace_tos);
trace_tos = n;
if (n)
{ QueryPerformanceCounter(&t);
n.ohd += ohd + t - endtime;
n.subtime += totaltime;
//printf("n.ohd = %lld\n",n.ohd);
}
}
}
////////////////////////// FILE INTERFACE /////////////////////////
/////////////////////////////////////
// Read line from file fp.
// Returns:
// trace_malloc'd line buffer
// null if end of file
static char* trace_readline(FILE* fp)
{ int c;
int dim;
int i;
char *buf;
//printf("trace_readline(%p)\n", fp);
i = 0;
dim = 0;
buf = null;
while (1)
{
if (i == dim)
{ char *p;
dim += 80;
p = cast(char *)trace_malloc(dim);
memcpy(p,buf,i);
trace_free(buf);
buf = p;
}
c = fgetc(fp);
switch (c)
{
case EOF:
if (i == 0)
{ trace_free(buf);
return null;
}
case '\n':
goto L1;
default:
break;
}
buf[i] = cast(char)c;
i++;
}
L1:
buf[i] = 0;
//printf("line '%s'\n",buf);
return buf;
}
//////////////////////////////////////
// Skip space
static char *skipspace(char *p)
{
while (isspace(*p))
p++;
return p;
}
////////////////////////////////////////////////////////
// Merge in profiling data from existing file.
static void trace_merge()
{ FILE *fp;
char *buf;
char *p;
uint count;
Symbol *s;
SymPair *sfanin;
SymPair **psp;
if (trace_logfilename && (fp = fopen(trace_logfilename.ptr,"r")) !is null)
{
buf = null;
sfanin = null;
psp = &sfanin;
while (1)
{
trace_free(buf);
buf = trace_readline(fp);
if (!buf)
break;
switch (*buf)
{
case '=': // ignore rest of file
trace_free(buf);
goto L1;
case ' ':
case '\t': // fan in or fan out line
count = strtoul(buf,&p,10);
if (p == buf) // if invalid conversion
continue;
p = skipspace(p);
if (!*p)
continue;
s = trace_addsym(p[0 .. strlen(p)]);
trace_sympair_add(psp,s,count);
break;
default:
if (!isalpha(*buf))
{
if (!sfanin)
psp = &sfanin;
continue; // regard unrecognized line as separator
}
case '?':
case '_':
case '$':
case '@':
p = buf;
while (isgraph(*p))
p++;
*p = 0;
//printf("trace_addsym('%s')\n",buf);
s = trace_addsym(buf[0 .. strlen(buf)]);
if (s.Sfanin)
{ SymPair *sp;
for (; sfanin; sfanin = sp)
{
trace_sympair_add(&s.Sfanin,sfanin.sym,sfanin.count);
sp = sfanin.next;
trace_free(sfanin);
}
}
else
{ s.Sfanin = sfanin;
}
sfanin = null;
psp = &s.Sfanout;
{ timer_t t;
p++;
count = strtoul(p,&p,10);
t = cast(long)strtoull(p,&p,10);
s.totaltime += t;
t = cast(long)strtoull(p,&p,10);
s.functime += t;
}
break;
}
}
L1:
fclose(fp);
}
}
////////////////////////// COMPILER INTERFACE /////////////////////
/////////////////////////////////////////////
// Function called by trace code in function prolog.
void _trace_pro_n()
{
/* Length of string is either:
* db length
* ascii string
* or:
* db 0x0FF
* db 0
* dw length
* ascii string
*/
asm
{ naked ;
pushad ;
mov ECX,8*4[ESP] ;
xor EAX,EAX ;
mov AL,[ECX] ;
cmp AL,0xFF ;
jne L1 ;
cmp byte ptr 1[ECX],0 ;
jne L1 ;
mov AX,2[ECX] ;
add 8*4[ESP],3 ;
add ECX,3 ;
L1: inc EAX ;
inc ECX ;
add 8*4[ESP],EAX ;
dec EAX ;
push ECX ;
push EAX ;
call trace_pro ;
add ESP,8 ;
popad ;
ret ;
}
}
/////////////////////////////////////////////
// Function called by trace code in function epilog.
void _trace_epi_n()
{
asm
{ naked ;
pushad ;
}
trace_epi();
asm
{
popad ;
ret ;
}
}
version (Windows)
{
extern (Windows)
{
export int QueryPerformanceCounter(timer_t *);
export int QueryPerformanceFrequency(timer_t *);
}
}
else version (X86)
{
extern (D)
{
void QueryPerformanceCounter(timer_t* ctr)
{
asm
{ naked ;
mov ECX,EAX ;
rdtsc ;
mov [ECX],EAX ;
mov 4[ECX],EDX ;
ret ;
}
}
void QueryPerformanceFrequency(timer_t* freq)
{
*freq = 3579545;
}
}
}
else
{
static assert(0);
}

View File

@@ -0,0 +1,95 @@
module rt.typeinfo.ti_AC;
// Object[]
class TypeInfo_AC : TypeInfo
{
override hash_t getHash(in void* p)
{ Object[] s = *cast(Object[]*)p;
hash_t hash = 0;
foreach (Object o; s)
{
if (o)
hash += o.toHash();
}
return hash;
}
override equals_t equals(in void* p1, in void* p2)
{
Object[] s1 = *cast(Object[]*)p1;
Object[] s2 = *cast(Object[]*)p2;
if (s1.length == s2.length)
{
for (size_t u = 0; u < s1.length; u++)
{ Object o1 = s1[u];
Object o2 = s2[u];
// Do not pass null's to Object.opEquals()
if (o1 is o2 ||
(!(o1 is null) && !(o2 is null) && o1.opEquals(o2)))
continue;
return false;
}
return true;
}
return false;
}
override int compare(in void* p1, in void* p2)
{
Object[] s1 = *cast(Object[]*)p1;
Object[] s2 = *cast(Object[]*)p2;
ptrdiff_t c;
c = cast(ptrdiff_t)s1.length - cast(ptrdiff_t)s2.length;
if (c == 0)
{
for (size_t u = 0; u < s1.length; u++)
{ Object o1 = s1[u];
Object o2 = s2[u];
if (o1 is o2)
continue;
// Regard null references as always being "less than"
if (o1)
{
if (!o2)
{ c = 1;
break;
}
c = o1.opCmp(o2);
if (c)
break;
}
else
{ c = -1;
break;
}
}
}
if (c < 0)
c = -1;
else if (c > 0)
c = 1;
return c;
}
override size_t tsize()
{
return (Object[]).sizeof;
}
override uint flags()
{
return 1;
}
override TypeInfo next()
{
return typeid(Object);
}
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
* Written by Walter Bright
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, in both source and binary form, subject to the following
* restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
module rt.typeinfo.ti_Acdouble;
private import typeinfo.ti_cdouble;
// cdouble[]
class TypeInfo_Ar : TypeInfo
{
override string toString() { return "cdouble[]"; }
override hash_t getHash(in void* p)
{ cdouble[] s = *cast(cdouble[]*)p;
size_t len = s.length;
cdouble *str = s.ptr;
hash_t hash = 0;
while (len)
{
hash *= 9;
hash += (cast(uint *)str)[0];
hash += (cast(uint *)str)[1];
hash += (cast(uint *)str)[2];
hash += (cast(uint *)str)[3];
str++;
len--;
}
return hash;
}
override equals_t equals(in void* p1, in void* p2)
{
cdouble[] s1 = *cast(cdouble[]*)p1;
cdouble[] s2 = *cast(cdouble[]*)p2;
size_t len = s1.length;
if (len != s2.length)
return false;
for (size_t u = 0; u < len; u++)
{
if (!TypeInfo_r._equals(s1[u], s2[u]))
return false;
}
return true;
}
override int compare(in void* p1, in void* p2)
{
cdouble[] s1 = *cast(cdouble[]*)p1;
cdouble[] s2 = *cast(cdouble[]*)p2;
size_t len = s1.length;
if (s2.length < len)
len = s2.length;
for (size_t u = 0; u < len; u++)
{
int c = TypeInfo_r._compare(s1[u], s2[u]);
if (c)
return c;
}
if (s1.length < s2.length)
return -1;
else if (s1.length > s2.length)
return 1;
return 0;
}
override size_t tsize()
{
return (cdouble[]).sizeof;
}
override uint flags()
{
return 1;
}
override TypeInfo next()
{
return typeid(cdouble);
}
}

View File

@@ -0,0 +1,103 @@
/*
* Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
* Written by Walter Bright
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, in both source and binary form, subject to the following
* restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
module rt.typeinfo.ti_Acfloat;
private import typeinfo.ti_cfloat;
// cfloat[]
class TypeInfo_Aq : TypeInfo
{
override string toString() { return "cfloat[]"; }
override hash_t getHash(in void* p)
{ cfloat[] s = *cast(cfloat[]*)p;
size_t len = s.length;
cfloat *str = s.ptr;
hash_t hash = 0;
while (len)
{
hash *= 9;
hash += (cast(uint *)str)[0];
hash += (cast(uint *)str)[1];
str++;
len--;
}
return hash;
}
override equals_t equals(in void* p1, in void* p2)
{
cfloat[] s1 = *cast(cfloat[]*)p1;
cfloat[] s2 = *cast(cfloat[]*)p2;
size_t len = s1.length;
if (len != s2.length)
return false;
for (size_t u = 0; u < len; u++)
{
if (!TypeInfo_q._equals(s1[u], s2[u]))
return false;
}
return true;
}
override int compare(in void* p1, in void* p2)
{
cfloat[] s1 = *cast(cfloat[]*)p1;
cfloat[] s2 = *cast(cfloat[]*)p2;
size_t len = s1.length;
if (s2.length < len)
len = s2.length;
for (size_t u = 0; u < len; u++)
{
int c = TypeInfo_q._compare(s1[u], s2[u]);
if (c)
return c;
}
if (s1.length < s2.length)
return -1;
else if (s1.length > s2.length)
return 1;
return 0;
}
override size_t tsize()
{
return (cfloat[]).sizeof;
}
override uint flags()
{
return 1;
}
override TypeInfo next()
{
return typeid(cfloat);
}
}

View File

@@ -0,0 +1,106 @@
/*
* Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
* Written by Walter Bright
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, in both source and binary form, subject to the following
* restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
module rt.typeinfo.ti_Acreal;
private import typeinfo.ti_creal;
// creal[]
class TypeInfo_Ac : TypeInfo
{
override string toString() { return "creal[]"; }
override hash_t getHash(in void* p)
{ creal[] s = *cast(creal[]*)p;
size_t len = s.length;
creal *str = s.ptr;
hash_t hash = 0;
while (len)
{
hash *= 9;
hash += (cast(uint *)str)[0];
hash += (cast(uint *)str)[1];
hash += (cast(uint *)str)[2];
hash += (cast(uint *)str)[3];
hash += (cast(uint *)str)[4];
str++;
len--;
}
return hash;
}
override equals_t equals(in void* p1, in void* p2)
{
creal[] s1 = *cast(creal[]*)p1;
creal[] s2 = *cast(creal[]*)p2;
size_t len = s1.length;
if (len != s2.length)
return 0;
for (size_t u = 0; u < len; u++)
{
if (!TypeInfo_c._equals(s1[u], s2[u]))
return false;
}
return true;
}
override int compare(in void* p1, in void* p2)
{
creal[] s1 = *cast(creal[]*)p1;
creal[] s2 = *cast(creal[]*)p2;
size_t len = s1.length;
if (s2.length < len)
len = s2.length;
for (size_t u = 0; u < len; u++)
{
int c = TypeInfo_c._compare(s1[u], s2[u]);
if (c)
return c;
}
if (s1.length < s2.length)
return -1;
else if (s1.length > s2.length)
return 1;
return 0;
}
override size_t tsize()
{
return (creal[]).sizeof;
}
override uint flags()
{
return 1;
}
override TypeInfo next()
{
return typeid(creal);
}
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
* Written by Walter Bright
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, in both source and binary form, subject to the following
* restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
module rt.typeinfo.ti_Adouble;
private import typeinfo.ti_double;
// double[]
class TypeInfo_Ad : TypeInfo
{
override string toString() { return "double[]"; }
override hash_t getHash(in void* p)
{ double[] s = *cast(double[]*)p;
size_t len = s.length;
auto str = s.ptr;
hash_t hash = 0;
while (len)
{
hash *= 9;
hash += (cast(uint *)str)[0];
hash += (cast(uint *)str)[1];
str++;
len--;
}
return hash;
}
override equals_t equals(in void* p1, in void* p2)
{
double[] s1 = *cast(double[]*)p1;
double[] s2 = *cast(double[]*)p2;
size_t len = s1.length;
if (len != s2.length)
return 0;
for (size_t u = 0; u < len; u++)
{
if (!TypeInfo_d._equals(s1[u], s2[u]))
return false;
}
return true;
}
override int compare(in void* p1, in void* p2)
{
double[] s1 = *cast(double[]*)p1;
double[] s2 = *cast(double[]*)p2;
size_t len = s1.length;
if (s2.length < len)
len = s2.length;
for (size_t u = 0; u < len; u++)
{
int c = TypeInfo_d._compare(s1[u], s2[u]);
if (c)
return c;
}
if (s1.length < s2.length)
return -1;
else if (s1.length > s2.length)
return 1;
return 0;
}
override size_t tsize()
{
return (double[]).sizeof;
}
override uint flags()
{
return 1;
}
override TypeInfo next()
{
return typeid(double);
}
}
// idouble[]
class TypeInfo_Ap : TypeInfo_Ad
{
override string toString() { return "idouble[]"; }
override TypeInfo next()
{
return typeid(idouble);
}
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
* Written by Walter Bright
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, in both source and binary form, subject to the following
* restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
module rt.typeinfo.ti_Afloat;
private import typeinfo.ti_float;
// float[]
class TypeInfo_Af : TypeInfo
{
override string toString() { return "float[]"; }
override hash_t getHash(in void* p)
{ float[] s = *cast(float[]*)p;
size_t len = s.length;
auto str = s.ptr;
hash_t hash = 0;
while (len)
{
hash *= 9;
hash += *cast(uint *)str;
str++;
len--;
}
return hash;
}
override equals_t equals(in void* p1, in void* p2)
{
float[] s1 = *cast(float[]*)p1;
float[] s2 = *cast(float[]*)p2;
size_t len = s1.length;
if (len != s2.length)
return 0;
for (size_t u = 0; u < len; u++)
{
if (!TypeInfo_f._equals(s1[u], s2[u]))
return false;
}
return true;
}
override int compare(in void* p1, in void* p2)
{
float[] s1 = *cast(float[]*)p1;
float[] s2 = *cast(float[]*)p2;
size_t len = s1.length;
if (s2.length < len)
len = s2.length;
for (size_t u = 0; u < len; u++)
{
int c = TypeInfo_f._compare(s1[u], s2[u]);
if (c)
return c;
}
if (s1.length < s2.length)
return -1;
else if (s1.length > s2.length)
return 1;
return 0;
}
override size_t tsize()
{
return (float[]).sizeof;
}
override uint flags()
{
return 1;
}
override TypeInfo next()
{
return typeid(float);
}
}
// ifloat[]
class TypeInfo_Ao : TypeInfo_Af
{
override string toString() { return "ifloat[]"; }
override TypeInfo next()
{
return typeid(ifloat);
}
}

View File

@@ -0,0 +1,204 @@
module rt.typeinfo.ti_Ag;
private import util.string;
private import stdc.string;
// byte[]
class TypeInfo_Ag : TypeInfo
{
override string toString() { return "byte[]"; }
override hash_t getHash(in void* p)
{ byte[] s = *cast(byte[]*)p;
size_t len = s.length;
byte *str = s.ptr;
hash_t hash = 0;
while (1)
{
switch (len)
{
case 0:
return hash;
case 1:
hash *= 9;
hash += *cast(ubyte *)str;
return hash;
case 2:
hash *= 9;
hash += *cast(ushort *)str;
return hash;
case 3:
hash *= 9;
hash += (*cast(ushort *)str << 8) +
(cast(ubyte *)str)[2];
return hash;
default:
hash *= 9;
hash += *cast(uint *)str;
str += 4;
len -= 4;
break;
}
}
return hash;
}
override equals_t equals(in void* p1, in void* p2)
{
byte[] s1 = *cast(byte[]*)p1;
byte[] s2 = *cast(byte[]*)p2;
return s1.length == s2.length &&
memcmp(cast(byte *)s1, cast(byte *)s2, s1.length) == 0;
}
override int compare(in void* p1, in void* p2)
{
byte[] s1 = *cast(byte[]*)p1;
byte[] s2 = *cast(byte[]*)p2;
size_t len = s1.length;
if (s2.length < len)
len = s2.length;
for (size_t u = 0; u < len; u++)
{
int result = s1[u] - s2[u];
if (result)
return result;
}
if (s1.length < s2.length)
return -1;
else if (s1.length > s2.length)
return 1;
return 0;
}
override size_t tsize()
{
return (byte[]).sizeof;
}
override uint flags()
{
return 1;
}
override TypeInfo next()
{
return typeid(byte);
}
}
// ubyte[]
class TypeInfo_Ah : TypeInfo_Ag
{
override string toString() { return "ubyte[]"; }
override int compare(in void* p1, in void* p2)
{
char[] s1 = *cast(char[]*)p1;
char[] s2 = *cast(char[]*)p2;
return dstrcmp(s1, s2);
}
override TypeInfo next()
{
return typeid(ubyte);
}
}
// void[]
class TypeInfo_Av : TypeInfo_Ah
{
override string toString() { return "void[]"; }
override TypeInfo next()
{
return typeid(void);
}
}
// bool[]
class TypeInfo_Ab : TypeInfo_Ah
{
override string toString() { return "bool[]"; }
override TypeInfo next()
{
return typeid(bool);
}
}
// char[]
class TypeInfo_Aa : TypeInfo_Ag
{
override string toString() { return "char[]"; }
override hash_t getHash(in void* p)
{ char[] s = *cast(char[]*)p;
hash_t hash = 0;
version (all)
{
foreach (char c; s)
hash = hash * 11 + c;
}
else
{
size_t len = s.length;
char *str = s;
while (1)
{
switch (len)
{
case 0:
return hash;
case 1:
hash *= 9;
hash += *cast(ubyte *)str;
return hash;
case 2:
hash *= 9;
hash += *cast(ushort *)str;
return hash;
case 3:
hash *= 9;
hash += (*cast(ushort *)str << 8) +
(cast(ubyte *)str)[2];
return hash;
default:
hash *= 9;
hash += *cast(uint *)str;
str += 4;
len -= 4;
break;
}
}
}
return hash;
}
override TypeInfo next()
{
return typeid(char);
}
}

View File

@@ -0,0 +1,129 @@
module rt.typeinfo.ti_Aint;
private import stdc.string;
// int[]
class TypeInfo_Ai : TypeInfo
{
override string toString() { return "int[]"; }
override hash_t getHash(in void* p)
{ int[] s = *cast(int[]*)p;
auto len = s.length;
auto str = s.ptr;
hash_t hash = 0;
while (len)
{
hash *= 9;
hash += *cast(uint *)str;
str++;
len--;
}
return hash;
}
override equals_t equals(in void* p1, in void* p2)
{
int[] s1 = *cast(int[]*)p1;
int[] s2 = *cast(int[]*)p2;
return s1.length == s2.length &&
memcmp(cast(void *)s1, cast(void *)s2, s1.length * int.sizeof) == 0;
}
override int compare(in void* p1, in void* p2)
{
int[] s1 = *cast(int[]*)p1;
int[] s2 = *cast(int[]*)p2;
size_t len = s1.length;
if (s2.length < len)
len = s2.length;
for (size_t u = 0; u < len; u++)
{
int result = s1[u] - s2[u];
if (result)
return result;
}
if (s1.length < s2.length)
return -1;
else if (s1.length > s2.length)
return 1;
return 0;
}
override size_t tsize()
{
return (int[]).sizeof;
}
override uint flags()
{
return 1;
}
override TypeInfo next()
{
return typeid(int);
}
}
unittest
{
int[][] a = [[5,3,8,7], [2,5,3,8,7]];
a.sort;
assert(a == [[2,5,3,8,7], [5,3,8,7]]);
a = [[5,3,8,7], [5,3,8]];
a.sort;
assert(a == [[5,3,8], [5,3,8,7]]);
}
// uint[]
class TypeInfo_Ak : TypeInfo_Ai
{
override string toString() { return "uint[]"; }
override int compare(in void* p1, in void* p2)
{
uint[] s1 = *cast(uint[]*)p1;
uint[] s2 = *cast(uint[]*)p2;
size_t len = s1.length;
if (s2.length < len)
len = s2.length;
for (size_t u = 0; u < len; u++)
{
int result = s1[u] - s2[u];
if (result)
return result;
}
if (s1.length < s2.length)
return -1;
else if (s1.length > s2.length)
return 1;
return 0;
}
override TypeInfo next()
{
return typeid(uint);
}
}
// dchar[]
class TypeInfo_Aw : TypeInfo_Ak
{
override string toString() { return "dchar[]"; }
override TypeInfo next()
{
return typeid(dchar);
}
}

View File

@@ -0,0 +1,109 @@
module rt.typeinfo.ti_Along;
private import stdc.string;
// long[]
class TypeInfo_Al : TypeInfo
{
override string toString() { return "long[]"; }
override hash_t getHash(in void* p)
{ long[] s = *cast(long[]*)p;
size_t len = s.length;
auto str = s.ptr;
hash_t hash = 0;
while (len)
{
hash *= 9;
hash += *cast(uint *)str + *(cast(uint *)str + 1);
str++;
len--;
}
return hash;
}
override equals_t equals(in void* p1, in void* p2)
{
long[] s1 = *cast(long[]*)p1;
long[] s2 = *cast(long[]*)p2;
return s1.length == s2.length &&
memcmp(cast(void *)s1, cast(void *)s2, s1.length * long.sizeof) == 0;
}
override int compare(in void* p1, in void* p2)
{
long[] s1 = *cast(long[]*)p1;
long[] s2 = *cast(long[]*)p2;
size_t len = s1.length;
if (s2.length < len)
len = s2.length;
for (size_t u = 0; u < len; u++)
{
if (s1[u] < s2[u])
return -1;
else if (s1[u] > s2[u])
return 1;
}
if (s1.length < s2.length)
return -1;
else if (s1.length > s2.length)
return 1;
return 0;
}
override size_t tsize()
{
return (long[]).sizeof;
}
override uint flags()
{
return 1;
}
override TypeInfo next()
{
return typeid(long);
}
}
// ulong[]
class TypeInfo_Am : TypeInfo_Al
{
override string toString() { return "ulong[]"; }
override int compare(in void* p1, in void* p2)
{
ulong[] s1 = *cast(ulong[]*)p1;
ulong[] s2 = *cast(ulong[]*)p2;
size_t len = s1.length;
if (s2.length < len)
len = s2.length;
for (size_t u = 0; u < len; u++)
{
if (s1[u] < s2[u])
return -1;
else if (s1[u] > s2[u])
return 1;
}
if (s1.length < s2.length)
return -1;
else if (s1.length > s2.length)
return 1;
return 0;
}
override TypeInfo next()
{
return typeid(ulong);
}
}

View File

@@ -0,0 +1,116 @@
/*
* Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
* Written by Walter Bright
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, in both source and binary form, subject to the following
* restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
module rt.typeinfo.ti_Areal;
private import typeinfo.ti_real;
// real[]
class TypeInfo_Ae : TypeInfo
{
override string toString() { return "real[]"; }
override hash_t getHash(in void* p)
{ real[] s = *cast(real[]*)p;
size_t len = s.length;
auto str = s.ptr;
hash_t hash = 0;
while (len)
{
hash *= 9;
hash += (cast(uint *)str)[0];
hash += (cast(uint *)str)[1];
hash += (cast(ushort *)str)[4];
str++;
len--;
}
return hash;
}
override equals_t equals(in void* p1, in void* p2)
{
real[] s1 = *cast(real[]*)p1;
real[] s2 = *cast(real[]*)p2;
size_t len = s1.length;
if (len != s2.length)
return false;
for (size_t u = 0; u < len; u++)
{
if (!TypeInfo_e._equals(s1[u], s2[u]))
return false;
}
return true;
}
override int compare(in void* p1, in void* p2)
{
real[] s1 = *cast(real[]*)p1;
real[] s2 = *cast(real[]*)p2;
size_t len = s1.length;
if (s2.length < len)
len = s2.length;
for (size_t u = 0; u < len; u++)
{
int c = TypeInfo_e._compare(s1[u], s2[u]);
if (c)
return c;
}
if (s1.length < s2.length)
return -1;
else if (s1.length > s2.length)
return 1;
return 0;
}
override size_t tsize()
{
return (real[]).sizeof;
}
override uint flags()
{
return 1;
}
override TypeInfo next()
{
return typeid(real);
}
}
// ireal[]
class TypeInfo_Aj : TypeInfo_Ae
{
override string toString() { return "ireal[]"; }
override TypeInfo next()
{
return typeid(ireal);
}
}

View File

@@ -0,0 +1,132 @@
module rt.typeinfo.ti_Ashort;
private import stdc.string;
// short[]
class TypeInfo_As : TypeInfo
{
override string toString() { return "short[]"; }
override hash_t getHash(in void* p)
{ short[] s = *cast(short[]*)p;
size_t len = s.length;
short *str = s.ptr;
hash_t hash = 0;
while (1)
{
switch (len)
{
case 0:
return hash;
case 1:
hash *= 9;
hash += *cast(ushort *)str;
return hash;
default:
hash *= 9;
hash += *cast(uint *)str;
str += 2;
len -= 2;
break;
}
}
return hash;
}
override equals_t equals(in void* p1, in void* p2)
{
short[] s1 = *cast(short[]*)p1;
short[] s2 = *cast(short[]*)p2;
return s1.length == s2.length &&
memcmp(cast(void *)s1, cast(void *)s2, s1.length * short.sizeof) == 0;
}
override int compare(in void* p1, in void* p2)
{
short[] s1 = *cast(short[]*)p1;
short[] s2 = *cast(short[]*)p2;
size_t len = s1.length;
if (s2.length < len)
len = s2.length;
for (size_t u = 0; u < len; u++)
{
int result = s1[u] - s2[u];
if (result)
return result;
}
if (s1.length < s2.length)
return -1;
else if (s1.length > s2.length)
return 1;
return 0;
}
override size_t tsize()
{
return (short[]).sizeof;
}
override uint flags()
{
return 1;
}
override TypeInfo next()
{
return typeid(short);
}
}
// ushort[]
class TypeInfo_At : TypeInfo_As
{
override string toString() { return "ushort[]"; }
override int compare(in void* p1, in void* p2)
{
ushort[] s1 = *cast(ushort[]*)p1;
ushort[] s2 = *cast(ushort[]*)p2;
size_t len = s1.length;
if (s2.length < len)
len = s2.length;
for (size_t u = 0; u < len; u++)
{
int result = s1[u] - s2[u];
if (result)
return result;
}
if (s1.length < s2.length)
return -1;
else if (s1.length > s2.length)
return 1;
return 0;
}
override TypeInfo next()
{
return typeid(ushort);
}
}
// wchar[]
class TypeInfo_Au : TypeInfo_At
{
override string toString() { return "wchar[]"; }
override TypeInfo next()
{
return typeid(wchar);
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
* Written by Walter Bright
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, in both source and binary form, subject to the following
* restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
module rt.typeinfo.ti_C;
// Object
class TypeInfo_C : TypeInfo
{
override hash_t getHash(in void* p)
{
Object o = *cast(Object*)p;
return o ? o.toHash() : 0;
}
override equals_t equals(in void* p1, in void* p2)
{
Object o1 = *cast(Object*)p1;
Object o2 = *cast(Object*)p2;
return o1 == o2;
}
override int compare(in void* p1, in void* p2)
{
Object o1 = *cast(Object*)p1;
Object o2 = *cast(Object*)p2;
int c = 0;
// Regard null references as always being "less than"
if (!(o1 is o2))
{
if (o1)
{ if (!o2)
c = 1;
else
c = o1.opCmp(o2);
}
else
c = -1;
}
return c;
}
override size_t tsize()
{
return Object.sizeof;
}
override uint flags()
{
return 1;
}
}

View File

@@ -0,0 +1,38 @@
// byte
module rt.typeinfo.ti_byte;
class TypeInfo_g : TypeInfo
{
override string toString() { return "byte"; }
override hash_t getHash(in void* p)
{
return *cast(byte *)p;
}
override equals_t equals(in void* p1, in void* p2)
{
return *cast(byte *)p1 == *cast(byte *)p2;
}
override int compare(in void* p1, in void* p2)
{
return *cast(byte *)p1 - *cast(byte *)p2;
}
override size_t tsize()
{
return byte.sizeof;
}
override void swap(void *p1, void *p2)
{
byte t;
t = *cast(byte *)p1;
*cast(byte *)p1 = *cast(byte *)p2;
*cast(byte *)p2 = t;
}
}

View File

@@ -0,0 +1,66 @@
// cdouble
module rt.typeinfo.ti_cdouble;
class TypeInfo_r : TypeInfo
{
override string toString() { return "cdouble"; }
override hash_t getHash(in void* p)
{
return (cast(uint *)p)[0] + (cast(uint *)p)[1] +
(cast(uint *)p)[2] + (cast(uint *)p)[3];
}
static equals_t _equals(cdouble f1, cdouble f2)
{
return f1 == f2;
}
static int _compare(cdouble f1, cdouble f2)
{ int result;
if (f1.re < f2.re)
result = -1;
else if (f1.re > f2.re)
result = 1;
else if (f1.im < f2.im)
result = -1;
else if (f1.im > f2.im)
result = 1;
else
result = 0;
return result;
}
override equals_t equals(in void* p1, in void* p2)
{
return _equals(*cast(cdouble *)p1, *cast(cdouble *)p2);
}
override int compare(in void* p1, in void* p2)
{
return _compare(*cast(cdouble *)p1, *cast(cdouble *)p2);
}
override size_t tsize()
{
return cdouble.sizeof;
}
override void swap(void *p1, void *p2)
{
cdouble t;
t = *cast(cdouble *)p1;
*cast(cdouble *)p1 = *cast(cdouble *)p2;
*cast(cdouble *)p2 = t;
}
override void[] init()
{ static cdouble r;
return (cast(cdouble *)&r)[0 .. 1];
}
}

View File

@@ -0,0 +1,65 @@
// cfloat
module rt.typeinfo.ti_cfloat;
class TypeInfo_q : TypeInfo
{
override string toString() { return "cfloat"; }
override hash_t getHash(in void* p)
{
return (cast(uint *)p)[0] + (cast(uint *)p)[1];
}
static equals_t _equals(cfloat f1, cfloat f2)
{
return f1 == f2;
}
static int _compare(cfloat f1, cfloat f2)
{ int result;
if (f1.re < f2.re)
result = -1;
else if (f1.re > f2.re)
result = 1;
else if (f1.im < f2.im)
result = -1;
else if (f1.im > f2.im)
result = 1;
else
result = 0;
return result;
}
override equals_t equals(in void* p1, in void* p2)
{
return _equals(*cast(cfloat *)p1, *cast(cfloat *)p2);
}
override int compare(in void* p1, in void* p2)
{
return _compare(*cast(cfloat *)p1, *cast(cfloat *)p2);
}
override size_t tsize()
{
return cfloat.sizeof;
}
override void swap(void *p1, void *p2)
{
cfloat t;
t = *cast(cfloat *)p1;
*cast(cfloat *)p1 = *cast(cfloat *)p2;
*cast(cfloat *)p2 = t;
}
override void[] init()
{ static cfloat r;
return (cast(cfloat *)&r)[0 .. 1];
}
}

View File

@@ -0,0 +1,42 @@
module rt.typeinfo.ti_char;
class TypeInfo_a : TypeInfo
{
override string toString() { return "char"; }
override hash_t getHash(in void* p)
{
return *cast(char *)p;
}
override equals_t equals(in void* p1, in void* p2)
{
return *cast(char *)p1 == *cast(char *)p2;
}
override int compare(in void* p1, in void* p2)
{
return *cast(char *)p1 - *cast(char *)p2;
}
override size_t tsize()
{
return char.sizeof;
}
override void swap(void *p1, void *p2)
{
char t;
t = *cast(char *)p1;
*cast(char *)p1 = *cast(char *)p2;
*cast(char *)p2 = t;
}
override void[] init()
{ static char c;
return (cast(char *)&c)[0 .. 1];
}
}

View File

@@ -0,0 +1,67 @@
// creal
module rt.typeinfo.ti_creal;
class TypeInfo_c : TypeInfo
{
override string toString() { return "creal"; }
override hash_t getHash(in void* p)
{
return (cast(uint *)p)[0] + (cast(uint *)p)[1] +
(cast(uint *)p)[2] + (cast(uint *)p)[3] +
(cast(uint *)p)[4];
}
static equals_t _equals(creal f1, creal f2)
{
return f1 == f2;
}
static int _compare(creal f1, creal f2)
{ int result;
if (f1.re < f2.re)
result = -1;
else if (f1.re > f2.re)
result = 1;
else if (f1.im < f2.im)
result = -1;
else if (f1.im > f2.im)
result = 1;
else
result = 0;
return result;
}
override equals_t equals(in void* p1, in void* p2)
{
return _equals(*cast(creal *)p1, *cast(creal *)p2);
}
override int compare(in void* p1, in void* p2)
{
return _compare(*cast(creal *)p1, *cast(creal *)p2);
}
override size_t tsize()
{
return creal.sizeof;
}
override void swap(void *p1, void *p2)
{
creal t;
t = *cast(creal *)p1;
*cast(creal *)p1 = *cast(creal *)p2;
*cast(creal *)p2 = t;
}
override void[] init()
{ static creal r;
return (cast(creal *)&r)[0 .. 1];
}
}

View File

@@ -0,0 +1,44 @@
// dchar
module rt.typeinfo.ti_dchar;
class TypeInfo_w : TypeInfo
{
override string toString() { return "dchar"; }
override hash_t getHash(in void* p)
{
return *cast(dchar *)p;
}
override equals_t equals(in void* p1, in void* p2)
{
return *cast(dchar *)p1 == *cast(dchar *)p2;
}
override int compare(in void* p1, in void* p2)
{
return *cast(dchar *)p1 - *cast(dchar *)p2;
}
override size_t tsize()
{
return dchar.sizeof;
}
override void swap(void *p1, void *p2)
{
dchar t;
t = *cast(dchar *)p1;
*cast(dchar *)p1 = *cast(dchar *)p2;
*cast(dchar *)p2 = t;
}
override void[] init()
{ static dchar c;
return (cast(dchar *)&c)[0 .. 1];
}
}

View File

@@ -0,0 +1,39 @@
// delegate
module rt.typeinfo.ti_delegate;
alias void delegate(int) dg;
class TypeInfo_D : TypeInfo
{
override hash_t getHash(in void* p)
{ long l = *cast(long *)p;
return cast(uint)(l + (l >> 32));
}
override equals_t equals(in void* p1, in void* p2)
{
return *cast(dg *)p1 == *cast(dg *)p2;
}
override size_t tsize()
{
return dg.sizeof;
}
override void swap(void *p1, void *p2)
{
dg t;
t = *cast(dg *)p1;
*cast(dg *)p1 = *cast(dg *)p2;
*cast(dg *)p2 = t;
}
override uint flags()
{
return 1;
}
}

View File

@@ -0,0 +1,64 @@
// double
module rt.typeinfo.ti_double;
class TypeInfo_d : TypeInfo
{
override string toString() { return "double"; }
override hash_t getHash(in void* p)
{
return (cast(uint *)p)[0] + (cast(uint *)p)[1];
}
static equals_t _equals(double f1, double f2)
{
return f1 == f2 ||
(f1 !<>= f1 && f2 !<>= f2);
}
static int _compare(double d1, double d2)
{
if (d1 !<>= d2) // if either are NaN
{
if (d1 !<>= d1)
{ if (d2 !<>= d2)
return 0;
return -1;
}
return 1;
}
return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1);
}
override equals_t equals(in void* p1, in void* p2)
{
return _equals(*cast(double *)p1, *cast(double *)p2);
}
override int compare(in void* p1, in void* p2)
{
return _compare(*cast(double *)p1, *cast(double *)p2);
}
override size_t tsize()
{
return double.sizeof;
}
override void swap(void *p1, void *p2)
{
double t;
t = *cast(double *)p1;
*cast(double *)p1 = *cast(double *)p2;
*cast(double *)p2 = t;
}
override void[] init()
{ static double r;
return (cast(double *)&r)[0 .. 1];
}
}

View File

@@ -0,0 +1,64 @@
// float
module rt.typeinfo.ti_float;
class TypeInfo_f : TypeInfo
{
override string toString() { return "float"; }
override hash_t getHash(in void* p)
{
return *cast(uint *)p;
}
static equals_t _equals(float f1, float f2)
{
return f1 == f2 ||
(f1 !<>= f1 && f2 !<>= f2);
}
static int _compare(float d1, float d2)
{
if (d1 !<>= d2) // if either are NaN
{
if (d1 !<>= d1)
{ if (d2 !<>= d2)
return 0;
return -1;
}
return 1;
}
return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1);
}
override equals_t equals(in void* p1, in void* p2)
{
return _equals(*cast(float *)p1, *cast(float *)p2);
}
override int compare(in void* p1, in void* p2)
{
return _compare(*cast(float *)p1, *cast(float *)p2);
}
override size_t tsize()
{
return float.sizeof;
}
override void swap(void *p1, void *p2)
{
float t;
t = *cast(float *)p1;
*cast(float *)p1 = *cast(float *)p2;
*cast(float *)p2 = t;
}
override void[] init()
{ static float r;
return (cast(float *)&r)[0 .. 1];
}
}

View File

@@ -0,0 +1,11 @@
// idouble
module rt.typeinfo.ti_idouble;
private import typeinfo.ti_double;
class TypeInfo_p : TypeInfo_d
{
override string toString() { return "idouble"; }
}

View File

@@ -0,0 +1,11 @@
// ifloat
module rt.typeinfo.ti_ifloat;
private import typeinfo.ti_float;
class TypeInfo_o : TypeInfo_f
{
override string toString() { return "ifloat"; }
}

View File

@@ -0,0 +1,42 @@
// int
module rt.typeinfo.ti_int;
class TypeInfo_i : TypeInfo
{
override string toString() { return "int"; }
override hash_t getHash(in void* p)
{
return *cast(uint *)p;
}
override equals_t equals(in void* p1, in void* p2)
{
return *cast(uint *)p1 == *cast(uint *)p2;
}
override int compare(in void* p1, in void* p2)
{
if (*cast(int*) p1 < *cast(int*) p2)
return -1;
else if (*cast(int*) p1 > *cast(int*) p2)
return 1;
return 0;
}
override size_t tsize()
{
return int.sizeof;
}
override void swap(void *p1, void *p2)
{
int t;
t = *cast(int *)p1;
*cast(int *)p1 = *cast(int *)p2;
*cast(int *)p2 = t;
}
}

View File

@@ -0,0 +1,11 @@
// ireal
module rt.typeinfo.ti_ireal;
private import typeinfo.ti_real;
class TypeInfo_j : TypeInfo_e
{
override string toString() { return "ireal"; }
}

View File

@@ -0,0 +1,42 @@
// long
module rt.typeinfo.ti_long;
class TypeInfo_l : TypeInfo
{
override string toString() { return "long"; }
override hash_t getHash(in void* p)
{
return *cast(uint *)p + (cast(uint *)p)[1];
}
override equals_t equals(in void* p1, in void* p2)
{
return *cast(long *)p1 == *cast(long *)p2;
}
override int compare(in void* p1, in void* p2)
{
if (*cast(long *)p1 < *cast(long *)p2)
return -1;
else if (*cast(long *)p1 > *cast(long *)p2)
return 1;
return 0;
}
override size_t tsize()
{
return long.sizeof;
}
override void swap(void *p1, void *p2)
{
long t;
t = *cast(long *)p1;
*cast(long *)p1 = *cast(long *)p2;
*cast(long *)p2 = t;
}
}

View File

@@ -0,0 +1,46 @@
// pointer
module rt.typeinfo.ti_ptr;
class TypeInfo_P : TypeInfo
{
override hash_t getHash(in void* p)
{
return cast(uint)*cast(void* *)p;
}
override equals_t equals(in void* p1, in void* p2)
{
return *cast(void* *)p1 == *cast(void* *)p2;
}
override int compare(in void* p1, in void* p2)
{
auto c = *cast(void* *)p1 - *cast(void* *)p2;
if (c < 0)
return -1;
else if (c > 0)
return 1;
return 0;
}
override size_t tsize()
{
return (void*).sizeof;
}
override void swap(void *p1, void *p2)
{
void* t;
t = *cast(void* *)p1;
*cast(void* *)p1 = *cast(void* *)p2;
*cast(void* *)p2 = t;
}
override uint flags()
{
return 1;
}
}

View File

@@ -0,0 +1,64 @@
// real
module rt.typeinfo.ti_real;
class TypeInfo_e : TypeInfo
{
override string toString() { return "real"; }
override hash_t getHash(in void* p)
{
return (cast(uint *)p)[0] + (cast(uint *)p)[1] + (cast(ushort *)p)[4];
}
static equals_t _equals(real f1, real f2)
{
return f1 == f2 ||
(f1 !<>= f1 && f2 !<>= f2);
}
static int _compare(real d1, real d2)
{
if (d1 !<>= d2) // if either are NaN
{
if (d1 !<>= d1)
{ if (d2 !<>= d2)
return 0;
return -1;
}
return 1;
}
return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1);
}
override equals_t equals(in void* p1, in void* p2)
{
return _equals(*cast(real *)p1, *cast(real *)p2);
}
override int compare(in void* p1, in void* p2)
{
return _compare(*cast(real *)p1, *cast(real *)p2);
}
override size_t tsize()
{
return real.sizeof;
}
override void swap(void *p1, void *p2)
{
real t;
t = *cast(real *)p1;
*cast(real *)p1 = *cast(real *)p2;
*cast(real *)p2 = t;
}
override void[] init()
{ static real r;
return (cast(real *)&r)[0 .. 1];
}
}

View File

@@ -0,0 +1,38 @@
// short
module rt.typeinfo.ti_short;
class TypeInfo_s : TypeInfo
{
override string toString() { return "short"; }
override hash_t getHash(in void* p)
{
return *cast(short *)p;
}
override equals_t equals(in void* p1, in void* p2)
{
return *cast(short *)p1 == *cast(short *)p2;
}
override int compare(in void* p1, in void* p2)
{
return *cast(short *)p1 - *cast(short *)p2;
}
override size_t tsize()
{
return short.sizeof;
}
override void swap(void *p1, void *p2)
{
short t;
t = *cast(short *)p1;
*cast(short *)p1 = *cast(short *)p2;
*cast(short *)p2 = t;
}
}

View File

@@ -0,0 +1,43 @@
// ubyte
module rt.typeinfo.ti_ubyte;
class TypeInfo_h : TypeInfo
{
override string toString() { return "ubyte"; }
override hash_t getHash(in void* p)
{
return *cast(ubyte *)p;
}
override equals_t equals(in void* p1, in void* p2)
{
return *cast(ubyte *)p1 == *cast(ubyte *)p2;
}
override int compare(in void* p1, in void* p2)
{
return *cast(ubyte *)p1 - *cast(ubyte *)p2;
}
override size_t tsize()
{
return ubyte.sizeof;
}
override void swap(void *p1, void *p2)
{
ubyte t;
t = *cast(ubyte *)p1;
*cast(ubyte *)p1 = *cast(ubyte *)p2;
*cast(ubyte *)p2 = t;
}
}
class TypeInfo_b : TypeInfo_h
{
override string toString() { return "bool"; }
}

View File

@@ -0,0 +1,42 @@
// uint
module rt.typeinfo.ti_uint;
class TypeInfo_k : TypeInfo
{
override string toString() { return "uint"; }
override hash_t getHash(in void* p)
{
return *cast(uint *)p;
}
override equals_t equals(in void* p1, in void* p2)
{
return *cast(uint *)p1 == *cast(uint *)p2;
}
override int compare(in void* p1, in void* p2)
{
if (*cast(uint*) p1 < *cast(uint*) p2)
return -1;
else if (*cast(uint*) p1 > *cast(uint*) p2)
return 1;
return 0;
}
override size_t tsize()
{
return uint.sizeof;
}
override void swap(void *p1, void *p2)
{
int t;
t = *cast(uint *)p1;
*cast(uint *)p1 = *cast(uint *)p2;
*cast(uint *)p2 = t;
}
}

View File

@@ -0,0 +1,42 @@
// ulong
module rt.typeinfo.ti_ulong;
class TypeInfo_m : TypeInfo
{
override string toString() { return "ulong"; }
override hash_t getHash(in void* p)
{
return *cast(uint *)p + (cast(uint *)p)[1];
}
override equals_t equals(in void* p1, in void* p2)
{
return *cast(ulong *)p1 == *cast(ulong *)p2;
}
override int compare(in void* p1, in void* p2)
{
if (*cast(ulong *)p1 < *cast(ulong *)p2)
return -1;
else if (*cast(ulong *)p1 > *cast(ulong *)p2)
return 1;
return 0;
}
override size_t tsize()
{
return ulong.sizeof;
}
override void swap(void *p1, void *p2)
{
ulong t;
t = *cast(ulong *)p1;
*cast(ulong *)p1 = *cast(ulong *)p2;
*cast(ulong *)p2 = t;
}
}

View File

@@ -0,0 +1,38 @@
// ushort
module rt.typeinfo.ti_ushort;
class TypeInfo_t : TypeInfo
{
override string toString() { return "ushort"; }
override hash_t getHash(in void* p)
{
return *cast(ushort *)p;
}
override equals_t equals(in void* p1, in void* p2)
{
return *cast(ushort *)p1 == *cast(ushort *)p2;
}
override int compare(in void* p1, in void* p2)
{
return *cast(ushort *)p1 - *cast(ushort *)p2;
}
override size_t tsize()
{
return ushort.sizeof;
}
override void swap(void *p1, void *p2)
{
ushort t;
t = *cast(ushort *)p1;
*cast(ushort *)p1 = *cast(ushort *)p2;
*cast(ushort *)p2 = t;
}
}

View File

@@ -0,0 +1,43 @@
// void
module rt.typeinfo.ti_void;
class TypeInfo_v : TypeInfo
{
override string toString() { return "void"; }
override hash_t getHash(in void* p)
{
assert(0);
}
override equals_t equals(in void* p1, in void* p2)
{
return *cast(byte *)p1 == *cast(byte *)p2;
}
override int compare(in void* p1, in void* p2)
{
return *cast(byte *)p1 - *cast(byte *)p2;
}
override size_t tsize()
{
return void.sizeof;
}
override void swap(void *p1, void *p2)
{
byte t;
t = *cast(byte *)p1;
*cast(byte *)p1 = *cast(byte *)p2;
*cast(byte *)p2 = t;
}
override uint flags()
{
return 1;
}
}

View File

@@ -0,0 +1,43 @@
module rt.typeinfo.ti_wchar;
class TypeInfo_u : TypeInfo
{
override string toString() { return "wchar"; }
override hash_t getHash(in void* p)
{
return *cast(wchar *)p;
}
override equals_t equals(in void* p1, in void* p2)
{
return *cast(wchar *)p1 == *cast(wchar *)p2;
}
override int compare(in void* p1, in void* p2)
{
return *cast(wchar *)p1 - *cast(wchar *)p2;
}
override size_t tsize()
{
return wchar.sizeof;
}
override void swap(void *p1, void *p2)
{
wchar t;
t = *cast(wchar *)p1;
*cast(wchar *)p1 = *cast(wchar *)p2;
*cast(wchar *)p2 = t;
}
override void[] init()
{ static wchar c;
return (cast(wchar *)&c)[0 .. 1];
}
}

View File

@@ -0,0 +1,49 @@
/**
* The console module contains some simple routines for console output.
*
* Copyright: Public Domain
* License: Public Domain
* Authors: Sean Kelly
*/
module rt.util.console;
private
{
version (Windows)
{
import sys.windows.windows;
}
else version( Posix )
{
import stdc.posix.unistd;
}
import util.string;
}
struct Console
{
Console opCall( in char[] val )
{
version( Windows )
{
uint count = void;
WriteFile( GetStdHandle( 0xfffffff5 ), val.ptr, val.length, &count, null );
}
else version( Posix )
{
write( 2, val.ptr, val.length );
}
return *this;
}
Console opCall( uint val )
{
char[10] tmp = void;
return opCall( tmp.intToString( val ) );
}
}
Console console;

View File

@@ -0,0 +1,464 @@
/**
* Identify the characteristics of the host CPU.
*
* Implemented according to:
- AP-485 Intel(C) Processor Identification and the CPUID Instruction
$(LINK http://www.intel.com/design/xeon/applnots/241618.htm)
- Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2A: Instruction Set Reference, A-M
$(LINK http://developer.intel.com/design/pentium4/manuals/index_new.htm)
- AMD CPUID Specification Publication # 25481
$(LINK http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25481.pdf)
Example:
---
import std.cpuid;
import std.stdio;
void main()
{
writefln(std.cpuid.toString());
}
---
AUTHORS: Tomas Lindquist Olsen &lt;tomas@famolsen.dk&gt;
(slightly altered by Walter Bright)
COPYRIGHT: Public Domain
* BUGS: Only works on x86 CPUs
*
* Macros:
* WIKI = Phobos/StdCpuid
* COPYRIGHT = Public Domain
*/
/*
* Modified by Sean Kelly for use with the D Runtime Project
*/
module rt.util.cpuid;
private import stdc.string;
version(D_InlineAsm_X86)
{
/// Returns vendor string
char[] vendor() {return vendorStr;}
/// Returns processor string
string processor() {return processorStr;}
/// Is MMX supported?
bool mmx() {return (flags&MMX_BIT)!=0;}
/// Is FXSR supported?
bool fxsr() {return (flags&FXSR_BIT)!=0;}
/// Is SSE supported?
bool sse() {return (flags&SSE_BIT)!=0;}
/// Is SSE2 supported?
bool sse2() {return (flags&SSE2_BIT)!=0;}
/// Is SSE3 supported?
bool sse3() {return (misc&SSE3_BIT)!=0;}
/// Is SSSE3 supported?
bool ssse3() {return (misc&SSSE3_BIT)!=0;}
/// Is AMD 3DNOW supported?
bool amd3dnow() {return (exflags&AMD_3DNOW_BIT)!=0;}
/// Is AMD 3DNOW Ext supported?
bool amd3dnowExt() {return (exflags&AMD_3DNOW_EXT_BIT)!=0;}
/// Is AMD MMX supported?
bool amdMmx() {return (exflags&AMD_MMX_BIT)!=0;}
/// Is this an Intel Architecture IA64?
bool ia64() {return (flags&IA64_BIT)!=0;}
/// Is this an AMD 64?
bool amd64() {return (exflags&AMD64_BIT)!=0;}
/// Is hyperthreading supported?
bool hyperThreading() {return (flags&HTT_BIT)!=0;}
/// Returns number of threads per CPU
uint threadsPerCPU() {return maxThreads;}
/// Returns number of cores in CPU
uint coresPerCPU() {return maxCores;}
/// Is this an Intel processor?
bool intel() {return manufac==INTEL;}
/// Is this an AMD processor?
bool amd() {return manufac==AMD;}
/// Returns stepping
uint stepping() {return _stepping;}
/// Returns model
uint model() {return _model;}
/// Returns family
uint family() {return _family;}
//uint processorType() {return (signature>>>12)&0x3;}
static this()
{
getVendorString();
getProcessorString();
getFeatureFlags();
// stepping / family / model
_stepping = signature&0xF;
uint fbase = (signature>>>8)&0xF;
uint fex = (signature>>>20)&0xFF;
uint mbase = (signature>>>4)&0xF;
uint mex = (signature>>>16)&0xF;
// vendor specific
void function() threadFn;
switch(vendorStr)
{
case "GenuineIntel":
manufac = INTEL;
threadFn = &getThreadingIntel;
if (fbase == 0xF)
_family = fbase+fex;
else
_family = fbase;
if (_family == 0x6 || _family == 0xF)
_model = mbase+(mex<<4);
else
_model = mbase;
break;
case "AuthenticAMD":
manufac = AMD;
threadFn = &getThreadingAMD;
if (fbase < 0xF)
{
_family = fbase;
_model = mbase;
}
else
{
_family = fbase+fex;
_model = mbase+(mex<<4);
}
break;
default:
manufac = OTHER;
}
// threading details
if (hyperThreading && threadFn !is null)
{
threadFn();
}
}
private:
// feature flags
enum : uint
{
MMX_BIT = 1<<23,
FXSR_BIT = 1<<24,
SSE_BIT = 1<<25,
SSE2_BIT = 1<<26,
HTT_BIT = 1<<28,
IA64_BIT = 1<<30
}
// feature flags misc
enum : uint
{
SSE3_BIT = 1,
SSSE3_BIT = 1<<9
}
// extended feature flags
enum : uint
{
AMD_MMX_BIT = 1<<22,
AMD64_BIT = 1<<29,
AMD_3DNOW_EXT_BIT = 1<<30,
AMD_3DNOW_BIT = 1<<31
}
// manufacturer
enum
{
OTHER,
INTEL,
AMD
}
uint flags, misc, exflags, apic, signature;
uint _stepping, _model, _family;
char[12] vendorStr = 0;
string processorStr = "";
uint maxThreads=1;
uint maxCores=1;
uint manufac=OTHER;
/* **
* fetches the cpu vendor string
*/
private void getVendorString()
{
char* dst = vendorStr.ptr;
// puts the vendor string into dst
asm
{
mov EAX, 0 ;
cpuid ;
mov EAX, dst ;
mov [EAX], EBX ;
mov [EAX+4], EDX ;
mov [EAX+8], ECX ;
}
}
private void getProcessorString()
{
char[48] buffer;
char* dst = buffer.ptr;
// puts the processor string into dst
asm
{
mov EAX, 0x8000_0000 ;
cpuid ;
cmp EAX, 0x8000_0004 ;
jb PSLabel ; // no support
push EDI ;
mov EDI, dst ;
mov EAX, 0x8000_0002 ;
cpuid ;
mov [EDI], EAX ;
mov [EDI+4], EBX ;
mov [EDI+8], ECX ;
mov [EDI+12], EDX ;
mov EAX, 0x8000_0003 ;
cpuid ;
mov [EDI+16], EAX ;
mov [EDI+20], EBX ;
mov [EDI+24], ECX ;
mov [EDI+28], EDX ;
mov EAX, 0x8000_0004 ;
cpuid ;
mov [EDI+32], EAX ;
mov [EDI+36], EBX ;
mov [EDI+40], ECX ;
mov [EDI+44], EDX ;
pop EDI ;
PSLabel: ;
}
if (buffer[0] == char.init) // no support
return;
// seems many intel processors prepend whitespace
processorStr = cast(string)strip(toString(dst)).dup;
}
private void getFeatureFlags()
{
uint f,m,e,a,s;
asm
{
mov EAX, 0 ;
cpuid ;
cmp EAX, 1 ;
jb FeatLabel ; // no support
mov EAX, 1 ;
cpuid ;
mov f, EDX ;
mov m, ECX ;
mov a, EBX ;
mov s, EAX ;
FeatLabel: ;
mov EAX, 0x8000_0000 ;
cpuid ;
cmp EAX, 0x8000_0001 ;
jb FeatLabel2 ; // no support
mov EAX, 0x8000_0001 ;
cpuid ;
mov e, EDX ;
FeatLabel2:
;
}
flags = f;
misc = m;
exflags = e;
apic = a;
signature = s;
}
private void getThreadingIntel()
{
uint n;
ubyte b = 0;
asm
{
mov EAX, 0 ;
cpuid ;
cmp EAX, 4 ;
jb IntelSingle ;
mov EAX, 4 ;
mov ECX, 0 ;
cpuid ;
mov n, EAX ;
mov b, 1 ;
IntelSingle: ;
}
if (b != 0)
{
maxCores = ((n>>>26)&0x3F)+1;
maxThreads = (apic>>>16)&0xFF;
}
else
{
maxCores = maxThreads = 1;
}
}
private void getThreadingAMD()
{
ubyte n;
ubyte b = 0;
asm
{
mov EAX, 0x8000_0000 ;
cpuid ;
cmp EAX, 0x8000_0008 ;
jb AMDSingle ;
mov EAX, 0x8000_0008 ;
cpuid ;
mov n, CL ;
mov b, 1 ;
AMDSingle: ;
}
if (b != 0)
{
maxCores = n+1;
maxThreads = (apic>>>16)&0xFF;
}
else
{
maxCores = maxThreads = 1;
}
}
/***************************************************************************
* Support code for above, from std.string and std.ctype
***************************************************************************/
private
{
enum
{
_SPC = 8,
_CTL = 0x20,
_BLK = 0x40,
_HEX = 0x80,
_UC = 1,
_LC = 2,
_PNC = 0x10,
_DIG = 4,
_ALP = _UC|_LC,
}
ubyte _ctype[128] =
[
_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,
_CTL,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL,_CTL,
_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,
_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,
_SPC|_BLK,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,
_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,
_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,
_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,
_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,
_PNC,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC,
_UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC,
_UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC,
_UC,_UC,_UC,_PNC,_PNC,_PNC,_PNC,_PNC,
_PNC,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC,
_LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC,
_LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC,
_LC,_LC,_LC,_PNC,_PNC,_PNC,_PNC,_CTL
];
/**
* Returns !=0 if c is a space, tab, vertical tab, form feed,
* carriage return, or linefeed.
*/
int isspace(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_SPC) : 0; }
/*****************************************
* Strips leading or trailing whitespace, or both.
*/
char[] stripl(char[] s)
{
uint i;
for (i = 0; i < s.length; i++)
{
if (!isspace(s[i]))
break;
}
return s[i .. s.length];
}
char[] stripr(char[] s) /// ditto
{
uint i;
for (i = s.length; i > 0; i--)
{
if (!isspace(s[i - 1]))
break;
}
return s[0 .. i];
}
char[] strip(char[] s) /// ditto
{
return stripr(stripl(s));
}
char[] toString(char* s)
{
return s ? s[0 .. strlen(s)] : null;
}
string toString(invariant(char)* s)
{
return s ? s[0 .. strlen(s)] : null;
}
}
}
else
{
char[] vendor() {return "unknown vendor"; }
char[] processor() {return "unknown processor"; }
bool mmx() {return false; }
bool fxsr() {return false; }
bool sse() {return false; }
bool sse2() {return false; }
bool sse3() {return false; }
bool ssse3() {return false; }
bool amd3dnow() {return false; }
bool amd3dnowExt() {return false; }
bool amdMmx() {return false; }
bool ia64() {return false; }
bool amd64() {return false; }
bool hyperThreading() {return false; }
uint threadsPerCPU() {return 0; }
uint coresPerCPU() {return 0; }
bool intel() {return false; }
bool amd() {return false; }
uint stepping() {return 0; }
uint model() {return 0; }
uint family() {return 0; }
}

View File

@@ -0,0 +1,106 @@
/*
* Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
* Written by Walter Bright
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, in both source and binary form, subject to the following
* restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
// Simple ASCII char classification functions
module rt.util.ctype;
int isalnum(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_ALP|_DIG) : 0; }
int isalpha(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_ALP) : 0; }
int iscntrl(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_CTL) : 0; }
int isdigit(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_DIG) : 0; }
int islower(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_LC) : 0; }
int ispunct(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_PNC) : 0; }
int isspace(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_SPC) : 0; }
int isupper(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_UC) : 0; }
int isxdigit(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_HEX) : 0; }
int isgraph(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_ALP|_DIG|_PNC) : 0; }
int isprint(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_ALP|_DIG|_PNC|_BLK) : 0; }
int isascii(dchar c) { return c <= 0x7F; }
dchar tolower(dchar c)
out (result)
{
assert(!isupper(result));
}
body
{
return isupper(c) ? c + (cast(dchar)'a' - 'A') : c;
}
dchar toupper(dchar c)
out (result)
{
assert(!islower(result));
}
body
{
return islower(c) ? c - (cast(dchar)'a' - 'A') : c;
}
private:
enum
{
_SPC = 8,
_CTL = 0x20,
_BLK = 0x40,
_HEX = 0x80,
_UC = 1,
_LC = 2,
_PNC = 0x10,
_DIG = 4,
_ALP = _UC|_LC,
}
ubyte _ctype[128] =
[
_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,
_CTL,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL,_CTL,
_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,
_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,
_SPC|_BLK,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,
_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,
_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,
_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,
_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,
_PNC,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC,
_UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC,
_UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC,
_UC,_UC,_UC,_PNC,_PNC,_PNC,_PNC,_PNC,
_PNC,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC,
_LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC,
_LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC,
_LC,_LC,_LC,_PNC,_PNC,_PNC,_PNC,_CTL
];
unittest
{
assert(isspace(' '));
assert(!isspace('z'));
assert(toupper('a') == 'A');
assert(tolower('Q') == 'q');
assert(!isxdigit('G'));
}

View File

@@ -0,0 +1,35 @@
/**
* The exception module defines all system-level exceptions and provides a
* mechanism to alter system-level error handling.
*
* Copyright: Copyright (c) 2005-2008, The D Runtime Project
* License: BSD Style, see LICENSE
* Authors: Sean Kelly
*/
module rt.util.string;
private import stdc.string;
char[] intToString( char[] buf, uint val )
{
assert( buf.length > 9 );
auto p = buf.ptr + buf.length;
do
{
*--p = cast(char)(val % 10 + '0');
} while( val /= 10 );
return buf[p - buf.ptr .. $];
}
int dstrcmp( in char[] s1, in char[] s2 )
{
auto len = s1.length;
if( s2.length < len )
len = s2.length;
if( memcmp( s1.ptr, s2.ptr, len ) == 0 )
return 0;
return s1.length > s2.length ? 1 : -1;
}

View File

@@ -0,0 +1,917 @@
// Written in the D programming language
/*
* Copyright (C) 2003-2004 by Digital Mars, www.digitalmars.com
* Written by Walter Bright
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
/********************************************
* Encode and decode UTF-8, UTF-16 and UTF-32 strings.
*
* For Win32 systems, the C wchar_t type is UTF-16 and corresponds to the D
* wchar type.
* For linux systems, the C wchar_t type is UTF-32 and corresponds to
* the D utf.dchar type.
*
* UTF character support is restricted to (\u0000 &lt;= character &lt;= \U0010FFFF).
*
* See_Also:
* $(LINK2 http://en.wikipedia.org/wiki/Unicode, Wikipedia)<br>
* $(LINK http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8)<br>
* $(LINK http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335)
* Macros:
* WIKI = Phobos/StdUtf
*/
module rt.util.utf;
extern (C) void onUnicodeError( string msg, size_t idx );
/*******************************
* Test if c is a valid UTF-32 character.
*
* \uFFFE and \uFFFF are considered valid by this function,
* as they are permitted for internal use by an application,
* but they are not allowed for interchange by the Unicode standard.
*
* Returns: true if it is, false if not.
*/
bool isValidDchar(dchar c)
{
/* Note: FFFE and FFFF are specifically permitted by the
* Unicode standard for application internal use, but are not
* allowed for interchange.
* (thanks to Arcane Jill)
*/
return c < 0xD800 ||
(c > 0xDFFF && c <= 0x10FFFF /*&& c != 0xFFFE && c != 0xFFFF*/);
}
unittest
{
debug(utf) printf("utf.isValidDchar.unittest\n");
assert(isValidDchar(cast(dchar)'a') == true);
assert(isValidDchar(cast(dchar)0x1FFFFF) == false);
}
auto UTF8stride =
[
cast(ubyte)
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,
];
/**
* stride() returns the length of a UTF-8 sequence starting at index i
* in string s.
* Returns:
* The number of bytes in the UTF-8 sequence or
* 0xFF meaning s[i] is not the start of of UTF-8 sequence.
*/
uint stride(in char[] s, size_t i)
{
return UTF8stride[s[i]];
}
/**
* stride() returns the length of a UTF-16 sequence starting at index i
* in string s.
*/
uint stride(in wchar[] s, size_t i)
{ uint u = s[i];
return 1 + (u >= 0xD800 && u <= 0xDBFF);
}
/**
* stride() returns the length of a UTF-32 sequence starting at index i
* in string s.
* Returns: The return value will always be 1.
*/
uint stride(in dchar[] s, size_t i)
{
return 1;
}
/*******************************************
* Given an index i into an array of characters s[],
* and assuming that index i is at the start of a UTF character,
* determine the number of UCS characters up to that index i.
*/
size_t toUCSindex(in char[] s, size_t i)
{
size_t n;
size_t j;
for (j = 0; j < i; )
{
j += stride(s, j);
n++;
}
if (j > i)
{
onUnicodeError("invalid UTF-8 sequence", j);
}
return n;
}
/** ditto */
size_t toUCSindex(in wchar[] s, size_t i)
{
size_t n;
size_t j;
for (j = 0; j < i; )
{
j += stride(s, j);
n++;
}
if (j > i)
{
onUnicodeError("invalid UTF-16 sequence", j);
}
return n;
}
/** ditto */
size_t toUCSindex(in dchar[] s, size_t i)
{
return i;
}
/******************************************
* Given a UCS index n into an array of characters s[], return the UTF index.
*/
size_t toUTFindex(in char[] s, size_t n)
{
size_t i;
while (n--)
{
uint j = UTF8stride[s[i]];
if (j == 0xFF)
onUnicodeError("invalid UTF-8 sequence", i);
i += j;
}
return i;
}
/** ditto */
size_t toUTFindex(in wchar[] s, size_t n)
{
size_t i;
while (n--)
{ wchar u = s[i];
i += 1 + (u >= 0xD800 && u <= 0xDBFF);
}
return i;
}
/** ditto */
size_t toUTFindex(in dchar[] s, size_t n)
{
return n;
}
/* =================== Decode ======================= */
/***************
* Decodes and returns character starting at s[idx]. idx is advanced past the
* decoded character. If the character is not well formed, a UtfException is
* thrown and idx remains unchanged.
*/
dchar decode(in char[] s, inout size_t idx)
in
{
assert(idx >= 0 && idx < s.length);
}
out (result)
{
assert(isValidDchar(result));
}
body
{
size_t len = s.length;
dchar V;
size_t i = idx;
char u = s[i];
if (u & 0x80)
{ uint n;
char u2;
/* The following encodings are valid, except for the 5 and 6 byte
* combinations:
* 0xxxxxxx
* 110xxxxx 10xxxxxx
* 1110xxxx 10xxxxxx 10xxxxxx
* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
*/
for (n = 1; ; n++)
{
if (n > 4)
goto Lerr; // only do the first 4 of 6 encodings
if (((u << n) & 0x80) == 0)
{
if (n == 1)
goto Lerr;
break;
}
}
// Pick off (7 - n) significant bits of B from first byte of octet
V = cast(dchar)(u & ((1 << (7 - n)) - 1));
if (i + (n - 1) >= len)
goto Lerr; // off end of string
/* The following combinations are overlong, and illegal:
* 1100000x (10xxxxxx)
* 11100000 100xxxxx (10xxxxxx)
* 11110000 1000xxxx (10xxxxxx 10xxxxxx)
* 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx)
* 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx)
*/
u2 = s[i + 1];
if ((u & 0xFE) == 0xC0 ||
(u == 0xE0 && (u2 & 0xE0) == 0x80) ||
(u == 0xF0 && (u2 & 0xF0) == 0x80) ||
(u == 0xF8 && (u2 & 0xF8) == 0x80) ||
(u == 0xFC && (u2 & 0xFC) == 0x80))
goto Lerr; // overlong combination
for (uint j = 1; j != n; j++)
{
u = s[i + j];
if ((u & 0xC0) != 0x80)
goto Lerr; // trailing bytes are 10xxxxxx
V = (V << 6) | (u & 0x3F);
}
if (!isValidDchar(V))
goto Lerr;
i += n;
}
else
{
V = cast(dchar) u;
i++;
}
idx = i;
return V;
Lerr:
onUnicodeError("invalid UTF-8 sequence", i);
return V; // dummy return
}
unittest
{ size_t i;
dchar c;
debug(utf) printf("utf.decode.unittest\n");
static s1 = "abcd"c;
i = 0;
c = decode(s1, i);
assert(c == cast(dchar)'a');
assert(i == 1);
c = decode(s1, i);
assert(c == cast(dchar)'b');
assert(i == 2);
static s2 = "\xC2\xA9"c;
i = 0;
c = decode(s2, i);
assert(c == cast(dchar)'\u00A9');
assert(i == 2);
static s3 = "\xE2\x89\xA0"c;
i = 0;
c = decode(s3, i);
assert(c == cast(dchar)'\u2260');
assert(i == 3);
static s4 =
[ "\xE2\x89"c, // too short
"\xC0\x8A",
"\xE0\x80\x8A",
"\xF0\x80\x80\x8A",
"\xF8\x80\x80\x80\x8A",
"\xFC\x80\x80\x80\x80\x8A",
];
for (int j = 0; j < s4.length; j++)
{
try
{
i = 0;
c = decode(s4[j], i);
assert(0);
}
catch (Object o)
{
i = 23;
}
assert(i == 23);
}
}
/** ditto */
dchar decode(in wchar[] s, inout size_t idx)
in
{
assert(idx >= 0 && idx < s.length);
}
out (result)
{
assert(isValidDchar(result));
}
body
{
string msg;
dchar V;
size_t i = idx;
uint u = s[i];
if (u & ~0x7F)
{ if (u >= 0xD800 && u <= 0xDBFF)
{ uint u2;
if (i + 1 == s.length)
{ msg = "surrogate UTF-16 high value past end of string";
goto Lerr;
}
u2 = s[i + 1];
if (u2 < 0xDC00 || u2 > 0xDFFF)
{ msg = "surrogate UTF-16 low value out of range";
goto Lerr;
}
u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00);
i += 2;
}
else if (u >= 0xDC00 && u <= 0xDFFF)
{ msg = "unpaired surrogate UTF-16 value";
goto Lerr;
}
else if (u == 0xFFFE || u == 0xFFFF)
{ msg = "illegal UTF-16 value";
goto Lerr;
}
else
i++;
}
else
{
i++;
}
idx = i;
return cast(dchar)u;
Lerr:
onUnicodeError(msg, i);
return cast(dchar)u; // dummy return
}
/** ditto */
dchar decode(in dchar[] s, inout size_t idx)
in
{
assert(idx >= 0 && idx < s.length);
}
body
{
size_t i = idx;
dchar c = s[i];
if (!isValidDchar(c))
goto Lerr;
idx = i + 1;
return c;
Lerr:
onUnicodeError("invalid UTF-32 value", i);
return c; // dummy return
}
/* =================== Encode ======================= */
/*******************************
* Encodes character c and appends it to array s[].
*/
void encode(inout char[] s, dchar c)
in
{
assert(isValidDchar(c));
}
body
{
char[] r = s;
if (c <= 0x7F)
{
r ~= cast(char) c;
}
else
{
char[4] buf;
uint L;
if (c <= 0x7FF)
{
buf[0] = cast(char)(0xC0 | (c >> 6));
buf[1] = cast(char)(0x80 | (c & 0x3F));
L = 2;
}
else if (c <= 0xFFFF)
{
buf[0] = cast(char)(0xE0 | (c >> 12));
buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F));
buf[2] = cast(char)(0x80 | (c & 0x3F));
L = 3;
}
else if (c <= 0x10FFFF)
{
buf[0] = cast(char)(0xF0 | (c >> 18));
buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F));
buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F));
buf[3] = cast(char)(0x80 | (c & 0x3F));
L = 4;
}
else
{
assert(0);
}
r ~= buf[0 .. L];
}
s = r;
}
unittest
{
debug(utf) printf("utf.encode.unittest\n");
char[] s = "abcd".dup;
encode(s, cast(dchar)'a');
assert(s.length == 5);
assert(s == "abcda");
encode(s, cast(dchar)'\u00A9');
assert(s.length == 7);
assert(s == "abcda\xC2\xA9");
//assert(s == "abcda\u00A9"); // BUG: fix compiler
encode(s, cast(dchar)'\u2260');
assert(s.length == 10);
assert(s == "abcda\xC2\xA9\xE2\x89\xA0");
}
/** ditto */
void encode(inout wchar[] s, dchar c)
in
{
assert(isValidDchar(c));
}
body
{
wchar[] r = s;
if (c <= 0xFFFF)
{
r ~= cast(wchar) c;
}
else
{
wchar[2] buf;
buf[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800);
buf[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00);
r ~= buf;
}
s = r;
}
/** ditto */
void encode(inout dchar[] s, dchar c)
in
{
assert(isValidDchar(c));
}
body
{
s ~= c;
}
/**
Returns the code length of $(D c) in the encoding using $(D C) as a
code point. The code is returned in character count, not in bytes.
*/
ubyte codeLength(C)(dchar c)
{
static if (C.sizeof == 1)
{
return
c <= 0x7F ? 1
: c <= 0x7FF ? 2
: c <= 0xFFFF ? 3
: c <= 0x10FFFF ? 4
: (assert(false), 6);
}
else static if (C.sizeof == 2)
{
return c <= 0xFFFF ? 1 : 2;
}
else
{
static assert(C.sizeof == 4);
return 1;
}
}
/* =================== Validation ======================= */
/***********************************
Checks to see if string is well formed or not. $(D S) can be an array
of $(D char), $(D wchar), or $(D dchar). Throws a $(D UtfException)
if it is not. Use to check all untrusted input for correctness.
*/
void validate(S)(in S s)
{
auto len = s.length;
for (size_t i = 0; i < len; )
{
decode(s, i);
}
}
/* =================== Conversion to UTF8 ======================= */
char[] toUTF8(char[4] buf, dchar c)
in
{
assert(isValidDchar(c));
}
body
{
if (c <= 0x7F)
{
buf[0] = cast(char) c;
return buf[0 .. 1];
}
else if (c <= 0x7FF)
{
buf[0] = cast(char)(0xC0 | (c >> 6));
buf[1] = cast(char)(0x80 | (c & 0x3F));
return buf[0 .. 2];
}
else if (c <= 0xFFFF)
{
buf[0] = cast(char)(0xE0 | (c >> 12));
buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F));
buf[2] = cast(char)(0x80 | (c & 0x3F));
return buf[0 .. 3];
}
else if (c <= 0x10FFFF)
{
buf[0] = cast(char)(0xF0 | (c >> 18));
buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F));
buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F));
buf[3] = cast(char)(0x80 | (c & 0x3F));
return buf[0 .. 4];
}
assert(0);
}
/*******************
* Encodes string s into UTF-8 and returns the encoded string.
*/
string toUTF8(string s)
in
{
validate(s);
}
body
{
return s;
}
/** ditto */
string toUTF8(in wchar[] s)
{
char[] r;
size_t i;
size_t slen = s.length;
r.length = slen;
for (i = 0; i < slen; i++)
{ wchar c = s[i];
if (c <= 0x7F)
r[i] = cast(char)c; // fast path for ascii
else
{
r.length = i;
foreach (dchar c; s[i .. slen])
{
encode(r, c);
}
break;
}
}
return cast(string)r;
}
/** ditto */
string toUTF8(in dchar[] s)
{
char[] r;
size_t i;
size_t slen = s.length;
r.length = slen;
for (i = 0; i < slen; i++)
{ dchar c = s[i];
if (c <= 0x7F)
r[i] = cast(char)c; // fast path for ascii
else
{
r.length = i;
foreach (dchar d; s[i .. slen])
{
encode(r, d);
}
break;
}
}
return cast(string)r;
}
/* =================== Conversion to UTF16 ======================= */
wchar[] toUTF16(wchar[2] buf, dchar c)
in
{
assert(isValidDchar(c));
}
body
{
if (c <= 0xFFFF)
{
buf[0] = cast(wchar) c;
return buf[0 .. 1];
}
else
{
buf[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800);
buf[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00);
return buf[0 .. 2];
}
}
/****************
* Encodes string s into UTF-16 and returns the encoded string.
* toUTF16z() is suitable for calling the 'W' functions in the Win32 API that take
* an LPWSTR or LPCWSTR argument.
*/
wstring toUTF16(in char[] s)
{
wchar[] r;
size_t slen = s.length;
r.length = slen;
r.length = 0;
for (size_t i = 0; i < slen; )
{
dchar c = s[i];
if (c <= 0x7F)
{
i++;
r ~= cast(wchar)c;
}
else
{
c = decode(s, i);
encode(r, c);
}
}
return cast(wstring)r;
}
alias const(wchar)* wptr;
/** ditto */
wptr toUTF16z(in char[] s)
{
wchar[] r;
size_t slen = s.length;
r.length = slen + 1;
r.length = 0;
for (size_t i = 0; i < slen; )
{
dchar c = s[i];
if (c <= 0x7F)
{
i++;
r ~= cast(wchar)c;
}
else
{
c = decode(s, i);
encode(r, c);
}
}
r ~= "\000";
return r.ptr;
}
/** ditto */
wstring toUTF16(wstring s)
in
{
validate(s);
}
body
{
return s;
}
/** ditto */
wstring toUTF16(in dchar[] s)
{
wchar[] r;
size_t slen = s.length;
r.length = slen;
r.length = 0;
for (size_t i = 0; i < slen; i++)
{
encode(r, s[i]);
}
return cast(wstring)r;
}
/* =================== Conversion to UTF32 ======================= */
/*****
* Encodes string s into UTF-32 and returns the encoded string.
*/
dstring toUTF32(in char[] s)
{
dchar[] r;
size_t slen = s.length;
size_t j = 0;
r.length = slen; // r[] will never be longer than s[]
for (size_t i = 0; i < slen; )
{
dchar c = s[i];
if (c >= 0x80)
c = decode(s, i);
else
i++; // c is ascii, no need for decode
r[j++] = c;
}
return cast(dstring)r[0 .. j];
}
/** ditto */
dstring toUTF32(in wchar[] s)
{
dchar[] r;
size_t slen = s.length;
size_t j = 0;
r.length = slen; // r[] will never be longer than s[]
for (size_t i = 0; i < slen; )
{
dchar c = s[i];
if (c >= 0x80)
c = decode(s, i);
else
i++; // c is ascii, no need for decode
r[j++] = c;
}
return cast(dstring)r[0 .. j];
}
/** ditto */
dstring toUTF32(dstring s)
in
{
validate(s);
}
body
{
return s;
}
/* ================================ tests ================================== */
unittest
{
debug(utf) printf("utf.toUTF.unittest\n");
auto c = "hello"c;
auto w = toUTF16(c);
assert(w == "hello");
auto d = toUTF32(c);
assert(d == "hello");
c = toUTF8(w);
assert(c == "hello");
d = toUTF32(w);
assert(d == "hello");
c = toUTF8(d);
assert(c == "hello");
w = toUTF16(d);
assert(w == "hello");
c = "hel\u1234o";
w = toUTF16(c);
assert(w == "hel\u1234o");
d = toUTF32(c);
assert(d == "hel\u1234o");
c = toUTF8(w);
assert(c == "hel\u1234o");
d = toUTF32(w);
assert(d == "hel\u1234o");
c = toUTF8(d);
assert(c == "hel\u1234o");
w = toUTF16(d);
assert(w == "hel\u1234o");
c = "he\U0010AAAAllo";
w = toUTF16(c);
//foreach (wchar c; w) printf("c = x%x\n", c);
//foreach (wchar c; cast(wstring)"he\U0010AAAAllo") printf("c = x%x\n", c);
assert(w == "he\U0010AAAAllo");
d = toUTF32(c);
assert(d == "he\U0010AAAAllo");
c = toUTF8(w);
assert(c == "he\U0010AAAAllo");
d = toUTF32(w);
assert(d == "he\U0010AAAAllo");
c = toUTF8(d);
assert(c == "he\U0010AAAAllo");
w = toUTF16(d);
assert(w == "he\U0010AAAAllo");
}

View File

@@ -0,0 +1,171 @@
# Makefile to build the compiler runtime D library for Win32
# Designed to work with DigitalMars make
# Targets:
# make
# Same as make all
# make lib
# Build the compiler runtime library
# make doc
# Generate documentation
# make clean
# Delete unneeded files created by build process
LIB_TARGET=druntime-rt-dmd.lib
LIB_MASK=druntime-rt-dmd*.lib
CP=xcopy /y
RM=del /f
MD=mkdir
CFLAGS=-mn -6 -r $(ADD_CFLAGS)
#CFLAGS=-g -mn -6 -r $(ADD_CFLAGS)
DFLAGS=-release -O -inline -w -nofloat $(ADD_DFLAGS)
#DFLAGS=-g -w -nofloat $(ADD_DFLAGS)
TFLAGS=-O -inline -w -nofloat $(ADD_DFLAGS)
#TFLAGS=-g -w -nofloat $(ADD_DFLAGS)
DOCFLAGS=-version=DDoc
CC=dmc
LC=lib
DC=dmd
LIB_DEST=..\..\..\lib
.DEFAULT: .asm .c .cpp .d .html .obj
.asm.obj:
$(CC) -c $<
.c.obj:
$(CC) -c $(CFLAGS) $< -o$@
.cpp.obj:
$(CC) -c $(CFLAGS) $< -o$@
.d.obj:
$(DC) -c $(DFLAGS) $< -of$@
.d.html:
$(DC) -c -o- $(DOCFLAGS) -Df$*.html dmd.ddoc $<
targets : lib doc
all : lib doc
lib : dmd.lib
doc : dmd.doc
######################################################
OBJ_BASE= \
aaA.obj \
aApply.obj \
aApplyR.obj \
adi.obj \
arrayassign.obj \
arraybyte.obj \
arraycast.obj \
arraycat.obj \
arraydouble.obj \
arrayfloat.obj \
arrayint.obj \
arrayreal.obj \
arrayshort.obj \
cast_.obj \
complex.obj \
cover.obj \
critical.obj \
deh.obj \
dmain2.obj \
invariant.obj \
invariant_.obj \
lifetime.obj \
memory.obj \
memset.obj \
monitor.obj \
obj.obj \
object_.obj \
qsort.obj \
switch_.obj \
trace.obj
# NOTE: trace.obj and cover.obj are not necessary for a successful build
# as both are used for debugging features (profiling and coverage)
# NOTE: a pre-compiled minit.obj has been provided in dmd for Win32 and
# minit.asm is not used by dmd for linux
OBJ_UTIL= \
util\console.obj \
util\cpuid.obj \
util\ctype.obj \
util\string.obj \
util\utf.obj
OBJ_TI= \
typeinfo\ti_AC.obj \
typeinfo\ti_Acdouble.obj \
typeinfo\ti_Acfloat.obj \
typeinfo\ti_Acreal.obj \
typeinfo\ti_Adouble.obj \
typeinfo\ti_Afloat.obj \
typeinfo\ti_Ag.obj \
typeinfo\ti_Aint.obj \
typeinfo\ti_Along.obj \
typeinfo\ti_Areal.obj \
typeinfo\ti_Ashort.obj \
typeinfo\ti_byte.obj \
typeinfo\ti_C.obj \
typeinfo\ti_cdouble.obj \
typeinfo\ti_cfloat.obj \
typeinfo\ti_char.obj \
typeinfo\ti_creal.obj \
typeinfo\ti_dchar.obj \
typeinfo\ti_delegate.obj \
typeinfo\ti_double.obj \
typeinfo\ti_float.obj \
typeinfo\ti_idouble.obj \
typeinfo\ti_ifloat.obj \
typeinfo\ti_int.obj \
typeinfo\ti_ireal.obj \
typeinfo\ti_long.obj \
typeinfo\ti_ptr.obj \
typeinfo\ti_real.obj \
typeinfo\ti_short.obj \
typeinfo\ti_ubyte.obj \
typeinfo\ti_uint.obj \
typeinfo\ti_ulong.obj \
typeinfo\ti_ushort.obj \
typeinfo\ti_void.obj \
typeinfo\ti_wchar.obj
ALL_OBJS= \
$(OBJ_BASE) \
$(OBJ_UTIL) \
$(OBJ_TI)
######################################################
ALL_DOCS=
######################################################
dmd.lib : $(LIB_TARGET)
$(LIB_TARGET) : $(ALL_OBJS)
$(RM) $@
$(LC) -c -n $@ $(ALL_OBJS) minit.obj
dmd.doc : $(ALL_DOCS)
@echo No documentation available.
######################################################
clean :
$(RM) /s *.di
$(RM) $(ALL_OBJS)
$(RM) $(ALL_DOCS)
$(RM) $(LIB_MASK)
install :
$(MD) $(LIB_DEST)
$(CP) $(LIB_MASK) $(LIB_DEST)\.

View File

@@ -0,0 +1,414 @@
/**
* Part of the D programming language runtime library.
*/
/*
* Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
* Written by Walter Bright
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, in both source and binary form, subject to the following
* restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
/*
* Modified by Sean Kelly <sean@f4.ca> for use with Tango.
*/
/* This code handles decoding UTF strings for foreach loops.
* There are 6 combinations of conversions between char, wchar,
* and dchar, and 2 of each of those.
*/
private import util.utf;
//debug = apply;
debug(apply)
{
extern(C) int printf(char*, ...);
}
/**********************************************
*/
// dg is D, but _aApplycd() is C
extern (D) typedef int delegate(void *) dg_t;
extern (C) int _aApplycd1(char[] aa, dg_t dg)
{ int result;
size_t i;
size_t len = aa.length;
debug(apply) printf("_aApplycd1(), len = %d\n", len);
for (i = 0; i < len; )
{ dchar d;
d = aa[i];
if (d & 0x80)
d = decode(aa, i);
else
i++;
result = dg(cast(void *)&d);
if (result)
break;
}
return result;
}
extern (C) int _aApplywd1(wchar[] aa, dg_t dg)
{ int result;
size_t i;
size_t len = aa.length;
debug(apply) printf("_aApplywd1(), len = %d\n", len);
for (i = 0; i < len; )
{ dchar d;
d = aa[i];
if (d & ~0x7F)
d = decode(aa, i);
else
i++;
result = dg(cast(void *)&d);
if (result)
break;
}
return result;
}
extern (C) int _aApplycw1(char[] aa, dg_t dg)
{ int result;
size_t i;
size_t len = aa.length;
debug(apply) printf("_aApplycw1(), len = %d\n", len);
for (i = 0; i < len; )
{ dchar d;
wchar w;
w = aa[i];
if (w & 0x80)
{ d = decode(aa, i);
if (d <= 0xFFFF)
w = cast(wchar) d;
else
{
w = cast(wchar)((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
result = dg(cast(void *)&w);
if (result)
break;
w = cast(wchar)(((d - 0x10000) & 0x3FF) + 0xDC00);
}
}
else
i++;
result = dg(cast(void *)&w);
if (result)
break;
}
return result;
}
extern (C) int _aApplywc1(wchar[] aa, dg_t dg)
{ int result;
size_t i;
size_t len = aa.length;
debug(apply) printf("_aApplywc1(), len = %d\n", len);
for (i = 0; i < len; )
{ dchar d;
wchar w;
char c;
w = aa[i];
if (w & ~0x7F)
{
char[4] buf;
d = decode(aa, i);
auto b = toUTF8(buf, d);
foreach (char c2; b)
{
result = dg(cast(void *)&c2);
if (result)
return result;
}
continue;
}
else
{ c = cast(char)w;
i++;
}
result = dg(cast(void *)&c);
if (result)
break;
}
return result;
}
extern (C) int _aApplydc1(dchar[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplydc1(), len = %d\n", aa.length);
foreach (dchar d; aa)
{
char c;
if (d & ~0x7F)
{
char[4] buf;
auto b = toUTF8(buf, d);
foreach (char c2; b)
{
result = dg(cast(void *)&c2);
if (result)
return result;
}
continue;
}
else
{
c = cast(char)d;
}
result = dg(cast(void *)&c);
if (result)
break;
}
return result;
}
extern (C) int _aApplydw1(dchar[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplydw1(), len = %d\n", aa.length);
foreach (dchar d; aa)
{
wchar w;
if (d <= 0xFFFF)
w = cast(wchar) d;
else
{
w = cast(wchar)((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
result = dg(cast(void *)&w);
if (result)
break;
w = cast(wchar)(((d - 0x10000) & 0x3FF) + 0xDC00);
}
result = dg(cast(void *)&w);
if (result)
break;
}
return result;
}
/****************************************************************************/
// dg is D, but _aApplycd2() is C
extern (D) typedef int delegate(void *, void *) dg2_t;
extern (C) int _aApplycd2(char[] aa, dg2_t dg)
{ int result;
size_t i;
size_t n;
size_t len = aa.length;
debug(apply) printf("_aApplycd2(), len = %d\n", len);
for (i = 0; i < len; i += n)
{ dchar d;
d = aa[i];
if (d & 0x80)
{
n = i;
d = decode(aa, n);
n -= i;
}
else
n = 1;
result = dg(&i, cast(void *)&d);
if (result)
break;
}
return result;
}
extern (C) int _aApplywd2(wchar[] aa, dg2_t dg)
{ int result;
size_t i;
size_t n;
size_t len = aa.length;
debug(apply) printf("_aApplywd2(), len = %d\n", len);
for (i = 0; i < len; i += n)
{ dchar d;
d = aa[i];
if (d & ~0x7F)
{
n = i;
d = decode(aa, n);
n -= i;
}
else
n = 1;
result = dg(&i, cast(void *)&d);
if (result)
break;
}
return result;
}
extern (C) int _aApplycw2(char[] aa, dg2_t dg)
{ int result;
size_t i;
size_t n;
size_t len = aa.length;
debug(apply) printf("_aApplycw2(), len = %d\n", len);
for (i = 0; i < len; i += n)
{ dchar d;
wchar w;
w = aa[i];
if (w & 0x80)
{ n = i;
d = decode(aa, n);
n -= i;
if (d <= 0xFFFF)
w = cast(wchar) d;
else
{
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
result = dg(&i, cast(void *)&w);
if (result)
break;
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
}
}
else
n = 1;
result = dg(&i, cast(void *)&w);
if (result)
break;
}
return result;
}
extern (C) int _aApplywc2(wchar[] aa, dg2_t dg)
{ int result;
size_t i;
size_t n;
size_t len = aa.length;
debug(apply) printf("_aApplywc2(), len = %d\n", len);
for (i = 0; i < len; i += n)
{ dchar d;
wchar w;
char c;
w = aa[i];
if (w & ~0x7F)
{
char[4] buf;
n = i;
d = decode(aa, n);
n -= i;
auto b = toUTF8(buf, d);
foreach (char c2; b)
{
result = dg(&i, cast(void *)&c2);
if (result)
return result;
}
continue;
}
else
{ c = cast(char)w;
n = 1;
}
result = dg(&i, cast(void *)&c);
if (result)
break;
}
return result;
}
extern (C) int _aApplydc2(dchar[] aa, dg2_t dg)
{ int result;
size_t i;
size_t len = aa.length;
debug(apply) printf("_aApplydc2(), len = %d\n", len);
for (i = 0; i < len; i++)
{ dchar d;
char c;
d = aa[i];
debug(apply) printf("d = %u\n", d);
if (d & ~0x7F)
{
char[4] buf;
auto b = toUTF8(buf, d);
foreach (char c2; b)
{
debug(apply) printf("c2 = %d\n", c2);
result = dg(&i, cast(void *)&c2);
if (result)
return result;
}
continue;
}
else
{ c = cast(char)d;
}
result = dg(&i, cast(void *)&c);
if (result)
break;
}
return result;
}
extern (C) int _aApplydw2(dchar[] aa, dg2_t dg)
{ int result;
debug(apply) printf("_aApplydw2(), len = %d\n", aa.length);
foreach (size_t i, dchar d; aa)
{
wchar w;
auto j = i;
if (d <= 0xFFFF)
w = cast(wchar) d;
else
{
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
result = dg(&j, cast(void *)&w);
if (result)
break;
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
}
result = dg(&j, cast(void *)&w);
if (result)
break;
}
return result;
}

View File

@@ -0,0 +1,975 @@
/**
* Part of the D programming language runtime library.
*/
/*
* Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
* Written by Walter Bright
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, in both source and binary form, subject to the following
* restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
/*
* Modified by Sean Kelly <sean@f4.ca> for use with Tango.
*/
/* This code handles decoding UTF strings for foreach_reverse loops.
* There are 6 combinations of conversions between char, wchar,
* and dchar, and 2 of each of those.
*/
private import util.utf;
/**********************************************/
/* 1 argument versions */
// dg is D, but _aApplyRcd() is C
extern (D) typedef int delegate(void *) dg_t;
extern (C) int _aApplyRcd1(in char[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplyRcd1(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
i--;
d = aa[i];
if (d & 0x80)
{ char c = cast(char)d;
uint j;
uint m = 0x3F;
d = 0;
while ((c & 0xC0) != 0xC0)
{ if (i == 0)
onUnicodeError("Invalid UTF-8 sequence", 0);
i--;
d |= (c & 0x3F) << j;
j += 6;
m >>= 1;
c = aa[i];
}
d |= (c & m) << j;
}
result = dg(cast(void *)&d);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRcd1.unittest\n");
char[] s = "hello"c;
int i;
foreach_reverse(dchar d; s)
{
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(dchar d; s)
{
//printf("i = %d, d = %x\n", i, d);
switch (i)
{
case 0: assert(d == 'b'); break;
case 1: assert(d == '\U00100456'); break;
case 2: assert(d == '\u1234'); break;
case 3: assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 4);
}
/*****************************/
extern (C) int _aApplyRwd1(in wchar[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplyRwd1(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
i--;
d = aa[i];
if (d >= 0xDC00 && d <= 0xDFFF)
{ if (i == 0)
onUnicodeError("Invalid UTF-16 sequence", 0);
i--;
d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
}
result = dg(cast(void *)&d);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRwd1.unittest\n");
wchar[] s = "hello"w;
int i;
foreach_reverse(dchar d; s)
{
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(dchar d; s)
{
//printf("i = %d, d = %x\n", i, d);
switch (i)
{
case 0: assert(d == 'b'); break;
case 1: assert(d == '\U00100456'); break;
case 2: assert(d == '\u1234'); break;
case 3: assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 4);
}
/*****************************/
extern (C) int _aApplyRcw1(in char[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplyRcw1(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
wchar w;
i--;
w = aa[i];
if (w & 0x80)
{ char c = cast(char)w;
uint j;
uint m = 0x3F;
d = 0;
while ((c & 0xC0) != 0xC0)
{ if (i == 0)
onUnicodeError("Invalid UTF-8 sequence", 0);
i--;
d |= (c & 0x3F) << j;
j += 6;
m >>= 1;
c = aa[i];
}
d |= (c & m) << j;
if (d <= 0xFFFF)
w = cast(wchar) d;
else
{
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
result = dg(cast(void *)&w);
if (result)
break;
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
}
}
result = dg(cast(void *)&w);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRcw1.unittest\n");
char[] s = "hello"c;
int i;
foreach_reverse(wchar d; s)
{
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(wchar d; s)
{
//printf("i = %d, d = %x\n", i, d);
switch (i)
{
case 0: assert(d == 'b'); break;
case 1: assert(d == 0xDBC1); break;
case 2: assert(d == 0xDC56); break;
case 3: assert(d == 0x1234); break;
case 4: assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
}
/*****************************/
extern (C) int _aApplyRwc1(in wchar[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplyRwc1(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
char c;
i--;
d = aa[i];
if (d >= 0xDC00 && d <= 0xDFFF)
{ if (i == 0)
onUnicodeError("Invalid UTF-16 sequence", 0);
i--;
d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
}
if (d & ~0x7F)
{
char[4] buf;
auto b = toUTF8(buf, d);
foreach (char c2; b)
{
result = dg(cast(void *)&c2);
if (result)
return result;
}
continue;
}
c = cast(char)d;
result = dg(cast(void *)&c);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRwc1.unittest\n");
wchar[] s = "hello"w;
int i;
foreach_reverse(char d; s)
{
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(char d; s)
{
//printf("i = %d, d = %x\n", i, d);
switch (i)
{
case 0: assert(d == 'b'); break;
case 1: assert(d == 0xF4); break;
case 2: assert(d == 0x80); break;
case 3: assert(d == 0x91); break;
case 4: assert(d == 0x96); break;
case 5: assert(d == 0xE1); break;
case 6: assert(d == 0x88); break;
case 7: assert(d == 0xB4); break;
case 8: assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 9);
}
/*****************************/
extern (C) int _aApplyRdc1(in dchar[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplyRdc1(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0;)
{ dchar d = aa[--i];
char c;
if (d & ~0x7F)
{
char[4] buf;
auto b = toUTF8(buf, d);
foreach (char c2; b)
{
result = dg(cast(void *)&c2);
if (result)
return result;
}
continue;
}
else
{
c = cast(char)d;
}
result = dg(cast(void *)&c);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRdc1.unittest\n");
dchar[] s = "hello"d;
int i;
foreach_reverse(char d; s)
{
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(char d; s)
{
//printf("i = %d, d = %x\n", i, d);
switch (i)
{
case 0: assert(d == 'b'); break;
case 1: assert(d == 0xF4); break;
case 2: assert(d == 0x80); break;
case 3: assert(d == 0x91); break;
case 4: assert(d == 0x96); break;
case 5: assert(d == 0xE1); break;
case 6: assert(d == 0x88); break;
case 7: assert(d == 0xB4); break;
case 8: assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 9);
}
/*****************************/
extern (C) int _aApplyRdw1(in dchar[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplyRdw1(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d = aa[--i];
wchar w;
if (d <= 0xFFFF)
w = cast(wchar) d;
else
{
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
result = dg(cast(void *)&w);
if (result)
break;
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
}
result = dg(cast(void *)&w);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRdw1.unittest\n");
dchar[] s = "hello"d;
int i;
foreach_reverse(wchar d; s)
{
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(wchar d; s)
{
//printf("i = %d, d = %x\n", i, d);
switch (i)
{
case 0: assert(d == 'b'); break;
case 1: assert(d == 0xDBC1); break;
case 2: assert(d == 0xDC56); break;
case 3: assert(d == 0x1234); break;
case 4: assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
}
/****************************************************************************/
/* 2 argument versions */
// dg is D, but _aApplyRcd2() is C
extern (D) typedef int delegate(void *, void *) dg2_t;
extern (C) int _aApplyRcd2(in char[] aa, dg2_t dg)
{ int result;
size_t i;
size_t len = aa.length;
debug(apply) printf("_aApplyRcd2(), len = %d\n", len);
for (i = len; i != 0; )
{ dchar d;
i--;
d = aa[i];
if (d & 0x80)
{ char c = cast(char)d;
uint j;
uint m = 0x3F;
d = 0;
while ((c & 0xC0) != 0xC0)
{ if (i == 0)
onUnicodeError("Invalid UTF-8 sequence", 0);
i--;
d |= (c & 0x3F) << j;
j += 6;
m >>= 1;
c = aa[i];
}
d |= (c & m) << j;
}
result = dg(&i, cast(void *)&d);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRcd2.unittest\n");
char[] s = "hello"c;
int i;
foreach_reverse(k, dchar d; s)
{
assert(k == 4 - i);
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(k, dchar d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
switch (i)
{
case 0: assert(d == 'b'); assert(k == 8); break;
case 1: assert(d == '\U00100456'); assert(k == 4); break;
case 2: assert(d == '\u1234'); assert(k == 1); break;
case 3: assert(d == 'a'); assert(k == 0); break;
default: assert(0);
}
i++;
}
assert(i == 4);
}
/*****************************/
extern (C) int _aApplyRwd2(in wchar[] aa, dg2_t dg)
{ int result;
debug(apply) printf("_aApplyRwd2(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
i--;
d = aa[i];
if (d >= 0xDC00 && d <= 0xDFFF)
{ if (i == 0)
onUnicodeError("Invalid UTF-16 sequence", 0);
i--;
d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
}
result = dg(&i, cast(void *)&d);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRwd2.unittest\n");
wchar[] s = "hello"w;
int i;
foreach_reverse(k, dchar d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
assert(k == 4 - i);
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(k, dchar d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
switch (i)
{
case 0: assert(k == 4); assert(d == 'b'); break;
case 1: assert(k == 2); assert(d == '\U00100456'); break;
case 2: assert(k == 1); assert(d == '\u1234'); break;
case 3: assert(k == 0); assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 4);
}
/*****************************/
extern (C) int _aApplyRcw2(in char[] aa, dg2_t dg)
{ int result;
debug(apply) printf("_aApplyRcw2(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
wchar w;
i--;
w = aa[i];
if (w & 0x80)
{ char c = cast(char)w;
uint j;
uint m = 0x3F;
d = 0;
while ((c & 0xC0) != 0xC0)
{ if (i == 0)
onUnicodeError("Invalid UTF-8 sequence", 0);
i--;
d |= (c & 0x3F) << j;
j += 6;
m >>= 1;
c = aa[i];
}
d |= (c & m) << j;
if (d <= 0xFFFF)
w = cast(wchar) d;
else
{
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
result = dg(&i, cast(void *)&w);
if (result)
break;
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
}
}
result = dg(&i, cast(void *)&w);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRcw2.unittest\n");
char[] s = "hello"c;
int i;
foreach_reverse(k, wchar d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
assert(k == 4 - i);
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(k, wchar d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
switch (i)
{
case 0: assert(k == 8); assert(d == 'b'); break;
case 1: assert(k == 4); assert(d == 0xDBC1); break;
case 2: assert(k == 4); assert(d == 0xDC56); break;
case 3: assert(k == 1); assert(d == 0x1234); break;
case 4: assert(k == 0); assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
}
/*****************************/
extern (C) int _aApplyRwc2(in wchar[] aa, dg2_t dg)
{ int result;
debug(apply) printf("_aApplyRwc2(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
char c;
i--;
d = aa[i];
if (d >= 0xDC00 && d <= 0xDFFF)
{ if (i == 0)
onUnicodeError("Invalid UTF-16 sequence", 0);
i--;
d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
}
if (d & ~0x7F)
{
char[4] buf;
auto b = toUTF8(buf, d);
foreach (char c2; b)
{
result = dg(&i, cast(void *)&c2);
if (result)
return result;
}
continue;
}
c = cast(char)d;
result = dg(&i, cast(void *)&c);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRwc2.unittest\n");
wchar[] s = "hello"w;
int i;
foreach_reverse(k, char d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
assert(k == 4 - i);
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(k, char d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
switch (i)
{
case 0: assert(k == 4); assert(d == 'b'); break;
case 1: assert(k == 2); assert(d == 0xF4); break;
case 2: assert(k == 2); assert(d == 0x80); break;
case 3: assert(k == 2); assert(d == 0x91); break;
case 4: assert(k == 2); assert(d == 0x96); break;
case 5: assert(k == 1); assert(d == 0xE1); break;
case 6: assert(k == 1); assert(d == 0x88); break;
case 7: assert(k == 1); assert(d == 0xB4); break;
case 8: assert(k == 0); assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 9);
}
/*****************************/
extern (C) int _aApplyRdc2(in dchar[] aa, dg2_t dg)
{ int result;
debug(apply) printf("_aApplyRdc2(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d = aa[--i];
char c;
if (d & ~0x7F)
{
char[4] buf;
auto b = toUTF8(buf, d);
foreach (char c2; b)
{
result = dg(&i, cast(void *)&c2);
if (result)
return result;
}
continue;
}
else
{ c = cast(char)d;
}
result = dg(&i, cast(void *)&c);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRdc2.unittest\n");
dchar[] s = "hello"d;
int i;
foreach_reverse(k, char d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
assert(k == 4 - i);
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(k, char d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
switch (i)
{
case 0: assert(k == 3); assert(d == 'b'); break;
case 1: assert(k == 2); assert(d == 0xF4); break;
case 2: assert(k == 2); assert(d == 0x80); break;
case 3: assert(k == 2); assert(d == 0x91); break;
case 4: assert(k == 2); assert(d == 0x96); break;
case 5: assert(k == 1); assert(d == 0xE1); break;
case 6: assert(k == 1); assert(d == 0x88); break;
case 7: assert(k == 1); assert(d == 0xB4); break;
case 8: assert(k == 0); assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 9);
}
/*****************************/
extern (C) int _aApplyRdw2(in dchar[] aa, dg2_t dg)
{ int result;
debug(apply) printf("_aApplyRdw2(), len = %d\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d = aa[--i];
wchar w;
if (d <= 0xFFFF)
w = cast(wchar) d;
else
{
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
result = dg(&i, cast(void *)&w);
if (result)
break;
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
}
result = dg(&i, cast(void *)&w);
if (result)
break;
}
return result;
}
unittest
{
debug(apply) printf("_aApplyRdw2.unittest\n");
dchar[] s = "hello"d;
int i;
foreach_reverse(k, wchar d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
assert(k == 4 - i);
switch (i)
{
case 0: assert(d == 'o'); break;
case 1: assert(d == 'l'); break;
case 2: assert(d == 'l'); break;
case 3: assert(d == 'e'); break;
case 4: assert(d == 'h'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
s = "a\u1234\U00100456b";
i = 0;
foreach_reverse(k, wchar d; s)
{
//printf("i = %d, k = %d, d = %x\n", i, k, d);
switch (i)
{
case 0: assert(k == 3); assert(d == 'b'); break;
case 1: assert(k == 2); assert(d == 0xDBC1); break;
case 2: assert(k == 2); assert(d == 0xDC56); break;
case 3: assert(k == 1); assert(d == 0x1234); break;
case 4: assert(k == 0); assert(d == 'a'); break;
default: assert(0);
}
i++;
}
assert(i == 5);
}

View File

@@ -0,0 +1,837 @@
//_ aaA.d
/**
* Part of the D programming language runtime library.
* Implementation of associative arrays.
*/
/*
* Copyright (C) 2000-2008 by Digital Mars, www.digitalmars.com
* Written by Walter Bright
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
/*
* Modified by Sean Kelly <sean@f4.ca> for use with Tango.
* Modified by Tomas Lindquist Olsen <tomas@famolsen.dk> for use with LDC.
*/
private
{
version( D_Version2 )
{
import stdc.stdarg;
import stdc.string;
}
else
{
import tango.stdc.stdarg;
import tango.stdc.string;
}
enum BlkAttr : uint
{
FINALIZE = 0b0000_0001,
NO_SCAN = 0b0000_0010,
NO_MOVE = 0b0000_0100,
ALL_BITS = 0b1111_1111
}
extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
extern (C) void gc_free( void* p );
}
// Auto-rehash and pre-allocate - Dave Fladebo
static size_t[] prime_list = [
97UL, 389UL,
1_543UL, 6_151UL,
24_593UL, 98_317UL,
393_241UL, 1_572_869UL,
6_291_469UL, 25_165_843UL,
100_663_319UL, 402_653_189UL,
1_610_612_741UL, 4_294_967_291UL,
// 8_589_934_513UL, 17_179_869_143UL
];
struct aaA
{
aaA *left;
aaA *right;
hash_t hash;
/* key */
/* value */
}
struct BB
{
aaA*[] b;
size_t nodes; // total number of aaA nodes
TypeInfo keyti; // TODO: replace this with TypeInfo_AssociativeArray when available in _aaGet()
}
/* This is the type actually seen by the programmer, although
* it is completely opaque.
*/
// LDC doesn't pass structs in registers so no need to wrap it ...
alias BB* AA;
/**********************************
* Align to next pointer boundary, so that
* GC won't be faced with misaligned pointers
* in value.
*/
size_t aligntsize(size_t tsize)
{
return (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
}
extern (C):
/*************************************************
* Invariant for aa.
*/
/+
void _aaInvAh(aaA*[] aa)
{
for (size_t i = 0; i < aa.length; i++)
{
if (aa[i])
_aaInvAh_x(aa[i]);
}
}
private int _aaCmpAh_x(aaA *e1, aaA *e2)
{ int c;
c = e1.hash - e2.hash;
if (c == 0)
{
c = e1.key.length - e2.key.length;
if (c == 0)
c = memcmp((char *)e1.key, (char *)e2.key, e1.key.length);
}
return c;
}
private void _aaInvAh_x(aaA *e)
{
hash_t key_hash;
aaA *e1;
aaA *e2;
key_hash = getHash(e.key);
assert(key_hash == e.hash);
while (1)
{ int c;
e1 = e.left;
if (e1)
{
_aaInvAh_x(e1); // ordinary recursion
do
{
c = _aaCmpAh_x(e1, e);
assert(c < 0);
e1 = e1.right;
} while (e1 != null);
}
e2 = e.right;
if (e2)
{
do
{
c = _aaCmpAh_x(e, e2);
assert(c < 0);
e2 = e2.left;
} while (e2 != null);
e = e.right; // tail recursion
}
else
break;
}
}
+/
/****************************************************
* Determine number of entries in associative array.
*/
size_t _aaLen(AA aa)
in
{
//printf("_aaLen()+\n");
//_aaInv(aa);
}
out (result)
{
size_t len = 0;
void _aaLen_x(aaA* ex)
{
auto e = ex;
len++;
while (1)
{
if (e.right)
_aaLen_x(e.right);
e = e.left;
if (!e)
break;
len++;
}
}
if (aa)
{
foreach (e; aa.b)
{
if (e)
_aaLen_x(e);
}
}
assert(len == result);
//printf("_aaLen()-\n");
}
body
{
return aa ? aa.nodes : 0;
}
/*************************************************
* Get pointer to value in associative array indexed by key.
* Add entry for key if it is not already there.
*/
void* _aaGet(AA* aa_arg, TypeInfo keyti, size_t valuesize, void* pkey)
in
{
assert(aa_arg);
}
out (result)
{
assert(result);
assert(*aa_arg);
assert((*aa_arg).b.length);
//assert(_aaInAh(*aa, key));
}
body
{
//auto pkey = cast(void *)(&valuesize + 1);
size_t i;
aaA *e;
auto keysize = aligntsize(keyti.tsize());
if (!*aa_arg)
*aa_arg = new BB();
auto aa = *aa_arg;
aa.keyti = keyti;
if (!aa.b.length)
{
alias aaA *pa;
auto len = prime_list[0];
aa.b = new pa[len];
}
auto key_hash = keyti.getHash(pkey);
//printf("hash = %d\n", key_hash);
i = key_hash % aa.b.length;
auto pe = &aa.b[i];
while ((e = *pe) !is null)
{
if (key_hash == e.hash)
{
auto c = keyti.compare(pkey, e + 1);
if (c == 0)
goto Lret;
pe = (c < 0) ? &e.left : &e.right;
}
else
pe = (key_hash < e.hash) ? &e.left : &e.right;
}
// Not found, create new elem
//printf("create new one\n");
size_t size = aaA.sizeof + keysize + valuesize;
e = cast(aaA *) gc_calloc(size);
memcpy(e + 1, pkey, keysize);
e.hash = key_hash;
*pe = e;
auto nodes = ++aa.nodes;
//printf("length = %d, nodes = %d\n", (*aa).length, nodes);
if (nodes > aa.b.length * 4)
{
_aaRehash(aa_arg,keyti);
}
Lret:
return cast(void *)(e + 1) + keysize;
}
/*************************************************
* Get pointer to value in associative array indexed by key.
* Returns null if it is not already there.
*/
void* _aaGetRvalue(AA aa, TypeInfo keyti, size_t valuesize, void *pkey)
{
//printf("_aaGetRvalue(valuesize = %u)\n", valuesize);
if (!aa)
return null;
//auto pkey = cast(void *)(&valuesize + 1);
auto keysize = aligntsize(keyti.tsize());
auto len = aa.b.length;
if (len)
{
auto key_hash = keyti.getHash(pkey);
//printf("hash = %d\n", key_hash);
size_t i = key_hash % len;
auto e = aa.b[i];
while (e !is null)
{
if (key_hash == e.hash)
{
auto c = keyti.compare(pkey, e + 1);
if (c == 0)
return cast(void *)(e + 1) + keysize;
e = (c < 0) ? e.left : e.right;
}
else
e = (key_hash < e.hash) ? e.left : e.right;
}
}
return null; // not found, caller will throw exception
}
/*************************************************
* Determine if key is in aa.
* Returns:
* null not in aa
* !=null in aa, return pointer to value
*/
void* _aaIn(AA aa, TypeInfo keyti, void *pkey)
in
{
}
out (result)
{
//assert(result == 0 || result == 1);
}
body
{
if (aa)
{
//auto pkey = cast(void *)(&keyti + 1);
//printf("_aaIn(), .length = %d, .ptr = %x\n", aa.length, cast(uint)aa.ptr);
auto len = aa.b.length;
if (len)
{
auto key_hash = keyti.getHash(pkey);
//printf("hash = %d\n", key_hash);
size_t i = key_hash % len;
auto e = aa.b[i];
while (e !is null)
{
if (key_hash == e.hash)
{
auto c = keyti.compare(pkey, e + 1);
if (c == 0)
return cast(void *)(e + 1) + aligntsize(keyti.tsize());
e = (c < 0) ? e.left : e.right;
}
else
e = (key_hash < e.hash) ? e.left : e.right;
}
}
}
// Not found
return null;
}
/*************************************************
* Delete key entry in aa[].
* If key is not in aa[], do nothing.
*/
void _aaDel(AA aa, TypeInfo keyti, void *pkey)
{
//auto pkey = cast(void *)(&keyti + 1);
aaA *e;
if (aa && aa.b.length)
{
auto key_hash = keyti.getHash(pkey);
//printf("hash = %d\n", key_hash);
size_t i = key_hash % aa.b.length;
auto pe = &aa.b[i];
while ((e = *pe) !is null) // null means not found
{
if (key_hash == e.hash)
{
auto c = keyti.compare(pkey, e + 1);
if (c == 0)
{
if (!e.left && !e.right)
{
*pe = null;
}
else if (e.left && !e.right)
{
*pe = e.left;
e.left = null;
}
else if (!e.left && e.right)
{
*pe = e.right;
e.right = null;
}
else
{
*pe = e.left;
e.left = null;
do
pe = &(*pe).right;
while (*pe);
*pe = e.right;
e.right = null;
}
aa.nodes--;
gc_free(e);
break;
}
pe = (c < 0) ? &e.left : &e.right;
}
else
pe = (key_hash < e.hash) ? &e.left : &e.right;
}
}
}
/********************************************
* Produce array of values from aa.
* The actual type is painted on the return value by the frontend
* This means the returned length should be the number of elements
*/
void[] _aaValues(AA aa, size_t keysize, size_t valuesize)
in
{
assert(keysize == aligntsize(keysize));
}
body
{
size_t resi;
void[] a;
void _aaValues_x(aaA* e)
{
do
{
memcpy(a.ptr + resi * valuesize,
cast(byte*)e + aaA.sizeof + keysize,
valuesize);
resi++;
if (e.left)
{ if (!e.right)
{ e = e.left;
continue;
}
_aaValues_x(e.left);
}
e = e.right;
} while (e !is null);
}
if (aa)
{
auto len = _aaLen(aa);
auto ptr = cast(byte*) gc_malloc(len * valuesize,
valuesize < (void*).sizeof ? BlkAttr.NO_SCAN : 0);
a = ptr[0 .. len];
resi = 0;
foreach (e; aa.b)
{
if (e)
_aaValues_x(e);
}
assert(resi == a.length);
}
return a;
}
/********************************************
* Rehash an array.
*/
void* _aaRehash(AA* paa, TypeInfo keyti)
in
{
//_aaInvAh(paa);
}
out (result)
{
//_aaInvAh(result);
}
body
{
BB newb;
void _aaRehash_x(aaA* olde)
{
while (1)
{
auto left = olde.left;
auto right = olde.right;
olde.left = null;
olde.right = null;
aaA *e;
//printf("rehash %p\n", olde);
auto key_hash = olde.hash;
size_t i = key_hash % newb.b.length;
auto pe = &newb.b[i];
while ((e = *pe) !is null)
{
//printf("\te = %p, e.left = %p, e.right = %p\n", e, e.left, e.right);
assert(e.left != e);
assert(e.right != e);
if (key_hash == e.hash)
{
auto c = keyti.compare(olde + 1, e + 1);
assert(c != 0);
pe = (c < 0) ? &e.left : &e.right;
}
else
pe = (key_hash < e.hash) ? &e.left : &e.right;
}
*pe = olde;
if (right)
{
if (!left)
{ olde = right;
continue;
}
_aaRehash_x(right);
}
if (!left)
break;
olde = left;
}
}
//printf("Rehash\n");
if (*paa)
{
auto aa = *paa;
auto len = _aaLen(aa);
if (len)
{ size_t i;
for (i = 0; i < prime_list.length - 1; i++)
{
if (len <= prime_list[i])
break;
}
len = prime_list[i];
newb.b = new aaA*[len];
newb.keyti = keyti;
foreach (e; aa.b)
{
if (e)
_aaRehash_x(e);
}
newb.nodes = (*aa).nodes;
}
**paa = newb;
}
return *paa;
}
/********************************************
* Produce array of N byte keys from aa.
* The actual type is painted on the return value by the frontend
* This means the returned length should be the number of elements
*/
void[] _aaKeys(AA aa, size_t keysize)
{
byte[] res;
size_t resi;
void _aaKeys_x(aaA* e)
{
do
{
memcpy(&res[resi * keysize], cast(byte*)(e + 1), keysize);
resi++;
if (e.left)
{ if (!e.right)
{ e = e.left;
continue;
}
_aaKeys_x(e.left);
}
e = e.right;
} while (e !is null);
}
auto len = _aaLen(aa);
if (!len)
return null;
res = (cast(byte*) gc_malloc(len * keysize,
!(aa.keyti.flags() & 1) ? BlkAttr.NO_SCAN : 0)) [0 .. len * keysize];
resi = 0;
foreach (e; aa.b)
{
if (e)
_aaKeys_x(e);
}
assert(resi == len);
return res.ptr[0 .. len];
}
/**********************************************
* 'apply' for associative arrays - to support foreach
*/
// dg is D, but _aaApply() is C
extern (D) typedef int delegate(void *) dg_t;
int _aaApply(AA aa, size_t keysize, dg_t dg)
in
{
assert(aligntsize(keysize) == keysize);
}
body
{ int result;
//printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa, keysize, dg);
int treewalker(aaA* e)
{ int result;
do
{
//printf("treewalker(e = %p, dg = x%llx)\n", e, dg);
result = dg(cast(void *)(e + 1) + keysize);
if (result)
break;
if (e.right)
{ if (!e.left)
{
e = e.right;
continue;
}
result = treewalker(e.right);
if (result)
break;
}
e = e.left;
} while (e);
return result;
}
if (aa)
{
foreach (e; aa.b)
{
if (e)
{
result = treewalker(e);
if (result)
break;
}
}
}
return result;
}
// dg is D, but _aaApply2() is C
extern (D) typedef int delegate(void *, void *) dg2_t;
int _aaApply2(AA aa, size_t keysize, dg2_t dg)
in
{
assert(aligntsize(keysize) == keysize);
}
body
{ int result;
//printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa, keysize, dg);
int treewalker(aaA* e)
{ int result;
do
{
//printf("treewalker(e = %p, dg = x%llx)\n", e, dg);
result = dg(cast(void *)(e + 1), cast(void *)(e + 1) + keysize);
if (result)
break;
if (e.right)
{ if (!e.left)
{
e = e.right;
continue;
}
result = treewalker(e.right);
if (result)
break;
}
e = e.left;
} while (e);
return result;
}
if (aa)
{
foreach (e; aa.b)
{
if (e)
{
result = treewalker(e);
if (result)
break;
}
}
}
return result;
}
/***********************************
* Construct an associative array of type ti from
* length pairs of key/value pairs.
*/
/+
extern (C)
BB* _d_assocarrayliteralT(TypeInfo_AssociativeArray ti, size_t length, ...)
{
auto valuesize = ti.next.tsize(); // value size
auto keyti = ti.key;
auto keysize = keyti.tsize(); // key size
BB* result;
//printf("_d_assocarrayliteralT(keysize = %d, valuesize = %d, length = %d)\n", keysize, valuesize, length);
//printf("tivalue = %.*s\n", ti.next.classinfo.name);
if (length == 0 || valuesize == 0 || keysize == 0)
{
;
}
else
{
va_list q;
va_start!(size_t)(q, length);
result = new BB();
size_t i;
for (i = 0; i < prime_list.length - 1; i++)
{
if (length <= prime_list[i])
break;
}
auto len = prime_list[i];
result.b = new aaA*[len];
size_t keystacksize = (keysize + int.sizeof - 1) & ~(int.sizeof - 1);
size_t valuestacksize = (valuesize + int.sizeof - 1) & ~(int.sizeof - 1);
size_t keytsize = aligntsize(keysize);
for (size_t j = 0; j < length; j++)
{ void* pkey = q;
q += keystacksize;
void* pvalue = q;
q += valuestacksize;
aaA* e;
auto key_hash = keyti.getHash(pkey);
//printf("hash = %d\n", key_hash);
i = key_hash % len;
auto pe = &result.b[i];
while (1)
{
e = *pe;
if (!e)
{
// Not found, create new elem
//printf("create new one\n");
e = cast(aaA *) cast(void*) new void[aaA.sizeof + keytsize + valuesize];
memcpy(e + 1, pkey, keysize);
e.hash = key_hash;
*pe = e;
result.nodes++;
break;
}
if (key_hash == e.hash)
{
auto c = keyti.compare(pkey, e + 1);
if (c == 0)
break;
pe = (c < 0) ? &e.left : &e.right;
}
else
pe = (key_hash < e.hash) ? &e.left : &e.right;
}
memcpy(cast(void *)(e + 1) + keytsize, pvalue, valuesize);
}
va_end(q);
}
return result;
}
+/

View File

@@ -0,0 +1,602 @@
//_ adi.d
/**
* Part of the D programming language runtime library.
* Dynamic array property support routines
*/
/*
* Copyright (C) 2000-2006 by Digital Mars, www.digitalmars.com
* Written by Walter Bright
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, in both source and binary form, subject to the following
* restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
/*
* Modified by Sean Kelly <sean@f4.ca> for use with Tango.
*/
//debug=adi; // uncomment to turn on debugging printf's
private
{
version( D_Version2 )
{
import stdc.stdlib;
import stdc.string;
}
else
{
import tango.stdc.stdlib;
import tango.stdc.string;
}
import util.utf;
enum BlkAttr : uint
{
FINALIZE = 0b0000_0001,
NO_SCAN = 0b0000_0010,
NO_MOVE = 0b0000_0100,
ALL_BITS = 0b1111_1111
}
extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
extern (C) void gc_free( void* p );
}
/**********************************************
* Reverse array of chars.
* Handled separately because embedded multibyte encodings should not be
* reversed.
*/
extern (C) char[] _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;
debug(adi) printf("lo = %d, hi = %d\n", lo, hi);
if (clo <= 0x7F && chi <= 0x7F)
{
debug(adi) printf("\tascii\n");
*lo = chi;
*hi = clo;
lo++;
hi--;
continue;
}
uint stridelo = UTF8stride[clo];
// don't barf on invalid strides, just ignore it
if (stridelo == 0xFF)
stridelo = 1;
uint stridehi = 1;
while ((chi & 0xC0) == 0x80)
{
chi = *--hi;
stridehi++;
assert(hi >= lo);
}
if (lo == hi)
break;
debug(adi) printf("\tstridelo = %d, stridehi = %d\n", stridelo, stridehi);
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 , cast(size_t)(hi - lo) - stridelo);
memcpy(lo, tmp.ptr, stridehi);
memcpy(hi + stridehi - stridelo, tmplo.ptr, stridelo);
lo += stridehi;
hi = hi - 1 + (stridehi - stridelo);
}
}
return a;
}
unittest
{
char[] a = "abcd"c;
char[] r = a.dup.reverse;
//writefln(r);
assert(r == "dcba");
a = "a\u1235\u1234c";
//writefln(a);
r = a.dup.reverse;
//writefln(r);
assert(r == "c\u1234\u1235a");
a = "ab\u1234c";
//writefln(a);
r = a.dup.reverse;
//writefln(r);
assert(r == "c\u1234ba");
a = "\u3026\u2021\u3061\n";
r = a.dup.reverse;
assert(r == "\n\u3061\u2021\u3026");
}
/**********************************************
* Reverse array of wchars.
* Handled separately because embedded multiword encodings should not be
* reversed.
*/
extern (C) wchar[] _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 + stridehi - 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 + (stridehi - stridelo);
}
}
return a;
}
unittest
{
wchar[] a = "abcd";
wchar[] r;
r = a.dup.reverse;
assert(r == "dcba");
a = "a\U00012356\U00012346c";
r = a.dup.reverse;
assert(r == "c\U00012346\U00012356a");
a = "ab\U00012345c";
r = a.dup.reverse;
assert(r == "c\U00012345ba");
}
/**********************************************
* Support for array.reverse property.
* The actual type is painted on the return value by the frontend
* Given and returned length are number of elements
*/
extern (C) void[] _adReverse(void[] a, size_t szelem)
out (result)
{
assert(result.ptr is a.ptr);
}
body
{
if (a.length >= 2)
{
byte* tmp;
byte[16] buffer;
void* lo = a.ptr;
void* hi = a.ptr + (a.length - 1) * szelem;
tmp = buffer.ptr;
if (szelem > 16)
{
//version (Win32)
//tmp = cast(byte*) alloca(szelem);
//else
tmp = cast(byte*) gc_malloc(szelem);
}
for (; lo < hi; lo += szelem, hi -= szelem)
{
memcpy(tmp, lo, szelem);
memcpy(lo, hi, szelem);
memcpy(hi, tmp, szelem);
}
version (Win32)
{
}
else
{
//if (szelem > 16)
// BUG: bad code is generate for delete pointer, tries
// to call delclass.
//gc_free(tmp);
}
}
return a.ptr[0 .. a.length];
}
unittest
{
debug(adi) printf("array.reverse.unittest\n");
int[] a = new int[5];
int[] b;
size_t i;
for (i = 0; i < 5; i++)
a[i] = i;
b = a.reverse;
assert(b is a);
for (i = 0; i < 5; i++)
assert(a[i] == 4 - i);
struct X20
{ // More than 16 bytes in size
int a;
int b, c, d, e;
}
X20[] c = new X20[5];
X20[] d;
for (i = 0; i < 5; i++)
{ c[i].a = i;
c[i].e = 10;
}
d = c.reverse;
assert(d is c);
for (i = 0; i < 5; i++)
{
assert(c[i].a == 4 - i);
assert(c[i].e == 10);
}
}
/**********************************************
* Sort array of chars.
*/
extern (C) char[] _adSortChar(char[] a)
{
if (a.length > 1)
{
dstring da = toUTF32(a);
da.sort;
size_t i = 0;
foreach (dchar d; da)
{ char[4] buf;
auto t = toUTF8(buf, d);
a[i .. i + t.length] = t[];
i += t.length;
}
delete da;
}
return a;
}
/**********************************************
* Sort array of wchars.
*/
extern (C) wchar[] _adSortWchar(wchar[] a)
{
if (a.length > 1)
{
dstring da = toUTF32(a);
da.sort;
size_t i = 0;
foreach (dchar d; da)
{ wchar[2] buf;
auto t = toUTF16(buf, d);
a[i .. i + t.length] = t[];
i += t.length;
}
delete da;
}
return a;
}
/***************************************
* Support for array equality test.
* The actual type is painted on the return value by the frontend
* Given lengths are number of elements
*/
extern (C) int _adEq(void[] a1, void[] a2, TypeInfo ti)
{
debug(adi) printf("_adEq(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
if (a1.length != a2.length)
return 0; // not equal
else if (a1.ptr == a2.ptr)
return 1; // equal
// let typeinfo decide
return ti.equals(&a1, &a2);
}
unittest
{
debug(adi) printf("array.Eq unittest\n");
char[] a = "hello"c;
assert(a != "hel");
assert(a != "helloo");
assert(a != "betty");
assert(a == "hello");
assert(a != "hxxxx");
}
/***************************************
* Support for array compare test.
* The actual type is painted on the return value by the frontend
* Given lengths are number of elements
*/
extern (C) int _adCmp(void[] a1, void[] a2, TypeInfo ti)
{
debug(adi) printf("adCmp()\n");
if (a1.ptr == a2.ptr &&
a1.length == a2.length)
return 0;
auto len = a1.length;
if (a2.length < len)
len = a2.length;
// let typeinfo decide
return ti.compare(&a1, &a2);
}
unittest
{
debug(adi) printf("array.Cmp unittest\n");
char[] a = "hello"c;
assert(a > "hel");
assert(a >= "hel");
assert(a < "helloo");
assert(a <= "helloo");
assert(a > "betty");
assert(a >= "betty");
assert(a == "hello");
assert(a <= "hello");
assert(a >= "hello");
}
/***************************************
* Support for array compare test.
* The actual type is painted on the return value by the frontend
* Given lengths are number of elements
*/
extern (C) int _adCmpChar(void[] a1, void[] a2)
{
version(D_InlineAsm_X86)
{
//version = Asm86;
}
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;
debug(adi) printf("adCmpChar()\n");
len = cast(int)a1.length;
if (a2.length < len)
len = cast(int)a2.length;
c = memcmp(cast(char *)a1.ptr, cast(char *)a2.ptr, len);
if (!c)
c = cast(int)a1.length - cast(int)a2.length;
return c;
}
}
unittest
{
debug(adi) printf("array.CmpChar unittest\n");
char[] a = "hello"c;
assert(a > "hel");
assert(a >= "hel");
assert(a < "helloo");
assert(a <= "helloo");
assert(a > "betty");
assert(a >= "betty");
assert(a == "hello");
assert(a <= "hello");
assert(a >= "hello");
}

View File

@@ -0,0 +1,158 @@
private import ldc.intrinsics;
extern(C):
int memcmp(void*,void*,size_t);
size_t strlen(char*);
version(LLVM64)
alias llvm_memcpy_i64 llvm_memcpy;
else
alias llvm_memcpy_i32 llvm_memcpy;
// per-element array init routines
void _d_array_init_i1(bool* a, size_t n, bool v)
{
auto p = a;
auto end = a+n;
while (p !is end)
*p++ = v;
}
void _d_array_init_i8(ubyte* a, size_t n, ubyte v)
{
auto p = a;
auto end = a+n;
while (p !is end)
*p++ = v;
}
void _d_array_init_i16(ushort* a, size_t n, ushort v)
{
auto p = a;
auto end = a+n;
while (p !is end)
*p++ = v;
}
void _d_array_init_i32(uint* a, size_t n, uint v)
{
auto p = a;
auto end = a+n;
while (p !is end)
*p++ = v;
}
void _d_array_init_i64(ulong* a, size_t n, ulong v)
{
auto p = a;
auto end = a+n;
while (p !is end)
*p++ = v;
}
void _d_array_init_float(float* a, size_t n, float v)
{
auto p = a;
auto end = a+n;
while (p !is end)
*p++ = v;
}
void _d_array_init_double(double* a, size_t n, double v)
{
auto p = a;
auto end = a+n;
while (p !is end)
*p++ = v;
}
void _d_array_init_real(real* a, size_t n, real v)
{
auto p = a;
auto end = a+n;
while (p !is end)
*p++ = v;
}
void _d_array_init_cfloat(cfloat* a, size_t n, cfloat v)
{
auto p = a;
auto end = a+n;
while (p !is end)
*p++ = v;
}
void _d_array_init_cdouble(cdouble* a, size_t n, cdouble v)
{
auto p = a;
auto end = a+n;
while (p !is end)
*p++ = v;
}
void _d_array_init_creal(creal* a, size_t n, creal v)
{
auto p = a;
auto end = a+n;
while (p !is end)
*p++ = v;
}
void _d_array_init_pointer(void** a, size_t n, void* v)
{
auto p = a;
auto end = a+n;
while (p !is end)
*p++ = v;
}
void _d_array_init_mem(void* a, size_t na, void* v, size_t nv)
{
auto p = a;
auto end = a + na*nv;
while (p !is end) {
llvm_memcpy(p,v,nv,0);
p += nv;
}
}
/*
void _d_array_init(TypeInfo ti, void* a)
{
auto initializer = ti.next.init();
auto isize = initializer.length;
auto q = initializer.ptr;
if (isize == 1)
memset(p, *cast(ubyte*)q, size);
else if (isize == int.sizeof)
{
int init = *cast(int*)q;
size /= int.sizeof;
for (size_t u = 0; u < size; u++)
{
(cast(int*)p)[u] = init;
}
}
else
{
for (size_t u = 0; u < size; u += isize)
{
memcpy(p + u, q, isize);
}
}
}*/
// for array cast
size_t _d_array_cast_len(size_t len, size_t elemsz, size_t newelemsz)
{
if (newelemsz == 1) {
return len*elemsz;
}
else if ((len*elemsz) % newelemsz) {
throw new Exception("Bad array cast");
}
return (len*elemsz)/newelemsz;
}

View File

@@ -0,0 +1,196 @@
/*
* Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
* Written by Walter Bright
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, in both source and binary form, subject to the following
* restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
*/
/*
* Modified by Sean Kelly <sean@f4.ca> for use with Tango.
*/
extern (C):
//debug = PRINTF;
debug(PRINTF) int printf(char*, ...);
/******************************************
* 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;
debug(PRINTF) printf("toObject(%p)\n", p);
if (p)
{
o = cast(Object)p;
debug(PRINTF) printf("o = %p\n", o);
debug(PRINTF) printf("o.vtbl = %p\n", *cast(void**)p);
ClassInfo oc = o.classinfo;
debug(PRINTF) printf("oc = %p\n", oc);
Interface *pi = **cast(Interface ***)p;
debug(PRINTF) printf("pi = %p\n", pi);
/* Interface.offset lines up with ClassInfo.name.ptr,
* so we rely on pointers never being less than 64K,
* and interface vtable offsets never being greater.
*/
if (pi.offset < 0x10000)
{
debug(PRINTF) printf("\tpi.offset = %d\n", pi.offset);
o = cast(Object)(p - pi.offset);
}
}
debug(PRINTF) printf("toObject = %p\n", o);
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;
debug(PRINTF) printf("_d_interface_cast(p = %p, c = '%.*s')\n", p, c.name.length, c.name.ptr);
if (p)
{
Interface *pi = **cast(Interface ***)p;
debug(PRINTF) printf("\tpi.offset = %d\n", pi.offset);
o = cast(Object)(p - pi.offset);
return _d_dynamic_cast(o, c);
}
debug(PRINTF) printf("_d_interface_cast = %p\n", o);
return o;
}
Object _d_dynamic_cast(Object o, ClassInfo c)
{ ClassInfo oc;
size_t offset = 0;
debug(PRINTF) printf("_d_dynamic_cast(o = %p, c = '%.*s')\n", o, c.name.length, c.name.ptr);
if (o)
{
oc = o.classinfo;
if (_d_isbaseof2(oc, c, offset))
{
debug(PRINTF) printf("\toffset = %d\n", offset);
o = cast(Object)(cast(void*)o + offset);
}
else
o = null;
}
//printf("\tresult = %p\n", o);
debug(PRINTF) printf("_d_dynamic_cast = %p\n", o);
return o;
}
int _d_isbaseof2(ClassInfo oc, ClassInfo c, ref size_t offset)
{ int i;
debug(PRINTF) printf("_d_isbaseof2(%.*s, %.*s, %ul)\n", oc.name.length, oc.name.ptr, c.name.length, c.name.ptr, offset);
if (oc is c)
return 1;
do
{
debug(PRINTF) printf("oc.interfaces.length = %ul\n", oc.interfaces.length);
if (oc.base is c)
return 1;
for (i = 0; i < oc.interfaces.length; i++)
{
ClassInfo ic;
ic = oc.interfaces[i].classinfo;
debug(PRINTF) printf("checking %.*s\n", ic.name.length, ic.name.ptr);
if (ic is c)
{ offset = cast(size_t)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 = cast(size_t)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);
}

View File

@@ -0,0 +1,164 @@
/*
* Placed into the Public Domain
* written by Walter Bright, Digital Mars
* www.digitalmars.com
*/
/* ================================= Win32 ============================ */
#if _WIN32
#include <windows.h>
/******************************************
* Enter/exit critical section.
*/
/* We don't initialize critical sections unless we actually need them.
* So keep a linked list of the ones we do use, and in the static destructor
* code, walk the list and release them.
*/
typedef struct D_CRITICAL_SECTION
{
struct D_CRITICAL_SECTION *next;
CRITICAL_SECTION cs;
} D_CRITICAL_SECTION;
static D_CRITICAL_SECTION *dcs_list;
static D_CRITICAL_SECTION critical_section;
static volatile int inited;
void _d_criticalenter(D_CRITICAL_SECTION *dcs)
{
if (!dcs->next)
{
EnterCriticalSection(&critical_section.cs);
if (!dcs->next) // if, in the meantime, another thread didn't set it
{
dcs->next = dcs_list;
dcs_list = dcs;
InitializeCriticalSection(&dcs->cs);
}
LeaveCriticalSection(&critical_section.cs);
}
EnterCriticalSection(&dcs->cs);
}
void _d_criticalexit(D_CRITICAL_SECTION *dcs)
{
LeaveCriticalSection(&dcs->cs);
}
void _STI_critical_init()
{
if (!inited)
{ InitializeCriticalSection(&critical_section.cs);
dcs_list = &critical_section;
inited = 1;
}
}
void _STD_critical_term()
{
if (inited)
{ inited = 0;
while (dcs_list)
{
DeleteCriticalSection(&dcs_list->cs);
dcs_list = dcs_list->next;
}
}
}
#endif
/* ================================= linux ============================ */
#if linux || __APPLE__ || __FreeBSD__
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#if !linux
#define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
#endif
/******************************************
* Enter/exit critical section.
*/
/* We don't initialize critical sections unless we actually need them.
* So keep a linked list of the ones we do use, and in the static destructor
* code, walk the list and release them.
*/
typedef struct D_CRITICAL_SECTION
{
struct D_CRITICAL_SECTION *next;
pthread_mutex_t cs;
} D_CRITICAL_SECTION;
static D_CRITICAL_SECTION *dcs_list;
static D_CRITICAL_SECTION critical_section;
static pthread_mutexattr_t _criticals_attr;
void _STI_critical_init(void);
void _STD_critical_term(void);
void _d_criticalenter(D_CRITICAL_SECTION *dcs)
{
if (!dcs_list)
{ _STI_critical_init();
atexit(_STD_critical_term);
}
//printf("_d_criticalenter(dcs = x%x)\n", dcs);
if (!dcs->next)
{
pthread_mutex_lock(&critical_section.cs);
if (!dcs->next) // if, in the meantime, another thread didn't set it
{
dcs->next = dcs_list;
dcs_list = dcs;
pthread_mutex_init(&dcs->cs, &_criticals_attr);
}
pthread_mutex_unlock(&critical_section.cs);
}
pthread_mutex_lock(&dcs->cs);
}
void _d_criticalexit(D_CRITICAL_SECTION *dcs)
{
//printf("_d_criticalexit(dcs = x%x)\n", dcs);
pthread_mutex_unlock(&dcs->cs);
}
void _STI_critical_init()
{
if (!dcs_list)
{ //printf("_STI_critical_init()\n");
pthread_mutexattr_init(&_criticals_attr);
pthread_mutexattr_settype(&_criticals_attr, PTHREAD_MUTEX_RECURSIVE_NP);
// The global critical section doesn't need to be recursive
pthread_mutex_init(&critical_section.cs, 0);
dcs_list = &critical_section;
}
}
void _STD_critical_term()
{
if (dcs_list)
{ //printf("_STI_critical_term()\n");
while (dcs_list)
{
//printf("\tlooping... %x\n", dcs_list);
pthread_mutex_destroy(&dcs_list->cs);
dcs_list = dcs_list->next;
}
}
}
#endif

View File

@@ -0,0 +1,314 @@
/*
* Placed into the Public Domain.
* written by Walter Bright
* www.digitalmars.com
*/
/*
* Modified by Sean Kelly <sean@f4.ca> for use with Tango.
*/
private
{
import util.console;
version( D_Version2)
{
import stdc.stddef;
import stdc.stdlib;
import stdc.string;
}
else
{
import tango.stdc.stddef;
import tango.stdc.stdlib;
import tango.stdc.string;
}
import memory;
}
version( Win32 )
{
extern (Windows) void* LocalFree(void*);
extern (Windows) wchar_t* GetCommandLineW();
extern (Windows) wchar_t** CommandLineToArgvW(wchar_t*, int*);
extern (Windows) export int WideCharToMultiByte(uint, uint, wchar_t*, int, char*, int, char*, int);
//pragma(lib, "shell32.lib"); // needed for CommandLineToArgvW
//pragma(lib, "tango-win32-dmd.lib"); // links Tango's Win32 library to reduce EXE size
}
extern (C) void _STI_monitor_staticctor();
extern (C) void _STD_monitor_staticdtor();
extern (C) void _STI_critical_init();
extern (C) void _STD_critical_term();
extern (C) void gc_init();
extern (C) void gc_term();
extern (C) void _moduleCtor();
extern (C) void _moduleDtor();
extern (C) void thread_joinAll();
//debug=PRINTF;
debug(PRINTF) extern (C) int printf(char*, ...);
/***********************************
* These functions must be defined for any D program linked
* against this library.
*/
extern (C) void onAssertError( char[] file, size_t line );
extern (C) void onAssertErrorMsg( char[] file, size_t line, char[] msg );
extern (C) void onArrayBoundsError( char[] file, size_t line );
extern (C) void onSwitchError( char[] file, size_t line );
extern (C) bool runModuleUnitTests();
// this function is called from the utf module
//extern (C) void onUnicodeError( char[] msg, size_t idx );
/***********************************
* These are internal callbacks for various language errors.
*/
extern (C) void _d_assert( char[] file, uint line )
{
onAssertError( file, line );
}
extern (C) void _d_assert_msg( char[] msg, char[] file, uint line )
{
onAssertErrorMsg( file, line, msg );
}
extern (C) void _d_array_bounds( char[] file, uint line )
{
onArrayBoundsError( file, line );
}
extern (C) void _d_switch_error( char[] file, uint line )
{
onSwitchError( file, line );
}
bool _d_isHalting = false;
extern (C) bool rt_isHalting()
{
return _d_isHalting;
}
extern (C) bool rt_trapExceptions = true;
void _d_criticalInit()
{
_STI_monitor_staticctor();
_STI_critical_init();
initStaticDataPtrs();
}
alias void delegate( Throwable ) ExceptionHandler;
// this is here so users can manually initialize the runtime
// for example, when there is no main function etc.
extern (C) bool rt_init( ExceptionHandler dg = null )
{
_d_criticalInit();
try
{
gc_init();
_moduleCtor();
return true;
}
catch( Throwable e )
{
if( dg )
dg( e );
}
catch
{
}
_d_criticalTerm();
return false;
}
void _d_criticalTerm()
{
_STD_critical_term();
_STD_monitor_staticdtor();
}
// this is here so users can manually terminate the runtime
// for example, when there is no main function etc.
extern (C) bool rt_term( ExceptionHandler dg = null )
{
try
{
thread_joinAll();
_d_isHalting = true;
_moduleDtor();
gc_term();
return true;
}
catch( Throwable e )
{
if( dg )
dg( e );
}
catch
{
}
finally
{
_d_criticalTerm();
}
return false;
}
/***********************************
* The D main() function supplied by the user's program
*/
int main(char[][] args);
/***********************************
* Substitutes for the C main() function.
* It's purpose is to wrap the call to the D main()
* function and catch any unhandled exceptions.
*/
extern (C) int main(int argc, char **argv, char** env)
{
char[][] args;
int result;
debug(PRINTF) printf("main ctors\n");
_STI_monitor_staticctor();
_STI_critical_init();
initStaticDataPtrs();
debug(PRINTF) printf("main args\n");
// GDC seems to get by without this Windows special case...
version (Win32)
{
wchar_t* wcbuf = GetCommandLineW();
size_t wclen = wcslen(wcbuf);
int wargc = 0;
wchar_t** wargs = CommandLineToArgvW(wcbuf, &wargc);
assert(wargc == argc);
char* cargp = null;
size_t cargl = WideCharToMultiByte(65001, 0, wcbuf, wclen, null, 0, null, 0);
cargp = cast(char*) alloca(cargl);
args = ((cast(char[]*) alloca(wargc * (char[]).sizeof)))[0 .. wargc];
for (size_t i = 0, p = 0; i < wargc; i++)
{
int wlen = wcslen( wargs[i] );
int clen = WideCharToMultiByte(65001, 0, &wargs[i][0], wlen, null, 0, null, 0);
args[i] = cargp[p .. p+clen];
p += clen; assert(p <= cargl);
WideCharToMultiByte(65001, 0, &wargs[i][0], wlen, &args[i][0], clen, null, 0);
}
LocalFree(wargs);
wargs = null;
wargc = 0;
}
else
{
char[]* am = cast(char[]*) malloc(argc * (char[]).sizeof);
scope(exit) free(am);
for (size_t i = 0; i < argc; i++)
{
auto len = strlen(argv[i]);
am[i] = argv[i][0 .. len];
}
args = am[0 .. argc];
}
debug(PRINTF) printf("main trap exceptions\n");
bool trapExceptions = rt_trapExceptions;
void tryExec(void delegate() dg)
{
debug(PRINTF) printf("main try exec\n");
if (trapExceptions)
{
try
{
dg();
}
catch (Throwable e)
{
while (e)
{
if (e.file)
{
// fprintf(stderr, "%.*s(%u): %.*s\n", e.file, e.line, e.msg);
console (e.classinfo.name)("@")(e.file)("(")(e.line)("): ")(e.toString)("\n");
}
else
{
// fprintf(stderr, "%.*s\n", e.toString());
console (e.classinfo.name)(": ")(e.toString)("\n");
}
if (e.info)
{
console ("----------------\n");
foreach (t; e.info)
console (t)("\n");
}
if (e.next)
console ("\n");
e = e.next;
}
result = EXIT_FAILURE;
}
catch (Object o)
{
// fprintf(stderr, "%.*s\n", o.toString());
console (o.toString)("\n");
result = EXIT_FAILURE;
}
}
else
{
dg();
}
}
// NOTE: The lifetime of a process is much like the lifetime of an object:
// it is initialized, then used, then destroyed. If initialization
// fails, the successive two steps are never reached. However, if
// initialization succeeds, then cleanup will occur even if the use
// step fails in some way. Here, the use phase consists of running
// the user's main function. If main terminates with an exception,
// the exception is handled and then cleanup begins. An exception
// thrown during cleanup, however, will abort the cleanup process.
void runMain()
{
debug(PRINTF) printf("main runMain\n");
result = main(args);
}
void runAll()
{
debug(PRINTF) printf("main runAll\n");
gc_init();
_moduleCtor();
if (runModuleUnitTests())
tryExec(&runMain);
thread_joinAll();
_d_isHalting = true;
_moduleDtor();
gc_term();
}
tryExec(&runAll);
debug(PRINTF) printf("main dtor\n");
_STD_critical_term();
_STD_monitor_staticdtor();
return result;
}

View File

@@ -0,0 +1,388 @@
/**
* This module contains functions and structures required for
* exception handling.
*/
module eh;
import util.console;
import ldc.cstdarg;
// debug = EH_personality;
// current EH implementation works on x86
// if it has a working unwind runtime
version(X86) {
version(linux) version=X86_UNWIND;
version(darwin) version=X86_UNWIND;
}
version(X86_64) {
version(linux) version=X86_UNWIND;
}
private extern(C) void abort();
private extern(C) int printf(in char*, ...);
private extern(C) int vprintf(in char*, va_list va);
// D runtime functions
extern(C) {
int _d_isbaseof(ClassInfo oc, ClassInfo c);
}
// libunwind headers
extern(C)
{
enum _Unwind_Reason_Code
{
NO_REASON = 0,
FOREIGN_EXCEPTION_CAUGHT = 1,
FATAL_PHASE2_ERROR = 2,
FATAL_PHASE1_ERROR = 3,
NORMAL_STOP = 4,
END_OF_STACK = 5,
HANDLER_FOUND = 6,
INSTALL_CONTEXT = 7,
CONTINUE_UNWIND = 8
}
enum _Unwind_Action
{
SEARCH_PHASE = 1,
CLEANUP_PHASE = 2,
HANDLER_PHASE = 3,
FORCE_UNWIND = 4
}
alias void* _Unwind_Context_Ptr;
alias void function(_Unwind_Reason_Code, _Unwind_Exception*) _Unwind_Exception_Cleanup_Fn;
struct _Unwind_Exception
{
char[8] exception_class;
_Unwind_Exception_Cleanup_Fn exception_cleanup;
int private_1;
int private_2;
}
version(X86_UNWIND)
{
void _Unwind_Resume(_Unwind_Exception*);
_Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception*);
ulong _Unwind_GetLanguageSpecificData(_Unwind_Context_Ptr context);
ulong _Unwind_GetIP(_Unwind_Context_Ptr context);
ulong _Unwind_SetIP(_Unwind_Context_Ptr context, ulong new_value);
ulong _Unwind_SetGR(_Unwind_Context_Ptr context, int index, ulong new_value);
ulong _Unwind_GetRegionStart(_Unwind_Context_Ptr context);
}
else
{
// runtime calls these directly
void _Unwind_Resume(_Unwind_Exception*)
{
console("_Unwind_Resume is not implemented on this platform.\n");
}
_Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception*)
{
console("_Unwind_RaiseException is not implemented on this platform.\n");
return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
}
}
}
// error and exit
extern(C) private void fatalerror(in char* format, ...)
{
va_list args;
va_start(args, format);
printf("Fatal error in EH code: ");
vprintf(format, args);
printf("\n");
abort();
}
// helpers for reading certain DWARF data
private ubyte* get_uleb128(ubyte* addr, ref size_t res)
{
res = 0;
size_t bitsize = 0;
// read as long as high bit is set
while(*addr & 0x80) {
res |= (*addr & 0x7f) << bitsize;
bitsize += 7;
addr += 1;
if(bitsize >= size_t.sizeof*8)
fatalerror("tried to read uleb128 that exceeded size of size_t");
}
// read last
if(bitsize != 0 && *addr >= 1 << size_t.sizeof*8 - bitsize)
fatalerror("Fatal error in EH code: tried to read uleb128 that exceeded size of size_t");
res |= (*addr) << bitsize;
return addr + 1;
}
private ubyte* get_sleb128(ubyte* addr, ref ptrdiff_t res)
{
res = 0;
size_t bitsize = 0;
// read as long as high bit is set
while(*addr & 0x80) {
res |= (*addr & 0x7f) << bitsize;
bitsize += 7;
addr += 1;
if(bitsize >= size_t.sizeof*8)
fatalerror("tried to read sleb128 that exceeded size of size_t");
}
// read last
if(bitsize != 0 && *addr >= 1 << size_t.sizeof*8 - bitsize)
fatalerror("tried to read sleb128 that exceeded size of size_t");
res |= (*addr) << bitsize;
// take care of sign
if(bitsize < size_t.sizeof*8 && ((*addr) & 0x40))
res |= cast(ptrdiff_t)(-1) ^ ((1 << (bitsize+7)) - 1);
return addr + 1;
}
// exception struct used by the runtime.
// _d_throw allocates a new instance and passes the address of its
// _Unwind_Exception member to the unwind call. The personality
// routine is then able to get the whole struct by looking at the data
// surrounding the unwind info.
struct _d_exception
{
Object exception_object;
_Unwind_Exception unwind_info;
}
// the 8-byte string identifying the type of exception
// the first 4 are for vendor, the second 4 for language
//TODO: This may be the wrong way around
char[8] _d_exception_class = "LLDCD1\0\0";
//
// x86 unwind specific implementation of personality function
// and helpers
//
version(X86_UNWIND)
{
// the personality routine gets called by the unwind handler and is responsible for
// reading the EH tables and deciding what to do
extern(C) _Unwind_Reason_Code _d_eh_personality(int ver, _Unwind_Action actions, ulong exception_class, _Unwind_Exception* exception_info, _Unwind_Context_Ptr context)
{
// check ver: the C++ Itanium ABI only allows ver == 1
if(ver != 1)
return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
// check exceptionClass
//TODO: Treat foreign exceptions with more respect
if((cast(char*)&exception_class)[0..8] != _d_exception_class)
return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
// find call site table, action table and classinfo table
// Note: callsite and action tables do not contain static-length
// data and will be parsed as needed
// Note: classinfo_table points past the end of the table
ubyte* callsite_table;
ubyte* action_table;
ClassInfo* classinfo_table;
_d_getLanguageSpecificTables(context, callsite_table, action_table, classinfo_table);
/*
find landing pad and action table index belonging to ip by walking
the callsite_table
*/
ubyte* callsite_walker = callsite_table;
// get the instruction pointer
// will be used to find the right entry in the callsite_table
// -1 because it will point past the last instruction
ulong ip = _Unwind_GetIP(context) - 1;
// address block_start is relative to
ulong region_start = _Unwind_GetRegionStart(context);
// table entries
uint block_start_offset, block_size;
ulong landing_pad;
size_t action_offset;
while(true) {
// if we've gone through the list and found nothing...
if(callsite_walker >= action_table)
return _Unwind_Reason_Code.CONTINUE_UNWIND;
block_start_offset = *cast(uint*)callsite_walker;
block_size = *(cast(uint*)callsite_walker + 1);
landing_pad = *(cast(uint*)callsite_walker + 2);
if(landing_pad)
landing_pad += region_start;
callsite_walker = get_uleb128(callsite_walker + 3*uint.sizeof, action_offset);
debug(EH_personality_verbose) printf("%d %d %d\n", block_start_offset, block_size, landing_pad);
// since the list is sorted, as soon as we're past the ip
// there's no handler to be found
if(ip < region_start + block_start_offset)
return _Unwind_Reason_Code.CONTINUE_UNWIND;
// if we've found our block, exit
if(ip < region_start + block_start_offset + block_size)
break;
}
debug(EH_personality) printf("Found correct landing pad and actionOffset %d\n", action_offset);
// now we need the exception's classinfo to find a handler
// the exception_info is actually a member of a larger _d_exception struct
// the runtime allocated. get that now
_d_exception* exception_struct = cast(_d_exception*)(cast(ubyte*)exception_info - _d_exception.unwind_info.offsetof);
// if there's no action offset and no landing pad, continue unwinding
if(!action_offset && !landing_pad)
return _Unwind_Reason_Code.CONTINUE_UNWIND;
// if there's no action offset but a landing pad, this is a cleanup handler
else if(!action_offset && landing_pad)
return _d_eh_install_finally_context(actions, landing_pad, exception_struct, context);
/*
walk action table chain, comparing classinfos using _d_isbaseof
*/
ubyte* action_walker = action_table + action_offset - 1;
ptrdiff_t ti_offset, next_action_offset;
while(true) {
action_walker = get_sleb128(action_walker, ti_offset);
// it is intentional that we not modify action_walker here
// next_action_offset is from current action_walker position
get_sleb128(action_walker, next_action_offset);
// negative are 'filters' which we don't use
if(!(ti_offset >= 0))
fatalerror("Filter actions are unsupported");
// zero means cleanup, which we require to be the last action
if(ti_offset == 0) {
if(!(next_action_offset == 0))
fatalerror("Cleanup action must be last in chain");
return _d_eh_install_finally_context(actions, landing_pad, exception_struct, context);
}
// get classinfo for action and check if the one in the
// exception structure is a base
ClassInfo catch_ci = classinfo_table[-ti_offset];
debug(EH_personality) printf("Comparing catch %s to exception %s\n", catch_ci.name.ptr, exception_struct.exception_object.classinfo.name.ptr);
if(_d_isbaseof(exception_struct.exception_object.classinfo, catch_ci))
return _d_eh_install_catch_context(actions, ti_offset, landing_pad, exception_struct, context);
// we've walked through all actions and found nothing...
if(next_action_offset == 0)
return _Unwind_Reason_Code.CONTINUE_UNWIND;
else
action_walker += next_action_offset;
}
fatalerror("reached unreachable");
return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
}
// These are the register numbers for SetGR that
// llvm's eh.exception and eh.selector intrinsics
// will pick up.
// Found by trial-and-error :/
version (X86_64)
{
private int eh_exception_regno = 3;
private int eh_selector_regno = 1;
} else {
private int eh_exception_regno = 0;
private int eh_selector_regno = 2;
}
private _Unwind_Reason_Code _d_eh_install_catch_context(_Unwind_Action actions, ptrdiff_t switchval, ulong landing_pad, _d_exception* exception_struct, _Unwind_Context_Ptr context)
{
debug(EH_personality) printf("Found catch clause!\n");
if(actions & _Unwind_Action.SEARCH_PHASE)
return _Unwind_Reason_Code.HANDLER_FOUND;
else if(actions & _Unwind_Action.HANDLER_PHASE)
{
debug(EH_personality) printf("Setting switch value to: %d!\n", switchval);
_Unwind_SetGR(context, eh_exception_regno, cast(ulong)cast(void*)(exception_struct.exception_object));
_Unwind_SetGR(context, eh_selector_regno, switchval);
_Unwind_SetIP(context, landing_pad);
return _Unwind_Reason_Code.INSTALL_CONTEXT;
}
fatalerror("reached unreachable");
return _Unwind_Reason_Code.FATAL_PHASE2_ERROR;
}
private _Unwind_Reason_Code _d_eh_install_finally_context(_Unwind_Action actions, ulong landing_pad, _d_exception* exception_struct, _Unwind_Context_Ptr context)
{
// if we're merely in search phase, continue
if(actions & _Unwind_Action.SEARCH_PHASE)
return _Unwind_Reason_Code.CONTINUE_UNWIND;
debug(EH_personality) printf("Calling cleanup routine...\n");
_Unwind_SetGR(context, eh_exception_regno, cast(ulong)exception_struct);
_Unwind_SetGR(context, eh_selector_regno, 0);
_Unwind_SetIP(context, landing_pad);
return _Unwind_Reason_Code.INSTALL_CONTEXT;
}
private void _d_getLanguageSpecificTables(_Unwind_Context_Ptr context, ref ubyte* callsite, ref ubyte* action, ref ClassInfo* ci)
{
ubyte* data = cast(ubyte*)_Unwind_GetLanguageSpecificData(context);
//TODO: Do proper DWARF reading here
if(*data++ != 0xff)
fatalerror("DWARF header has unexpected format 1");
if(*data++ != 0x00)
fatalerror("DWARF header has unexpected format 2");
size_t cioffset;
data = get_uleb128(data, cioffset);
ci = cast(ClassInfo*)(data + cioffset);
if(*data++ != 0x03)
fatalerror("DWARF header has unexpected format 3");
size_t callsitelength;
data = get_uleb128(data, callsitelength);
action = data + callsitelength;
callsite = data;
}
} // end of x86 Linux specific implementation
extern(C) void _d_throw_exception(Object e)
{
if (e !is null)
{
_d_exception* exc_struct = new _d_exception;
exc_struct.unwind_info.exception_class[] = _d_exception_class;
exc_struct.exception_object = e;
_Unwind_Reason_Code ret = _Unwind_RaiseException(&exc_struct.unwind_info);
console("_Unwind_RaiseException failed with reason code: ")(ret)("\n");
}
abort();
}
extern(C) void _d_eh_resume_unwind(_d_exception* exception_struct)
{
_Unwind_Resume(&exception_struct.unwind_info);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,25 @@
/*
* Placed into the Public Domain
* written by Walter Bright
* www.digitalmars.com
*/
extern(C) void _d_invariant(Object o)
{ ClassInfo c;
//printf("__d_invariant(%p)\n", o);
// BUG: needs to be filename/line of caller, not library routine
assert(o !is null); // just do null check, not invariant check
c = o.classinfo;
do
{
if (c.classInvariant)
{
(*c.classInvariant)(o);
}
c = c.base;
} while (c);
}

View File

@@ -0,0 +1,261 @@
# Makefile to build the LDC compiler runtime D library for Linux
# Designed to work with GNU make
# Targets:
# make
# Same as make all
# make lib
# Build the compiler runtime library
# make doc
# Generate documentation
# make clean
# Delete unneeded files created by build process
LIB_TARGET_FULL=libldc-runtime.a
LIB_TARGET_BC_ONLY=libldc-runtime-bc-only.a
LIB_TARGET_C_ONLY=libldc-runtime-c-only.a
LIB_TARGET_SHARED=libldc-runtime-shared.so
LIB_MASK=libldc-runtime*.*
CP=cp -f
RM=rm -f
MD=mkdir -p
#CFLAGS=-O3 $(ADD_CFLAGS)
CFLAGS=$(ADD_CFLAGS)
#DFLAGS=-release -O3 -inline -w $(ADD_DFLAGS)
DFLAGS=-w $(ADD_DFLAGS)
#TFLAGS=-O3 -inline -w $(ADD_DFLAGS)
TFLAGS=-w $(ADD_DFLAGS)
DOCFLAGS=-version=DDoc
CC=gcc
LC=llvm-ar rsv
LLINK=llvm-link
LCC=llc
CLC=ar rsv
DC=ldc
LLC=llvm-as
LIB_DEST=..
.SUFFIXES: .s .S .c .cpp .d .ll .html .o .bc
.s.o:
$(CC) -c $(CFLAGS) $< -o$@
.S.o:
$(CC) -c $(CFLAGS) $< -o$@
.c.o:
$(CC) -c $(CFLAGS) $< -o$@
.cpp.o:
g++ -c $(CFLAGS) $< -o$@
.d.o:
$(DC) -c $(DFLAGS) $< -of$@ -output-bc
.d.html:
$(DC) -c -o- $(DOCFLAGS) -Df$*.html ldc.ddoc $<
targets : lib sharedlib doc
all : lib sharedlib doc
#lib : ldc.bclib ldc.clib ldc.lib
lib : ldc.clib ldc.lib
sharedlib : ldc.sharedlib
doc : ldc.doc
######################################################
OBJ_C= \
monitor.o \
critical.o
OBJ_BASE_BC= \
aaA.bc \
aApply.bc \
aApplyR.bc \
adi.bc \
arrayInit.bc \
cast.bc \
dmain2.bc \
eh.bc \
genobj.bc \
lifetime.bc \
memory.bc \
qsort2.bc \
switch.bc \
invariant.bc
OBJ_UTIL_BC= \
util/console.bc \
util/ctype.bc \
util/string.bc \
util/utf.bc
OBJ_LDC_BC= \
ldc/bitmanip.bc \
ldc/vararg.bc
OBJ_TI_BC= \
typeinfo/ti_AC.bc \
typeinfo/ti_Acdouble.bc \
typeinfo/ti_Acfloat.bc \
typeinfo/ti_Acreal.bc \
typeinfo/ti_Adouble.bc \
typeinfo/ti_Afloat.bc \
typeinfo/ti_Ag.bc \
typeinfo/ti_Aint.bc \
typeinfo/ti_Along.bc \
typeinfo/ti_Areal.bc \
typeinfo/ti_Ashort.bc \
typeinfo/ti_byte.bc \
typeinfo/ti_C.bc \
typeinfo/ti_cdouble.bc \
typeinfo/ti_cfloat.bc \
typeinfo/ti_char.bc \
typeinfo/ti_creal.bc \
typeinfo/ti_dchar.bc \
typeinfo/ti_delegate.bc \
typeinfo/ti_double.bc \
typeinfo/ti_float.bc \
typeinfo/ti_idouble.bc \
typeinfo/ti_ifloat.bc \
typeinfo/ti_int.bc \
typeinfo/ti_ireal.bc \
typeinfo/ti_long.bc \
typeinfo/ti_ptr.bc \
typeinfo/ti_real.bc \
typeinfo/ti_short.bc \
typeinfo/ti_ubyte.bc \
typeinfo/ti_uint.bc \
typeinfo/ti_ulong.bc \
typeinfo/ti_ushort.bc \
typeinfo/ti_void.bc \
typeinfo/ti_wchar.bc
OBJ_BASE_O= \
aaA.o \
aApply.o \
aApplyR.o \
adi.o \
arrayInit.o \
cast.o \
dmain2.o \
eh.o \
genobj.o \
lifetime.o \
memory.o \
qsort2.o \
switch.o \
invariant.o
OBJ_UTIL_O= \
util/console.o \
util/ctype.o \
util/string.o \
util/utf.o
OBJ_LDC_O= \
ldc/bitmanip.o \
ldc/vararg.o
OBJ_TI_O= \
typeinfo/ti_AC.o \
typeinfo/ti_Acdouble.o \
typeinfo/ti_Acfloat.o \
typeinfo/ti_Acreal.o \
typeinfo/ti_Adouble.o \
typeinfo/ti_Afloat.o \
typeinfo/ti_Ag.o \
typeinfo/ti_Aint.o \
typeinfo/ti_Along.o \
typeinfo/ti_Areal.o \
typeinfo/ti_Ashort.o \
typeinfo/ti_byte.o \
typeinfo/ti_C.o \
typeinfo/ti_cdouble.o \
typeinfo/ti_cfloat.o \
typeinfo/ti_char.o \
typeinfo/ti_creal.o \
typeinfo/ti_dchar.o \
typeinfo/ti_delegate.o \
typeinfo/ti_double.o \
typeinfo/ti_float.o \
typeinfo/ti_idouble.o \
typeinfo/ti_ifloat.o \
typeinfo/ti_int.o \
typeinfo/ti_ireal.o \
typeinfo/ti_long.o \
typeinfo/ti_ptr.o \
typeinfo/ti_real.o \
typeinfo/ti_short.o \
typeinfo/ti_ubyte.o \
typeinfo/ti_uint.o \
typeinfo/ti_ulong.o \
typeinfo/ti_ushort.o \
typeinfo/ti_void.o \
typeinfo/ti_wchar.o
ALL_OBJS_BC= \
$(OBJ_BASE_BC) \
$(OBJ_UTIL_BC) \
$(OBJ_TI_BC) \
$(OBJ_LDC_BC)
ALL_OBJS_O= \
$(OBJ_BASE_O) \
$(OBJ_UTIL_O) \
$(OBJ_TI_O) \
$(OBJ_LDC_O) \
$(OBJ_C)
######################################################
ALL_DOCS=
######################################################
#ldc.bclib : $(LIB_TARGET_BC_ONLY)
ldc.clib : $(LIB_TARGET_C_ONLY)
ldc.lib : $(LIB_TARGET_FULL)
ldc.sharedlib : $(LIB_TARGET_SHARED)
#$(LIB_TARGET_BC_ONLY) : $(ALL_OBJS_O)
# $(RM) $@
# $(LC) $@ $(ALL_OBJS_BC)
$(LIB_TARGET_FULL) : $(ALL_OBJS_O)
$(RM) $@
$(CLC) $@ $(ALL_OBJS_O)
$(LIB_TARGET_C_ONLY) : $(OBJ_C)
$(RM) $@
$(CLC) $@ $(OBJ_C)
$(LIB_TARGET_SHARED) : $(ALL_OBJS_O)
$(RM) $@
$(CC) -shared -o $@ $(ALL_OBJS_O)
ldc.doc : $(ALL_DOCS)
echo No documentation available.
######################################################
clean :
find . -name "*.di" | xargs $(RM)
# $(RM) $(ALL_OBJS_BC)
$(RM) $(ALL_OBJS_O)
$(RM) $(ALL_DOCS)
$(RM) $(LIB_MASK)
install :
$(MD) $(LIB_DEST)
$(CP) $(LIB_MASK) $(LIB_DEST)/.

View File

@@ -0,0 +1,81 @@
/*
* D phobos intrinsics for LDC
*
* From GDC ... public domain!
*/
module ldc.bitmanip;
// Check for the right compiler
version(LDC)
{
// OK
}
else
{
static assert(false, "This module is only valid for LDC");
}
int bsf(uint v)
{
uint m = 1;
uint i;
for (i = 0; i < 32; i++,m<<=1) {
if (v&m)
return i;
}
return i; // supposed to be undefined
}
int bsr(uint v)
{
uint m = 0x80000000;
uint i;
for (i = 32; i ; i--,m>>>=1) {
if (v&m)
return i-1;
}
return i; // supposed to be undefined
}
int bt(uint *p, uint bitnum)
{
return (p[bitnum / (uint.sizeof*8)] & (1<<(bitnum & ((uint.sizeof*8)-1)))) ? -1 : 0 ;
}
int btc(uint *p, uint bitnum)
{
uint * q = p + (bitnum / (uint.sizeof*8));
uint mask = 1 << (bitnum & ((uint.sizeof*8) - 1));
int result = *q & mask;
*q ^= mask;
return result ? -1 : 0;
}
int btr(uint *p, uint bitnum)
{
uint * q = p + (bitnum / (uint.sizeof*8));
uint mask = 1 << (bitnum & ((uint.sizeof*8) - 1));
int result = *q & mask;
*q &= ~mask;
return result ? -1 : 0;
}
int bts(uint *p, uint bitnum)
{
uint * q = p + (bitnum / (uint.sizeof*8));
uint mask = 1 << (bitnum & ((uint.sizeof*8) - 1));
int result = *q & mask;
*q |= mask;
return result ? -1 : 0;
}
pragma(intrinsic, "llvm.bswap.i32")
uint bswap(uint val);
ubyte inp(uint p) { throw new Exception("inp intrinsic not yet implemented"); }
ushort inpw(uint p) { throw new Exception("inpw intrinsic not yet implemented"); }
uint inpl(uint p) { throw new Exception("inpl intrinsic not yet implemented"); }
ubyte outp(uint p, ubyte v) { throw new Exception("outp intrinsic not yet implemented"); }
ushort outpw(uint p, ushort v) { throw new Exception("outpw intrinsic not yet implemented"); }
uint outpl(uint p, uint v) { throw new Exception("outpl intrinsic not yet implemented"); }

View File

@@ -0,0 +1,43 @@
/*
* This module holds the implementation of special vararg templates for D style var args.
*
* Provides the functions tango.core.Vararg expects to be present!
*/
module ldc.Vararg;
// Check for the right compiler
version(LDC)
{
// OK
}
else
{
static assert(false, "This module is only valid for LDC");
}
alias void* va_list;
void va_start(T) ( out va_list ap, inout T parmn )
{
// not needed !
}
T va_arg(T)(ref va_list vp)
{
T* arg = cast(T*) vp;
// ldc always aligns to size_t.sizeof in vararg lists
vp = cast(va_list) ( cast(void*) vp + ( ( T.sizeof + size_t.sizeof - 1 ) & ~( size_t.sizeof - 1 ) ) );
return *arg;
}
void va_end( va_list ap )
{
// not needed !
}
void va_copy( out va_list dst, va_list src )
{
// seems pretty useless !
dst = src;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,105 @@
/*
* Placed into the Public Domain
* written by Walter Bright, Digital Mars
* www.digitalmars.com
*/
/*
* Modified by Sean Kelly <sean@f4.ca> for use with Tango.
*/
#include <stddef.h>
#if __cplusplus
extern "C" {
#endif
struct ClassInfo;
struct Vtbl;
typedef struct Vtbl
{
size_t len;
void **vptr;
} Vtbl;
typedef struct Interface
{
struct ClassInfo *classinfo;
struct Vtbl vtbl;
int offset;
} Interface;
typedef struct Object
{
void **vptr;
void *monitor;
} Object;
typedef struct ClassInfo
{
Object object;
size_t initlen;
void *init;
size_t namelen;
char *name;
Vtbl vtbl;
size_t interfacelen;
Interface *interfaces;
struct ClassInfo *baseClass;
void *destructor;
void *invariant;
int flags;
} ClassInfo;
typedef struct Exception
{
Object object;
size_t msglen;
char* msg;
size_t filelen;
char* file;
size_t line;
struct Interface *info;
struct Exception *next;
} Exception;
typedef struct Array
{
size_t length;
void *ptr;
} Array;
typedef struct Delegate
{
void *thisptr;
void (*funcptr)();
} Delegate;
void _d_monitorenter(Object *h);
void _d_monitorexit(Object *h);
int _d_isbaseof(ClassInfo *b, ClassInfo *c);
Object *_d_dynamic_cast(Object *o, ClassInfo *ci);
Object * _d_allocclass(ClassInfo *ci);
void _d_delclass(Object **p);
void _d_OutOfMemory();
#if __cplusplus
}
#endif

View File

@@ -0,0 +1,378 @@
/**
* This module exposes functionality for inspecting and manipulating memory.
*
* Copyright: Copyright (C) 2005-2006 Digital Mars, www.digitalmars.com.
* All rights reserved.
* License:
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, in both source and binary form, subject to the following
* restrictions:
*
* o The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* o Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
* o This notice may not be removed or altered from any source
* distribution.
* Authors: Walter Bright, Sean Kelly
*/
module memory;
version = GC_Use_Dynamic_Ranges;
// does Posix suffice?
version(Posix)
{
version = GC_Use_Data_Proc_Maps;
}
version(GC_Use_Data_Proc_Maps)
{
version(Posix) {} else {
static assert(false, "Proc Maps only supported on Posix systems");
}
version( D_Version2 )
{
private import stdc.posix.unistd;
private import stdc.posix.fcntl;
private import stdc.string;
}
else
{
private import tango.stdc.posix.unistd;
private import tango.stdc.posix.fcntl;
private import tango.stdc.string;
}
version = GC_Use_Dynamic_Ranges;
}
private
{
version( linux )
{
//version = SimpleLibcStackEnd;
version( SimpleLibcStackEnd )
{
extern (C) extern void* __libc_stack_end;
}
else
{
version( D_Version2 )
import stdc.posix.dlfcn;
else
import tango.stdc.posix.dlfcn;
}
}
version(LDC)
{
pragma(intrinsic, "llvm.frameaddress")
{
void* llvm_frameaddress(uint level=0);
}
}
}
/**
*
*/
extern (C) void* rt_stackBottom()
{
version( Win32 )
{
void* bottom;
asm
{
mov EAX, FS:4;
mov bottom, EAX;
}
return bottom;
}
else version( linux )
{
version( SimpleLibcStackEnd )
{
return __libc_stack_end;
}
else
{
// See discussion: http://autopackage.org/forums/viewtopic.php?t=22
static void** libc_stack_end;
if( libc_stack_end == libc_stack_end.init )
{
void* handle = dlopen( null, RTLD_NOW );
libc_stack_end = cast(void**) dlsym( handle, "__libc_stack_end" );
dlclose( handle );
}
return *libc_stack_end;
}
}
else version( darwin )
{
// darwin has a fixed stack bottom
return cast(void*) 0xc0000000;
}
else
{
static assert( false, "Operating system not supported." );
}
}
/**
*
*/
extern (C) void* rt_stackTop()
{
version(LDC)
{
return llvm_frameaddress();
}
else version( D_InlineAsm_X86 )
{
asm
{
naked;
mov EAX, ESP;
ret;
}
}
else
{
static assert( false, "Architecture not supported." );
}
}
private
{
version( Win32 )
{
extern (C)
{
extern int _data_start__;
extern int _bss_end__;
alias _data_start__ Data_Start;
alias _bss_end__ Data_End;
}
}
else version( linux )
{
extern (C)
{
extern int _data;
extern int __data_start;
extern int _end;
extern int _data_start__;
extern int _data_end__;
extern int _bss_start__;
extern int _bss_end__;
extern int __fini_array_end;
}
alias __data_start Data_Start;
alias _end Data_End;
}
version( GC_Use_Dynamic_Ranges )
{
version( D_Version2 )
private import stdc.stdlib;
else
private import tango.stdc.stdlib;
struct DataSeg
{
void* beg;
void* end;
}
DataSeg* allSegs = null;
size_t numSegs = 0;
extern (C) void _d_gc_add_range( void* beg, void* end )
{
void* ptr = realloc( allSegs, (numSegs + 1) * DataSeg.sizeof );
if( ptr ) // if realloc fails, we have problems
{
allSegs = cast(DataSeg*) ptr;
allSegs[numSegs].beg = beg;
allSegs[numSegs].end = end;
numSegs++;
}
}
extern (C) void _d_gc_remove_range( void* beg )
{
for( size_t pos = 0; pos < numSegs; ++pos )
{
if( beg == allSegs[pos].beg )
{
while( ++pos < numSegs )
{
allSegs[pos-1] = allSegs[pos];
}
numSegs--;
return;
}
}
}
}
alias void delegate( void*, void* ) scanFn;
void* dataStart, dataEnd;
}
/**
*
*/
extern (C) void rt_scanStaticData( scanFn scan )
{
scan( dataStart, dataEnd );
version( GC_Use_Dynamic_Ranges )
{
for( size_t pos = 0; pos < numSegs; ++pos )
{
scan( allSegs[pos].beg, allSegs[pos].end );
}
}
}
void initStaticDataPtrs()
{
version( D_Version2 )
enum { int S = (void*).sizeof }
else
const int S = (void*).sizeof;
// Can't assume the input addresses are word-aligned
static void* adjust_up( void* p )
{
return p + ((S - (cast(size_t)p & (S-1))) & (S-1)); // cast ok even if 64-bit
}
static void * adjust_down( void* p )
{
return p - (cast(size_t) p & (S-1));
}
version( Win32 )
{
dataStart = adjust_up( &Data_Start );
dataEnd = adjust_down( &Data_End );
}
else version( GC_Use_Data_Proc_Maps )
{
// TODO: Exclude zero-mapped regions
int fd = open("/proc/self/maps", O_RDONLY);
int count; // %% need to configure ret for read..
char buf[2024];
char* p;
char* e;
char* s;
void* start;
void* end;
p = buf.ptr;
if (fd != -1)
{
while ( (count = read(fd, p, buf.sizeof - (p - buf.ptr))) > 0 )
{
e = p + count;
p = buf.ptr;
while (true)
{
s = p;
while (p < e && *p != '\n')
p++;
if (p < e)
{
// parse the entry in [s, p)
static if( S == 4 )
{
enum Ofs
{
Write_Prot = 19,
Start_Addr = 0,
End_Addr = 9,
Addr_Len = 8,
}
}
else static if( S == 8 )
{
enum Ofs
{
Write_Prot = 35,
Start_Addr = 0,
End_Addr = 9,
Addr_Len = 17,
}
}
else
{
static assert( false );
}
// %% this is wrong for 64-bit:
// uint strtoul(char *,char **,int);
if( s[Ofs.Write_Prot] == 'w' )
{
s[Ofs.Start_Addr + Ofs.Addr_Len] = '\0';
s[Ofs.End_Addr + Ofs.Addr_Len] = '\0';
start = cast(void*) strtoul(s + Ofs.Start_Addr, null, 16);
end = cast(void*) strtoul(s + Ofs.End_Addr, null, 16);
// 1. Exclude anything overlapping [dataStart, dataEnd)
// 2. Exclude stack
if ( ( !dataEnd ||
!( dataStart >= start && dataEnd <= end ) ) &&
!( &buf[0] >= start && &buf[0] < end ) )
{
// we already have static data from this region. anything else
// is heap (%% check)
debug (ProcMaps) printf("Adding map range %p 0%p\n", start, end);
_d_gc_add_range(start, end);
}
}
p++;
}
else
{
count = p - s;
memmove(buf.ptr, s, count);
p = buf.ptr + count;
break;
}
}
}
close(fd);
}
}
else version(linux)
{
dataStart = adjust_up( &Data_Start );
dataEnd = adjust_down( &Data_End );
}
else
{
static assert( false, "Operating system not supported." );
}
}

View File

@@ -0,0 +1,212 @@
// D programming language runtime library
// Public Domain
// written by Walter Bright, Digital Mars
// www.digitalmars.com
// This is written in C because nobody has written a pthreads interface
// to D yet.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#if _WIN32
#elif linux || __APPLE__
#define USE_PTHREADS 1
#else
#endif
#if _WIN32
#include <windows.h>
#endif
#if USE_PTHREADS
#include <pthread.h>
#endif
#include "mars.h"
// This is what the monitor reference in Object points to
typedef struct Monitor
{
void* impl; // for user-level monitors
Array devt; // for internal monitors
#if _WIN32
CRITICAL_SECTION mon;
#endif
#if USE_PTHREADS
pthread_mutex_t mon;
#endif
} Monitor;
#define MONPTR(h) (&((Monitor *)(h)->monitor)->mon)
static volatile int inited;
/* =============================== Win32 ============================ */
#if _WIN32
static CRITICAL_SECTION _monitor_critsec;
void _STI_monitor_staticctor()
{
if (!inited)
{ InitializeCriticalSection(&_monitor_critsec);
inited = 1;
}
}
void _STD_monitor_staticdtor()
{
if (inited)
{ inited = 0;
DeleteCriticalSection(&_monitor_critsec);
}
}
void _d_monitor_create(Object *h)
{
/*
* NOTE: Assume this is only called when h->monitor is null prior to the
* call. However, please note that another thread may call this function
* at the same time, so we can not assert this here. Instead, try and
* create a lock, and if one already exists then forget about it.
*/
//printf("+_d_monitor_create(%p)\n", h);
assert(h);
Monitor *cs = NULL;
EnterCriticalSection(&_monitor_critsec);
if (!h->monitor)
{
cs = (Monitor *)calloc(sizeof(Monitor), 1);
assert(cs);
InitializeCriticalSection(&cs->mon);
h->monitor = (void *)cs;
cs = NULL;
}
LeaveCriticalSection(&_monitor_critsec);
if (cs)
free(cs);
//printf("-_d_monitor_create(%p)\n", h);
}
void _d_monitor_destroy(Object *h)
{
//printf("+_d_monitor_destroy(%p)\n", h);
assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
DeleteCriticalSection(MONPTR(h));
free((void *)h->monitor);
h->monitor = NULL;
//printf("-_d_monitor_destroy(%p)\n", h);
}
int _d_monitor_lock(Object *h)
{
//printf("+_d_monitor_acquire(%p)\n", h);
assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
EnterCriticalSection(MONPTR(h));
//printf("-_d_monitor_acquire(%p)\n", h);
}
void _d_monitor_unlock(Object *h)
{
//printf("+_d_monitor_release(%p)\n", h);
assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
LeaveCriticalSection(MONPTR(h));
//printf("-_d_monitor_release(%p)\n", h);
}
#endif
/* =============================== linux ============================ */
#if USE_PTHREADS
#if !linux
#define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
#endif
// Includes attribute fixes from David Friedman's GDC port
static pthread_mutex_t _monitor_critsec;
static pthread_mutexattr_t _monitors_attr;
void _STI_monitor_staticctor()
{
if (!inited)
{
pthread_mutexattr_init(&_monitors_attr);
pthread_mutexattr_settype(&_monitors_attr, PTHREAD_MUTEX_RECURSIVE_NP);
pthread_mutex_init(&_monitor_critsec, 0);
inited = 1;
}
}
void _STD_monitor_staticdtor()
{
if (inited)
{ inited = 0;
pthread_mutex_destroy(&_monitor_critsec);
pthread_mutexattr_destroy(&_monitors_attr);
}
}
void _d_monitor_create(Object *h)
{
/*
* NOTE: Assume this is only called when h->monitor is null prior to the
* call. However, please note that another thread may call this function
* at the same time, so we can not assert this here. Instead, try and
* create a lock, and if one already exists then forget about it.
*/
//printf("+_d_monitor_create(%p)\n", h);
assert(h);
Monitor *cs = NULL;
pthread_mutex_lock(&_monitor_critsec);
if (!h->monitor)
{
cs = (Monitor *)calloc(sizeof(Monitor), 1);
assert(cs);
pthread_mutex_init(&cs->mon, & _monitors_attr);
h->monitor = (void *)cs;
cs = NULL;
}
pthread_mutex_unlock(&_monitor_critsec);
if (cs)
free(cs);
//printf("-_d_monitor_create(%p)\n", h);
}
void _d_monitor_destroy(Object *h)
{
//printf("+_d_monitor_destroy(%p)\n", h);
assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
pthread_mutex_destroy(MONPTR(h));
free((void *)h->monitor);
h->monitor = NULL;
//printf("-_d_monitor_destroy(%p)\n", h);
}
int _d_monitor_lock(Object *h)
{
//printf("+_d_monitor_acquire(%p)\n", h);
assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
pthread_mutex_lock(MONPTR(h));
//printf("-_d_monitor_acquire(%p)\n", h);
}
void _d_monitor_unlock(Object *h)
{
//printf("+_d_monitor_release(%p)\n", h);
assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
pthread_mutex_unlock(MONPTR(h));
//printf("-_d_monitor_release(%p)\n", h);
}
#endif

View File

@@ -0,0 +1,67 @@
/*
* Placed into Public Domain
* written by Walter Bright
* www.digitalmars.com
*
* This is a public domain version of qsort.d.
* All it does is call C's qsort(), but runs a little slower since
* it needs to synchronize a global variable.
*/
/*
* Modified by Sean Kelly <sean@f4.ca> for use with Tango.
*/
//debug=qsort;
version( D_Version2 )
private import stdlib = stdc.stdlib;
else
private import stdlib = tango.stdc.stdlib;
private TypeInfo tiglobal;
extern (C) int cmp(in void* p1, in void* p2)
{
return tiglobal.compare(p1, p2);
}
extern (C) void[] _adSort(void[] a, TypeInfo ti)
{
synchronized
{
tiglobal = ti;
stdlib.qsort(a.ptr, a.length, cast(size_t)ti.tsize(), &cmp);
}
return a;
}
unittest
{
debug(qsort) printf("array.sort.unittest()\n");
int a[] = new int[10];
a[0] = 23;
a[1] = 1;
a[2] = 64;
a[3] = 5;
a[4] = 6;
a[5] = 5;
a[6] = 17;
a[7] = 3;
a[8] = 0;
a[9] = -1;
a.sort;
for (int i = 0; i < a.length - 1; i++)
{
//printf("i = %d", i);
//printf(" %d %d\n", a[i], a[i + 1]);
assert(a[i] <= a[i + 1]);
}
}

Some files were not shown because too many files have changed in this diff Show More