Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
143 commits
Select commit Hold shift + click to select a range
64bb371
Add main function
TurkeyMan Aug 17, 2025
084fa96
Migrate to lower_snake case...
TurkeyMan Aug 17, 2025
e2f7577
Merge pull request #6 from open-watt/lower_snake
megaeels Aug 19, 2025
e683e62
More snake_case migration...
TurkeyMan Aug 21, 2025
c1db95f
Merge pull request #8 from open-watt/more_snake_case
megaeels Aug 24, 2025
8374c4f
Improve SI unit/quantity
TurkeyMan Aug 17, 2025
b60cd60
Merge pull request #3 from open-watt/si_quantity_improve
megaeels Aug 24, 2025
f0fc160
Improve variant support for Quantity
TurkeyMan Aug 19, 2025
ea77b2f
Merge pull request #7 from open-watt/improve_variant
megaeels Aug 24, 2025
225132d
Added ChaCha stream cypher
TurkeyMan Aug 17, 2025
fa63396
Remove a couple of dangling phobos references.
TurkeyMan Aug 26, 2025
f0910e2
Merge pull request #9 from open-watt/dangling_phobos_references
samsinsane Aug 26, 2025
26f6475
Merge pull request #5 from open-watt/chacha
samsinsane Aug 26, 2025
da335b5
Tweak the Promise API
TurkeyMan Sep 2, 2025
c50deb8
Add StringResult
TurkeyMan Sep 3, 2025
cccff26
Minor improvements to urt.time
TurkeyMan Sep 3, 2025
3eb2492
Merge pull request #10 from open-watt/tweak_promise
megaeels Sep 3, 2025
ab86fba
Merge pull request #12 from open-watt/tweak_time
megaeels Sep 3, 2025
e1b0fec
Merge pull request #11 from open-watt/string_result
megaeels Sep 3, 2025
aa707f5
Improved the compare function a bit
TurkeyMan Sep 4, 2025
f2311af
Made CacheString pure, since the cache is immutable.
TurkeyMan Sep 4, 2025
72fc423
Improved user variants.
TurkeyMan Sep 4, 2025
3de6039
Merge pull request #15 from open-watt/variant_improve
megaeels Sep 4, 2025
5a33859
Merge pull request #14 from open-watt/pure_string_heap
megaeels Sep 4, 2025
e6234bd
Merge pull request #13 from open-watt/improve_compare
megaeels Sep 4, 2025
d1b1cfe
The body of Array.concat was just completely missing!
TurkeyMan Sep 5, 2025
b1b9875
Merge pull request #16 from open-watt/improve_array
samsinsane Sep 5, 2025
d2da65b
Fix map range
TurkeyMan Sep 10, 2025
f995f3f
Merge pull request #17 from open-watt/map_const_iterate
samsinsane Sep 10, 2025
760585b
Override accept inheriting blocking from listening socket.
TurkeyMan Sep 12, 2025
f8ae2a0
Merge pull request #18 from open-watt/nonblocking_accept
samsinsane Sep 13, 2025
cc271b9
Fixes to tstringz functions, which seemed to have 2 separate implemen…
TurkeyMan Sep 16, 2025
f142ae7
Merge pull request #20 from open-watt/fix_tstringz
megaeels Sep 16, 2025
d225b3a
Properly detect integer variants fed via float (like numbers from com…
TurkeyMan Sep 15, 2025
428d7ed
Merge pull request #19 from open-watt/detect_int_variant
samsinsane Sep 16, 2025
c54e6da
Array was missing slice-assign operators.
TurkeyMan Sep 22, 2025
89940c6
Merge pull request #21 from open-watt/array_slice_assign
samsinsane Sep 25, 2025
a769067
Added comparison functions for InetAddress
TurkeyMan Sep 24, 2025
c24344d
Merge pull request #22 from open-watt/inet_cmp
samsinsane Sep 26, 2025
42c8de0
Flesh out unicode implementation, including functions to perform case…
TurkeyMan Oct 7, 2025
78124e8
Several socket/inet improvements.
TurkeyMan Oct 14, 2025
c51ea98
Merge pull request #23 from open-watt/uni_compare_case_insensitive
samsinsane Oct 18, 2025
fff21bd
Merge pull request #24 from open-watt/socket_improvement
samsinsane Oct 18, 2025
bf85e90
Renamed IPSubnet to IPNetworkAddress (because it stores a full address!)
TurkeyMan Oct 19, 2025
f3e5ec3
Merge pull request #25 from open-watt/network_address
samsinsane Oct 19, 2025
e345a97
Fix a really dumb bug.
TurkeyMan Oct 30, 2025
34a1d38
Merge pull request #26 from open-watt/set_system_idle_params
samsinsane Oct 30, 2025
970bcaa
Added ascii strcmp/icmp
TurkeyMan Nov 3, 2025
25ee833
Merge pull request #27 from open-watt/ascii_icmp
samsinsane Nov 3, 2025
5c0fb18
Added toString/fromString for common time types.
TurkeyMan Nov 3, 2025
d552735
Added support for `Duration` to `Variant`, which is a synonym for `Qu…
TurkeyMan Nov 3, 2025
9c94b23
Merge pull request #28 from open-watt/time_improvements
samsinsane Nov 3, 2025
7b57ce8
Fixed format for Quantity and related types.
TurkeyMan Nov 5, 2025
42f5ac1
Add a way to register simple log sinks.
TurkeyMan Nov 5, 2025
0cf0f6b
Fix the DateTime stringify function.
TurkeyMan Nov 5, 2025
1ba0f73
Merge pull request #30 from open-watt/format_quantity
samsinsane Nov 6, 2025
bcaaa13
Merge pull request #31 from open-watt/log_sink
samsinsane Nov 6, 2025
c1fd9b9
Merge pull request #32 from open-watt/fix_datetime_tostring
samsinsane Nov 6, 2025
294a273
Improve StringLit interaction with immutable.
TurkeyMan Nov 10, 2025
9b6bebc
Added EnumInfo for efficient runtime enum lookup.
TurkeyMan Nov 10, 2025
c03c465
Merge pull request #33 from open-watt/improve_stringlit
samsinsane Nov 10, 2025
43e7272
Merge pull request #34 from open-watt/enum_info
samsinsane Nov 10, 2025
848e77e
Remove enum_keys helper in favour of the new enum tools.
TurkeyMan Nov 10, 2025
3164ae6
Merge pull request #35 from open-watt/remove_enum_keys
samsinsane Nov 11, 2025
fe37a7e
Fix several logging bugs (actually mostly string formatting bugs!)
TurkeyMan Nov 16, 2025
d495ce1
Merge pull request #36 from open-watt/logging_bugs
samsinsane Nov 17, 2025
d329520
Add support for Variant to store binary data.
TurkeyMan Nov 30, 2025
60ddd5e
Add 2 little helpers:
TurkeyMan Nov 30, 2025
73ea15e
Merge pull request #37 from open-watt/variant_buffer
samsinsane Dec 1, 2025
5bc723c
Merge pull request #38 from open-watt/helpers
samsinsane Dec 1, 2025
7082478
More druntime scrubbing...
TurkeyMan Dec 1, 2025
e55eafd
Json string writer must escape strings
TurkeyMan Dec 2, 2025
4a60880
Variant fixes
TurkeyMan Dec 4, 2025
0db535a
Merge pull request #41 from open-watt/variant_improvement
samsinsane Dec 6, 2025
f4ec849
Merge pull request #40 from open-watt/json_string_escape
samsinsane Dec 6, 2025
99d6f33
Merge pull request #39 from open-watt/druntime_scrub
samsinsane Dec 6, 2025
c978668
Added a function to build a runtime EnumInfo.
TurkeyMan Dec 7, 2025
d3a470d
Added a helper for building string caches.
TurkeyMan Dec 7, 2025
7025ea7
Fix qsort... apparently I buggered it up!
TurkeyMan Dec 7, 2025
0b3c110
Added a signed parse_int_with_base
TurkeyMan Dec 7, 2025
4406091
Added a template to make a ScaledUnit from a string.
TurkeyMan Dec 7, 2025
38f75e3
Unroll array
TurkeyMan Dec 7, 2025
6b1c6f6
Merge pull request #42 from open-watt/runtime_enum_info
samsinsane Dec 7, 2025
c0666b5
Merge pull request #43 from open-watt/string_cache_builder
samsinsane Dec 7, 2025
1f5014a
Merge pull request #44 from open-watt/fix_qsort
samsinsane Dec 7, 2025
96292f3
Merge pull request #45 from open-watt/parse_int_with_base
samsinsane Dec 7, 2025
cf0b532
Merge pull request #46 from open-watt/unit_helper
samsinsane Dec 7, 2025
8e48602
Merge pull request #47 from open-watt/unroll_array
samsinsane Dec 7, 2025
74fc4f1
Fixed an assortment of small bugs.
TurkeyMan Dec 8, 2025
ada8cb1
Merge pull request #48 from open-watt/bugs
samsinsane Dec 9, 2025
bb72172
Fix handling of negative times.
TurkeyMan Dec 10, 2025
50b70d0
Merge pull request #50 from open-watt/negative_time_to_string
samsinsane Dec 11, 2025
5b90efc
Fix EnumInfo typed values array offset.
TurkeyMan Dec 12, 2025
b7ca9d6
Fixed a bug resuming from a fibre multiple times.
TurkeyMan Dec 12, 2025
9cb542b
Merge pull request #51 from open-watt/enum_info
samsinsane Dec 12, 2025
f8341be
Merge pull request #52 from open-watt/fibre_fix
samsinsane Dec 12, 2025
a7cc818
Add toString for Arrays and Maps.
TurkeyMan Dec 14, 2025
89eba28
Write a log message before calling abort() when a fibre encounters an…
TurkeyMan Dec 14, 2025
ebe36c6
Merge pull request #53 from open-watt/fibre_abort
samsinsane Dec 14, 2025
9c2687e
Merge pull request #54 from open-watt/stringify_array_map
samsinsane Dec 14, 2025
f086793
Fixed a swap-endian bug in a function that had never been called.
TurkeyMan Dec 30, 2025
aa0d02b
Explicit format arg.
TurkeyMan Dec 14, 2025
d47457b
Merge pull request #56 from open-watt/fix_endian
samsinsane Dec 30, 2025
41dc261
Merge pull request #55 from open-watt/format_arg
samsinsane Dec 30, 2025
22e16a0
Added a function to parse a decimal uint, reporting the exponent wher…
TurkeyMan Dec 31, 2025
37b741c
Merge pull request #57 from open-watt/parse_with_exp
samsinsane Dec 31, 2025
50d5ba5
Added unittest for parse_uint_with_exponent... fixed a bug.
TurkeyMan Dec 31, 2025
2583158
Merge pull request #58 from open-watt/parse_int_exp_test
samsinsane Dec 31, 2025
50f7c18
Fixed some string formatting bugs and TODOs
TurkeyMan Jan 7, 2026
7b035ab
Merge pull request #59 from open-watt/string_and_json_formatting
samsinsane Jan 7, 2026
73cd497
Properly support template toString functions, and also improved/simpl…
TurkeyMan Jan 8, 2026
a672ee1
Fleshed out the wildcard match, and Claude added a shitload of tests!
TurkeyMan Jan 8, 2026
964f61e
Merge pull request #60 from open-watt/support_template_to_string
samsinsane Jan 8, 2026
8bed07c
Merge pull request #61 from open-watt/wildcard_match
samsinsane Jan 8, 2026
3c483a2
Added case insensitive option, numeric match, and optional match.
TurkeyMan Jan 8, 2026
28d390d
Merge pull request #62 from open-watt/wildcard_match
samsinsane Jan 19, 2026
2233eec
Fixed unit parsing.
TurkeyMan Jan 21, 2026
b93a3f5
Merge pull request #63 from open-watt/unit_fix
samsinsane Jan 21, 2026
569e27b
Trim underscore from enum keys, which often exist to disambiguate fro…
TurkeyMan Jan 24, 2026
f7de5c1
Add a function to adjust a Quantity scale.
TurkeyMan Jan 24, 2026
5d854a8
Add some helpers to StringCacheBuilder
TurkeyMan Jan 25, 2026
03315ff
Merge pull request #64 from open-watt/trim_enum_keys
samsinsane Jan 26, 2026
a93453a
Merge pull request #65 from open-watt/adjust_scale
samsinsane Jan 26, 2026
ccb4210
Merge pull request #66 from open-watt/string_cache_builder
samsinsane Jan 26, 2026
0efbdde
Array!char.concat/append was extended to support the same set of argu…
TurkeyMan Jan 28, 2026
361a283
Fix variant opCmp
TurkeyMan Jan 29, 2026
ba38341
Merge pull request #67 from open-watt/char_array_concat
samsinsane Jan 30, 2026
05b6be9
Merge pull request #68 from open-watt/variant_cmp
samsinsane Jan 30, 2026
2be4ae3
Improve the DateTime parsing, and supported DateTime -> SysTime conve…
TurkeyMan Feb 1, 2026
114e944
Move function out of urt.
TurkeyMan Feb 1, 2026
fe4b700
Parse e-notation, delete the `with_decimal` ones, normalise, and reor…
TurkeyMan Feb 1, 2026
a913c44
Fix CTFE implementation of qsort!
TurkeyMan Feb 2, 2026
73eb471
Quantity fix.
TurkeyMan Feb 2, 2026
8eac6ce
Merge pull request #70 from open-watt/date_time_parsing
samsinsane Feb 2, 2026
2f55196
Merge pull request #69 from open-watt/trim_comment
samsinsane Feb 2, 2026
b375c99
Merge pull request #71 from open-watt/improve_int_parsing
samsinsane Feb 2, 2026
83bd4b8
Merge pull request #72 from open-watt/qsort_fix
samsinsane Feb 2, 2026
ee24fbf
Merge pull request #73 from open-watt/quantity_fix
samsinsane Feb 2, 2026
6925ddd
Fixed integer division.
TurkeyMan Feb 6, 2026
08df319
Reserve null in the string cache.
TurkeyMan Feb 4, 2026
c225ba5
Merge pull request #75 from open-watt/fix_unit
megaeels Feb 7, 2026
d4e8c27
Merge pull request #74 from open-watt/string_cache_null
megaeels Feb 7, 2026
c4ede51
Added parse_quantity which is like parse_float, but with a unit suffix.
TurkeyMan Feb 8, 2026
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
19 changes: 2 additions & 17 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,7 @@ DEPFILE := $(OBJDIR)/$(TARGETNAME).d

DFLAGS := $(DFLAGS) -preview=bitfields -preview=rvaluerefparam -preview=nosharedaccess -preview=in

ifeq ($(OS),windows)
SOURCES := $(shell dir /s /b $(SRCDIR)\\*.d)
else
SOURCES := $(shell find "$(SRCDIR)" -type f -name '*.d')
endif

# Set target file based on build type and OS
ifeq ($(BUILD_TYPE),exe)
Expand Down Expand Up @@ -93,30 +89,19 @@ else
endif

ifeq ($(CONFIG),unittest)
DFLAGS := $(DFLAGS) -unittest
DFLAGS := $(DFLAGS) -unittest -main
endif

-include $(DEPFILE)

$(TARGET):
ifeq ($(OS),windows)
@if not exist "obj" mkdir "obj" > nul 2>&1
@if not exist "$(subst /,\,$(OBJDIR))" mkdir "$(subst /,\,$(OBJDIR))" > nul 2>&1
@if not exist "bin" mkdir "bin" > nul 2>&1
@if not exist "$(subst /,\,$(TARGETDIR))" mkdir "$(subst /,\,$(TARGETDIR))" > nul 2>&1
else
mkdir -p $(OBJDIR) $(TARGETDIR)
endif
ifeq ($(D_COMPILER),ldc)
"$(DC)" $(DFLAGS) $(BUILD_CMD_FLAGS) -of$(TARGET) -od$(OBJDIR) -deps=$(DEPFILE) $(SOURCES)
else ifeq ($(D_COMPILER),dmd)
ifeq ($(BUILD_TYPE),lib)
"$(DC)" $(DFLAGS) $(BUILD_CMD_FLAGS) -of$(notdir $(TARGET)) -od$(OBJDIR) -makedeps $(SOURCES) > $(DEPFILE)
ifeq ($(OS),windows)
move "$(subst /,\,$(OBJDIR))\\$(notdir $(TARGET))" "$(subst /,\,$(TARGETDIR))" > nul
else
"$(DC)" $(DFLAGS) $(BUILD_CMD_FLAGS) -of$(OBJDIR)/$(notdir $(TARGET)) -od$(OBJDIR) -makedeps $(SOURCES) > $(DEPFILE)
mv "$(OBJDIR)/$(notdir $(TARGET))" "$(TARGETDIR)"
endif
else # exe
"$(DC)" $(DFLAGS) $(BUILD_CMD_FLAGS) -of$(TARGET) -od$(OBJDIR) -makedeps $(SOURCES) > $(DEPFILE)
endif
Expand Down
227 changes: 142 additions & 85 deletions src/urt/algorithm.d
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module urt.algorithm;

import urt.traits : lvalueOf;
import urt.meta : AliasSeq;
import urt.traits : is_some_function, lvalue_of, Parameters, ReturnType, Unqual;
import urt.util : swap;

version = SmallSize;
Expand All @@ -10,36 +11,44 @@ nothrow @nogc:

auto compare(T, U)(auto ref T a, auto ref U b)
{
static if (__traits(compiles, lvalueOf!T.opCmp(lvalueOf!U)))
static if (__traits(compiles, a.opCmp(b)))
return a.opCmp(b);
else static if (__traits(compiles, lvalueOf!U.opCmp(lvalueOf!T)))
else static if (__traits(compiles, b.opCmp(a)))
return -b.opCmp(a);
else static if (is(T : A[], A))
else static if (is(T : A[], A) || is(U : B[], B))
{
import urt.traits : isPrimitive;
import urt.traits : is_primitive;

static assert(is(T : A[], A) && is(U : B[], B), "TODO: compare an array with a not-array?");

auto ai = a.ptr;
auto bi = b.ptr;
size_t len = a.length < b.length ? a.length : b.length;
static if (isPrimitive!A)

// first compere the pointers...
if (ai !is bi)
{
// compare strings
foreach (i; 0 .. len)
size_t len = a.length < b.length ? a.length : b.length;
static if (is_primitive!A)
{
if (ai[i] != bi[i])
return ai[i] < bi[i] ? -1 : 1;
// compare strings
foreach (i; 0 .. len)
{
if (ai[i] != bi[i])
return ai[i] < bi[i] ? -1 : 1;
}
}
}
else
{
// compare arrays
foreach (i; 0 .. len)
else
{
auto cmp = compare(ai[i], bi[i]);
if (cmp != 0)
return cmp;
// compare arrays
foreach (i; 0 .. len)
{
if (auto cmp = compare(ai[i], bi[i]))
return cmp;
}
}
}

// finally, compare the lengths
if (a.length == b.length)
return 0;
return a.length < b.length ? -1 : 1;
Expand All @@ -48,8 +57,39 @@ auto compare(T, U)(auto ref T a, auto ref U b)
return a < b ? -1 : (a > b ? 1 : 0);
}

size_t binarySearch(alias pred = void, T, Cmp...)(T[] arr, auto ref Cmp cmpArgs)
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 = count;
while (low < high)
{
size_t mid = low + (high - low) / 2;

// should we chase the first in a sequence of same values?
int cmp = pred(p + mid*stride, value);
if (cmp < 0)
low = mid + 1;
else
high = mid;
}
if (low == count)
return count;
if (pred(p + low*stride, value) == 0)
return low;
return count;
}

size_t binary_search(alias pred = void, T, Cmp...)(T[] arr, auto ref Cmp cmp_args)
if (!is(Unqual!T == void))
{
static if (is(pred == void))
static assert (cmp_args.length == 1, "binary_search without a predicate requires exactly one comparison argument");

T* p = arr.ptr;
size_t low = 0;
size_t high = arr.length;
Expand All @@ -59,90 +99,105 @@ size_t binarySearch(alias pred = void, T, Cmp...)(T[] arr, auto ref Cmp cmpArgs)
static if (is(pred == void))
{
// should we chase the first in a sequence of same values?
if (p[mid] < cmpArgs[0])
if (p[mid] < cmp_args[0])
low = mid + 1;
else
high = mid;
}
else
{
// should we chase the first in a sequence of same values?
int cmp = pred(p[mid], cmpArgs);
int cmp = pred(p[mid], cmp_args);
if (cmp < 0)
low = mid + 1;
else
high = mid;
}
}
if (low == arr.length)
return arr.length;
static if (is(pred == void))
{
if (p[low] == cmpArgs[0])
if (p[low] == cmp_args[0])
return low;
}
else
{
if (pred(p[low], cmpArgs) == 0)
if (pred(p[low], cmp_args) == 0)
return low;
}
return arr.length;
}


void qsort(alias pred = void, T)(T[] arr)
void qsort(alias pred = void, T)(T[] arr) pure
{
if (arr.length <= 1)
return;

version (SmallSize)
enum use_small_size_impl = true;
else
enum use_small_size_impl = false;

if (!__ctfe && use_small_size_impl)
{
static if (is(pred == void))
static if (__traits(compiles, lvalueOf!T.opCmp(lvalueOf!T)))
static int compare(const void* a, const void* b) nothrow @nogc
static if (__traits(compiles, lvalue_of!T.opCmp(lvalue_of!T)))
static int compare(const void* a, const void* b) pure nothrow @nogc
=> (*cast(const T*)a).opCmp(*cast(const T*)b);
else
static int compare(const void* a, const void* b) nothrow @nogc
static int compare(const void* a, const void* b) pure nothrow @nogc
=> *cast(const T*)a < *cast(const T*)b ? -1 : *cast(const T*)a > *cast(const T*)b ? 1 : 0;
else
static int compare(const void* a, const void* b) nothrow @nogc
static int compare(const void* a, const void* b) pure nothrow @nogc
=> pred(*cast(T*)a, *cast(T*)b);

qsort(arr[], T.sizeof, &compare, (void* a, void* b) nothrow @nogc {
qsort(arr[], T.sizeof, &compare, (void* a, void* b) pure nothrow @nogc {
swap(*cast(T*)a, *cast(T*)b);
});
}
else
{
T* p = arr.ptr;
if (arr.length > 1)
{
size_t pivotIndex = arr.length / 2;
T* pivot = &p[pivotIndex];
const n = cast(ptrdiff_t)arr.length;

size_t pivotIndex = n / 2;
T* pivot = p + pivotIndex;

size_t i = 0;
size_t j = arr.length - 1;
size_t i = 0;
ptrdiff_t j = n - 1;

while (i <= j)
while (i <= j)
{
static if (is(pred == void))
{
static if (is(pred == void))
{
while (p[i] < *pivot) i++;
while (p[j] > *pivot) j--;
}
else
{
while (pred(*cast(T*)&p[i], *cast(T*)pivot) < 0) i++;
while (pred(*cast(T*)&p[j], *cast(T*)pivot) > 0) j--;
}
if (i <= j)
{
swap(p[i], p[j]);
i++;
j--;
}
while (p[i] < *pivot) ++i;
while (p[j] > *pivot) --j;
}
else
{
while (pred(p[i], *pivot) < 0) ++i;
while (pred(p[j], *pivot) > 0) --j;
}
if (i <= j)
{
// track pivot value across swaps
if (p + i == pivot)
pivot = p + j;
else if (p + j == pivot)
pivot = p + i;

if (j > 0)
qsort(p[0 .. j + 1]);
if (i < arr.length)
qsort(p[i .. arr.length]);
swap(p[i], p[j]);
++i;
--j;
}
}

if (j >= 0)
qsort!pred(p[0 .. j + 1]);
if (i < n)
qsort!pred(p[i .. n]);
}
}

Expand All @@ -151,26 +206,26 @@ unittest
struct S
{
int x;
int opCmp(ref const S rh) const nothrow @nogc
int opCmp(ref const S rh) pure const nothrow @nogc
=> x < rh.x ? -1 : x > rh.x ? 1 : 0;
}

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

S[5] arr2 = [ S(3), S(100), S(-1), S(17), S(30)];
S[5] arr2 = [ S(3), S(100), S(-1), S(17), S(30) ];
qsort(arr2);
foreach (i, ref s; arr2)
assert(s.x == arr[i]);

// test binary search, not that they're sorted...
assert(binarySearch(arr, -1) == 0);
assert(binarySearch!(s => s.x < 30 ? -1 : s.x > 30 ? 1 : 0)(arr2) == 3);
assert(binarySearch(arr, 0) == arr.length);
assert(binary_search(arr, -1) == 0);
assert(binary_search!(s => s.x < 30 ? -1 : s.x > 30 ? 1 : 0)(arr2) == 3);
assert(binary_search(arr, 0) == arr.length);

int[10] rep = [1, 10, 10, 10, 10, 10, 10, 10, 10, 100];
assert(binarySearch(rep, 10) == 1);
assert(binary_search(rep, 10) == 1);
}


Expand All @@ -181,34 +236,36 @@ version (SmallSize)
// just one generic implementation to minimise the code...
// kinda slow though... look at all those multiplies!
// maybe there's some way to make this faster :/
void qsort(void[] arr, size_t elementSize, int function(const void* a, const void* b) nothrow @nogc compare, void function(void* a, void* b) nothrow @nogc swap)
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
{
void* p = arr.ptr;
size_t length = arr.length / elementSize;
if (length > 1)
{
size_t pivotIndex = length / 2;
void* pivot = p + pivotIndex*elementSize;
size_t length = arr.length / element_size;
if (length <= 1)
return;

size_t pivot_index = length / 2;
size_t last = length - 1;
swap(p + pivot_index*element_size, p + last*element_size);

size_t i = 0;
size_t j = length - 1;
void* pivot = p + last*element_size;

while (i <= j)
size_t partition = 0;
for (size_t k = 0; k < last; ++k)
{
void* elem = p + k*element_size;
if (compare(elem, pivot) < 0)
{
while (compare(p + i*elementSize, pivot) < 0) i++;
while (compare(p + j*elementSize, pivot) > 0) j--;
if (i <= j)
{
swap(p + i*elementSize, p + j*elementSize);
i++;
j--;
}
if (k != partition)
swap(elem, p + partition*element_size);
++partition;
}

if (j > 0)
qsort(p[0 .. (j + 1)*elementSize], elementSize, compare, swap);
if (i < length)
qsort(p[i*elementSize .. length*elementSize], elementSize, compare, swap);
}

swap(p + partition*element_size, p + last*element_size);

if (partition > 1)
qsort(p[0 .. partition*element_size], element_size, compare, swap);
if (partition + 1 < length)
qsort(p[(partition + 1)*element_size .. length*element_size], element_size, compare, swap);
}
}
Loading