wip setting everything up for wasm
This commit is contained in:
parent
6ae59dab5b
commit
899a28a17e
BIN
Test_Runner
Executable file
BIN
Test_Runner
Executable file
Binary file not shown.
427
aliases.d
427
aliases.d
@ -1,9 +1,23 @@
|
|||||||
module dlib.aliases;
|
module dlib.aliases;
|
||||||
|
|
||||||
import core.memory;
|
// import core.memory;
|
||||||
import std.stdint;
|
//import std.stdint;
|
||||||
import dlib.math;
|
import dlib.math;
|
||||||
|
|
||||||
|
enum string NO_IMPL = "Not yet implemented.";
|
||||||
|
|
||||||
|
public import std.traits;
|
||||||
|
public import std.meta;
|
||||||
|
|
||||||
|
version(WebAssembly)
|
||||||
|
{
|
||||||
|
enum bool NativeTarget = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enum bool NativeTarget = true;
|
||||||
|
}
|
||||||
|
|
||||||
debug
|
debug
|
||||||
{
|
{
|
||||||
const BUILD_DEBUG = true;
|
const BUILD_DEBUG = true;
|
||||||
@ -13,41 +27,41 @@ else
|
|||||||
const BUILD_DEBUG = false;
|
const BUILD_DEBUG = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
alias i8 = byte;
|
alias i8 = byte;
|
||||||
alias i16 = short;
|
alias i16 = short;
|
||||||
alias i32 = int;
|
alias i32 = int;
|
||||||
alias i64 = long;
|
alias i64 = long;
|
||||||
|
|
||||||
alias u8 = ubyte;
|
alias u8 = ubyte;
|
||||||
alias u16 = ushort;
|
alias u16 = ushort;
|
||||||
alias u32 = uint;
|
alias u32 = uint;
|
||||||
alias u64 = ulong;
|
alias u64 = ulong;
|
||||||
|
|
||||||
alias f32 = float;
|
alias f32 = float;
|
||||||
alias f64 = double;
|
alias f64 = double;
|
||||||
|
|
||||||
alias b32 = uint;
|
alias b32 = uint;
|
||||||
|
|
||||||
alias intptr = i64;
|
alias intptr = i64;
|
||||||
alias uintptr = u64;
|
alias uintptr = u64;
|
||||||
|
|
||||||
alias usize = size_t;
|
alias usize = size_t;
|
||||||
|
|
||||||
alias Vec2 = Vector!(f32, 2);
|
alias Vec2 = Vector!(f32, 2);
|
||||||
alias Vec3 = Vector!(f32, 3);
|
alias Vec3 = Vector!(f32, 3);
|
||||||
alias Vec4 = Vector!(f32, 4);
|
alias Vec4 = Vector!(f32, 4);
|
||||||
|
|
||||||
alias DVec2 = Vector!(f64, 2);
|
alias DVec2 = Vector!(f64, 2);
|
||||||
alias DVec3 = Vector!(f64, 3);
|
alias DVec3 = Vector!(f64, 3);
|
||||||
alias DVec4 = Vector!(f64, 4);
|
alias DVec4 = Vector!(f64, 4);
|
||||||
|
|
||||||
alias IVec2 = Vector!(i32, 2);
|
alias IVec2 = Vector!(i32, 2);
|
||||||
alias IVec3 = Vector!(i32, 3);
|
alias IVec3 = Vector!(i32, 3);
|
||||||
alias IVec4 = Vector!(i32, 4);
|
alias IVec4 = Vector!(i32, 4);
|
||||||
|
|
||||||
alias I8Vec2 = Vector!(i8, 2);
|
alias I8Vec2 = Vector!(i8, 2);
|
||||||
alias I8Vec3 = Vector!(i8, 3);
|
alias I8Vec3 = Vector!(i8, 3);
|
||||||
alias I8Vec4 = Vector!(i8, 4);
|
alias I8Vec4 = Vector!(i8, 4);
|
||||||
|
|
||||||
alias I16Vec2 = Vector!(i16, 2);
|
alias I16Vec2 = Vector!(i16, 2);
|
||||||
alias I16Vec3 = Vector!(i16, 3);
|
alias I16Vec3 = Vector!(i16, 3);
|
||||||
@ -61,13 +75,13 @@ alias I64Vec2 = Vector!(i64, 2);
|
|||||||
alias I64Vec3 = Vector!(i64, 3);
|
alias I64Vec3 = Vector!(i64, 3);
|
||||||
alias I64Vec4 = Vector!(i64, 4);
|
alias I64Vec4 = Vector!(i64, 4);
|
||||||
|
|
||||||
alias UVec2 = Vector!(u32, 2);
|
alias UVec2 = Vector!(u32, 2);
|
||||||
alias UVec3 = Vector!(u32, 3);
|
alias UVec3 = Vector!(u32, 3);
|
||||||
alias UVec4 = Vector!(u32, 4);
|
alias UVec4 = Vector!(u32, 4);
|
||||||
|
|
||||||
alias U8Vec2 = Vector!(u8, 2);
|
alias U8Vec2 = Vector!(u8, 2);
|
||||||
alias U8Vec3 = Vector!(u8, 3);
|
alias U8Vec3 = Vector!(u8, 3);
|
||||||
alias U8Vec4 = Vector!(u8, 4);
|
alias U8Vec4 = Vector!(u8, 4);
|
||||||
|
|
||||||
alias U16Vec2 = Vector!(u16, 2);
|
alias U16Vec2 = Vector!(u16, 2);
|
||||||
alias U16Vec3 = Vector!(u16, 3);
|
alias U16Vec3 = Vector!(u16, 3);
|
||||||
@ -81,10 +95,345 @@ alias U64Vec2 = Vector!(u64, 2);
|
|||||||
alias U64Vec3 = Vector!(u64, 3);
|
alias U64Vec3 = Vector!(u64, 3);
|
||||||
alias U64Vec4 = Vector!(u64, 4);
|
alias U64Vec4 = Vector!(u64, 4);
|
||||||
|
|
||||||
alias Mat2 = Matrix!(f32, 2);
|
alias Mat2 = Matrix!(f32, 2);
|
||||||
alias Mat3 = Matrix!(f32, 3);
|
alias Mat3 = Matrix!(f32, 3);
|
||||||
alias Mat4 = Matrix!(f32, 4);
|
alias Mat4 = Matrix!(f32, 4);
|
||||||
|
|
||||||
alias DMat2 = Matrix!(f64, 2);
|
alias DMat2 = Matrix!(f64, 2);
|
||||||
alias DMat3 = Matrix!(f64, 3);
|
alias DMat3 = Matrix!(f64, 3);
|
||||||
alias DMat4 = Matrix!(f64, 4);
|
alias DMat4 = Matrix!(f64, 4);
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
enum bool isFloatingPoint(T) = __traits(isFloating, T) && is(T: real);
|
||||||
|
enum bool isSigned(T) = __traits(isArithmetic, T) && !__traits(isUnsigned, 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) && !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 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)
|
||||||
|
{
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
version (StdDdoc)
|
||||||
|
{
|
||||||
|
template Unqual(T)
|
||||||
|
{
|
||||||
|
import core.internal.traits : CoreUnqual = Unqual;
|
||||||
|
alias Unqual = CoreUnqual!(T);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
import core.internal.traits : CoreUnqual = Unqual;
|
||||||
|
alias Unqual = CoreUnqual;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These apply to all floating-point types
|
||||||
|
version (LittleEndian)
|
||||||
|
{
|
||||||
|
enum MANTISSA_LSB = 0;
|
||||||
|
enum MANTISSA_MSB = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enum MANTISSA_LSB = 1;
|
||||||
|
enum MANTISSA_MSB = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool isInfinity(X)(X x) @nogc @trusted pure nothrow
|
||||||
|
if (isFloatingPoint!(X))
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isNaN(X)(X x) @nogc @trusted pure nothrow
|
||||||
|
if (isFloatingPoint!(X))
|
||||||
|
{
|
||||||
|
version (all)
|
||||||
|
{
|
||||||
|
return x != x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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; });
|
||||||
|
|
||||||
|
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 isStaticArray(T) = __traits(isStaticArray, T);
|
||||||
|
|
||||||
|
enum isArray(T) = isStaticArray!T || isDynamicArray!T;
|
||||||
|
|
||||||
|
*/
|
||||||
|
|||||||
39
alloc.d
39
alloc.d
@ -5,9 +5,14 @@ import dlib.math;
|
|||||||
import dlib.platform;
|
import dlib.platform;
|
||||||
import dlib.util;
|
import dlib.util;
|
||||||
|
|
||||||
import std.stdio;
|
version(WebAssembly)
|
||||||
import core.stdc.string : memset;
|
{
|
||||||
import core.memory;
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
import core.memory : malloc = pureMalloc, realloc = pureRealloc, free = pureFree;
|
||||||
|
}
|
||||||
|
|
||||||
static Scratch g_scratch;
|
static Scratch g_scratch;
|
||||||
static u64 g_scratch_index;
|
static u64 g_scratch_index;
|
||||||
@ -76,16 +81,16 @@ MFree(T)(T[] slice)
|
|||||||
T*
|
T*
|
||||||
Alloc(T)()
|
Alloc(T)()
|
||||||
{
|
{
|
||||||
void* mem = pureMalloc(T.sizeof);
|
void* mem = malloc(T.sizeof);
|
||||||
memset(mem, 0, T.sizeof);
|
MemSet(mem, 0, T.sizeof);
|
||||||
return (cast(T*)mem);
|
return (cast(T*)mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
T[]
|
T[]
|
||||||
Alloc(T)(u64 count)
|
Alloc(T)(usize count)
|
||||||
{
|
{
|
||||||
void* mem = pureMalloc(T.sizeof * count);
|
void* mem = malloc(T.sizeof * count);
|
||||||
memset(mem, 0, T.sizeof * count);
|
MemSet(mem, 0, T.sizeof * count);
|
||||||
return (cast(T*)mem)[0 .. count];
|
return (cast(T*)mem)[0 .. count];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +98,7 @@ T[]
|
|||||||
Alloc(T)(T[] target)
|
Alloc(T)(T[] target)
|
||||||
{
|
{
|
||||||
T[] arr = Alloc!(T)(target.length);
|
T[] arr = Alloc!(T)(target.length);
|
||||||
arr[] = target[];
|
arr[] = target[];
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,20 +137,20 @@ Alloc(T)(u64 count, T set)
|
|||||||
T[]
|
T[]
|
||||||
Realloc(T)(T[] arr, u64 count)
|
Realloc(T)(T[] arr, u64 count)
|
||||||
{
|
{
|
||||||
void* mem = pureRealloc(arr.ptr, T.sizeof * count);
|
void* mem = realloc(arr.ptr, T.sizeof * count);
|
||||||
return (cast(T*)mem)[0 .. count];
|
return (cast(T*)mem)[0 .. count];
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Free(T)(T[] arr)
|
Free(T)(T[] arr)
|
||||||
{
|
{
|
||||||
pureFree(arr.ptr);
|
free(arr.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Free(T)(T* ptr)
|
Free(T)(T* ptr)
|
||||||
{
|
{
|
||||||
pureFree(ptr);
|
free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Arena
|
Arena
|
||||||
@ -257,8 +262,8 @@ T[]
|
|||||||
Alloc(T)(Arena* arena, u64 count)
|
Alloc(T)(Arena* arena, u64 count)
|
||||||
{
|
{
|
||||||
void* mem = AllocAlign(arena, T.sizeof * count, DEFAULT_ALIGNMENT);
|
void* mem = AllocAlign(arena, T.sizeof * count, DEFAULT_ALIGNMENT);
|
||||||
memset(mem, 0, T.sizeof * count);
|
MemSet(mem, 0, T.sizeof * count);
|
||||||
return (cast(T*)mem)[0 .. count];
|
return (cast(T*)mem)[0 .. cast(usize)count];
|
||||||
}
|
}
|
||||||
|
|
||||||
T[]
|
T[]
|
||||||
@ -305,7 +310,7 @@ T*
|
|||||||
Alloc(T)(Arena* arena)
|
Alloc(T)(Arena* arena)
|
||||||
{
|
{
|
||||||
void* mem = AllocAlign(arena, T.sizeof, DEFAULT_ALIGNMENT);
|
void* mem = AllocAlign(arena, T.sizeof, DEFAULT_ALIGNMENT);
|
||||||
memset(mem, 0, T.sizeof);
|
MemSet(mem, 0, T.sizeof);
|
||||||
return cast(T*)mem;
|
return cast(T*)mem;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -413,7 +418,7 @@ ScratchAlloc(string target)
|
|||||||
}
|
}
|
||||||
|
|
||||||
T[]
|
T[]
|
||||||
ScratchAlloc(T)(T[] target, u64 start, u64 len)
|
ScratchAlloc(T)(T[] target, usize start, usize len)
|
||||||
{
|
{
|
||||||
T[] arr = ScratchAlloc!(T)(len);
|
T[] arr = ScratchAlloc!(T)(len);
|
||||||
arr[0 .. $] = target[start .. start+len];
|
arr[0 .. $] = target[start .. start+len];
|
||||||
@ -421,7 +426,7 @@ ScratchAlloc(T)(T[] target, u64 start, u64 len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
string
|
string
|
||||||
ScratchAlloc(string target, u64 start, u64 len)
|
ScratchAlloc(string target, usize start, usize len)
|
||||||
{
|
{
|
||||||
u8[] str = ScratchAlloc!(u8)(len);
|
u8[] str = ScratchAlloc!(u8)(len);
|
||||||
str[0 .. $] = cast(u8[])target[start .. start+len];
|
str[0 .. $] = cast(u8[])target[start .. start+len];
|
||||||
|
|||||||
144
assets.d
144
assets.d
@ -1,46 +1,50 @@
|
|||||||
module dlib.assets;
|
module dlib.assets;
|
||||||
|
|
||||||
import dlibincludes : cgltf_result,
|
|
||||||
cgltf_memory_options,
|
|
||||||
cgltf_file_options,
|
|
||||||
cgltf_size,
|
|
||||||
cgltf_image,
|
|
||||||
cgltf_accessor,
|
|
||||||
cgltf_result_success,
|
|
||||||
cgltf_result_io_error,
|
|
||||||
cgltf_free,
|
|
||||||
cgltf_options,
|
|
||||||
cgltf_node,
|
|
||||||
cgltf_load_buffers,
|
|
||||||
cgltf_data,
|
|
||||||
cgltf_load_buffer_base64,
|
|
||||||
stbi_image_free,
|
|
||||||
stbi_load_from_memory,
|
|
||||||
cgltf_primitive_type_triangles,
|
|
||||||
cgltf_node_transform_world,
|
|
||||||
cgltf_float,
|
|
||||||
cgltf_mesh,
|
|
||||||
cgltf_parse,
|
|
||||||
cgltf_attribute_type_position,
|
|
||||||
cgltf_type_vec3,
|
|
||||||
cgltf_component_type_r_32f,
|
|
||||||
cgltf_attribute_type_normal,
|
|
||||||
cgltf_attribute_type_tangent,
|
|
||||||
cgltf_type_vec4,
|
|
||||||
cgltf_attribute_type_texcoord,
|
|
||||||
cgltf_type_vec2,
|
|
||||||
cgltf_component_type_r_8u,
|
|
||||||
cgltf_component_type_r_16u,
|
|
||||||
cgltf_attribute_type_color,
|
|
||||||
cgltf_component_type_r_32u;
|
|
||||||
import dlib.aliases;
|
import dlib.aliases;
|
||||||
|
|
||||||
|
static if(NativeTarget)
|
||||||
|
{
|
||||||
|
|
||||||
|
import dlibincludes : cgltf_result,
|
||||||
|
cgltf_memory_options,
|
||||||
|
cgltf_file_options,
|
||||||
|
cgltf_size,
|
||||||
|
cgltf_image,
|
||||||
|
cgltf_accessor,
|
||||||
|
cgltf_result_success,
|
||||||
|
cgltf_result_io_error,
|
||||||
|
cgltf_free,
|
||||||
|
cgltf_options,
|
||||||
|
cgltf_node,
|
||||||
|
cgltf_load_buffers,
|
||||||
|
cgltf_data,
|
||||||
|
cgltf_load_buffer_base64,
|
||||||
|
stbi_image_free,
|
||||||
|
stbi_load_from_memory,
|
||||||
|
cgltf_primitive_type_triangles,
|
||||||
|
cgltf_node_transform_world,
|
||||||
|
cgltf_float,
|
||||||
|
cgltf_mesh,
|
||||||
|
cgltf_parse,
|
||||||
|
cgltf_attribute_type_position,
|
||||||
|
cgltf_type_vec3,
|
||||||
|
cgltf_component_type_r_32f,
|
||||||
|
cgltf_attribute_type_normal,
|
||||||
|
cgltf_attribute_type_tangent,
|
||||||
|
cgltf_type_vec4,
|
||||||
|
cgltf_attribute_type_texcoord,
|
||||||
|
cgltf_type_vec2,
|
||||||
|
cgltf_component_type_r_8u,
|
||||||
|
cgltf_component_type_r_16u,
|
||||||
|
cgltf_attribute_type_color,
|
||||||
|
cgltf_component_type_r_32u;
|
||||||
import dlib.util;
|
import dlib.util;
|
||||||
import dlib.alloc;
|
import dlib.alloc;
|
||||||
import dlib.math;
|
import dlib.math;
|
||||||
|
|
||||||
|
import std.format;
|
||||||
import std.file;
|
import std.file;
|
||||||
import std.path;
|
import std.path;
|
||||||
import std.format;
|
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
import core.stdc.string : strlen;
|
import core.stdc.string : strlen;
|
||||||
import core.stdc.stdio : File = FILE, FOpen = fopen, FSeek = fseek, FTell = ftell, FClose = fclose, FRead = fread, SeekSet = SEEK_SET, SeekEnd = SEEK_END;
|
import core.stdc.stdio : File = FILE, FOpen = fopen, FSeek = fseek, FTell = ftell, FClose = fclose, FRead = fread, SeekSet = SEEK_SET, SeekEnd = SEEK_END;
|
||||||
@ -144,14 +148,14 @@ struct Mesh
|
|||||||
|
|
||||||
__gshared string g_BASE_ASSETS_DIR;
|
__gshared string g_BASE_ASSETS_DIR;
|
||||||
|
|
||||||
static u32
|
static u32
|
||||||
MagicValue(string str)
|
MagicValue(string str)
|
||||||
{
|
{
|
||||||
assert(str.length == 4, "Magic value must 4 characters");
|
assert(str.length == 4, "Magic value must 4 characters");
|
||||||
return cast(u32)(cast(u32)(str[0] << 24) | cast(u32)(str[1] << 16) | cast(u32)(str[2] << 8) | cast(u32)(str[3] << 0));
|
return cast(u32)(cast(u32)(str[0] << 24) | cast(u32)(str[1] << 16) | cast(u32)(str[2] << 8) | cast(u32)(str[3] << 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SetBaseAssetsDir(string dir)
|
SetBaseAssetsDir(string dir)
|
||||||
{
|
{
|
||||||
if(!isDir(dir))
|
if(!isDir(dir))
|
||||||
@ -162,7 +166,7 @@ SetBaseAssetsDir(string dir)
|
|||||||
g_BASE_ASSETS_DIR = dir;
|
g_BASE_ASSETS_DIR = dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
U32ColToVec4(u32 col, Vec4* vec)
|
U32ColToVec4(u32 col, Vec4* vec)
|
||||||
{
|
{
|
||||||
if(!col)
|
if(!col)
|
||||||
@ -222,7 +226,7 @@ GLTFFreeCallback(cgltf_memory_options* memory_opts, cgltf_file_options* file_opt
|
|||||||
Free(data);
|
Free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageData
|
ImageData
|
||||||
LoadImage(void* data, i32 size)
|
LoadImage(void* data, i32 size)
|
||||||
{
|
{
|
||||||
ImageData image;
|
ImageData image;
|
||||||
@ -251,7 +255,7 @@ LoadImage(void* data, i32 size)
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
UnloadImage(ImageData* image)
|
UnloadImage(ImageData* image)
|
||||||
{
|
{
|
||||||
version(NO_STBI) {}
|
version(NO_STBI) {}
|
||||||
@ -261,7 +265,7 @@ UnloadImage(ImageData* image)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageData
|
ImageData
|
||||||
LoadImage(cgltf_image* asset_image, string tex_path)
|
LoadImage(cgltf_image* asset_image, string tex_path)
|
||||||
{
|
{
|
||||||
ImageData image;
|
ImageData image;
|
||||||
@ -335,7 +339,7 @@ LoadImage(cgltf_image* asset_image, string tex_path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PostTypeCheck:
|
PostTypeCheck:
|
||||||
u8[] image_data;
|
u8[] image_data;
|
||||||
if(accepted)
|
if(accepted)
|
||||||
{
|
{
|
||||||
@ -359,7 +363,7 @@ LoadImage(cgltf_image* asset_image, string tex_path)
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelData
|
ModelData
|
||||||
LoadGLTF(Arena* arena, string file_name)
|
LoadGLTF(Arena* arena, string file_name)
|
||||||
{
|
{
|
||||||
ModelData model;
|
ModelData model;
|
||||||
@ -616,11 +620,11 @@ LoadGLTF(Arena* arena, string file_name)
|
|||||||
for(u64 k = 0; k < model.meshes[mesh_index].vtx.length; k += 1)
|
for(u64 k = 0; k < model.meshes[mesh_index].vtx.length; k += 1)
|
||||||
{
|
{
|
||||||
model.meshes[mesh_index].vtx[k].color = Vec4(
|
model.meshes[mesh_index].vtx[k].color = Vec4(
|
||||||
cast(f32)(buffer[k*3+0])/255.0,
|
cast(f32)(buffer[k*3+0])/255.0,
|
||||||
cast(f32)(buffer[k*3+1])/255.0,
|
cast(f32)(buffer[k*3+1])/255.0,
|
||||||
cast(f32)(buffer[k*3+2])/255.0,
|
cast(f32)(buffer[k*3+2])/255.0,
|
||||||
1.0
|
1.0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(attr.component_type == cgltf_component_type_r_16u)
|
else if(attr.component_type == cgltf_component_type_r_16u)
|
||||||
@ -629,11 +633,11 @@ LoadGLTF(Arena* arena, string file_name)
|
|||||||
for(u64 k = 0; k < model.meshes[mesh_index].vtx.length; k += 1)
|
for(u64 k = 0; k < model.meshes[mesh_index].vtx.length; k += 1)
|
||||||
{
|
{
|
||||||
model.meshes[mesh_index].vtx[k].color = Vec4(
|
model.meshes[mesh_index].vtx[k].color = Vec4(
|
||||||
cast(f32)(buffer[k*3+0])/65535.0,
|
cast(f32)(buffer[k*3+0])/65535.0,
|
||||||
cast(f32)(buffer[k*3+1])/65535.0,
|
cast(f32)(buffer[k*3+1])/65535.0,
|
||||||
cast(f32)(buffer[k*3+2])/65535.0,
|
cast(f32)(buffer[k*3+2])/65535.0,
|
||||||
1.0
|
1.0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(attr.component_type == cgltf_component_type_r_32f)
|
else if(attr.component_type == cgltf_component_type_r_32f)
|
||||||
@ -657,11 +661,11 @@ LoadGLTF(Arena* arena, string file_name)
|
|||||||
for(u64 k = 0; k < model.meshes[mesh_index].vtx.length; k += 1)
|
for(u64 k = 0; k < model.meshes[mesh_index].vtx.length; k += 1)
|
||||||
{
|
{
|
||||||
model.meshes[mesh_index].vtx[k].color = Vec4(
|
model.meshes[mesh_index].vtx[k].color = Vec4(
|
||||||
cast(f32)(buffer[k*4+0])/255.0,
|
cast(f32)(buffer[k*4+0])/255.0,
|
||||||
cast(f32)(buffer[k*4+1])/255.0,
|
cast(f32)(buffer[k*4+1])/255.0,
|
||||||
cast(f32)(buffer[k*4+2])/255.0,
|
cast(f32)(buffer[k*4+2])/255.0,
|
||||||
cast(f32)(buffer[k*4+3])/255.0
|
cast(f32)(buffer[k*4+3])/255.0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(attr.component_type == cgltf_component_type_r_16u)
|
else if(attr.component_type == cgltf_component_type_r_16u)
|
||||||
@ -670,11 +674,11 @@ LoadGLTF(Arena* arena, string file_name)
|
|||||||
for(u64 k = 0; k < model.meshes[mesh_index].vtx.length; k += 1)
|
for(u64 k = 0; k < model.meshes[mesh_index].vtx.length; k += 1)
|
||||||
{
|
{
|
||||||
model.meshes[mesh_index].vtx[k].color = Vec4(
|
model.meshes[mesh_index].vtx[k].color = Vec4(
|
||||||
cast(f32)(buffer[k*4+0])/65535.0,
|
cast(f32)(buffer[k*4+0])/65535.0,
|
||||||
cast(f32)(buffer[k*4+1])/65535.0,
|
cast(f32)(buffer[k*4+1])/65535.0,
|
||||||
cast(f32)(buffer[k*4+2])/65535.0,
|
cast(f32)(buffer[k*4+2])/65535.0,
|
||||||
cast(f32)(buffer[k*4+3])/65535.0
|
cast(f32)(buffer[k*4+3])/65535.0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(attr.component_type == cgltf_component_type_r_32f)
|
else if(attr.component_type == cgltf_component_type_r_32f)
|
||||||
@ -689,7 +693,7 @@ LoadGLTF(Arena* arena, string file_name)
|
|||||||
{
|
{
|
||||||
Logf("Color component type [%s] not supported", attr.component_type);
|
Logf("Color component type [%s] not supported", attr.component_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
@ -705,7 +709,7 @@ LoadGLTF(Arena* arena, string file_name)
|
|||||||
|
|
||||||
model.meshes[mesh_index].idx = model.idx_buf[idx_index .. idx_index+attr.count];
|
model.meshes[mesh_index].idx = model.idx_buf[idx_index .. idx_index+attr.count];
|
||||||
idx_index += attr.count;
|
idx_index += attr.count;
|
||||||
|
|
||||||
if(attr.component_type == cgltf_component_type_r_16u)
|
if(attr.component_type == cgltf_component_type_r_16u)
|
||||||
{
|
{
|
||||||
u16* buffer = GetGLTFBuffer!(u16)(attr);
|
u16* buffer = GetGLTFBuffer!(u16)(attr);
|
||||||
@ -754,7 +758,7 @@ LoadGLTF(Arena* arena, string file_name)
|
|||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
AddMeshVertices(cgltf_accessor* accessor, ModelData* model, u64 mesh_index, u64* vtx_count)
|
AddMeshVertices(cgltf_accessor* accessor, ModelData* model, u64 mesh_index, u64* vtx_count)
|
||||||
{
|
{
|
||||||
if(model.meshes[mesh_index].vtx == null)
|
if(model.meshes[mesh_index].vtx == null)
|
||||||
@ -766,17 +770,17 @@ AddMeshVertices(cgltf_accessor* accessor, ModelData* model, u64 mesh_index, u64*
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
T*
|
T*
|
||||||
GetGLTFBuffer(T)(cgltf_accessor* accessor)
|
GetGLTFBuffer(T)(cgltf_accessor* accessor)
|
||||||
{
|
{
|
||||||
return cast(T*)(accessor.buffer_view.buffer.data) + (accessor.buffer_view.offset/T.sizeof) + (accessor.offset/T.sizeof);
|
return cast(T*)(accessor.buffer_view.buffer.data) + (accessor.buffer_view.offset/T.sizeof) + (accessor.offset/T.sizeof);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ImageData
|
static ImageData
|
||||||
GenerateDefaultTexture(u32 x, u32 y)
|
GenerateDefaultTexture(u32 x, u32 y)
|
||||||
{
|
{
|
||||||
ImageData data = {
|
ImageData data = {
|
||||||
w: x,
|
w: x,
|
||||||
h: y,
|
h: y,
|
||||||
ch: 4,
|
ch: 4,
|
||||||
};
|
};
|
||||||
@ -802,7 +806,7 @@ GenerateDefaultTexture(u32 x, u32 y)
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Material
|
static Material
|
||||||
GenerateDefaultMaterial()
|
GenerateDefaultMaterial()
|
||||||
{
|
{
|
||||||
Material mat;
|
Material mat;
|
||||||
@ -813,4 +817,4 @@ GenerateDefaultMaterial()
|
|||||||
return mat;
|
return mat;
|
||||||
}
|
}
|
||||||
|
|
||||||
import std.exception;
|
}
|
||||||
|
|||||||
13
build.sh
13
build.sh
@ -70,3 +70,16 @@ if ! [ -f "${build}/libcgltf.a" ]; then
|
|||||||
ar rcs $lib $obj
|
ar rcs $lib $obj
|
||||||
rm $obj
|
rm $obj
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# XXHASH
|
||||||
|
src="${script_dir}/external/xxhash/xxhash.c"
|
||||||
|
flags="-std=c99 -Wno-everything -Iexternal/xxhash -c -static"
|
||||||
|
obj="${build}/xxhash.o"
|
||||||
|
lib="${build}/libxxhash.a"
|
||||||
|
|
||||||
|
if ! [ -f $lib ]; then
|
||||||
|
$c_compiler $flags $src $out $obj
|
||||||
|
ar rcs $lib $obj
|
||||||
|
rm $obj
|
||||||
|
fi
|
||||||
|
|||||||
@ -17,9 +17,17 @@
|
|||||||
# include FT_GLYPH_H
|
# include FT_GLYPH_H
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef NO_STBI
|
#if !defined(NO_STBI) && !defined(BUILD_WASM)
|
||||||
# include "external/stb/stb_image.h"
|
# include "external/stb/stb_image.h"
|
||||||
# include "external/stb/stb_image_write.h"
|
# include "external/stb/stb_image_write.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BUILD_WASM
|
||||||
|
# define CGLM_FORCE_DEPTH_ZERO_TO_ONE
|
||||||
|
# include "external/cglm/cglm.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NO_STBI
|
||||||
# include "external/stb/stb_truetype.h"
|
# include "external/stb/stb_truetype.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -27,8 +35,12 @@
|
|||||||
# include "../VulkanRenderer/vulkan_includes.c"
|
# include "../VulkanRenderer/vulkan_includes.c"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define CGLM_FORCE_DEPTH_ZERO_TO_ONE
|
|
||||||
#include "external/cglm/cglm.h"
|
|
||||||
|
|
||||||
#include "external/cgltf/cgltf.h"
|
#include "external/cgltf/cgltf.h"
|
||||||
|
|
||||||
|
#define PRINTF_SUPPORT_FLOAT
|
||||||
|
#include "external/printf/printf.c"
|
||||||
|
|
||||||
|
#define XXH_NO_STDLIB 1
|
||||||
|
#define XXH_STATIC_LINKING_ONLY 1
|
||||||
|
#include "external/xxhash/xxhash.h"
|
||||||
|
|||||||
224
external/arsd-webassembly/arsd/color.d
vendored
Normal file
224
external/arsd-webassembly/arsd/color.d
vendored
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
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
Normal file
8
external/arsd-webassembly/arsd/simpleaudio.d
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
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
Normal file
315
external/arsd-webassembly/arsd/simpledisplay.d
vendored
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
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
Normal file
178
external/arsd-webassembly/arsd/webassembly.d
vendored
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
/+
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
778
external/arsd-webassembly/core/arsd/aa.d
vendored
Normal file
778
external/arsd-webassembly/core/arsd/aa.d
vendored
Normal file
@ -0,0 +1,778 @@
|
|||||||
|
/**
|
||||||
|
* Implementation of associative arrays.
|
||||||
|
*
|
||||||
|
* Copyright: Copyright Digital Mars 2000 - 2015.
|
||||||
|
* License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
|
||||||
|
* Authors: Martin Nowak
|
||||||
|
* Source: $(DRUNTIMESRC rt/_aaA.d)
|
||||||
|
*/
|
||||||
|
module core.arsd.aa;
|
||||||
|
|
||||||
|
/// AA version for debuggers, bump whenever changing the layout
|
||||||
|
extern (C) immutable int _aaVersion = 1;
|
||||||
|
|
||||||
|
import core.internal.hash;
|
||||||
|
import core.arsd.memory_allocation;
|
||||||
|
|
||||||
|
uint min(uint a, uint b) { return a < b ? a : b; }
|
||||||
|
uint max(uint a, uint b) { return a > b ? a : b; }
|
||||||
|
|
||||||
|
// grow threshold
|
||||||
|
private enum GROW_NUM = 4;
|
||||||
|
private enum GROW_DEN = 5;
|
||||||
|
// shrink threshold
|
||||||
|
private enum SHRINK_NUM = 1;
|
||||||
|
private enum SHRINK_DEN = 8;
|
||||||
|
// grow factor
|
||||||
|
private enum GROW_FAC = 4;
|
||||||
|
// growing the AA doubles it's size, so the shrink threshold must be
|
||||||
|
// smaller than half the grow threshold to have a hysteresis
|
||||||
|
static assert(GROW_FAC * SHRINK_NUM * GROW_DEN < GROW_NUM * SHRINK_DEN);
|
||||||
|
// initial load factor (for literals), mean of both thresholds
|
||||||
|
private enum INIT_NUM = (GROW_DEN * SHRINK_NUM + GROW_NUM * SHRINK_DEN) / 2;
|
||||||
|
private enum INIT_DEN = SHRINK_DEN * GROW_DEN;
|
||||||
|
|
||||||
|
private enum INIT_NUM_BUCKETS = 8;
|
||||||
|
// magic hash constants to distinguish empty, deleted, and filled buckets
|
||||||
|
private enum HASH_EMPTY = 0;
|
||||||
|
private enum HASH_DELETED = 0x1;
|
||||||
|
private enum HASH_FILLED_MARK = size_t(1) << 8 * size_t.sizeof - 1;
|
||||||
|
|
||||||
|
// The compiler uses `void*` for its prototypes.
|
||||||
|
// Don't wrap in a struct to maintain ABI compatibility.
|
||||||
|
alias AA = Impl*;
|
||||||
|
|
||||||
|
private bool empty(scope const AA impl) pure nothrow @nogc
|
||||||
|
{
|
||||||
|
return impl is null || !impl.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct Impl
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
this(scope const TypeInfo_AssociativeArray ti, size_t sz = INIT_NUM_BUCKETS)
|
||||||
|
{
|
||||||
|
keysz = cast(uint) ti.key.size;
|
||||||
|
valsz = cast(uint) ti.value.size;
|
||||||
|
buckets = allocBuckets(sz);
|
||||||
|
firstUsed = cast(uint) buckets.length;
|
||||||
|
valoff = cast(uint) talign(keysz, ti.value.talign);
|
||||||
|
|
||||||
|
import core.arsd.objectutils : hasPostblit;
|
||||||
|
|
||||||
|
if (hasPostblit(cast()ti.key))
|
||||||
|
flags |= Flags.keyHasPostblit;
|
||||||
|
if ((ti.key.flags | ti.value.flags) & 1)
|
||||||
|
flags |= Flags.hasPointers;
|
||||||
|
|
||||||
|
entryTI = fakeEntryTI(this, ti.key, ti.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bucket[] buckets;
|
||||||
|
uint used;
|
||||||
|
uint deleted;
|
||||||
|
TypeInfo_Struct entryTI;
|
||||||
|
uint firstUsed;
|
||||||
|
immutable uint keysz;
|
||||||
|
immutable uint valsz;
|
||||||
|
immutable uint valoff;
|
||||||
|
Flags flags;
|
||||||
|
|
||||||
|
enum Flags : ubyte
|
||||||
|
{
|
||||||
|
none = 0x0,
|
||||||
|
keyHasPostblit = 0x1,
|
||||||
|
hasPointers = 0x2,
|
||||||
|
}
|
||||||
|
|
||||||
|
@property size_t length() const pure nothrow @nogc
|
||||||
|
{
|
||||||
|
assert(used >= deleted);
|
||||||
|
return used - deleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property size_t dim() const pure nothrow @nogc @safe
|
||||||
|
{
|
||||||
|
return buckets.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property size_t mask() const pure nothrow @nogc
|
||||||
|
{
|
||||||
|
return dim - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the first slot to insert a value with hash
|
||||||
|
inout(Bucket)* findSlotInsert(size_t hash) inout pure nothrow @nogc
|
||||||
|
{
|
||||||
|
for (size_t i = hash & mask, j = 1;; ++j)
|
||||||
|
{
|
||||||
|
if (!buckets[i].filled)
|
||||||
|
return &buckets[i];
|
||||||
|
i = (i + j) & mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lookup a key
|
||||||
|
inout(Bucket)* findSlotLookup(size_t hash, scope const void* pkey, scope const TypeInfo keyti) inout
|
||||||
|
{
|
||||||
|
for (size_t i = hash & mask, j = 1;; ++j)
|
||||||
|
{
|
||||||
|
if (buckets[i].hash == hash && keyti.equals(pkey, buckets[i].entry))
|
||||||
|
return &buckets[i];
|
||||||
|
else if (buckets[i].empty)
|
||||||
|
return null;
|
||||||
|
i = (i + j) & mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void grow(scope const TypeInfo keyti)
|
||||||
|
{
|
||||||
|
// If there are so many deleted entries, that growing would push us
|
||||||
|
// below the shrink threshold, we just purge deleted entries instead.
|
||||||
|
if (length * SHRINK_DEN < GROW_FAC * dim * SHRINK_NUM)
|
||||||
|
resize(dim);
|
||||||
|
else
|
||||||
|
resize(GROW_FAC * dim);
|
||||||
|
}
|
||||||
|
|
||||||
|
void shrink(scope const TypeInfo keyti)
|
||||||
|
{
|
||||||
|
if (dim > INIT_NUM_BUCKETS)
|
||||||
|
resize(dim / GROW_FAC);
|
||||||
|
}
|
||||||
|
|
||||||
|
void resize(size_t ndim)
|
||||||
|
{
|
||||||
|
auto obuckets = buckets;
|
||||||
|
buckets = allocBuckets(ndim);
|
||||||
|
|
||||||
|
foreach (ref b; obuckets[firstUsed .. $])
|
||||||
|
if (b.filled)
|
||||||
|
*findSlotInsert(b.hash) = b;
|
||||||
|
|
||||||
|
firstUsed = 0;
|
||||||
|
used -= deleted;
|
||||||
|
deleted = 0;
|
||||||
|
free(cast(ubyte*)(obuckets.ptr)); // safe to free b/c impossible to reference
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() pure nothrow
|
||||||
|
{
|
||||||
|
import core.stdc.string : memset;
|
||||||
|
// clear all data, but don't change bucket array length
|
||||||
|
memset(&buckets[firstUsed], 0, (buckets.length - firstUsed) * Bucket.sizeof);
|
||||||
|
deleted = used = 0;
|
||||||
|
firstUsed = cast(uint) dim;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// Bucket
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
private struct Bucket
|
||||||
|
{
|
||||||
|
private pure nothrow @nogc:
|
||||||
|
size_t hash;
|
||||||
|
void* entry;
|
||||||
|
|
||||||
|
@property bool empty() const
|
||||||
|
{
|
||||||
|
return hash == HASH_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property bool deleted() const
|
||||||
|
{
|
||||||
|
return hash == HASH_DELETED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property bool filled() const @safe
|
||||||
|
{
|
||||||
|
return cast(ptrdiff_t) hash < 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bucket[] allocBuckets(size_t dim) @trusted
|
||||||
|
{
|
||||||
|
enum attr = 0b0001_0000; //enum attr = GC.BlkAttr.NO_INTERIOR;
|
||||||
|
immutable sz = dim * Bucket.sizeof;
|
||||||
|
return (cast(Bucket*) calloc(sz, attr))[0 .. dim];
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// Entry
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
private void* allocEntry(scope const Impl* aa, scope const void* pkey)
|
||||||
|
{
|
||||||
|
immutable akeysz = aa.valoff;
|
||||||
|
void* res = void;
|
||||||
|
if(aa.entryTI)
|
||||||
|
res = _d_newitemU(aa.entryTI);
|
||||||
|
else
|
||||||
|
res = malloc(akeysz + aa.valsz).ptr;
|
||||||
|
|
||||||
|
memcpy(res, pkey, aa.keysz); // copy key
|
||||||
|
memset(res + akeysz, 0, aa.valsz); // zero value
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
package void entryDtor(void* p, const TypeInfo_Struct sti)
|
||||||
|
{
|
||||||
|
// key and value type info stored after the TypeInfo_Struct by tiEntry()
|
||||||
|
auto sizeti = __traits(classInstanceSize, TypeInfo_Struct);
|
||||||
|
auto extra = cast(const(TypeInfo)*)(cast(void*) sti + sizeti);
|
||||||
|
extra[0].destroy(p);
|
||||||
|
extra[1].destroy(p + talign(extra[0].size, extra[1].talign));
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool hasDtor(const TypeInfo ti) pure nothrow
|
||||||
|
{
|
||||||
|
|
||||||
|
if (typeid(ti) is typeid(TypeInfo_Struct))
|
||||||
|
if ((cast(TypeInfo_Struct) cast(void*) ti).xdtor)
|
||||||
|
return true;
|
||||||
|
if (typeid(ti) is typeid(TypeInfo_StaticArray))
|
||||||
|
return hasDtor(cast()ti.next);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// build type info for Entry with additional key and value fields
|
||||||
|
TypeInfo_Struct fakeEntryTI(ref Impl aa, const TypeInfo keyti, const TypeInfo valti)
|
||||||
|
{
|
||||||
|
import core.arsd.objectutils;
|
||||||
|
//Same as unqualify
|
||||||
|
auto kti = unqualify(keyti);
|
||||||
|
auto vti = unqualify(valti);
|
||||||
|
|
||||||
|
|
||||||
|
bool entryHasDtor = hasDtor(kti) || hasDtor(vti);
|
||||||
|
if (!entryHasDtor)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// save kti and vti after type info for struct
|
||||||
|
enum sizeti = __traits(classInstanceSize, TypeInfo_Struct);
|
||||||
|
void* p = malloc(sizeti + (2) * (void*).sizeof).ptr;
|
||||||
|
|
||||||
|
memcpy(p, __traits(initSymbol, TypeInfo_Struct).ptr, sizeti);
|
||||||
|
|
||||||
|
auto ti = cast(TypeInfo_Struct) p;
|
||||||
|
auto extra = cast(TypeInfo*)(p + sizeti);
|
||||||
|
extra[0] = cast() kti;
|
||||||
|
extra[1] = cast() vti;
|
||||||
|
|
||||||
|
static immutable tiMangledName = "S2rt3aaA__T5EntryZ";
|
||||||
|
ti.name = tiMangledName;
|
||||||
|
|
||||||
|
|
||||||
|
// we don't expect the Entry objects to be used outside of this module, so we have control
|
||||||
|
// over the non-usage of the callback methods and other entries and can keep these null
|
||||||
|
// xtoHash, xopEquals, xopCmp, xtoString and xpostblit
|
||||||
|
immutable entrySize = aa.valoff + aa.valsz;
|
||||||
|
ti.m_init = (cast(ubyte*) null)[0 .. entrySize]; // init length, but not ptr
|
||||||
|
|
||||||
|
if (entryHasDtor)
|
||||||
|
{
|
||||||
|
// xdtor needs to be built from the dtors of key and value for the GC
|
||||||
|
ti.xdtorti = &entryDtor;
|
||||||
|
ti.m_flags |= TypeInfo_Struct.StructFlags.isDynamicType;
|
||||||
|
}
|
||||||
|
|
||||||
|
ti.align_ = cast(uint) max(kti.talign, vti.talign);
|
||||||
|
|
||||||
|
return ti;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// Helper functions
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
private size_t talign(size_t tsize, size_t algn) @safe pure nothrow @nogc
|
||||||
|
{
|
||||||
|
immutable mask = algn - 1;
|
||||||
|
assert(!(mask & algn));
|
||||||
|
return (tsize + mask) & ~mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mix hash to "fix" bad hash functions
|
||||||
|
private size_t mix(size_t h) @safe pure nothrow @nogc
|
||||||
|
{
|
||||||
|
// final mix function of MurmurHash2
|
||||||
|
enum m = 0x5bd1e995;
|
||||||
|
h ^= h >> 13;
|
||||||
|
h *= m;
|
||||||
|
h ^= h >> 15;
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
private size_t calcHash(scope const void* pkey, scope const TypeInfo keyti) nothrow
|
||||||
|
{
|
||||||
|
immutable hash = keyti.getHash(pkey);
|
||||||
|
// highest bit is set to distinguish empty/deleted from filled buckets
|
||||||
|
return mix(hash) | HASH_FILLED_MARK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private size_t nextpow2(const size_t n) pure nothrow @nogc
|
||||||
|
{
|
||||||
|
import core.bitop : bsr;
|
||||||
|
|
||||||
|
if (!n)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
const isPowerOf2 = !((n - 1) & n);
|
||||||
|
return 1 << (bsr(n) + !isPowerOf2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// API Implementation
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Allocate associative array data.
|
||||||
|
* Called for `new SomeAA` expression.
|
||||||
|
* Params:
|
||||||
|
* ti = TypeInfo for the associative array
|
||||||
|
* Returns:
|
||||||
|
* A new associative array.
|
||||||
|
*/
|
||||||
|
extern (C) Impl* _aaNew(const TypeInfo_AssociativeArray ti)
|
||||||
|
{
|
||||||
|
return new Impl(ti);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determine number of entries in associative array.
|
||||||
|
extern (C) size_t _aaLen(scope const AA aa) pure nothrow @nogc
|
||||||
|
{
|
||||||
|
return aa ? aa.length : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************
|
||||||
|
* Lookup *pkey in aa.
|
||||||
|
* Called only from implementation of (aa[key]) expressions when value is mutable.
|
||||||
|
* Params:
|
||||||
|
* paa = associative array opaque pointer
|
||||||
|
* ti = TypeInfo for the associative array
|
||||||
|
* valsz = ignored
|
||||||
|
* pkey = pointer to the key value
|
||||||
|
* Returns:
|
||||||
|
* if key was in the aa, a mutable pointer to the existing value.
|
||||||
|
* If key was not in the aa, a mutable pointer to newly inserted value which
|
||||||
|
* is set to all zeros
|
||||||
|
*/
|
||||||
|
extern (C) void* _aaGetY(scope ubyte** paa, const TypeInfo_AssociativeArray ti,
|
||||||
|
const size_t valsz, scope const void* pkey)
|
||||||
|
{
|
||||||
|
bool found;
|
||||||
|
return _aaGetX(paa, ti, valsz, pkey, found);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************
|
||||||
|
* Lookup *pkey in aa.
|
||||||
|
* Called only from implementation of require
|
||||||
|
* Params:
|
||||||
|
* paa = associative array opaque pointer
|
||||||
|
* ti = TypeInfo for the associative array
|
||||||
|
* valsz = ignored
|
||||||
|
* pkey = pointer to the key value
|
||||||
|
* found = true if the value was found
|
||||||
|
* Returns:
|
||||||
|
* if key was in the aa, a mutable pointer to the existing value.
|
||||||
|
* If key was not in the aa, a mutable pointer to newly inserted value which
|
||||||
|
* is set to all zeros
|
||||||
|
*/
|
||||||
|
extern (C) void* _aaGetX(scope ubyte** paa, const TypeInfo_AssociativeArray ti,
|
||||||
|
const size_t valsz, scope const void* pkey, out bool found)
|
||||||
|
{
|
||||||
|
|
||||||
|
// lazily alloc implementation
|
||||||
|
AA aa = *cast(AA*)paa;
|
||||||
|
if (aa is null)
|
||||||
|
{
|
||||||
|
aa = new Impl(ti);
|
||||||
|
*cast(AA*)paa = aa;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get hash and bucket for key
|
||||||
|
immutable hash = calcHash(pkey, ti.key);
|
||||||
|
|
||||||
|
// found a value => return it
|
||||||
|
if (auto p = aa.findSlotLookup(hash, pkey, ti.key))
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
return p.entry + aa.valoff;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto p = aa.findSlotInsert(hash);
|
||||||
|
if (p.deleted)
|
||||||
|
--aa.deleted;
|
||||||
|
// check load factor and possibly grow
|
||||||
|
else if (++aa.used * GROW_DEN > aa.dim * GROW_NUM)
|
||||||
|
{
|
||||||
|
aa.grow(ti.key);
|
||||||
|
p = aa.findSlotInsert(hash);
|
||||||
|
assert(p.empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update search cache and allocate entry
|
||||||
|
aa.firstUsed = min(aa.firstUsed, cast(uint)(p - aa.buckets.ptr));
|
||||||
|
p.hash = hash;
|
||||||
|
p.entry = allocEntry(aa, pkey);
|
||||||
|
// postblit for key
|
||||||
|
if (aa.flags & Impl.Flags.keyHasPostblit)
|
||||||
|
{
|
||||||
|
import core.arsd.objectutils;
|
||||||
|
__doPostblit(p.entry, aa.keysz, unqualify(ti.key));
|
||||||
|
}
|
||||||
|
// return pointer to value
|
||||||
|
return p.entry + aa.valoff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************
|
||||||
|
* Lookup *pkey in aa.
|
||||||
|
* Called only from implementation of (aa[key]) expressions when value is not mutable.
|
||||||
|
* Params:
|
||||||
|
* aa = associative array opaque pointer
|
||||||
|
* keyti = TypeInfo for the key
|
||||||
|
* valsz = ignored
|
||||||
|
* pkey = pointer to the key value
|
||||||
|
* Returns:
|
||||||
|
* pointer to value if present, null otherwise
|
||||||
|
*/
|
||||||
|
extern (C) inout(void)* _aaGetRvalueX(inout ubyte** aa, scope const TypeInfo keyti, const size_t valsz,
|
||||||
|
scope const void* pkey)
|
||||||
|
{
|
||||||
|
return _aaInX(aa, keyti, pkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************
|
||||||
|
* Lookup *pkey in aa.
|
||||||
|
* Called only from implementation of (key in aa) expressions.
|
||||||
|
* Params:
|
||||||
|
* aa = associative array opaque pointer
|
||||||
|
* keyti = TypeInfo for the key
|
||||||
|
* pkey = pointer to the key value
|
||||||
|
* Returns:
|
||||||
|
* pointer to value if present, null otherwise
|
||||||
|
*/
|
||||||
|
extern (C) inout(void)* _aaInX(inout ubyte** _aa, scope const TypeInfo keyti, scope const void* pkey)
|
||||||
|
{
|
||||||
|
import std.stdio;
|
||||||
|
AA aa = cast(AA)_aa;
|
||||||
|
if (aa.empty)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
immutable hash = calcHash(pkey, keyti);
|
||||||
|
if (auto p = aa.findSlotLookup(hash, pkey, keyti))
|
||||||
|
return cast(inout)(p.entry + aa.valoff);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete entry scope const AA, return true if it was present
|
||||||
|
extern (C) bool _aaDelX(ubyte* _aa, scope const TypeInfo keyti, scope const void* pkey)
|
||||||
|
{
|
||||||
|
AA aa = cast(AA)_aa;
|
||||||
|
if (aa.empty)
|
||||||
|
return false;
|
||||||
|
immutable hash = calcHash(pkey, keyti);
|
||||||
|
if (auto p = aa.findSlotLookup(hash, pkey, keyti))
|
||||||
|
{
|
||||||
|
// clear entry
|
||||||
|
p.hash = HASH_DELETED;
|
||||||
|
p.entry = null;
|
||||||
|
|
||||||
|
++aa.deleted;
|
||||||
|
// `shrink` reallocates, and allocating from a finalizer leads to
|
||||||
|
// InvalidMemoryError: https://issues.dlang.org/show_bug.cgi?id=21442
|
||||||
|
if (aa.length * SHRINK_DEN < aa.dim * SHRINK_NUM) // && !GC.inFinalizer() no GC so never in finalizer
|
||||||
|
aa.shrink(keyti);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove all elements from AA.
|
||||||
|
extern (C) void _aaClear(ubyte* _aa) pure nothrow
|
||||||
|
{
|
||||||
|
AA aa = cast(AA)_aa;
|
||||||
|
if (!aa.empty)
|
||||||
|
{
|
||||||
|
aa.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rehash AA
|
||||||
|
extern (C) void* _aaRehash(ubyte** _paa, scope const TypeInfo keyti)
|
||||||
|
{
|
||||||
|
AA* paa = cast(AA*)_paa;
|
||||||
|
AA aa = *paa;
|
||||||
|
if (!aa.empty)
|
||||||
|
aa.resize(nextpow2(INIT_DEN * aa.length / INIT_NUM));
|
||||||
|
return aa;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a GC allocated array of all values
|
||||||
|
extern (C) inout(void[]) _aaValues(inout ubyte* _aa, const size_t keysz, const size_t valsz,
|
||||||
|
const TypeInfo tiValueArray)
|
||||||
|
{
|
||||||
|
AA aa = cast(AA)_aa;
|
||||||
|
if (aa.empty)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
auto res = _d_newarrayU(tiValueArray, aa.length).ptr;
|
||||||
|
auto pval = res;
|
||||||
|
|
||||||
|
immutable off = aa.valoff;
|
||||||
|
foreach (b; aa.buckets[aa.firstUsed .. $])
|
||||||
|
{
|
||||||
|
if (!b.filled)
|
||||||
|
continue;
|
||||||
|
pval[0 .. valsz] = b.entry[off .. valsz + off];
|
||||||
|
pval += valsz;
|
||||||
|
}
|
||||||
|
// postblit is done in object.values
|
||||||
|
return (cast(inout(void)*) res)[0 .. aa.length]; // fake length, return number of elements
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a GC allocated array of all keys
|
||||||
|
extern (C) inout(void[]) _aaKeys(inout ubyte* _aa, const size_t keysz, const TypeInfo tiKeyArray)
|
||||||
|
{
|
||||||
|
AA aa = cast(AA)_aa;
|
||||||
|
if (aa.empty)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
auto res = _d_newarrayU(tiKeyArray, aa.length).ptr;
|
||||||
|
auto pkey = res;
|
||||||
|
|
||||||
|
foreach (b; aa.buckets[aa.firstUsed .. $])
|
||||||
|
{
|
||||||
|
if (!b.filled)
|
||||||
|
continue;
|
||||||
|
pkey[0 .. keysz] = b.entry[0 .. keysz];
|
||||||
|
pkey += keysz;
|
||||||
|
}
|
||||||
|
// postblit is done in object.keys
|
||||||
|
return (cast(inout(void)*) res)[0 .. aa.length]; // fake length, return number of elements
|
||||||
|
}
|
||||||
|
|
||||||
|
// opApply callbacks are extern(D)
|
||||||
|
extern (D) alias dg_t = int delegate(void*);
|
||||||
|
extern (D) alias dg2_t = int delegate(void*, void*);
|
||||||
|
|
||||||
|
/// foreach opApply over all values
|
||||||
|
extern (C) int _aaApply(ubyte* _aa, const size_t keysz, dg_t dg)
|
||||||
|
{
|
||||||
|
AA aa = cast(AA)_aa;
|
||||||
|
if (aa.empty)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
immutable off = aa.valoff;
|
||||||
|
foreach (b; aa.buckets)
|
||||||
|
{
|
||||||
|
if (!b.filled)
|
||||||
|
continue;
|
||||||
|
if (auto res = dg(b.entry + off))
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// foreach opApply over all key/value pairs
|
||||||
|
extern (C) int _aaApply2(ubyte* _aa, const size_t keysz, dg2_t dg)
|
||||||
|
{
|
||||||
|
AA aa = cast(AA)_aa;
|
||||||
|
if (aa.empty)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
immutable off = aa.valoff;
|
||||||
|
foreach (b; aa.buckets)
|
||||||
|
{
|
||||||
|
if (!b.filled)
|
||||||
|
continue;
|
||||||
|
if (auto res = dg(b.entry, b.entry + off))
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Construct an associative array of type ti from corresponding keys and values.
|
||||||
|
* Called for an AA literal `[k1:v1, k2:v2]`.
|
||||||
|
* Params:
|
||||||
|
* ti = TypeInfo for the associative array
|
||||||
|
* keys = array of keys
|
||||||
|
* vals = array of values
|
||||||
|
* Returns:
|
||||||
|
* A new associative array opaque pointer, or null if `keys` is empty.
|
||||||
|
*/
|
||||||
|
extern (C) ubyte* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, void[] keys,
|
||||||
|
void[] vals)
|
||||||
|
{
|
||||||
|
assert(keys.length == vals.length);
|
||||||
|
|
||||||
|
immutable keysz = ti.key.size;
|
||||||
|
immutable valsz = ti.value.size;
|
||||||
|
immutable length = keys.length;
|
||||||
|
|
||||||
|
if (!length)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
auto aa = new Impl(ti, nextpow2(INIT_DEN * length / INIT_NUM));
|
||||||
|
|
||||||
|
void* pkey = keys.ptr;
|
||||||
|
void* pval = vals.ptr;
|
||||||
|
immutable off = aa.valoff;
|
||||||
|
uint actualLength = 0;
|
||||||
|
foreach (_; 0 .. length)
|
||||||
|
{
|
||||||
|
immutable hash = calcHash(pkey, ti.key);
|
||||||
|
auto p = aa.findSlotLookup(hash, pkey, ti.key);
|
||||||
|
if (p is null)
|
||||||
|
{
|
||||||
|
p = aa.findSlotInsert(hash);
|
||||||
|
p.hash = hash;
|
||||||
|
p.entry = allocEntry(aa, pkey); // move key, no postblit
|
||||||
|
aa.firstUsed = min(aa.firstUsed, cast(uint)(p - aa.buckets.ptr));
|
||||||
|
actualLength++;
|
||||||
|
}
|
||||||
|
else if (aa.entryTI && hasDtor(ti.value))
|
||||||
|
{
|
||||||
|
// destroy existing value before overwriting it
|
||||||
|
ti.value.destroy(p.entry + off);
|
||||||
|
}
|
||||||
|
// set hash and blit value
|
||||||
|
auto pdst = p.entry + off;
|
||||||
|
pdst[0 .. valsz] = pval[0 .. valsz]; // move value, no postblit
|
||||||
|
|
||||||
|
pkey += keysz;
|
||||||
|
pval += valsz;
|
||||||
|
}
|
||||||
|
aa.used = actualLength;
|
||||||
|
return cast(ubyte*)aa;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// compares 2 AAs for equality
|
||||||
|
extern (C) int _aaEqual(scope const TypeInfo tiRaw, scope const ubyte* _aa1, scope const ubyte* _aa2)
|
||||||
|
{
|
||||||
|
AA aa1 = cast(AA)_aa1;
|
||||||
|
AA aa2 = cast(AA)_aa2;
|
||||||
|
if (aa1 is aa2)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
immutable len = _aaLen(aa1);
|
||||||
|
if (len != _aaLen(aa2))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!len) // both empty
|
||||||
|
return true;
|
||||||
|
|
||||||
|
import core.arsd.objectutils;
|
||||||
|
|
||||||
|
auto uti = unqualify(tiRaw); //unqualify
|
||||||
|
auto ti = *cast(TypeInfo_AssociativeArray*)&uti;
|
||||||
|
// compare the entries
|
||||||
|
immutable off = aa1.valoff;
|
||||||
|
foreach (b1; aa1.buckets)
|
||||||
|
{
|
||||||
|
if (!b1.filled)
|
||||||
|
continue;
|
||||||
|
auto pb2 = aa2.findSlotLookup(b1.hash, b1.entry, ti.key);
|
||||||
|
if (pb2 is null || !ti.value.equals(b1.entry + off, pb2.entry + off))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// compute a hash
|
||||||
|
extern (C) size_t _aaGetHash(scope const ubyte** _paa, scope const TypeInfo tiRaw) nothrow
|
||||||
|
{
|
||||||
|
AA* paa = cast(AA*)_paa;
|
||||||
|
const AA aa = *paa;
|
||||||
|
|
||||||
|
if (aa.empty)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
|
||||||
|
import core.arsd.objectutils;
|
||||||
|
auto uti = unqualify(tiRaw);
|
||||||
|
auto ti = *cast(TypeInfo_AssociativeArray*)&uti;
|
||||||
|
immutable off = aa.valoff;
|
||||||
|
auto keyHash = &ti.key.getHash;
|
||||||
|
auto valHash = &ti.value.getHash;
|
||||||
|
|
||||||
|
size_t h;
|
||||||
|
foreach (b; aa.buckets)
|
||||||
|
{
|
||||||
|
// use addition here, so that hash is independent of element order
|
||||||
|
if (b.filled)
|
||||||
|
h += hashOf(valHash(b.entry + off), keyHash(b.entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _aaRange implements a ForwardRange
|
||||||
|
*/
|
||||||
|
struct Range
|
||||||
|
{
|
||||||
|
ubyte* impl;
|
||||||
|
size_t idx;
|
||||||
|
alias impl this;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern (C) pure nothrow @nogc @trusted
|
||||||
|
{
|
||||||
|
Range _aaRange(return scope ubyte* _aa)
|
||||||
|
{
|
||||||
|
AA aa = cast(AA)_aa;
|
||||||
|
if (!aa)
|
||||||
|
return Range();
|
||||||
|
|
||||||
|
foreach (i; aa.firstUsed .. aa.dim)
|
||||||
|
{
|
||||||
|
if (aa.buckets[i].filled)
|
||||||
|
return Range(cast(ubyte*)aa, i);
|
||||||
|
}
|
||||||
|
return Range(cast(ubyte*)aa, aa.dim);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _aaRangeEmpty(Range r)
|
||||||
|
{
|
||||||
|
return r.impl is null || r.idx >= (cast(Impl*)r.impl).dim;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* _aaRangeFrontKey(Range r)
|
||||||
|
{
|
||||||
|
assert(!_aaRangeEmpty(r));
|
||||||
|
if (r.idx >= (cast(Impl*)r.impl).dim)
|
||||||
|
return null;
|
||||||
|
return (cast(Impl*)r.impl).buckets[r.idx].entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* _aaRangeFrontValue(Range r)
|
||||||
|
{
|
||||||
|
Impl* ri = cast(Impl*)r.impl;
|
||||||
|
assert(!_aaRangeEmpty(r));
|
||||||
|
if (r.idx >= ri.dim)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
auto entry = ri.buckets[r.idx].entry;
|
||||||
|
return entry is null ?
|
||||||
|
null :
|
||||||
|
(() @trusted { return entry + ri.valoff; } ());
|
||||||
|
}
|
||||||
|
|
||||||
|
void _aaRangePopFront(ref Range r)
|
||||||
|
{
|
||||||
|
Impl* ri = (cast(Impl*)r.impl);
|
||||||
|
if (r.idx >= ri.dim) return;
|
||||||
|
for (++r.idx; r.idx < ri.dim; ++r.idx)
|
||||||
|
{
|
||||||
|
if (ri.buckets[r.idx].filled)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
260
external/arsd-webassembly/core/arsd/memory_allocation.d
vendored
Normal file
260
external/arsd-webassembly/core/arsd/memory_allocation.d
vendored
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
module core.arsd.memory_allocation;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private __gshared ubyte* nextFree;
|
||||||
|
private __gshared size_t memorySize; // in units of 64 KB pages
|
||||||
|
|
||||||
|
// ldc defines this, used to find where wasm memory begins
|
||||||
|
private extern extern(C) ubyte __heap_base;
|
||||||
|
// ---unused--- -- stack grows down -- -- heap here --
|
||||||
|
// this is less than __heap_base. memory map 0 ... __data_end ... __heap_base ... end of memory
|
||||||
|
private extern extern(C) ubyte __data_end;
|
||||||
|
|
||||||
|
// llvm intrinsics {
|
||||||
|
/+
|
||||||
|
mem must be 0 (it is index of memory thing)
|
||||||
|
delta is in 64 KB pages
|
||||||
|
return OLD size in 64 KB pages, or size_t.max if it failed.
|
||||||
|
+/
|
||||||
|
pragma(LDC_intrinsic, "llvm.wasm.memory.grow.i32")
|
||||||
|
private int llvm_wasm_memory_grow(int mem, int delta);
|
||||||
|
|
||||||
|
|
||||||
|
// in 64 KB pages
|
||||||
|
pragma(LDC_intrinsic, "llvm.wasm.memory.size.i32")
|
||||||
|
private int llvm_wasm_memory_size(int mem);
|
||||||
|
// }
|
||||||
|
// debug
|
||||||
|
void printBlockDebugInfo(AllocatedBlock* block) {
|
||||||
|
import std.stdio;
|
||||||
|
writeln(block.blockSize, " ", block.flags, " ", block.checkChecksum() ? "OK" : "X", " ");
|
||||||
|
if(block.checkChecksum())
|
||||||
|
writeln(cast(size_t)((cast(ubyte*) (block + 2)) + block.blockSize), " ", block.file, " : ", block.line);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// debug
|
||||||
|
export extern(C) void printBlockDebugInfo(void* ptr) {
|
||||||
|
if(ptr is null) {
|
||||||
|
foreach(block; AllocatedBlock) {
|
||||||
|
printBlockDebugInfo(block);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise assume it is a pointer returned from malloc
|
||||||
|
|
||||||
|
auto block = (cast(AllocatedBlock*) ptr) - 1;
|
||||||
|
if(ptr is null)
|
||||||
|
block = cast(AllocatedBlock*) &__heap_base;
|
||||||
|
|
||||||
|
printBlockDebugInfo(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export extern(C) ubyte* bridge_malloc(size_t sz) {
|
||||||
|
return malloc(sz).ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
align(16)
|
||||||
|
struct AllocatedBlock {
|
||||||
|
enum Magic = 0x731a_9bec;
|
||||||
|
enum Flags {
|
||||||
|
inUse = 1,
|
||||||
|
unique = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t blockSize;
|
||||||
|
size_t flags;
|
||||||
|
size_t magic;
|
||||||
|
size_t checksum;
|
||||||
|
|
||||||
|
size_t used; // the amount actually requested out of the block; used for assumeSafeAppend
|
||||||
|
|
||||||
|
/* debug */
|
||||||
|
string file;
|
||||||
|
size_t line;
|
||||||
|
|
||||||
|
// note this struct MUST align each alloc on an 8 byte boundary or JS is gonna throw bullshit
|
||||||
|
|
||||||
|
void populateChecksum() {
|
||||||
|
checksum = blockSize ^ magic;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkChecksum() const @nogc {
|
||||||
|
return magic == Magic && checksum == (blockSize ^ magic);
|
||||||
|
}
|
||||||
|
|
||||||
|
ubyte[] dataSlice() return {
|
||||||
|
return ((cast(ubyte*) &this) + typeof(this).sizeof)[0 .. blockSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
static int opApply(scope int delegate(AllocatedBlock*) dg) {
|
||||||
|
if(nextFree is null)
|
||||||
|
return 0;
|
||||||
|
ubyte* next = &__heap_base;
|
||||||
|
AllocatedBlock* block = cast(AllocatedBlock*) next;
|
||||||
|
while(block.checkChecksum()) {
|
||||||
|
if(auto result = dg(block))
|
||||||
|
return result;
|
||||||
|
next += AllocatedBlock.sizeof;
|
||||||
|
next += block.blockSize;
|
||||||
|
block = cast(AllocatedBlock*) next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static assert(AllocatedBlock.sizeof % 16 == 0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private bool growMemoryIfNeeded(size_t sz) @trusted {
|
||||||
|
if(cast(size_t) nextFree + AllocatedBlock.sizeof + sz >= memorySize * 64*1024) {
|
||||||
|
if(llvm_wasm_memory_grow(0, 4) == size_t.max)
|
||||||
|
assert(0, "Out of memory"); // out of memory
|
||||||
|
|
||||||
|
memorySize = llvm_wasm_memory_size(0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(ubyte* ptr) @nogc @trusted {
|
||||||
|
auto block = (cast(AllocatedBlock*) ptr) - 1;
|
||||||
|
if(!block.checkChecksum())
|
||||||
|
assert(false, "Could not check block on free");
|
||||||
|
|
||||||
|
block.used = 0;
|
||||||
|
block.flags = 0;
|
||||||
|
|
||||||
|
// last one
|
||||||
|
if(ptr + block.blockSize == nextFree) {
|
||||||
|
nextFree = cast(ubyte*) block;
|
||||||
|
assert(cast(size_t)nextFree % 16 == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ubyte[] malloc(size_t sz, string file = __FILE__, size_t line = __LINE__) @trusted {
|
||||||
|
// lol bumping that pointer
|
||||||
|
if(nextFree is null) {
|
||||||
|
nextFree = &__heap_base; // seems to be 75312
|
||||||
|
assert(cast(size_t)nextFree % 16 == 0);
|
||||||
|
memorySize = llvm_wasm_memory_size(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
while(growMemoryIfNeeded(sz)) {}
|
||||||
|
|
||||||
|
auto base = cast(AllocatedBlock*) nextFree;
|
||||||
|
|
||||||
|
auto blockSize = sz;
|
||||||
|
if(auto val = blockSize % 16)
|
||||||
|
blockSize += 16 - val; // does NOT include this metadata section!
|
||||||
|
|
||||||
|
// debug list allocations
|
||||||
|
//import std.stdio; writeln(file, ":", line, " / ", sz, " +", blockSize);
|
||||||
|
|
||||||
|
base.blockSize = blockSize;
|
||||||
|
base.flags = AllocatedBlock.Flags.inUse;
|
||||||
|
// these are just to make it more reliable to detect this header by backtracking through the pointer from a random array.
|
||||||
|
// otherwise it'd prolly follow the linked list from the beginning every time or make a free list or something. idk tbh.
|
||||||
|
base.magic = AllocatedBlock.Magic;
|
||||||
|
base.populateChecksum();
|
||||||
|
|
||||||
|
base.used = sz;
|
||||||
|
|
||||||
|
// debug
|
||||||
|
base.file = file;
|
||||||
|
base.line = line;
|
||||||
|
|
||||||
|
nextFree += AllocatedBlock.sizeof;
|
||||||
|
|
||||||
|
auto ret = nextFree;
|
||||||
|
|
||||||
|
nextFree += blockSize;
|
||||||
|
|
||||||
|
//writeln(cast(size_t) nextFree);
|
||||||
|
//import std.stdio; writeln(cast(size_t) ret, " of ", sz, " rounded to ", blockSize);
|
||||||
|
//writeln(file, ":", line);
|
||||||
|
assert(cast(size_t) ret % 8 == 0);
|
||||||
|
|
||||||
|
return ret[0 .. sz];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ubyte[] calloc(size_t count, size_t size, string file = __FILE__, size_t line = __LINE__) @trusted
|
||||||
|
{
|
||||||
|
auto ret = malloc(count*size,file,line);
|
||||||
|
ret[0..$] = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ubyte[] realloc(ubyte* ptr, size_t newSize, string file = __FILE__, size_t line = __LINE__) @trusted {
|
||||||
|
if(ptr is null)
|
||||||
|
return malloc(newSize, file, line);
|
||||||
|
|
||||||
|
auto block = (cast(AllocatedBlock*) ptr) - 1;
|
||||||
|
if(!block.checkChecksum())
|
||||||
|
assert(false, "Could not check block while realloc");
|
||||||
|
|
||||||
|
// block.populateChecksum();
|
||||||
|
if(newSize <= block.blockSize) {
|
||||||
|
block.used = newSize;
|
||||||
|
return ptr[0 .. newSize];
|
||||||
|
} else {
|
||||||
|
// FIXME: see if we can extend teh block into following free space before resorting to malloc
|
||||||
|
|
||||||
|
if(ptr + block.blockSize == nextFree) {
|
||||||
|
while(growMemoryIfNeeded(newSize)) {}
|
||||||
|
|
||||||
|
size_t blockSize = newSize;
|
||||||
|
if(const over = blockSize % 16)
|
||||||
|
blockSize+= 16 - over;
|
||||||
|
|
||||||
|
block.blockSize = blockSize;
|
||||||
|
block.used = newSize;
|
||||||
|
block.populateChecksum();
|
||||||
|
nextFree = ptr + block.blockSize;
|
||||||
|
assert(cast(size_t)nextFree % 16 == 0);
|
||||||
|
return ptr[0 .. newSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto newThing = malloc(newSize);
|
||||||
|
newThing[0 .. block.used] = ptr[0 .. block.used];
|
||||||
|
|
||||||
|
if(block.flags & AllocatedBlock.Flags.unique) {
|
||||||
|
// if we do malloc, this means we are allowed to free the existing block
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(cast(size_t) newThing.ptr % 16 == 0);
|
||||||
|
|
||||||
|
return newThing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the ptr isn't owned by the runtime, it will completely malloc the data (instead of realloc)
|
||||||
|
* and copy its old content.
|
||||||
|
*/
|
||||||
|
ubyte[] realloc(ubyte[] ptr, size_t newSize, string file = __FILE__, size_t line = __LINE__) @trusted
|
||||||
|
{
|
||||||
|
if(ptr is null)
|
||||||
|
return malloc(newSize, file, line);
|
||||||
|
auto block = (cast(AllocatedBlock*) ptr) - 1;
|
||||||
|
if(!block.checkChecksum())
|
||||||
|
{
|
||||||
|
auto ret = malloc(newSize, file, line);
|
||||||
|
ret[0..ptr.length] = ptr[]; //Don't clear ptr memory as it can't be clear.
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else return realloc(ptr.ptr, newSize, file, line);
|
||||||
|
}
|
||||||
68
external/arsd-webassembly/core/arsd/objectutils.d
vendored
Normal file
68
external/arsd-webassembly/core/arsd/objectutils.d
vendored
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
module core.arsd.objectutils;
|
||||||
|
|
||||||
|
///Provides only __doPostblit and hasPostblit for making the code simpler.
|
||||||
|
size_t structTypeInfoSize(const TypeInfo ti) pure nothrow @nogc
|
||||||
|
{
|
||||||
|
if (ti && typeid(ti) is typeid(TypeInfo_Struct)) // avoid a complete dynamic type cast
|
||||||
|
{
|
||||||
|
auto sti = cast(TypeInfo_Struct)cast(void*)ti;
|
||||||
|
if (sti.xdtor)
|
||||||
|
return size_t.sizeof;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// strip const/immutable/shared/inout from type info
|
||||||
|
inout(TypeInfo) unqualify(return scope inout(TypeInfo) cti) pure nothrow @nogc
|
||||||
|
{
|
||||||
|
TypeInfo ti = cast() cti;
|
||||||
|
while (ti)
|
||||||
|
{
|
||||||
|
// avoid dynamic type casts
|
||||||
|
auto tti = typeid(ti);
|
||||||
|
if (tti is typeid(TypeInfo_Const))
|
||||||
|
ti = (cast(TypeInfo_Const)cast(void*)ti).base;
|
||||||
|
else if (tti is typeid(TypeInfo_Invariant))
|
||||||
|
ti = (cast(TypeInfo_Invariant)cast(void*)ti).base;
|
||||||
|
else if (tti is typeid(TypeInfo_Shared))
|
||||||
|
ti = (cast(TypeInfo_Shared)cast(void*)ti).base;
|
||||||
|
else if (tti is typeid(TypeInfo_Inout))
|
||||||
|
ti = (cast(TypeInfo_Inout)cast(void*)ti).base;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ti;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasPostblit(in TypeInfo ti) nothrow pure
|
||||||
|
{
|
||||||
|
return (&ti.postblit).funcptr !is &TypeInfo.postblit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __doPostblit(void *ptr, size_t len, const TypeInfo ti)
|
||||||
|
{
|
||||||
|
if (!hasPostblit(ti))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (auto tis = cast(TypeInfo_Struct)ti)
|
||||||
|
{
|
||||||
|
// this is a struct, check the xpostblit member
|
||||||
|
auto pblit = tis.xpostblit;
|
||||||
|
if (!pblit)
|
||||||
|
// postblit not specified, no point in looping.
|
||||||
|
return;
|
||||||
|
|
||||||
|
// optimized for struct, call xpostblit directly for each element
|
||||||
|
immutable size = ti.size;
|
||||||
|
const eptr = ptr + len;
|
||||||
|
for (;ptr < eptr;ptr += size)
|
||||||
|
pblit(ptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// generic case, call the typeinfo's postblit function
|
||||||
|
immutable size = ti.size;
|
||||||
|
const eptr = ptr + len;
|
||||||
|
for (;ptr < eptr;ptr += size)
|
||||||
|
ti.postblit(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
444
external/arsd-webassembly/core/arsd/utf_decoding.d
vendored
Normal file
444
external/arsd-webassembly/core/arsd/utf_decoding.d
vendored
Normal file
@ -0,0 +1,444 @@
|
|||||||
|
module core.arsd.utf_decoding;
|
||||||
|
|
||||||
|
|
||||||
|
import core.internal.utf : decode, toUTF8;
|
||||||
|
|
||||||
|
/**********************************************/
|
||||||
|
/* 1 argument versions */
|
||||||
|
|
||||||
|
/**
|
||||||
|
Delegate type corresponding to transformed loop body
|
||||||
|
|
||||||
|
The parameter is a pointer to the current `char`, `wchar` or `dchar`
|
||||||
|
|
||||||
|
Returns: non-zero when a `break` statement is hit
|
||||||
|
*/
|
||||||
|
extern (D) alias dg_t = int delegate(void* c);
|
||||||
|
|
||||||
|
// Note: dg is extern(D), but _aApplycd() is extern(C)
|
||||||
|
|
||||||
|
/**
|
||||||
|
Loop over a string while changing the UTF encoding
|
||||||
|
|
||||||
|
There are 6 combinations of conversions between `char`, `wchar`, and `dchar`,
|
||||||
|
and 2 of each of those.
|
||||||
|
|
||||||
|
The naming convention is as follows:
|
||||||
|
|
||||||
|
_aApply{c,d,w}{c,d,w}{1,2}
|
||||||
|
|
||||||
|
The first letter corresponds to the input string encoding, and the second letter corresponds to the target character type.
|
||||||
|
|
||||||
|
- c = `char`
|
||||||
|
- w = `wchar`
|
||||||
|
- d = `dchar`
|
||||||
|
|
||||||
|
The `1` variant only produces the character, the `2` variant also produces a loop index.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
---
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
string str;
|
||||||
|
wtring wstr;
|
||||||
|
dstring dstr;
|
||||||
|
|
||||||
|
foreach (dchar c; str) {}
|
||||||
|
// _aApplycd1
|
||||||
|
|
||||||
|
foreach (wchar c; dstr) {}
|
||||||
|
// _aApplydw1
|
||||||
|
|
||||||
|
foreach (i, wchar c; str) {}
|
||||||
|
// _aApplycw2
|
||||||
|
|
||||||
|
foreach (wchar w; wstr) {}
|
||||||
|
// no conversion
|
||||||
|
}
|
||||||
|
---
|
||||||
|
|
||||||
|
Params:
|
||||||
|
aa = input string
|
||||||
|
dg = foreach body transformed into a delegate, similar to `opApply`
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
non-zero when the loop was exited through a `break`
|
||||||
|
*/
|
||||||
|
extern (C) int _aApplycd1(in char[] aa, dg_t dg)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
size_t len = aa.length;
|
||||||
|
|
||||||
|
debug(apply) printf("_aApplycd1(), len = %d\n", len);
|
||||||
|
for (size_t i = 0; i < len; )
|
||||||
|
{
|
||||||
|
dchar d = aa[i];
|
||||||
|
if (d & 0x80)
|
||||||
|
d = decode(aa, i);
|
||||||
|
else
|
||||||
|
++i;
|
||||||
|
result = dg(cast(void *)&d);
|
||||||
|
if (result)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// ditto
|
||||||
|
extern (C) int _aApplywd1(in wchar[] aa, dg_t dg)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
size_t len = aa.length;
|
||||||
|
|
||||||
|
debug(apply) printf("_aApplywd1(), len = %d\n", len);
|
||||||
|
for (size_t i = 0; i < len; )
|
||||||
|
{
|
||||||
|
dchar d = aa[i];
|
||||||
|
if (d >= 0xD800)
|
||||||
|
d = decode(aa, i);
|
||||||
|
else
|
||||||
|
++i;
|
||||||
|
result = dg(cast(void *)&d);
|
||||||
|
if (result)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// ditto
|
||||||
|
extern (C) int _aApplycw1(in char[] aa, dg_t dg)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
size_t len = aa.length;
|
||||||
|
|
||||||
|
debug(apply) printf("_aApplycw1(), len = %d\n", len);
|
||||||
|
for (size_t i = 0; i < len; )
|
||||||
|
{
|
||||||
|
wchar w = aa[i];
|
||||||
|
if (w & 0x80)
|
||||||
|
{
|
||||||
|
dchar d = decode(aa, i);
|
||||||
|
if (d <= 0xFFFF)
|
||||||
|
w = cast(wchar) d;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
w = cast(wchar)((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||||
|
result = dg(cast(void *)&w);
|
||||||
|
if (result)
|
||||||
|
break;
|
||||||
|
w = cast(wchar)(((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++i;
|
||||||
|
result = dg(cast(void *)&w);
|
||||||
|
if (result)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// ditto
|
||||||
|
extern (C) int _aApplywc1(in wchar[] aa, dg_t dg)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
size_t len = aa.length;
|
||||||
|
|
||||||
|
debug(apply) printf("_aApplywc1(), len = %d\n", len);
|
||||||
|
for (size_t i = 0; i < len; )
|
||||||
|
{
|
||||||
|
wchar w = aa[i];
|
||||||
|
if (w & ~0x7F)
|
||||||
|
{
|
||||||
|
char[4] buf = void;
|
||||||
|
|
||||||
|
dchar d = decode(aa, i);
|
||||||
|
auto b = toUTF8(buf, d);
|
||||||
|
foreach (char c2; b)
|
||||||
|
{
|
||||||
|
result = dg(cast(void *)&c2);
|
||||||
|
if (result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char c = cast(char)w;
|
||||||
|
++i;
|
||||||
|
result = dg(cast(void *)&c);
|
||||||
|
if (result)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// ditto
|
||||||
|
extern (C) int _aApplydc1(in dchar[] aa, dg_t dg)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
debug(apply) printf("_aApplydc1(), len = %d\n", aa.length);
|
||||||
|
foreach (dchar d; aa)
|
||||||
|
{
|
||||||
|
if (d & ~0x7F)
|
||||||
|
{
|
||||||
|
char[4] buf = void;
|
||||||
|
|
||||||
|
auto b = toUTF8(buf, d);
|
||||||
|
foreach (char c2; b)
|
||||||
|
{
|
||||||
|
result = dg(cast(void *)&c2);
|
||||||
|
if (result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char c = cast(char)d;
|
||||||
|
result = dg(cast(void *)&c);
|
||||||
|
if (result)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// ditto
|
||||||
|
extern (C) int _aApplydw1(in dchar[] aa, dg_t dg)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
debug(apply) printf("_aApplydw1(), len = %d\n", aa.length);
|
||||||
|
foreach (dchar d; aa)
|
||||||
|
{
|
||||||
|
wchar w;
|
||||||
|
|
||||||
|
if (d <= 0xFFFF)
|
||||||
|
w = cast(wchar) d;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
w = cast(wchar)((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||||
|
result = dg(cast(void *)&w);
|
||||||
|
if (result)
|
||||||
|
break;
|
||||||
|
w = cast(wchar)(((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||||
|
}
|
||||||
|
result = dg(cast(void *)&w);
|
||||||
|
if (result)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
/* 2 argument versions */
|
||||||
|
|
||||||
|
/**
|
||||||
|
Delegate type corresponding to transformed loop body
|
||||||
|
|
||||||
|
Parameters are pointers to a `size_t` loop index, and the current `char`, `wchar` or `dchar`.
|
||||||
|
|
||||||
|
Returns: non-zero when a `break` statement is hit
|
||||||
|
*/
|
||||||
|
extern (D) alias dg2_t = int delegate(void* i, void* c);
|
||||||
|
|
||||||
|
// Note: dg is extern(D), but _aApplycd2() is extern(C)
|
||||||
|
|
||||||
|
/**
|
||||||
|
Variants of _aApplyXXX that include a loop index.
|
||||||
|
*/
|
||||||
|
extern (C) int _aApplycd2(in char[] aa, dg2_t dg)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
size_t len = aa.length;
|
||||||
|
|
||||||
|
debug(apply) printf("_aApplycd2(), len = %d\n", len);
|
||||||
|
size_t n;
|
||||||
|
for (size_t i = 0; i < len; i += n)
|
||||||
|
{
|
||||||
|
dchar d = aa[i];
|
||||||
|
if (d & 0x80)
|
||||||
|
{
|
||||||
|
n = i;
|
||||||
|
d = decode(aa, n);
|
||||||
|
n -= i;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
n = 1;
|
||||||
|
result = dg(&i, cast(void *)&d);
|
||||||
|
if (result)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ditto
|
||||||
|
extern (C) int _aApplywd2(in wchar[] aa, dg2_t dg)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
size_t len = aa.length;
|
||||||
|
|
||||||
|
debug(apply) printf("_aApplywd2(), len = %d\n", len);
|
||||||
|
size_t n;
|
||||||
|
for (size_t i = 0; i < len; i += n)
|
||||||
|
{
|
||||||
|
dchar d = aa[i];
|
||||||
|
if (d & ~0x7F)
|
||||||
|
{
|
||||||
|
n = i;
|
||||||
|
d = decode(aa, n);
|
||||||
|
n -= i;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
n = 1;
|
||||||
|
result = dg(&i, cast(void *)&d);
|
||||||
|
if (result)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ditto
|
||||||
|
extern (C) int _aApplycw2(in char[] aa, dg2_t dg)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
size_t len = aa.length;
|
||||||
|
|
||||||
|
debug(apply) printf("_aApplycw2(), len = %d\n", len);
|
||||||
|
size_t n;
|
||||||
|
for (size_t i = 0; i < len; i += n)
|
||||||
|
{
|
||||||
|
wchar w = aa[i];
|
||||||
|
if (w & 0x80)
|
||||||
|
{
|
||||||
|
n = i;
|
||||||
|
dchar d = decode(aa, n);
|
||||||
|
n -= i;
|
||||||
|
if (d <= 0xFFFF)
|
||||||
|
w = cast(wchar) d;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||||
|
result = dg(&i, cast(void *)&w);
|
||||||
|
if (result)
|
||||||
|
break;
|
||||||
|
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
n = 1;
|
||||||
|
result = dg(&i, cast(void *)&w);
|
||||||
|
if (result)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// ditto
|
||||||
|
extern (C) int _aApplywc2(in wchar[] aa, dg2_t dg)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
size_t len = aa.length;
|
||||||
|
|
||||||
|
debug(apply) printf("_aApplywc2(), len = %d\n", len);
|
||||||
|
size_t n;
|
||||||
|
for (size_t i = 0; i < len; i += n)
|
||||||
|
{
|
||||||
|
wchar w = aa[i];
|
||||||
|
if (w & ~0x7F)
|
||||||
|
{
|
||||||
|
char[4] buf = void;
|
||||||
|
|
||||||
|
n = i;
|
||||||
|
dchar d = decode(aa, n);
|
||||||
|
n -= i;
|
||||||
|
auto b = toUTF8(buf, d);
|
||||||
|
foreach (char c2; b)
|
||||||
|
{
|
||||||
|
result = dg(&i, cast(void *)&c2);
|
||||||
|
if (result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char c = cast(char)w;
|
||||||
|
n = 1;
|
||||||
|
result = dg(&i, cast(void *)&c);
|
||||||
|
if (result)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// ditto
|
||||||
|
extern (C) int _aApplydc2(in dchar[] aa, dg2_t dg)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
size_t len = aa.length;
|
||||||
|
|
||||||
|
debug(apply) printf("_aApplydc2(), len = %d\n", len);
|
||||||
|
for (size_t i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
dchar d = aa[i];
|
||||||
|
if (d & ~0x7F)
|
||||||
|
{
|
||||||
|
char[4] buf = void;
|
||||||
|
|
||||||
|
auto b = toUTF8(buf, d);
|
||||||
|
foreach (char c2; b)
|
||||||
|
{
|
||||||
|
result = dg(&i, cast(void *)&c2);
|
||||||
|
if (result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char c = cast(char)d;
|
||||||
|
result = dg(&i, cast(void *)&c);
|
||||||
|
if (result)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// ditto
|
||||||
|
extern (C) int _aApplydw2(in dchar[] aa, dg2_t dg)
|
||||||
|
{ int result;
|
||||||
|
|
||||||
|
debug(apply) printf("_aApplydw2(), len = %d\n", aa.length);
|
||||||
|
foreach (size_t i, dchar d; aa)
|
||||||
|
{
|
||||||
|
wchar w;
|
||||||
|
auto j = i;
|
||||||
|
|
||||||
|
if (d <= 0xFFFF)
|
||||||
|
w = cast(wchar) d;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||||
|
result = dg(&j, cast(void *)&w);
|
||||||
|
if (result)
|
||||||
|
break;
|
||||||
|
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||||
|
}
|
||||||
|
result = dg(&j, cast(void *)&w);
|
||||||
|
if (result)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
892
external/arsd-webassembly/core/internal/utf.d
vendored
Normal file
892
external/arsd-webassembly/core/internal/utf.d
vendored
Normal file
@ -0,0 +1,892 @@
|
|||||||
|
/********************************************
|
||||||
|
* Encode and decode UTF-8, UTF-16 and UTF-32 strings.
|
||||||
|
*
|
||||||
|
* For Win32 systems, the C wchar_t type is UTF-16 and corresponds to the D
|
||||||
|
* wchar type.
|
||||||
|
* For Posix systems, the C wchar_t type is UTF-32 and corresponds to
|
||||||
|
* the D utf.dchar type.
|
||||||
|
*
|
||||||
|
* UTF character support is restricted to (\u0000 <= character <= \U0010FFFF).
|
||||||
|
*
|
||||||
|
* See_Also:
|
||||||
|
* $(LINK2 http://en.wikipedia.org/wiki/Unicode, Wikipedia)<br>
|
||||||
|
* $(LINK http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8)<br>
|
||||||
|
* $(LINK http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335)
|
||||||
|
*
|
||||||
|
* Copyright: Copyright Digital Mars 2003 - 2016.
|
||||||
|
* License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
|
||||||
|
* Authors: Walter Bright, Sean Kelly
|
||||||
|
* Source: $(DRUNTIMESRC core/internal/_utf.d)
|
||||||
|
*/
|
||||||
|
|
||||||
|
module core.internal.utf;
|
||||||
|
|
||||||
|
extern (C) void onUnicodeError( string msg, size_t idx, string file = __FILE__, size_t line = __LINE__ ) @trusted
|
||||||
|
{
|
||||||
|
_d_assert_msg("onUnicodeError: "~msg, file, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************
|
||||||
|
* Test if c is a valid UTF-32 character.
|
||||||
|
*
|
||||||
|
* \uFFFE and \uFFFF are considered valid by this function,
|
||||||
|
* as they are permitted for internal use by an application,
|
||||||
|
* but they are not allowed for interchange by the Unicode standard.
|
||||||
|
*
|
||||||
|
* Returns: true if it is, false if not.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@safe @nogc pure nothrow
|
||||||
|
bool isValidDchar(dchar c)
|
||||||
|
{
|
||||||
|
/* Note: FFFE and FFFF are specifically permitted by the
|
||||||
|
* Unicode standard for application internal use, but are not
|
||||||
|
* allowed for interchange.
|
||||||
|
* (thanks to Arcane Jill)
|
||||||
|
*/
|
||||||
|
|
||||||
|
return c < 0xD800 ||
|
||||||
|
(c > 0xDFFF && c <= 0x10FFFF /*&& c != 0xFFFE && c != 0xFFFF*/);
|
||||||
|
}
|
||||||
|
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
debug(utf) printf("utf.isValidDchar.unittest\n");
|
||||||
|
assert(isValidDchar(cast(dchar)'a') == true);
|
||||||
|
assert(isValidDchar(cast(dchar)0x1FFFFF) == false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static immutable UTF8stride =
|
||||||
|
[
|
||||||
|
cast(ubyte)
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||||
|
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||||
|
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||||
|
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||||
|
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||||
|
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||||
|
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||||
|
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||||
|
4,4,4,4,4,4,4,4,5,5,5,5,6,6,0xFF,0xFF,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stride() returns the length of a UTF-8 sequence starting at index i
|
||||||
|
* in string s.
|
||||||
|
* Returns:
|
||||||
|
* The number of bytes in the UTF-8 sequence or
|
||||||
|
* 0xFF meaning s[i] is not the start of of UTF-8 sequence.
|
||||||
|
*/
|
||||||
|
@safe @nogc pure nothrow
|
||||||
|
uint stride(const scope char[] s, size_t i)
|
||||||
|
{
|
||||||
|
return UTF8stride[s[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stride() returns the length of a UTF-16 sequence starting at index i
|
||||||
|
* in string s.
|
||||||
|
*/
|
||||||
|
@safe @nogc pure nothrow
|
||||||
|
uint stride(const scope wchar[] s, size_t i)
|
||||||
|
{ uint u = s[i];
|
||||||
|
return 1 + (u >= 0xD800 && u <= 0xDBFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stride() returns the length of a UTF-32 sequence starting at index i
|
||||||
|
* in string s.
|
||||||
|
* Returns: The return value will always be 1.
|
||||||
|
*/
|
||||||
|
@safe @nogc pure nothrow
|
||||||
|
uint stride(const scope dchar[] s, size_t i)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************
|
||||||
|
* Given an index i into an array of characters s[],
|
||||||
|
* and assuming that index i is at the start of a UTF character,
|
||||||
|
* determine the number of UCS characters up to that index i.
|
||||||
|
*/
|
||||||
|
@safe
|
||||||
|
size_t toUCSindex(const scope char[] s, size_t i)
|
||||||
|
{
|
||||||
|
size_t n;
|
||||||
|
size_t j;
|
||||||
|
|
||||||
|
for (j = 0; j < i; )
|
||||||
|
{
|
||||||
|
j += stride(s, j);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
if (j > i)
|
||||||
|
{
|
||||||
|
onUnicodeError("invalid UTF-8 sequence", j);
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ditto */
|
||||||
|
@safe
|
||||||
|
size_t toUCSindex(const scope wchar[] s, size_t i)
|
||||||
|
{
|
||||||
|
size_t n;
|
||||||
|
size_t j;
|
||||||
|
|
||||||
|
for (j = 0; j < i; )
|
||||||
|
{
|
||||||
|
j += stride(s, j);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
if (j > i)
|
||||||
|
{
|
||||||
|
onUnicodeError("invalid UTF-16 sequence", j);
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ditto */
|
||||||
|
@safe @nogc pure nothrow
|
||||||
|
size_t toUCSindex(const scope dchar[] s, size_t i)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************
|
||||||
|
* Given a UCS index n into an array of characters s[], return the UTF index.
|
||||||
|
*/
|
||||||
|
@safe
|
||||||
|
size_t toUTFindex(const scope char[] s, size_t n)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
while (n--)
|
||||||
|
{
|
||||||
|
uint j = UTF8stride[s[i]];
|
||||||
|
if (j == 0xFF)
|
||||||
|
onUnicodeError("invalid UTF-8 sequence", i);
|
||||||
|
i += j;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ditto */
|
||||||
|
@safe @nogc pure nothrow
|
||||||
|
size_t toUTFindex(const scope wchar[] s, size_t n)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
while (n--)
|
||||||
|
{ wchar u = s[i];
|
||||||
|
|
||||||
|
i += 1 + (u >= 0xD800 && u <= 0xDBFF);
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ditto */
|
||||||
|
@safe @nogc pure nothrow
|
||||||
|
size_t toUTFindex(const scope dchar[] s, size_t n)
|
||||||
|
{
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =================== Decode ======================= */
|
||||||
|
|
||||||
|
/***************
|
||||||
|
* Decodes and returns character starting at s[idx]. idx is advanced past the
|
||||||
|
* decoded character. If the character is not well formed, a UtfException is
|
||||||
|
* thrown and idx remains unchanged.
|
||||||
|
*/
|
||||||
|
@safe
|
||||||
|
dchar decode(const scope char[] s, ref size_t idx)
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(idx >= 0 && idx < s.length);
|
||||||
|
}
|
||||||
|
out (result)
|
||||||
|
{
|
||||||
|
assert(isValidDchar(result));
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
size_t len = s.length;
|
||||||
|
dchar V;
|
||||||
|
size_t i = idx;
|
||||||
|
char u = s[i];
|
||||||
|
|
||||||
|
if (u & 0x80)
|
||||||
|
{ uint n;
|
||||||
|
char u2;
|
||||||
|
|
||||||
|
/* The following encodings are valid, except for the 5 and 6 byte
|
||||||
|
* combinations:
|
||||||
|
* 0xxxxxxx
|
||||||
|
* 110xxxxx 10xxxxxx
|
||||||
|
* 1110xxxx 10xxxxxx 10xxxxxx
|
||||||
|
* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||||
|
* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||||
|
* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||||
|
*/
|
||||||
|
for (n = 1; ; n++)
|
||||||
|
{
|
||||||
|
if (n > 4)
|
||||||
|
goto Lerr; // only do the first 4 of 6 encodings
|
||||||
|
if (((u << n) & 0x80) == 0)
|
||||||
|
{
|
||||||
|
if (n == 1)
|
||||||
|
goto Lerr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pick off (7 - n) significant bits of B from first byte of octet
|
||||||
|
V = cast(dchar)(u & ((1 << (7 - n)) - 1));
|
||||||
|
|
||||||
|
if (i + (n - 1) >= len)
|
||||||
|
goto Lerr; // off end of string
|
||||||
|
|
||||||
|
/* The following combinations are overlong, and illegal:
|
||||||
|
* 1100000x (10xxxxxx)
|
||||||
|
* 11100000 100xxxxx (10xxxxxx)
|
||||||
|
* 11110000 1000xxxx (10xxxxxx 10xxxxxx)
|
||||||
|
* 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx)
|
||||||
|
* 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx)
|
||||||
|
*/
|
||||||
|
u2 = s[i + 1];
|
||||||
|
if ((u & 0xFE) == 0xC0 ||
|
||||||
|
(u == 0xE0 && (u2 & 0xE0) == 0x80) ||
|
||||||
|
(u == 0xF0 && (u2 & 0xF0) == 0x80) ||
|
||||||
|
(u == 0xF8 && (u2 & 0xF8) == 0x80) ||
|
||||||
|
(u == 0xFC && (u2 & 0xFC) == 0x80))
|
||||||
|
goto Lerr; // overlong combination
|
||||||
|
|
||||||
|
for (uint j = 1; j != n; j++)
|
||||||
|
{
|
||||||
|
u = s[i + j];
|
||||||
|
if ((u & 0xC0) != 0x80)
|
||||||
|
goto Lerr; // trailing bytes are 10xxxxxx
|
||||||
|
V = (V << 6) | (u & 0x3F);
|
||||||
|
}
|
||||||
|
if (!isValidDchar(V))
|
||||||
|
goto Lerr;
|
||||||
|
i += n;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
V = cast(dchar) u;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = i;
|
||||||
|
return V;
|
||||||
|
|
||||||
|
Lerr:
|
||||||
|
onUnicodeError("invalid UTF-8 sequence", i);
|
||||||
|
return V; // dummy return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** ditto */
|
||||||
|
@safe
|
||||||
|
dchar decode(const scope wchar[] s, ref size_t idx)
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(idx >= 0 && idx < s.length);
|
||||||
|
}
|
||||||
|
out (result)
|
||||||
|
{
|
||||||
|
assert(isValidDchar(result));
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
string msg;
|
||||||
|
dchar V;
|
||||||
|
size_t i = idx;
|
||||||
|
uint u = s[i];
|
||||||
|
|
||||||
|
if (u & ~0x7F)
|
||||||
|
{ if (u >= 0xD800 && u <= 0xDBFF)
|
||||||
|
{ uint u2;
|
||||||
|
|
||||||
|
if (i + 1 == s.length)
|
||||||
|
{ msg = "surrogate UTF-16 high value past end of string";
|
||||||
|
goto Lerr;
|
||||||
|
}
|
||||||
|
u2 = s[i + 1];
|
||||||
|
if (u2 < 0xDC00 || u2 > 0xDFFF)
|
||||||
|
{ msg = "surrogate UTF-16 low value out of range";
|
||||||
|
goto Lerr;
|
||||||
|
}
|
||||||
|
u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00);
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
else if (u >= 0xDC00 && u <= 0xDFFF)
|
||||||
|
{ msg = "unpaired surrogate UTF-16 value";
|
||||||
|
goto Lerr;
|
||||||
|
}
|
||||||
|
else if (u == 0xFFFE || u == 0xFFFF)
|
||||||
|
{ msg = "illegal UTF-16 value";
|
||||||
|
goto Lerr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = i;
|
||||||
|
return cast(dchar)u;
|
||||||
|
|
||||||
|
Lerr:
|
||||||
|
onUnicodeError(msg, i);
|
||||||
|
return cast(dchar)u; // dummy return
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ditto */
|
||||||
|
@safe
|
||||||
|
dchar decode(const scope dchar[] s, ref size_t idx)
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(idx >= 0 && idx < s.length);
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
size_t i = idx;
|
||||||
|
dchar c = s[i];
|
||||||
|
|
||||||
|
if (!isValidDchar(c))
|
||||||
|
goto Lerr;
|
||||||
|
idx = i + 1;
|
||||||
|
return c;
|
||||||
|
|
||||||
|
Lerr:
|
||||||
|
onUnicodeError("invalid UTF-32 value", i);
|
||||||
|
return c; // dummy return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* =================== Encode ======================= */
|
||||||
|
|
||||||
|
/*******************************
|
||||||
|
* Encodes character c and appends it to array s[].
|
||||||
|
*/
|
||||||
|
@safe pure nothrow
|
||||||
|
void encode(ref char[] s, dchar c)
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(isValidDchar(c));
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
char[] r = s;
|
||||||
|
|
||||||
|
if (c <= 0x7F)
|
||||||
|
{
|
||||||
|
r ~= cast(char) c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char[4] buf = void;
|
||||||
|
uint L;
|
||||||
|
|
||||||
|
if (c <= 0x7FF)
|
||||||
|
{
|
||||||
|
buf[0] = cast(char)(0xC0 | (c >> 6));
|
||||||
|
buf[1] = cast(char)(0x80 | (c & 0x3F));
|
||||||
|
L = 2;
|
||||||
|
}
|
||||||
|
else if (c <= 0xFFFF)
|
||||||
|
{
|
||||||
|
buf[0] = cast(char)(0xE0 | (c >> 12));
|
||||||
|
buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F));
|
||||||
|
buf[2] = cast(char)(0x80 | (c & 0x3F));
|
||||||
|
L = 3;
|
||||||
|
}
|
||||||
|
else if (c <= 0x10FFFF)
|
||||||
|
{
|
||||||
|
buf[0] = cast(char)(0xF0 | (c >> 18));
|
||||||
|
buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F));
|
||||||
|
buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F));
|
||||||
|
buf[3] = cast(char)(0x80 | (c & 0x3F));
|
||||||
|
L = 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
r ~= buf[0 .. L];
|
||||||
|
}
|
||||||
|
s = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
debug(utf) printf("utf.encode.unittest\n");
|
||||||
|
|
||||||
|
char[] s = "abcd".dup;
|
||||||
|
encode(s, cast(dchar)'a');
|
||||||
|
assert(s.length == 5);
|
||||||
|
assert(s == "abcda");
|
||||||
|
|
||||||
|
encode(s, cast(dchar)'\u00A9');
|
||||||
|
assert(s.length == 7);
|
||||||
|
assert(s == "abcda\xC2\xA9");
|
||||||
|
//assert(s == "abcda\u00A9"); // BUG: fix compiler
|
||||||
|
|
||||||
|
encode(s, cast(dchar)'\u2260');
|
||||||
|
assert(s.length == 10);
|
||||||
|
assert(s == "abcda\xC2\xA9\xE2\x89\xA0");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ditto */
|
||||||
|
@safe pure nothrow
|
||||||
|
void encode(ref wchar[] s, dchar c)
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(isValidDchar(c));
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
wchar[] r = s;
|
||||||
|
|
||||||
|
if (c <= 0xFFFF)
|
||||||
|
{
|
||||||
|
r ~= cast(wchar) c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wchar[2] buf = void;
|
||||||
|
|
||||||
|
buf[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||||
|
buf[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00);
|
||||||
|
r ~= buf;
|
||||||
|
}
|
||||||
|
s = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ditto */
|
||||||
|
@safe pure nothrow
|
||||||
|
void encode(ref dchar[] s, dchar c)
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(isValidDchar(c));
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
s ~= c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the code length of $(D c) in the encoding using $(D C) as a
|
||||||
|
code point. The code is returned in character count, not in bytes.
|
||||||
|
*/
|
||||||
|
@safe pure nothrow @nogc
|
||||||
|
ubyte codeLength(C)(dchar c)
|
||||||
|
{
|
||||||
|
static if (C.sizeof == 1)
|
||||||
|
{
|
||||||
|
if (c <= 0x7F) return 1;
|
||||||
|
if (c <= 0x7FF) return 2;
|
||||||
|
if (c <= 0xFFFF) return 3;
|
||||||
|
if (c <= 0x10FFFF) return 4;
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
else static if (C.sizeof == 2)
|
||||||
|
{
|
||||||
|
return c <= 0xFFFF ? 1 : 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static assert(C.sizeof == 4);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =================== Validation ======================= */
|
||||||
|
|
||||||
|
/***********************************
|
||||||
|
Checks to see if string is well formed or not. $(D S) can be an array
|
||||||
|
of $(D char), $(D wchar), or $(D dchar). Returns $(D false) if it is not.
|
||||||
|
Use to check all untrusted input for correctness.
|
||||||
|
*/
|
||||||
|
@safe
|
||||||
|
bool isValidString(S)(const scope S s)
|
||||||
|
{
|
||||||
|
auto len = s.length;
|
||||||
|
for (size_t i = 0; i < len; )
|
||||||
|
{
|
||||||
|
decode(s, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =================== Conversion to UTF8 ======================= */
|
||||||
|
|
||||||
|
@safe nothrow @nogc
|
||||||
|
char[] toUTF8(return scope char[] buf, dchar c)
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(isValidDchar(c));
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (c <= 0x7F)
|
||||||
|
{
|
||||||
|
buf[0] = cast(char) c;
|
||||||
|
return buf[0 .. 1];
|
||||||
|
}
|
||||||
|
else if (c <= 0x7FF)
|
||||||
|
{
|
||||||
|
buf[0] = cast(char)(0xC0 | (c >> 6));
|
||||||
|
buf[1] = cast(char)(0x80 | (c & 0x3F));
|
||||||
|
return buf[0 .. 2];
|
||||||
|
}
|
||||||
|
else if (c <= 0xFFFF)
|
||||||
|
{
|
||||||
|
buf[0] = cast(char)(0xE0 | (c >> 12));
|
||||||
|
buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F));
|
||||||
|
buf[2] = cast(char)(0x80 | (c & 0x3F));
|
||||||
|
return buf[0 .. 3];
|
||||||
|
}
|
||||||
|
else if (c <= 0x10FFFF)
|
||||||
|
{
|
||||||
|
buf[0] = cast(char)(0xF0 | (c >> 18));
|
||||||
|
buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F));
|
||||||
|
buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F));
|
||||||
|
buf[3] = cast(char)(0x80 | (c & 0x3F));
|
||||||
|
return buf[0 .. 4];
|
||||||
|
}
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************
|
||||||
|
* Encodes string s into UTF-8 and returns the encoded string.
|
||||||
|
*/
|
||||||
|
@safe
|
||||||
|
string toUTF8(return scope string s)
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(isValidString(s));
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ditto */
|
||||||
|
@trusted
|
||||||
|
string toUTF8(const scope wchar[] s)
|
||||||
|
{
|
||||||
|
char[] r;
|
||||||
|
size_t i;
|
||||||
|
size_t slen = s.length;
|
||||||
|
|
||||||
|
r.length = slen;
|
||||||
|
|
||||||
|
for (i = 0; i < slen; i++)
|
||||||
|
{ wchar c = s[i];
|
||||||
|
|
||||||
|
if (c <= 0x7F)
|
||||||
|
r[i] = cast(char)c; // fast path for ascii
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r.length = i;
|
||||||
|
foreach (dchar ch; s[i .. slen])
|
||||||
|
{
|
||||||
|
encode(r, ch);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cast(string)r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ditto */
|
||||||
|
@trusted
|
||||||
|
string toUTF8(const scope dchar[] s)
|
||||||
|
{
|
||||||
|
char[] r;
|
||||||
|
size_t i;
|
||||||
|
size_t slen = s.length;
|
||||||
|
|
||||||
|
r.length = slen;
|
||||||
|
|
||||||
|
for (i = 0; i < slen; i++)
|
||||||
|
{ dchar c = s[i];
|
||||||
|
|
||||||
|
if (c <= 0x7F)
|
||||||
|
r[i] = cast(char)c; // fast path for ascii
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r.length = i;
|
||||||
|
foreach (dchar d; s[i .. slen])
|
||||||
|
{
|
||||||
|
encode(r, d);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cast(string)r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =================== Conversion to UTF16 ======================= */
|
||||||
|
|
||||||
|
@safe pure nothrow @nogc
|
||||||
|
wchar[] toUTF16(return scope wchar[] buf, dchar c)
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(isValidDchar(c));
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (c <= 0xFFFF)
|
||||||
|
{
|
||||||
|
buf[0] = cast(wchar) c;
|
||||||
|
return buf[0 .. 1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buf[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||||
|
buf[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00);
|
||||||
|
return buf[0 .. 2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************
|
||||||
|
* Encodes string s into UTF-16 and returns the encoded string.
|
||||||
|
* toUTF16z() is suitable for calling the 'W' functions in the Win32 API that take
|
||||||
|
* an LPWSTR or LPCWSTR argument.
|
||||||
|
*/
|
||||||
|
@trusted
|
||||||
|
wstring toUTF16(const scope char[] s)
|
||||||
|
{
|
||||||
|
wchar[] r;
|
||||||
|
size_t slen = s.length;
|
||||||
|
|
||||||
|
if (!__ctfe)
|
||||||
|
{
|
||||||
|
// Reserve still does a lot if slen is zero.
|
||||||
|
// Return early for that case.
|
||||||
|
if (0 == slen)
|
||||||
|
return ""w;
|
||||||
|
r.reserve(slen);
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < slen; )
|
||||||
|
{
|
||||||
|
dchar c = s[i];
|
||||||
|
if (c <= 0x7F)
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
r ~= cast(wchar)c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
c = decode(s, i);
|
||||||
|
encode(r, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cast(wstring)r;
|
||||||
|
}
|
||||||
|
|
||||||
|
alias const(wchar)* wptr;
|
||||||
|
/** ditto */
|
||||||
|
@trusted
|
||||||
|
wptr toUTF16z(const scope char[] s)
|
||||||
|
{
|
||||||
|
wchar[] r;
|
||||||
|
size_t slen = s.length;
|
||||||
|
|
||||||
|
if (!__ctfe)
|
||||||
|
{
|
||||||
|
// Reserve still does a lot if slen is zero.
|
||||||
|
// Return early for that case.
|
||||||
|
if (0 == slen)
|
||||||
|
return &"\0"w[0];
|
||||||
|
r.reserve(slen + 1);
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < slen; )
|
||||||
|
{
|
||||||
|
dchar c = s[i];
|
||||||
|
if (c <= 0x7F)
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
r ~= cast(wchar)c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
c = decode(s, i);
|
||||||
|
encode(r, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r ~= '\000';
|
||||||
|
return &r[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ditto */
|
||||||
|
@safe
|
||||||
|
wstring toUTF16(return scope wstring s)
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(isValidString(s));
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ditto */
|
||||||
|
@trusted
|
||||||
|
wstring toUTF16(const scope dchar[] s)
|
||||||
|
{
|
||||||
|
wchar[] r;
|
||||||
|
size_t slen = s.length;
|
||||||
|
|
||||||
|
if (!__ctfe)
|
||||||
|
{
|
||||||
|
// Reserve still does a lot if slen is zero.
|
||||||
|
// Return early for that case.
|
||||||
|
if (0 == slen)
|
||||||
|
return ""w;
|
||||||
|
r.reserve(slen);
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < slen; i++)
|
||||||
|
{
|
||||||
|
encode(r, s[i]);
|
||||||
|
}
|
||||||
|
return cast(wstring)r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =================== Conversion to UTF32 ======================= */
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* Encodes string s into UTF-32 and returns the encoded string.
|
||||||
|
*/
|
||||||
|
@trusted
|
||||||
|
dstring toUTF32(const scope char[] s)
|
||||||
|
{
|
||||||
|
dchar[] r;
|
||||||
|
size_t slen = s.length;
|
||||||
|
size_t j = 0;
|
||||||
|
|
||||||
|
r.length = slen; // r[] will never be longer than s[]
|
||||||
|
for (size_t i = 0; i < slen; )
|
||||||
|
{
|
||||||
|
dchar c = s[i];
|
||||||
|
if (c >= 0x80)
|
||||||
|
c = decode(s, i);
|
||||||
|
else
|
||||||
|
i++; // c is ascii, no need for decode
|
||||||
|
r[j++] = c;
|
||||||
|
}
|
||||||
|
return cast(dstring)r[0 .. j];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ditto */
|
||||||
|
@trusted
|
||||||
|
dstring toUTF32(const scope wchar[] s)
|
||||||
|
{
|
||||||
|
dchar[] r;
|
||||||
|
size_t slen = s.length;
|
||||||
|
size_t j = 0;
|
||||||
|
|
||||||
|
r.length = slen; // r[] will never be longer than s[]
|
||||||
|
for (size_t i = 0; i < slen; )
|
||||||
|
{
|
||||||
|
dchar c = s[i];
|
||||||
|
if (c >= 0x80)
|
||||||
|
c = decode(s, i);
|
||||||
|
else
|
||||||
|
i++; // c is ascii, no need for decode
|
||||||
|
r[j++] = c;
|
||||||
|
}
|
||||||
|
return cast(dstring)r[0 .. j];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ditto */
|
||||||
|
@safe
|
||||||
|
dstring toUTF32(return scope dstring s)
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(isValidString(s));
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================ tests ================================== */
|
||||||
|
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
debug(utf) printf("utf.toUTF.unittest\n");
|
||||||
|
|
||||||
|
auto c = "hello"c[];
|
||||||
|
auto w = toUTF16(c);
|
||||||
|
assert(w == "hello");
|
||||||
|
auto d = toUTF32(c);
|
||||||
|
assert(d == "hello");
|
||||||
|
|
||||||
|
c = toUTF8(w);
|
||||||
|
assert(c == "hello");
|
||||||
|
d = toUTF32(w);
|
||||||
|
assert(d == "hello");
|
||||||
|
|
||||||
|
c = toUTF8(d);
|
||||||
|
assert(c == "hello");
|
||||||
|
w = toUTF16(d);
|
||||||
|
assert(w == "hello");
|
||||||
|
|
||||||
|
|
||||||
|
c = "hel\u1234o";
|
||||||
|
w = toUTF16(c);
|
||||||
|
assert(w == "hel\u1234o");
|
||||||
|
d = toUTF32(c);
|
||||||
|
assert(d == "hel\u1234o");
|
||||||
|
|
||||||
|
c = toUTF8(w);
|
||||||
|
assert(c == "hel\u1234o");
|
||||||
|
d = toUTF32(w);
|
||||||
|
assert(d == "hel\u1234o");
|
||||||
|
|
||||||
|
c = toUTF8(d);
|
||||||
|
assert(c == "hel\u1234o");
|
||||||
|
w = toUTF16(d);
|
||||||
|
assert(w == "hel\u1234o");
|
||||||
|
|
||||||
|
|
||||||
|
c = "he\U000BAAAAllo";
|
||||||
|
w = toUTF16(c);
|
||||||
|
//foreach (wchar c; w) printf("c = x%x\n", c);
|
||||||
|
//foreach (wchar c; cast(wstring)"he\U000BAAAAllo") printf("c = x%x\n", c);
|
||||||
|
assert(w == "he\U000BAAAAllo");
|
||||||
|
d = toUTF32(c);
|
||||||
|
assert(d == "he\U000BAAAAllo");
|
||||||
|
|
||||||
|
c = toUTF8(w);
|
||||||
|
assert(c == "he\U000BAAAAllo");
|
||||||
|
d = toUTF32(w);
|
||||||
|
assert(d == "he\U000BAAAAllo");
|
||||||
|
|
||||||
|
c = toUTF8(d);
|
||||||
|
assert(c == "he\U000BAAAAllo");
|
||||||
|
w = toUTF16(d);
|
||||||
|
assert(w == "he\U000BAAAAllo");
|
||||||
|
|
||||||
|
wchar[2] buf;
|
||||||
|
auto ret = toUTF16(buf, '\U000BAAAA');
|
||||||
|
assert(ret == "\U000BAAAA");
|
||||||
|
}
|
||||||
2031
external/arsd-webassembly/object.d
vendored
Normal file
2031
external/arsd-webassembly/object.d
vendored
Normal file
File diff suppressed because it is too large
Load Diff
8
external/arsd-webassembly/std/random.d
vendored
Normal file
8
external/arsd-webassembly/std/random.d
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
module std.random;
|
||||||
|
|
||||||
|
import arsd.webassembly;
|
||||||
|
|
||||||
|
int uniform(int low, int high) {
|
||||||
|
int max = high - low;
|
||||||
|
return low + eval!int(q{ return Math.floor(Math.random() * $0); }, max);
|
||||||
|
}
|
||||||
17
external/arsd-webassembly/std/stdio.d
vendored
Normal file
17
external/arsd-webassembly/std/stdio.d
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
840
external/printf/printf.c
vendored
Normal file
840
external/printf/printf.c
vendored
Normal file
@ -0,0 +1,840 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// \author (c) Marco Paland (info@paland.com)
|
||||||
|
// 2014-2019, PALANDesign Hannover, Germany
|
||||||
|
//
|
||||||
|
// \license The MIT License (MIT)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
//
|
||||||
|
// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on
|
||||||
|
// embedded systems with a very limited resources. These routines are thread
|
||||||
|
// safe and reentrant!
|
||||||
|
// Use this instead of the bloated standard/newlib printf cause these use
|
||||||
|
// malloc for printf (and may not be thread safe).
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "printf.h"
|
||||||
|
|
||||||
|
|
||||||
|
// define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the
|
||||||
|
// printf_config.h header file
|
||||||
|
// default: undefined
|
||||||
|
#ifdef PRINTF_INCLUDE_CONFIG_H
|
||||||
|
#include "printf_config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// 'ntoa' conversion buffer size, this must be big enough to hold one converted
|
||||||
|
// numeric number including padded zeros (dynamically created on stack)
|
||||||
|
// default: 32 byte
|
||||||
|
#ifndef PRINTF_NTOA_BUFFER_SIZE
|
||||||
|
#define PRINTF_NTOA_BUFFER_SIZE 32U
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 'ftoa' conversion buffer size, this must be big enough to hold one converted
|
||||||
|
// float number including padded zeros (dynamically created on stack)
|
||||||
|
// default: 32 byte
|
||||||
|
#ifndef PRINTF_FTOA_BUFFER_SIZE
|
||||||
|
#define PRINTF_FTOA_BUFFER_SIZE 32U
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// support for the floating point type (%f)
|
||||||
|
// default: activated
|
||||||
|
#ifndef PRINTF_DISABLE_SUPPORT_FLOAT
|
||||||
|
#define PRINTF_SUPPORT_FLOAT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// support for exponential floating point notation (%e/%g)
|
||||||
|
// default: activated
|
||||||
|
#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL
|
||||||
|
#define PRINTF_SUPPORT_EXPONENTIAL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// define the default floating point precision
|
||||||
|
// default: 6 digits
|
||||||
|
#ifndef PRINTF_DEFAULT_FLOAT_PRECISION
|
||||||
|
#define PRINTF_DEFAULT_FLOAT_PRECISION 6U
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// define the largest float suitable to print with %f
|
||||||
|
// default: 1e9
|
||||||
|
#ifndef PRINTF_MAX_FLOAT
|
||||||
|
#define PRINTF_MAX_FLOAT 1e9
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// support for the long long types (%llu or %p)
|
||||||
|
// default: activated
|
||||||
|
#ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG
|
||||||
|
#define PRINTF_SUPPORT_LONG_LONG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// support for the ptrdiff_t type (%t)
|
||||||
|
// ptrdiff_t is normally defined in <stddef.h> as long or long long type
|
||||||
|
// default: activated
|
||||||
|
#ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T
|
||||||
|
#define PRINTF_SUPPORT_PTRDIFF_T
|
||||||
|
#endif
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// internal flag definitions
|
||||||
|
#define FLAGS_ZEROPAD (1U << 0U)
|
||||||
|
#define FLAGS_LEFT (1U << 1U)
|
||||||
|
#define FLAGS_PLUS (1U << 2U)
|
||||||
|
#define FLAGS_SPACE (1U << 3U)
|
||||||
|
#define FLAGS_HASH (1U << 4U)
|
||||||
|
#define FLAGS_UPPERCASE (1U << 5U)
|
||||||
|
#define FLAGS_CHAR (1U << 6U)
|
||||||
|
#define FLAGS_SHORT (1U << 7U)
|
||||||
|
#define FLAGS_LONG (1U << 8U)
|
||||||
|
#define FLAGS_LONG_LONG (1U << 9U)
|
||||||
|
#define FLAGS_PRECISION (1U << 10U)
|
||||||
|
#define FLAGS_ADAPT_EXP (1U << 11U)
|
||||||
|
|
||||||
|
|
||||||
|
// import float.h for DBL_MAX
|
||||||
|
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||||
|
#include <float.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// output function type
|
||||||
|
typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen);
|
||||||
|
|
||||||
|
// internal buffer output
|
||||||
|
static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen)
|
||||||
|
{
|
||||||
|
if (idx < maxlen) {
|
||||||
|
((char*)buffer)[idx] = character;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// internal null output
|
||||||
|
static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen)
|
||||||
|
{
|
||||||
|
(void)character; (void)buffer; (void)idx; (void)maxlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
// internal secure strlen
|
||||||
|
// \return The length of the string (excluding the terminating 0) limited by 'maxsize'
|
||||||
|
static inline unsigned int _strnlen_s(const char* str, size_t maxsize)
|
||||||
|
{
|
||||||
|
const char* s;
|
||||||
|
for (s = str; *s && maxsize--; ++s);
|
||||||
|
return (unsigned int)(s - str);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// internal test if char is a digit (0-9)
|
||||||
|
// \return true if char is a digit
|
||||||
|
static inline bool _is_digit(char ch)
|
||||||
|
{
|
||||||
|
return (ch >= '0') && (ch <= '9');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// internal ASCII string to unsigned int conversion
|
||||||
|
static unsigned int _atoi(const char** str)
|
||||||
|
{
|
||||||
|
unsigned int i = 0U;
|
||||||
|
while (_is_digit(**str)) {
|
||||||
|
i = i * 10U + (unsigned int)(*((*str)++) - '0');
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// output the specified string in reverse, taking care of any zero-padding
|
||||||
|
static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags)
|
||||||
|
{
|
||||||
|
const size_t start_idx = idx;
|
||||||
|
|
||||||
|
// pad spaces up to given width
|
||||||
|
if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
|
||||||
|
for (size_t i = len; i < width; i++) {
|
||||||
|
out(' ', buffer, idx++, maxlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// reverse string
|
||||||
|
while (len) {
|
||||||
|
out(buf[--len], buffer, idx++, maxlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
// append pad spaces up to given width
|
||||||
|
if (flags & FLAGS_LEFT) {
|
||||||
|
while (idx - start_idx < width) {
|
||||||
|
out(' ', buffer, idx++, maxlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// internal itoa format
|
||||||
|
static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags)
|
||||||
|
{
|
||||||
|
// pad leading zeros
|
||||||
|
if (!(flags & FLAGS_LEFT)) {
|
||||||
|
if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
|
||||||
|
width--;
|
||||||
|
}
|
||||||
|
while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||||
|
buf[len++] = '0';
|
||||||
|
}
|
||||||
|
while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||||
|
buf[len++] = '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle hash
|
||||||
|
if (flags & FLAGS_HASH) {
|
||||||
|
if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) {
|
||||||
|
len--;
|
||||||
|
if (len && (base == 16U)) {
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||||
|
buf[len++] = 'x';
|
||||||
|
}
|
||||||
|
else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||||
|
buf[len++] = 'X';
|
||||||
|
}
|
||||||
|
else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||||
|
buf[len++] = 'b';
|
||||||
|
}
|
||||||
|
if (len < PRINTF_NTOA_BUFFER_SIZE) {
|
||||||
|
buf[len++] = '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len < PRINTF_NTOA_BUFFER_SIZE) {
|
||||||
|
if (negative) {
|
||||||
|
buf[len++] = '-';
|
||||||
|
}
|
||||||
|
else if (flags & FLAGS_PLUS) {
|
||||||
|
buf[len++] = '+'; // ignore the space if the '+' exists
|
||||||
|
}
|
||||||
|
else if (flags & FLAGS_SPACE) {
|
||||||
|
buf[len++] = ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// internal itoa for 'long' type
|
||||||
|
static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags)
|
||||||
|
{
|
||||||
|
char buf[PRINTF_NTOA_BUFFER_SIZE];
|
||||||
|
size_t len = 0U;
|
||||||
|
|
||||||
|
// no hash for 0 values
|
||||||
|
if (!value) {
|
||||||
|
flags &= ~FLAGS_HASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write if precision != 0 and value is != 0
|
||||||
|
if (!(flags & FLAGS_PRECISION) || value) {
|
||||||
|
do {
|
||||||
|
const char digit = (char)(value % base);
|
||||||
|
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
||||||
|
value /= base;
|
||||||
|
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// internal itoa for 'long long' type
|
||||||
|
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||||
|
static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags)
|
||||||
|
{
|
||||||
|
char buf[PRINTF_NTOA_BUFFER_SIZE];
|
||||||
|
size_t len = 0U;
|
||||||
|
|
||||||
|
// no hash for 0 values
|
||||||
|
if (!value) {
|
||||||
|
flags &= ~FLAGS_HASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write if precision != 0 and value is != 0
|
||||||
|
if (!(flags & FLAGS_PRECISION) || value) {
|
||||||
|
do {
|
||||||
|
const char digit = (char)(value % base);
|
||||||
|
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
||||||
|
value /= base;
|
||||||
|
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
|
||||||
|
}
|
||||||
|
#endif // PRINTF_SUPPORT_LONG_LONG
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||||
|
|
||||||
|
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||||
|
// forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT
|
||||||
|
static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// internal ftoa for fixed decimal floating point
|
||||||
|
static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
|
||||||
|
{
|
||||||
|
char buf[PRINTF_FTOA_BUFFER_SIZE];
|
||||||
|
size_t len = 0U;
|
||||||
|
double diff = 0.0;
|
||||||
|
|
||||||
|
// powers of 10
|
||||||
|
static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
|
||||||
|
|
||||||
|
// test for special values
|
||||||
|
if (value != value)
|
||||||
|
return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags);
|
||||||
|
if (value < -DBL_MAX)
|
||||||
|
return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags);
|
||||||
|
if (value > DBL_MAX)
|
||||||
|
return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags);
|
||||||
|
|
||||||
|
// test for very large values
|
||||||
|
// standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad
|
||||||
|
if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) {
|
||||||
|
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||||
|
return _etoa(out, buffer, idx, maxlen, value, prec, width, flags);
|
||||||
|
#else
|
||||||
|
return 0U;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// test for negative
|
||||||
|
bool negative = false;
|
||||||
|
if (value < 0) {
|
||||||
|
negative = true;
|
||||||
|
value = 0 - value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set default precision, if not set explicitly
|
||||||
|
if (!(flags & FLAGS_PRECISION)) {
|
||||||
|
prec = PRINTF_DEFAULT_FLOAT_PRECISION;
|
||||||
|
}
|
||||||
|
// limit precision to 9, cause a prec >= 10 can lead to overflow errors
|
||||||
|
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) {
|
||||||
|
buf[len++] = '0';
|
||||||
|
prec--;
|
||||||
|
}
|
||||||
|
|
||||||
|
int whole = (int)value;
|
||||||
|
double tmp = (value - whole) * pow10[prec];
|
||||||
|
unsigned long frac = (unsigned long)tmp;
|
||||||
|
diff = tmp - frac;
|
||||||
|
|
||||||
|
if (diff > 0.5) {
|
||||||
|
++frac;
|
||||||
|
// handle rollover, e.g. case 0.99 with prec 1 is 1.0
|
||||||
|
if (frac >= pow10[prec]) {
|
||||||
|
frac = 0;
|
||||||
|
++whole;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (diff < 0.5) {
|
||||||
|
}
|
||||||
|
else if ((frac == 0U) || (frac & 1U)) {
|
||||||
|
// if halfway, round up if odd OR if last digit is 0
|
||||||
|
++frac;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prec == 0U) {
|
||||||
|
diff = value - (double)whole;
|
||||||
|
if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) {
|
||||||
|
// exactly 0.5 and ODD, then round up
|
||||||
|
// 1.5 -> 2, but 2.5 -> 2
|
||||||
|
++whole;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
unsigned int count = prec;
|
||||||
|
// now do fractional part, as an unsigned number
|
||||||
|
while (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||||
|
--count;
|
||||||
|
buf[len++] = (char)(48U + (frac % 10U));
|
||||||
|
if (!(frac /= 10U)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// add extra 0s
|
||||||
|
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) {
|
||||||
|
buf[len++] = '0';
|
||||||
|
}
|
||||||
|
if (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||||
|
// add decimal
|
||||||
|
buf[len++] = '.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// do whole part, number is reversed
|
||||||
|
while (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||||
|
buf[len++] = (char)(48 + (whole % 10));
|
||||||
|
if (!(whole /= 10)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pad leading zeros
|
||||||
|
if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) {
|
||||||
|
if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
|
||||||
|
width--;
|
||||||
|
}
|
||||||
|
while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) {
|
||||||
|
buf[len++] = '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||||
|
if (negative) {
|
||||||
|
buf[len++] = '-';
|
||||||
|
}
|
||||||
|
else if (flags & FLAGS_PLUS) {
|
||||||
|
buf[len++] = '+'; // ignore the space if the '+' exists
|
||||||
|
}
|
||||||
|
else if (flags & FLAGS_SPACE) {
|
||||||
|
buf[len++] = ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||||
|
// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse <m.jasperse@gmail.com>
|
||||||
|
static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
|
||||||
|
{
|
||||||
|
// check for NaN and special values
|
||||||
|
if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) {
|
||||||
|
return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine the sign
|
||||||
|
const bool negative = value < 0;
|
||||||
|
if (negative) {
|
||||||
|
value = -value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// default precision
|
||||||
|
if (!(flags & FLAGS_PRECISION)) {
|
||||||
|
prec = PRINTF_DEFAULT_FLOAT_PRECISION;
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine the decimal exponent
|
||||||
|
// based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c)
|
||||||
|
union {
|
||||||
|
uint64_t U;
|
||||||
|
double F;
|
||||||
|
} conv;
|
||||||
|
|
||||||
|
conv.F = value;
|
||||||
|
int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2
|
||||||
|
conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2)
|
||||||
|
// now approximate log10 from the log2 integer part and an expansion of ln around 1.5
|
||||||
|
int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168);
|
||||||
|
// now we want to compute 10^expval but we want to be sure it won't overflow
|
||||||
|
exp2 = (int)(expval * 3.321928094887362 + 0.5);
|
||||||
|
const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453;
|
||||||
|
const double z2 = z * z;
|
||||||
|
conv.U = (uint64_t)(exp2 + 1023) << 52U;
|
||||||
|
// compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex
|
||||||
|
conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14)))));
|
||||||
|
// correct for rounding errors
|
||||||
|
if (value < conv.F) {
|
||||||
|
expval--;
|
||||||
|
conv.F /= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters
|
||||||
|
unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U;
|
||||||
|
|
||||||
|
// in "%g" mode, "prec" is the number of *significant figures* not decimals
|
||||||
|
if (flags & FLAGS_ADAPT_EXP) {
|
||||||
|
// do we want to fall-back to "%f" mode?
|
||||||
|
if ((value >= 1e-4) && (value < 1e6)) {
|
||||||
|
if ((int)prec > expval) {
|
||||||
|
prec = (unsigned)((int)prec - expval - 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
prec = 0;
|
||||||
|
}
|
||||||
|
flags |= FLAGS_PRECISION; // make sure _ftoa respects precision
|
||||||
|
// no characters in exponent
|
||||||
|
minwidth = 0U;
|
||||||
|
expval = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// we use one sigfig for the whole part
|
||||||
|
if ((prec > 0) && (flags & FLAGS_PRECISION)) {
|
||||||
|
--prec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// will everything fit?
|
||||||
|
unsigned int fwidth = width;
|
||||||
|
if (width > minwidth) {
|
||||||
|
// we didn't fall-back so subtract the characters required for the exponent
|
||||||
|
fwidth -= minwidth;
|
||||||
|
} else {
|
||||||
|
// not enough characters, so go back to default sizing
|
||||||
|
fwidth = 0U;
|
||||||
|
}
|
||||||
|
if ((flags & FLAGS_LEFT) && minwidth) {
|
||||||
|
// if we're padding on the right, DON'T pad the floating part
|
||||||
|
fwidth = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rescale the float value
|
||||||
|
if (expval) {
|
||||||
|
value /= conv.F;
|
||||||
|
}
|
||||||
|
|
||||||
|
// output the floating part
|
||||||
|
const size_t start_idx = idx;
|
||||||
|
idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP);
|
||||||
|
|
||||||
|
// output the exponent part
|
||||||
|
if (minwidth) {
|
||||||
|
// output the exponential symbol
|
||||||
|
out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen);
|
||||||
|
// output the exponent value
|
||||||
|
idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth-1, FLAGS_ZEROPAD | FLAGS_PLUS);
|
||||||
|
// might need to right-pad spaces
|
||||||
|
if (flags & FLAGS_LEFT) {
|
||||||
|
while (idx - start_idx < width) out(' ', buffer, idx++, maxlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
#endif // PRINTF_SUPPORT_EXPONENTIAL
|
||||||
|
#endif // PRINTF_SUPPORT_FLOAT
|
||||||
|
|
||||||
|
|
||||||
|
// internal vsnprintf
|
||||||
|
static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va)
|
||||||
|
{
|
||||||
|
unsigned int flags, width, precision, n;
|
||||||
|
size_t idx = 0U;
|
||||||
|
|
||||||
|
if (!buffer) {
|
||||||
|
// use null output function
|
||||||
|
out = _out_null;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*format)
|
||||||
|
{
|
||||||
|
// format specifier? %[flags][width][.precision][length]
|
||||||
|
if (*format != '%') {
|
||||||
|
// no
|
||||||
|
out(*format, buffer, idx++, maxlen);
|
||||||
|
format++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// yes, evaluate it
|
||||||
|
format++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// evaluate flags
|
||||||
|
flags = 0U;
|
||||||
|
do {
|
||||||
|
switch (*format) {
|
||||||
|
case '0': flags |= FLAGS_ZEROPAD; format++; n = 1U; break;
|
||||||
|
case '-': flags |= FLAGS_LEFT; format++; n = 1U; break;
|
||||||
|
case '+': flags |= FLAGS_PLUS; format++; n = 1U; break;
|
||||||
|
case ' ': flags |= FLAGS_SPACE; format++; n = 1U; break;
|
||||||
|
case '#': flags |= FLAGS_HASH; format++; n = 1U; break;
|
||||||
|
default : n = 0U; break;
|
||||||
|
}
|
||||||
|
} while (n);
|
||||||
|
|
||||||
|
// evaluate width field
|
||||||
|
width = 0U;
|
||||||
|
if (_is_digit(*format)) {
|
||||||
|
width = _atoi(&format);
|
||||||
|
}
|
||||||
|
else if (*format == '*') {
|
||||||
|
const int w = va_arg(va, int);
|
||||||
|
if (w < 0) {
|
||||||
|
flags |= FLAGS_LEFT; // reverse padding
|
||||||
|
width = (unsigned int)-w;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
width = (unsigned int)w;
|
||||||
|
}
|
||||||
|
format++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// evaluate precision field
|
||||||
|
precision = 0U;
|
||||||
|
if (*format == '.') {
|
||||||
|
flags |= FLAGS_PRECISION;
|
||||||
|
format++;
|
||||||
|
if (_is_digit(*format)) {
|
||||||
|
precision = _atoi(&format);
|
||||||
|
}
|
||||||
|
else if (*format == '*') {
|
||||||
|
const int prec = (int)va_arg(va, int);
|
||||||
|
precision = prec > 0 ? (unsigned int)prec : 0U;
|
||||||
|
format++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// evaluate length field
|
||||||
|
switch (*format) {
|
||||||
|
case 'l' :
|
||||||
|
flags |= FLAGS_LONG;
|
||||||
|
format++;
|
||||||
|
if (*format == 'l') {
|
||||||
|
flags |= FLAGS_LONG_LONG;
|
||||||
|
format++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'h' :
|
||||||
|
flags |= FLAGS_SHORT;
|
||||||
|
format++;
|
||||||
|
if (*format == 'h') {
|
||||||
|
flags |= FLAGS_CHAR;
|
||||||
|
format++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#if defined(PRINTF_SUPPORT_PTRDIFF_T)
|
||||||
|
case 't' :
|
||||||
|
flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case 'j' :
|
||||||
|
flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
case 'z' :
|
||||||
|
flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// evaluate specifier
|
||||||
|
switch (*format) {
|
||||||
|
case 'd' :
|
||||||
|
case 'i' :
|
||||||
|
case 'u' :
|
||||||
|
case 'x' :
|
||||||
|
case 'X' :
|
||||||
|
case 'o' :
|
||||||
|
case 'b' : {
|
||||||
|
// set the base
|
||||||
|
unsigned int base;
|
||||||
|
if (*format == 'x' || *format == 'X') {
|
||||||
|
base = 16U;
|
||||||
|
}
|
||||||
|
else if (*format == 'o') {
|
||||||
|
base = 8U;
|
||||||
|
}
|
||||||
|
else if (*format == 'b') {
|
||||||
|
base = 2U;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
base = 10U;
|
||||||
|
flags &= ~FLAGS_HASH; // no hash for dec format
|
||||||
|
}
|
||||||
|
// uppercase
|
||||||
|
if (*format == 'X') {
|
||||||
|
flags |= FLAGS_UPPERCASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// no plus or space flag for u, x, X, o, b
|
||||||
|
if ((*format != 'i') && (*format != 'd')) {
|
||||||
|
flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore '0' flag when precision is given
|
||||||
|
if (flags & FLAGS_PRECISION) {
|
||||||
|
flags &= ~FLAGS_ZEROPAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert the integer
|
||||||
|
if ((*format == 'i') || (*format == 'd')) {
|
||||||
|
// signed
|
||||||
|
if (flags & FLAGS_LONG_LONG) {
|
||||||
|
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||||
|
const long long value = va_arg(va, long long);
|
||||||
|
idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (flags & FLAGS_LONG) {
|
||||||
|
const long value = va_arg(va, long);
|
||||||
|
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int);
|
||||||
|
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// unsigned
|
||||||
|
if (flags & FLAGS_LONG_LONG) {
|
||||||
|
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||||
|
idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (flags & FLAGS_LONG) {
|
||||||
|
idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) : va_arg(va, unsigned int);
|
||||||
|
idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||||
|
case 'f' :
|
||||||
|
case 'F' :
|
||||||
|
if (*format == 'F') flags |= FLAGS_UPPERCASE;
|
||||||
|
idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
#if defined(PRINTF_SUPPORT_EXPONENTIAL)
|
||||||
|
case 'e':
|
||||||
|
case 'E':
|
||||||
|
case 'g':
|
||||||
|
case 'G':
|
||||||
|
if ((*format == 'g')||(*format == 'G')) flags |= FLAGS_ADAPT_EXP;
|
||||||
|
if ((*format == 'E')||(*format == 'G')) flags |= FLAGS_UPPERCASE;
|
||||||
|
idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
#endif // PRINTF_SUPPORT_EXPONENTIAL
|
||||||
|
#endif // PRINTF_SUPPORT_FLOAT
|
||||||
|
case 'c' : {
|
||||||
|
unsigned int l = 1U;
|
||||||
|
// pre padding
|
||||||
|
if (!(flags & FLAGS_LEFT)) {
|
||||||
|
while (l++ < width) {
|
||||||
|
out(' ', buffer, idx++, maxlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// char output
|
||||||
|
out((char)va_arg(va, int), buffer, idx++, maxlen);
|
||||||
|
// post padding
|
||||||
|
if (flags & FLAGS_LEFT) {
|
||||||
|
while (l++ < width) {
|
||||||
|
out(' ', buffer, idx++, maxlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 's' : {
|
||||||
|
const char* p = va_arg(va, char*);
|
||||||
|
unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1);
|
||||||
|
// pre padding
|
||||||
|
if (flags & FLAGS_PRECISION) {
|
||||||
|
l = (l < precision ? l : precision);
|
||||||
|
}
|
||||||
|
if (!(flags & FLAGS_LEFT)) {
|
||||||
|
while (l++ < width) {
|
||||||
|
out(' ', buffer, idx++, maxlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// string output
|
||||||
|
while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
|
||||||
|
out(*(p++), buffer, idx++, maxlen);
|
||||||
|
}
|
||||||
|
// post padding
|
||||||
|
if (flags & FLAGS_LEFT) {
|
||||||
|
while (l++ < width) {
|
||||||
|
out(' ', buffer, idx++, maxlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'p' : {
|
||||||
|
width = sizeof(void*) * 2U;
|
||||||
|
flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE;
|
||||||
|
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||||
|
const bool is_ll = sizeof(uintptr_t) == sizeof(long long);
|
||||||
|
if (is_ll) {
|
||||||
|
idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
#endif
|
||||||
|
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags);
|
||||||
|
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case '%' :
|
||||||
|
out('%', buffer, idx++, maxlen);
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default :
|
||||||
|
out(*format, buffer, idx++, maxlen);
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// termination
|
||||||
|
out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
|
||||||
|
|
||||||
|
// return written chars without terminating \0
|
||||||
|
return (int)idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
int sprintf_(char* buffer, const char* format, ...)
|
||||||
|
{
|
||||||
|
va_list va;
|
||||||
|
va_start(va, format);
|
||||||
|
const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va);
|
||||||
|
va_end(va);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
97
external/printf/printf.h
vendored
Normal file
97
external/printf/printf.h
vendored
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// \author (c) Marco Paland (info@paland.com)
|
||||||
|
// 2014-2019, PALANDesign Hannover, Germany
|
||||||
|
//
|
||||||
|
// \license The MIT License (MIT)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
//
|
||||||
|
// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on
|
||||||
|
// embedded systems with a very limited resources.
|
||||||
|
// Use this instead of bloated standard/newlib printf.
|
||||||
|
// These routines are thread safe and reentrant.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef _PRINTF_H_
|
||||||
|
#define _PRINTF_H_
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tiny sprintf implementation
|
||||||
|
* Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD!
|
||||||
|
* \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output!
|
||||||
|
* \param format A string that specifies the format of the output
|
||||||
|
* \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
|
||||||
|
*/
|
||||||
|
#define sprintf sprintf_
|
||||||
|
int sprintf_(char* buffer, const char* format, ...);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tiny snprintf/vsnprintf implementation
|
||||||
|
* \param buffer A pointer to the buffer where to store the formatted string
|
||||||
|
* \param count The maximum number of characters to store in the buffer, including a terminating null character
|
||||||
|
* \param format A string that specifies the format of the output
|
||||||
|
* \param va A value identifying a variable arguments list
|
||||||
|
* \return The number of characters that COULD have been written into the buffer, not counting the terminating
|
||||||
|
* null character. A value equal or larger than count indicates truncation. Only when the returned value
|
||||||
|
* is non-negative and less than count, the string has been completely written.
|
||||||
|
*/
|
||||||
|
#define snprintf snprintf_
|
||||||
|
#define vsnprintf vsnprintf_
|
||||||
|
int snprintf_(char* buffer, size_t count, const char* format, ...);
|
||||||
|
int vsnprintf_(char* buffer, size_t count, const char* format, va_list va);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tiny vprintf implementation
|
||||||
|
* \param format A string that specifies the format of the output
|
||||||
|
* \param va A value identifying a variable arguments list
|
||||||
|
* \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
|
||||||
|
*/
|
||||||
|
#define vprintf vprintf_
|
||||||
|
int vprintf_(const char* format, va_list va);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* printf with output function
|
||||||
|
* You may use this as dynamic alternative to printf() with its fixed _putchar() output
|
||||||
|
* \param out An output function which takes one character and an argument pointer
|
||||||
|
* \param arg An argument pointer for user data passed to output function
|
||||||
|
* \param format A string that specifies the format of the output
|
||||||
|
* \return The number of characters that are sent to the output function, not counting the terminating null character
|
||||||
|
*/
|
||||||
|
int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _PRINTF_H_
|
||||||
201
external/tinyalloc/LICENCE
vendored
Normal file
201
external/tinyalloc/LICENCE
vendored
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright {yyyy} {name of copyright owner}
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
270
external/tinyalloc/tinyalloc.c
vendored
Normal file
270
external/tinyalloc/tinyalloc.c
vendored
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
#include "tinyalloc.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef TA_DEBUG
|
||||||
|
extern void print_s(char *);
|
||||||
|
extern void print_i(size_t);
|
||||||
|
#else
|
||||||
|
#define print_s(X)
|
||||||
|
#define print_i(X)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct Block Block;
|
||||||
|
|
||||||
|
struct Block {
|
||||||
|
void *addr;
|
||||||
|
Block *next;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Block *free; // first free block
|
||||||
|
Block *used; // first used block
|
||||||
|
Block *fresh; // first available blank block
|
||||||
|
size_t top; // top free addr
|
||||||
|
} Heap;
|
||||||
|
|
||||||
|
static Heap *heap = NULL;
|
||||||
|
static const void *heap_limit = NULL;
|
||||||
|
static size_t heap_split_thresh;
|
||||||
|
static size_t heap_alignment;
|
||||||
|
static size_t heap_max_blocks;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If compaction is enabled, inserts block
|
||||||
|
* into free list, sorted by addr.
|
||||||
|
* If disabled, add block has new head of
|
||||||
|
* the free list.
|
||||||
|
*/
|
||||||
|
static void insert_block(Block *block) {
|
||||||
|
#ifndef TA_DISABLE_COMPACT
|
||||||
|
Block *ptr = heap->free;
|
||||||
|
Block *prev = NULL;
|
||||||
|
while (ptr != NULL) {
|
||||||
|
if ((size_t)block->addr <= (size_t)ptr->addr) {
|
||||||
|
print_s("insert");
|
||||||
|
print_i((size_t)ptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prev = ptr;
|
||||||
|
ptr = ptr->next;
|
||||||
|
}
|
||||||
|
if (prev != NULL) {
|
||||||
|
if (ptr == NULL) {
|
||||||
|
print_s("new tail");
|
||||||
|
}
|
||||||
|
prev->next = block;
|
||||||
|
} else {
|
||||||
|
print_s("new head");
|
||||||
|
heap->free = block;
|
||||||
|
}
|
||||||
|
block->next = ptr;
|
||||||
|
#else
|
||||||
|
block->next = heap->free;
|
||||||
|
heap->free = block;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef TA_DISABLE_COMPACT
|
||||||
|
static void release_blocks(Block *scan, Block *to) {
|
||||||
|
Block *scan_next;
|
||||||
|
while (scan != to) {
|
||||||
|
print_s("release");
|
||||||
|
print_i((size_t)scan);
|
||||||
|
scan_next = scan->next;
|
||||||
|
scan->next = heap->fresh;
|
||||||
|
heap->fresh = scan;
|
||||||
|
scan->addr = 0;
|
||||||
|
scan->size = 0;
|
||||||
|
scan = scan_next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void compact() {
|
||||||
|
Block *ptr = heap->free;
|
||||||
|
Block *prev;
|
||||||
|
Block *scan;
|
||||||
|
while (ptr != NULL) {
|
||||||
|
prev = ptr;
|
||||||
|
scan = ptr->next;
|
||||||
|
while (scan != NULL &&
|
||||||
|
(size_t)prev->addr + prev->size == (size_t)scan->addr) {
|
||||||
|
print_s("merge");
|
||||||
|
print_i((size_t)scan);
|
||||||
|
prev = scan;
|
||||||
|
scan = scan->next;
|
||||||
|
}
|
||||||
|
if (prev != ptr) {
|
||||||
|
size_t new_size =
|
||||||
|
(size_t)prev->addr - (size_t)ptr->addr + prev->size;
|
||||||
|
print_s("new size");
|
||||||
|
print_i(new_size);
|
||||||
|
ptr->size = new_size;
|
||||||
|
Block *next = prev->next;
|
||||||
|
// make merged blocks available
|
||||||
|
release_blocks(ptr->next, prev->next);
|
||||||
|
// relink
|
||||||
|
ptr->next = next;
|
||||||
|
}
|
||||||
|
ptr = ptr->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool ta_init(const void *base, const void *limit, const size_t heap_blocks, const size_t split_thresh, const size_t alignment) {
|
||||||
|
heap = (Heap *)base;
|
||||||
|
heap_limit = limit;
|
||||||
|
heap_split_thresh = split_thresh;
|
||||||
|
heap_alignment = alignment;
|
||||||
|
heap_max_blocks = heap_blocks;
|
||||||
|
|
||||||
|
heap->free = NULL;
|
||||||
|
heap->used = NULL;
|
||||||
|
heap->fresh = (Block *)(heap + 1);
|
||||||
|
heap->top = (size_t)(heap->fresh + heap_blocks);
|
||||||
|
|
||||||
|
Block *block = heap->fresh;
|
||||||
|
size_t i = heap_max_blocks - 1;
|
||||||
|
while (i--) {
|
||||||
|
block->next = block + 1;
|
||||||
|
block++;
|
||||||
|
}
|
||||||
|
block->next = NULL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ta_free(void *free) {
|
||||||
|
Block *block = heap->used;
|
||||||
|
Block *prev = NULL;
|
||||||
|
while (block != NULL) {
|
||||||
|
if (free == block->addr) {
|
||||||
|
if (prev) {
|
||||||
|
prev->next = block->next;
|
||||||
|
} else {
|
||||||
|
heap->used = block->next;
|
||||||
|
}
|
||||||
|
insert_block(block);
|
||||||
|
#ifndef TA_DISABLE_COMPACT
|
||||||
|
compact();
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
prev = block;
|
||||||
|
block = block->next;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Block *alloc_block(size_t num) {
|
||||||
|
Block *ptr = heap->free;
|
||||||
|
Block *prev = NULL;
|
||||||
|
size_t top = heap->top;
|
||||||
|
num = (num + heap_alignment - 1) & -heap_alignment;
|
||||||
|
while (ptr != NULL) {
|
||||||
|
const int is_top = ((size_t)ptr->addr + ptr->size >= top) && ((size_t)ptr->addr + num <= (size_t)heap_limit);
|
||||||
|
if (is_top || ptr->size >= num) {
|
||||||
|
if (prev != NULL) {
|
||||||
|
prev->next = ptr->next;
|
||||||
|
} else {
|
||||||
|
heap->free = ptr->next;
|
||||||
|
}
|
||||||
|
ptr->next = heap->used;
|
||||||
|
heap->used = ptr;
|
||||||
|
if (is_top) {
|
||||||
|
print_s("resize top block");
|
||||||
|
ptr->size = num;
|
||||||
|
heap->top = (size_t)ptr->addr + num;
|
||||||
|
#ifndef TA_DISABLE_SPLIT
|
||||||
|
} else if (heap->fresh != NULL) {
|
||||||
|
size_t excess = ptr->size - num;
|
||||||
|
if (excess >= heap_split_thresh) {
|
||||||
|
ptr->size = num;
|
||||||
|
Block *split = heap->fresh;
|
||||||
|
heap->fresh = split->next;
|
||||||
|
split->addr = (void *)((size_t)ptr->addr + num);
|
||||||
|
print_s("split");
|
||||||
|
print_i((size_t)split->addr);
|
||||||
|
split->size = excess;
|
||||||
|
insert_block(split);
|
||||||
|
#ifndef TA_DISABLE_COMPACT
|
||||||
|
compact();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
prev = ptr;
|
||||||
|
ptr = ptr->next;
|
||||||
|
}
|
||||||
|
// no matching free blocks
|
||||||
|
// see if any other blocks available
|
||||||
|
size_t new_top = top + num;
|
||||||
|
if (heap->fresh != NULL && new_top <= (size_t)heap_limit) {
|
||||||
|
ptr = heap->fresh;
|
||||||
|
heap->fresh = ptr->next;
|
||||||
|
ptr->addr = (void *)top;
|
||||||
|
ptr->next = heap->used;
|
||||||
|
ptr->size = num;
|
||||||
|
heap->used = ptr;
|
||||||
|
heap->top = new_top;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *ta_alloc(size_t num) {
|
||||||
|
Block *block = alloc_block(num);
|
||||||
|
if (block != NULL) {
|
||||||
|
return block->addr;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void memclear(void *ptr, size_t num) {
|
||||||
|
size_t *ptrw = (size_t *)ptr;
|
||||||
|
size_t numw = (num & -sizeof(size_t)) / sizeof(size_t);
|
||||||
|
while (numw--) {
|
||||||
|
*ptrw++ = 0;
|
||||||
|
}
|
||||||
|
num &= (sizeof(size_t) - 1);
|
||||||
|
uint8_t *ptrb = (uint8_t *)ptrw;
|
||||||
|
while (num--) {
|
||||||
|
*ptrb++ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *ta_calloc(size_t num, size_t size) {
|
||||||
|
num *= size;
|
||||||
|
Block *block = alloc_block(num);
|
||||||
|
if (block != NULL) {
|
||||||
|
memclear(block->addr, num);
|
||||||
|
return block->addr;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t count_blocks(Block *ptr) {
|
||||||
|
size_t num = 0;
|
||||||
|
while (ptr != NULL) {
|
||||||
|
num++;
|
||||||
|
ptr = ptr->next;
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ta_num_free() {
|
||||||
|
return count_blocks(heap->free);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ta_num_used() {
|
||||||
|
return count_blocks(heap->used);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ta_num_fresh() {
|
||||||
|
return count_blocks(heap->fresh);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ta_check() {
|
||||||
|
return heap_max_blocks == ta_num_free() + ta_num_used() + ta_num_fresh();
|
||||||
|
}
|
||||||
23
external/tinyalloc/tinyalloc.h
vendored
Normal file
23
external/tinyalloc/tinyalloc.h
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
uint32_t grow(uint32_t pages);
|
||||||
|
|
||||||
|
bool ta_init(const void *base, const void *limit, const size_t heap_blocks, const size_t split_thresh, const size_t alignment);
|
||||||
|
void *ta_alloc(size_t num);
|
||||||
|
void *ta_calloc(size_t num, size_t size);
|
||||||
|
bool ta_free(void *ptr);
|
||||||
|
|
||||||
|
size_t ta_num_free();
|
||||||
|
size_t ta_num_used();
|
||||||
|
size_t ta_num_fresh();
|
||||||
|
bool ta_check();
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
1
external/xxhash/xxhash.c
vendored
1
external/xxhash/xxhash.c
vendored
@ -38,5 +38,6 @@
|
|||||||
|
|
||||||
#define XXH_STATIC_LINKING_ONLY /* access advanced declarations */
|
#define XXH_STATIC_LINKING_ONLY /* access advanced declarations */
|
||||||
#define XXH_IMPLEMENTATION /* access definitions */
|
#define XXH_IMPLEMENTATION /* access definitions */
|
||||||
|
#define XXH_NO_STDLIB 1
|
||||||
|
|
||||||
#include "xxhash.h"
|
#include "xxhash.h"
|
||||||
|
|||||||
72
external/xxhash/xxhash.h
vendored
72
external/xxhash/xxhash.h
vendored
@ -2394,35 +2394,57 @@ static void XXH_free(void* p) { free(p); }
|
|||||||
|
|
||||||
#endif /* XXH_NO_STDLIB */
|
#endif /* XXH_NO_STDLIB */
|
||||||
|
|
||||||
#ifndef XXH_memcpy
|
void *
|
||||||
/*!
|
memcpy(void *dest, const void *src, size_t n)
|
||||||
* @internal
|
{
|
||||||
* @brief XXH_memcpy() macro can be redirected at compile time
|
if(!dest || n == 0) return dest;
|
||||||
*/
|
|
||||||
# include <string.h>
|
|
||||||
# define XXH_memcpy memcpy
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef XXH_memset
|
uint8_t *dp = (uint8_t *)dest;
|
||||||
/*!
|
uint8_t *sp = (uint8_t *)src;
|
||||||
* @internal
|
|
||||||
* @brief XXH_memset() macro can be redirected at compile time
|
|
||||||
*/
|
|
||||||
# include <string.h>
|
|
||||||
# define XXH_memset memset
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef XXH_memcmp
|
for(size_t i = 0; i < n; i += 1)
|
||||||
/*!
|
{
|
||||||
* @internal
|
dp[i] = sp[i];
|
||||||
* @brief XXH_memcmp() macro can be redirected at compile time
|
}
|
||||||
* Note: only needed by XXH128.
|
|
||||||
*/
|
|
||||||
# include <string.h>
|
|
||||||
# define XXH_memcmp memcmp
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
memset(void *dest, int ch, size_t n)
|
||||||
|
{
|
||||||
|
if(!dest || n == 0) return dest;
|
||||||
|
|
||||||
|
uint8_t *p = (uint8_t *)dest;
|
||||||
|
uint8_t v = (uint8_t )(ch & 0xFF);
|
||||||
|
|
||||||
|
for(size_t i = 0; i < n; i += 1)
|
||||||
|
{
|
||||||
|
p[i] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
memcmp(const void *s1, const void *s2, size_t n)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
uint8_t *p1 = (uint8_t *)s1;
|
||||||
|
uint8_t *p2 = (uint8_t *)s2;
|
||||||
|
|
||||||
|
for(size_t i = 0; i < n; i += 1)
|
||||||
|
{
|
||||||
|
result += p1[i] - p2[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define XXH_memcpy memcpy
|
||||||
|
#define XXH_memset memset
|
||||||
|
#define XXH_memcmp memcmp
|
||||||
|
|
||||||
#include <limits.h> /* ULLONG_MAX */
|
#include <limits.h> /* ULLONG_MAX */
|
||||||
|
|
||||||
|
|||||||
38
fonts.d
38
fonts.d
@ -5,10 +5,6 @@ import dlib.aliases;
|
|||||||
import dlib.util;
|
import dlib.util;
|
||||||
import dlib.alloc;
|
import dlib.alloc;
|
||||||
import dlib.math;
|
import dlib.math;
|
||||||
import std.math.traits : isNaN;
|
|
||||||
import std.math : Floor = floor;
|
|
||||||
import std.algorithm.comparison : clamp;
|
|
||||||
import std.algorithm.sorting;
|
|
||||||
|
|
||||||
const u64 FONT_MAX_BANDS = 8;
|
const u64 FONT_MAX_BANDS = 8;
|
||||||
const u64 FONT_TEX_WIDTH = 4096;
|
const u64 FONT_TEX_WIDTH = 4096;
|
||||||
@ -162,6 +158,9 @@ struct Glyph
|
|||||||
f32 atlas_top;
|
f32 atlas_top;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static if(NativeTarget)
|
||||||
|
{
|
||||||
|
|
||||||
__gshared FT_Library FT_LIB;
|
__gshared FT_Library FT_LIB;
|
||||||
alias FontFace = FT_Face;
|
alias FontFace = FT_Face;
|
||||||
|
|
||||||
@ -388,6 +387,8 @@ CreateAtlas(Arena* arena, FontFace font, u32 size, UVec2 atlas_dim)
|
|||||||
return atlas;
|
return atlas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BuildFontGlyph(Arena* arena, u32 index, u32 glyph_index, SlugFontInfo* font_info, u32* curve_index, stbtt_fontinfo* stb_font_info)
|
BuildFontGlyph(Arena* arena, u32 index, u32 glyph_index, SlugFontInfo* font_info, u32* curve_index, stbtt_fontinfo* stb_font_info)
|
||||||
{
|
{
|
||||||
@ -421,14 +422,14 @@ BuildFontGlyph(Arena* arena, u32 index, u32 glyph_index, SlugFontInfo* font_info
|
|||||||
f32 dx = x-cx;
|
f32 dx = x-cx;
|
||||||
f32 dy = y-cy;
|
f32 dy = y-cy;
|
||||||
|
|
||||||
if(fabs(dx) < 0.1 && fabs(dy) < 0.1)
|
if(Abs(dx) < 0.1 && Abs(dy) < 0.1)
|
||||||
{
|
{
|
||||||
cx = x;
|
cx = x;
|
||||||
cy = y;
|
cy = y;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
f32 length = sqrt(dx*dx + dy*dy);
|
f32 length = Sqrt(dx*dx + dy*dy);
|
||||||
f32 nx = -dy/length*0.05;
|
f32 nx = -dy/length*0.05;
|
||||||
f32 ny = -dx/length*0.05;
|
f32 ny = -dx/length*0.05;
|
||||||
|
|
||||||
@ -554,7 +555,7 @@ LoadFontCurves(Arena* arena, SlugFontInfo* font_info, u8[] font_file_data)
|
|||||||
curve_texel_count += font_info.glyphs[i].curve_count*2;
|
curve_texel_count += font_info.glyphs[i].curve_count*2;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 curve_texel_height = clamp(cast(u32)((curve_texel_count+FONT_TEX_WIDTH-1) / FONT_TEX_WIDTH), 1, u32.max);
|
u32 curve_texel_height = Clamp(cast(u32)((curve_texel_count+FONT_TEX_WIDTH-1) / FONT_TEX_WIDTH), 1, u32.max);
|
||||||
|
|
||||||
u32[] curve_start_indices = Alloc!(u32)(arena, font_info.glyphs.length);
|
u32[] curve_start_indices = Alloc!(u32)(arena, font_info.glyphs.length);
|
||||||
SlugTexel!(f32) curve_texel = {
|
SlugTexel!(f32) curve_texel = {
|
||||||
@ -578,14 +579,14 @@ LoadFontCurves(Arena* arena, SlugFontInfo* font_info, u8[] font_file_data)
|
|||||||
UVec2 t0 = UVec2(curve_index%FONT_TEX_WIDTH, curve_index/FONT_TEX_WIDTH);
|
UVec2 t0 = UVec2(curve_index%FONT_TEX_WIDTH, curve_index/FONT_TEX_WIDTH);
|
||||||
u32 offset = cast(u32)((t0.y*FONT_TEX_WIDTH + t0.x) * 4);
|
u32 offset = cast(u32)((t0.y*FONT_TEX_WIDTH + t0.x) * 4);
|
||||||
|
|
||||||
curve_texel.data[offset .. offset+4] = [curve.p1.x, curve.p1.y, curve.p2.x, curve.p2.y];
|
Assign(curve_texel.data[offset .. offset+4], curve.p1.x, curve.p1.y, curve.p2.x, curve.p2.y);
|
||||||
|
|
||||||
curve_index += 1;
|
curve_index += 1;
|
||||||
|
|
||||||
UVec2 t1 = UVec2(curve_index%FONT_TEX_WIDTH, curve_index/FONT_TEX_WIDTH);
|
UVec2 t1 = UVec2(curve_index%FONT_TEX_WIDTH, curve_index/FONT_TEX_WIDTH);
|
||||||
offset = cast(u32)((t1.y*FONT_TEX_WIDTH + t1.x) * 4);
|
offset = cast(u32)((t1.y*FONT_TEX_WIDTH + t1.x) * 4);
|
||||||
|
|
||||||
curve_texel.data[offset .. offset+4] = [curve.p3.x, curve.p3.y, 0.0, 0.0];
|
Assign(curve_texel.data[offset .. offset+4], curve.p3.x, curve.p3.y, 0.0, 0.0);
|
||||||
|
|
||||||
curve_index += 1;
|
curve_index += 1;
|
||||||
}
|
}
|
||||||
@ -617,7 +618,7 @@ LoadFontCurves(Arena* arena, SlugFontInfo* font_info, u8[] font_file_data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 band_texel_height = clamp(cast(u32)((band_total_count+FONT_TEX_WIDTH-1) / FONT_TEX_WIDTH), 1U, u32.max);
|
u32 band_texel_height = Clamp(cast(u32)((band_total_count+FONT_TEX_WIDTH-1) / FONT_TEX_WIDTH), 1U, u32.max);
|
||||||
SlugTexel!(u32) band_texel = {
|
SlugTexel!(u32) band_texel = {
|
||||||
data: Alloc!(u32)(arena, FONT_TEX_WIDTH*band_texel_height*4),
|
data: Alloc!(u32)(arena, FONT_TEX_WIDTH*band_texel_height*4),
|
||||||
width: FONT_TEX_WIDTH,
|
width: FONT_TEX_WIDTH,
|
||||||
@ -683,7 +684,7 @@ LoadFontCurves(Arena* arena, SlugFontInfo* font_info, u8[] font_file_data)
|
|||||||
count = band_data.bands[1][index].count;
|
count = band_data.bands[1][index].count;
|
||||||
}
|
}
|
||||||
|
|
||||||
band_texel.data[di .. di+2] = [count, offsets[j]];
|
Assign(band_texel.data[di .. di+2], count, offsets[j]);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach(j; 0 .. band_total)
|
foreach(j; 0 .. band_total)
|
||||||
@ -700,7 +701,7 @@ LoadFontCurves(Arena* arena, SlugFontInfo* font_info, u8[] font_file_data)
|
|||||||
u32 tl = ls+k;
|
u32 tl = ls+k;
|
||||||
u32 di = cast(u32)((tl/FONT_TEX_WIDTH*FONT_TEX_WIDTH + tl%FONT_TEX_WIDTH) * 4);
|
u32 di = cast(u32)((tl/FONT_TEX_WIDTH*FONT_TEX_WIDTH + tl%FONT_TEX_WIDTH) * 4);
|
||||||
|
|
||||||
band_texel.data[di .. di+2] = [ct%FONT_TEX_WIDTH, ct/FONT_TEX_WIDTH];
|
Assign(band_texel.data[di .. di+2], ct%FONT_TEX_WIDTH, ct/FONT_TEX_WIDTH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -729,7 +730,8 @@ SlugSortBand(Arena* arena, SlugBandEntry* entry, SlugCurve[] curves, u32 axis)
|
|||||||
refs[i] = SlugCurveRef(entry.indices[i], mx);
|
refs[i] = SlugCurveRef(entry.indices[i], mx);
|
||||||
}
|
}
|
||||||
|
|
||||||
sort!("a.sort_key < b.sort_key")(refs);
|
assert(false, "implement sorting!");
|
||||||
|
// sort!("a.sort_key < b.sort_key")(refs);
|
||||||
|
|
||||||
foreach(i; 0 .. entry.count)
|
foreach(i; 0 .. entry.count)
|
||||||
{
|
{
|
||||||
@ -802,8 +804,8 @@ SlugBuildBands(Arena* arena, u32 index, SlugFontInfo* font_info, u32 band_count)
|
|||||||
|
|
||||||
if(size.y > 0.0)
|
if(size.y > 0.0)
|
||||||
{
|
{
|
||||||
u32 b0 = cast(u32)clamp(floor(curve_min.y * glyph.band_scale.y + glyph.band_offset.y), 0.0, cast(f32)(band_count-1));
|
u32 b0 = cast(u32)Clamp(Floor(curve_min.y * glyph.band_scale.y + glyph.band_offset.y), 0.0, cast(f32)(band_count-1));
|
||||||
u32 b1 = cast(u32)clamp(floor(curve_max.y * glyph.band_scale.y + glyph.band_offset.y), 0.0, cast(f32)(band_count-1));
|
u32 b1 = cast(u32)Clamp(Floor(curve_max.y * glyph.band_scale.y + glyph.band_offset.y), 0.0, cast(f32)(band_count-1));
|
||||||
|
|
||||||
for(u32 j = b0; j <= b1; j += 1)
|
for(u32 j = b0; j <= b1; j += 1)
|
||||||
{
|
{
|
||||||
@ -814,8 +816,8 @@ SlugBuildBands(Arena* arena, u32 index, SlugFontInfo* font_info, u32 band_count)
|
|||||||
|
|
||||||
if(size.x > 0.0)
|
if(size.x > 0.0)
|
||||||
{
|
{
|
||||||
u32 b0 = cast(u32)clamp(Floor(curve_min.x * glyph.band_scale.x + glyph.band_offset.x), 0.0, cast(f32)(band_count-1));
|
u32 b0 = cast(u32)Clamp(Floor(curve_min.x * glyph.band_scale.x + glyph.band_offset.x), 0.0, cast(f32)(band_count-1));
|
||||||
u32 b1 = cast(u32)clamp(Floor(curve_max.x * glyph.band_scale.x + glyph.band_offset.x), 0.0, cast(f32)(band_count-1));
|
u32 b1 = cast(u32)Clamp(Floor(curve_max.x * glyph.band_scale.x + glyph.band_offset.x), 0.0, cast(f32)(band_count-1));
|
||||||
|
|
||||||
for(u32 j = b0; j <= b1; j += 1)
|
for(u32 j = b0; j <= b1; j += 1)
|
||||||
{
|
{
|
||||||
@ -883,7 +885,7 @@ SlugLoadFontVertex(u8 ch, IVec2 pos, SlugFont* font, SlugBuffer* buffer)
|
|||||||
vertices[3].em_space_pos = Vec2(glyph.rect.max.x, glyph.rect.min.y);
|
vertices[3].em_space_pos = Vec2(glyph.rect.max.x, glyph.rect.min.y);
|
||||||
|
|
||||||
u32 vidx = vertex_start;
|
u32 vidx = vertex_start;
|
||||||
indices[0 .. 6] = [vidx+0, vidx+2, vidx+3, vidx+3, vidx+1, vidx+0];
|
Assign(indices[0 .. 6], vidx+0, vidx+2, vidx+3, vidx+3, vidx+1, vidx+0);
|
||||||
|
|
||||||
buffer.quad_offset += 1;
|
buffer.quad_offset += 1;
|
||||||
|
|
||||||
|
|||||||
@ -9,3 +9,11 @@ public import dlib.platform;
|
|||||||
public import dlib.aliases;
|
public import dlib.aliases;
|
||||||
public import dlib.fonts;
|
public import dlib.fonts;
|
||||||
public import dlib.assets;
|
public import dlib.assets;
|
||||||
|
|
||||||
|
version(DLIB_TEST)
|
||||||
|
{
|
||||||
|
version(WebAssembly)
|
||||||
|
{
|
||||||
|
void _start() { main() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
304
platform.d
304
platform.d
@ -1,6 +1,10 @@
|
|||||||
module dlib.platform;
|
module dlib.platform;
|
||||||
|
|
||||||
import dlib.aliases;
|
import dlib.aliases;
|
||||||
|
|
||||||
|
static if(NativeTarget)
|
||||||
|
{
|
||||||
|
|
||||||
import dlib.alloc : Reset;
|
import dlib.alloc : Reset;
|
||||||
import dlib.alloc;
|
import dlib.alloc;
|
||||||
import dlib.util;
|
import dlib.util;
|
||||||
@ -23,117 +27,121 @@ const WINDOW_EDGE_BUFFER = 50;
|
|||||||
enum Input : u32
|
enum Input : u32
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
Backspace = 0x08,
|
Backspace = 0x08,
|
||||||
Tab = 0x09,
|
Tab = 0x09,
|
||||||
Enter = 0x0A,
|
Enter = 0x0A,
|
||||||
Escape = 0x1B,
|
Escape = 0x1B,
|
||||||
Space = 0x20,
|
Space = 0x20,
|
||||||
Exclamation = 0x21,
|
Exclamation = 0x21,
|
||||||
DoubleQuote = 0x22,
|
DoubleQuote = 0x22,
|
||||||
Hash = 0x23,
|
Hash = 0x23,
|
||||||
Dollar = 0x24,
|
Dollar = 0x24,
|
||||||
Percent = 0x25,
|
Percent = 0x25,
|
||||||
Ampersand = 0x26,
|
Ampersand = 0x26,
|
||||||
SingleQuote = 0x27,
|
SingleQuote = 0x27,
|
||||||
LeftParen = 0x28,
|
LeftParen = 0x28,
|
||||||
RightParent = 0x29,
|
RightParent = 0x29,
|
||||||
Asterisk = 0x2A,
|
Asterisk = 0x2A,
|
||||||
Plus = 0x2B,
|
Plus = 0x2B,
|
||||||
Comma = 0x2C,
|
Comma = 0x2C,
|
||||||
Minus = 0x2D,
|
Minus = 0x2D,
|
||||||
Period = 0x2E,
|
Period = 0x2E,
|
||||||
Slash = 0x2F,
|
Slash = 0x2F,
|
||||||
Zero = 0x30,
|
Zero = 0x30,
|
||||||
One = 0x31,
|
One = 0x31,
|
||||||
Two = 0x32,
|
Two = 0x32,
|
||||||
Three = 0x33,
|
Three = 0x33,
|
||||||
Four = 0x34,
|
Four = 0x34,
|
||||||
Five = 0x35,
|
Five = 0x35,
|
||||||
Six = 0x36,
|
Six = 0x36,
|
||||||
Seven = 0x37,
|
Seven = 0x37,
|
||||||
Eight = 0x38,
|
Eight = 0x38,
|
||||||
Nine = 0x39,
|
Nine = 0x39,
|
||||||
Colon = 0x3A,
|
Colon = 0x3A,
|
||||||
Semicolon = 0x3B,
|
Semicolon = 0x3B,
|
||||||
LessThan = 0x3C,
|
LessThan = 0x3C,
|
||||||
Equals = 0x3D,
|
Equals = 0x3D,
|
||||||
GreaterThan = 0x3E,
|
GreaterThan = 0x3E,
|
||||||
Question = 0x3F,
|
Question = 0x3F,
|
||||||
At = 0x40,
|
At = 0x40,
|
||||||
A = 0x41, B = 0x42, C = 0x43, D = 0x44, E = 0x45, F = 0x46, G = 0x47, H = 0x48, I = 0x49, J = 0x4A, K = 0x4B, L = 0x4C, M = 0x4D,
|
A = 0x41, B = 0x42, C = 0x43, D = 0x44, E = 0x45, F = 0x46, G = 0x47, H = 0x48, I = 0x49, J = 0x4A, K = 0x4B, L = 0x4C, M = 0x4D,
|
||||||
N = 0x4E, O = 0x4F, P = 0x50, Q = 0x51, R = 0x52, S = 0x53, T = 0x54, U = 0x55, V = 0x56, W = 0x57, X = 0x58, Y = 0x59, Z = 0x5A,
|
N = 0x4E, O = 0x4F, P = 0x50, Q = 0x51, R = 0x52, S = 0x53, T = 0x54, U = 0x55, V = 0x56, W = 0x57, X = 0x58, Y = 0x59, Z = 0x5A,
|
||||||
LeftBracket = 0x5B,
|
LeftBracket = 0x5B,
|
||||||
BackSlash = 0x5C,
|
BackSlash = 0x5C,
|
||||||
RightBracket = 0x5D,
|
RightBracket = 0x5D,
|
||||||
Caret = 0x5E,
|
Caret = 0x5E,
|
||||||
Underscore = 0x5F,
|
Underscore = 0x5F,
|
||||||
Grave = 0x60,
|
Grave = 0x60,
|
||||||
a = I.A+32, b = I.B+32, c = I.C+32, d = I.D+32, e = I.E+32, f = I.F+32, g = I.G+32, h = I.H+32, i = I.I+32, j = I.J+32, k = I.K+32, l = I.L+32, m = I.M+32,
|
a = I.A+32, b = I.B+32, c = I.C+32, d = I.D+32, e = I.E+32, f = I.F+32, g = I.G+32, h = I.H+32, i = I.I+32, j = I.J+32, k = I.K+32, l = I.L+32, m = I.M+32,
|
||||||
n = I.N+32, o = I.O+32, p = I.P+32, q = I.Q+32, r = I.R+32, s = I.S+32, t = I.T+32, u = I.U+32, v = I.V+32, w = I.W+32, x = I.X+32, y = I.Y+32, z = I.Z+32,
|
n = I.N+32, o = I.O+32, p = I.P+32, q = I.Q+32, r = I.R+32, s = I.S+32, t = I.T+32, u = I.U+32, v = I.V+32, w = I.W+32, x = I.X+32, y = I.Y+32, z = I.Z+32,
|
||||||
LeftBrace = 0x7B,
|
LeftBrace = 0x7B,
|
||||||
VerticalBar = 0x7C,
|
VerticalBar = 0x7C,
|
||||||
RightBrace = 0x7D,
|
RightBrace = 0x7D,
|
||||||
Tilde = 0x7E,
|
Tilde = 0x7E,
|
||||||
Delete = 0x7F,
|
Delete = 0x7F,
|
||||||
|
|
||||||
F1 = 0x150,
|
F1 = 0x150,
|
||||||
F2 = 0x151,
|
F2 = 0x151,
|
||||||
F3 = 0x152,
|
F3 = 0x152,
|
||||||
F4 = 0x153,
|
F4 = 0x153,
|
||||||
F5 = 0x154,
|
F5 = 0x154,
|
||||||
F6 = 0x155,
|
F6 = 0x155,
|
||||||
F7 = 0x156,
|
F7 = 0x156,
|
||||||
F8 = 0x157,
|
F8 = 0x157,
|
||||||
F9 = 0x158,
|
F9 = 0x158,
|
||||||
F10 = 0x159,
|
F10 = 0x159,
|
||||||
F11 = 0x15A,
|
F11 = 0x15A,
|
||||||
F12 = 0x15B,
|
F12 = 0x15B,
|
||||||
|
|
||||||
PrintScreen = 0x10C,
|
PrintScreen = 0x10C,
|
||||||
ScrollLock = 0x10D,
|
ScrollLock = 0x10D,
|
||||||
Pause = 0x10E,
|
Pause = 0x10E,
|
||||||
Insert = 0x10F,
|
Insert = 0x10F,
|
||||||
Home = 0x110,
|
Home = 0x110,
|
||||||
End = 0x111,
|
End = 0x111,
|
||||||
PageUp = 0x112,
|
PageUp = 0x112,
|
||||||
PageDown = 0x113,
|
PageDown = 0x113,
|
||||||
NumLock = 0x114,
|
|
||||||
|
|
||||||
NumEnter = 0x10A,
|
NumLock = 0x114,
|
||||||
|
NumEnter = 0x10A,
|
||||||
NumAsterisk = 0x12A,
|
NumAsterisk = 0x12A,
|
||||||
NumPlus = 0x12B,
|
NumPlus = 0x12B,
|
||||||
NumMinus = 0x12D,
|
NumMinus = 0x12D,
|
||||||
NumPeriod = 0x12E,
|
NumPeriod = 0x12E,
|
||||||
NumSlash = 0x12F,
|
NumSlash = 0x12F,
|
||||||
NumZero = 0x130,
|
NumZero = 0x130,
|
||||||
NumOne = 0x131,
|
NumOne = 0x131,
|
||||||
NumTwo = 0x132,
|
NumTwo = 0x132,
|
||||||
NumThree = 0x133,
|
NumThree = 0x133,
|
||||||
NumFour = 0x134,
|
NumFour = 0x134,
|
||||||
NumFive = 0x135,
|
NumFive = 0x135,
|
||||||
NumSix = 0x136,
|
NumSix = 0x136,
|
||||||
NumSeven = 0x137,
|
NumSeven = 0x137,
|
||||||
NumEight = 0x138,
|
NumEight = 0x138,
|
||||||
NumNine = 0x139,
|
NumNine = 0x139,
|
||||||
|
|
||||||
LeftCtrl = 0x13A,
|
LeftCtrl = 0x13A,
|
||||||
RightCtrl = 0x13B,
|
RightCtrl = 0x13B,
|
||||||
LeftShift = 0x13C,
|
LeftShift = 0x13C,
|
||||||
RightShift = 0x13D,
|
RightShift = 0x13D,
|
||||||
LeftSuper = 0x13E,
|
LeftSuper = 0x13E,
|
||||||
RightSuper = 0x13F,
|
RightSuper = 0x13F,
|
||||||
LeftAlt = 0x140,
|
LeftAlt = 0x140,
|
||||||
RightAlt = 0x141,
|
RightAlt = 0x141,
|
||||||
CapsLock = 0x142,
|
CapsLock = 0x142,
|
||||||
|
|
||||||
Left = 0x143,
|
Left = 0x143,
|
||||||
Right = 0x144,
|
Right = 0x144,
|
||||||
Up = 0x145,
|
Up = 0x145,
|
||||||
Down = 0x146,
|
Down = 0x146,
|
||||||
|
|
||||||
// Mouse
|
// Mouse
|
||||||
MouseMotion = 0x147,
|
MouseMotion = 0x147,
|
||||||
|
LeftClick = 0x148,
|
||||||
LeftClick = 0x148, MiddleClick = 0x149, RightClick = 0x14A, ScrollUp = 0x14B, ScrollDown = 0x14C,
|
MiddleClick = 0x149,
|
||||||
|
RightClick = 0x14A,
|
||||||
|
ScrollUp = 0x14B,
|
||||||
|
ScrollDown = 0x14C,
|
||||||
};
|
};
|
||||||
|
|
||||||
alias I = Input;
|
alias I = Input;
|
||||||
@ -204,7 +212,7 @@ GetEvents(PlatformWindow* window)
|
|||||||
{
|
{
|
||||||
Lock(&window.input_mutex);
|
Lock(&window.input_mutex);
|
||||||
|
|
||||||
Inputs* inputs = &window.inputs[window.input_idx];
|
Inputs* inputs = &window.inputs[window.input_idx];
|
||||||
window.input_idx = (window.input_idx + 1) % 2;
|
window.input_idx = (window.input_idx + 1) % 2;
|
||||||
ResetInputs(&window.inputs[window.input_idx]);
|
ResetInputs(&window.inputs[window.input_idx]);
|
||||||
|
|
||||||
@ -381,17 +389,17 @@ import core.sys.linux.sys.inotify;
|
|||||||
import core.sys.linux.fcntl;
|
import core.sys.linux.fcntl;
|
||||||
import core.sys.posix.sys.time : timespec, timeval, gettimeofday;
|
import core.sys.posix.sys.time : timespec, timeval, gettimeofday;
|
||||||
import core.sys.posix.unistd;
|
import core.sys.posix.unistd;
|
||||||
import core.sys.posix.pthread : PThread = pthread_t,
|
import core.sys.posix.pthread : PThread = pthread_t,
|
||||||
PThreadCond = pthread_cond_t,
|
PThreadCond = pthread_cond_t,
|
||||||
PThreadMutex = pthread_mutex_t,
|
PThreadMutex = pthread_mutex_t,
|
||||||
PThreadMutexInit = pthread_mutex_init,
|
PThreadMutexInit = pthread_mutex_init,
|
||||||
PThreadCondInit = pthread_cond_init,
|
PThreadCondInit = pthread_cond_init,
|
||||||
PThreadCreate = pthread_create,
|
PThreadCreate = pthread_create,
|
||||||
PThreadMutexLock = pthread_mutex_lock,
|
PThreadMutexLock = pthread_mutex_lock,
|
||||||
PThreadCondWait = pthread_cond_wait,
|
PThreadCondWait = pthread_cond_wait,
|
||||||
PThreadMutexUnlock = pthread_mutex_unlock,
|
PThreadMutexUnlock = pthread_mutex_unlock,
|
||||||
PThreadCondSignal = pthread_cond_signal,
|
PThreadCondSignal = pthread_cond_signal,
|
||||||
PThreadExit = pthread_exit,
|
PThreadExit = pthread_exit,
|
||||||
PThreadCondTimedWait = pthread_cond_timedwait;
|
PThreadCondTimedWait = pthread_cond_timedwait;
|
||||||
|
|
||||||
import core.stdc.string : strlen;
|
import core.stdc.string : strlen;
|
||||||
@ -584,32 +592,29 @@ PushMotion(Inputs* inputs, i32 rel_x, i32 rel_y, i32 x, i32 y)
|
|||||||
|
|
||||||
struct PlatformWindow
|
struct PlatformWindow
|
||||||
{
|
{
|
||||||
Atom[Atoms.max] atoms;
|
Atom[Atoms.max] atoms;
|
||||||
Display* display;
|
Display* display;
|
||||||
Window window;
|
Window window;
|
||||||
Window root_window;
|
Window root_window;
|
||||||
i32 screen_id;
|
i32 screen_id;
|
||||||
// xcb_connection_t* conn;
|
u32 w;
|
||||||
// xcb_screen_t* screen;
|
u32 h;
|
||||||
// xcb_window_t window;
|
i32 mouse_prev_x;
|
||||||
u32 w;
|
i32 mouse_prev_y;
|
||||||
u32 h;
|
bool locked_cursor;
|
||||||
i32 mouse_prev_x;
|
bool close;
|
||||||
i32 mouse_prev_y;
|
Modifier modifier;
|
||||||
bool locked_cursor;
|
|
||||||
bool close;
|
|
||||||
Modifier modifier;
|
|
||||||
|
|
||||||
SysThread thread;
|
SysThread thread;
|
||||||
MessageQueue msg_queue;
|
MessageQueue msg_queue;
|
||||||
u32 input_idx;
|
u32 input_idx;
|
||||||
Inputs[2] inputs;
|
Inputs[2] inputs;
|
||||||
TicketMut input_mutex;
|
TicketMut input_mutex;
|
||||||
|
|
||||||
Mut cb_msg_mut;
|
Mut cb_msg_mut;
|
||||||
TicketMut cb_mut;
|
TicketMut cb_mut;
|
||||||
Selection[CBM.max] selections;
|
Selection[CBM.max] selections;
|
||||||
version(linux) u32 cb_transfer_size;
|
version(linux) u32 cb_transfer_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Library
|
struct Library
|
||||||
@ -1977,3 +1982,62 @@ version(DLIB_TEST) unittest
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pragma(inline) u64
|
||||||
|
RDTSC()
|
||||||
|
{
|
||||||
|
union u64_split
|
||||||
|
{
|
||||||
|
u64 full;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u32 lower;
|
||||||
|
u32 upper;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
u64_split val;
|
||||||
|
|
||||||
|
u64_split* valp = &val;
|
||||||
|
asm
|
||||||
|
{
|
||||||
|
cpuid;
|
||||||
|
rdtsc;
|
||||||
|
mov R8, valp;
|
||||||
|
mov valp.upper.offsetof[R8], EDX;
|
||||||
|
mov valp.lower.offsetof[R8], EAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
return val.full;
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma(inline) u64
|
||||||
|
OSTimeFreq()
|
||||||
|
{
|
||||||
|
u64 freq;
|
||||||
|
|
||||||
|
version (linux)
|
||||||
|
{
|
||||||
|
u64 freq = 1000000;
|
||||||
|
}
|
||||||
|
else static assert(false, NO_IMPL);
|
||||||
|
|
||||||
|
return freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma(inline) u64
|
||||||
|
OSTime()
|
||||||
|
{
|
||||||
|
version(linux)
|
||||||
|
{
|
||||||
|
import core.sys.linux.sys.time;
|
||||||
|
timeval value;
|
||||||
|
gettimeofday(&value, null);
|
||||||
|
|
||||||
|
u64 time = OSTimeFreq() * cast(u64)(value.tv_sec) + cast(u64)(value.tv_usec);
|
||||||
|
}
|
||||||
|
else static assert(false, NO_IMPL);
|
||||||
|
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
9
test.sh
9
test.sh
@ -2,11 +2,16 @@
|
|||||||
|
|
||||||
name="Test_Runner"
|
name="Test_Runner"
|
||||||
|
|
||||||
|
flags="-P-I/usr/include/freetype2 -L-lfreetype"
|
||||||
|
if [ "$1" == "wasm" ]; then
|
||||||
|
flags="-mtriple=wasm32-unknown-unknown-wasm --Xcc=-DBUILD_WASM -Iexternal/arsd-webassembly"
|
||||||
|
fi
|
||||||
|
|
||||||
/bin/bash ./build.sh build
|
/bin/bash ./build.sh build
|
||||||
|
|
||||||
ldc2 platform.d fonts.d aliases.d math.d util.d alloc.d assets.d external/xxhash/xxhash.d build/libcglm.a -d-version=DLIB_TEST -Xcc=-mno-sse -P-I/usr/include/freetype2 -L-lfreetype --main --unittest -g --of=$name -verrors=8
|
ldc2 platform.d fonts.d aliases.d math.d util.d alloc.d assets.d build/libxxhash.a build/libcglm.a build/libprintf.a $flags -d-version=DLIB_TEST --main --unittest -g --of=$name -verrors=50
|
||||||
|
|
||||||
rm $name.o
|
rm $name.o
|
||||||
./$name
|
./$name
|
||||||
rm $name
|
#rm $name
|
||||||
|
|
||||||
|
|||||||
517
util.d
517
util.d
@ -3,35 +3,44 @@ module dlib.util;
|
|||||||
import dlib.aliases;
|
import dlib.aliases;
|
||||||
import dlib.alloc;
|
import dlib.alloc;
|
||||||
|
|
||||||
import xxhash3;
|
|
||||||
import dlibincludes;
|
import dlibincludes;
|
||||||
|
|
||||||
import std.stdio : write, writeln, writef, writefln, stderr;
|
//import std.traits;
|
||||||
import std.conv;
|
|
||||||
import std.string;
|
|
||||||
import std.traits;
|
|
||||||
|
|
||||||
import core.stdc.string : memset;
|
static if(NativeTarget)
|
||||||
import core.simd;
|
{
|
||||||
|
import std.format : sformat;
|
||||||
|
import std.stdio : write, writeln, writef, writefln, stderr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
enum bool StringType(T) = (is(T: string) || is(T: u8[]) || is(T: char[]) || is(T: const(char)[]));
|
}
|
||||||
|
|
||||||
|
enum bool StringType(T) = (is(T: string) || is(T: u8[]) || is(T: char[]) || is(T: const(char)[]));
|
||||||
|
|
||||||
pragma(inline) void
|
pragma(inline) void
|
||||||
Int3()
|
Int3()
|
||||||
{
|
{
|
||||||
debug asm
|
static if(NativeTarget)
|
||||||
{
|
{
|
||||||
db 0xCC;
|
debug asm
|
||||||
|
{
|
||||||
|
db 0xCC;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma(inline) void
|
pragma(inline) void
|
||||||
Pause()
|
Pause()
|
||||||
{
|
{
|
||||||
asm
|
static if(NativeTarget)
|
||||||
{
|
{
|
||||||
rep;
|
asm
|
||||||
nop;
|
{
|
||||||
|
rep;
|
||||||
|
nop;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,37 +78,37 @@ CastArr(T, U)(U[] input_array)
|
|||||||
return output_array;
|
return output_array;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
Debugf(Args...)(string fmt, Args args)
|
|
||||||
{
|
|
||||||
debug Logf(fmt, args, "[DEBUG]: ");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Logf(string prefix = "INFO ", Args...)(string fmt, Args args)
|
Logf(string prefix = "INFO ", Args...)(string fmt, Args args)
|
||||||
{
|
{
|
||||||
try
|
static if(NativeTarget)
|
||||||
{
|
{
|
||||||
writef("[%s]: ", prefix);
|
try
|
||||||
writefln(fmt, args);
|
{
|
||||||
}
|
writef("[%s]: ", prefix);
|
||||||
catch (Exception e)
|
writefln(fmt, args);
|
||||||
{
|
}
|
||||||
assert(false, "Incompatible format type");
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
assert(false, "Incompatible format type");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Logif(Args...)(string fmt, Args args, string func = __FUNCTION__)
|
Logif(Args...)(string fmt, Args args, string func = __FUNCTION__)
|
||||||
{
|
{
|
||||||
try
|
static if(NativeTarget)
|
||||||
{
|
{
|
||||||
writef("FN: [%s] ", func);
|
try
|
||||||
Logf(fmt, args);
|
{
|
||||||
}
|
writef("FN: [%s] ", func);
|
||||||
catch (Exception e)
|
Logf(fmt, args);
|
||||||
{
|
}
|
||||||
assert(false, "Incompatible format type");
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
assert(false, "Incompatible format type");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,24 +124,10 @@ Errf(Args...)(string fmt, Args args)
|
|||||||
Logf!("ERROR", Args)(fmt, args);
|
Logf!("ERROR", Args)(fmt, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
static string
|
void
|
||||||
AssignStr(T, alias p)() if(StringType!(T))
|
Debugf(Args...)(string fmt, Args args)
|
||||||
{
|
{
|
||||||
import std.format : format;
|
debug Logf(fmt, args, "[DEBUG]: ");
|
||||||
|
|
||||||
enum string id = __traits(identifier, p);
|
|
||||||
string result = "";
|
|
||||||
static if(is(T == string))
|
|
||||||
{
|
|
||||||
result = id;
|
|
||||||
}
|
|
||||||
else static if(StringType!(T))
|
|
||||||
{
|
|
||||||
result = format("Str(%s)", id);
|
|
||||||
}
|
|
||||||
else static assert(false, "Unknown type for AssignItem");
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string
|
string
|
||||||
@ -146,13 +141,13 @@ Scratchf(Args...)(string fmt, Args args)
|
|||||||
void
|
void
|
||||||
Log(string str)
|
Log(string str)
|
||||||
{
|
{
|
||||||
writeln(str);
|
static if(NativeTarget) writeln(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Log(char* str)
|
Log(char* str)
|
||||||
{
|
{
|
||||||
writeln(str);
|
static if(NativeTarget) writeln(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
@nogc u64
|
@nogc u64
|
||||||
@ -203,7 +198,7 @@ GetFilePath(string file_name)
|
|||||||
{
|
{
|
||||||
string result = file_name;
|
string result = file_name;
|
||||||
|
|
||||||
for(u64 i = file_name.length-1; i64(i) >= 0; i -= 1)
|
for(usize i = file_name.length-1; i64(i) >= 0; i -= 1)
|
||||||
{
|
{
|
||||||
version(Windows)
|
version(Windows)
|
||||||
{
|
{
|
||||||
@ -272,7 +267,7 @@ ConcatInPlace(T)(T* list, T* to_concat)
|
|||||||
list.last = to_concat.last;
|
list.last = to_concat.last;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(to_concat, 0, T.sizeof);
|
MemSet(to_concat, 0, T.sizeof);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -477,7 +472,7 @@ struct KVPair(K, V)
|
|||||||
|
|
||||||
struct Result(V)
|
struct Result(V)
|
||||||
{
|
{
|
||||||
V value;
|
V value;
|
||||||
bool ok;
|
bool ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,10 +482,10 @@ struct HashTable(K, V)
|
|||||||
|
|
||||||
LinkedList!(P) free_lists;
|
LinkedList!(P) free_lists;
|
||||||
LinkedList!(P)[] lists;
|
LinkedList!(P)[] lists;
|
||||||
P* nil;
|
P* nil;
|
||||||
Arena arena;
|
Arena arena;
|
||||||
u64 node_count;
|
u64 node_count;
|
||||||
u64 list_count;
|
u64 list_count;
|
||||||
|
|
||||||
void opIndexAssign(V value, K key)
|
void opIndexAssign(V value, K key)
|
||||||
{
|
{
|
||||||
@ -640,7 +635,7 @@ Delete(K, V)(HashTable!(K, V)* ht, K key)
|
|||||||
result.ok = true;
|
result.ok = true;
|
||||||
result.value = node.value;
|
result.value = node.value;
|
||||||
|
|
||||||
memset(&node.value, 0, node.value.sizeof);
|
MemSet(&node.value, 0, node.value.sizeof);
|
||||||
|
|
||||||
SLLPush(&ht.free_lists, node, ht.nil);
|
SLLPush(&ht.free_lists, node, ht.nil);
|
||||||
|
|
||||||
@ -658,110 +653,28 @@ const u64 HASH_SEED = 5995;
|
|||||||
pragma(inline) u64
|
pragma(inline) u64
|
||||||
Hash(T)(T[] value)
|
Hash(T)(T[] value)
|
||||||
{
|
{
|
||||||
return xxh3_64bits_withSeed(value.ptr, (T.sizeof * value.length) / u8.sizeof, HASH_SEED);
|
return XXH3_64bits_withSeed(value.ptr, (T.sizeof * value.length) / u8.sizeof, HASH_SEED);
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma(inline) u64
|
pragma(inline) u64
|
||||||
Hash(T)(T* value)
|
Hash(T)(T* value)
|
||||||
{
|
{
|
||||||
return xxh3_64bits_withSeed(value, T.sizeof / u8.sizeof, HASH_SEED);
|
return XXH3_64bits_withSeed(value, T.sizeof / u8.sizeof, HASH_SEED);
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma(inline) u64
|
pragma(inline) u64
|
||||||
Hash(string str)
|
Hash(string str)
|
||||||
{
|
{
|
||||||
return xxh3_64bits_withSeed(str.ptr, str.length, HASH_SEED);
|
return XXH3_64bits_withSeed(str.ptr, str.length, HASH_SEED);
|
||||||
}
|
|
||||||
|
|
||||||
pragma(inline) u64
|
|
||||||
Hash(void* ptr_1, u64 len_1, void* ptr_2, u64 len_2)
|
|
||||||
{
|
|
||||||
XXH3_state_t xxh;
|
|
||||||
XXH3_INITSTATE(&xxh);
|
|
||||||
xxh3_64bits_reset_withSeed(&xxh, HASH_SEED);
|
|
||||||
xxh3_64bits_update(&xxh, ptr_1, len_1);
|
|
||||||
xxh3_64bits_update(&xxh, ptr_2, len_2);
|
|
||||||
|
|
||||||
return xxh3_64bits_digest(&xxh);
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma(inline) u64
|
|
||||||
Hash(T, U)(T value_1, U value_2) if(isArray!(T) && isArray!(U))
|
|
||||||
{
|
|
||||||
return Hash(value_1.ptr, value_1.length*T.sizeof, value_2.ptr, value_2.length*U.sizeof);
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma(inline) u64
|
|
||||||
Hash(T, U)(T value_1, U value_2) if(isArray!(T) && !isArray!(U))
|
|
||||||
{
|
|
||||||
return Hash(value_1.ptr, value_1.length*value_1[0].sizeof, &value_2, U.sizeof);
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma(inline) u64
|
|
||||||
Hash(T, U)(T value_1, U value_2) if(!isArray!(T) && !isArray!(U))
|
|
||||||
{
|
|
||||||
return Hash(&value_1, T.sizeof, &value_2, U.sizeof);
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma(inline) u64
|
|
||||||
RDTSC()
|
|
||||||
{
|
|
||||||
union u64_split
|
|
||||||
{
|
|
||||||
u64 full;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
u32 lower;
|
|
||||||
u32 upper;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
u64_split val;
|
|
||||||
u64_split* valp = &val;
|
|
||||||
asm
|
|
||||||
{
|
|
||||||
cpuid;
|
|
||||||
rdtsc;
|
|
||||||
mov R8, valp;
|
|
||||||
mov valp.upper.offsetof[R8], EDX;
|
|
||||||
mov valp.lower.offsetof[R8], EAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
return val.full;
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma(inline) u64
|
|
||||||
OSTimeFreq()
|
|
||||||
{
|
|
||||||
version (linux)
|
|
||||||
{
|
|
||||||
u64 freq = 1000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
return freq;
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma(inline) u64
|
|
||||||
OSTime()
|
|
||||||
{
|
|
||||||
version(linux)
|
|
||||||
{
|
|
||||||
import core.sys.linux.sys.time;
|
|
||||||
timeval value;
|
|
||||||
gettimeofday(&value, null);
|
|
||||||
|
|
||||||
u64 time = OSTimeFreq() * cast(u64)(value.tv_sec) + cast(u64)(value.tv_usec);
|
|
||||||
}
|
|
||||||
|
|
||||||
return time;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: probably needs improvement/testing
|
// TODO: probably needs improvement/testing
|
||||||
struct IntervalTimer
|
struct IntervalTimer
|
||||||
{
|
{
|
||||||
u64 cpu_freq;
|
Timer base;
|
||||||
u64 interval;
|
u64 interval;
|
||||||
u64 prev;
|
|
||||||
|
alias base this;
|
||||||
}
|
}
|
||||||
|
|
||||||
IntervalTimer
|
IntervalTimer
|
||||||
@ -773,35 +686,9 @@ CreateFPSTimer(u64 fps)
|
|||||||
IntervalTimer
|
IntervalTimer
|
||||||
CreateTimer(u64 ms)
|
CreateTimer(u64 ms)
|
||||||
{
|
{
|
||||||
IntervalTimer timer;
|
IntervalTimer timer = { base: CreateTimer() };
|
||||||
|
|
||||||
u64 ms_to_wait = 50;
|
timer.interval = timer.cpu_freq * (ms/1000);
|
||||||
|
|
||||||
u64 os_freq = OSTimeFreq();
|
|
||||||
u64 cpu_start = RDTSC();
|
|
||||||
u64 os_start = OSTime();
|
|
||||||
u64 os_end = 0;
|
|
||||||
u64 os_elapsed = 0;
|
|
||||||
|
|
||||||
u64 os_wait_time = os_freq * ms_to_wait / 1000;
|
|
||||||
|
|
||||||
while (os_elapsed < os_wait_time)
|
|
||||||
{
|
|
||||||
os_end = OSTime();
|
|
||||||
os_elapsed = os_end - os_start;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 cpu_end = RDTSC();
|
|
||||||
u64 cpu_elapsed = cpu_end - cpu_start;
|
|
||||||
u64 cpu_freq = 0;
|
|
||||||
if(os_elapsed)
|
|
||||||
{
|
|
||||||
cpu_freq = os_freq * cpu_elapsed / os_elapsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
timer.cpu_freq = cpu_freq;
|
|
||||||
timer.interval = cpu_freq*(ms/1000);
|
|
||||||
timer.prev = RDTSC();
|
|
||||||
|
|
||||||
return timer;
|
return timer;
|
||||||
}
|
}
|
||||||
@ -809,18 +696,33 @@ CreateTimer(u64 ms)
|
|||||||
void
|
void
|
||||||
ResetTimer(IntervalTimer* t)
|
ResetTimer(IntervalTimer* t)
|
||||||
{
|
{
|
||||||
t.prev = RDTSC();
|
static if(NativeTarget)
|
||||||
|
{
|
||||||
|
t.prev = RDTSC();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(false, NO_IMPL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma(inline) bool
|
pragma(inline) bool
|
||||||
CheckTimer(IntervalTimer* t)
|
CheckTimer(IntervalTimer* t)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
u64 time = RDTSC();
|
|
||||||
if(time - t.prev > t.interval)
|
static if(NativeTarget)
|
||||||
{
|
{
|
||||||
result = true;
|
u64 time = RDTSC();
|
||||||
t.prev = time;
|
if(time - t.prev > t.interval)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
t.prev = time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(false, NO_IMPL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -835,34 +737,43 @@ struct Timer
|
|||||||
Timer
|
Timer
|
||||||
CreateTimer()
|
CreateTimer()
|
||||||
{
|
{
|
||||||
u64 ms_to_wait = 50;
|
static if(NativeTarget)
|
||||||
|
|
||||||
u64 os_freq = OSTimeFreq();
|
|
||||||
u64 cpu_start = RDTSC();
|
|
||||||
u64 os_start = OSTime();
|
|
||||||
u64 os_end = 0;
|
|
||||||
u64 os_elapsed = 0;
|
|
||||||
|
|
||||||
u64 os_wait_time = os_freq * ms_to_wait / 1000;
|
|
||||||
|
|
||||||
while (os_elapsed < os_wait_time)
|
|
||||||
{
|
{
|
||||||
os_end = OSTime();
|
u64 ms_to_wait = 50;
|
||||||
os_elapsed = os_end - os_start;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 cpu_end = RDTSC();
|
u64 os_freq = OSTimeFreq();
|
||||||
u64 cpu_elapsed = cpu_end - cpu_start;
|
u64 cpu_start = RDTSC();
|
||||||
u64 cpu_freq = 0;
|
u64 os_start = OSTime();
|
||||||
if(os_elapsed)
|
u64 os_end = 0;
|
||||||
|
u64 os_elapsed = 0;
|
||||||
|
|
||||||
|
u64 os_wait_time = os_freq * ms_to_wait / 1000;
|
||||||
|
|
||||||
|
while (os_elapsed < os_wait_time)
|
||||||
|
{
|
||||||
|
os_end = OSTime();
|
||||||
|
os_elapsed = os_end - os_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 cpu_end = RDTSC();
|
||||||
|
u64 cpu_elapsed = cpu_end - cpu_start;
|
||||||
|
u64 cpu_freq = 0;
|
||||||
|
if(os_elapsed)
|
||||||
|
{
|
||||||
|
cpu_freq = os_freq * cpu_elapsed / os_elapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer timer = {
|
||||||
|
cpu_freq: cpu_freq,
|
||||||
|
prev: RDTSC(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
cpu_freq = os_freq * cpu_elapsed / os_elapsed;
|
Timer timer;
|
||||||
}
|
|
||||||
|
|
||||||
Timer timer = {
|
assert(false, NO_IMPL);
|
||||||
cpu_freq: cpu_freq,
|
}
|
||||||
prev: RDTSC(),
|
|
||||||
};
|
|
||||||
|
|
||||||
return timer;
|
return timer;
|
||||||
}
|
}
|
||||||
@ -870,92 +781,132 @@ CreateTimer()
|
|||||||
pragma(inline) f32
|
pragma(inline) f32
|
||||||
DeltaTime(Timer* t)
|
DeltaTime(Timer* t)
|
||||||
{
|
{
|
||||||
u64 time = RDTSC();
|
u64 time, step;
|
||||||
u64 step = time - t.prev;
|
|
||||||
t.prev = time;
|
static if(NativeTarget)
|
||||||
|
{
|
||||||
|
time = RDTSC();
|
||||||
|
step = time - t.prev;
|
||||||
|
t.prev = time;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(false, NO_IMPL);
|
||||||
|
}
|
||||||
|
|
||||||
return cast(f32)(step) / cast(f32)(t.cpu_freq);
|
return cast(f32)(step) / cast(f32)(t.cpu_freq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static string
|
static string
|
||||||
IntToStr(int n) nothrow pure @safe
|
Replace(string target, u8 find, string replace)
|
||||||
{
|
{
|
||||||
string result;
|
assert(__ctfe, "Function can only be run at compile time");
|
||||||
|
|
||||||
static immutable string[] table = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
|
u8[1024] result = '\0';
|
||||||
if(n < table.length)
|
|
||||||
|
usize count;
|
||||||
|
foreach(ch; target)
|
||||||
{
|
{
|
||||||
result = table[n];
|
if(ch == find)
|
||||||
}
|
{
|
||||||
else
|
for(usize i = 0; i < replace.length; i += 1)
|
||||||
{
|
{
|
||||||
result = to!string(n);
|
result[count++] = replace[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result[count++] = ch;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return Str(result[0 .. count]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static string
|
static string
|
||||||
GenerateLoop(string format_string, int N)() nothrow pure @safe
|
Str(T)(T v) if(isIntegral!(T))
|
||||||
{
|
{
|
||||||
string result;
|
assert(__ctfe);
|
||||||
for (int i = 0; i < N; i++)
|
|
||||||
|
if(v == 0)
|
||||||
{
|
{
|
||||||
result ~= format_string.replace("@", IntToStr(i));
|
return "0";
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
|
u8[] slice = new u8[32];
|
||||||
|
|
||||||
|
enum base = 10;
|
||||||
|
i32 i = 30;
|
||||||
|
|
||||||
|
for(; v && i; i--, v /= base)
|
||||||
|
{
|
||||||
|
slice[i] = r"0123456789"[v%base];
|
||||||
|
}
|
||||||
|
|
||||||
|
return Str(slice[i+1 .. $]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MemCpy(void* dst_p, void* src_p, u64 length)
|
MemSet(void* dst_p, i32 ch, u64 count) @nogc nothrow
|
||||||
|
{
|
||||||
|
u8[] slice = (cast(u8*)dst_p)[0 .. cast(usize)count];
|
||||||
|
slice[] = cast(u8)(ch&0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MemCpy(void* dst_p, void* src_p, usize length)
|
||||||
{
|
{
|
||||||
u8* dst = cast(u8*)dst_p;
|
u8* dst = cast(u8*)dst_p;
|
||||||
u8* src = cast(u8*)src_p;
|
u8* src = cast(u8*)src_p;
|
||||||
|
|
||||||
u64 remaining = length;
|
usize remaining = length;
|
||||||
if(remaining >= 64)
|
version(X86_64)
|
||||||
{
|
{
|
||||||
for(u64 i = 0; i + 64 < length; i += 64)
|
if(remaining >= 64)
|
||||||
{
|
{
|
||||||
asm
|
for(u64 i = 0; i + 64 < length; i += 64)
|
||||||
{
|
{
|
||||||
mov R8, src;
|
asm
|
||||||
mov R9, dst;
|
{
|
||||||
|
mov R8, src;
|
||||||
|
mov R9, dst;
|
||||||
|
|
||||||
add R8, i;
|
add R8, i;
|
||||||
movdqu XMM0, [R8+00];
|
movdqu XMM0, [R8+00];
|
||||||
movdqu XMM1, [R8+16];
|
movdqu XMM1, [R8+16];
|
||||||
movdqu XMM2, [R8+32];
|
movdqu XMM2, [R8+32];
|
||||||
movdqu XMM3, [R8+48];
|
movdqu XMM3, [R8+48];
|
||||||
|
|
||||||
add R9, i;
|
|
||||||
movups [R9+00], XMM0;
|
|
||||||
movups [R9+16], XMM1;
|
|
||||||
movups [R9+32], XMM2;
|
|
||||||
movups [R9+48], XMM3;
|
|
||||||
|
|
||||||
sub remaining, 64;
|
add R9, i;
|
||||||
|
movups [R9+00], XMM0;
|
||||||
|
movups [R9+16], XMM1;
|
||||||
|
movups [R9+32], XMM2;
|
||||||
|
movups [R9+48], XMM3;
|
||||||
|
|
||||||
|
sub remaining, 64;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if(remaining >= 32)
|
if(remaining >= 32)
|
||||||
{
|
|
||||||
for(u64 i = length - remaining; i + 32 < length; i += 32)
|
|
||||||
{
|
{
|
||||||
asm
|
for(u64 i = length - remaining; i + 32 < length; i += 32)
|
||||||
{
|
{
|
||||||
mov R8, src;
|
asm
|
||||||
mov R9, dst;
|
{
|
||||||
|
mov R8, src;
|
||||||
|
mov R9, dst;
|
||||||
|
|
||||||
add R8, i;
|
add R8, i;
|
||||||
movdqu XMM0, [R8+00];
|
movdqu XMM0, [R8+00];
|
||||||
movdqu XMM1, [R8+16];
|
movdqu XMM1, [R8+16];
|
||||||
|
|
||||||
add R9, i;
|
add R9, i;
|
||||||
movdqu [R9+00], XMM0;
|
movdqu [R9+00], XMM0;
|
||||||
movdqu [R9+16], XMM1;
|
movdqu [R9+16], XMM1;
|
||||||
|
|
||||||
sub remaining, 32;
|
sub remaining, 32;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -966,11 +917,15 @@ MemCpy(void* dst_p, void* src_p, u64 length)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u8[]
|
void
|
||||||
Embed(string file_name)
|
Assign(T, Args...)(T slice, Args args) if(isArray!(T))
|
||||||
{
|
{
|
||||||
import std.file;
|
assert(slice.length == Args.length);
|
||||||
return cast(u8[])read(file_name);
|
|
||||||
|
static foreach(i; 0 .. Args.length)
|
||||||
|
{
|
||||||
|
slice[i] = cast(typeof(slice[0]))args[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
version(DLIB_TEST) unittest
|
version(DLIB_TEST) unittest
|
||||||
@ -1089,7 +1044,8 @@ version(DLIB_TEST) unittest
|
|||||||
|
|
||||||
assert(list.first != null && list.last != null);
|
assert(list.first != null && list.last != null);
|
||||||
|
|
||||||
TestDLList(&list, [0, 1, 2, 3, 4]);
|
u32[5] test1 = [0, 1, 2, 3, 4];
|
||||||
|
TestDLList(&list, test1);
|
||||||
|
|
||||||
u32 count = 0;
|
u32 count = 0;
|
||||||
u32[3] res1 = [0, 2, 4];
|
u32[3] res1 = [0, 2, 4];
|
||||||
@ -1116,7 +1072,6 @@ version(DLIB_TEST) unittest
|
|||||||
}
|
}
|
||||||
|
|
||||||
{ // MemCpy
|
{ // MemCpy
|
||||||
import std.conv;
|
|
||||||
|
|
||||||
u8[777] bytes;
|
u8[777] bytes;
|
||||||
u8[777] test_bytes;
|
u8[777] test_bytes;
|
||||||
@ -1145,7 +1100,6 @@ version(DLIB_TEST) unittest
|
|||||||
{
|
{
|
||||||
if(v != bytes[count])
|
if(v != bytes[count])
|
||||||
{
|
{
|
||||||
Logf("Failed %d %d %d", i, v, bytes[count]);
|
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1193,9 +1147,9 @@ version(DLIB_TEST) unittest
|
|||||||
u64 val_1 = 555555;
|
u64 val_1 = 555555;
|
||||||
u32 val_2 = 33333;
|
u32 val_2 = 33333;
|
||||||
|
|
||||||
u64 v1 = Hash(arr_1, arr_2);
|
u64 v1 = Hash(arr_1);
|
||||||
u64 v2 = Hash(arr_1, val_1);
|
u64 v2 = Hash(arr_2);
|
||||||
u64 v3 = Hash(val_1, val_2);
|
u64 v3 = Hash(&val_1);
|
||||||
|
|
||||||
assert(v1 > 0);
|
assert(v1 > 0);
|
||||||
assert(v2 > 0);
|
assert(v2 > 0);
|
||||||
@ -1204,7 +1158,7 @@ version(DLIB_TEST) unittest
|
|||||||
|
|
||||||
{ // Casts
|
{ // Casts
|
||||||
u8[] arr = CastStr!(u8)("Test");
|
u8[] arr = CastStr!(u8)("Test");
|
||||||
char[] char_arr = ['a', 'b'];
|
char[2] char_arr = ['a', 'b'];
|
||||||
arr = CastArr!(u8)(char_arr);
|
arr = CastArr!(u8)(char_arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1213,4 +1167,33 @@ version(DLIB_TEST) unittest
|
|||||||
string str = Scratchf("%s testing %s", 55, "testing");
|
string str = Scratchf("%s testing %s", 55, "testing");
|
||||||
assert(str == "55 testing testing");
|
assert(str == "55 testing testing");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
u64[555] slice = 53321;
|
||||||
|
|
||||||
|
MemSet(slice.ptr, 0, u64.sizeof*slice.length);
|
||||||
|
|
||||||
|
for(u64 i = 0; i < slice.length; i += 1)
|
||||||
|
{
|
||||||
|
assert(slice[i] == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
MemSet(slice.ptr, 5, u64.sizeof*slice.length);
|
||||||
|
|
||||||
|
u64 cmp = cast(u64)(
|
||||||
|
cast(u64)(5) << 56 |
|
||||||
|
cast(u64)(5) << 48 |
|
||||||
|
cast(u64)(5) << 40 |
|
||||||
|
cast(u64)(5) << 32 |
|
||||||
|
cast(u64)(5) << 24 |
|
||||||
|
cast(u64)(5) << 16 |
|
||||||
|
cast(u64)(5) << 8 |
|
||||||
|
cast(u64)(5) << 0
|
||||||
|
);
|
||||||
|
|
||||||
|
for(u64 i = 0; i < slice.length; i += 1)
|
||||||
|
{
|
||||||
|
assert(slice[i] == cmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
0
wasm/wasm.js
Normal file
0
wasm/wasm.js
Normal file
Loading…
x
Reference in New Issue
Block a user