11module 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;
45import urt.util : swap;
56
67version = 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+
5984size_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