Skip to content

Commit 9b6bebc

Browse files
committed
Added EnumInfo for efficient runtime enum lookup.
1 parent 294a273 commit 9b6bebc

File tree

2 files changed

+278
-21
lines changed

2 files changed

+278
-21
lines changed

src/urt/algorithm.d

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module urt.algorithm;
22

3-
import urt.traits : lvalue_of;
3+
import urt.meta : AliasSeq;
4+
import urt.traits : is_some_function, lvalue_of, Parameters, ReturnType, Unqual;
45
import urt.util : swap;
56

67
version = SmallSize;
@@ -56,8 +57,36 @@ auto compare(T, U)(auto ref T a, auto ref U b)
5657
return a < b ? -1 : (a > b ? 1 : 0);
5758
}
5859

60+
size_t binary_search(Pred)(const void[] arr, size_t stride, const void* value, auto ref Pred pred)
61+
if (is_some_function!Pred && is(ReturnType!Pred == int) && is(Parameters!Pred == AliasSeq!(const void*, const void*)))
62+
{
63+
const void* p = arr.ptr;
64+
size_t low = 0;
65+
size_t high = arr.length;
66+
while (low < high)
67+
{
68+
size_t mid = low + (high - low) / 2;
69+
70+
// should we chase the first in a sequence of same values?
71+
int cmp = pred(p + mid*stride, value);
72+
if (cmp < 0)
73+
low = mid + 1;
74+
else
75+
high = mid;
76+
}
77+
if (low == arr.length)
78+
return arr.length;
79+
if (pred(p + low*stride, value) == 0)
80+
return low;
81+
return arr.length;
82+
}
83+
5984
size_t binary_search(alias pred = void, T, Cmp...)(T[] arr, auto ref Cmp cmp_args)
85+
if (!is(Unqual!T == void))
6086
{
87+
static if (is(pred == void))
88+
static assert (cmp_args.length == 1, "binary_search without a predicate requires exactly one comparison argument");
89+
6190
T* p = arr.ptr;
6291
size_t low = 0;
6392
size_t high = arr.length;
@@ -82,6 +111,8 @@ size_t binary_search(alias pred = void, T, Cmp...)(T[] arr, auto ref Cmp cmp_arg
82111
high = mid;
83112
}
84113
}
114+
if (low == arr.length)
115+
return arr.length;
85116
static if (is(pred == void))
86117
{
87118
if (p[low] == cmp_args[0])
@@ -96,22 +127,27 @@ size_t binary_search(alias pred = void, T, Cmp...)(T[] arr, auto ref Cmp cmp_arg
96127
}
97128

98129

99-
void qsort(alias pred = void, T)(T[] arr)
130+
void qsort(alias pred = void, T)(T[] arr) pure
100131
{
101132
version (SmallSize)
133+
enum use_small_size_impl = true;
134+
else
135+
enum use_small_size_impl = false;
136+
137+
if (!__ctfe && use_small_size_impl)
102138
{
103139
static if (is(pred == void))
104140
static if (__traits(compiles, lvalue_of!T.opCmp(lvalue_of!T)))
105-
static int compare(const void* a, const void* b) nothrow @nogc
141+
static int compare(const void* a, const void* b) pure nothrow @nogc
106142
=> (*cast(const T*)a).opCmp(*cast(const T*)b);
107143
else
108-
static int compare(const void* a, const void* b) nothrow @nogc
144+
static int compare(const void* a, const void* b) pure nothrow @nogc
109145
=> *cast(const T*)a < *cast(const T*)b ? -1 : *cast(const T*)a > *cast(const T*)b ? 1 : 0;
110146
else
111-
static int compare(const void* a, const void* b) nothrow @nogc
147+
static int compare(const void* a, const void* b) pure nothrow @nogc
112148
=> pred(*cast(T*)a, *cast(T*)b);
113149

114-
qsort(arr[], T.sizeof, &compare, (void* a, void* b) nothrow @nogc {
150+
qsort(arr[], T.sizeof, &compare, (void* a, void* b) pure nothrow @nogc {
115151
swap(*cast(T*)a, *cast(T*)b);
116152
});
117153
}
@@ -121,7 +157,7 @@ void qsort(alias pred = void, T)(T[] arr)
121157
if (arr.length > 1)
122158
{
123159
size_t pivotIndex = arr.length / 2;
124-
T* pivot = &p[pivotIndex];
160+
T* pivot = p + pivotIndex;
125161

126162
size_t i = 0;
127163
size_t j = arr.length - 1;
@@ -135,8 +171,8 @@ void qsort(alias pred = void, T)(T[] arr)
135171
}
136172
else
137173
{
138-
while (pred(*cast(T*)&p[i], *cast(T*)pivot) < 0) i++;
139-
while (pred(*cast(T*)&p[j], *cast(T*)pivot) > 0) j--;
174+
while (pred(p[i], *pivot) < 0) i++;
175+
while (pred(p[j], *pivot) > 0) j--;
140176
}
141177
if (i <= j)
142178
{
@@ -147,9 +183,9 @@ void qsort(alias pred = void, T)(T[] arr)
147183
}
148184

149185
if (j > 0)
150-
qsort(p[0 .. j + 1]);
186+
qsort!pred(p[0 .. j + 1]);
151187
if (i < arr.length)
152-
qsort(p[i .. arr.length]);
188+
qsort!pred(p[i .. arr.length]);
153189
}
154190
}
155191
}
@@ -159,15 +195,15 @@ unittest
159195
struct S
160196
{
161197
int x;
162-
int opCmp(ref const S rh) const nothrow @nogc
198+
int opCmp(ref const S rh) pure const nothrow @nogc
163199
=> x < rh.x ? -1 : x > rh.x ? 1 : 0;
164200
}
165201

166202
int[5] arr = [3, 100, -1, 17, 30];
167203
qsort(arr);
168204
assert(arr == [-1, 3, 17, 30, 100]);
169205

170-
S[5] arr2 = [ S(3), S(100), S(-1), S(17), S(30)];
206+
S[5] arr2 = [ S(3), S(100), S(-1), S(17), S(30) ];
171207
qsort(arr2);
172208
foreach (i, ref s; arr2)
173209
assert(s.x == arr[i]);
@@ -189,7 +225,7 @@ version (SmallSize)
189225
// just one generic implementation to minimise the code...
190226
// kinda slow though... look at all those multiplies!
191227
// maybe there's some way to make this faster :/
192-
void qsort(void[] arr, size_t element_size, int function(const void* a, const void* b) nothrow @nogc compare, void function(void* a, void* b) nothrow @nogc swap)
228+
void qsort(void[] arr, size_t element_size, int function(const void* a, const void* b) pure nothrow @nogc compare, void function(void* a, void* b) pure nothrow @nogc swap) pure
193229
{
194230
void* p = arr.ptr;
195231
size_t length = arr.length / element_size;

0 commit comments

Comments
 (0)