1 /**
2 *
3 * Various @nogc alternatives. This file includes parts of `std.process`, `std.random`, `std.uuid`.
4 *
5 * Authors:
6 *    $(HTTP guillaumepiolat.fr, Guillaume Piolat)
7 *    $(LINK2 https://github.com/kyllingstad, Lars Tandle Kyllingstad),
8 *    $(LINK2 https://github.com/schveiguy, Steven Schveighoffer),
9 *    $(HTTP thecybershadow.net, Vladimir Panteleev)
10 *
11 * Copyright:
12 *   Copyright (c) 2016, Auburn Sounds.
13 *   Copyright (c) 2013, Lars Tandle Kyllingstad (std.process).
14 *   Copyright (c) 2013, Steven Schveighoffer (std.process).
15 *   Copyright (c) 2013, Vladimir Panteleev (std.process).
16 *
17 * License:
18 *   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
19 */
20 module dplug.core.nogc;
21 
22 import core.stdc..string: strdup, memcpy, strlen;
23 import core.stdc.stdlib: malloc, free, getenv;
24 import core.memory: GC;
25 import core.exception: onOutOfMemoryErrorNoGC;
26 
27 import std.conv: emplace;
28 import std.traits;
29 import std.array: empty;
30 import std.exception: assumeUnique;
31 
32 // This module provides many utilities to deal with @nogc
33 
34 version = doNotUseRuntime;
35 
36 //
37 // Faking @nogc
38 //
39 
40 auto assumeNoGC(T) (T t)
41 {
42     static if (isFunctionPointer!T || isDelegate!T)
43     {
44         enum attrs = functionAttributes!T | FunctionAttribute.nogc;
45         return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t;
46     }
47     else
48         static assert(false);
49 }
50 
51 auto assumeNothrowNoGC(T) (T t)
52 {
53     static if (isFunctionPointer!T || isDelegate!T)
54     {
55         enum attrs = functionAttributes!T | FunctionAttribute.nogc | FunctionAttribute.nothrow_;
56         return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t;
57     }
58     else
59         static assert(false);
60 }
61 
62 unittest
63 {
64     void funcThatDoesGC()
65     {
66         int a = 4;
67         int[] b = [a, a, a];
68     }
69 
70     void anotherFunction() nothrow @nogc
71     {
72         assumeNothrowNoGC( (){ funcThatDoesGC(); } )();
73     }
74 
75     void aThirdFunction() @nogc
76     {
77         assumeNoGC( () { funcThatDoesGC(); } )();
78     }
79 }
80 
81 
82 //
83 // Optimistic .destroy, which is @nogc nothrow by breaking the type-system
84 //
85 
86 // for classes
87 void destroyNoGC(T)(T x) nothrow @nogc if (is(T == class) || is(T == interface))
88 {
89     assumeNothrowNoGC(
90         (T x)
91         {
92             return destroy(x);
93         })(x);
94 }
95 
96 // for struct
97 void destroyNoGC(T)(ref T obj) nothrow @nogc if (is(T == struct))
98 {
99     assumeNothrowNoGC(
100         (ref T x)
101         {
102             return destroy(x);
103         })(obj);
104 }
105 /*
106 void destroyNoGC(T : U[n], U, size_t n)(ref T obj) nothrow @nogc
107 {
108     assumeNothrowNoGC(
109         (T x)
110         {
111             return destroy(x);
112         })(obj);
113 }*/
114 
115 void destroyNoGC(T)(ref T obj) nothrow @nogc
116     if (!is(T == struct) && !is(T == class) && !is(T == interface))
117 {
118     assumeNothrowNoGC(
119                       (ref T x)
120                       {
121                           return destroy(x);
122                       })(obj);
123 }
124 
125 
126 
127 //
128 // Constructing and destroying without the GC.
129 //
130 
131 /// Allocates and construct a struct or class object.
132 /// Returns: Newly allocated object.
133 // Note: strangely enough, deprecated alias didn't work for this.
134 deprecated("Use mallocNew instead")
135 auto mallocEmplace(T, Args...)(Args args)
136 {
137     static if (is(T == class))
138         immutable size_t allocSize = __traits(classInstanceSize, T);
139     else
140         immutable size_t allocSize = T.sizeof;
141 
142     void* rawMemory = malloc(allocSize);
143     if (!rawMemory)
144         onOutOfMemoryErrorNoGC();
145 
146     version(doNotUseRuntime)
147     {
148     }
149     else
150     {
151         static if (hasIndirections!T)
152             GC.addRange(rawMemory, allocSize);
153     }
154 
155     static if (is(T == class))
156     {
157         T obj = emplace!T(rawMemory[0 .. allocSize], args);
158     }
159     else
160     {
161         T* obj = cast(T*)rawMemory;
162         emplace!T(obj, args);
163     }
164 
165     return obj;
166 }
167 
168 /// Allocates and construct a struct or class object.
169 /// Returns: Newly allocated object.
170 auto mallocNew(T, Args...)(Args args)
171 {
172     static if (is(T == class))
173         immutable size_t allocSize = __traits(classInstanceSize, T);
174     else
175         immutable size_t allocSize = T.sizeof;
176 
177     void* rawMemory = malloc(allocSize);
178     if (!rawMemory)
179         onOutOfMemoryErrorNoGC();
180 
181     version(doNotUseRuntime)
182     {
183     }
184     else
185     {
186         static if (hasIndirections!T)
187             GC.addRange(rawMemory, allocSize);
188     }
189 
190     static if (is(T == class))
191     {
192         T obj = emplace!T(rawMemory[0 .. allocSize], args);
193     }
194     else
195     {
196         T* obj = cast(T*)rawMemory;
197         emplace!T(obj, args);
198     }
199 
200     return obj;
201 }
202 
203 /// Destroys and frees a class object created with $(D mallocEmplace).
204 void destroyFree(T)(T p) if (is(T == class))
205 {
206     if (p !is null)
207     {
208         destroyNoGC(p);
209 
210         version(doNotUseRuntime)
211         {
212         }
213         else
214         {
215             static if (hasIndirections!T)
216                 GC.removeRange(cast(void*)p);
217         }
218 
219         free(cast(void*)p);
220     }
221 }
222 
223 /// Destroys and frees an interface object created with $(D mallocEmplace).
224 void destroyFree(T)(T p) if (is(T == interface))
225 {
226     if (p !is null)
227     {
228         void* here = cast(void*)(cast(Object)p);
229         destroyNoGC(p);
230 
231         version(doNotUseRuntime)
232         {
233         }
234         else
235         {
236             static if (hasIndirections!T)
237                 GC.removeRange(here);
238         }
239 
240         free(cast(void*)here);
241     }
242 }
243 
244 /// Destroys and frees a non-class object created with $(D mallocEmplace).
245 void destroyFree(T)(T* p) if (!is(T == class))
246 {
247     if (p !is null)
248     {
249         destroyNoGC(p);
250 
251         version(doNotUseRuntime)
252         {
253         }
254         else
255         {
256             static if (hasIndirections!T)
257                 GC.removeRange(cast(void*)p);
258         }
259 
260         free(cast(void*)p);
261     }
262 }
263 
264 
265 unittest
266 {
267     class A
268     {
269         int _i;
270         this(int i)
271         {
272             _i = i;
273         }
274     }
275 
276     struct B
277     {
278         int i;
279     }
280 
281     void testMallocEmplace()
282     {
283         A a = mallocNew!A(4);
284         destroyFree(a);
285 
286         B* b = mallocNew!B(5);
287         destroyFree(b);
288     }
289 
290     testMallocEmplace();
291 }
292 
293 version( D_InlineAsm_X86 )
294 {
295     version = AsmX86;
296 }
297 else version( D_InlineAsm_X86_64 )
298 {
299     version = AsmX86;
300 }
301 
302 /// Allocates a slice with `malloc`.
303 T[] mallocSlice(T)(size_t count) nothrow @nogc
304 {
305     T[] slice = mallocSliceNoInit!T(count);
306     static if (is(T == struct))
307     {
308         // we must avoid calling struct destructors with uninitialized memory
309         for(size_t i = 0; i < count; ++i)
310         {
311             T uninitialized;
312             memcpy(&slice[i], &uninitialized, T.sizeof);
313         }
314     }
315     else
316         slice[0..count] = T.init;
317     return slice;
318 }
319 
320 /// Allocates a slice with `malloc`, but does not initialize the content.
321 T[] mallocSliceNoInit(T)(size_t count) nothrow @nogc
322 {
323     T* p = cast(T*) malloc(count * T.sizeof);
324     return p[0..count];
325 }
326 
327 /// Frees a slice allocated with `mallocSlice`.
328 void freeSlice(T)(const(T)[] slice) nothrow @nogc
329 {
330     free(cast(void*)(slice.ptr)); // const cast here
331 }
332 
333 /// Duplicates a slice with `malloc`. Equivalent to `.dup`
334 /// Has to be cleaned-up with `free()`.
335 T[] mallocDup(T)(const(T)[] slice) nothrow @nogc if (!is(T == struct))
336 {
337     T[] copy = mallocSliceNoInit!T(slice.length);
338     memcpy(copy.ptr, slice.ptr, slice.length * T.sizeof);
339     return copy;
340 }
341 
342 /// Duplicates a slice with `malloc`. Equivalent to `.idup`
343 /// Has to be cleaned-up with `free()`.
344 immutable(T)[] mallocIDup(T)(const(T)[] slice) nothrow @nogc if (!is(T == struct))
345 {
346     return assumeUnique(mallocDup!T(slice));
347 }
348 
349 /// Duplicates a zero-terminated string with `malloc`, return a `char[]`. Equivalent to `.dup`
350 /// Has to be cleaned-up with `free()`.
351 /// Note: The zero-terminating byte is preserved. This allow to have a string which also can be converted
352 /// to a C string with `.ptr`. However the zero byte is not included in slice length.
353 char[] stringDup(const(char)* cstr) nothrow @nogc
354 {
355     assert(cstr !is null);
356     size_t len = strlen(cstr);
357     char* copy = strdup(cstr);
358     return copy[0..len];
359 }
360 
361 /// Duplicates a zero-terminated string with `malloc`, return a `string`. Equivalent to `.idup`
362 /// Has to be cleaned-up with `free()`.
363 /// Note: The zero-terminating byte is preserved. This allow to have a string which also can be converted
364 /// to a C string with `.ptr`. However the zero byte is not included in slice length.
365 string stringIDup(const(char)* cstr) nothrow @nogc
366 {
367     return assumeUnique(stringDup(cstr));
368 }
369 
370 unittest
371 {
372     int[] slice = mallocSlice!int(4);
373     freeSlice(slice);
374     assert(slice[3] == int.init);
375 
376     slice = mallocSliceNoInit!int(4);
377     freeSlice(slice);
378 
379     slice = mallocSliceNoInit!int(0);
380     assert(slice == []);
381     freeSlice(slice);
382 }
383 
384 /// Semantic function to check that a D string implicitely conveys a 
385 /// termination byte after the slice.
386 /// (typically those comes from string literals or `stringDup`/`stringIDup`)
387 const(char)* assumeZeroTerminated(const(char)[] input) nothrow @nogc
388 {
389     if (input.ptr is null)
390         return null;
391 
392     // Check that the null character is there
393     assert(input.ptr[input.length] == '\0');
394     return input.ptr;
395 }
396 
397 
398 //
399 // @nogc sorting.
400 //
401 
402 /// Must return -1 if a < b
403 ///              0 if a == b
404 ///              1 if a > b
405 alias nogcComparisonFunction(T) = int delegate(in T a, in T b) nothrow @nogc;
406 
407 /// @nogc quicksort
408 /// From the excellent: http://codereview.stackexchange.com/a/77788
409 deprecated("Use grailSort() instead, which is faster") void quicksort(T)(T[] array, nogcComparisonFunction!T comparison) nothrow @nogc
410 {
411     if (array.length < 2)
412         return;
413 
414     static void swapElem(ref T lhs, ref T rhs)
415     {
416         T tmp = lhs;
417         lhs = rhs;
418         rhs = tmp;
419     }
420 
421     int partition(T* arr, int left, int right) nothrow @nogc
422     {
423         immutable int mid = left + (right - left) / 2;
424         T pivot = arr[mid];
425         // move the mid point value to the front.
426         swapElem(arr[mid],arr[left]);
427         int i = left + 1;
428         int j = right;
429         while (i <= j)
430         {
431             while(i <= j && comparison(arr[i], pivot) <= 0 )
432                 i++;
433 
434             while(i <= j && comparison(arr[j], pivot) > 0)
435                 j--;
436 
437             if (i < j)
438                 swapElem(arr[i], arr[j]);
439         }
440         swapElem(arr[i - 1], arr[left]);
441         return i - 1;
442     }
443 
444     void doQsort(T* array, int left, int right) nothrow @nogc
445     {
446         if (left >= right)
447             return;
448 
449         int part = partition(array, left, right);
450         doQsort(array, left, part - 1);
451         doQsort(array, part + 1, right);
452     }
453 
454     doQsort(array.ptr, 0, cast(int)(array.length) - 1);
455 }
456 
457 //
458 // STABLE IN-PLACE SORT (implementation is at bottom of file)
459 //
460 
461 void grailSort(T)(T[] inoutElements, nogcComparisonFunction!T comparison) nothrow @nogc
462 {
463     GrailSort!T(inoutElements.ptr, cast(int)(inoutElements.length), comparison);
464 }
465 
466 unittest
467 {
468     int[2][] testData = [[110, 0], [5, 0], [10, 0], [3, 0], [110, 1], [5, 1], [10, 1], [3, 1]];
469     grailSort!(int[2])(testData, (a, b) => (a[0] - b[0]));
470     assert(testData == [[3, 0], [3, 1], [5, 0], [5, 1], [10, 0], [10, 1], [110, 0], [110, 1]]);
471 }
472 
473 
474 //
475 // STABLE MERGE SORT
476 //
477 
478 /// Stable merge sort, using a temporary array.
479 /// Array A[] has the items to sort.
480 /// Array B[] is a work array.
481 /// `grailSort` is approx. 30% slower but doesn't need a scratchBuffer.
482 void mergeSort(T)(T[] inoutElements, T[] scratchBuffer, nogcComparisonFunction!T comparison) nothrow @nogc
483 {
484     // Left source half is A[ iBegin:iMiddle-1].
485     // Right source half is A[iMiddle:iEnd-1   ].
486     // Result is            B[ iBegin:iEnd-1   ].
487     void topDownMerge(T)(T* A, int iBegin, int iMiddle, int iEnd, T* B) nothrow @nogc
488     {
489         int i = iBegin;
490         int j = iMiddle;
491 
492         // While there are elements in the left or right runs...
493         for (int k = iBegin; k < iEnd; k++)
494         {
495             // If left run head exists and is <= existing right run head.
496             if ( i < iMiddle && ( j >= iEnd || (comparison(A[i], A[j]) <= 0) ) )
497             {
498                 B[k] = A[i];
499                 i = i + 1;
500             }
501             else
502             {
503                 B[k] = A[j];
504                 j = j + 1;
505             }
506         }
507     }
508 
509     // Sort the given run of array A[] using array B[] as a source.
510     // iBegin is inclusive; iEnd is exclusive (A[iEnd] is not in the set).
511     void topDownSplitMerge(T)(T* B, int iBegin, int iEnd, T* A) nothrow @nogc
512     {
513         if(iEnd - iBegin < 2)                       // if run size == 1
514             return;                                 //   consider it sorted
515         // split the run longer than 1 item into halves
516         int iMiddle = (iEnd + iBegin) / 2;              // iMiddle = mid point
517         // recursively sort both runs from array A[] into B[]
518         topDownSplitMerge!T(A, iBegin,  iMiddle, B);  // sort the left  run
519         topDownSplitMerge!T(A, iMiddle,    iEnd, B);  // sort the right run
520         // merge the resulting runs from array B[] into A[]
521         topDownMerge!T(B, iBegin, iMiddle, iEnd, A);
522     }
523 
524     assert(inoutElements.length == scratchBuffer.length);
525     int n = cast(int)inoutElements.length;
526     scratchBuffer[] = inoutElements[]; // copy data into temporary buffer
527     topDownSplitMerge(scratchBuffer.ptr, 0, n, inoutElements.ptr);
528 }
529 
530 unittest
531 {
532     int[2][] scratch;
533     scratch.length = 8;
534     int[2][] testData = [[110, 0], [5, 0], [10, 0], [3, 0], [110, 1], [5, 1], [10, 1], [3, 1]];
535     mergeSort!(int[2])(testData, scratch, (a, b) => (a[0] - b[0]));
536     assert(testData == [[3, 0], [3, 1], [5, 0], [5, 1], [10, 0], [10, 1], [110, 0], [110, 1]]);
537 }
538 
539 /// To call for something that should never happen, but we still
540 /// want to make a "best effort" at runtime even if it can be meaningless.
541 /// MAYDO: change that name, it's not actually unrecoverable
542 /// MAYDO: stop using that function
543 void unrecoverableError() nothrow @nogc
544 {
545     debug
546     {
547         // Crash unconditionally
548         assert(false);
549     }
550     else
551     {
552         // There is a trade-off here, if we crash immediately we will be
553         // correctly identified by the user as the origin of the bug, which
554         // is always helpful.
555         // But crashing may in many-case also crash the host, which is not very friendly.
556         // Eg: a plugin not instancing vs host crashing.
557         // The reasoning is that the former is better from the user POV.
558     }
559 }
560 
561 
562 /// A bit faster than a dynamic cast.
563 /// This is to avoid TypeInfo look-up.
564 T unsafeObjectCast(T)(Object obj)
565 {
566     return cast(T)(cast(void*)(obj));
567 }
568 
569 
570 /// Inserts a breakpoint instruction. useful to trigger the debugger.
571 void debugBreak() nothrow @nogc
572 {
573     version( AsmX86 )
574     {
575         asm nothrow @nogc
576         {
577             int 3;
578         }
579     }
580     else version( GNU )
581     {
582         // __builtin_trap() is not the same thing unfortunately
583         asm
584         {
585             "int $0x03" : : : ;
586         }
587     }
588     else
589     {
590         static assert(false, "No debugBreak() for this compiler");
591     }
592 }
593 
594 
595 // Copy source into dest.
596 // dest must contain room for maxChars characters
597 // A zero-byte character is then appended.
598 void stringNCopy(char* dest, size_t maxChars, const(char)[] source) nothrow @nogc
599 {
600     if (maxChars == 0)
601         return;
602 
603     size_t max = maxChars < source.length ? maxChars - 1 : source.length;
604     for (int i = 0; i < max; ++i)
605         dest[i] = source[i];
606     dest[max] = '\0';
607 }
608 
609 
610 //
611 // Low-cost C string conversions
612 //
613 alias CString = CStringImpl!char;
614 alias CString16 = CStringImpl!wchar;
615 
616 /// Zero-terminated C string, to replace toStringz and toUTF16z
617 struct CStringImpl(CharType) if (is(CharType: char) || is(CharType: wchar))
618 {
619 public:
620 nothrow:
621 @nogc:
622 
623     const(CharType)* storage = null;
624     alias storage this;
625 
626 
627     this(const(CharType)[] s)
628     {
629         // Always copy. We can't assume anything about the input.
630         size_t len = s.length;
631         CharType* buffer = cast(CharType*) malloc((len + 1) * CharType.sizeof);
632         buffer[0..len] = s[0..len];
633         buffer[len] = '\0';
634         storage = buffer;
635         wasAllocated = true;
636     }
637 
638     // The constructor taking immutable can safely assume that such memory
639     // has been allocated by the GC or malloc, or an allocator that align
640     // pointer on at least 4 bytes.
641     this(immutable(CharType)[] s)
642     {
643         // Same optimizations that for toStringz
644         if (s.empty)
645         {
646             enum emptyString = cast(CharType[])"";
647             storage = emptyString.ptr;
648             return;
649         }
650 
651         /* Peek past end of s[], if it's 0, no conversion necessary.
652         * Note that the compiler will put a 0 past the end of static
653         * strings, and the storage allocator will put a 0 past the end
654         * of newly allocated char[]'s.
655         */
656         const(CharType)* p = s.ptr + s.length;
657         // Is p dereferenceable? A simple test: if the p points to an
658         // address multiple of 4, then conservatively assume the pointer
659         // might be pointing to another block of memory, which might be
660         // unreadable. Otherwise, it's definitely pointing to valid
661         // memory.
662         if ((cast(size_t) p & 3) && *p == 0)
663         {
664             storage = s.ptr;
665             return;
666         }
667 
668         size_t len = s.length;
669         CharType* buffer = cast(CharType*) malloc((len + 1) * CharType.sizeof);
670         buffer[0..len] = s[0..len];
671         buffer[len] = '\0';
672         storage = buffer;
673         wasAllocated = true;
674     }
675 
676     ~this()
677     {
678         if (wasAllocated)
679             free(cast(void*)storage);
680     }
681 
682     @disable this(this);
683 
684 private:
685     bool wasAllocated = false;
686 }
687 
688 
689 //
690 // Launch browser, replaces std.process.browse
691 //
692 
693 void browseNoGC(string url) nothrow @nogc
694 {
695     version(Windows)
696     {
697         import core.sys.windows.winuser;
698         import core.sys.windows.shellapi;
699         ShellExecuteA(null, CString("open").storage, CString(url).storage, null, null, SW_SHOWNORMAL);
700     }
701 
702     version(OSX)
703     {
704         import core.sys.posix.unistd;
705         const(char)*[5] args;
706 
707         auto curl = CString(url).storage;
708         const(char)* browser = getenv("BROWSER");
709         if (browser)
710         {
711             browser = strdup(browser);
712             args[0] = browser;
713             args[1] = curl;
714             args[2] = null;
715         }
716         else
717         {
718             args[0] = "open".ptr;
719             args[1] = curl;
720             args[2] = null;
721         }
722 
723         auto childpid = core.sys.posix.unistd.fork();
724         if (childpid == 0)
725         {
726             core.sys.posix.unistd.execvp(args[0], cast(char**)args.ptr);
727             return;
728         }
729         if (browser)
730             free(cast(void*)browser);
731     }
732 }
733 
734 
735 
736 //
737 // GRAIL SORT IMPLEMENTATION BELOW
738 //
739 // The MIT License (MIT)
740 // 
741 // Copyright (c) 2013 Andrey Astrelin
742 // 
743 // Permission is hereby granted, free of charge, to any person obtaining a copy of
744 // this software and associated documentation files (the "Software"), to deal in
745 // the Software without restriction, including without limitation the rights to
746 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
747 // the Software, and to permit persons to whom the Software is furnished to do so,
748 // subject to the following conditions:
749 // 
750 // The above copyright notice and this permission notice shall be included in all
751 // copies or substantial portions of the Software.
752 // 
753 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
754 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
755 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
756 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
757 // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
758 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
759 
760 private:
761 
762 void grail_swap1(T)(T *a,T *b){
763     T c=*a;
764     *a=*b;
765     *b=c;
766 }
767 void grail_swapN(T)(T *a,T *b,int n){
768     while(n--) grail_swap1(a++,b++);
769 }
770 void grail_rotate(T)(T *a,int l1,int l2){
771     while(l1 && l2){
772         if(l1<=l2){
773             grail_swapN(a,a+l1,l1);
774             a+=l1; l2-=l1;
775         } else{
776             grail_swapN(a+(l1-l2),a+l1,l2);
777             l1-=l2;
778         }
779     }
780 }
781 
782 int grail_BinSearchLeft(T)(T *arr,int len,T *key, nogcComparisonFunction!T comparison){
783     int a=-1,b=len,c;
784     while(a<b-1){
785         c=a+((b-a)>>1);
786         if(comparison(arr[c],*key)>=0) b=c;
787         else a=c;
788     }
789     return b;
790 }
791 int grail_BinSearchRight(T)(T *arr,int len,T *key, nogcComparisonFunction!T comparison){
792     int a=-1,b=len,c;
793     while(a<b-1){
794         c=a+((b-a)>>1);
795         if(comparison(arr[c],*key)>0) b=c;
796         else a=c;
797     }
798     return b;
799 }
800 
801 // cost: 2*len+nk^2/2
802 int grail_FindKeys(T)(T *arr,int len,int nkeys, nogcComparisonFunction!T comparison){
803     int h=1,h0=0;  // first key is always here
804     int u=1,r;
805     while(u<len && h<nkeys){
806         r=grail_BinSearchLeft!T(arr+h0,h,arr+u, comparison);
807         if(r==h || comparison(arr[u],arr[h0+r])!=0){
808             grail_rotate(arr+h0,h,u-(h0+h));
809             h0=u-h;
810             grail_rotate(arr+(h0+r),h-r,1);
811             h++;
812         }
813         u++;
814     }
815     grail_rotate(arr,h0,h);
816     return h;
817 }
818 
819 // cost: min(L1,L2)^2+max(L1,L2)
820 void grail_MergeWithoutBuffer(T)(T *arr,int len1,int len2, nogcComparisonFunction!T comparison){
821     int h;
822     if(len1<len2){
823         while(len1){
824             h=grail_BinSearchLeft!T(arr+len1,len2,arr, comparison);
825             if(h!=0){
826                 grail_rotate(arr,len1,h);
827                 arr+=h;
828                 len2-=h;
829             }
830             if(len2==0) break;
831             do{
832                 arr++; len1--;
833             } while(len1 && comparison(*arr,arr[len1])<=0);
834         }
835     } else{
836         while(len2){
837             h=grail_BinSearchRight!T(arr,len1,arr+(len1+len2-1), comparison);
838             if(h!=len1){
839                 grail_rotate(arr+h,len1-h,len2);
840                 len1=h;
841             }
842             if(len1==0) break;
843             do{
844                 len2--;
845             } while(len2 && comparison(arr[len1-1],arr[len1+len2-1])<=0);
846         }
847     }
848 }
849 
850 // arr[M..-1] - buffer, arr[0,L1-1]++arr[L1,L1+L2-1] -> arr[M,M+L1+L2-1]
851 void grail_MergeLeft(T)(T *arr,int L1,int L2,int M, nogcComparisonFunction!T comparison){
852     int p0=0,p1=L1; L2+=L1;
853     while(p1<L2){
854         if(p0==L1 || comparison(arr[p0],arr[p1])>0){
855             grail_swap1(arr+(M++),arr+(p1++));
856         } else{
857             grail_swap1(arr+(M++),arr+(p0++));
858         }
859     }
860     if(M!=p0) grail_swapN(arr+M,arr+p0,L1-p0);
861 }
862 void grail_MergeRight(T)(T *arr,int L1,int L2,int M, nogcComparisonFunction!T comparison){
863     int p0=L1+L2+M-1,p2=L1+L2-1,p1=L1-1;
864 
865     while(p1>=0){
866         if(p2<L1 || comparison(arr[p1],arr[p2])>0){
867             grail_swap1(arr+(p0--),arr+(p1--));
868         } else{
869             grail_swap1(arr+(p0--),arr+(p2--));
870         }
871     }
872     if(p2!=p0) while(p2>=L1) grail_swap1(arr+(p0--),arr+(p2--));
873 }
874 
875 void grail_SmartMergeWithBuffer(T)(T *arr,int *alen1,int *atype,int len2,int lkeys, nogcComparisonFunction!T comparison){
876     int p0=-lkeys,p1=0,p2=*alen1,q1=p2,q2=p2+len2;
877     int ftype=1-*atype;  // 1 if inverted
878     while(p1<q1 && p2<q2){
879         if(comparison(arr[p1],arr[p2])-ftype<0) grail_swap1(arr+(p0++),arr+(p1++));
880         else grail_swap1(arr+(p0++),arr+(p2++));
881     }
882     if(p1<q1){
883         *alen1=q1-p1;
884         while(p1<q1) grail_swap1(arr+(--q1),arr+(--q2));
885     } else{
886         *alen1=q2-p2;
887         *atype=ftype;
888     }
889 }
890 void grail_SmartMergeWithoutBuffer(T)(T *arr,int *alen1,int *atype,int _len2, nogcComparisonFunction!T comparison){
891     int len1,len2,ftype,h;
892     
893     if(!_len2) return;
894     len1=*alen1;
895     len2=_len2;
896     ftype=1-*atype;
897     if(len1 && comparison(arr[len1-1],arr[len1])-ftype>=0){
898         while(len1){
899             h=ftype ? grail_BinSearchLeft!T(arr+len1,len2,arr, comparison) : grail_BinSearchRight!T(arr+len1,len2,arr, comparison);
900             if(h!=0){
901                 grail_rotate(arr,len1,h);
902                 arr+=h;
903                 len2-=h;
904             }
905             if(len2==0){
906                 *alen1=len1;
907                 return;
908             }
909             do{
910                 arr++; len1--;
911             } while(len1 && comparison(*arr,arr[len1])-ftype<0);
912         }
913     }
914     *alen1=len2; *atype=ftype;
915 }
916 
917 /***** Sort With Extra Buffer *****/
918 
919 // arr[M..-1] - free, arr[0,L1-1]++arr[L1,L1+L2-1] -> arr[M,M+L1+L2-1]
920 void grail_MergeLeftWithXBuf(T)(T *arr,int L1,int L2,int M, nogcComparisonFunction!T comparison){
921     int p0=0,p1=L1; L2+=L1;
922     while(p1<L2){
923         if(p0==L1 || comparison(arr[p0],arr[p1])>0) arr[M++]=arr[p1++];
924         else arr[M++]=arr[p0++];
925     }
926     if(M!=p0) while(p0<L1) arr[M++]=arr[p0++];
927 }
928 
929 void grail_SmartMergeWithXBuf(T)(T *arr,int *alen1,int *atype,int len2,int lkeys, nogcComparisonFunction!T comparison){
930     int p0=-lkeys,p1=0,p2=*alen1,q1=p2,q2=p2+len2;
931     int ftype=1-*atype;  // 1 if inverted
932     while(p1<q1 && p2<q2){
933         if(comparison(arr[p1],arr[p2])-ftype<0) arr[p0++]=arr[p1++];
934         else arr[p0++]=arr[p2++];
935     }
936     if(p1<q1){
937         *alen1=q1-p1;
938         while(p1<q1) arr[--q2]=arr[--q1];
939     } else{
940         *alen1=q2-p2;
941         *atype=ftype;
942     }
943 }
944 
945 // arr - starting array. arr[-lblock..-1] - buffer (if havebuf).
946 // lblock - length of regular blocks. First nblocks are stable sorted by 1st elements and key-coded
947 // keys - arrays of keys, in same order as blocks. key<midkey means stream A
948 // nblock2 are regular blocks from stream A. llast is length of last (irregular) block from stream B, that should go before nblock2 blocks.
949 // llast=0 requires nblock2=0 (no irregular blocks). llast>0, nblock2=0 is possible.
950 void grail_MergeBuffersLeftWithXBuf(T)(T *keys,T *midkey,T *arr,int nblock,int lblock,int nblock2,int llast, nogcComparisonFunction!T comparison){
951     int l,prest,lrest,frest,pidx,cidx,fnext,plast;
952 
953     if(nblock==0){
954         l=nblock2*lblock;
955         grail_MergeLeftWithXBuf!T(arr,l,llast,-lblock, comparison);
956         return;
957     }
958 
959     lrest=lblock;
960     frest=comparison(*keys,*midkey)<0 ? 0 : 1;
961     pidx=lblock;
962     for(cidx=1;cidx<nblock;cidx++,pidx+=lblock){
963         prest=pidx-lrest;
964         fnext=comparison(keys[cidx],*midkey)<0 ? 0 : 1;
965         if(fnext==frest){
966             memcpy(arr+prest-lblock,arr+prest,lrest*T.sizeof);
967             prest=pidx;
968             lrest=lblock;
969         } else{
970             grail_SmartMergeWithXBuf!T(arr+prest,&lrest,&frest,lblock,lblock, comparison);
971         }
972     }
973     prest=pidx-lrest;
974     if(llast){
975         plast=pidx+lblock*nblock2;
976         if(frest){
977             memcpy(arr+prest-lblock,arr+prest,lrest*T.sizeof);
978             prest=pidx;
979             lrest=lblock*nblock2;
980             frest=0;
981         } else{
982             lrest+=lblock*nblock2;
983         }
984         grail_MergeLeftWithXBuf!T(arr+prest,lrest,llast,-lblock, comparison);
985     } else{
986         memcpy(arr+prest-lblock,arr+prest,lrest*T.sizeof);
987     }
988 }
989 
990 /***** End Sort With Extra Buffer *****/
991 
992 // build blocks of length K
993 // input: [-K,-1] elements are buffer
994 // output: first K elements are buffer, blocks 2*K and last subblock sorted
995 void grail_BuildBlocks(T)(T *arr,int L,int K,T *extbuf,int LExtBuf, nogcComparisonFunction!T comparison){
996     int m,u,h,p0,p1,rest,restk,p,kbuf;
997     kbuf=K<LExtBuf ? K : LExtBuf;
998     while(kbuf&(kbuf-1)) kbuf&=kbuf-1;  // max power or 2 - just in case
999 
1000     if(kbuf){
1001         memcpy(extbuf,arr-kbuf,kbuf*T.sizeof);
1002         for(m=1;m<L;m+=2){
1003             u=0;
1004             if(comparison(arr[m-1],arr[m])>0) u=1;
1005             arr[m-3]=arr[m-1+u];
1006             arr[m-2]=arr[m-u];
1007         }
1008         if(L%2) arr[L-3]=arr[L-1];
1009         arr-=2;
1010         for(h=2;h<kbuf;h*=2){
1011             p0=0;
1012             p1=L-2*h;
1013             while(p0<=p1){
1014                 grail_MergeLeftWithXBuf!T(arr+p0,h,h,-h, comparison);
1015                 p0+=2*h;
1016             }
1017             rest=L-p0;
1018             if(rest>h){
1019                 grail_MergeLeftWithXBuf!T(arr+p0,h,rest-h,-h, comparison);
1020             } else {
1021                 for(;p0<L;p0++) arr[p0-h]=arr[p0];
1022             }
1023             arr-=h;
1024         }
1025         memcpy(arr+L,extbuf,kbuf*T.sizeof);
1026     } else{
1027         for(m=1;m<L;m+=2){
1028             u=0;
1029             if(comparison(arr[m-1],arr[m])>0) u=1;
1030             grail_swap1(arr+(m-3),arr+(m-1+u));
1031             grail_swap1(arr+(m-2),arr+(m-u));
1032         }
1033         if(L%2) grail_swap1(arr+(L-1),arr+(L-3));
1034         arr-=2;
1035         h=2;
1036     }
1037     for(;h<K;h*=2){
1038         p0=0;
1039         p1=L-2*h;
1040         while(p0<=p1){
1041             grail_MergeLeft!T(arr+p0,h,h,-h, comparison);
1042             p0+=2*h;
1043         }
1044         rest=L-p0;
1045         if(rest>h){
1046             grail_MergeLeft!T(arr+p0,h,rest-h,-h, comparison);
1047         } else grail_rotate(arr+p0-h,h,rest);
1048         arr-=h;
1049     }
1050     restk=L%(2*K);
1051     p=L-restk;
1052     if(restk<=K) grail_rotate(arr+p,restk,K);
1053     else grail_MergeRight!T(arr+p,K,restk-K,K, comparison);
1054     while(p>0){
1055         p-=2*K;
1056         grail_MergeRight!T(arr+p,K,K,K, comparison);
1057     }
1058 }
1059 
1060 // arr - starting array. arr[-lblock..-1] - buffer (if havebuf).
1061 // lblock - length of regular blocks. First nblocks are stable sorted by 1st elements and key-coded
1062 // keys - arrays of keys, in same order as blocks. key<midkey means stream A
1063 // nblock2 are regular blocks from stream A. llast is length of last (irregular) block from stream B, that should go before nblock2 blocks.
1064 // llast=0 requires nblock2=0 (no irregular blocks). llast>0, nblock2=0 is possible.
1065 void grail_MergeBuffersLeft(T)(T *keys,T *midkey,T *arr,int nblock,int lblock,bool havebuf,int nblock2,int llast, nogcComparisonFunction!T comparison){
1066     int l,prest,lrest,frest,pidx,cidx,fnext,plast;
1067     
1068     if(nblock==0){
1069         l=nblock2*lblock;
1070         if(havebuf) grail_MergeLeft!T(arr,l,llast,-lblock, comparison);
1071         else grail_MergeWithoutBuffer!T(arr,l,llast, comparison);
1072         return;
1073     }
1074 
1075     lrest=lblock;
1076     frest=comparison(*keys,*midkey)<0 ? 0 : 1;
1077     pidx=lblock;
1078     for(cidx=1;cidx<nblock;cidx++,pidx+=lblock){
1079         prest=pidx-lrest;
1080         fnext=comparison(keys[cidx],*midkey)<0 ? 0 : 1;
1081         if(fnext==frest){
1082             if(havebuf) grail_swapN(arr+prest-lblock,arr+prest,lrest);
1083             prest=pidx;
1084             lrest=lblock;
1085         } else{
1086             if(havebuf){
1087                 grail_SmartMergeWithBuffer!T(arr+prest,&lrest,&frest,lblock,lblock, comparison);
1088             } else{
1089                 grail_SmartMergeWithoutBuffer!T(arr+prest,&lrest,&frest,lblock, comparison);
1090             }
1091 
1092         }
1093     }
1094     prest=pidx-lrest;
1095     if(llast){
1096         plast=pidx+lblock*nblock2;
1097         if(frest){
1098             if(havebuf) grail_swapN(arr+prest-lblock,arr+prest,lrest);
1099             prest=pidx;
1100             lrest=lblock*nblock2;
1101             frest=0;
1102         } else{
1103             lrest+=lblock*nblock2;
1104         }
1105         if(havebuf) grail_MergeLeft!T(arr+prest,lrest,llast,-lblock, comparison);
1106         else grail_MergeWithoutBuffer!T(arr+prest,lrest,llast, comparison);
1107     } else{
1108         if(havebuf) grail_swapN(arr+prest,arr+(prest-lblock),lrest);
1109     }
1110 }
1111 
1112 void grail_SortIns(T)(T *arr,int len, nogcComparisonFunction!T comparison){
1113     int i,j;
1114     for(i=1;i<len;i++){
1115         for(j=i-1;j>=0 && comparison(arr[j+1],arr[j])<0;j--) grail_swap1(arr+j,arr+(j+1));
1116     }
1117 }
1118 
1119 void grail_LazyStableSort(T)(T *arr,int L, nogcComparisonFunction!T comparison){
1120     int m,u,h,p0,p1,rest;
1121     for(m=1;m<L;m+=2){
1122         u=0;
1123         if(comparison(arr[m-1],arr[m])>0) grail_swap1(arr+(m-1),arr+m);
1124     }
1125     for(h=2;h<L;h*=2){
1126         p0=0;
1127         p1=L-2*h;
1128         while(p0<=p1){
1129             grail_MergeWithoutBuffer!T(arr+p0,h,h, comparison);
1130             p0+=2*h;
1131         }
1132         rest=L-p0;
1133         if(rest>h) grail_MergeWithoutBuffer!T(arr+p0,h,rest-h, comparison);
1134     }
1135 }
1136 
1137 // keys are on the left of arr. Blocks of length LL combined. We'll combine them in pairs
1138 // LL and nkeys are powers of 2. (2*LL/lblock) keys are guarantied
1139 void grail_CombineBlocks(T)(T *keys,T *arr,int len,int LL,int lblock,bool havebuf,T *xbuf, nogcComparisonFunction!T comparison){
1140     int M,nkeys,b,NBlk,midkey,lrest,u,p,v,kc,nbl2,llast;
1141     T *arr1;
1142     
1143     M=len/(2*LL);
1144     lrest=len%(2*LL);
1145     nkeys=(2*LL)/lblock;
1146     if(lrest<=LL){
1147         len-=lrest;
1148         lrest=0;
1149     }
1150     if(xbuf) memcpy(xbuf,arr-lblock,lblock*T.sizeof);
1151     for(b=0;b<=M;b++){
1152         if(b==M && lrest==0) break;
1153         arr1=arr+b*2*LL;
1154         NBlk=(b==M ? lrest : 2*LL)/lblock;
1155         grail_SortIns!T(keys,NBlk+(b==M ? 1 : 0), comparison);
1156         midkey=LL/lblock;
1157         for(u=1;u<NBlk;u++){
1158             p=u-1;
1159             for(v=u;v<NBlk;v++){
1160                 kc=comparison(arr1[p*lblock],arr1[v*lblock]);
1161                 if(kc>0 || (kc==0 && comparison(keys[p],keys[v])>0)) p=v;
1162             }
1163             if(p!=u-1){
1164                 grail_swapN(arr1+(u-1)*lblock,arr1+p*lblock,lblock);
1165                 grail_swap1(keys+(u-1),keys+p);
1166                 if(midkey==u-1 || midkey==p) midkey^=(u-1)^p;
1167             }
1168         }
1169         nbl2=llast=0;
1170         if(b==M) llast=lrest%lblock;
1171         if(llast!=0){
1172             while(nbl2<NBlk && comparison(arr1[NBlk*lblock],arr1[(NBlk-nbl2-1)*lblock])<0) nbl2++;
1173         }
1174         if(xbuf) grail_MergeBuffersLeftWithXBuf!T(keys,keys+midkey,arr1,NBlk-nbl2,lblock,nbl2,llast, comparison);
1175         else grail_MergeBuffersLeft!T(keys,keys+midkey,arr1,NBlk-nbl2,lblock,havebuf,nbl2,llast, comparison);
1176     }
1177     if(xbuf){
1178         for(p=len;--p>=0;) arr[p]=arr[p-lblock];
1179         memcpy(arr-lblock,xbuf,lblock*T.sizeof);
1180     }else if(havebuf) while(--len>=0) grail_swap1(arr+len,arr+len-lblock);
1181 }
1182 
1183 
1184 void grail_commonSort(T)(T *arr,int Len,T *extbuf,int LExtBuf, nogcComparisonFunction!T comparison){
1185     int lblock,nkeys,findkeys,ptr,cbuf,lb,nk;
1186     bool havebuf,chavebuf;
1187     long s;
1188     
1189     if(Len<16){
1190         grail_SortIns!T(arr,Len, comparison);
1191         return;
1192     }
1193 
1194     lblock=1;
1195     while(lblock*lblock<Len) lblock*=2;
1196     nkeys=(Len-1)/lblock+1;
1197     findkeys=grail_FindKeys!T(arr,Len,nkeys+lblock, comparison);
1198     havebuf=true;
1199     if(findkeys<nkeys+lblock){
1200         if(findkeys<4){
1201             grail_LazyStableSort!T(arr,Len, comparison);
1202             return;
1203         }
1204         nkeys=lblock;
1205         while(nkeys>findkeys) nkeys/=2;
1206         havebuf=false;
1207         lblock=0;
1208     }
1209     ptr=lblock+nkeys;
1210     cbuf=havebuf ? lblock : nkeys;
1211     if(havebuf) grail_BuildBlocks!T(arr+ptr,Len-ptr,cbuf,extbuf,LExtBuf, comparison);
1212     else grail_BuildBlocks!T(arr+ptr,Len-ptr,cbuf,null,0, comparison);
1213 
1214     // 2*cbuf are built
1215     while(Len-ptr>(cbuf*=2)){
1216         lb=lblock;
1217         chavebuf=havebuf;
1218         if(!havebuf){
1219             if(nkeys>4 && nkeys/8*nkeys>=cbuf){
1220                 lb=nkeys/2;
1221                 chavebuf=true;
1222             } else{
1223                 nk=1;
1224                 s=cast(long)cbuf*findkeys/2;
1225                 while(nk<nkeys && s!=0){
1226                     nk*=2; s/=8;
1227                 }
1228                 lb=(2*cbuf)/nk;
1229             }
1230         }
1231         grail_CombineBlocks!T(arr,arr+ptr,Len-ptr,cbuf,lb,chavebuf,chavebuf && lb<=LExtBuf ? extbuf : null, comparison);
1232     }
1233     grail_SortIns!T(arr,ptr, comparison);
1234     grail_MergeWithoutBuffer!T(arr,ptr,Len-ptr, comparison);
1235 }
1236 
1237 void GrailSort(T)(T *arr, int Len, nogcComparisonFunction!T comparison){
1238     grail_commonSort!T(arr,Len,null,0, comparison);
1239 }
1240 
1241 void GrailSortWithBuffer(T)(T *arr,int Len, nogcComparisonFunction!T comparison){
1242     T[128] ExtBuf;
1243     grail_commonSort!T(arr,Len,ExtBuf.ptr,128, comparison);
1244 }
1245 
1246 /****** classic MergeInPlace *************/
1247 
1248 void grail_RecMerge(T)(T *A,int L1,int L2, nogcComparisonFunction!T comparison){
1249     int K,k1,k2,m1,m2;
1250     if(L1<3 || L2<3){
1251         grail_MergeWithoutBuffer(A,L1,L2); return;
1252     }
1253     if(L1<L2) K=L1+L2/2;
1254     else K=L1/2;
1255     k1=k2=grail_BinSearchLeft(A,L1,A+K);
1256     if(k2<L1 && comparison(A+k2,A+K)==0) k2=grail_BinSearchRight(A+k1,L1-k1,A+K)+k1;
1257     m1=grail_BinSearchLeft(A+L1,L2,A+K);
1258     m2=m1;
1259     if(m2<L2 && comparison(A+L1+m2,A+K)==0) m2=grail_BinSearchRight(A+L1+m1,L2-m1,A+K)+m1;
1260     if(k1==k2) grail_rotate(A+k2,L1-k2,m2);
1261     else{
1262         grail_rotate(A+k1,L1-k1,m1);
1263         if(m2!=m1) grail_rotate(A+(k2+m1),L1-k2,m2-m1);
1264     }
1265     grail_RecMerge(A+(k2+m2),L1-k2,L2-m2);
1266     grail_RecMerge(A,k1,m1);
1267 }
1268 void RecStableSort(T)(T *arr,int L){
1269     int u,m,h,p0,p1,rest;
1270 
1271     for(m=1;m<L;m+=2){
1272         u=0;
1273         if(comparison(arr+m-1,arr+m)>0) grail_swap1(arr+(m-1),arr+m);
1274     }
1275     for(h=2;h<L;h*=2){
1276         p0=0;
1277         p1=L-2*h;
1278         while(p0<=p1){
1279             grail_RecMerge(arr+p0,h,h);
1280             p0+=2*h;
1281         }
1282         rest=L-p0;
1283         if(rest>h) grail_RecMerge(arr+p0,h,rest-h);
1284     }
1285 }