Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions src/urt/algorithm.d
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,12 @@ auto compare(T, U)(auto ref T a, auto ref U b)
size_t binary_search(Pred)(const void[] arr, size_t stride, const void* value, auto ref Pred pred)
if (is_some_function!Pred && is(ReturnType!Pred == int) && is(Parameters!Pred == AliasSeq!(const void*, const void*)))
{
debug assert(arr.length % stride == 0, "array length must be a multiple of stride");
const count = arr.length / stride;

const void* p = arr.ptr;
size_t low = 0;
size_t high = arr.length;
size_t high = count;
while (low < high)
{
size_t mid = low + (high - low) / 2;
Expand All @@ -74,11 +77,11 @@ size_t binary_search(Pred)(const void[] arr, size_t stride, const void* value, a
else
high = mid;
}
if (low == arr.length)
return arr.length;
if (low == count)
return count;
if (pred(p + low*stride, value) == 0)
return low;
return arr.length;
return count;
}

size_t binary_search(alias pred = void, T, Cmp...)(T[] arr, auto ref Cmp cmp_args)
Expand Down
105 changes: 60 additions & 45 deletions src/urt/meta/package.d
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,6 @@ template INTERLEAVE_SEPARATOR(alias sep, Args...)
}


template enum_keys(E)
{
static assert(is_enum!E, "enum_keys only works with enums!");
__gshared immutable string[enum_strings.length] enum_keys = [ enum_strings ];
private alias enum_strings = __traits(allMembers, E);
}

const(E)* enum_from_key(E)(const(char)[] key)
if (is_enum!E)
=> MakeEnumInfo!E.value_for(key);
Expand All @@ -145,52 +138,65 @@ const(char)[] enum_key_from_value(E)(EnumType!E value)
if (is_enum!E)
=> MakeEnumInfo!E.key_for(value);

const(char)[] enum_key_by_decl_index(E)(size_t value)
if (is_enum!E)
=> MakeEnumInfo!E.key_by_decl_index(value);

struct VoidEnumInfo
{
import urt.algorithm : binary_search;
import urt.string;
nothrow @nogc:

// keys and values are sorted for binary search
const String[] keys;
const void[] values;
uint stride;
const String* keys;
const void* values;
ubyte count;
ushort stride;
uint type_hash;

const(char)[] key_for(const void* value, int function(const void* a, const void* b) pure nothrow @nogc pred) const pure
{
size_t i = binary_search(values, stride, value, pred);
if (i < values.length)
size_t i = binary_search(values[0 .. count*stride], stride, value, pred);
if (i < count)
return keys[_v2k_lookup[i]][];
return null;
}

const(char)[] key_for(const void* value, int delegate(const void* a, const void* b) pure nothrow @nogc pred) const pure
{
size_t i = binary_search(values, stride, value, pred);
if (i < values.length)
size_t i = binary_search(values[0 .. count*stride], stride, value, pred);
if (i < count)
return keys[_v2k_lookup[i]][];
return null;
}

const(char)[] key_by_decl_index(size_t i) const pure
{
assert(i < count, "Declaration index out of range");
return keys[_decl_lookup[i]][];
}

const(void)* value_for(const(char)[] key) const pure
{
size_t i = binary_search(keys, key);
if (i == keys.length)
size_t i = binary_search(keys[0 .. count], key);
if (i == count)
return null;
i = _k2v_lookup[i];
return &values[i*stride];
return values + i*stride;
}

bool contains(const(char)[] key) const pure
{
size_t i = binary_search(keys, key);
return i < keys.length;
size_t i = binary_search(keys[0 .. count], key);
return i < count;
}

private:
// these tables map between indices of keys and values
const ubyte[] _k2v_lookup;
const ubyte[] _v2k_lookup;
const ubyte* _k2v_lookup;
const ubyte* _v2k_lookup;
const ubyte* _decl_lookup;
}

template EnumInfo(E)
Expand All @@ -205,6 +211,7 @@ template EnumInfo(E)
{
import urt.algorithm : binary_search;
import urt.string;
nothrow @nogc:

static assert (EnumInfo.sizeof == EnumInfo.sizeof, "Template EnumInfo must not add any members!");

Expand All @@ -214,50 +221,54 @@ template EnumInfo(E)
static assert(false, E.string ~ " is not an enum type!");

// keys and values are sorted for binary search
const String[] keys;
const UE[] values;
uint stride = E.sizeof;
const String* keys;
const UE* values;
const ubyte count = __traits(allMembers, E).length;
const ushort stride = E.sizeof;
uint type_hash;

ref inout(VoidEnumInfo) make_void() inout
=> *cast(inout VoidEnumInfo*)&this;

const(char)[] key_for(V value) const pure
{
size_t i = binary_search(values, value);
if (i < values.length)
size_t i = binary_search(values[0 .. count], value);
if (i < count)
return keys[_v2k_lookup[i]][];
return null;
}

const(char)[] key_by_decl_index(size_t i) const pure
=> make_void().key_by_decl_index(i);

const(UE)* value_for(const(char)[] key) const pure
{
size_t i = binary_search(keys, key);
if (i == keys.length)
size_t i = binary_search(keys[0 .. count], key);
if (i == count)
return null;
return &values[_k2v_lookup[i]];
return values + _k2v_lookup[i];
}

bool contains(const(char)[] key) const pure
{
size_t i = binary_search(keys, key);
return i < keys.length;
}
=> make_void().contains(key);

private:
// these tables map between indices of keys and values
const ubyte[] _k2v_lookup;
const ubyte[] _v2k_lookup;
const ubyte* _k2v_lookup;
const ubyte* _v2k_lookup;
const ubyte* _decl_lookup;
}

// sanity check the typed one matches the untyped one
static assert(EnumInfo.sizeof == VoidEnumInfo.sizeof);
static assert(EnumInfo.keys.offsetof == VoidEnumInfo.keys.offsetof);
static assert(EnumInfo.values.offsetof == VoidEnumInfo.values.offsetof);
static assert(EnumInfo.count.offsetof == VoidEnumInfo.count.offsetof);
static assert(EnumInfo.stride.offsetof == VoidEnumInfo.stride.offsetof);
static assert(EnumInfo.type_hash.offsetof == VoidEnumInfo.type_hash.offsetof);
static assert(EnumInfo._k2v_lookup.offsetof == VoidEnumInfo._k2v_lookup.offsetof);
static assert(EnumInfo._v2k_lookup.offsetof == VoidEnumInfo._v2k_lookup.offsetof);
static assert(EnumInfo._decl_lookup.offsetof == VoidEnumInfo._decl_lookup.offsetof);
}
}

Expand All @@ -267,30 +278,33 @@ template MakeEnumInfo(E)
{
alias UE = Unqual!E;

__gshared immutable MakeEnumInfo = EnumInfo!UE(
_keys[],
_values[],
enum ubyte NumItems = __traits(allMembers, E).length;
static assert(NumItems <= ubyte.max, "Too many enum items!");

__gshared immutable MakeEnumInfo = immutable(EnumInfo!UE)(
_keys.ptr,
_values.ptr,
NumItems,
E.sizeof,
0,
_k2v_lookup[],
_v2k_lookup[],
_lookup.ptr,
_lookup.ptr + NumItems,
_lookup.ptr + NumItems*2
);

private:
import urt.algorithm : binary_search, compare, qsort;
import urt.string;
import urt.string.uni : uni_compare;

enum NumItems = __traits(allMembers, E).length;
static assert(NumItems <= ubyte.max, "Too many enum items!");

// keys and values are sorted for binary search
__gshared immutable String[NumItems] _keys = [ STATIC_MAP!(GetKey, iota) ];
__gshared immutable UE[NumItems] _values = [ STATIC_MAP!(GetValue, iota) ];

// these tables map between indices of keys and values
__gshared immutable ubyte[NumItems] _k2v_lookup = [ STATIC_MAP!(GetKeyRedirect, iota) ];
__gshared immutable ubyte[NumItems] _v2k_lookup = [ STATIC_MAP!(GetValRedirect, iota) ];
__gshared immutable ubyte[NumItems * 3] _lookup = [ STATIC_MAP!(GetKeyRedirect, iota),
STATIC_MAP!(GetValRedirect, iota),
STATIC_MAP!(GetKeyOrig, iota) ];

// a whole bunch of nonsense to build the tables...
struct KI
Expand All @@ -317,6 +331,7 @@ private:
enum GetValue(size_t i) = by_value[i].v;
enum GetKeyRedirect(size_t i) = inv_val[by_key[i].i];
enum GetValRedirect(size_t i) = inv_key[by_value[i].i];
enum GetKeyOrig(size_t i) = inv_key[i];
}


Expand Down