Skip to content

Commit 6af8bfe

Browse files
committed
Unconditionally use move semantics
1 parent 38ab433 commit 6af8bfe

File tree

2 files changed

+36
-103
lines changed

2 files changed

+36
-103
lines changed

README.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ See also the following links for a detailed description of TimSort:
1010
* http://svn.python.org/projects/python/trunk/Objects/listsort.txt
1111
* http://en.wikipedia.org/wiki/Timsort
1212

13+
This library is compatible with C++11. If you need a C++98 version, you can check the 1.x.y branch of this repository.
14+
1315
According to the benchmarks, it is slower than `std::sort()` on randomized sequences, but faster on partially-sorted
1416
ones. `gfx::timsort` should be usable as a drop-in replacement for `std::stable_sort`, with the difference that it
1517
can't fallback to a O(n log² n) algorithm when there isn't enough extra heap memory available.
@@ -44,12 +46,6 @@ gfx::timsort(vec.begin(), vec.end(), std::less<size_t>(), &len);
4446
4547
## COMPATIBILITY
4648
47-
This library is compatible with C++98, but if you compile it with C++11 or higher it will try to use `std::move()`
48-
when possible instead of copying vaues around, which notably allows to sort collections of move-only types (see
49-
[#9](https://github.com/gfx/cpp-TimSort/pull/9) for details).
50-
51-
You can explicity control the use of `std::move()` by setting the macro `GFX_TIMSORT_USE_STD_MOVE` to `0` or `1`.
52-
5349
The library has been tested with the following compilers:
5450
* GCC 5
5551
* Clang 3.8

include/gfx/timsort.hpp

Lines changed: 34 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <algorithm>
3434
#include <functional>
3535
#include <iterator>
36+
#include <utility>
3637
#include <vector>
3738

3839
// Semantic versioning macros
@@ -57,43 +58,6 @@
5758
# define GFX_TIMSORT_LOG(expr) ((void)0)
5859
#endif
5960

60-
// If GFX_TIMSORT_USE_STD_MOVE is not defined, try to define it as follows:
61-
// - Check standard feature-testing macro
62-
// - Check non-standard feature-testing macro
63-
// - Check C++ standard (disable if < C++11)
64-
// - Check compiler-specific versions known to support move semantics
65-
66-
#ifndef GFX_TIMSORT_USE_STD_MOVE
67-
# if defined(__cpp_rvalue_references)
68-
# define GFX_TIMSORT_USE_STD_MOVE 1
69-
# elif defined(__has_feature)
70-
# if __has_feature(cxx_rvalue_references)
71-
# define GFX_TIMSORT_USE_STD_MOVE 1
72-
# else
73-
# define GFX_TIMSORT_USE_STD_MOVE 0
74-
# endif
75-
# elif !(defined(__cplusplus) && __cplusplus >= 201103L)
76-
# define GFX_TIMSORT_USE_STD_MOVE 0
77-
# elif defined(_MSC_VER) && _MSC_VER >= 1700
78-
# define GFX_TIMSORT_USE_STD_MOVE 1
79-
# elif defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ >= 4 && __GNUC_MINOR__ >= 6))
80-
# define GFX_TIMSORT_USE_STD_MOVE 1
81-
# else
82-
# define GFX_TIMSORT_USE_STD_MOVE 0
83-
# endif
84-
#endif
85-
86-
#if GFX_TIMSORT_USE_STD_MOVE
87-
#include <utility>
88-
#define GFX_TIMSORT_MOVE(x) std::move(x)
89-
#define GFX_TIMSORT_MOVE_RANGE(in1, in2, out) std::move((in1), (in2), (out));
90-
#define GFX_TIMSORT_MOVE_BACKWARD(in1, in2, out) std::move_backward((in1), (in2), (out));
91-
#else
92-
#define GFX_TIMSORT_MOVE(x) (x)
93-
#define GFX_TIMSORT_MOVE_RANGE(in1, in2, out) std::copy((in1), (in2), (out));
94-
#define GFX_TIMSORT_MOVE_BACKWARD(in1, in2, out) std::copy_backward((in1), (in2), (out));
95-
#endif
96-
9761

9862
namespace gfx {
9963

@@ -105,23 +69,11 @@ namespace detail {
10569

10670
// Equivalent to C++20 std::identity
10771
struct identity {
108-
#if GFX_TIMSORT_USE_STD_MOVE
10972
template <typename T>
110-
T&& operator()(T&& value) const
73+
constexpr T&& operator()(T&& value) const noexcept
11174
{
11275
return std::forward<T>(value);
11376
}
114-
#else
115-
template <typename T>
116-
T& operator()(T& value) const {
117-
return value;
118-
}
119-
120-
template <typename T>
121-
T const& operator()(T const& value) const {
122-
return value;
123-
}
124-
#endif
12577
};
12678

12779
// Merge a predicate and a projection function
@@ -130,27 +82,20 @@ struct projection_compare {
13082
projection_compare(Compare comp, Projection proj) : compare(comp), projection(proj) {
13183
}
13284

133-
#if GFX_TIMSORT_USE_STD_MOVE
13485
template <typename T, typename U>
13586
bool operator()(T &&lhs, U &&rhs) {
136-
# ifdef __cpp_lib_invoke
87+
#ifdef __cpp_lib_invoke
13788
return static_cast<bool>(std::invoke(compare,
13889
std::invoke(projection, std::forward<T>(lhs)),
13990
std::invoke(projection, std::forward<U>(rhs))
14091
));
141-
# else
92+
#else
14293
return static_cast<bool>(compare(
14394
projection(std::forward<T>(lhs)),
14495
projection(std::forward<U>(rhs))
14596
));
146-
# endif
147-
}
148-
#else
149-
template <typename T, typename U>
150-
bool operator()(T &lhs, U &rhs) {
151-
return static_cast<bool>(compare(projection(lhs), projection(rhs)));
152-
}
15397
#endif
98+
}
15499

155100
Compare compare;
156101
Projection projection;
@@ -190,13 +135,13 @@ template <typename RandomAccessIterator, typename Compare> class TimSort {
190135
}
191136
for (; start < hi; ++start) {
192137
GFX_TIMSORT_ASSERT(lo <= start);
193-
value_t pivot = GFX_TIMSORT_MOVE(*start);
138+
value_t pivot = std::move(*start);
194139

195140
iter_t const pos = std::upper_bound(lo, start, pivot, compare);
196141
for (iter_t p = start; p > pos; --p) {
197-
*p = GFX_TIMSORT_MOVE(*(p - 1));
142+
*p = std::move(*(p - 1));
198143
}
199-
*pos = GFX_TIMSORT_MOVE(pivot);
144+
*pos = std::move(pivot);
200145
}
201146
}
202147

@@ -420,17 +365,17 @@ template <typename RandomAccessIterator, typename Compare> class TimSort {
420365

421366
static void rotateLeft(iter_t first, iter_t last)
422367
{
423-
value_t tmp = GFX_TIMSORT_MOVE(*first);
424-
iter_t last_1 = GFX_TIMSORT_MOVE_RANGE(first + 1, last, first);
425-
*last_1 = GFX_TIMSORT_MOVE(tmp);
368+
value_t tmp = std::move(*first);
369+
iter_t last_1 = std::move(first + 1, last, first);
370+
*last_1 = std::move(tmp);
426371
}
427372

428373
static void rotateRight(iter_t first, iter_t last)
429374
{
430375
iter_t last_1 = last - 1;
431-
value_t tmp = GFX_TIMSORT_MOVE(*last_1);
432-
GFX_TIMSORT_MOVE_BACKWARD(first, last_1, last);
433-
*first = GFX_TIMSORT_MOVE(tmp);
376+
value_t tmp = std::move(*last_1);
377+
std::move_backward(first, last_1, last);
378+
*first = std::move(tmp);
434379
}
435380

436381

@@ -452,7 +397,7 @@ template <typename RandomAccessIterator, typename Compare> class TimSort {
452397
iter_t cursor2 = base2;
453398
iter_t dest = base1;
454399

455-
*dest = GFX_TIMSORT_MOVE(*cursor2);
400+
*dest = std::move(*cursor2);
456401
++cursor2;
457402
++dest;
458403
--len2;
@@ -469,7 +414,7 @@ template <typename RandomAccessIterator, typename Compare> class TimSort {
469414
GFX_TIMSORT_ASSERT(len2 > 0);
470415

471416
if (compare(*cursor2, *cursor1)) {
472-
*dest = GFX_TIMSORT_MOVE(*cursor2);
417+
*dest = std::move(*cursor2);
473418
++cursor2;
474419
++dest;
475420
++count2;
@@ -478,7 +423,7 @@ template <typename RandomAccessIterator, typename Compare> class TimSort {
478423
goto epilogue;
479424
}
480425
} else {
481-
*dest = GFX_TIMSORT_MOVE(*cursor1);
426+
*dest = std::move(*cursor1);
482427
++cursor1;
483428
++dest;
484429
++count1;
@@ -495,7 +440,7 @@ template <typename RandomAccessIterator, typename Compare> class TimSort {
495440

496441
count1 = gallopRight(*cursor2, cursor1, len1, 0, compare);
497442
if (count1 != 0) {
498-
GFX_TIMSORT_MOVE_BACKWARD(cursor1, cursor1 + count1, dest + count1);
443+
std::move_backward(cursor1, cursor1 + count1, dest + count1);
499444
dest += count1;
500445
cursor1 += count1;
501446
len1 -= count1;
@@ -504,7 +449,7 @@ template <typename RandomAccessIterator, typename Compare> class TimSort {
504449
goto epilogue;
505450
}
506451
}
507-
*dest = GFX_TIMSORT_MOVE(*cursor2);
452+
*dest = std::move(*cursor2);
508453
++cursor2;
509454
++dest;
510455
if (--len2 == 0) {
@@ -513,15 +458,15 @@ template <typename RandomAccessIterator, typename Compare> class TimSort {
513458

514459
count2 = gallopLeft(*cursor1, cursor2, len2, 0, compare);
515460
if (count2 != 0) {
516-
GFX_TIMSORT_MOVE_RANGE(cursor2, cursor2 + count2, dest);
461+
std::move(cursor2, cursor2 + count2, dest);
517462
dest += count2;
518463
cursor2 += count2;
519464
len2 -= count2;
520465
if (len2 == 0) {
521466
goto epilogue;
522467
}
523468
}
524-
*dest = GFX_TIMSORT_MOVE(*cursor1);
469+
*dest = std::move(*cursor1);
525470
++cursor1;
526471
++dest;
527472
if (--len1 == 1) {
@@ -543,13 +488,13 @@ template <typename RandomAccessIterator, typename Compare> class TimSort {
543488

544489
if (len1 == 1) {
545490
GFX_TIMSORT_ASSERT(len2 > 0);
546-
GFX_TIMSORT_MOVE_RANGE(cursor2, cursor2 + len2, dest);
547-
*(dest + len2) = GFX_TIMSORT_MOVE(*cursor1);
491+
std::move(cursor2, cursor2 + len2, dest);
492+
*(dest + len2) = std::move(*cursor1);
548493
} else {
549494
GFX_TIMSORT_ASSERT(len1 != 0 && "Comparison function violates its general contract");
550495
GFX_TIMSORT_ASSERT(len2 == 0);
551496
GFX_TIMSORT_ASSERT(len1 > 1);
552-
GFX_TIMSORT_MOVE_RANGE(cursor1, cursor1 + len1, dest);
497+
std::move(cursor1, cursor1 + len1, dest);
553498
}
554499
}
555500

@@ -571,7 +516,7 @@ template <typename RandomAccessIterator, typename Compare> class TimSort {
571516
tmp_iter_t cursor2 = tmp_.begin() + (len2 - 1);
572517
iter_t dest = base2 + (len2 - 1);
573518

574-
*dest = GFX_TIMSORT_MOVE(*(--cursor1));
519+
*dest = std::move(*(--cursor1));
575520
--dest;
576521
--len1;
577522

@@ -593,7 +538,7 @@ template <typename RandomAccessIterator, typename Compare> class TimSort {
593538
GFX_TIMSORT_ASSERT(len2 > 1);
594539

595540
if (compare(*cursor2, *cursor1)) {
596-
*dest = GFX_TIMSORT_MOVE(*cursor1);
541+
*dest = std::move(*cursor1);
597542
--dest;
598543
++count1;
599544
count2 = 0;
@@ -602,7 +547,7 @@ template <typename RandomAccessIterator, typename Compare> class TimSort {
602547
}
603548
--cursor1;
604549
} else {
605-
*dest = GFX_TIMSORT_MOVE(*cursor2);
550+
*dest = std::move(*cursor2);
606551
--cursor2;
607552
--dest;
608553
++count2;
@@ -624,13 +569,13 @@ template <typename RandomAccessIterator, typename Compare> class TimSort {
624569
dest -= count1;
625570
cursor1 -= count1;
626571
len1 -= count1;
627-
GFX_TIMSORT_MOVE_BACKWARD(cursor1, cursor1 + count1, dest + (1 + count1));
572+
std::move_backward(cursor1, cursor1 + count1, dest + (1 + count1));
628573

629574
if (len1 == 0) {
630575
goto epilogue;
631576
}
632577
}
633-
*dest = GFX_TIMSORT_MOVE(*cursor2);
578+
*dest = std::move(*cursor2);
634579
--cursor2;
635580
--dest;
636581
if (--len2 == 1) {
@@ -642,12 +587,12 @@ template <typename RandomAccessIterator, typename Compare> class TimSort {
642587
dest -= count2;
643588
cursor2 -= count2;
644589
len2 -= count2;
645-
GFX_TIMSORT_MOVE_RANGE(cursor2 + 1, cursor2 + (1 + count2), dest + 1);
590+
std::move(cursor2 + 1, cursor2 + (1 + count2), dest + 1);
646591
if (len2 <= 1) {
647592
goto epilogue;
648593
}
649594
}
650-
*dest = GFX_TIMSORT_MOVE(*(--cursor1));
595+
*dest = std::move(*(--cursor1));
651596
--dest;
652597
if (--len1 == 0) {
653598
goto epilogue;
@@ -669,23 +614,19 @@ template <typename RandomAccessIterator, typename Compare> class TimSort {
669614
if (len2 == 1) {
670615
GFX_TIMSORT_ASSERT(len1 > 0);
671616
dest -= len1;
672-
GFX_TIMSORT_MOVE_BACKWARD(cursor1 - len1, cursor1, dest + (1 + len1));
673-
*dest = GFX_TIMSORT_MOVE(*cursor2);
617+
std::move_backward(cursor1 - len1, cursor1, dest + (1 + len1));
618+
*dest = std::move(*cursor2);
674619
} else {
675620
GFX_TIMSORT_ASSERT(len2 != 0 && "Comparison function violates its general contract");
676621
GFX_TIMSORT_ASSERT(len1 == 0);
677622
GFX_TIMSORT_ASSERT(len2 > 1);
678-
GFX_TIMSORT_MOVE_RANGE(tmp_.begin(), tmp_.begin() + len2, dest - (len2 - 1));
623+
std::move(tmp_.begin(), tmp_.begin() + len2, dest - (len2 - 1));
679624
}
680625
}
681626

682627
void copy_to_tmp(iter_t const begin, diff_t len) {
683-
#if GFX_TIMSORT_USE_STD_MOVE
684628
tmp_.assign(std::make_move_iterator(begin),
685629
std::make_move_iterator(begin + len));
686-
#else
687-
tmp_.assign(begin, begin + len);
688-
#endif
689630
}
690631

691632
public:
@@ -773,9 +714,5 @@ void timsort(RandomAccessIterator const first, RandomAccessIterator const last)
773714
#undef GFX_TIMSORT_ASSERT
774715
#undef GFX_TIMSORT_ENABLE_LOG
775716
#undef GFX_TIMSORT_LOG
776-
#undef GFX_TIMSORT_MOVE
777-
#undef GFX_TIMSORT_MOVE_RANGE
778-
#undef GFX_TIMSORT_MOVE_BACKWARD
779-
#undef GFX_TIMSORT_USE_STD_MOVE
780717

781718
#endif // GFX_TIMSORT_HPP

0 commit comments

Comments
 (0)