| 18 | #ifdef _M_CEE
| 18 | a--;
|
|---|
| 19 | #define __fileDECL __clrcall
| 19 | b--;
|
|---|
| 20 | #else
| 20 | offset++;
|
|---|
| 21 | #define __fileDECL __cdecl
| 21 | }
|
|---|
| 22 | #endif
| 22 | }
|
|---|
| 23 |
| 23 | } |
|---|
| 24 |
| | |
|---|
| 25 |
| | |
|---|
| 26 | #ifdef __USE_CONTEXT
| | |
|---|
| 27 | #define __COMPARE(context, p1, p2) comp(context, p1, p2)
| | |
|---|
| 28 | #define __SHORTSORT(lo, hi, width, comp, context) shortsort_s(lo, hi, width, comp, context);
| | |
|---|
| 29 | #else
| | |
|---|
| 30 | #define __COMPARE(context, p1, p2) comp(p1, p2)
| | |
|---|
| 31 | #define __SHORTSORT(lo, hi, width, comp, context) shortsort(lo, hi, width, comp);
| | |
|---|
| 32 | #endif
| | |
|---|
| 33 |
| | |
|---|
| 34 |
| | |
|---|
| 35 |
| | |
|---|
| 36 | // Swaps the objects of size 'width' that are pointed to by 'a' and 'b'
| | |
|---|
| 37 | #ifndef _QSORT_SWAP_DEFINED
| | |
|---|
| 38 | #define _QSORT_SWAP_DEFINED
| | |
|---|
| 39 | _CRT_SECURITYSAFECRITICAL_ATTRIBUTE
| | |
|---|
| 40 | static void __fileDECL swap(_Inout_updates_(width) char* a, _Inout_updates_(width) char* b, size_t width)
| | |
|---|
| 41 | {
| | |
|---|
| 42 | if (a != b)
| | |
|---|
| 43 | {
| | |
|---|
| 44 | // Do the swap one character at a time to avoid potential alignment
| | |
|---|
| 45 | // problems:
| | |
|---|
| 46 | while (width--)
| | |
|---|
| 47 | {
| | |
|---|
| 48 | char const tmp = *a;
| | |
|---|
| 49 | *a++ = *b;
| | |
|---|
| 50 | *b++ = tmp;
| | |
|---|
| 51 | }
| | |
|---|
| 52 | }
| | |
|---|
| 53 | }
| | |
|---|
| 54 | #endif // _QSORT_SWAP_DEFINED
| | |
|---|
| 55 |
| | |
|---|
| 56 |
| | |
|---|
| 57 |
| | |
|---|
| 58 | // An insertion sort for sorting short arrays. Sorts the sub-array of elements
| | |
|---|
| 59 | // between lo and hi (inclusive). Assumes lo < hi. lo and hi are pointers to
| | |
|---|
| 60 | // the first and last elements in the range to be sorted (note: hi does not
| | |
|---|
| 61 | // point one-past-the-end). The comp is a comparer with the same behavior as
| | |
|---|
| 62 | // specified for qsort.
| | |
|---|
| 63 | _CRT_SECURITYSAFECRITICAL_ATTRIBUTE
| | |
|---|
| 64 | #ifdef __USE_CONTEXT
| | |
|---|
| 65 | static void __fileDECL shortsort_s(
| | |
|---|
| 66 | _Inout_updates_(hi - lo + 1) char* lo,
| | |
|---|
| 67 | _Inout_updates_(width) char* hi,
| | |
|---|
| 68 | size_t const width,
| | |
|---|
| 69 | int (__fileDECL* comp)(void*, void const*, void const*),
| | |
|---|
| 70 | void* const context
| | |
|---|
| 71 | )
| | |
|---|
| 72 | #else // __USE_CONTEXT
| | |
|---|
| 73 | static void __fileDECL shortsort(
| | |
|---|
| 74 | _Inout_updates_(hi - lo + 1) char* lo,
| | |
|---|
| 75 | _Inout_updates_(width) char* hi,
| | |
|---|
| 76 | size_t const width,
| | |
|---|
| 77 | int (__fileDECL* comp)(void const*, void const*)
| | |
|---|
| 78 | )
| | |
|---|
| 79 | #endif // __USE_CONTEXT
| | |
|---|
| 80 | {
| | |
|---|
| 81 | // Note: in assertions below, i and j are alway inside original bound of
| | |
|---|
| 82 | // array to sort.
| | |
|---|
| 83 |
| | |
|---|
| 84 | // Reentrancy diligence: Save (and unset) global-state mode to the stack before making callout to 'compare'
| | |
|---|
| 85 | __crt_state_management::scoped_global_state_reset saved_state;
| | |
|---|
| 86 |
| | |
|---|
| 87 | while (hi > lo)
| | |
|---|
| 88 | {
| | |
|---|
| 89 | // A[i] <= A[j] for i <= j, j > hi
| | |
|---|
| 90 | char* max = lo;
| | |
|---|
| 91 | for (char* p = lo+width; p <= hi; p += width)
| | |
|---|
| 92 | {
| | |
|---|
| 93 | // A[i] <= A[max] for lo <= i < p
| | |
|---|
| 94 | if (__COMPARE(context, p, max) > 0)
| | |
|---|
| 95 | {
| | |
|---|
| 96 | max = p;
| | |
|---|
| 97 | }
| | |
|---|
| 98 | // A[i] <= A[max] for lo <= i <= p
| | |
|---|
| 99 | }
| | |
|---|
| 100 |
| | |
|---|
| 101 | // A[i] <= A[max] for lo <= i <= hi
| | |
|---|
| 102 |
| | |
|---|
| 103 | swap(max, hi, width);
| | |
|---|
| 104 |
| | |
|---|
| 105 | // A[i] <= A[hi] for i <= hi, so A[i] <= A[j] for i <= j, j >= hi
| | |
|---|
| 106 |
| | |
|---|
| 107 | hi -= width;
| | |
|---|
| 108 |
| | |
|---|
| 109 | // A[i] <= A[j] for i <= j, j > hi, loop top condition established
| | |
|---|
| 110 | }
| | |
|---|
| 111 |
| | |
|---|
| 112 | // A[i] <= A[j] for i <= j, j > lo, which implies A[i] <= A[j] for i < j,
| | |
|---|
| 113 | // so array is sorted
| | |
|---|
| 114 | }
| | |
|---|
| 115 |
| | |
|---|
| 116 |
| | |
|---|
| 117 |
| | |
|---|
| 118 | // This macro defines the cutoff between using QuickSort and insertion sort for
| | |
|---|
| 119 | // arrays; arrays with lengths shorter or equal to the below value use insertion
| | |
|---|
| 120 | // sort.
| | |
|---|
| 121 | #define CUTOFF 8 // Testing shows that this is a good value.
| | |
|---|
| 122 |
| | |
|---|
| 123 | // Note: The theoretical number of stack entries required is no more than 1 +
| | |
|---|
| 124 | // log2(num). But we switch to insertion sort for CUTOFF elements or less, so
| | |
|---|
| 125 | // we really only need 1 + log2(num) - log(CUTOFF) stack entries. For a CUTOFF
| | |
|---|
| 126 | // of 8, that means we need no more than 30 stack entries for 32-bit platforms
| | |
|---|
| 127 | // and 62 for 64-bit platforms.
| | |
|---|
| 128 | #define STKSIZ (8 * sizeof(void*) - 2)
| | |
|---|
| 129 |
| | |
|---|
| 130 |
| | |
|---|
| 131 |
| | |
|---|
| 132 | // QuickSort function for sorting arrays. The array is sorted in place.
| | |
|---|
| 133 | // Parameters:
| | |
|---|
| 134 | // * base: Pointer to the initial element of the array
| | |
|---|
| 135 | // * num: Number of elements in the array
| | |
|---|
| 136 | // * width: Width of each element in the array, in bytes
| | |
|---|
| 137 | // * comp: Pointer to a function returning analog of strcmp for strings, but
| | |
|---|
| 138 | // supplied by the caller for comparing the array elements. It
| | |
|---|
| 139 | // accepts two pointers to elements; returns negative if 1 < 2;
| | |
|---|
| 140 | // zero if 1 == 2, and positive if 1 > 2.
| | |
|---|
| 141 | #ifndef _M_CEE
| | |
|---|
| 142 | extern "C"
| | |
|---|
| 143 | #endif
| | |
|---|
| 144 | _CRT_SECURITYSAFECRITICAL_ATTRIBUTE
| | |
|---|
| 145 | #ifdef __USE_CONTEXT
| | |
|---|
| 146 | void __fileDECL qsort_s(
| | |
|---|
| 147 | void* const base,
| | |
|---|
| 148 | size_t const num,
| | |
|---|
| 149 | size_t const width,
| | |
|---|
| 150 | int (__fileDECL* const comp)(void*, void const*, void const*),
| | |
|---|
| 151 | void* const context
| | |
|---|
| 152 | )
| | |
|---|
| 153 | #else // __USE_CONTEXT
| | |
|---|
| 154 | void __fileDECL qsort(
| | |
|---|
| 155 | void* const base,
| | |
|---|
| 156 | size_t const num,
| | |
|---|
| 157 | size_t const width,
| | |
|---|
| 158 | int (__fileDECL* const comp)(void const*, void const*)
| | |
|---|
| 159 | )
| | |
|---|
| 160 | #endif // __USE_CONTEXT
| | |
|---|
| 161 | {
| | |
|---|
| 162 | _VALIDATE_RETURN_VOID(base != nullptr || num == 0, EINVAL);
| | |
|---|
| 163 | _VALIDATE_RETURN_VOID(width > 0, EINVAL);
| | |
|---|
| 164 | _VALIDATE_RETURN_VOID(comp != nullptr, EINVAL);
| | |
|---|
| 165 |
| | |
|---|
| 166 | // A stack for saving the sub-arrays yet to be processed:
| | |
|---|
| 167 | char* lostk[STKSIZ];
| | |
|---|
| 168 | char* histk[STKSIZ];
| | |
|---|
| 169 | int stkptr = 0;
| | |
|---|
| 170 |
| | |
|---|
| 171 | if (num < 2)
| | |
|---|
| 172 | return; // Nothing to do:
| | |
|---|
| 173 |
| | |
|---|
| 174 | // The ends of the sub-array currently being sorted (note that 'hi' points
| | |
|---|
| 175 | // to the last element, not one-past-the-end):
| | |
|---|
| 176 | char* lo = static_cast<char*>(base);
| | |
|---|
| 177 | char* hi = static_cast<char*>(base) + width * (num-1);
| | |
|---|
| 178 |
| | |
|---|
| 179 | // This entry point is for pseudo-recursion calling: setting
| | |
|---|
| 180 | // lo and hi and jumping to here is like recursion, but stkptr is
| | |
|---|
| 181 | // preserved, locals aren't, so we preserve stuff on the stack.
| | |
|---|
| 182 | recurse:
| | |
|---|
| 183 |
| | |
|---|
| 184 | // The number of elements in the sub-array currently being sorted:
| | |
|---|
| 185 | size_t const size = (hi - lo) / width + 1;
| | |
|---|
| 186 |
| | |
|---|
| 187 | // Below a certain size, it is faster to use a O(n^2) sorting method:
| | |
|---|
| 188 | if (size <= CUTOFF)
| | |
|---|
| 189 | {
| | |
|---|
| 190 | __SHORTSORT(lo, hi, width, comp, context);
| | |
|---|
| 191 | }
| | |
|---|
| 192 | else
| | |
|---|
| 193 | {
| | |
|---|
| 194 | // First we pick a partitioning element. The efficiency of the
| | |
|---|
| 195 | // algorithm demands that we find one that is approximately the median
| | |
|---|
| 196 | // of the values, but also that we select one fast. We choose the
| | |
|---|
| 197 | // median of the first, middle, and last elements, to avoid bad
| | |
|---|
| 198 | // performance in the face of already sorted data, or data that is made
| | |
|---|
| 199 | // up of multiple sorted runs appended together. Testing shows that a
| | |
|---|
| 200 | // median-of-three algorithm provides better performance than simply
| | |
|---|
| 201 | // picking the middle element for the latter case.
| | |
|---|
| 202 |
| | |
|---|
| 203 | // Find the middle element:
| | |
|---|
| 204 | char* mid = lo + (size / 2) * width;
| | |
|---|
| 205 |
| | |
|---|
| 206 | // Sort the first, middle, last elements into order:
| | |
|---|
| 207 | if (__COMPARE(context, lo, mid) > 0)
| | |
|---|
| 208 | swap(lo, mid, width);
| | |
|---|
| 209 |
| | |
|---|
| 210 | if (__COMPARE(context, lo, hi) > 0)
| | |
|---|
| 211 | swap(lo, hi, width);
| | |
|---|
| 212 |
| | |
|---|
| 213 | if (__COMPARE(context, mid, hi) > 0)
| | |
|---|
| 214 | swap(mid, hi, width);
| | |
|---|
| 215 |
| | |
|---|
| 216 | // We now wish to partition the array into three pieces, one consisting
| | |
|---|
| 217 | // of elements <= partition element, one of elements equal to the
| | |
|---|
| 218 | // partition element, and one of elements > than it. This is done
| | |
|---|
| 219 | // below; comments indicate conditions established at every step.
| | |
|---|
| 220 |
| | |
|---|
| 221 | char* loguy = lo;
| | |
|---|
| 222 | char* higuy = hi;
| | |
|---|
| 223 |
| | |
|---|
| 224 | // Note that higuy decreases and loguy increases on every iteration,
| | |
|---|
| 225 | // so loop must terminate.
| | |
|---|
| 226 | for (;;)
| | |
|---|
| 227 | {
| | |
|---|
| 228 | // lo <= loguy < hi, lo < higuy <= hi,
| | |
|---|
| 229 | // A[i] <= A[mid] for lo <= i <= loguy,
| | |
|---|
| 230 | // A[i] > A[mid] for higuy <= i < hi,
| | |
|---|
| 231 | // A[hi] >= A[mid]
| | |
|---|
| 232 |
| | |
|---|
| 233 | // The doubled loop is to avoid calling comp(mid,mid), since some
| | |
|---|
| 234 | // existing comparison funcs don't work when passed the same
| | |
|---|
| 235 | // value for both pointers.
| | |
|---|
| 236 |
| | |
|---|
| 237 | if (mid > loguy)
| | |
|---|
| 238 | {
| | |
|---|
| 239 | do
| | |
|---|
| 240 | {
| | |
|---|
| 241 | loguy += width;
| | |
|---|
| 242 | }
| | |
|---|
| 243 | while (loguy < mid && __COMPARE(context, loguy, mid) <= 0);
| | |
|---|
| 244 | }
| | |
|---|
| 245 | if (mid <= loguy)
| | |
|---|
| 246 | {
| | |
|---|
| 247 | do
| | |
|---|
| 248 | {
| | |
|---|
| 249 | loguy += width;
| | |
|---|
| 250 | }
| | |
|---|
| 251 | while (loguy <= hi && __COMPARE(context, loguy, mid) <= 0);
| | |
|---|
| 252 | }
| | |
|---|
| 253 |
| | |
|---|
| 254 | // lo < loguy <= hi+1, A[i] <= A[mid] for lo <= i < loguy,
| | |
|---|
| 255 | // either loguy > hi or A[loguy] > A[mid]
| | |
|---|
| 256 |
| | |
|---|
| 257 | do
| | |
|---|
| 258 | {
| | |
|---|
| 259 | higuy -= width;
| | |
|---|
| 260 | }
| | |
|---|
| 261 | while (higuy > mid && __COMPARE(context, higuy, mid) > 0);
| | |
|---|
| 262 |
| | |
|---|
| 263 | // lo <= higuy < hi, A[i] > A[mid] for higuy < i < hi,
| | |
|---|
| 264 | // either higuy == lo or A[higuy] <= A[mid]
| | |
|---|
| 265 |
| | |
|---|
| 266 | if (higuy < loguy)
| | |
|---|
| 267 | break;
| | |
|---|
| 268 |
| | |
|---|
| 269 | // if loguy > hi or higuy == lo, then we would have exited, so
| | |
|---|
| 270 | // A[loguy] > A[mid], A[higuy] <= A[mid],
| | |
|---|
| 271 | // loguy <= hi, higuy > lo
| | |
|---|
| 272 |
| | |
|---|
| 273 | swap(loguy, higuy, width);
| | |
|---|
| 274 |
| | |
|---|
| 275 | // If the partition element was moved, follow it. Only need
| | |
|---|
| 276 | // to check for mid == higuy, since before the swap,
| | |
|---|
| 277 | // A[loguy] > A[mid] implies loguy != mid.
| | |
|---|
| 278 |
| | |
|---|
| 279 | if (mid == higuy)
| | |
|---|
| 280 | mid = loguy;
| | |
|---|
| 281 |
| | |
|---|
| 282 | // A[loguy] <= A[mid], A[higuy] > A[mid]; so condition at top
| | |
|---|
| 283 | // of loop is re-established
| | |
|---|
| 284 | }
| | |
|---|
| 285 |
| | |
|---|
| 286 | // A[i] <= A[mid] for lo <= i < loguy,
| | |
|---|
| 287 | // A[i] > A[mid] for higuy < i < hi,
| | |
|---|
| 288 | // A[hi] >= A[mid]
| | |
|---|
| 289 | // higuy < loguy
| | |
|---|
| 290 | // implying:
| | |
|---|
| 291 | // higuy == loguy-1
| | |
|---|
| 292 | // or higuy == hi - 1, loguy == hi + 1, A[hi] == A[mid]
| | |
|---|
| 293 |
| | |
|---|
| 294 | // Find adjacent elements equal to the partition element. The
| | |
|---|
| 295 | // doubled loop is to avoid calling comp(mid,mid), since some
| | |
|---|
| 296 | // existing comparison funcs don't work when passed the same value
| | |
|---|
| 297 | // for both pointers.
| | |
|---|
| 298 |
| | |
|---|
| 299 | higuy += width;
| | |
|---|
| 300 | if (mid < higuy)
| | |
|---|
| 301 | {
| | |
|---|
| 302 | do
| | |
|---|
| 303 | {
| | |
|---|
| 304 | higuy -= width;
| | |
|---|
| 305 | }
| | |
|---|
| 306 | while (higuy > mid && __COMPARE(context, higuy, mid) == 0);
| | |
|---|
| 307 | }
| | |
|---|
| 308 | if (mid >= higuy)
| | |
|---|
| 309 | {
| | |
|---|
| 310 | do
| | |
|---|
| 311 | {
| | |
|---|
| 312 | higuy -= width;
| | |
|---|
| 313 | }
| | |
|---|
| 314 | while (higuy > lo && __COMPARE(context, higuy, mid) == 0);
| | |
|---|
| 315 | }
| | |
|---|
| 316 |
| | |
|---|
| 317 | // OK, now we have the following:
| | |
|---|
| 318 | // higuy < loguy
| | |
|---|
| 319 | // lo <= higuy <= hi
| | |
|---|
| 320 | // A[i] <= A[mid] for lo <= i <= higuy
| | |
|---|
| 321 | // A[i] == A[mid] for higuy < i < loguy
| | |
|---|
| 322 | // A[i] > A[mid] for loguy <= i < hi
| | |
|---|
| 323 | // A[hi] >= A[mid] */
| | |
|---|
| 324 |
| | |
|---|
| 325 | // We've finished the partition, now we want to sort the subarrays
| | |
|---|
| 326 | // [lo, higuy] and [loguy, hi].
| | |
|---|
| 327 | // We do the smaller one first to minimize stack usage.
| | |
|---|
| 328 | // We only sort arrays of length 2 or more.
| | |
|---|
| 329 |
| | |
|---|
| 330 | if (higuy - lo >= hi - loguy)
| | |
|---|
| 331 | {
| | |
|---|
| 332 | if (lo < higuy)
| | |
|---|
| 333 | {
| | |
|---|
| 334 | // Save the big recursion for later:
| | |
|---|
| 335 | lostk[stkptr] = lo;
| | |
|---|
| 336 | histk[stkptr] = higuy;
| | |
|---|
| 337 | ++stkptr;
| | |
|---|
| 338 | }
| | |
|---|
| 339 |
| | |
|---|
| 340 | if (loguy < hi)
| | |
|---|
| 341 | {
| | |
|---|
| 342 | // Do the small recursion:
| | |
|---|
| 343 | lo = loguy;
| | |
|---|
| 344 | goto recurse;
| | |
|---|
| 345 | }
| | |
|---|
| 346 | }
| | |
|---|
| 347 | else
| | |
|---|
| 348 | {
| | |
|---|
| 349 | if (loguy < hi)
| | |
|---|
| 350 | {
| | |
|---|
| 351 | // Save the big recursion for later:
| | |
|---|
| 352 | lostk[stkptr] = loguy;
| | |
|---|
| 353 | histk[stkptr] = hi;
| | |
|---|
| 354 | ++stkptr;
| | |
|---|
| 355 | }
| | |
|---|
| 356 |
| | |
|---|
| 357 | if (lo < higuy)
| | |
|---|
| 358 | {
| | |
|---|
| 359 | // Do the small recursion:
| | |
|---|
| 360 | hi = higuy;
| | |
|---|
| 361 | goto recurse;
| | |
|---|
| 362 | }
| | |
|---|
| 363 | }
| | |
|---|
| 364 | }
| | |
|---|
| 365 |
| | |
|---|
| 366 | // We have sorted the array, except for any pending sorts on the stack.
| | |
|---|
| 367 | // Check if there are any, and sort them:
| | |
|---|
| 368 | --stkptr;
| | |
|---|
| 369 | if (stkptr >= 0)
| | |
|---|
| 370 | {
| | |
|---|
| 371 | // Pop sub-array from the stack:
| | |
|---|
| 372 | lo = lostk[stkptr];
| | |
|---|
| 373 | hi = histk[stkptr];
| | |
|---|
| 374 | goto recurse;
| | |
|---|
| 375 | }
| | |
|---|
| 376 | else
| | |
|---|
| 377 | {
| | |
|---|
| 378 | // Otherwise, all sub-arrays have been sorted:
| | |
|---|
| 379 | return;
| | |
|---|
| 380 | }
| | |
|---|
| 381 | }
| | |
|---|
| 382 |
| | |
|---|
| 383 | #undef __COMPARE
| | |
|---|
| 384 | #undef __SHORTSORT | | |
|---|