158f0484fSRodney W. Grimes.\" Copyright (c) 1990, 1991, 1993 258f0484fSRodney W. Grimes.\" The Regents of the University of California. All rights reserved. 358f0484fSRodney W. Grimes.\" 458f0484fSRodney W. Grimes.\" This code is derived from software contributed to Berkeley by 558f0484fSRodney W. Grimes.\" the American National Standards Committee X3, on Information 658f0484fSRodney W. Grimes.\" Processing Systems. 758f0484fSRodney W. Grimes.\" 858f0484fSRodney W. Grimes.\" Redistribution and use in source and binary forms, with or without 958f0484fSRodney W. Grimes.\" modification, are permitted provided that the following conditions 1058f0484fSRodney W. Grimes.\" are met: 1158f0484fSRodney W. Grimes.\" 1. Redistributions of source code must retain the above copyright 1258f0484fSRodney W. Grimes.\" notice, this list of conditions and the following disclaimer. 1358f0484fSRodney W. Grimes.\" 2. Redistributions in binary form must reproduce the above copyright 1458f0484fSRodney W. Grimes.\" notice, this list of conditions and the following disclaimer in the 1558f0484fSRodney W. Grimes.\" documentation and/or other materials provided with the distribution. 16580b4d18SEd Maste.\" 3. Neither the name of the University nor the names of its contributors 1758f0484fSRodney W. Grimes.\" may be used to endorse or promote products derived from this software 1858f0484fSRodney W. Grimes.\" without specific prior written permission. 1958f0484fSRodney W. Grimes.\" 2058f0484fSRodney W. Grimes.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2158f0484fSRodney W. Grimes.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2258f0484fSRodney W. Grimes.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2358f0484fSRodney W. Grimes.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2458f0484fSRodney W. Grimes.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2558f0484fSRodney W. Grimes.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2658f0484fSRodney W. Grimes.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2758f0484fSRodney W. Grimes.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2858f0484fSRodney W. Grimes.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2958f0484fSRodney W. Grimes.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3058f0484fSRodney W. Grimes.\" SUCH DAMAGE. 3158f0484fSRodney W. Grimes.\" 3258f0484fSRodney W. Grimes.\" @(#)qsort.3 8.1 (Berkeley) 6/4/93 337f3dea24SPeter Wemm.\" $FreeBSD$ 3458f0484fSRodney W. Grimes.\" 358ce3e01eSGiorgos Keramidas.Dd February 20, 2013 3658f0484fSRodney W. Grimes.Dt QSORT 3 3758f0484fSRodney W. Grimes.Os 3858f0484fSRodney W. Grimes.Sh NAME 39*46cdc140SDavid Chisnall.Nm qsort , qsort_b , qsort_r , heapsort , heapsort_b , mergesort, mergesort_b 4058f0484fSRodney W. Grimes.Nd sort functions 4125bb73e0SAlexey Zelkin.Sh LIBRARY 4225bb73e0SAlexey Zelkin.Lb libc 4358f0484fSRodney W. Grimes.Sh SYNOPSIS 448aefde06SJeroen Ruigrok van der Werven.In stdlib.h 4558f0484fSRodney W. Grimes.Ft void 461798791dSRuslan Ermilov.Fo qsort 471798791dSRuslan Ermilov.Fa "void *base" 481798791dSRuslan Ermilov.Fa "size_t nmemb" 491798791dSRuslan Ermilov.Fa "size_t size" 501798791dSRuslan Ermilov.Fa "int \*[lp]*compar\*[rp]\*[lp]const void *, const void *\*[rp]" 511798791dSRuslan Ermilov.Fc 52eca67d51SGarrett Wollman.Ft void 53*46cdc140SDavid Chisnall.Fo qsort_b 54*46cdc140SDavid Chisnall.Fa "void *base" 55*46cdc140SDavid Chisnall.Fa "size_t nmemb" 56*46cdc140SDavid Chisnall.Fa "size_t size" 57*46cdc140SDavid Chisnall.Fa "int \*[lp]^compar\*[rp]\*[lp]const void *, const void *\*[rp]" 58*46cdc140SDavid Chisnall.Fc 59*46cdc140SDavid Chisnall.Ft void 60eca67d51SGarrett Wollman.Fo qsort_r 61eca67d51SGarrett Wollman.Fa "void *base" 62eca67d51SGarrett Wollman.Fa "size_t nmemb" 63eca67d51SGarrett Wollman.Fa "size_t size" 64eca67d51SGarrett Wollman.Fa "void *thunk" 651798791dSRuslan Ermilov.Fa "int \*[lp]*compar\*[rp]\*[lp]void *, const void *, const void *\*[rp]" 66eca67d51SGarrett Wollman.Fc 6758f0484fSRodney W. Grimes.Ft int 681798791dSRuslan Ermilov.Fo heapsort 691798791dSRuslan Ermilov.Fa "void *base" 701798791dSRuslan Ermilov.Fa "size_t nmemb" 711798791dSRuslan Ermilov.Fa "size_t size" 721798791dSRuslan Ermilov.Fa "int \*[lp]*compar\*[rp]\*[lp]const void *, const void *\*[rp]" 731798791dSRuslan Ermilov.Fc 7458f0484fSRodney W. Grimes.Ft int 75*46cdc140SDavid Chisnall.Fo heapsort_b 76*46cdc140SDavid Chisnall.Fa "void *base" 77*46cdc140SDavid Chisnall.Fa "size_t nmemb" 78*46cdc140SDavid Chisnall.Fa "size_t size" 79*46cdc140SDavid Chisnall.Fa "int \*[lp]^compar\*[rp]\*[lp]const void *, const void *\*[rp]" 80*46cdc140SDavid Chisnall.Fc 81*46cdc140SDavid Chisnall.Ft int 821798791dSRuslan Ermilov.Fo mergesort 831798791dSRuslan Ermilov.Fa "void *base" 841798791dSRuslan Ermilov.Fa "size_t nmemb" 851798791dSRuslan Ermilov.Fa "size_t size" 861798791dSRuslan Ermilov.Fa "int \*[lp]*compar\*[rp]\*[lp]const void *, const void *\*[rp]" 871798791dSRuslan Ermilov.Fc 88*46cdc140SDavid Chisnall.Ft int 89*46cdc140SDavid Chisnall.Fo mergesort_b 90*46cdc140SDavid Chisnall.Fa "void *base" 91*46cdc140SDavid Chisnall.Fa "size_t nmemb" 92*46cdc140SDavid Chisnall.Fa "size_t size" 93*46cdc140SDavid Chisnall.Fa "int \*[lp]^compar\*[rp]\*[lp]const void *, const void *\*[rp]" 94*46cdc140SDavid Chisnall.Fc 9558f0484fSRodney W. Grimes.Sh DESCRIPTION 9658f0484fSRodney W. GrimesThe 9758f0484fSRodney W. Grimes.Fn qsort 9858f0484fSRodney W. Grimesfunction is a modified partition-exchange sort, or quicksort. 9958f0484fSRodney W. GrimesThe 10058f0484fSRodney W. Grimes.Fn heapsort 10158f0484fSRodney W. Grimesfunction is a modified selection sort. 10258f0484fSRodney W. GrimesThe 10358f0484fSRodney W. Grimes.Fn mergesort 10458f0484fSRodney W. Grimesfunction is a modified merge sort with exponential search 10558f0484fSRodney W. Grimesintended for sorting data with pre-existing order. 10658f0484fSRodney W. Grimes.Pp 10758f0484fSRodney W. GrimesThe 10858f0484fSRodney W. Grimes.Fn qsort 10958f0484fSRodney W. Grimesand 11058f0484fSRodney W. Grimes.Fn heapsort 11158f0484fSRodney W. Grimesfunctions sort an array of 11258f0484fSRodney W. Grimes.Fa nmemb 11358f0484fSRodney W. Grimesobjects, the initial member of which is pointed to by 11458f0484fSRodney W. Grimes.Fa base . 11558f0484fSRodney W. GrimesThe size of each object is specified by 11658f0484fSRodney W. Grimes.Fa size . 1171fae73b1SRuslan ErmilovThe 1181fae73b1SRuslan Ermilov.Fn mergesort 1191fae73b1SRuslan Ermilovfunction 12058f0484fSRodney W. Grimesbehaves similarly, but 12158f0484fSRodney W. Grimes.Em requires 12258f0484fSRodney W. Grimesthat 12358f0484fSRodney W. Grimes.Fa size 12458f0484fSRodney W. Grimesbe greater than 12558f0484fSRodney W. Grimes.Dq "sizeof(void *) / 2" . 12658f0484fSRodney W. Grimes.Pp 12758f0484fSRodney W. GrimesThe contents of the array 12858f0484fSRodney W. Grimes.Fa base 12958f0484fSRodney W. Grimesare sorted in ascending order according to 13058f0484fSRodney W. Grimesa comparison function pointed to by 13158f0484fSRodney W. Grimes.Fa compar , 13258f0484fSRodney W. Grimeswhich requires two arguments pointing to the objects being 13358f0484fSRodney W. Grimescompared. 13458f0484fSRodney W. Grimes.Pp 13558f0484fSRodney W. GrimesThe comparison function must return an integer less than, equal to, or 13658f0484fSRodney W. Grimesgreater than zero if the first argument is considered to be respectively 13758f0484fSRodney W. Grimesless than, equal to, or greater than the second. 13858f0484fSRodney W. Grimes.Pp 139eca67d51SGarrett WollmanThe 140eca67d51SGarrett Wollman.Fn qsort_r 141eca67d51SGarrett Wollmanfunction behaves identically to 142eca67d51SGarrett Wollman.Fn qsort , 143eca67d51SGarrett Wollmanexcept that it takes an additional argument, 144eca67d51SGarrett Wollman.Fa thunk , 145eca67d51SGarrett Wollmanwhich is passed unchanged as the first argument to function pointed to 146eca67d51SGarrett Wollman.Fa compar . 147eca67d51SGarrett WollmanThis allows the comparison function to access additional 148eca67d51SGarrett Wollmandata without using global variables, and thus 149eca67d51SGarrett Wollman.Fn qsort_r 150eca67d51SGarrett Wollmanis suitable for use in functions which must be reentrant. 151*46cdc140SDavid ChisnallThe 152*46cdc140SDavid Chisnall.Fn qsort_b 153*46cdc140SDavid Chisnallfunction behaves identically to 154*46cdc140SDavid Chisnall.Fn qsort , 155*46cdc140SDavid Chisnallexcept that it takes a block, rather than a function pointer. 156eca67d51SGarrett Wollman.Pp 157eca67d51SGarrett WollmanThe algorithms implemented by 158eca67d51SGarrett Wollman.Fn qsort , 159eca67d51SGarrett Wollman.Fn qsort_r , 16058f0484fSRodney W. Grimesand 16158f0484fSRodney W. Grimes.Fn heapsort 16258f0484fSRodney W. Grimesare 16358f0484fSRodney W. Grimes.Em not 16458f0484fSRodney W. Grimesstable, that is, if two members compare as equal, their order in 16558f0484fSRodney W. Grimesthe sorted array is undefined. 166eca67d51SGarrett WollmanThe 167*46cdc140SDavid Chisnall.Fn heapsort_b 168*46cdc140SDavid Chisnallfunction behaves identically to 169*46cdc140SDavid Chisnall.Fn heapsort , 170*46cdc140SDavid Chisnallexcept that it takes a block, rather than a function pointer. 171*46cdc140SDavid ChisnallThe 17258f0484fSRodney W. Grimes.Fn mergesort 173eca67d51SGarrett Wollmanalgorithm is stable. 174*46cdc140SDavid ChisnallThe 175*46cdc140SDavid Chisnall.Fn mergesort_b 176*46cdc140SDavid Chisnallfunction behaves identically to 177*46cdc140SDavid Chisnall.Fn mergesort , 178*46cdc140SDavid Chisnallexcept that it takes a block, rather than a function pointer. 17958f0484fSRodney W. Grimes.Pp 18058f0484fSRodney W. GrimesThe 18158f0484fSRodney W. Grimes.Fn qsort 182eca67d51SGarrett Wollmanand 183eca67d51SGarrett Wollman.Fn qsort_r 1841a0a9345SRuslan Ermilovfunctions are an implementation of C.A.R. 1851a0a9345SRuslan ErmilovHoare's 1861798791dSRuslan Ermilov.Dq quicksort 1871798791dSRuslan Ermilovalgorithm, 1881a0a9345SRuslan Ermilova variant of partition-exchange sorting; in particular, see 1891a0a9345SRuslan Ermilov.An D.E. Knuth Ns 's 1901a0a9345SRuslan Ermilov.%T "Algorithm Q" . 191eca67d51SGarrett Wollman.Sy Quicksort 19258f0484fSRodney W. Grimestakes O N lg N average time. 19358f0484fSRodney W. GrimesThis implementation uses median selection to avoid its 19458f0484fSRodney W. GrimesO N**2 worst-case behavior. 19558f0484fSRodney W. Grimes.Pp 19658f0484fSRodney W. GrimesThe 19758f0484fSRodney W. Grimes.Fn heapsort 1981a0a9345SRuslan Ermilovfunction is an implementation of 1991a0a9345SRuslan Ermilov.An "J.W.J. William" Ns 's 2001798791dSRuslan Ermilov.Dq heapsort 2011798791dSRuslan Ermilovalgorithm, 2021a0a9345SRuslan Ermilova variant of selection sorting; in particular, see 2031a0a9345SRuslan Ermilov.An "D.E. Knuth" Ns 's 2041a0a9345SRuslan Ermilov.%T "Algorithm H" . 205eca67d51SGarrett Wollman.Sy Heapsort 20658f0484fSRodney W. Grimestakes O N lg N worst-case time. 20758f0484fSRodney W. GrimesIts 20858f0484fSRodney W. Grimes.Em only 20958f0484fSRodney W. Grimesadvantage over 21058f0484fSRodney W. Grimes.Fn qsort 21158f0484fSRodney W. Grimesis that it uses almost no additional memory; while 21258f0484fSRodney W. Grimes.Fn qsort 21358f0484fSRodney W. Grimesdoes not allocate memory, it is implemented using recursion. 21458f0484fSRodney W. Grimes.Pp 21558f0484fSRodney W. GrimesThe function 21658f0484fSRodney W. Grimes.Fn mergesort 21758f0484fSRodney W. Grimesrequires additional memory of size 21858f0484fSRodney W. Grimes.Fa nmemb * 21958f0484fSRodney W. Grimes.Fa size 22058f0484fSRodney W. Grimesbytes; it should be used only when space is not at a premium. 2211fae73b1SRuslan ErmilovThe 2221fae73b1SRuslan Ermilov.Fn mergesort 2231fae73b1SRuslan Ermilovfunction 22458f0484fSRodney W. Grimesis optimized for data with pre-existing order; its worst case 22558f0484fSRodney W. Grimestime is O N lg N; its best case is O N. 22658f0484fSRodney W. Grimes.Pp 22758f0484fSRodney W. GrimesNormally, 22858f0484fSRodney W. Grimes.Fn qsort 22958f0484fSRodney W. Grimesis faster than 23058f0484fSRodney W. Grimes.Fn mergesort 23158f0484fSRodney W. Grimesis faster than 23258f0484fSRodney W. Grimes.Fn heapsort . 23358f0484fSRodney W. GrimesMemory availability and pre-existing order in the data can make this 23458f0484fSRodney W. Grimesuntrue. 23558f0484fSRodney W. Grimes.Sh RETURN VALUES 23658f0484fSRodney W. GrimesThe 23758f0484fSRodney W. Grimes.Fn qsort 238eca67d51SGarrett Wollmanand 239eca67d51SGarrett Wollman.Fn qsort_r 240eca67d51SGarrett Wollmanfunctions 241eca67d51SGarrett Wollmanreturn no value. 24258f0484fSRodney W. Grimes.Pp 243d6002fefSRuslan Ermilov.Rv -std heapsort mergesort 2448ce3e01eSGiorgos Keramidas.Sh EXAMPLES 2458ce3e01eSGiorgos KeramidasA sample program that sorts an array of 2468ce3e01eSGiorgos Keramidas.Vt int 2478ce3e01eSGiorgos Keramidasvalues in place using 2488ce3e01eSGiorgos Keramidas.Fn qsort , 2498ce3e01eSGiorgos Keramidasand then prints the sorted array to standard output is: 2508ce3e01eSGiorgos Keramidas.Bd -literal 2518ce3e01eSGiorgos Keramidas#include <stdio.h> 2528ce3e01eSGiorgos Keramidas#include <stdlib.h> 2538ce3e01eSGiorgos Keramidas 2548ce3e01eSGiorgos Keramidas/* 2558ce3e01eSGiorgos Keramidas * Custom comparison function that can compare 'int' values through pointers 2568ce3e01eSGiorgos Keramidas * passed by qsort(3). 2578ce3e01eSGiorgos Keramidas */ 2588ce3e01eSGiorgos Keramidasstatic int 2598ce3e01eSGiorgos Keramidasint_compare(const void *p1, const void *p2) 2608ce3e01eSGiorgos Keramidas{ 261302318d5SGiorgos Keramidas int left = *(const int *)p1; 262302318d5SGiorgos Keramidas int right = *(const int *)p2; 2638ce3e01eSGiorgos Keramidas 264302318d5SGiorgos Keramidas return ((left > right) - (left < right)); 2658ce3e01eSGiorgos Keramidas} 2668ce3e01eSGiorgos Keramidas 2678ce3e01eSGiorgos Keramidas/* 2688ce3e01eSGiorgos Keramidas * Sort an array of 'int' values and print it to standard output. 2698ce3e01eSGiorgos Keramidas */ 2708ce3e01eSGiorgos Keramidasint 2718ce3e01eSGiorgos Keramidasmain(void) 2728ce3e01eSGiorgos Keramidas{ 2738ce3e01eSGiorgos Keramidas int int_array[] = { 4, 5, 9, 3, 0, 1, 7, 2, 8, 6 }; 274302318d5SGiorgos Keramidas const size_t array_size = sizeof(int_array) / sizeof(int_array[0]); 275302318d5SGiorgos Keramidas size_t k; 2768ce3e01eSGiorgos Keramidas 277302318d5SGiorgos Keramidas qsort(&int_array, array_size, sizeof(int_array[0]), int_compare); 2788ce3e01eSGiorgos Keramidas for (k = 0; k < array_size; k++) 2798ce3e01eSGiorgos Keramidas printf(" %d", int_array[k]); 280302318d5SGiorgos Keramidas puts(""); 281302318d5SGiorgos Keramidas return (EXIT_SUCCESS); 2828ce3e01eSGiorgos Keramidas} 2838ce3e01eSGiorgos Keramidas.Ed 284954349a6SJoel Dahl.Sh COMPATIBILITY 285954349a6SJoel DahlPrevious versions of 286954349a6SJoel Dahl.Fn qsort 287954349a6SJoel Dahldid not permit the comparison routine itself to call 288954349a6SJoel Dahl.Fn qsort 3 . 289954349a6SJoel DahlThis is no longer true. 29058f0484fSRodney W. Grimes.Sh ERRORS 29158f0484fSRodney W. GrimesThe 29258f0484fSRodney W. Grimes.Fn heapsort 2938d2c3c32SRobert Nordierand 2948d2c3c32SRobert Nordier.Fn mergesort 2958d2c3c32SRobert Nordierfunctions succeed unless: 29658f0484fSRodney W. Grimes.Bl -tag -width Er 29758f0484fSRodney W. Grimes.It Bq Er EINVAL 29858f0484fSRodney W. GrimesThe 29958f0484fSRodney W. Grimes.Fa size 30058f0484fSRodney W. Grimesargument is zero, or, 30158f0484fSRodney W. Grimesthe 30258f0484fSRodney W. Grimes.Fa size 30358f0484fSRodney W. Grimesargument to 30458f0484fSRodney W. Grimes.Fn mergesort 30558f0484fSRodney W. Grimesis less than 30658f0484fSRodney W. Grimes.Dq "sizeof(void *) / 2" . 30758f0484fSRodney W. Grimes.It Bq Er ENOMEM 3081fae73b1SRuslan ErmilovThe 3091fae73b1SRuslan Ermilov.Fn heapsort 31058f0484fSRodney W. Grimesor 31158f0484fSRodney W. Grimes.Fn mergesort 3121fae73b1SRuslan Ermilovfunctions 31358f0484fSRodney W. Grimeswere unable to allocate memory. 31458f0484fSRodney W. Grimes.El 31558f0484fSRodney W. Grimes.Sh SEE ALSO 31658f0484fSRodney W. Grimes.Xr sort 1 , 31758f0484fSRodney W. Grimes.Xr radixsort 3 31858f0484fSRodney W. Grimes.Rs 31958f0484fSRodney W. Grimes.%A Hoare, C.A.R. 32058f0484fSRodney W. Grimes.%D 1962 32158f0484fSRodney W. Grimes.%T "Quicksort" 32258f0484fSRodney W. Grimes.%J "The Computer Journal" 32358f0484fSRodney W. Grimes.%V 5:1 32458f0484fSRodney W. Grimes.%P pp. 10-15 32558f0484fSRodney W. Grimes.Re 32658f0484fSRodney W. Grimes.Rs 32758f0484fSRodney W. Grimes.%A Williams, J.W.J 32858f0484fSRodney W. Grimes.%D 1964 32958f0484fSRodney W. Grimes.%T "Heapsort" 33058f0484fSRodney W. Grimes.%J "Communications of the ACM" 33158f0484fSRodney W. Grimes.%V 7:1 33258f0484fSRodney W. Grimes.%P pp. 347-348 33358f0484fSRodney W. Grimes.Re 33458f0484fSRodney W. Grimes.Rs 33558f0484fSRodney W. Grimes.%A Knuth, D.E. 33658f0484fSRodney W. Grimes.%D 1968 33758f0484fSRodney W. Grimes.%B "The Art of Computer Programming" 33858f0484fSRodney W. Grimes.%V Vol. 3 33958f0484fSRodney W. Grimes.%T "Sorting and Searching" 34058f0484fSRodney W. Grimes.%P pp. 114-123, 145-149 34158f0484fSRodney W. Grimes.Re 34258f0484fSRodney W. Grimes.Rs 3435e24a424STim J. Robbins.%A McIlroy, P.M. 34458f0484fSRodney W. Grimes.%T "Optimistic Sorting and Information Theoretic Complexity" 34558f0484fSRodney W. Grimes.%J "Fourth Annual ACM-SIAM Symposium on Discrete Algorithms" 34658f0484fSRodney W. Grimes.%V January 1992 34758f0484fSRodney W. Grimes.Re 34858f0484fSRodney W. Grimes.Rs 34958f0484fSRodney W. Grimes.%A Bentley, J.L. 3505e24a424STim J. Robbins.%A McIlroy, M.D. 35158f0484fSRodney W. Grimes.%T "Engineering a Sort Function" 3525e24a424STim J. Robbins.%J "Software--Practice and Experience" 3535e24a424STim J. Robbins.%V Vol. 23(11) 3545e24a424STim J. Robbins.%P pp. 1249-1265 3555e24a424STim J. Robbins.%D November\ 1993 35658f0484fSRodney W. Grimes.Re 35758f0484fSRodney W. Grimes.Sh STANDARDS 35858f0484fSRodney W. GrimesThe 35958f0484fSRodney W. Grimes.Fn qsort 36058f0484fSRodney W. Grimesfunction 36158f0484fSRodney W. Grimesconforms to 362588a200cSRuslan Ermilov.St -isoC . 363*46cdc140SDavid Chisnall.Sh HISTORY 364*46cdc140SDavid ChisnallThe variants of these functions that take blocks as arguments first appeared in 365*46cdc140SDavid ChisnallMac OS X. 366*46cdc140SDavid ChisnallThis implementation was created by David Chisnall. 367