reorganize files, fix wasm, good to go
This commit is contained in:
parent
83d09f6b49
commit
b0c0120fc4
4
build.sh
4
build.sh
@ -21,10 +21,10 @@ if [ -n "$wasm" ]; then
|
|||||||
|
|
||||||
cpp_compiler="clang++"
|
cpp_compiler="clang++"
|
||||||
c_compiler="clang"
|
c_compiler="clang"
|
||||||
flags="-target wasm32 -nostdlib -Wl,--no-entry -c -static -mbulk-memory -mbulk-memory-opt -matomics -msimd128 -mno-gc"
|
flags="-target wasm32 -nostdlib -c -static -mbulk-memory -mbulk-memory-opt -matomics -msimd128 -mno-gc"
|
||||||
files="${ext_path}/tinyalloc/tinyalloc.c"
|
files="${ext_path}/tinyalloc/tinyalloc.c"
|
||||||
includes="-I${ext_path}/tinyalloc"
|
includes="-I${ext_path}/tinyalloc"
|
||||||
out=""
|
out="-obuild/dlibincludes.wasm"
|
||||||
|
|
||||||
$c_compiler $flags $includes $files $out
|
$c_compiler $flags $includes $files $out
|
||||||
else
|
else
|
||||||
|
|||||||
@ -39,9 +39,7 @@ alias f64 = double;
|
|||||||
|
|
||||||
alias b32 = uint;
|
alias b32 = uint;
|
||||||
|
|
||||||
alias intptr = i64;
|
alias uintptr = size_t;
|
||||||
alias uintptr = u64;
|
|
||||||
|
|
||||||
alias usize = size_t;
|
alias usize = size_t;
|
||||||
|
|
||||||
alias Vec2 = Vector!(f32, 2);
|
alias Vec2 = Vector!(f32, 2);
|
||||||
@ -72,6 +72,12 @@ WasmGrow(u32 size)
|
|||||||
return grow(0, size);
|
return grow(0, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern(C) u32
|
||||||
|
WasmGrow2(u32 index, u32 size)
|
||||||
|
{
|
||||||
|
return grow(0, size);
|
||||||
|
}
|
||||||
|
|
||||||
extern(C) u32
|
extern(C) u32
|
||||||
WasmSize()
|
WasmSize()
|
||||||
{
|
{
|
||||||
@ -5,7 +5,7 @@ import dlib.util;
|
|||||||
|
|
||||||
import std.traits;
|
import std.traits;
|
||||||
import std.math.traits;
|
import std.math.traits;
|
||||||
import std.meta;
|
import core.internal.traits : allSatisfy;
|
||||||
|
|
||||||
public import std.math.rounding : round;
|
public import std.math.rounding : round;
|
||||||
public import core.math : sqrt, cos, sin;
|
public import core.math : sqrt, cos, sin;
|
||||||
@ -815,7 +815,7 @@ align(16) struct Matrix(T, int D)
|
|||||||
|
|
||||||
this(U...)(U values)
|
this(U...)(U values)
|
||||||
{
|
{
|
||||||
static if((U.length == N) && allSatisfy!(IsTypeAssignable, U))
|
static if((U.length == N) && (allSatisfy!(IsTypeAssignable, U) || allSatisfy!(isFloatingPoint, U)))
|
||||||
{
|
{
|
||||||
static foreach(i, x; values)
|
static foreach(i, x; values)
|
||||||
{
|
{
|
||||||
@ -11,7 +11,28 @@ public import dlib.externdecl;
|
|||||||
|
|
||||||
version(WebAssembly)
|
version(WebAssembly)
|
||||||
{
|
{
|
||||||
|
version(unittest)
|
||||||
|
{
|
||||||
|
extern(C) void _start()
|
||||||
|
{
|
||||||
|
import wasm;
|
||||||
|
import std.format;
|
||||||
|
|
||||||
|
char[512] buffer;
|
||||||
|
u32[5] arr = [3, 55, 123, 528, 3943];
|
||||||
|
string str = Str(sformat(buffer, "Nigger %s pppp %s", "faggot", arr));
|
||||||
|
|
||||||
|
Console(str, true);
|
||||||
|
|
||||||
|
static foreach(test_fn; __traits(getUnitTests, __traits(parent, _start)))
|
||||||
|
{
|
||||||
|
test_fn();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Console("success", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -12,7 +12,7 @@ import core.stdc.string;
|
|||||||
static if(NativeTarget)
|
static if(NativeTarget)
|
||||||
{
|
{
|
||||||
import std.format : sformat;
|
import std.format : sformat;
|
||||||
import std.stdio : write, writeln, writef, writefln, stderr;
|
import std.stdio : writeln, writef, writefln;
|
||||||
import dlib.platform;
|
import dlib.platform;
|
||||||
}
|
}
|
||||||
|
|
||||||
224
external/arsd-webassembly/arsd/color.d
vendored
224
external/arsd-webassembly/arsd/color.d
vendored
@ -1,224 +0,0 @@
|
|||||||
module arsd.color;
|
|
||||||
|
|
||||||
char toHex(int a) {
|
|
||||||
if(a < 10)
|
|
||||||
return cast(char) (a + '0');
|
|
||||||
else
|
|
||||||
return cast(char) (a - 10 + 'a');
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Color {
|
|
||||||
int r, g, b, a;
|
|
||||||
this(int r, int g, int b, int a = 255) {
|
|
||||||
this.r = r;
|
|
||||||
this.g = g;
|
|
||||||
this.b = b;
|
|
||||||
this.a = a;
|
|
||||||
}
|
|
||||||
|
|
||||||
void toTempString(char[] data) {
|
|
||||||
data[0] = '#';
|
|
||||||
data[1] = toHex(r >> 4);
|
|
||||||
data[2] = toHex(r & 0x0f);
|
|
||||||
data[3] = toHex(g >> 4);
|
|
||||||
data[4] = toHex(g & 0x0f);
|
|
||||||
data[5] = toHex(b >> 4);
|
|
||||||
data[6] = toHex(b & 0x0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Color fromHsl(double h, double s, double l, double a = 255) {
|
|
||||||
h = h % 360;
|
|
||||||
|
|
||||||
double C = (1 - absInternal(2 * l - 1)) * s;
|
|
||||||
|
|
||||||
double hPrime = h / 60;
|
|
||||||
|
|
||||||
double X = C * (1 - absInternal(hPrime % 2 - 1));
|
|
||||||
|
|
||||||
double r, g, b;
|
|
||||||
|
|
||||||
if(h is double.nan)
|
|
||||||
r = g = b = 0;
|
|
||||||
else if (hPrime >= 0 && hPrime < 1) {
|
|
||||||
r = C;
|
|
||||||
g = X;
|
|
||||||
b = 0;
|
|
||||||
} else if (hPrime >= 1 && hPrime < 2) {
|
|
||||||
r = X;
|
|
||||||
g = C;
|
|
||||||
b = 0;
|
|
||||||
} else if (hPrime >= 2 && hPrime < 3) {
|
|
||||||
r = 0;
|
|
||||||
g = C;
|
|
||||||
b = X;
|
|
||||||
} else if (hPrime >= 3 && hPrime < 4) {
|
|
||||||
r = 0;
|
|
||||||
g = X;
|
|
||||||
b = C;
|
|
||||||
} else if (hPrime >= 4 && hPrime < 5) {
|
|
||||||
r = X;
|
|
||||||
g = 0;
|
|
||||||
b = C;
|
|
||||||
} else if (hPrime >= 5 && hPrime < 6) {
|
|
||||||
r = C;
|
|
||||||
g = 0;
|
|
||||||
b = X;
|
|
||||||
}
|
|
||||||
|
|
||||||
double m = l - C / 2;
|
|
||||||
|
|
||||||
r += m;
|
|
||||||
g += m;
|
|
||||||
b += m;
|
|
||||||
|
|
||||||
return Color(
|
|
||||||
cast(int)(r * 255),
|
|
||||||
cast(int)(g * 255),
|
|
||||||
cast(int)(b * 255),
|
|
||||||
cast(int)(a));
|
|
||||||
}
|
|
||||||
|
|
||||||
static immutable Color white = Color(255, 255, 255, 255);
|
|
||||||
static immutable Color black = Color(0, 0, 0, 255);
|
|
||||||
static immutable Color red = Color(255, 0, 0, 255);
|
|
||||||
static immutable Color blue = Color(0, 0, 255, 255);
|
|
||||||
static immutable Color green = Color(0, 255, 0, 255);
|
|
||||||
static immutable Color yellow = Color(255, 255, 0, 255);
|
|
||||||
static immutable Color teal = Color(0, 255, 255, 255);
|
|
||||||
static immutable Color purple = Color(255, 0, 255, 255);
|
|
||||||
static immutable Color gray = Color(127, 127, 127, 255);
|
|
||||||
static immutable Color transparent = Color(0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Point {
|
|
||||||
int x;
|
|
||||||
int y;
|
|
||||||
|
|
||||||
pure const nothrow @safe:
|
|
||||||
|
|
||||||
Point opBinary(string op)(in Point rhs) @nogc {
|
|
||||||
return Point(mixin("x" ~ op ~ "rhs.x"), mixin("y" ~ op ~ "rhs.y"));
|
|
||||||
}
|
|
||||||
|
|
||||||
Point opBinary(string op)(int rhs) @nogc {
|
|
||||||
return Point(mixin("x" ~ op ~ "rhs"), mixin("y" ~ op ~ "rhs"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Size {
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
nothrow @safe @nogc pure
|
|
||||||
double absInternal(double a) { return a < 0 ? -a : a; }
|
|
||||||
|
|
||||||
struct Rectangle {
|
|
||||||
int left; ///
|
|
||||||
int top; ///
|
|
||||||
int right; ///
|
|
||||||
int bottom; ///
|
|
||||||
|
|
||||||
pure const nothrow @safe @nogc:
|
|
||||||
|
|
||||||
///
|
|
||||||
this(int left, int top, int right, int bottom) {
|
|
||||||
this.left = left;
|
|
||||||
this.top = top;
|
|
||||||
this.right = right;
|
|
||||||
this.bottom = bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
this(in Point upperLeft, in Point lowerRight) {
|
|
||||||
this(upperLeft.x, upperLeft.y, lowerRight.x, lowerRight.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
this(in Point upperLeft, in Size size) {
|
|
||||||
this(upperLeft.x, upperLeft.y, upperLeft.x + size.width, upperLeft.y + size.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
@property Point upperLeft() {
|
|
||||||
return Point(left, top);
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
@property Point upperRight() {
|
|
||||||
return Point(right, top);
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
@property Point lowerLeft() {
|
|
||||||
return Point(left, bottom);
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
@property Point lowerRight() {
|
|
||||||
return Point(right, bottom);
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
@property Point center() {
|
|
||||||
return Point((right + left) / 2, (bottom + top) / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
@property Size size() {
|
|
||||||
return Size(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
@property int width() {
|
|
||||||
return right - left;
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
@property int height() {
|
|
||||||
return bottom - top;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if this rectangle entirely contains the other
|
|
||||||
bool contains(in Rectangle r) {
|
|
||||||
return contains(r.upperLeft) && contains(r.lowerRight);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ditto
|
|
||||||
bool contains(in Point p) {
|
|
||||||
return (p.x >= left && p.x < right && p.y >= top && p.y < bottom);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true of the two rectangles at any point overlap
|
|
||||||
bool overlaps(in Rectangle r) {
|
|
||||||
// the -1 in here are because right and top are exclusive
|
|
||||||
return !((right-1) < r.left || (r.right-1) < left || (bottom-1) < r.top || (r.bottom-1) < top);
|
|
||||||
}
|
|
||||||
|
|
||||||
/++
|
|
||||||
Returns a Rectangle representing the intersection of this and the other given one.
|
|
||||||
|
|
||||||
History:
|
|
||||||
Added July 1, 2021
|
|
||||||
+/
|
|
||||||
Rectangle intersectionOf(in Rectangle r) {
|
|
||||||
auto tmp = Rectangle(max(left, r.left), max(top, r.top), min(right, r.right), min(bottom, r.bottom));
|
|
||||||
if(tmp.left >= tmp.right || tmp.top >= tmp.bottom)
|
|
||||||
tmp = Rectangle.init;
|
|
||||||
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int max(int a, int b) @nogc nothrow pure @safe {
|
|
||||||
return a >= b ? a : b;
|
|
||||||
}
|
|
||||||
private int min(int a, int b) @nogc nothrow pure @safe {
|
|
||||||
return a <= b ? a : b;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
enum arsd_jsvar_compatible = "arsd_jsvar_compatible";
|
|
||||||
class MemoryImage {}
|
|
||||||
8
external/arsd-webassembly/arsd/simpleaudio.d
vendored
8
external/arsd-webassembly/arsd/simpleaudio.d
vendored
@ -1,8 +0,0 @@
|
|||||||
module arsd.simpleaudio;
|
|
||||||
|
|
||||||
struct AudioOutputThread {
|
|
||||||
this(int) {}
|
|
||||||
void start() {}
|
|
||||||
void beep(int = 0) {}
|
|
||||||
void boop(int = 0) {}
|
|
||||||
}
|
|
||||||
315
external/arsd-webassembly/arsd/simpledisplay.d
vendored
315
external/arsd-webassembly/arsd/simpledisplay.d
vendored
@ -1,315 +0,0 @@
|
|||||||
module arsd.simpledisplay;
|
|
||||||
|
|
||||||
public import arsd.color;
|
|
||||||
|
|
||||||
import arsd.webassembly;
|
|
||||||
|
|
||||||
//shared static this() { eval("hi there"); }
|
|
||||||
|
|
||||||
// the js bridge is SO EXPENSIVE we have to minimize using it.
|
|
||||||
|
|
||||||
class SimpleWindow {
|
|
||||||
this(int width, int height, string title = "D Application") {
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
|
|
||||||
element = eval!NativeHandle(q{
|
|
||||||
var s = document.getElementById("screen");
|
|
||||||
var canvas = document.createElement("canvas");
|
|
||||||
canvas.addEventListener("contextmenu", function(event) { event.preventDefault(); });
|
|
||||||
canvas.setAttribute("width", $0);
|
|
||||||
canvas.setAttribute("height", $1);
|
|
||||||
canvas.setAttribute("title", $2);
|
|
||||||
s.appendChild(canvas);
|
|
||||||
return canvas;
|
|
||||||
}, width, height, title);
|
|
||||||
|
|
||||||
canvasContext = eval!NativeHandle(q{
|
|
||||||
return $0.getContext("2d");
|
|
||||||
}, element);
|
|
||||||
}
|
|
||||||
|
|
||||||
NativeHandle element;
|
|
||||||
NativeHandle canvasContext;
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
|
|
||||||
void close() {
|
|
||||||
eval(q{ clearInterval($0); }, intervalId);
|
|
||||||
intervalId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void delegate() onClosing;
|
|
||||||
|
|
||||||
ScreenPainter draw() {
|
|
||||||
return ScreenPainter(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
int intervalId;
|
|
||||||
|
|
||||||
void eventLoop(T...)(int timeout, T t) {
|
|
||||||
foreach(arg; t) {
|
|
||||||
static if(is(typeof(arg) : void delegate())) {
|
|
||||||
sdpy_timer = arg;
|
|
||||||
} else static if(is(typeof(arg) : void delegate(KeyEvent))) {
|
|
||||||
sdpy_key = arg;
|
|
||||||
} else static if(is(typeof(arg) : void delegate(MouseEvent))) {
|
|
||||||
sdpy_mouse = arg;
|
|
||||||
} else static assert(0, typeof(arg).stringof);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(timeout)
|
|
||||||
intervalId = eval!int(q{
|
|
||||||
return setInterval(function(a) { exports.sdpy_timer_trigger(); }, $0);
|
|
||||||
}, timeout);
|
|
||||||
|
|
||||||
eval(q{
|
|
||||||
function translate(key) {
|
|
||||||
var k = 0;
|
|
||||||
switch(key) {
|
|
||||||
case "[": k = 1; break;
|
|
||||||
case "]": k = 2; break;
|
|
||||||
case "Left": case "ArrowLeft": k = 3; break;
|
|
||||||
case "Right": case "ArrowRight": k = 4; break;
|
|
||||||
case "Down": case "ArrowDown": k = 5; break;
|
|
||||||
case "Up": case "ArrowUp": k = 6; break;
|
|
||||||
case " ": k = 7; break;
|
|
||||||
// "Enter", "Esc" / "Escape"
|
|
||||||
default: k = 0;
|
|
||||||
}
|
|
||||||
return k;
|
|
||||||
}
|
|
||||||
document.body.addEventListener("keydown", function(event) {
|
|
||||||
exports.sdpy_key_trigger(1, translate(event.key));
|
|
||||||
event.preventDefault();
|
|
||||||
}, true);
|
|
||||||
document.body.addEventListener("keyup", function(event) {
|
|
||||||
exports.sdpy_key_trigger(0, translate(event.key));
|
|
||||||
event.preventDefault();
|
|
||||||
}, true);
|
|
||||||
$0.addEventListener("mousedown", function(event) {
|
|
||||||
exports.sdpy_mouse_trigger(1, event.button, event.offsetX, event.offsetY);
|
|
||||||
}, true);
|
|
||||||
$0.addEventListener("mouseup", function(event) {
|
|
||||||
exports.sdpy_mouse_trigger(0, event.button);
|
|
||||||
}, true);
|
|
||||||
}, element);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void delegate() sdpy_timer;
|
|
||||||
void delegate(KeyEvent) sdpy_key;
|
|
||||||
void delegate(MouseEvent) sdpy_mouse;
|
|
||||||
|
|
||||||
export extern(C) void sdpy_timer_trigger() {
|
|
||||||
sdpy_timer();
|
|
||||||
}
|
|
||||||
export extern(C) void sdpy_key_trigger(int pressed, int key) {
|
|
||||||
KeyEvent ke;
|
|
||||||
ke.pressed = pressed ? true : false;
|
|
||||||
ke.key = key;
|
|
||||||
if(sdpy_key)
|
|
||||||
sdpy_key(ke);
|
|
||||||
}
|
|
||||||
export extern(C) void sdpy_mouse_trigger(int pressed, int button, int x, int y) {
|
|
||||||
MouseEvent me;
|
|
||||||
me.type = pressed ? MouseEventType.buttonPressed : MouseEventType.buttonReleased;
|
|
||||||
switch(button) {
|
|
||||||
case 0:
|
|
||||||
me.button = MouseButton.left;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
me.button = MouseButton.middle;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
me.button = MouseButton.right;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
me.x = x;
|
|
||||||
me.y = y;
|
|
||||||
if(sdpy_mouse)
|
|
||||||
sdpy_mouse(me);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// push arguments in reverse order then push the command
|
|
||||||
enum canvasRender = q{
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ScreenPainter {
|
|
||||||
this(SimpleWindow window) {
|
|
||||||
// no need to arc here tbh
|
|
||||||
this.w = window.width;
|
|
||||||
this.h = window.height;
|
|
||||||
|
|
||||||
this.element = NativeHandle(window.element.handle, false);
|
|
||||||
this.context = NativeHandle(window.canvasContext.handle, false);
|
|
||||||
}
|
|
||||||
@disable this(this); // for now...
|
|
||||||
NativeHandle element;
|
|
||||||
NativeHandle context;
|
|
||||||
|
|
||||||
private int w, h;
|
|
||||||
|
|
||||||
void clear() {
|
|
||||||
addCommand(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void outlineColor(Color c) {
|
|
||||||
char[7] data;
|
|
||||||
c.toTempString(data[]);
|
|
||||||
addCommand(2, 7, data[0], data[1], data[2], data[3], data[4], data[5], data[6]);
|
|
||||||
return;
|
|
||||||
//context.properties.strokeStyle!string = cast(immutable)(data[]);
|
|
||||||
}
|
|
||||||
void fillColor(Color c) {
|
|
||||||
char[7] data;
|
|
||||||
c.toTempString(data[]);
|
|
||||||
addCommand(3, 7, data[0], data[1], data[2], data[3], data[4], data[5], data[6]);
|
|
||||||
return;
|
|
||||||
//context.properties.fillStyle!string = cast(immutable)(data[]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawPolygon(Point[] points) {
|
|
||||||
addCommand(8);
|
|
||||||
addCommand(cast(double) points.length);
|
|
||||||
foreach(point; points) {
|
|
||||||
push(cast(double) point.x);
|
|
||||||
push(cast(double) point.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawRectangle(Point p, int w, int h) {
|
|
||||||
addCommand(4, p.x, p.y, w, h);
|
|
||||||
}
|
|
||||||
void drawRectangle(Point p, Size s) {
|
|
||||||
drawRectangle(p, s.width, s.height);
|
|
||||||
}
|
|
||||||
void drawText(Point p, in char[] txt, Point lowerRight = Point(0, 0), uint alignment = 0) {
|
|
||||||
// FIXME use the new system
|
|
||||||
addCommand(5, p.x, p.y + 16, txt.length);
|
|
||||||
foreach(c; txt)
|
|
||||||
push(cast(double) c);
|
|
||||||
return;
|
|
||||||
eval(q{
|
|
||||||
var context = $0;
|
|
||||||
context.font = "18px sans-serif";
|
|
||||||
context.strokeText($1, $2, $3 + 16);
|
|
||||||
}, context, txt, p.x, p.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawCircle(Point upperLeft, int diameter) {
|
|
||||||
addCommand(6, upperLeft.x + diameter / 2, upperLeft.y + diameter / 2, diameter / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawLine(Point p1, Point p2) {
|
|
||||||
drawLine(p1.x, p1.y, p2.x, p2.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawLine(int x1, int y1, int x2, int y2) {
|
|
||||||
addCommand(7, x1, y1, x2, y2);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void addCommand(T...)(int cmd, T args) {
|
|
||||||
push(cmd);
|
|
||||||
foreach(arg; args) {
|
|
||||||
push(arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 50ish % on ronaroids total cpu without this
|
|
||||||
// with it, we at like 16%
|
|
||||||
static __gshared double[] commandStack;
|
|
||||||
size_t commandStackPosition;
|
|
||||||
|
|
||||||
void push(T)(T t) {
|
|
||||||
if(commandStackPosition == commandStack.length) {
|
|
||||||
commandStack.length = commandStack.length + 1024;
|
|
||||||
commandStack.assumeUniqueReference();
|
|
||||||
}
|
|
||||||
|
|
||||||
commandStack[commandStackPosition++] = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
~this() {
|
|
||||||
executeCanvasCommands(this.context.handle, this.commandStack.ptr, commandStackPosition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern(C) void executeCanvasCommands(int handle, double* start, size_t len);
|
|
||||||
|
|
||||||
struct KeyEvent {
|
|
||||||
int key;
|
|
||||||
bool pressed;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum MouseEventType : int {
|
|
||||||
motion = 0, /// The mouse moved inside the window
|
|
||||||
buttonPressed = 1, /// A mouse button was pressed or the wheel was spun
|
|
||||||
buttonReleased = 2, /// A mouse button was released
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MouseEvent {
|
|
||||||
MouseEventType type;
|
|
||||||
int x;
|
|
||||||
int y;
|
|
||||||
int dx;
|
|
||||||
int dy;
|
|
||||||
|
|
||||||
MouseButton button;
|
|
||||||
int modifierState;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum MouseButton : int {
|
|
||||||
none = 0,
|
|
||||||
left = 1, ///
|
|
||||||
right = 2, ///
|
|
||||||
middle = 4, ///
|
|
||||||
wheelUp = 8, ///
|
|
||||||
wheelDown = 16, ///
|
|
||||||
backButton = 32, /// often found on the thumb and used for back in browsers
|
|
||||||
forwardButton = 64, /// often found on the thumb and used for forward in browsers
|
|
||||||
}
|
|
||||||
|
|
||||||
enum TextAlignment : uint {
|
|
||||||
Left = 0, ///
|
|
||||||
Center = 1, ///
|
|
||||||
Right = 2, ///
|
|
||||||
|
|
||||||
VerticalTop = 0, ///
|
|
||||||
VerticalCenter = 4, ///
|
|
||||||
VerticalBottom = 8, ///
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Key {
|
|
||||||
LeftBracket = 1,
|
|
||||||
RightBracket,
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
Down,
|
|
||||||
Up,
|
|
||||||
Space
|
|
||||||
}
|
|
||||||
|
|
||||||
enum MouseCursor { cross }
|
|
||||||
|
|
||||||
class OperatingSystemFont {}
|
|
||||||
enum UsingSimpledisplayX11 = false;
|
|
||||||
enum SimpledisplayTimerAvailable = false;
|
|
||||||
|
|
||||||
|
|
||||||
class Sprite{}
|
|
||||||
|
|
||||||
enum bool OpenGlEnabled = false;
|
|
||||||
|
|
||||||
alias ScreenPainterImplementation = ScreenPainter;
|
|
||||||
|
|
||||||
mixin template ExperimentalTextComponent() {
|
|
||||||
class TextLayout {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
178
external/arsd-webassembly/arsd/webassembly.d
vendored
178
external/arsd-webassembly/arsd/webassembly.d
vendored
@ -1,178 +0,0 @@
|
|||||||
/+
|
|
||||||
This is the D interface to my webassembly javascript bridge.
|
|
||||||
+/
|
|
||||||
module arsd.webassembly;
|
|
||||||
|
|
||||||
struct AcquireArgument {
|
|
||||||
int type;
|
|
||||||
const(void)* ptr;
|
|
||||||
int length;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the basic bridge functions defined in webassembly-core.js {
|
|
||||||
|
|
||||||
@trusted @nogc pure nothrow
|
|
||||||
{
|
|
||||||
extern(C) void retain(int);
|
|
||||||
extern(C) void release(int);
|
|
||||||
extern(C) int acquire(int returnType, string callingModuleName, string code, AcquireArgument[] arguments);
|
|
||||||
extern(C) void abort();
|
|
||||||
extern(C) int monotimeNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
export extern(C) int invoke_d_array_delegate(size_t ptr, size_t funcptr, ubyte[] arg) {
|
|
||||||
void delegate(in ubyte[] arr) dg;
|
|
||||||
|
|
||||||
dg.ptr = cast(void*) ptr;
|
|
||||||
dg.funcptr = cast(typeof(dg.funcptr)) funcptr;
|
|
||||||
|
|
||||||
dg(arg);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/++
|
|
||||||
Evaluates the given code in Javascript. The arguments are available in JS as $0, $1, $2, ....
|
|
||||||
The `this` object in the evaluated code is set to an object representing the D module that
|
|
||||||
you can store some stuff in across calls without having to hit the global namespace.
|
|
||||||
|
|
||||||
Note that if you want to return a value from javascript, you MUST use the return keyword
|
|
||||||
in the script string.
|
|
||||||
|
|
||||||
Wrong: `eval!NativeHandle("document");`
|
|
||||||
|
|
||||||
Right: `eval!NativeHandle("return document");`
|
|
||||||
+/
|
|
||||||
template eval(T = void) {
|
|
||||||
T eval(Args...)(string code, Args args, string callingModuleName = __MODULE__) @trusted @nogc pure {
|
|
||||||
AcquireArgument[Args.length] aa;
|
|
||||||
foreach(idx, ref arg; args) {
|
|
||||||
// FIXME: some other type for unsigned....
|
|
||||||
static if(is(typeof(arg) : const int)) {
|
|
||||||
aa[idx].type = 0;
|
|
||||||
aa[idx].ptr = cast(void*) arg;
|
|
||||||
aa[idx].length = arg.sizeof;
|
|
||||||
} else static if(is(immutable typeof(arg) == immutable string)) {
|
|
||||||
aa[idx].type = 1;
|
|
||||||
aa[idx].ptr = arg.ptr;
|
|
||||||
aa[idx].length = arg.length;
|
|
||||||
} else static if(is(immutable typeof(arg) == immutable NativeHandle)) {
|
|
||||||
aa[idx].type = 2;
|
|
||||||
aa[idx].ptr = cast(void*) arg.handle;
|
|
||||||
aa[idx].length = NativeHandle.sizeof;
|
|
||||||
} else static if(is(typeof(arg) : const float)) {
|
|
||||||
aa[idx].type = 3;
|
|
||||||
aa[idx].ptr = cast(void*) &arg;
|
|
||||||
aa[idx].length = arg.sizeof;
|
|
||||||
} else static if(is(immutable typeof(arg) == immutable ubyte[])) {
|
|
||||||
aa[idx].type = 4;
|
|
||||||
aa[idx].ptr = arg.ptr;
|
|
||||||
aa[idx].length = arg.length;
|
|
||||||
/*
|
|
||||||
} else static if(is(typeof(arg) == delegate)) {
|
|
||||||
aa[idx].type = 5;
|
|
||||||
aa[idx].ptr = cast(void*) &arg;
|
|
||||||
aa[idx].length = arg.sizeof;
|
|
||||||
*/
|
|
||||||
} else {
|
|
||||||
static assert(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static if(is(T == void))
|
|
||||||
acquire(0, callingModuleName, code, aa[]);
|
|
||||||
else static if(is(T == int))
|
|
||||||
return acquire(1, callingModuleName, code, aa[]);
|
|
||||||
else static if(is(T == float))
|
|
||||||
return *cast(float*) cast(void*) acquire(2, callingModuleName, code, aa[]);
|
|
||||||
else static if(is(T == NativeHandle))
|
|
||||||
return NativeHandle(acquire(3, callingModuleName, code, aa[]));
|
|
||||||
else static if(is(T == string)) {
|
|
||||||
auto ptr = cast(int*) acquire(7, callingModuleName, code, aa[]);
|
|
||||||
auto len = *ptr;
|
|
||||||
ptr++;
|
|
||||||
return (cast(immutable(char)*) ptr)[0 .. len];
|
|
||||||
}
|
|
||||||
else static assert(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// and do some opDispatch on the native things to call their methods and it should look p cool
|
|
||||||
|
|
||||||
struct NativeHandle {
|
|
||||||
@trusted @nogc pure:
|
|
||||||
|
|
||||||
int handle;
|
|
||||||
bool arc;
|
|
||||||
this(int handle, bool arc = true) {
|
|
||||||
this.handle = handle;
|
|
||||||
this.arc = arc;
|
|
||||||
}
|
|
||||||
|
|
||||||
this(this) {
|
|
||||||
if(arc) retain(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
~this() {
|
|
||||||
if(arc) release(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
// never store these, they don't affect the refcount
|
|
||||||
PropertiesHelper properties() {
|
|
||||||
return PropertiesHelper(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
// never store these, they don't affect the refcount
|
|
||||||
MethodsHelper methods() {
|
|
||||||
return MethodsHelper(handle);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MethodsHelper {
|
|
||||||
@trusted @nogc pure:
|
|
||||||
@disable this();
|
|
||||||
@disable this(this);
|
|
||||||
|
|
||||||
int handle;
|
|
||||||
private this(int handle) { this.handle = handle; }
|
|
||||||
|
|
||||||
template opDispatch(string name) {
|
|
||||||
template opDispatch(T = NativeHandle)
|
|
||||||
{
|
|
||||||
T opDispatch(Args...)(Args args, string callingModuleName = __MODULE__) @trusted @nogc pure
|
|
||||||
{
|
|
||||||
return eval!T(q{
|
|
||||||
return $0[$1].apply($0, Array.prototype.slice.call(arguments, 2));
|
|
||||||
}, NativeHandle(this.handle, false), name, args, callingModuleName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
struct PropertiesHelper {
|
|
||||||
@trusted @nogc pure:
|
|
||||||
@disable this();
|
|
||||||
@disable this(this);
|
|
||||||
|
|
||||||
int handle;
|
|
||||||
private this(int handle) { this.handle = handle; }
|
|
||||||
|
|
||||||
template opDispatch(string name) {
|
|
||||||
template opDispatch(T = NativeHandle) {
|
|
||||||
T opDispatch() {
|
|
||||||
return eval!T(q{
|
|
||||||
return $0[$1];
|
|
||||||
}, NativeHandle(this.handle, false), name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void opDispatch(T value) {
|
|
||||||
return eval!void(q{
|
|
||||||
return $0[$1] = $2;
|
|
||||||
}, NativeHandle(this.handle, false), name, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
17
external/arsd-webassembly/std/stdio.d
vendored
17
external/arsd-webassembly/std/stdio.d
vendored
@ -1,17 +0,0 @@
|
|||||||
module std.stdio;
|
|
||||||
|
|
||||||
import arsd.webassembly;
|
|
||||||
|
|
||||||
void writeln(T...)(T t) {
|
|
||||||
eval(q{
|
|
||||||
var str = "";
|
|
||||||
for(var i = 0; i < arguments.length; i++)
|
|
||||||
str += arguments[i];
|
|
||||||
|
|
||||||
str += "\n";
|
|
||||||
|
|
||||||
var txt = document.createTextNode(str);
|
|
||||||
var fd = document.getElementById("stdout");
|
|
||||||
fd.appendChild(txt);
|
|
||||||
}, t);
|
|
||||||
}
|
|
||||||
0
wasm.d → external/wasmbuild.c
vendored
0
wasm.d → external/wasmbuild.c
vendored
11
test.sh
11
test.sh
@ -2,16 +2,19 @@
|
|||||||
|
|
||||||
name="Test_Runner"
|
name="Test_Runner"
|
||||||
|
|
||||||
shared_src="package.d platform.d fonts.d aliases.d math.d util.d alloc.d assets.d external.d"
|
shared_src="dlib/package.d dlib/platform.d dlib/fonts.d dlib/aliases.d dlib/math.d dlib/util.d dlib/alloc.d dlib/assets.d dlib/externdecl.d"
|
||||||
|
|
||||||
if [ "$1" == "wasm" ]; then
|
if [ "$1" == "wasm" ]; then
|
||||||
flags="-c -mtriple=wasm32-unknown-unknown-wasm --Xcc=-DBUILD_WASM -Iexternal/arsd-webassembly -L--no-entry -L--allow-undefined -i=core -i=std -i=. --of=build/dlibmain.wasm --d-version=inline_concat -verrors=90"
|
flags="-c -vgc -mtriple=wasm32-unknown-unknown-wasm -fvisibility=public -dllimport=all --unittest --Xcc=-DBUILD_WASM -Iwasm/runtime -L--no-entry -i=core -i=std -i=. -g --real-precision=double --of=build/dlibmain.wasm --d-version=inline_concat -verrors=90"
|
||||||
|
wasm_src="wasm/runtime/object.d"
|
||||||
|
|
||||||
/bin/bash ./build.sh build wasm
|
/bin/bash ./build.sh build wasm
|
||||||
|
|
||||||
ldc2 $flags $shared_src external/arsd-webassembly/object.d external/arsd-webassembly/core/stdc/string.d
|
ldc2 $flags $shared_src $wasm_src
|
||||||
|
|
||||||
wasm-ld "build/dlibmain.wasm build/dlibincludes.wasm -obuild/dlib.wasm"
|
wasm-ld build/dlibmain.wasm build/dlibincludes.wasm --error-limit=0 --export-memory -obuild/dlib.wasm
|
||||||
|
|
||||||
|
cp build/dlib.wasm wasm/dlib.wasm
|
||||||
else
|
else
|
||||||
flags="-P-I/usr/include/freetype2 -L-lfreetype --main --unittest -g --of=$name"
|
flags="-P-I/usr/include/freetype2 -L-lfreetype --main --unittest -g --of=$name"
|
||||||
|
|
||||||
|
|||||||
BIN
tinyalloc.o
BIN
tinyalloc.o
Binary file not shown.
BIN
wasm/dlib.wasm
Executable file
BIN
wasm/dlib.wasm
Executable file
Binary file not shown.
BIN
wasm/dlibmain.wasm
Normal file
BIN
wasm/dlibmain.wasm
Normal file
Binary file not shown.
12
wasm/index.html
Normal file
12
wasm/index.html
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body style="background-color: black; color: white;">
|
||||||
|
Test page
|
||||||
|
</body>
|
||||||
|
<script type="text/javascript" src="./wasm.js"></script>
|
||||||
|
<script>
|
||||||
|
StartWasm("./dlib.wasm");
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
83
wasm/runtime/core/checkedint.d
Normal file
83
wasm/runtime/core/checkedint.d
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
module core.checkedint;
|
||||||
|
|
||||||
|
version(LDC)
|
||||||
|
{
|
||||||
|
import ldc.intrinsics;
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma(inline, true)
|
||||||
|
uint addu()(uint x, uint y, ref bool overflow)
|
||||||
|
{
|
||||||
|
version (LDC)
|
||||||
|
{
|
||||||
|
if (!__ctfe)
|
||||||
|
{
|
||||||
|
auto res = llvm_uadd_with_overflow(x, y);
|
||||||
|
overflow |= res.overflow;
|
||||||
|
return res.result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
immutable uint r = x + y;
|
||||||
|
immutable bool o = r < x;
|
||||||
|
assert(o == (r < y));
|
||||||
|
if (o)
|
||||||
|
overflow = true;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint mulu()(uint x, uint y, ref bool overflow)
|
||||||
|
{
|
||||||
|
version (D_InlineAsm_X86) enum useAsm = true;
|
||||||
|
else version (D_InlineAsm_X86_64) enum useAsm = true;
|
||||||
|
else enum useAsm = false;
|
||||||
|
|
||||||
|
version (LDC)
|
||||||
|
{
|
||||||
|
if (!__ctfe)
|
||||||
|
{
|
||||||
|
auto res = llvm_umul_with_overflow(x, y);
|
||||||
|
overflow |= res.overflow;
|
||||||
|
return res.result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else static if (useAsm)
|
||||||
|
{
|
||||||
|
if (!__ctfe)
|
||||||
|
{
|
||||||
|
uint r;
|
||||||
|
bool o;
|
||||||
|
asm pure nothrow @nogc @trusted
|
||||||
|
{
|
||||||
|
mov EAX, x;
|
||||||
|
mul y; // EDX:EAX = EAX * y
|
||||||
|
mov r, EAX;
|
||||||
|
setc o;
|
||||||
|
}
|
||||||
|
overflow |= o;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
immutable ulong r = ulong(x) * ulong(y);
|
||||||
|
if (r >> 32)
|
||||||
|
overflow = true;
|
||||||
|
return cast(uint) r;
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma(inline, true)
|
||||||
|
int adds()(int x, int y, ref bool overflow)
|
||||||
|
{
|
||||||
|
version (LDC)
|
||||||
|
{
|
||||||
|
if (!__ctfe)
|
||||||
|
{
|
||||||
|
auto res = llvm_sadd_with_overflow(x, y);
|
||||||
|
overflow |= res.overflow;
|
||||||
|
return res.result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
long r = cast(long)x + cast(long)y;
|
||||||
|
if (r < int.min || r > int.max)
|
||||||
|
overflow = true;
|
||||||
|
return cast(int)r;
|
||||||
|
}
|
||||||
@ -2326,17 +2326,6 @@ private struct BufSlice
|
|||||||
this.to = to;
|
this.to = to;
|
||||||
}
|
}
|
||||||
|
|
||||||
invariant
|
|
||||||
{
|
|
||||||
if (buf is null)
|
|
||||||
{
|
|
||||||
assert(from == 0);
|
|
||||||
assert(to == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(from <= to);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto getSlice() inout nothrow scope { return buf[from .. to]; }
|
auto getSlice() inout nothrow scope { return buf[from .. to]; }
|
||||||
size_t length() const scope { return to - from; }
|
size_t length() const scope { return to - from; }
|
||||||
}
|
}
|
||||||
694
wasm/runtime/core/internal/convert.d
Normal file
694
wasm/runtime/core/internal/convert.d
Normal file
@ -0,0 +1,694 @@
|
|||||||
|
/**
|
||||||
|
* Written in the D programming language.
|
||||||
|
* This module provides functions to converting different values to const(ubyte)[]
|
||||||
|
*
|
||||||
|
* Copyright: Copyright Igor Stepanov 2013-2013.
|
||||||
|
* License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
|
||||||
|
* Authors: Igor Stepanov
|
||||||
|
* Source: $(DRUNTIMESRC core/internal/_convert.d)
|
||||||
|
*/
|
||||||
|
module core.internal.convert;
|
||||||
|
|
||||||
|
/+
|
||||||
|
A @nogc function can allocate memory during CTFE.
|
||||||
|
+/
|
||||||
|
@nogc nothrow pure @trusted
|
||||||
|
private ubyte[] ctfe_alloc(size_t n)
|
||||||
|
{
|
||||||
|
if (!__ctfe)
|
||||||
|
{
|
||||||
|
assert(0, "CTFE only");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static ubyte[] alloc(size_t x) nothrow pure
|
||||||
|
{
|
||||||
|
if (__ctfe) // Needed to prevent _d_newarray from appearing in compiled prorgam.
|
||||||
|
return new ubyte[x];
|
||||||
|
else
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
return (cast(ubyte[] function(size_t) @nogc nothrow pure) &alloc)(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@trusted pure nothrow @nogc
|
||||||
|
const(ubyte)[] toUbyte(T)(const scope ref T val) if (__traits(isFloating, T) && (is(T : real) || is(T : ireal)))
|
||||||
|
{
|
||||||
|
if (__ctfe)
|
||||||
|
{
|
||||||
|
static if (floatFormat!T == FloatFormat.Float || floatFormat!T == FloatFormat.Double)
|
||||||
|
{
|
||||||
|
static if (is(T : ireal)) // https://issues.dlang.org/show_bug.cgi?id=19932
|
||||||
|
const f = val.im;
|
||||||
|
else
|
||||||
|
alias f = val;
|
||||||
|
static if (T.sizeof == uint.sizeof)
|
||||||
|
uint bits = *cast(const uint*) &f;
|
||||||
|
else static if (T.sizeof == ulong.sizeof)
|
||||||
|
ulong bits = *cast(const ulong*) &f;
|
||||||
|
ubyte[] result = ctfe_alloc(T.sizeof);
|
||||||
|
version (BigEndian)
|
||||||
|
{
|
||||||
|
foreach_reverse (ref b; result)
|
||||||
|
{
|
||||||
|
b = cast(ubyte) bits;
|
||||||
|
bits >>= 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (ref b; result)
|
||||||
|
{
|
||||||
|
b = cast(ubyte) bits;
|
||||||
|
bits >>= 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else static if (floatFormat!T == FloatFormat.DoubleDouble)
|
||||||
|
{
|
||||||
|
// Parse DoubleDoubles as a pair of doubles.
|
||||||
|
// The layout of the type is:
|
||||||
|
//
|
||||||
|
// [1| 11 | 52 ][1| 11 | 52 ]
|
||||||
|
// [S| Exponent | Fraction (hi) ][S| Exponent | Fraction (low) ]
|
||||||
|
//
|
||||||
|
// We can get the least significant bits by subtracting the IEEE
|
||||||
|
// double precision portion from the real value.
|
||||||
|
|
||||||
|
import core.math : toPrec;
|
||||||
|
|
||||||
|
ubyte[] buff = ctfe_alloc(T.sizeof);
|
||||||
|
enum msbSize = double.sizeof;
|
||||||
|
|
||||||
|
static if (is(T : ireal))
|
||||||
|
double hi = toPrec!double(val.im);
|
||||||
|
else
|
||||||
|
double hi = toPrec!double(val);
|
||||||
|
buff[0 .. msbSize] = toUbyte(hi)[];
|
||||||
|
|
||||||
|
if (val is cast(T)0.0 || val is cast(T)-0.0 ||
|
||||||
|
val is T.nan || val is -T.nan ||
|
||||||
|
val is T.infinity || val > T.max ||
|
||||||
|
val is -T.infinity || val < -T.max)
|
||||||
|
{
|
||||||
|
// Zero, NaN, and Inf are all representable as doubles, so the
|
||||||
|
// least significant part can be 0.0.
|
||||||
|
buff[msbSize .. $] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static if (is(T : ireal))
|
||||||
|
double low = toPrec!double(val.im - hi);
|
||||||
|
else
|
||||||
|
double low = toPrec!double(val - hi);
|
||||||
|
buff[msbSize .. $] = toUbyte(low)[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arrays don't index differently between little and big-endian targets.
|
||||||
|
return buff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto parsed = parse(val);
|
||||||
|
|
||||||
|
ulong mantissa = parsed.mantissa;
|
||||||
|
uint exp = parsed.exponent;
|
||||||
|
uint sign = parsed.sign;
|
||||||
|
|
||||||
|
ubyte[] buff = ctfe_alloc(T.sizeof);
|
||||||
|
size_t off_bytes = 0;
|
||||||
|
size_t off_bits = 0;
|
||||||
|
// Quadruples won't fit in one ulong, so check for that.
|
||||||
|
enum mantissaMax = FloatTraits!T.MANTISSA < ulong.sizeof*8 ?
|
||||||
|
FloatTraits!T.MANTISSA : ulong.sizeof*8;
|
||||||
|
|
||||||
|
for (; off_bytes < mantissaMax/8; ++off_bytes)
|
||||||
|
{
|
||||||
|
buff[off_bytes] = cast(ubyte)mantissa;
|
||||||
|
mantissa >>= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
static if (floatFormat!T == FloatFormat.Quadruple)
|
||||||
|
{
|
||||||
|
ulong mantissa2 = parsed.mantissa2;
|
||||||
|
off_bytes--; // go back one, since mantissa only stored data in 56
|
||||||
|
// bits, ie 7 bytes
|
||||||
|
for (; off_bytes < FloatTraits!T.MANTISSA/8; ++off_bytes)
|
||||||
|
{
|
||||||
|
buff[off_bytes] = cast(ubyte)mantissa2;
|
||||||
|
mantissa2 >>= 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
off_bits = FloatTraits!T.MANTISSA%8;
|
||||||
|
buff[off_bytes] = cast(ubyte)mantissa;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i=0; i<FloatTraits!T.EXPONENT/8; ++i)
|
||||||
|
{
|
||||||
|
ubyte cur_exp = cast(ubyte)exp;
|
||||||
|
exp >>= 8;
|
||||||
|
buff[off_bytes] |= (cur_exp << off_bits);
|
||||||
|
++off_bytes;
|
||||||
|
buff[off_bytes] |= cur_exp >> 8 - off_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
exp <<= 8 - FloatTraits!T.EXPONENT%8 - 1;
|
||||||
|
buff[off_bytes] |= exp;
|
||||||
|
sign <<= 7;
|
||||||
|
buff[off_bytes] |= sign;
|
||||||
|
|
||||||
|
version (BigEndian)
|
||||||
|
{
|
||||||
|
for (size_t left = 0, right = buff.length - 1; left < right; left++, right--)
|
||||||
|
{
|
||||||
|
const swap = buff[left];
|
||||||
|
buff[left] = buff[right];
|
||||||
|
buff[right] = swap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return (cast(const(ubyte)*)&val)[0 .. T.sizeof];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@safe pure nothrow @nogc
|
||||||
|
private Float parse(bool is_denormalized = false, T:ireal)(T x)
|
||||||
|
{
|
||||||
|
return parse(x.im);
|
||||||
|
}
|
||||||
|
|
||||||
|
@safe pure nothrow @nogc
|
||||||
|
private Float parse(bool is_denormalized = false, T:real)(T x_) if (floatFormat!T != FloatFormat.Real80)
|
||||||
|
{
|
||||||
|
import core.internal.traits : Unqual;
|
||||||
|
Unqual!T x = x_;
|
||||||
|
static assert(floatFormat!T != FloatFormat.DoubleDouble,
|
||||||
|
"doubledouble float format not supported in CTFE");
|
||||||
|
if (x is cast(T)0.0) return FloatTraits!T.ZERO;
|
||||||
|
if (x is cast(T)-0.0) return FloatTraits!T.NZERO;
|
||||||
|
if (x is T.nan) return FloatTraits!T.NAN;
|
||||||
|
if (x is -T.nan) return FloatTraits!T.NNAN;
|
||||||
|
if (x is T.infinity || x > T.max) return FloatTraits!T.INF;
|
||||||
|
if (x is -T.infinity || x < -T.max) return FloatTraits!T.NINF;
|
||||||
|
|
||||||
|
uint sign = x < 0;
|
||||||
|
x = sign ? -x : x;
|
||||||
|
int e = binLog2(x);
|
||||||
|
real x2 = x;
|
||||||
|
uint exp = cast(uint)(e + (2^^(FloatTraits!T.EXPONENT-1) - 1));
|
||||||
|
|
||||||
|
if (!exp)
|
||||||
|
{
|
||||||
|
if (is_denormalized)
|
||||||
|
return Float(0, 0, sign);
|
||||||
|
else
|
||||||
|
return denormalizedMantissa(x, sign);
|
||||||
|
}
|
||||||
|
|
||||||
|
x2 /= binPow2(e);
|
||||||
|
|
||||||
|
static if (!is_denormalized)
|
||||||
|
x2 -= 1.0;
|
||||||
|
|
||||||
|
static if (floatFormat!T == FloatFormat.Quadruple)
|
||||||
|
{
|
||||||
|
// Store the 112-bit mantissa in two ulongs, specifically the lower 56
|
||||||
|
// bits of each, with the most significant bits in mantissa2. There's
|
||||||
|
// an edge case exposed by the labeled test below, where only a subnormal
|
||||||
|
// with the highest bit set being the 57th bit will "overflow" to the
|
||||||
|
// 57th bit in mantissa2 with the following logic, but that special case
|
||||||
|
// is handled by an additional check in denormalizedMantissa for
|
||||||
|
// Quadruples below.
|
||||||
|
|
||||||
|
x2 *= 2UL<<(FloatTraits!T.MANTISSA - (ulong.sizeof - 1)*8 - 1);
|
||||||
|
ulong mant2 = cast(ulong) x2;
|
||||||
|
x2 -= mant2;
|
||||||
|
|
||||||
|
x2 *= 2UL<<((ulong.sizeof - 1)*8 - 1);
|
||||||
|
ulong mant = cast(ulong) x2;
|
||||||
|
return Float(mant, exp, sign, mant2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x2 *= 2UL<<(FloatTraits!T.MANTISSA);
|
||||||
|
ulong mant = shiftrRound(cast(ulong)x2);
|
||||||
|
return Float(mant, exp, sign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@safe pure nothrow @nogc
|
||||||
|
private Float parse(bool _ = false, T:real)(T x_) if (floatFormat!T == FloatFormat.Real80)
|
||||||
|
{
|
||||||
|
import core.internal.traits : Unqual;
|
||||||
|
Unqual!T x = x_;
|
||||||
|
//HACK @@@3632@@@
|
||||||
|
|
||||||
|
if (x == 0.0L)
|
||||||
|
{
|
||||||
|
real y = 1.0L/x;
|
||||||
|
if (y == real.infinity) // -0.0
|
||||||
|
return FloatTraits!T.ZERO;
|
||||||
|
else
|
||||||
|
return FloatTraits!T.NZERO; //0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x != x) //HACK: should be if (x is real.nan) and if (x is -real.nan)
|
||||||
|
{
|
||||||
|
auto y = cast(double)x;
|
||||||
|
if (y is double.nan)
|
||||||
|
return FloatTraits!T.NAN;
|
||||||
|
else
|
||||||
|
return FloatTraits!T.NNAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x == real.infinity) return FloatTraits!T.INF;
|
||||||
|
if (x == -real.infinity) return FloatTraits!T.NINF;
|
||||||
|
|
||||||
|
enum EXPONENT_MED = (2^^(FloatTraits!T.EXPONENT-1) - 1);
|
||||||
|
uint sign = x < 0;
|
||||||
|
x = sign ? -x : x;
|
||||||
|
|
||||||
|
int e = binLog2(x);
|
||||||
|
uint exp = cast(uint)(e + EXPONENT_MED);
|
||||||
|
if (!exp)
|
||||||
|
{
|
||||||
|
return denormalizedMantissa(x, sign);
|
||||||
|
}
|
||||||
|
int pow = (FloatTraits!T.MANTISSA-1-e);
|
||||||
|
x *= binPow2((pow / EXPONENT_MED)*EXPONENT_MED); //To avoid overflow in 2.0L ^^ pow
|
||||||
|
x *= binPow2(pow % EXPONENT_MED);
|
||||||
|
ulong mant = cast(ulong)x;
|
||||||
|
return Float(mant, exp, sign);
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct Float
|
||||||
|
{
|
||||||
|
ulong mantissa;
|
||||||
|
uint exponent;
|
||||||
|
uint sign;
|
||||||
|
ulong mantissa2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private template FloatTraits(T) if (floatFormat!T == FloatFormat.Float)
|
||||||
|
{
|
||||||
|
enum DATASIZE = 4;
|
||||||
|
enum EXPONENT = 8;
|
||||||
|
enum MANTISSA = 23;
|
||||||
|
enum ZERO = Float(0, 0, 0);
|
||||||
|
enum NZERO = Float(0, 0, 1);
|
||||||
|
enum NAN = Float(0x400000UL, 0xff, 0);
|
||||||
|
enum NNAN = Float(0x400000UL, 0xff, 1);
|
||||||
|
enum INF = Float(0, 255, 0);
|
||||||
|
enum NINF = Float(0, 255, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private template FloatTraits(T) if (floatFormat!T == FloatFormat.Double)
|
||||||
|
{
|
||||||
|
enum DATASIZE = 8;
|
||||||
|
enum EXPONENT = 11;
|
||||||
|
enum MANTISSA = 52;
|
||||||
|
enum ZERO = Float(0, 0, 0);
|
||||||
|
enum NZERO = Float(0, 0, 1);
|
||||||
|
enum NAN = Float(0x8000000000000UL, 0x7ff, 0);
|
||||||
|
enum NNAN = Float(0x8000000000000UL, 0x7ff, 1);
|
||||||
|
enum INF = Float(0, 0x7ff, 0);
|
||||||
|
enum NINF = Float(0, 0x7ff, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private template FloatTraits(T) if (floatFormat!T == FloatFormat.Real80)
|
||||||
|
{
|
||||||
|
enum DATASIZE = 10;
|
||||||
|
enum EXPONENT = 15;
|
||||||
|
enum MANTISSA = 64;
|
||||||
|
enum ZERO = Float(0, 0, 0);
|
||||||
|
enum NZERO = Float(0, 0, 1);
|
||||||
|
enum NAN = Float(0xC000000000000000UL, 0x7fff, 0);
|
||||||
|
enum NNAN = Float(0xC000000000000000UL, 0x7fff, 1);
|
||||||
|
enum INF = Float(0x8000000000000000UL, 0x7fff, 0);
|
||||||
|
enum NINF = Float(0x8000000000000000UL, 0x7fff, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private template FloatTraits(T) if (floatFormat!T == FloatFormat.DoubleDouble) //Unsupported in CTFE
|
||||||
|
{
|
||||||
|
enum DATASIZE = 16;
|
||||||
|
enum EXPONENT = 11;
|
||||||
|
enum MANTISSA = 106;
|
||||||
|
enum ZERO = Float(0, 0, 0);
|
||||||
|
enum NZERO = Float(0, 0, 1);
|
||||||
|
enum NAN = Float(0x8000000000000UL, 0x7ff, 0);
|
||||||
|
enum NNAN = Float(0x8000000000000UL, 0x7ff, 1);
|
||||||
|
enum INF = Float(0, 0x7ff, 0);
|
||||||
|
enum NINF = Float(0, 0x7ff, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private template FloatTraits(T) if (floatFormat!T == FloatFormat.Quadruple)
|
||||||
|
{
|
||||||
|
enum DATASIZE = 16;
|
||||||
|
enum EXPONENT = 15;
|
||||||
|
enum MANTISSA = 112;
|
||||||
|
enum ZERO = Float(0, 0, 0);
|
||||||
|
enum NZERO = Float(0, 0, 1);
|
||||||
|
enum NAN = Float(0, 0x7fff, 0, 0x80000000000000UL);
|
||||||
|
enum NNAN = Float(0, 0x7fff, 1, 0x80000000000000UL);
|
||||||
|
enum INF = Float(0, 0x7fff, 0);
|
||||||
|
enum NINF = Float(0, 0x7fff, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@safe pure nothrow @nogc
|
||||||
|
private real binPow2(int pow)
|
||||||
|
{
|
||||||
|
static real binPosPow2(int pow) @safe pure nothrow @nogc
|
||||||
|
{
|
||||||
|
assert(pow > 0);
|
||||||
|
|
||||||
|
if (pow == 1) return 2.0L;
|
||||||
|
|
||||||
|
int subpow = pow/2;
|
||||||
|
real p = binPosPow2(subpow);
|
||||||
|
real ret = p*p;
|
||||||
|
|
||||||
|
if (pow%2)
|
||||||
|
{
|
||||||
|
ret *= 2.0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pow) return 1.0L;
|
||||||
|
if (pow > 0) return binPosPow2(pow);
|
||||||
|
return 1.0L/binPosPow2(-pow);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Need in CTFE, because CTFE float and double expressions computed more precisely that run-time expressions.
|
||||||
|
@safe pure nothrow @nogc
|
||||||
|
private ulong shiftrRound(ulong x)
|
||||||
|
{
|
||||||
|
return (x >> 1) + (x & 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@safe pure nothrow @nogc
|
||||||
|
private uint binLog2(T)(const T x)
|
||||||
|
{
|
||||||
|
assert(x > 0);
|
||||||
|
int max = 2 ^^ (FloatTraits!T.EXPONENT-1)-1;
|
||||||
|
int min = -max+1;
|
||||||
|
int med = (min + max) / 2;
|
||||||
|
|
||||||
|
if (x < T.min_normal) return -max;
|
||||||
|
|
||||||
|
while ((max - min) > 1)
|
||||||
|
{
|
||||||
|
if (binPow2(med) > x)
|
||||||
|
{
|
||||||
|
max = med;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
min = med;
|
||||||
|
}
|
||||||
|
med = (min + max) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x < binPow2(max))
|
||||||
|
return min;
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
@safe pure nothrow @nogc
|
||||||
|
private Float denormalizedMantissa(T)(T x, uint sign) if (floatFormat!T == FloatFormat.Real80)
|
||||||
|
{
|
||||||
|
x *= 2.0L^^FloatTraits!T.MANTISSA;
|
||||||
|
auto fl = parse(x);
|
||||||
|
uint pow = FloatTraits!T.MANTISSA - fl.exponent + 1;
|
||||||
|
return Float(fl.mantissa >> pow, 0, sign);
|
||||||
|
}
|
||||||
|
|
||||||
|
@safe pure nothrow @nogc
|
||||||
|
private Float denormalizedMantissa(T)(T x, uint sign)
|
||||||
|
if (floatFormat!T == FloatFormat.Float || floatFormat!T == FloatFormat.Double)
|
||||||
|
{
|
||||||
|
x *= 2.0L^^FloatTraits!T.MANTISSA;
|
||||||
|
auto fl = parse!true(x);
|
||||||
|
ulong mant = fl.mantissa >> (FloatTraits!T.MANTISSA - fl.exponent);
|
||||||
|
return Float(shiftrRound(mant), 0, sign);
|
||||||
|
}
|
||||||
|
|
||||||
|
@safe pure nothrow @nogc
|
||||||
|
private Float denormalizedMantissa(T)(T x, uint sign) if (floatFormat!T == FloatFormat.Quadruple)
|
||||||
|
{
|
||||||
|
x *= 2.0L^^FloatTraits!T.MANTISSA;
|
||||||
|
auto fl = parse!true(x);
|
||||||
|
uint offset = FloatTraits!T.MANTISSA - fl.exponent + 1;
|
||||||
|
enum mantissaSize = (ulong.sizeof - 1) * 8;
|
||||||
|
|
||||||
|
if (offset < mantissaSize)
|
||||||
|
{ // Create a new mantissa ulong with the trailing mantissa2 bits that
|
||||||
|
// need to be shifted into mantissa, by shifting the needed bits left,
|
||||||
|
// zeroing out the first byte, and then ORing it with mantissa shifted
|
||||||
|
// right by offset.
|
||||||
|
|
||||||
|
ulong shiftedMantissa = ((fl.mantissa2 << (mantissaSize - offset)) &
|
||||||
|
0x00FFFFFFFFFFFFFFUL) | fl.mantissa >> offset;
|
||||||
|
return Float(shiftedMantissa, 0, sign, fl.mantissa2 >> offset);
|
||||||
|
}
|
||||||
|
else if (offset > mantissaSize)
|
||||||
|
return Float(fl.mantissa2 >> offset - mantissaSize , 0, sign, 0);
|
||||||
|
else
|
||||||
|
// Handle special case mentioned in parse() above by zeroing out the
|
||||||
|
// 57'th bit of mantissa2, "shifting" it into mantissa, and setting the
|
||||||
|
// first bit of mantissa2.
|
||||||
|
return Float(fl.mantissa2 & 0x00FFFFFFFFFFFFFFUL , 0, sign, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum FloatFormat
|
||||||
|
{
|
||||||
|
Float,
|
||||||
|
Double,
|
||||||
|
Real80,
|
||||||
|
DoubleDouble,
|
||||||
|
Quadruple
|
||||||
|
}
|
||||||
|
|
||||||
|
template floatFormat(T) if (is(T:real) || is(T:ireal))
|
||||||
|
{
|
||||||
|
static if (T.mant_dig == 24)
|
||||||
|
enum floatFormat = FloatFormat.Float;
|
||||||
|
else static if (T.mant_dig == 53)
|
||||||
|
{
|
||||||
|
// Double precision, or real == double
|
||||||
|
static if (T.sizeof == double.sizeof)
|
||||||
|
enum floatFormat = FloatFormat.Double;
|
||||||
|
// 80-bit real with rounding precision set to 53 bits.
|
||||||
|
else static if (T.sizeof == real.sizeof)
|
||||||
|
enum floatFormat = FloatFormat.Real80;
|
||||||
|
}
|
||||||
|
else static if (T.mant_dig == 64)
|
||||||
|
enum floatFormat = FloatFormat.Real80;
|
||||||
|
else static if (T.mant_dig == 106)
|
||||||
|
enum floatFormat = FloatFormat.DoubleDouble;
|
||||||
|
else static if (T.mant_dig == 113)
|
||||||
|
enum floatFormat = FloatFormat.Quadruple;
|
||||||
|
else
|
||||||
|
static assert(0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
package template floatSize(T) if (is(T:real) || is(T:ireal))
|
||||||
|
{
|
||||||
|
enum floatSize = FloatTraits!(T).DATASIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// all toUbyte functions must be evaluable at compile time
|
||||||
|
@trusted pure nothrow @nogc
|
||||||
|
const(ubyte)[] toUbyte(T)(return scope const T[] arr) if (T.sizeof == 1)
|
||||||
|
{
|
||||||
|
pragma(inline, true);
|
||||||
|
return cast(const(ubyte)[])arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private const(ubyte)[] toUbyte_array_ctfe(T)(return scope const T[] arr)
|
||||||
|
{
|
||||||
|
pragma(inline, false);
|
||||||
|
ubyte[] ret = ctfe_alloc(T.sizeof * arr.length);
|
||||||
|
static if (is(T EType == enum)) // Odd style is to avoid template instantiation in most cases.
|
||||||
|
alias E = OriginalType!EType;
|
||||||
|
else
|
||||||
|
alias E = T;
|
||||||
|
static if (is(E == struct) || is(E == union) || __traits(isStaticArray, E) || !is(typeof(arr[0] is null)))
|
||||||
|
{
|
||||||
|
size_t offset = 0;
|
||||||
|
foreach (ref cur; arr)
|
||||||
|
{
|
||||||
|
ret[offset .. offset + T.sizeof] = toUbyte(cur)[0 .. T.sizeof];
|
||||||
|
offset += T.sizeof;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (cur; arr)
|
||||||
|
assert(cur is null, "Unable to compute byte representation of non-null pointer at compile time");
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@trusted pure nothrow @nogc
|
||||||
|
const(ubyte)[] toUbyte(T)(return scope const T[] arr) if (T.sizeof > 1)
|
||||||
|
{
|
||||||
|
pragma(inline, true);
|
||||||
|
return __ctfe ? toUbyte_array_ctfe(arr)
|
||||||
|
: (cast(const(ubyte)*)(arr.ptr))[0 .. T.sizeof*arr.length];
|
||||||
|
}
|
||||||
|
|
||||||
|
private const(ubyte)[] toUbyte_integral_ctfe(T)(const return ref scope T val)
|
||||||
|
{
|
||||||
|
pragma(inline, false);
|
||||||
|
static if (T.sizeof == 1)
|
||||||
|
{
|
||||||
|
ubyte[] result = ctfe_alloc(1);
|
||||||
|
result[0] = cast(ubyte) val;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
import core.internal.traits : Unqual;
|
||||||
|
ubyte[] tmp = ctfe_alloc(T.sizeof);
|
||||||
|
Unqual!T val_ = val;
|
||||||
|
for (size_t i = 0; i < T.sizeof; ++i)
|
||||||
|
{
|
||||||
|
size_t idx;
|
||||||
|
version (LittleEndian) idx = i;
|
||||||
|
else idx = T.sizeof-i-1;
|
||||||
|
tmp[idx] = cast(ubyte)(val_&0xff);
|
||||||
|
val_ >>= 8;
|
||||||
|
}
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@trusted pure nothrow @nogc
|
||||||
|
const(ubyte)[] toUbyte(T)(const ref scope T val) if (__traits(isIntegral, T) && !is(T == enum) && !is(T == __vector))
|
||||||
|
{
|
||||||
|
pragma(inline, true);
|
||||||
|
return __ctfe ? toUbyte_integral_ctfe(val)
|
||||||
|
: (cast(const ubyte*) &val)[0 .. T.sizeof];
|
||||||
|
}
|
||||||
|
|
||||||
|
private const(ubyte)[] toUbyte_vector_ctfe(T)(const return ref scope T val)
|
||||||
|
{
|
||||||
|
pragma(inline, false);
|
||||||
|
static if (is(typeof(val[0]) : void))
|
||||||
|
assert(0, "Unable to compute byte representation of " ~ T.stringof ~ " at compile time.");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This code looks like it should work in CTFE but it segfaults:
|
||||||
|
// auto a = val.array;
|
||||||
|
// return toUbyte(a);
|
||||||
|
alias E = typeof(val[0]);
|
||||||
|
ubyte[] result = ctfe_alloc(T.sizeof);
|
||||||
|
for (size_t i = 0, j = 0; i < T.sizeof; i += E.sizeof, ++j)
|
||||||
|
{
|
||||||
|
result[i .. i + E.sizeof] = toUbyte(val[j]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@trusted pure nothrow @nogc
|
||||||
|
const(ubyte)[] toUbyte(T)(const ref scope T val) if (is(T == __vector))
|
||||||
|
{
|
||||||
|
pragma(inline, true);
|
||||||
|
return __ctfe ? toUbyte_vector_ctfe(val)
|
||||||
|
: (cast(const ubyte*) &val)[0 .. T.sizeof];
|
||||||
|
}
|
||||||
|
|
||||||
|
private const(ubyte)[] toUbyte_enum_ctfe(T)(const return ref scope T val)
|
||||||
|
{
|
||||||
|
pragma(inline, false);
|
||||||
|
static if (is(T V == enum)){}
|
||||||
|
return toUbyte(*cast(const V*) &val);
|
||||||
|
}
|
||||||
|
|
||||||
|
@trusted pure nothrow @nogc
|
||||||
|
const(ubyte)[] toUbyte(T)(const ref return scope T val) if (is(T == enum))
|
||||||
|
{
|
||||||
|
pragma(inline, true);
|
||||||
|
return __ctfe ? toUbyte_enum_ctfe(val)
|
||||||
|
: (cast(const(ubyte)*)&val)[0 .. T.sizeof];
|
||||||
|
}
|
||||||
|
|
||||||
|
nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
// Issue 19008 - check toUbyte works on enums.
|
||||||
|
enum Month : uint { jan = 1}
|
||||||
|
Month m = Month.jan;
|
||||||
|
const bytes = toUbyte(m);
|
||||||
|
enum ctfe_works = (() { Month x = Month.jan; return toUbyte(x).length > 0; })();
|
||||||
|
}
|
||||||
|
|
||||||
|
private const(ubyte)[] toUbyte_delegate_ctfe(T)(const return ref scope T val)
|
||||||
|
{
|
||||||
|
pragma(inline, false);
|
||||||
|
if (val !is null) assert(0, "Unable to compute byte representation of non-null pointer at compile time");
|
||||||
|
return ctfe_alloc(T.sizeof);
|
||||||
|
}
|
||||||
|
|
||||||
|
@trusted pure nothrow @nogc
|
||||||
|
const(ubyte)[] toUbyte(T)(const ref T val) if (is(T == delegate) || is(T : V*, V) && __traits(getAliasThis, T).length == 0)
|
||||||
|
{
|
||||||
|
pragma(inline, true);
|
||||||
|
return __ctfe ? toUbyte_delegate_ctfe(val)
|
||||||
|
: (cast(const(ubyte)*)&val)[0 .. T.sizeof];
|
||||||
|
}
|
||||||
|
|
||||||
|
private const(ubyte)[] toUbyte_aggregate_ctfe(T)(const return ref scope T val)
|
||||||
|
{
|
||||||
|
pragma(inline, false);
|
||||||
|
ubyte[] bytes = ctfe_alloc(T.sizeof);
|
||||||
|
foreach (key, ref cur; val.tupleof)
|
||||||
|
{
|
||||||
|
static if (is(typeof(cur) EType == enum)) // Odd style is to avoid template instantiation in most cases.
|
||||||
|
alias CurType = OriginalType!EType;
|
||||||
|
else
|
||||||
|
alias CurType = typeof(cur);
|
||||||
|
static if (is(CurType == struct) || is(CurType == union) || __traits(isStaticArray, CurType) || !is(typeof(cur is null)))
|
||||||
|
{
|
||||||
|
bytes[val.tupleof[key].offsetof .. val.tupleof[key].offsetof + CurType.sizeof] = toUbyte(cur)[];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(cur is null, "Unable to compute byte representation of non-null reference field at compile time");
|
||||||
|
//skip, because val bytes are zeros
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@trusted pure nothrow @nogc
|
||||||
|
const(ubyte)[] toUbyte(T)(const return ref scope T val) if (is(T == struct) || is(T == union))
|
||||||
|
{
|
||||||
|
pragma(inline, true);
|
||||||
|
return __ctfe ? toUbyte_aggregate_ctfe(val)
|
||||||
|
: (cast(const(ubyte)*)&val)[0 .. T.sizeof];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strips off all `enum`s from type `T`.
|
||||||
|
// Perhaps move to core.internal.types.
|
||||||
|
private template OriginalType(T)
|
||||||
|
{
|
||||||
|
static if (is(T EType == enum))
|
||||||
|
alias OriginalType = .OriginalType!EType;
|
||||||
|
else
|
||||||
|
alias OriginalType = T;
|
||||||
|
}
|
||||||
123
wasm/runtime/core/internal/traits.d
Normal file
123
wasm/runtime/core/internal/traits.d
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
module core.internal.traits;
|
||||||
|
|
||||||
|
alias AliasSeq(T...) = T;
|
||||||
|
|
||||||
|
template allSatisfy(alias F, T...)
|
||||||
|
{
|
||||||
|
static foreach (Ti; T)
|
||||||
|
{
|
||||||
|
static if (!is(typeof(allSatisfy) == bool) && // not yet defined
|
||||||
|
!F!(Ti))
|
||||||
|
{
|
||||||
|
enum allSatisfy = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static if (!is(typeof(allSatisfy) == bool)) // if not yet defined
|
||||||
|
{
|
||||||
|
enum allSatisfy = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template Unqual(T : const U, U)
|
||||||
|
{
|
||||||
|
static if (is(U == shared V, V))
|
||||||
|
alias Unqual = V;
|
||||||
|
else
|
||||||
|
alias Unqual = U;
|
||||||
|
}
|
||||||
|
|
||||||
|
alias Unconst(T : const U, U) = U;
|
||||||
|
|
||||||
|
template hasElaborateMove(S)
|
||||||
|
{
|
||||||
|
static if (__traits(isStaticArray, S))
|
||||||
|
{
|
||||||
|
enum bool hasElaborateMove = S.sizeof && hasElaborateMove!(BaseElemOf!S);
|
||||||
|
}
|
||||||
|
else static if (is(S == struct))
|
||||||
|
{
|
||||||
|
enum hasElaborateMove = (is(typeof(S.init.opPostMove(lvalueOf!S))) &&
|
||||||
|
!is(typeof(S.init.opPostMove(rvalueOf!S)))) ||
|
||||||
|
anySatisfy!(.hasElaborateMove, Fields!S);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enum bool hasElaborateMove = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template substInout(T)
|
||||||
|
{
|
||||||
|
static if (is(T == immutable))
|
||||||
|
{
|
||||||
|
alias substInout = T;
|
||||||
|
}
|
||||||
|
else static if (is(T : shared const U, U) || is(T : const U, U))
|
||||||
|
{
|
||||||
|
// U is top-unqualified
|
||||||
|
mixin("alias substInout = "
|
||||||
|
~ (is(T == shared) ? "shared " : "")
|
||||||
|
~ (is(T == const) || is(T == inout) ? "const " : "") // substitute inout to const
|
||||||
|
~ "substInoutForm!U;");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
static assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template anySatisfy(alias F, Ts...)
|
||||||
|
{
|
||||||
|
static foreach (T; Ts)
|
||||||
|
{
|
||||||
|
static if (!is(typeof(anySatisfy) == bool) && // not yet defined
|
||||||
|
F!T)
|
||||||
|
{
|
||||||
|
enum anySatisfy = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static if (!is(typeof(anySatisfy) == bool)) // if not yet defined
|
||||||
|
{
|
||||||
|
enum anySatisfy = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template hasElaborateCopyConstructor(S)
|
||||||
|
{
|
||||||
|
static if (__traits(isStaticArray, S))
|
||||||
|
{
|
||||||
|
enum bool hasElaborateCopyConstructor = S.sizeof && hasElaborateCopyConstructor!(BaseElemOf!S);
|
||||||
|
}
|
||||||
|
else static if (is(S == struct))
|
||||||
|
{
|
||||||
|
enum hasElaborateCopyConstructor = __traits(hasCopyConstructor, S) || __traits(hasPostblit, S);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enum bool hasElaborateCopyConstructor = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template hasElaborateDestructor(S)
|
||||||
|
{
|
||||||
|
static if (__traits(isStaticArray, S))
|
||||||
|
{
|
||||||
|
enum bool hasElaborateDestructor = S.sizeof && hasElaborateDestructor!(BaseElemOf!S);
|
||||||
|
}
|
||||||
|
else static if (is(S == struct))
|
||||||
|
{
|
||||||
|
// Once https://issues.dlang.org/show_bug.cgi?id=24865 is fixed, then
|
||||||
|
// this should be the implementation, but until that's fixed, we need the
|
||||||
|
// uncommented code.
|
||||||
|
// enum hasElaborateDestructor = __traits(hasMember, S, "__xdtor");
|
||||||
|
|
||||||
|
enum hasElaborateDestructor = hasDtor([__traits(allMembers, S)]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enum bool hasElaborateDestructor = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bool isAggregateType(T) = is(T == struct) || is(T == union) ||
|
||||||
|
is(T == class) || is(T == interface);
|
||||||
|
|
||||||
|
enum bool isPointer(T) = is(T == U*, U) && !isAggregateType!T;
|
||||||
@ -436,7 +436,7 @@ unittest
|
|||||||
{
|
{
|
||||||
debug(utf) printf("utf.encode.unittest\n");
|
debug(utf) printf("utf.encode.unittest\n");
|
||||||
|
|
||||||
char[] s = "abcd".dup;
|
char[] s = r"abcd";
|
||||||
encode(s, cast(dchar)'a');
|
encode(s, cast(dchar)'a');
|
||||||
assert(s.length == 5);
|
assert(s.length == 5);
|
||||||
assert(s == "abcda");
|
assert(s == "abcda");
|
||||||
@ -71,3 +71,41 @@ void copyEmplace(S, T)(ref S source, ref T target) @system
|
|||||||
*cast(Unconst!(T)*) &target = *cast(Unconst!(T)*) &source;
|
*cast(Unconst!(T)*) &target = *cast(Unconst!(T)*) &source;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
T* emplace(T)(T* chunk) @safe pure nothrow
|
||||||
|
{
|
||||||
|
import core.internal.lifetime : emplaceRef;
|
||||||
|
|
||||||
|
emplaceRef!T(*chunk);
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
template forward(args...)
|
||||||
|
{
|
||||||
|
import core.internal.traits : AliasSeq;
|
||||||
|
|
||||||
|
template fwd(alias arg)
|
||||||
|
{
|
||||||
|
// by ref || lazy || const/immutable
|
||||||
|
static if (__traits(isRef, arg) ||
|
||||||
|
__traits(isOut, arg) ||
|
||||||
|
__traits(isLazy, arg) ||
|
||||||
|
!is(typeof(move(arg))))
|
||||||
|
alias fwd = arg;
|
||||||
|
// (r)value
|
||||||
|
else
|
||||||
|
@property auto fwd()
|
||||||
|
{
|
||||||
|
version (DigitalMars) { /* @@BUG 23890@@ */ } else pragma(inline, true);
|
||||||
|
return move(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
alias Result = AliasSeq!();
|
||||||
|
static foreach (arg; args)
|
||||||
|
Result = AliasSeq!(Result, fwd!arg);
|
||||||
|
static if (Result.length == 1)
|
||||||
|
alias forward = Result[0];
|
||||||
|
else
|
||||||
|
alias forward = Result;
|
||||||
|
}
|
||||||
@ -6,5 +6,5 @@ float llvm_sqrt(float x) pure nothrow @nogc @safe;
|
|||||||
pragma(LDC_intrinsic, "llvm.sqrt.f64")
|
pragma(LDC_intrinsic, "llvm.sqrt.f64")
|
||||||
double llvm_sqrt(double x) pure nothrow @nogc @safe;
|
double llvm_sqrt(double x) pure nothrow @nogc @safe;
|
||||||
|
|
||||||
float sqrt(float x ) => x < 0 ? float.nan : llvm_sqrt(x);
|
float sqrt(float x ) => x < 0.0f ? float.nan : llvm_sqrt(x);
|
||||||
double sqrt(double x) => x < 0 ? double.nan : llvm_sqrt(x);
|
double sqrt(double x) => x < 0.0f ? double.nan : llvm_sqrt(x);
|
||||||
@ -1,17 +1,21 @@
|
|||||||
// Minimal druntime for webassembly. Assumes your program has a main function.
|
// **************************************************
|
||||||
|
// ** VALID FOR 1.42.0 (DMD v2.112.1, LLVM 21.1.8) **
|
||||||
|
// **************************************************
|
||||||
|
|
||||||
|
|
||||||
module object;
|
module object;
|
||||||
|
|
||||||
public import core.internal.cast_ : _d_cast;
|
public import core.internal.cast_ : _d_cast;
|
||||||
|
|
||||||
static import arsd.webassembly;
|
alias AliasSeq(TList...) = TList;
|
||||||
|
|
||||||
import std.meta;
|
|
||||||
|
|
||||||
// import core.arsd.memory_allocation;
|
// import core.arsd.memory_allocation;
|
||||||
|
|
||||||
import core.stdc.string;
|
import core.stdc.string;
|
||||||
import dlib.externdecl;
|
import dlib.externdecl;
|
||||||
|
|
||||||
|
import wasm;
|
||||||
|
|
||||||
version(CarelessAlocation)
|
version(CarelessAlocation)
|
||||||
{
|
{
|
||||||
version = inline_concat;
|
version = inline_concat;
|
||||||
@ -34,6 +38,102 @@ alias sizediff_t = ptrdiff_t;
|
|||||||
enum immutable(void)* rtinfoNoPointers = null;
|
enum immutable(void)* rtinfoNoPointers = null;
|
||||||
enum immutable(void)* rtinfoHasPointers = cast(void*)1;
|
enum immutable(void)* rtinfoHasPointers = cast(void*)1;
|
||||||
|
|
||||||
|
int __cmp(C1, C2)(C1 lhs, C2 rhs)
|
||||||
|
if ((is(C1 : const(Object)) || (is(C1 == interface) && (__traits(getLinkage, C1) == "D"))) &&
|
||||||
|
(is(C2 : const(Object)) || (is(C2 == interface) && (__traits(getLinkage, C2) == "D"))))
|
||||||
|
{
|
||||||
|
static if (is(C1 == typeof(null)) && is(C2 == typeof(null)))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else static if (is(C1 == typeof(null)))
|
||||||
|
{
|
||||||
|
// Regard null references as always being "less than"
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else static if (is(C2 == typeof(null)))
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (lhs is rhs)
|
||||||
|
return 0;
|
||||||
|
if (lhs is null)
|
||||||
|
return -1;
|
||||||
|
if (rhs is null)
|
||||||
|
return 1;
|
||||||
|
return lhs.opCmp(rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TypeInfo_AssociativeArray : TypeInfo
|
||||||
|
{
|
||||||
|
override string toString() const
|
||||||
|
{
|
||||||
|
return MakeString(value.toString(), "[", key.toString(), "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
override bool opEquals(Object o)
|
||||||
|
{
|
||||||
|
if (this is o)
|
||||||
|
return true;
|
||||||
|
auto c = cast(const TypeInfo_AssociativeArray)o;
|
||||||
|
return c && this.key == c.key &&
|
||||||
|
this.value == c.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
override bool equals(in void* p1, in void* p2) @trusted const
|
||||||
|
{
|
||||||
|
return xopEquals(p1, p2);
|
||||||
|
}
|
||||||
|
|
||||||
|
override hash_t getHash(scope const void* p) nothrow @trusted const
|
||||||
|
{
|
||||||
|
return xtoHash(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// BUG: need to add the rest of the functions
|
||||||
|
|
||||||
|
override @property size_t tsize() nothrow pure const
|
||||||
|
{
|
||||||
|
return (char[int]).sizeof;
|
||||||
|
}
|
||||||
|
|
||||||
|
override const(void)[] initializer() const @trusted
|
||||||
|
{
|
||||||
|
return (cast(void *)null)[0 .. (char[int]).sizeof];
|
||||||
|
}
|
||||||
|
|
||||||
|
override @property inout(TypeInfo) next() nothrow pure inout { return value; }
|
||||||
|
override @property uint flags() nothrow pure const { return 1; }
|
||||||
|
|
||||||
|
// TypeInfo entry is generated from the type of this template to help rt/aaA.d
|
||||||
|
// private static import core.internal.newaa;
|
||||||
|
// alias Entry(K, V) = core.internal.newaa.Entry!(K, V);
|
||||||
|
|
||||||
|
TypeInfo value;
|
||||||
|
TypeInfo key;
|
||||||
|
TypeInfo entry;
|
||||||
|
|
||||||
|
bool function(scope const void* p1, scope const void* p2) nothrow @safe xopEquals;
|
||||||
|
hash_t function(scope const void*) nothrow @safe xtoHash;
|
||||||
|
|
||||||
|
alias aaOpEqual(K, V) = core.internal.newaa._aaOpEqual!(K, V);
|
||||||
|
alias aaGetHash(K, V) = core.internal.newaa._aaGetHash!(K, V);
|
||||||
|
|
||||||
|
override @property size_t talign() nothrow pure const
|
||||||
|
{
|
||||||
|
return (char[int]).alignof;
|
||||||
|
}
|
||||||
|
|
||||||
|
version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
|
||||||
|
{
|
||||||
|
arg1 = typeid(void*);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template RTInfoImpl(size_t[] pointerBitmap)
|
template RTInfoImpl(size_t[] pointerBitmap)
|
||||||
{
|
{
|
||||||
immutable size_t[pointerBitmap.length] RTInfoImpl = pointerBitmap[];
|
immutable size_t[pointerBitmap.length] RTInfoImpl = pointerBitmap[];
|
||||||
@ -90,70 +190,62 @@ void reserve(T)(ref T[] arr, size_t length) @trusted {
|
|||||||
arr = (cast(T*) (malloc(length * T.sizeof)))[0 .. 0];
|
arr = (cast(T*) (malloc(length * T.sizeof)))[0 .. 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: fix these to use sprintf
|
||||||
|
|
||||||
extern(C) void _d_arraybounds(string file, size_t line) {
|
extern(C) void _d_arraybounds(string file, size_t line)
|
||||||
arsd.webassembly.eval(
|
{
|
||||||
q{ console.error("Range error: " + $0 + ":" + $1 )},
|
Abort("Range Error");
|
||||||
file, line);
|
|
||||||
arsd.webassembly.abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Called when an out of range slice of an array is created
|
/// Called when an out of range slice of an array is created
|
||||||
extern(C) void _d_arraybounds_slice(string file, uint line, size_t lwr, size_t upr, size_t length)
|
extern(C) void _d_arraybounds_slice(string file, uint line, size_t lwr, size_t upr, size_t length)
|
||||||
{
|
{
|
||||||
arsd.webassembly.eval(
|
Abort("Range error on slice creation");
|
||||||
q{ console.error("Range error: " + $0 + ":" + $1 + " [" + $2 + ".." + $3 + "] <> " + $4)},
|
|
||||||
file, line, lwr, upr, length);
|
|
||||||
arsd.webassembly.abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called when an out of range array index is accessed
|
/// Called when an out of range array index is accessed
|
||||||
extern(C) void _d_arraybounds_index(string file, uint line, size_t index, size_t length)
|
extern(C) void _d_arraybounds_index(string file, uint line, size_t index, size_t length)
|
||||||
{
|
{
|
||||||
arsd.webassembly.eval(
|
Abort("Range error on indexing array");
|
||||||
q{ console.error("Array index " + $0 + " out of bounds '[0.."+$1+"]' " + $2 + ":" + $3)},
|
|
||||||
index, length, file, line);
|
|
||||||
arsd.webassembly.abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
extern(C) void _d_assert(string file, uint line) @trusted @nogc pure
|
extern(C) void _d_assert(string file, uint line) @trusted @nogc pure
|
||||||
{
|
{
|
||||||
arsd.webassembly.eval(q{ console.error("Assert failure: " + $0 + ":" + $1); /*, "[" + $2 + ".." + $3 + "] <> " + $4);*/ }, file, line);//, lwr, upr, length);
|
Abort("Assertion failure");
|
||||||
arsd.webassembly.abort();
|
|
||||||
}
|
|
||||||
void _d_assertp(immutable(char)* file, uint line)
|
|
||||||
{
|
|
||||||
// import core.stdc.string : strlen;
|
|
||||||
size_t sz = 0;
|
|
||||||
while(file[sz] != '\0') sz++;
|
|
||||||
arsd.webassembly.eval(q{ console.error("Assert failure: " + $0 + ":" + $1 + "(" + $2 + ")"); /*, "[" + $2 + ".." + $3 + "] <> " + $4);*/ }, file[0 .. sz], line);//, lwr, upr, length);
|
|
||||||
arsd.webassembly.abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _d_assertp(immutable(char)* file, uint line)
|
||||||
|
{
|
||||||
|
Abort("Assertion failure");
|
||||||
|
}
|
||||||
|
|
||||||
extern(C) void _d_assert_msg(string msg, string file, uint line) @trusted @nogc pure
|
extern(C) void _d_assert_msg(string msg, string file, uint line) @trusted @nogc pure
|
||||||
{
|
{
|
||||||
arsd.webassembly.eval(q{ console.error("Assert failure: " + $0 + ":" + $1 + "(" + $2 + ")"); /*, "[" + $2 + ".." + $3 + "] <> " + $4);*/ }, file, line, msg);//, lwr, upr, length);
|
Abort("Assertion failure with msg");
|
||||||
arsd.webassembly.abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void __switch_error(string file, size_t line) @trusted @nogc pure
|
void __switch_error(string file, size_t line) @trusted @nogc pure
|
||||||
{
|
{
|
||||||
_d_assert_msg("final switch error",file, line);
|
_d_assert_msg("final switch error", file, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool __equals(T1, T2)(scope const T1[] lhs, scope const T2[] rhs) {
|
bool __equals(T1, T2)(scope const T1[] lhs, scope const T2[] rhs) {
|
||||||
if (lhs.length != rhs.length) {
|
if (lhs.length != rhs.length)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
foreach(i; 0..lhs.length) {
|
|
||||||
if (lhs[i] != rhs[i]) {
|
foreach(i; 0..lhs.length)
|
||||||
|
{
|
||||||
|
if (lhs[i] != rhs[i])
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -581,13 +673,6 @@ class TypeInfo
|
|||||||
return __cmp(this.toString(), ti.toString());
|
return __cmp(this.toString(), ti.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@system unittest
|
|
||||||
{
|
|
||||||
assert(typeid(void) <= typeid(void));
|
|
||||||
assert(typeid(void).opCmp(null));
|
|
||||||
assert(!typeid(void).opCmp(typeid(void)));
|
|
||||||
}
|
|
||||||
|
|
||||||
override bool opEquals(Object o)
|
override bool opEquals(Object o)
|
||||||
{
|
{
|
||||||
return opEquals(cast(TypeInfo) o);
|
return opEquals(cast(TypeInfo) o);
|
||||||
@ -604,14 +689,6 @@ class TypeInfo
|
|||||||
return ti && this.toString() == ti.toString();
|
return ti && this.toString() == ti.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@system unittest
|
|
||||||
{
|
|
||||||
auto anotherObj = new Object();
|
|
||||||
|
|
||||||
assert(typeid(void).opEquals(typeid(void)));
|
|
||||||
assert(typeid(void) != anotherObj); // calling .opEquals here directly is a type mismatch
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes a hash of the instance of a type.
|
* Computes a hash of the instance of a type.
|
||||||
* Params:
|
* Params:
|
||||||
@ -662,36 +739,6 @@ class TypeInfo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@system unittest
|
|
||||||
{
|
|
||||||
class _TypeInfo_Dummy : TypeInfo
|
|
||||||
{
|
|
||||||
override const(void)[] initializer() const { return []; }
|
|
||||||
@property override size_t tsize() nothrow pure const @safe @nogc { return tsize_val; }
|
|
||||||
|
|
||||||
size_t tsize_val;
|
|
||||||
}
|
|
||||||
auto dummy = new _TypeInfo_Dummy();
|
|
||||||
cast(void)dummy.initializer(); // For coverage completeness
|
|
||||||
|
|
||||||
int a = 2, b = -2;
|
|
||||||
dummy.swap(&a, &b);
|
|
||||||
// does nothing because tsize is 0
|
|
||||||
assert(a == 2);
|
|
||||||
assert(b == -2);
|
|
||||||
|
|
||||||
dummy.tsize_val = int.sizeof;
|
|
||||||
dummy.swap(&a, &b);
|
|
||||||
assert(a == -2);
|
|
||||||
assert(b == 2);
|
|
||||||
|
|
||||||
void* ptr_a = null, ptr_b = cast(void*)1;
|
|
||||||
dummy.tsize_val = (void*).sizeof;
|
|
||||||
dummy.swap(&ptr_a, &ptr_b);
|
|
||||||
assert(ptr_a is cast(void*)1);
|
|
||||||
assert(ptr_b is null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get TypeInfo for 'next' type, as defined by what kind of type this is,
|
/** Get TypeInfo for 'next' type, as defined by what kind of type this is,
|
||||||
null if none. */
|
null if none. */
|
||||||
@property inout(TypeInfo) next() nothrow pure inout @nogc { return null; }
|
@property inout(TypeInfo) next() nothrow pure inout @nogc { return null; }
|
||||||
@ -746,6 +793,7 @@ else
|
|||||||
*/
|
*/
|
||||||
@property immutable(void)* rtInfo() nothrow pure const @trusted @nogc { return rtinfoHasPointers; } // better safe than sorry
|
@property immutable(void)* rtInfo() nothrow pure const @trusted @nogc { return rtinfoHasPointers; } // better safe than sorry
|
||||||
}
|
}
|
||||||
|
|
||||||
class TypeInfo_Class : TypeInfo
|
class TypeInfo_Class : TypeInfo
|
||||||
{
|
{
|
||||||
override string toString() const pure { return name; }
|
override string toString() const pure { return name; }
|
||||||
@ -1610,114 +1658,22 @@ class TypeInfo_Enum : TypeInfo
|
|||||||
this.base == c.base;
|
this.base == c.base;
|
||||||
}
|
}
|
||||||
|
|
||||||
@system unittest
|
|
||||||
{
|
|
||||||
enum E { A, B, C }
|
|
||||||
enum EE { A, B, C }
|
|
||||||
|
|
||||||
assert(typeid(E).opEquals(typeid(E)));
|
|
||||||
assert(!typeid(E).opEquals(typeid(EE)));
|
|
||||||
}
|
|
||||||
|
|
||||||
override size_t getHash(scope const void* p) const { return base.getHash(p); }
|
override size_t getHash(scope const void* p) const { return base.getHash(p); }
|
||||||
|
|
||||||
@system unittest
|
|
||||||
{
|
|
||||||
enum E { A, B, C }
|
|
||||||
E e1 = E.A;
|
|
||||||
E e2 = E.B;
|
|
||||||
|
|
||||||
assert(typeid(E).getHash(&e1) == hashOf(E.A));
|
|
||||||
assert(typeid(E).getHash(&e2) == hashOf(E.B));
|
|
||||||
|
|
||||||
enum ES : string { A = "foo", B = "bar" }
|
|
||||||
ES es1 = ES.A;
|
|
||||||
ES es2 = ES.B;
|
|
||||||
|
|
||||||
assert(typeid(ES).getHash(&es1) == hashOf("foo"));
|
|
||||||
assert(typeid(ES).getHash(&es2) == hashOf("bar"));
|
|
||||||
}
|
|
||||||
|
|
||||||
override bool equals(in void* p1, in void* p2) const { return base.equals(p1, p2); }
|
override bool equals(in void* p1, in void* p2) const { return base.equals(p1, p2); }
|
||||||
|
|
||||||
@system unittest
|
|
||||||
{
|
|
||||||
enum E { A, B, C }
|
|
||||||
|
|
||||||
E e1 = E.A;
|
|
||||||
E e2 = E.B;
|
|
||||||
|
|
||||||
assert(typeid(E).equals(&e1, &e1));
|
|
||||||
assert(!typeid(E).equals(&e1, &e2));
|
|
||||||
}
|
|
||||||
|
|
||||||
override int compare(in void* p1, in void* p2) const { return base.compare(p1, p2); }
|
override int compare(in void* p1, in void* p2) const { return base.compare(p1, p2); }
|
||||||
|
|
||||||
@system unittest
|
|
||||||
{
|
|
||||||
enum E { A, B, C }
|
|
||||||
|
|
||||||
E e1 = E.A;
|
|
||||||
E e2 = E.B;
|
|
||||||
|
|
||||||
assert(typeid(E).compare(&e1, &e1) == 0);
|
|
||||||
assert(typeid(E).compare(&e1, &e2) < 0);
|
|
||||||
assert(typeid(E).compare(&e2, &e1) > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
override @property size_t tsize() nothrow pure const { return base.tsize; }
|
override @property size_t tsize() nothrow pure const { return base.tsize; }
|
||||||
|
|
||||||
@safe unittest
|
|
||||||
{
|
|
||||||
enum E { A, B, C }
|
|
||||||
enum ES : string { A = "a", B = "b", C = "c"}
|
|
||||||
|
|
||||||
assert(typeid(E).tsize == E.sizeof);
|
|
||||||
assert(typeid(ES).tsize == ES.sizeof);
|
|
||||||
assert(typeid(E).tsize != ES.sizeof);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void swap(void* p1, void* p2) const { return base.swap(p1, p2); }
|
override void swap(void* p1, void* p2) const { return base.swap(p1, p2); }
|
||||||
|
|
||||||
@system unittest
|
|
||||||
{
|
|
||||||
enum E { A, B, C }
|
|
||||||
|
|
||||||
E e1 = E.A;
|
|
||||||
E e2 = E.B;
|
|
||||||
|
|
||||||
typeid(E).swap(&e1, &e2);
|
|
||||||
assert(e1 == E.B);
|
|
||||||
assert(e2 == E.A);
|
|
||||||
}
|
|
||||||
|
|
||||||
override @property inout(TypeInfo) next() nothrow pure inout { return base.next; }
|
override @property inout(TypeInfo) next() nothrow pure inout { return base.next; }
|
||||||
|
|
||||||
@system unittest
|
|
||||||
{
|
|
||||||
enum E { A, B, C }
|
|
||||||
|
|
||||||
assert(typeid(E).next is null);
|
|
||||||
}
|
|
||||||
|
|
||||||
override @property uint flags() nothrow pure const { return base.flags; }
|
override @property uint flags() nothrow pure const { return base.flags; }
|
||||||
|
|
||||||
@safe unittest
|
|
||||||
{
|
|
||||||
enum E { A, B, C }
|
|
||||||
|
|
||||||
assert(typeid(E).flags == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
override const(OffsetTypeInfo)[] offTi() const { return base.offTi; }
|
override const(OffsetTypeInfo)[] offTi() const { return base.offTi; }
|
||||||
|
|
||||||
@system unittest
|
|
||||||
{
|
|
||||||
enum E { A, B, C }
|
|
||||||
|
|
||||||
assert(typeid(E).offTi is null);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void destroy(void* p) const { return base.destroy(p); }
|
override void destroy(void* p) const { return base.destroy(p); }
|
||||||
override void postblit(void* p) const { return base.postblit(p); }
|
override void postblit(void* p) const { return base.postblit(p); }
|
||||||
|
|
||||||
@ -2222,7 +2178,6 @@ extern (C) void[] _d_arrayappendcd(ref byte[] x, dchar c)
|
|||||||
|
|
||||||
|
|
||||||
/* TODO: see if needed
|
/* TODO: see if needed
|
||||||
alias AliasSeq(T...) = T;
|
|
||||||
static foreach(type; AliasSeq!(byte, char, dchar, double, float, int, long, short, ubyte, uint, ulong, ushort, void, wchar)) {
|
static foreach(type; AliasSeq!(byte, char, dchar, double, float, int, long, short, ubyte, uint, ulong, ushort, void, wchar)) {
|
||||||
mixin(q{
|
mixin(q{
|
||||||
class TypeInfo_}~type.mangleof~q{ : TypeInfo {
|
class TypeInfo_}~type.mangleof~q{ : TypeInfo {
|
||||||
@ -2363,27 +2318,6 @@ class TypeInfo_Delegate : TypeInfo
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@safe unittest
|
|
||||||
{
|
|
||||||
double sqr(double x) { return x * x; }
|
|
||||||
sqr(double.init); // for coverage completeness
|
|
||||||
|
|
||||||
auto delegate_str = "double delegate(double) pure nothrow @nogc @safe";
|
|
||||||
|
|
||||||
assert(typeid(typeof(&sqr)).toString() == delegate_str);
|
|
||||||
assert(delegate_str.hashOf() == typeid(typeof(&sqr)).hashOf());
|
|
||||||
assert(typeid(typeof(&sqr)).toHash() == typeid(typeof(&sqr)).hashOf());
|
|
||||||
|
|
||||||
int g;
|
|
||||||
|
|
||||||
alias delegate_type = typeof((int a, int b) => a + b + g);
|
|
||||||
delegate_str = "int delegate(int, int) pure nothrow @nogc @safe";
|
|
||||||
|
|
||||||
assert(typeid(delegate_type).toString() == delegate_str);
|
|
||||||
assert(delegate_str.hashOf() == typeid(delegate_type).hashOf());
|
|
||||||
assert(typeid(delegate_type).toHash() == typeid(delegate_type).hashOf());
|
|
||||||
}
|
|
||||||
|
|
||||||
override bool opEquals(Object o)
|
override bool opEquals(Object o)
|
||||||
{
|
{
|
||||||
if (this is o)
|
if (this is o)
|
||||||
@ -2392,19 +2326,6 @@ class TypeInfo_Delegate : TypeInfo
|
|||||||
return c && this.deco == c.deco;
|
return c && this.deco == c.deco;
|
||||||
}
|
}
|
||||||
|
|
||||||
@system unittest
|
|
||||||
{
|
|
||||||
double sqr(double x) { return x * x; }
|
|
||||||
int dbl(int x) { return x + x; }
|
|
||||||
sqr(double.init); // for coverage completeness
|
|
||||||
dbl(int.init); // for coverage completeness
|
|
||||||
|
|
||||||
Object obj = typeid(typeof(&sqr));
|
|
||||||
assert(obj.opEquals(typeid(typeof(&sqr))));
|
|
||||||
assert(typeid(typeof(&sqr)) == typeid(typeof(&sqr)));
|
|
||||||
assert(typeid(typeof(&dbl)) != typeid(typeof(&sqr)));
|
|
||||||
}
|
|
||||||
|
|
||||||
override size_t getHash(scope const void* p) @trusted const
|
override size_t getHash(scope const void* p) @trusted const
|
||||||
{
|
{
|
||||||
return hashOf(*cast(const void delegate() *)p);
|
return hashOf(*cast(const void delegate() *)p);
|
||||||
@ -2612,7 +2533,7 @@ class TypeInfo_Const : TypeInfo
|
|||||||
}
|
}
|
||||||
|
|
||||||
///For some reason, getHash for interfaces wanted that
|
///For some reason, getHash for interfaces wanted that
|
||||||
pragma(mangle, "_D9invariant12_d_invariantFC6ObjectZv")
|
pragma(mangle, "_D2rt10invariant_12_d_invariantFC6ObjectZv")
|
||||||
extern(D) void _d_invariant(Object o)
|
extern(D) void _d_invariant(Object o)
|
||||||
{
|
{
|
||||||
TypeInfo_Class c;
|
TypeInfo_Class c;
|
||||||
@ -2886,7 +2807,6 @@ TTo[] __ArrayCast(TFrom, TTo)(return scope TFrom[] from) nothrow
|
|||||||
if ((fromSize % TTo.sizeof) != 0)
|
if ((fromSize % TTo.sizeof) != 0)
|
||||||
{
|
{
|
||||||
//onArrayCastError(TFrom.stringof, fromSize, TTo.stringof, toLength * TTo.sizeof);
|
//onArrayCastError(TFrom.stringof, fromSize, TTo.stringof, toLength * TTo.sizeof);
|
||||||
import arsd.webassembly;
|
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2966,6 +2886,7 @@ V[K] dup(T : V[K], K, V)(T aa)
|
|||||||
/** ditto */
|
/** ditto */
|
||||||
V[K] dup(T : V[K], K, V)(T* aa)
|
V[K] dup(T : V[K], K, V)(T* aa)
|
||||||
{
|
{
|
||||||
|
assert(false, "Not implemented for platform");
|
||||||
return (*aa).dup;
|
return (*aa).dup;
|
||||||
}
|
}
|
||||||
|
|
||||||
72
wasm/runtime/std/format.d
Normal file
72
wasm/runtime/std/format.d
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
module std.format;
|
||||||
|
|
||||||
|
import dlib.util;
|
||||||
|
import std.traits;
|
||||||
|
import wasm;
|
||||||
|
|
||||||
|
char[]
|
||||||
|
sformat(Char, Args...)(scope return char[] buf, scope const(Char)[] fmt, Args args)
|
||||||
|
{
|
||||||
|
SprintfType type = SprintfType.None;
|
||||||
|
static foreach(i; 0 .. Args.length)
|
||||||
|
{
|
||||||
|
static if(isArray!(Args[i]) || is(Args[i] == string))
|
||||||
|
{
|
||||||
|
{
|
||||||
|
alias ElementType = typeof(*Args[i].init.ptr);
|
||||||
|
|
||||||
|
with(SprintfType)
|
||||||
|
{
|
||||||
|
static if(is(Args[i] == string)) type = String;
|
||||||
|
else static if(is(ElementType == ubyte)) type = U8Array;
|
||||||
|
else static if(is(ElementType == byte)) type = I8Array;
|
||||||
|
else static if(is(ElementType == ushort)) type = U16Array;
|
||||||
|
else static if(is(ElementType == short)) type = I16Array;
|
||||||
|
else static if(is(ElementType == uint)) type = U32Array;
|
||||||
|
else static if(is(ElementType == int)) type = I32Array;
|
||||||
|
else static if(is(ElementType == ulong)) type = U64Array;
|
||||||
|
else static if(is(ElementType == long)) type = I64Array;
|
||||||
|
else static if(is(ElementType == float)) type = F32Array;
|
||||||
|
else static if(is(ElementType == double)) type = F64Array;
|
||||||
|
else static if(is(ElementType == char)) type = CharArray;
|
||||||
|
else static assert(false, "Type unsupported");
|
||||||
|
}
|
||||||
|
|
||||||
|
SprintfLoadArray(args[i].length, args[i].ptr, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
with(SprintfType)
|
||||||
|
{
|
||||||
|
static if(is(Args[i] == ubyte)) type = U8;
|
||||||
|
else static if(is(Args[i] == byte)) type = I8;
|
||||||
|
else static if(is(Args[i] == ushort)) type = U16;
|
||||||
|
else static if(is(Args[i] == short)) type = I16;
|
||||||
|
else static if(is(Args[i] == uint)) type = U32;
|
||||||
|
else static if(is(Args[i] == int)) type = I32;
|
||||||
|
else static if(is(Args[i] == ulong)) type = U64;
|
||||||
|
else static if(is(Args[i] == long)) type = I64;
|
||||||
|
else static if(is(Args[i] == size_t)) type = SizeT;
|
||||||
|
else static if(is(Args[i] == float)) type = F32;
|
||||||
|
else static if(is(Args[i] == double)) type = F64;
|
||||||
|
else static if(is(Args[i] == bool)) type = Bool;
|
||||||
|
else static if(is(Args[i] == char)) type = Char;
|
||||||
|
else static assert(false, "Type unsupported");
|
||||||
|
}
|
||||||
|
|
||||||
|
SprintfLoadValue(&args[i], type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t length = SprintfEnd(buf, Str(fmt));
|
||||||
|
|
||||||
|
return buf[0 .. length];
|
||||||
|
}
|
||||||
|
|
||||||
|
char[]
|
||||||
|
sformat(alias fmt, Args...)(char[] buf, Args args) if(isSomeString!(typeof(fmt)))
|
||||||
|
{
|
||||||
|
return .sformat(buf, fmt, args);
|
||||||
|
}
|
||||||
|
|
||||||
258
wasm/runtime/std/math/traits.d
Normal file
258
wasm/runtime/std/math/traits.d
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
module std.math.traits;
|
||||||
|
|
||||||
|
import std.traits;
|
||||||
|
|
||||||
|
enum RealFormat
|
||||||
|
{
|
||||||
|
ieeeHalf,
|
||||||
|
ieeeSingle,
|
||||||
|
ieeeDouble,
|
||||||
|
ieeeExtended, // x87 80-bit real
|
||||||
|
ieeeExtended53, // x87 real rounded to precision of double.
|
||||||
|
ibmExtended, // IBM 128-bit extended
|
||||||
|
ieeeQuadruple,
|
||||||
|
}
|
||||||
|
|
||||||
|
template floatTraits(T)
|
||||||
|
{
|
||||||
|
import std.traits : Unqual;
|
||||||
|
|
||||||
|
// EXPMASK is a ushort mask to select the exponent portion (without sign)
|
||||||
|
// EXPSHIFT is the number of bits the exponent is left-shifted by in its ushort
|
||||||
|
// EXPBIAS is the exponent bias - 1 (exp == EXPBIAS yields ×2^-1).
|
||||||
|
// EXPPOS_SHORT is the index of the exponent when represented as a ushort array.
|
||||||
|
// SIGNPOS_BYTE is the index of the sign when represented as a ubyte array.
|
||||||
|
// RECIP_EPSILON is the value such that (smallest_subnormal) * RECIP_EPSILON == T.min_normal
|
||||||
|
enum Unqual!T RECIP_EPSILON = (1/T.epsilon);
|
||||||
|
static if (T.mant_dig == 24)
|
||||||
|
{
|
||||||
|
// Single precision float
|
||||||
|
enum ushort EXPMASK = 0x7F80;
|
||||||
|
enum ushort EXPSHIFT = 7;
|
||||||
|
enum ushort EXPBIAS = 0x3F00;
|
||||||
|
enum uint EXPMASK_INT = 0x7F80_0000;
|
||||||
|
enum uint MANTISSAMASK_INT = 0x007F_FFFF;
|
||||||
|
enum realFormat = RealFormat.ieeeSingle;
|
||||||
|
version (LittleEndian)
|
||||||
|
{
|
||||||
|
enum EXPPOS_SHORT = 1;
|
||||||
|
enum SIGNPOS_BYTE = 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enum EXPPOS_SHORT = 0;
|
||||||
|
enum SIGNPOS_BYTE = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else static if (T.mant_dig == 53)
|
||||||
|
{
|
||||||
|
static if (T.sizeof == 8)
|
||||||
|
{
|
||||||
|
// Double precision float, or real == double
|
||||||
|
enum ushort EXPMASK = 0x7FF0;
|
||||||
|
enum ushort EXPSHIFT = 4;
|
||||||
|
enum ushort EXPBIAS = 0x3FE0;
|
||||||
|
enum uint EXPMASK_INT = 0x7FF0_0000;
|
||||||
|
enum uint MANTISSAMASK_INT = 0x000F_FFFF; // for the MSB only
|
||||||
|
enum ulong MANTISSAMASK_LONG = 0x000F_FFFF_FFFF_FFFF;
|
||||||
|
enum realFormat = RealFormat.ieeeDouble;
|
||||||
|
version (LittleEndian)
|
||||||
|
{
|
||||||
|
enum EXPPOS_SHORT = 3;
|
||||||
|
enum SIGNPOS_BYTE = 7;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enum EXPPOS_SHORT = 0;
|
||||||
|
enum SIGNPOS_BYTE = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else static if (T.sizeof == 12)
|
||||||
|
{
|
||||||
|
// Intel extended real80 rounded to double
|
||||||
|
enum ushort EXPMASK = 0x7FFF;
|
||||||
|
enum ushort EXPSHIFT = 0;
|
||||||
|
enum ushort EXPBIAS = 0x3FFE;
|
||||||
|
enum realFormat = RealFormat.ieeeExtended53;
|
||||||
|
version (LittleEndian)
|
||||||
|
{
|
||||||
|
enum EXPPOS_SHORT = 4;
|
||||||
|
enum SIGNPOS_BYTE = 9;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enum EXPPOS_SHORT = 0;
|
||||||
|
enum SIGNPOS_BYTE = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
static assert(false, "No traits support for " ~ T.stringof);
|
||||||
|
}
|
||||||
|
else static if (T.mant_dig == 64)
|
||||||
|
{
|
||||||
|
// Intel extended real80
|
||||||
|
enum ushort EXPMASK = 0x7FFF;
|
||||||
|
enum ushort EXPSHIFT = 0;
|
||||||
|
enum ushort EXPBIAS = 0x3FFE;
|
||||||
|
enum realFormat = RealFormat.ieeeExtended;
|
||||||
|
version (LittleEndian)
|
||||||
|
{
|
||||||
|
enum EXPPOS_SHORT = 4;
|
||||||
|
enum SIGNPOS_BYTE = 9;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enum EXPPOS_SHORT = 0;
|
||||||
|
enum SIGNPOS_BYTE = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else static if (T.mant_dig == 113)
|
||||||
|
{
|
||||||
|
// Quadruple precision float
|
||||||
|
enum ushort EXPMASK = 0x7FFF;
|
||||||
|
enum ushort EXPSHIFT = 0;
|
||||||
|
enum ushort EXPBIAS = 0x3FFE;
|
||||||
|
enum realFormat = RealFormat.ieeeQuadruple;
|
||||||
|
version (LittleEndian)
|
||||||
|
{
|
||||||
|
enum EXPPOS_SHORT = 7;
|
||||||
|
enum SIGNPOS_BYTE = 15;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enum EXPPOS_SHORT = 0;
|
||||||
|
enum SIGNPOS_BYTE = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else static if (T.mant_dig == 106)
|
||||||
|
{
|
||||||
|
// IBM Extended doubledouble
|
||||||
|
enum ushort EXPMASK = 0x7FF0;
|
||||||
|
enum ushort EXPSHIFT = 4;
|
||||||
|
enum realFormat = RealFormat.ibmExtended;
|
||||||
|
|
||||||
|
// For IBM doubledouble the larger magnitude double comes first.
|
||||||
|
// It's really a double[2] and arrays don't index differently
|
||||||
|
// between little and big-endian targets.
|
||||||
|
enum DOUBLEPAIR_MSB = 0;
|
||||||
|
enum DOUBLEPAIR_LSB = 1;
|
||||||
|
|
||||||
|
// The exponent/sign byte is for most significant part.
|
||||||
|
version (LittleEndian)
|
||||||
|
{
|
||||||
|
enum EXPPOS_SHORT = 3;
|
||||||
|
enum SIGNPOS_BYTE = 7;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enum EXPPOS_SHORT = 0;
|
||||||
|
enum SIGNPOS_BYTE = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
static assert(false, "No traits support for " ~ T.stringof);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isNaN(X)(X x) @nogc @trusted pure nothrow
|
||||||
|
if (isFloatingPoint!(X))
|
||||||
|
{
|
||||||
|
version (all)
|
||||||
|
{
|
||||||
|
return x != x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Code kept for historical context. At least on Intel, the simple test
|
||||||
|
x != x uses one dedicated instruction (ucomiss/ucomisd) that runs in one
|
||||||
|
cycle. Code for 80- and 128-bits is larger but still smaller than the
|
||||||
|
integrals-based solutions below. Future revisions may enable the code
|
||||||
|
below conditionally depending on hardware.
|
||||||
|
*/
|
||||||
|
alias F = floatTraits!(X);
|
||||||
|
static if (F.realFormat == RealFormat.ieeeSingle)
|
||||||
|
{
|
||||||
|
const uint p = *cast(uint *)&x;
|
||||||
|
// Sign bit (MSB) is irrelevant so mask it out.
|
||||||
|
// Next 8 bits should be all set.
|
||||||
|
// At least one bit among the least significant 23 bits should be set.
|
||||||
|
return (p & 0x7FFF_FFFF) > 0x7F80_0000;
|
||||||
|
}
|
||||||
|
else static if (F.realFormat == RealFormat.ieeeDouble)
|
||||||
|
{
|
||||||
|
const ulong p = *cast(ulong *)&x;
|
||||||
|
// Sign bit (MSB) is irrelevant so mask it out.
|
||||||
|
// Next 11 bits should be all set.
|
||||||
|
// At least one bit among the least significant 52 bits should be set.
|
||||||
|
return (p & 0x7FFF_FFFF_FFFF_FFFF) > 0x7FF0_0000_0000_0000;
|
||||||
|
}
|
||||||
|
else static if (F.realFormat == RealFormat.ieeeExtended ||
|
||||||
|
F.realFormat == RealFormat.ieeeExtended53)
|
||||||
|
{
|
||||||
|
const ushort e = F.EXPMASK & (cast(ushort *)&x)[F.EXPPOS_SHORT];
|
||||||
|
const ulong ps = *cast(ulong *)&x;
|
||||||
|
return e == F.EXPMASK &&
|
||||||
|
ps & 0x7FFF_FFFF_FFFF_FFFF; // not infinity
|
||||||
|
}
|
||||||
|
else static if (F.realFormat == RealFormat.ieeeQuadruple)
|
||||||
|
{
|
||||||
|
const ushort e = F.EXPMASK & (cast(ushort *)&x)[F.EXPPOS_SHORT];
|
||||||
|
const ulong psLsb = (cast(ulong *)&x)[MANTISSA_LSB];
|
||||||
|
const ulong psMsb = (cast(ulong *)&x)[MANTISSA_MSB];
|
||||||
|
return e == F.EXPMASK &&
|
||||||
|
(psLsb | (psMsb& 0x0000_FFFF_FFFF_FFFF)) != 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return x != x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isInfinity(X)(X x) @nogc @trusted pure nothrow
|
||||||
|
if (isFloatingPoint!(X))
|
||||||
|
{
|
||||||
|
import std.math.traits : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
|
||||||
|
|
||||||
|
alias F = floatTraits!(X);
|
||||||
|
static if (F.realFormat == RealFormat.ieeeSingle)
|
||||||
|
{
|
||||||
|
return ((*cast(uint *)&x) & 0x7FFF_FFFF) == 0x7F80_0000;
|
||||||
|
}
|
||||||
|
else static if (F.realFormat == RealFormat.ieeeDouble)
|
||||||
|
{
|
||||||
|
return ((*cast(ulong *)&x) & 0x7FFF_FFFF_FFFF_FFFF)
|
||||||
|
== 0x7FF0_0000_0000_0000;
|
||||||
|
}
|
||||||
|
else static if (F.realFormat == RealFormat.ieeeExtended ||
|
||||||
|
F.realFormat == RealFormat.ieeeExtended53)
|
||||||
|
{
|
||||||
|
const ushort e = cast(ushort)(F.EXPMASK & (cast(ushort *)&x)[F.EXPPOS_SHORT]);
|
||||||
|
const ulong ps = *cast(ulong *)&x;
|
||||||
|
|
||||||
|
// On Motorola 68K, infinity can have hidden bit = 1 or 0. On x86, it is always 1.
|
||||||
|
return e == F.EXPMASK && (ps & 0x7FFF_FFFF_FFFF_FFFF) == 0;
|
||||||
|
}
|
||||||
|
else static if (F.realFormat == RealFormat.ieeeQuadruple)
|
||||||
|
{
|
||||||
|
const long psLsb = (cast(long *)&x)[MANTISSA_LSB];
|
||||||
|
const long psMsb = (cast(long *)&x)[MANTISSA_MSB];
|
||||||
|
return (psLsb == 0)
|
||||||
|
&& (psMsb & 0x7FFF_FFFF_FFFF_FFFF) == 0x7FFF_0000_0000_0000;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return (x < -X.max) || (X.max < x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
version (LittleEndian)
|
||||||
|
{
|
||||||
|
enum MANTISSA_LSB = 0;
|
||||||
|
enum MANTISSA_MSB = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enum MANTISSA_LSB = 1;
|
||||||
|
enum MANTISSA_MSB = 0;
|
||||||
|
}
|
||||||
22
wasm/runtime/std/stdio.d
Normal file
22
wasm/runtime/std/stdio.d
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
module std.stdio;
|
||||||
|
|
||||||
|
import dlib.util;
|
||||||
|
import std.traits;
|
||||||
|
|
||||||
|
void
|
||||||
|
writefln(alias fmt, A...)(A args) if(isSomeString!(typeof(fmt)))
|
||||||
|
{
|
||||||
|
static foreach(i; 0 .. A.length)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
static if()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
writefln(Char, A...)(in Char[] fmt, A args)
|
||||||
|
{
|
||||||
|
writefln(Str(fmt), args);
|
||||||
|
}
|
||||||
|
|
||||||
84
wasm/runtime/std/traits.d
Normal file
84
wasm/runtime/std/traits.d
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
module std.traits;
|
||||||
|
|
||||||
|
enum bool isFloatingPoint(T) = __traits(isFloating, T) && is(T : real);
|
||||||
|
|
||||||
|
template isIntegral(T)
|
||||||
|
{
|
||||||
|
static if (!__traits(isIntegral, T))
|
||||||
|
enum isIntegral = false;
|
||||||
|
else static if (is(T U == enum))
|
||||||
|
enum isIntegral = isIntegral!U;
|
||||||
|
else
|
||||||
|
enum isIntegral = __traits(isZeroInit, T) // Not char, wchar, or dchar.
|
||||||
|
&& !is(immutable T == immutable bool) && !is(T == __vector);
|
||||||
|
}
|
||||||
|
|
||||||
|
template isNumeric(T)
|
||||||
|
{
|
||||||
|
static if (!__traits(isArithmetic, T))
|
||||||
|
enum isNumeric = false;
|
||||||
|
else static if (__traits(isFloating, T))
|
||||||
|
enum isNumeric = is(T : real); // Not __vector, imaginary, or complex.
|
||||||
|
else static if (is(T U == enum))
|
||||||
|
enum isNumeric = isNumeric!U;
|
||||||
|
else
|
||||||
|
enum isNumeric = __traits(isZeroInit, T) // Not char, wchar, or dchar.
|
||||||
|
&& !is(immutable T == immutable bool) && !is(T == __vector);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bool isSigned(T) = __traits(isArithmetic, T) && !__traits(isUnsigned, T)
|
||||||
|
&& is(T : real);
|
||||||
|
|
||||||
|
enum hasMember(T, string name) = __traits(hasMember, T, name);
|
||||||
|
|
||||||
|
enum bool isArray(T) = isStaticArray!T || isDynamicArray!T;
|
||||||
|
|
||||||
|
enum bool isStaticArray(T) = __traits(isStaticArray, T);
|
||||||
|
|
||||||
|
template isDynamicArray(T)
|
||||||
|
{
|
||||||
|
static if (is(T == U[], U))
|
||||||
|
enum bool isDynamicArray = true;
|
||||||
|
else static if (is(T U == enum))
|
||||||
|
// BUG: isDynamicArray / isStaticArray considers enums
|
||||||
|
// with appropriate base types as dynamic/static arrays
|
||||||
|
// Retain old behaviour for now, see
|
||||||
|
// https://github.com/dlang/phobos/pull/7574
|
||||||
|
enum bool isDynamicArray = isDynamicArray!U;
|
||||||
|
else
|
||||||
|
enum bool isDynamicArray = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum isAssignable(Lhs, Rhs = Lhs) = isRvalueAssignable!(Lhs, Rhs) && isLvalueAssignable!(Lhs, Rhs);
|
||||||
|
|
||||||
|
enum isRvalueAssignable(Lhs, Rhs = Lhs) = __traits(compiles, { lvalueOf!Lhs = rvalueOf!Rhs; });
|
||||||
|
|
||||||
|
enum isLvalueAssignable(Lhs, Rhs = Lhs) = __traits(compiles, { lvalueOf!Lhs = lvalueOf!Rhs; });
|
||||||
|
|
||||||
|
enum bool isInstanceOf(alias S, T) = is(T == S!Args, Args...);
|
||||||
|
|
||||||
|
template isInstanceOf(alias S, alias T)
|
||||||
|
{
|
||||||
|
enum impl(alias T : S!Args, Args...) = true;
|
||||||
|
enum impl(alias T) = false;
|
||||||
|
enum isInstanceOf = impl!T;
|
||||||
|
}
|
||||||
|
|
||||||
|
import core.internal.traits : CoreUnqual = Unqual;
|
||||||
|
alias Unqual = CoreUnqual;
|
||||||
|
|
||||||
|
@property T rvalueOf(T)(inout __InoutWorkaroundStruct = __InoutWorkaroundStruct.init);
|
||||||
|
|
||||||
|
@property ref T lvalueOf(T)(inout __InoutWorkaroundStruct = __InoutWorkaroundStruct.init);
|
||||||
|
|
||||||
|
enum bool isIterable(T) = is(typeof({ foreach (elem; T.init) {} }));
|
||||||
|
|
||||||
|
template isAggregateType(T)
|
||||||
|
{
|
||||||
|
static if (is(T == enum))
|
||||||
|
enum isAggregateType = isAggregateType!(OriginalType!T);
|
||||||
|
else
|
||||||
|
enum isAggregateType = is(T == struct) || is(T == class) || is(T == interface) || is(T == union);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bool isSomeString(T) = is(immutable T == immutable C[], C) && (is(C == char) || is(C == wchar) || is(C == dchar));
|
||||||
51
wasm/runtime/wasm.d
Normal file
51
wasm/runtime/wasm.d
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
module wasm;
|
||||||
|
|
||||||
|
import ldc.attributes;
|
||||||
|
|
||||||
|
enum SprintfType : size_t
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
U8,
|
||||||
|
I8,
|
||||||
|
U16,
|
||||||
|
I16,
|
||||||
|
U32,
|
||||||
|
I32,
|
||||||
|
U64,
|
||||||
|
I64,
|
||||||
|
SizeT,
|
||||||
|
F32,
|
||||||
|
F64,
|
||||||
|
Bool,
|
||||||
|
String,
|
||||||
|
U8Array,
|
||||||
|
I8Array,
|
||||||
|
U16Array,
|
||||||
|
I16Array,
|
||||||
|
U32Array,
|
||||||
|
I32Array,
|
||||||
|
U64Array,
|
||||||
|
I64Array,
|
||||||
|
F32Array,
|
||||||
|
F64Array,
|
||||||
|
Char,
|
||||||
|
CharArray,
|
||||||
|
}
|
||||||
|
|
||||||
|
extern extern(C) @nogc pure @llvmAttr("wasm-import-module", "env"):
|
||||||
|
|
||||||
|
@llvmAttr("wasm-import-name", "Console") void
|
||||||
|
Console(string str, bool write_line);
|
||||||
|
|
||||||
|
@llvmAttr("wasm-import-name", "Abort") void
|
||||||
|
Abort(string message);
|
||||||
|
|
||||||
|
@llvmAttr("wasm-import-name", "SprintfLoadValue") void
|
||||||
|
SprintfLoadValue(const(void)* ptr, SprintfType type);
|
||||||
|
|
||||||
|
@llvmAttr("wasm-import-name", "SprintfLoadArray") void
|
||||||
|
SprintfLoadArray(size_t length, const(void)* ptr, SprintfType type);
|
||||||
|
|
||||||
|
@llvmAttr("wasm-import-name", "SprintfEnd") size_t
|
||||||
|
SprintfEnd(char[] buffer, string format);
|
||||||
|
|
||||||
285
wasm/wasm.js
285
wasm/wasm.js
@ -0,0 +1,285 @@
|
|||||||
|
|
||||||
|
const TYPES = {
|
||||||
|
U8: 1,
|
||||||
|
I8: 2,
|
||||||
|
U16: 3,
|
||||||
|
I16: 4,
|
||||||
|
U32: 5,
|
||||||
|
I32: 6,
|
||||||
|
U64: 7,
|
||||||
|
I64: 8,
|
||||||
|
SizeT: 9,
|
||||||
|
F32: 10,
|
||||||
|
F64: 11,
|
||||||
|
Bool: 12,
|
||||||
|
String: 13,
|
||||||
|
U8Array: 14,
|
||||||
|
I8Array: 15,
|
||||||
|
U16Array: 16,
|
||||||
|
I16Array: 17,
|
||||||
|
U32Array: 18,
|
||||||
|
I32Array: 19,
|
||||||
|
U64Array: 20,
|
||||||
|
I64Array: 21,
|
||||||
|
F32Array: 22,
|
||||||
|
F64Array: 23,
|
||||||
|
Char: 24,
|
||||||
|
CharArray: 25,
|
||||||
|
};
|
||||||
|
|
||||||
|
function assert(condition, message)
|
||||||
|
{
|
||||||
|
if(!condition)
|
||||||
|
{
|
||||||
|
console.assert(condition, message);
|
||||||
|
throw "Assert failure";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class WasmManager
|
||||||
|
{
|
||||||
|
constructor(memory, ptr_size = 4)
|
||||||
|
{
|
||||||
|
this.ptr_size = ptr_size;
|
||||||
|
|
||||||
|
this.sprintf_values = [];
|
||||||
|
|
||||||
|
this.stdout_string = "";
|
||||||
|
|
||||||
|
switch(this.ptr_size)
|
||||||
|
{
|
||||||
|
case 8: this.LoadSize = this.LoadU64; break;
|
||||||
|
case 4:
|
||||||
|
default: this.LoadSize = this.LoadU32; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SetMemory(memory)
|
||||||
|
{
|
||||||
|
this.memory = memory;
|
||||||
|
this.data_view = new DataView(this.memory.buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadBool = (addr) => Boolean(this.data_view.getUint8(addr, true));
|
||||||
|
|
||||||
|
LoadF32 = (addr) => this.data_view.getFloat32(addr, true);
|
||||||
|
LoadF64 = (addr) => this.data_view.getFloat64(addr, true);
|
||||||
|
|
||||||
|
LoadU8 = (addr) => this.data_view.getUint8 (addr, true);
|
||||||
|
LoadI8 = (addr) => this.data_view.getInt8 (addr, true);
|
||||||
|
LoadU16 = (addr) => this.data_view.getUint16 (addr, true);
|
||||||
|
LoadI16 = (addr) => this.data_view.getInt16 (addr, true);
|
||||||
|
LoadU32 = (addr) => this.data_view.getUint32 (addr, true);
|
||||||
|
LoadI32 = (addr) => this.data_view.getInt32 (addr, true);
|
||||||
|
|
||||||
|
LoadU64(addr)
|
||||||
|
{
|
||||||
|
const lo = this.data_view.getUint32(addr+0, true);
|
||||||
|
const hi = this.data_view.getUint32(addr+4, true);
|
||||||
|
return lo + hi*4294967296;
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadI64(addr)
|
||||||
|
{
|
||||||
|
const lo = this.data_view.getUint32(addr+0, true);
|
||||||
|
const hi = this.data_view.getInt32 (addr+4, true);
|
||||||
|
return lo + hi*4294967296;
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadArray = (array_class, length, addr) => new array_class(this.memory.buffer, addr, length);
|
||||||
|
LoadString = (length, addr) => new TextDecoder().decode(this.LoadArray(Uint8Array, length, addr));
|
||||||
|
|
||||||
|
LoadCString(ptr)
|
||||||
|
{
|
||||||
|
if(!ptr) return null;
|
||||||
|
|
||||||
|
let length = 0;
|
||||||
|
for(; this.LoadU8(ptr+length); length += 1) {}
|
||||||
|
|
||||||
|
return this.LoadString(ptr, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreString(ptr, value)
|
||||||
|
{
|
||||||
|
const src = new TextEncoder().encode(value);
|
||||||
|
const dst = new Uint8Array(this.memory.buffer, ptr, src.length);
|
||||||
|
|
||||||
|
dst.set(src);
|
||||||
|
|
||||||
|
return src.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
Imports()
|
||||||
|
{
|
||||||
|
const manager = this;
|
||||||
|
return {
|
||||||
|
env: {
|
||||||
|
Abort(string_length, string_ptr)
|
||||||
|
{
|
||||||
|
console.error(manager.LoadString(string_length, string_ptr));
|
||||||
|
},
|
||||||
|
SprintfLoadValue(ptr, type)
|
||||||
|
{
|
||||||
|
let value = null;
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case TYPES.U8: value = manager.LoadU8(ptr); break;
|
||||||
|
case TYPES.I8: value = manager.LoadI8(ptr); break;
|
||||||
|
case TYPES.U16: value = manager.LoadU16(ptr); break;
|
||||||
|
case TYPES.I16: value = manager.LoadI16(ptr); break;
|
||||||
|
case TYPES.U32: value = manager.LoadU32(ptr); break;
|
||||||
|
case TYPES.I32: value = manager.LoadI32(ptr); break;
|
||||||
|
case TYPES.U64: value = manager.LoadU64(ptr); break;
|
||||||
|
case TYPES.I64: value = manager.LoadI64(ptr); break;
|
||||||
|
case TYPES.SizeT: value = manager.LoadSize(ptr); break;
|
||||||
|
case TYPES.F32: value = manager.LoadF32(ptr); break;
|
||||||
|
case TYPES.F64: value = manager.LoadF64(ptr); break;
|
||||||
|
case TYPES.Bool: value = manager.LoadBool(ptr); break;
|
||||||
|
case TYPES.Char: value = manager.LoadString(1, ptr); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(value)
|
||||||
|
{
|
||||||
|
if(type === TYPES.Bool)
|
||||||
|
{
|
||||||
|
manager.sprintf_values.push(value ? 'true' : 'false');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
manager.sprintf_values.push(''+value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SprintfLoadArray(length, ptr, type)
|
||||||
|
{
|
||||||
|
let value = null;
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case TYPES.CharArray:
|
||||||
|
case TYPES.String: value = manager.LoadString(length, ptr); break;
|
||||||
|
case TYPES.U8Array: value = manager.LoadArray(Uint8Array, length, ptr); break;
|
||||||
|
case TYPES.I8Array: value = manager.LoadArray(Int8Array, length, ptr); break;
|
||||||
|
case TYPES.U16Array: value = manager.LoadArray(Uint16Array, length, ptr); break;
|
||||||
|
case TYPES.I16Array: value = manager.LoadArray(Int16Array, length, ptr); break;
|
||||||
|
case TYPES.U32Array: value = manager.LoadArray(Uint32Array, length, ptr); break;
|
||||||
|
case TYPES.I32Array: value = manager.LoadArray(Int32Array, length, ptr); break;
|
||||||
|
case TYPES.U64Array: value = manager.LoadArray(BigUint64Array, length, ptr); break;
|
||||||
|
case TYPES.I64Array: value = manager.LoadArray(BigInt64Array, length, ptr); break;
|
||||||
|
case TYPES.F32Array: value = manager.LoadArray(Float32Array, length, ptr); break;
|
||||||
|
case TYPES.F64Array: value = manager.LoadArray(Float64Array, length, ptr); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(value)
|
||||||
|
{
|
||||||
|
if(type !== TYPES.String && type !== TYPES.CharArray)
|
||||||
|
{
|
||||||
|
value = `[${value.join(", ")}]`;
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.sprintf_values.push(value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SprintfEnd(buffer_length, buffer_ptr, string_length, string_ptr)
|
||||||
|
{
|
||||||
|
let format_string = manager.LoadString(string_length, string_ptr);
|
||||||
|
|
||||||
|
let index = format_string.indexOf("%");
|
||||||
|
|
||||||
|
let result = format_string.substring(0, index);
|
||||||
|
let format = format_string.substring(index);
|
||||||
|
|
||||||
|
function Next()
|
||||||
|
{
|
||||||
|
index = format.indexOf("%");
|
||||||
|
result += format.substring(0, index);
|
||||||
|
format = format.substring(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
let value_index = 0;
|
||||||
|
for(; value_index < manager.sprintf_values.length;)
|
||||||
|
{
|
||||||
|
assert(format.length);
|
||||||
|
|
||||||
|
const char = format.charAt(1);
|
||||||
|
assert(char !== " " && char.length, "Invalid format string " + format_string);
|
||||||
|
|
||||||
|
if(char === "%")
|
||||||
|
{
|
||||||
|
result += "%";
|
||||||
|
format = format.substring(2);
|
||||||
|
Next();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if(char >= '0' && char <= '9')
|
||||||
|
{
|
||||||
|
let digit_index = 2;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
let next_char = format.charAt(digit_index++);
|
||||||
|
|
||||||
|
assert(next_char !== " " && next_char.length, "Invalid format string " + format_string);
|
||||||
|
|
||||||
|
if(next_char < '0' || next_char > '9')
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result += manager.sprintf_values[value_index++];
|
||||||
|
format = format.substring(digit_index);
|
||||||
|
Next();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if((char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z'))
|
||||||
|
{
|
||||||
|
result += manager.sprintf_values[value_index++];
|
||||||
|
format = format.substring(2);
|
||||||
|
Next();
|
||||||
|
}
|
||||||
|
else assert(false, "Invalid format string " + format_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
result += format;
|
||||||
|
|
||||||
|
const bytes_written = manager.StoreString(buffer_ptr, result);
|
||||||
|
assert(bytes_written <= buffer_length, "Format string is longer than buffer length");
|
||||||
|
|
||||||
|
manager.sprintf_values = [];
|
||||||
|
|
||||||
|
return bytes_written;
|
||||||
|
},
|
||||||
|
Console(string_length, string_ptr, write_line)
|
||||||
|
{
|
||||||
|
manager.stdout_string += manager.LoadString(string_length, string_ptr);
|
||||||
|
if(write_line || manager.stdout_string.includes("\n"))
|
||||||
|
{
|
||||||
|
console.log(manager.stdout_string);
|
||||||
|
manager.stdout_string = "";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function StartWasm(path)
|
||||||
|
{
|
||||||
|
const manager = new WasmManager();
|
||||||
|
|
||||||
|
const response = await fetch(path);
|
||||||
|
const data = await response.arrayBuffer();
|
||||||
|
const wasm = await WebAssembly.instantiate(data, manager.Imports());
|
||||||
|
|
||||||
|
const exports = wasm.instance.exports;
|
||||||
|
|
||||||
|
if(exports.memory)
|
||||||
|
{
|
||||||
|
manager.SetMemory(exports.memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
exports?._start();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user