Skip to content

Commit 519774d

Browse files
author
Vlada Kanivets
committed
add tests for timsort
1 parent 88e65f8 commit 519774d

4 files changed

Lines changed: 1628 additions & 39 deletions

File tree

Lines changed: 104 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#pragma once
2+
#include "kf/stl/new"
13
/*
24
* Taken from https://github.com/swenson/sort
35
* Revision: 05fd77bfec049ce8b7c408c4d3dd2d51ee061a15
@@ -51,14 +53,12 @@ namespace timsort
5153
/* adapted from Hacker's Delight */
5254
inline int clzll(uint64_t x)
5355
{
54-
int n;
55-
5656
if (x == 0)
5757
{
5858
return 64;
5959
}
6060

61-
n = 0;
61+
int n = 0;
6262

6363
if (x <= 0x00000000FFFFFFFFL)
6464
{
@@ -137,14 +137,19 @@ namespace timsort
137137
size_t r = size - 1;
138138
size_t c = r >> 1;
139139

140+
if (dst == nullptr || size == 0)
141+
{
142+
return 0;
143+
}
144+
140145
/* check for out of bounds at the beginning. */
141146
if (cmp(x, dst[0]) < 0)
142147
{
143148
return 0;
144149
}
145-
else if (cmp(x, dst[r]) > 0)
150+
else if (cmp(x, dst[r]) >= 0)
146151
{
147-
return r;
152+
return size;
148153
}
149154

150155
T* cx = &dst[c];
@@ -181,6 +186,11 @@ namespace timsort
181186
template<class T>
182187
inline void binary_insertion_sort_start(T* dst, const size_t start, const size_t size)
183188
{
189+
if (dst == nullptr || size == 0)
190+
{
191+
return;
192+
}
193+
184194
for (size_t i = start; i < size; i++)
185195
{
186196
/* If this entry is already correct, just move along */
@@ -211,6 +221,11 @@ namespace timsort
211221
template<class T>
212222
inline void reverse_elements(T* dst, size_t start, size_t end)
213223
{
224+
if (dst == nullptr)
225+
{
226+
return;
227+
}
228+
214229
while (true)
215230
{
216231
if (start >= end)
@@ -227,6 +242,11 @@ namespace timsort
227242
template<class T>
228243
inline size_t count_run(T* dst, const size_t start, const size_t size)
229244
{
245+
if (dst == nullptr || size == 0)
246+
{
247+
return 0;
248+
}
249+
230250
size_t curr;
231251

232252
if (size - start == 1)
@@ -251,7 +271,7 @@ namespace timsort
251271
/* increasing run */
252272
while (true)
253273
{
254-
if (curr == size - 1)
274+
if (curr == size)
255275
{
256276
break;
257277
}
@@ -271,7 +291,7 @@ namespace timsort
271291
/* decreasing run */
272292
while (true)
273293
{
274-
if (curr == size - 1)
294+
if (curr == size)
275295
{
276296
break;
277297
}
@@ -292,6 +312,11 @@ namespace timsort
292312

293313
inline int check_invariant(TIM_SORT_RUN_T* stack, const int stack_curr)
294314
{
315+
if (stack == nullptr)
316+
{
317+
return -1;
318+
}
319+
295320
if (stack_curr < 2)
296321
{
297322
return 1;
@@ -332,11 +357,24 @@ namespace timsort
332357
template<class T>
333358
inline void tim_sort_resize(TEMP_STORAGE_T<T>* store, const size_t new_size)
334359
{
360+
if (store == nullptr)
361+
{
362+
return;
363+
}
364+
335365
if (store->alloc < new_size)
336366
{
337367
T* tempstore = (T*)malloc(new_size * sizeof(T));
338-
memcpy(tempstore, store->storage, store->alloc);
339-
detail::free(store->storage);
368+
if (tempstore == nullptr)
369+
{
370+
return;
371+
}
372+
373+
if (store->storage != nullptr)
374+
{
375+
memcpy(tempstore, store->storage, store->alloc * sizeof(T));
376+
detail::free(store->storage);
377+
}
340378

341379
store->storage = tempstore;
342380
store->alloc = new_size;
@@ -418,47 +456,49 @@ namespace timsort
418456
}
419457

420458
template<class T>
421-
inline int tim_sort_collapse(T* dst, TIM_SORT_RUN_T* stack, int stack_curr, TEMP_STORAGE_T<T>* store, const size_t size)
459+
inline int tim_sort_collapse(T* dst, TIM_SORT_RUN_T* stack, int stack_size, TEMP_STORAGE_T<T>* store, const size_t size)
422460
{
423461
while (true)
424462
{
425463
/* if the stack only has one thing on it, we are done with the collapse */
426-
if (stack_curr <= 1)
464+
if (stack_size <= 1)
427465
{
428466
break;
429467
}
430468

431469
/* if this is the last merge, just do it */
432-
if ((stack_curr == 2) && (stack[0].length + stack[1].length == size))
470+
if ((stack_size == 2) && (stack[0].length + stack[1].length == size))
433471
{
434-
tim_sort_merge(dst, stack, stack_curr, store);
472+
tim_sort_merge(dst, stack, stack_size, store);
435473
stack[0].length += stack[1].length;
436-
stack_curr--;
474+
stack[1] = { 0, 0 };
475+
stack_size--;
437476
break;
438477
}
439478
/* check if the invariant is off for a stack of 2 elements */
440-
else if ((stack_curr == 2) && (stack[0].length <= stack[1].length))
479+
else if ((stack_size == 2) && (stack[0].length <= stack[1].length))
441480
{
442-
tim_sort_merge(dst, stack, stack_curr, store);
481+
tim_sort_merge(dst, stack, stack_size, store);
443482
stack[0].length += stack[1].length;
444-
stack_curr--;
483+
stack[1] = { 0, 0 };
484+
stack_size--;
445485
break;
446486
}
447-
else if (stack_curr == 2)
487+
else if (stack_size == 2)
448488
{
449489
break;
450490
}
451491

452492
size_t A;
453-
size_t B = stack[stack_curr - 3].length;
454-
size_t C = stack[stack_curr - 2].length;
455-
size_t D = stack[stack_curr - 1].length;
493+
size_t B = stack[stack_size - 3].length;
494+
size_t C = stack[stack_size - 2].length;
495+
size_t D = stack[stack_size - 1].length;
456496

457497
int ABC, BCD, CD;
458498

459-
if (stack_curr >= 4)
499+
if (stack_size >= 4)
460500
{
461-
A = stack[stack_curr - 4].length;
501+
A = stack[stack_size - 4].length;
462502
ABC = (A <= B + C);
463503
}
464504
else
@@ -478,21 +518,23 @@ namespace timsort
478518
/* left merge */
479519
if (BCD && !CD)
480520
{
481-
tim_sort_merge(dst, stack, stack_curr - 1, store);
482-
stack[stack_curr - 3].length += stack[stack_curr - 2].length;
483-
stack[stack_curr - 2] = stack[stack_curr - 1];
484-
stack_curr--;
521+
tim_sort_merge(dst, stack, stack_size - 1, store);
522+
stack[stack_size - 3].length += stack[stack_size - 2].length;
523+
stack[stack_size - 2] = stack[stack_size - 1];
524+
stack[stack_size - 1] = { 0, 0 };
525+
stack_size--;
485526
}
486527
else
487528
{
488529
/* right merge */
489-
tim_sort_merge(dst, stack, stack_curr, store);
490-
stack[stack_curr - 2].length += stack[stack_curr - 1].length;
491-
stack_curr--;
530+
tim_sort_merge(dst, stack, stack_size, store);
531+
stack[stack_size - 2].length += stack[stack_size - 1].length;
532+
stack[stack_size - 1] = { 0, 0 };
533+
stack_size--;
492534
}
493535
}
494536

495-
return stack_curr;
537+
return stack_size;
496538
}
497539

498540
template<class T>
@@ -501,36 +543,49 @@ namespace timsort
501543
TEMP_STORAGE_T<T>* store,
502544
const size_t minrun,
503545
TIM_SORT_RUN_T* run_stack,
504-
size_t* stack_curr,
546+
size_t* stack_size,
505547
size_t* curr)
506548
{
549+
550+
if (dst == nullptr ||
551+
store == nullptr ||
552+
run_stack == nullptr ||
553+
stack_size == nullptr ||
554+
curr == nullptr)
555+
{
556+
return 0;
557+
}
558+
507559
size_t len = count_run(dst, *curr, size);
508560
size_t run = minrun;
509561

562+
/* If there is less than minrun left until the end of the array */
510563
if (run > size - *curr)
511564
{
512565
run = size - *curr;
513566
}
514567

568+
/* If the found sorted run is smaller than minrun,
569+
* we need to extend this segment by sorting the rest of the elements to match the run size */
515570
if (run > len)
516571
{
517572
binary_insertion_sort_start(&dst[*curr], len, run);
518573
len = run;
519574
}
520575

521-
run_stack[*stack_curr].start = *curr;
522-
run_stack[*stack_curr].length = len;
523-
(*stack_curr)++;
576+
run_stack[*stack_size].start = *curr;
577+
run_stack[*stack_size].length = len;
578+
(*stack_size)++;
524579
*curr += len;
525580

526581
if (*curr == size)
527582
{
528583
/* finish up */
529-
while (*stack_curr > 1)
584+
while (*stack_size > 1)
530585
{
531-
tim_sort_merge(dst, run_stack, static_cast<int>(*stack_curr), store);
532-
run_stack[*stack_curr - 2].length += run_stack[*stack_curr - 1].length;
533-
(*stack_curr)--;
586+
tim_sort_merge(dst, run_stack, static_cast<int>(*stack_size), store);
587+
run_stack[*stack_size - 2].length += run_stack[*stack_size - 1].length;
588+
(*stack_size)--;
534589
}
535590

536591
if (store->storage)
@@ -550,6 +605,11 @@ namespace timsort
550605
template<class T>
551606
inline void binary_insertion_sort(T* dst, const size_t size)
552607
{
608+
if (dst == nullptr)
609+
{
610+
return;
611+
}
612+
553613
/* don't bother sorting an array of size <= 1 */
554614
if (size <= 1)
555615
{
@@ -562,6 +622,11 @@ namespace timsort
562622
template<class T>
563623
inline void tim_sort(T* dst, const size_t size)
564624
{
625+
if (dst == nullptr)
626+
{
627+
return;
628+
}
629+
565630
/* don't bother sorting an array of size 1 */
566631
if (size <= 1)
567632
{

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ wdk_add_driver(kf-test WINVER NTDDI_WIN10 STL
5151
VariableSizeStructTest.cpp
5252
ScopeFailureTest.cpp
5353
Base64Test.cpp
54+
TimsortTest.cpp
5455
)
5556

5657
target_link_libraries(kf-test kf::kf kmtest::kmtest)

0 commit comments

Comments
 (0)