Skip to content

Commit a0f0daa

Browse files
Tor Didriksendahlerlend
authored andcommitted
Bug#36017204 MTR tests for SELECT fail with ICP, MRR, possibly other flags
Recent versions of Clang have changed their implementation of std::sort(), and our own 'varlen_sort()' function returns wrong results. The result is that some of our .mtr tests using the MRR strategy are failing. The fix is to remove usage of std::sort(), and implement our own sorting algorithm instead. Change-Id: Iec35400503309c026766d5b2f10b1e32e2e7a319
1 parent efdf012 commit a0f0daa

File tree

1 file changed

+33
-41
lines changed

1 file changed

+33
-41
lines changed

include/varlen_sort.h

Lines changed: 33 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -23,64 +23,54 @@
2323
along with this program; if not, write to the Free Software
2424
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
2525

26-
/**
27-
A RandomAccessIterator that splits up a char/uchar array into fixed-length
28-
elements, so that they can be sorted using std::sort. There is also a helper
29-
function varlen_sort() that is an adapter around std::sort for this purpose.
30-
*/
31-
3226
#include <assert.h>
3327

3428
#include "template_utils.h"
3529

3630
#include <algorithm>
37-
#include <memory>
38-
#include <utility>
31+
#include <cstddef>
32+
#include <iterator>
33+
34+
template <class RandomIt, class Compare>
35+
void my_insert_sort(RandomIt first, RandomIt last, Compare comp) {
36+
for (RandomIt high_water_mark = first + 1; high_water_mark < last;
37+
++high_water_mark) {
38+
for (RandomIt cur = high_water_mark; cur > first; --cur) {
39+
RandomIt prev = cur - 1;
40+
if (comp(*prev, *cur)) break;
41+
std::iter_swap(cur - 1, cur);
42+
}
43+
}
44+
}
3945

4046
/*
4147
Conceptually similar to a struct { uchar[N] },
42-
except that most of the time, it just holds a reference to an underlying
48+
except that it just holds a reference to an underlying
4349
array, instead of keeping the memory itself.
4450
*/
4551
struct varlen_element {
4652
varlen_element(unsigned char *ptr_arg, size_t elem_size_arg)
4753
: ptr(ptr_arg), elem_size(elem_size_arg) {}
4854

49-
varlen_element(varlen_element &other) = delete;
50-
51-
/*
52-
In this case, we need to own the memory ourselves. It is really only used
53-
when std::sort wants to do an insertion sort and needs a temporary element.
54-
*/
55-
varlen_element(varlen_element &&other) : elem_size(other.elem_size) {
56-
if (other.mem != nullptr) {
57-
mem = std::move(other.mem);
58-
} else {
59-
mem.reset(new unsigned char[other.elem_size]);
60-
memcpy(mem.get(), other.ptr, elem_size);
61-
}
62-
ptr = mem.get();
63-
}
64-
55+
varlen_element(const varlen_element &other) = delete;
56+
varlen_element(varlen_element &&other) = delete;
6557
varlen_element &operator=(const varlen_element &other) = delete;
66-
varlen_element &operator=(varlen_element &&other) {
67-
assert(elem_size == other.elem_size);
68-
memcpy(ptr, other.ptr, elem_size);
69-
return *this;
70-
}
58+
varlen_element &operator=(varlen_element &&other) = delete;
7159

72-
std::unique_ptr<unsigned char[]> mem;
73-
unsigned char *ptr = nullptr;
74-
size_t elem_size = 0;
60+
unsigned char *ptr{nullptr};
61+
size_t elem_size{0};
7562
};
7663

7764
// ValueSwappable.
78-
static inline void swap(const varlen_element &a, const varlen_element &b) {
65+
inline void swap(const varlen_element &a, const varlen_element &b) {
7966
assert(a.elem_size == b.elem_size);
8067
std::swap_ranges(a.ptr, a.ptr + a.elem_size, b.ptr);
8168
}
8269

83-
// Conceptually similar to a _pointer_ to an uchar[N].
70+
/**
71+
A RandomAccessIterator that splits up a char/uchar array into fixed-length
72+
elements. Conceptually similar to a _pointer_ to an uchar[N].
73+
*/
8474
class varlen_iterator {
8575
public:
8676
varlen_iterator(unsigned char *ptr_arg, size_t elem_size_arg)
@@ -95,7 +85,8 @@ class varlen_iterator {
9585

9686
// EqualityComparable (required for InputIterator).
9787
bool operator==(const varlen_iterator &other) const {
98-
return ptr == other.ptr && elem_size == other.elem_size;
88+
assert(elem_size == other.elem_size);
89+
return ptr == other.ptr;
9990
}
10091

10192
// InputIterator (required for ForwardIterator).
@@ -195,11 +186,12 @@ struct iterator_traits<varlen_iterator> : iterator_traits<varlen_element *> {
195186
*/
196187
template <class T, class Compare>
197188
inline void varlen_sort(T *first, T *last, size_t elem_size, Compare comp) {
198-
std::sort(varlen_iterator(pointer_cast<unsigned char *>(first), elem_size),
199-
varlen_iterator(pointer_cast<unsigned char *>(last), elem_size),
200-
[comp](const varlen_element &a, const varlen_element &b) {
201-
return comp(pointer_cast<T *>(a.ptr), pointer_cast<T *>(b.ptr));
202-
});
189+
my_insert_sort(
190+
varlen_iterator(pointer_cast<unsigned char *>(first), elem_size),
191+
varlen_iterator(pointer_cast<unsigned char *>(last), elem_size),
192+
[comp](const varlen_element &a, const varlen_element &b) {
193+
return comp(pointer_cast<T *>(a.ptr), pointer_cast<T *>(b.ptr));
194+
});
203195
}
204196

205197
#endif // !defined(VARLEN_SORT_INCLUDED)

0 commit comments

Comments
 (0)