Skip to content

Commit 210e9f3

Browse files
[libc++] Implement constexpr std::inplace_merge
1 parent 0751418 commit 210e9f3

File tree

6 files changed

+332
-207
lines changed

6 files changed

+332
-207
lines changed

libcxx/include/__algorithm/inplace_merge.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <__functional/identity.h>
2323
#include <__iterator/iterator_traits.h>
2424
#include <__iterator/reverse_iterator.h>
25+
#include <__memory/construct_at.h>
2526
#include <__memory/destruct_n.h>
2627
#include <__memory/unique_ptr.h>
2728
#include <__memory/unique_temporary_buffer.h>
@@ -106,13 +107,13 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __buffered_inplace_merg
106107
value_type* __p = __buff;
107108
for (_BidirectionalIterator __i = __first; __i != __middle;
108109
__d.template __incr<value_type>(), (void)++__i, (void)++__p)
109-
::new ((void*)__p) value_type(_IterOps<_AlgPolicy>::__iter_move(__i));
110+
std::__construct_at(__p, _IterOps<_AlgPolicy>::__iter_move(__i));
110111
std::__half_inplace_merge<_AlgPolicy>(__buff, __p, __middle, __last, __first, __comp);
111112
} else {
112113
value_type* __p = __buff;
113114
for (_BidirectionalIterator __i = __middle; __i != __last;
114115
__d.template __incr<value_type>(), (void)++__i, (void)++__p)
115-
::new ((void*)__p) value_type(_IterOps<_AlgPolicy>::__iter_move(__i));
116+
std::__construct_at(__p, _IterOps<_AlgPolicy>::__iter_move(__i));
116117
typedef reverse_iterator<_BidirectionalIterator> _RBi;
117118
typedef reverse_iterator<value_type*> _Rv;
118119
typedef __invert<_Compare> _Inverted;
@@ -203,7 +204,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void __inplace_merge(
203204
}
204205

205206
template <class _AlgPolicy, class _BidirectionalIterator, class _Compare>
206-
_LIBCPP_HIDE_FROM_ABI void __inplace_merge(
207+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __inplace_merge(
207208
_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last, _Compare&& __comp) {
208209
typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
209210
typedef typename iterator_traits<_BidirectionalIterator>::difference_type difference_type;
@@ -223,14 +224,14 @@ _LIBCPP_HIDE_FROM_ABI void __inplace_merge(
223224
}
224225

225226
template <class _BidirectionalIterator, class _Compare>
226-
inline _LIBCPP_HIDE_FROM_ABI void inplace_merge(
227+
_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR_SINCE_CXX26 void inplace_merge(
227228
_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last, _Compare __comp) {
228229
std::__inplace_merge<_ClassicAlgPolicy>(
229230
std::move(__first), std::move(__middle), std::move(__last), static_cast<__comp_ref_type<_Compare> >(__comp));
230231
}
231232

232233
template <class _BidirectionalIterator>
233-
inline _LIBCPP_HIDE_FROM_ABI void
234+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 inline void
234235
inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last) {
235236
std::inplace_merge(std::move(__first), std::move(__middle), std::move(__last), __less<>());
236237
}

libcxx/include/algorithm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1606,11 +1606,11 @@ template <class InputIterator1, class InputIterator2, class OutputIterator, clas
16061606
InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp);
16071607
16081608
template <class BidirectionalIterator>
1609-
void
1609+
constexpr void // constexpr in C++26
16101610
inplace_merge(BidirectionalIterator first, BidirectionalIterator middle, BidirectionalIterator last);
16111611
16121612
template <class BidirectionalIterator, class Compare>
1613-
void
1613+
constexpr void // constexpr in C++26
16141614
inplace_merge(BidirectionalIterator first, BidirectionalIterator middle, BidirectionalIterator last, Compare comp);
16151615
16161616
template <class InputIterator1, class InputIterator2>

libcxx/test/std/algorithms/alg.sorting/alg.merge/inplace_merge.pass.cpp

Lines changed: 125 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,9 @@
88

99
// <algorithm>
1010

11-
// template<BidirectionalIterator Iter>
12-
// requires ShuffleIterator<Iter>
13-
// && LessThanComparable<Iter::value_type>
14-
// void
15-
// inplace_merge(Iter first, Iter middle, Iter last);
11+
// template<class BidirectionalIterator>
12+
// constexpr void // constexpr since C++26
13+
// inplace_merge(BidirectionalIterator first, BidirectionalIterator middle, BidirectionalIterator last);
1614

1715
#include <algorithm>
1816
#include <cassert>
@@ -25,99 +23,147 @@
2523

2624
#if TEST_STD_VER >= 11
2725
struct S {
28-
S() : i_(0) {}
29-
S(int i) : i_(i) {}
26+
TEST_CONSTEXPR_CXX26 S() : i_(0) {}
27+
TEST_CONSTEXPR_CXX26 S(int i) : i_(i) {}
28+
29+
TEST_CONSTEXPR_CXX26 S(const S& rhs) : i_(rhs.i_) {}
30+
TEST_CONSTEXPR_CXX26 S(S&& rhs) : i_(rhs.i_) { rhs.i_ = -1; }
31+
32+
TEST_CONSTEXPR_CXX26 S& operator=(const S& rhs) {
33+
i_ = rhs.i_;
34+
return *this;
35+
}
36+
TEST_CONSTEXPR_CXX26 S& operator=(S&& rhs) {
37+
i_ = rhs.i_;
38+
rhs.i_ = -2;
39+
assert(this != &rhs);
40+
return *this;
41+
}
42+
TEST_CONSTEXPR_CXX26 S& operator=(int i) {
43+
i_ = i;
44+
return *this;
45+
}
46+
47+
TEST_CONSTEXPR_CXX26 bool operator<(const S& rhs) const { return i_ < rhs.i_; }
48+
TEST_CONSTEXPR_CXX26 bool operator==(const S& rhs) const { return i_ == rhs.i_; }
49+
TEST_CONSTEXPR_CXX26 bool operator==(int i) const { return i_ == i; }
50+
51+
TEST_CONSTEXPR_CXX26 void set(int i) { i_ = i; }
52+
53+
int i_;
54+
};
55+
#endif // TEST_STD_VER >= 11
3056

31-
S(const S& rhs) : i_(rhs.i_) {}
32-
S( S&& rhs) : i_(rhs.i_) { rhs.i_ = -1; }
33-
34-
S& operator =(const S& rhs) { i_ = rhs.i_; return *this; }
35-
S& operator =( S&& rhs) { i_ = rhs.i_; rhs.i_ = -2; assert(this != &rhs); return *this; }
36-
S& operator =(int i) { i_ = i; return *this; }
37-
38-
bool operator <(const S& rhs) const { return i_ < rhs.i_; }
39-
bool operator ==(const S& rhs) const { return i_ == rhs.i_; }
40-
bool operator ==(int i) const { return i_ == i; }
41-
42-
void set(int i) { i_ = i; }
57+
std::mt19937 randomness;
4358

44-
int i_;
45-
};
46-
#endif
59+
template <class Iter>
60+
void test_one_randomized(unsigned N, unsigned M) {
61+
typedef typename std::iterator_traits<Iter>::value_type value_type;
62+
value_type* ia = new value_type[N];
63+
64+
for (unsigned i = 0; i < N; ++i)
65+
ia[i] = i;
66+
std::shuffle(ia, ia + N, randomness);
67+
std::sort(ia, ia + M);
68+
std::sort(ia + M, ia + N);
69+
std::inplace_merge(Iter(ia), Iter(ia + M), Iter(ia + N));
70+
if (N > 0) {
71+
assert(ia[0] == 0);
72+
assert(ia[N - 1] == static_cast<value_type>(N - 1));
73+
assert(std::is_sorted(ia, ia + N));
74+
}
75+
delete[] ia;
76+
}
4777

48-
std::mt19937 randomness;
78+
template <class Iter>
79+
TEST_CONSTEXPR_CXX26 void test_one_non_randomized(unsigned N, unsigned M) {
80+
typedef typename std::iterator_traits<Iter>::value_type value_type;
81+
value_type* ia = new value_type[N];
82+
const unsigned long small_prime = 19937;
83+
const unsigned long large_prime = 212987;
84+
unsigned long product_mod = small_prime;
85+
for (unsigned i = 0; i < N; ++i) {
86+
ia[i] = static_cast<int>(product_mod);
87+
product_mod = product_mod * small_prime % large_prime;
88+
}
89+
std::sort(ia, ia + M);
90+
std::sort(ia + M, ia + N);
91+
std::inplace_merge(Iter(ia), Iter(ia + M), Iter(ia + N));
92+
if (N > 0) {
93+
assert(std::is_sorted(ia, ia + N));
94+
}
95+
delete[] ia;
96+
}
4997

5098
template <class Iter>
51-
void
52-
test_one(unsigned N, unsigned M)
53-
{
54-
typedef typename std::iterator_traits<Iter>::value_type value_type;
55-
assert(M <= N);
56-
value_type* ia = new value_type[N];
57-
for (unsigned i = 0; i < N; ++i)
58-
ia[i] = i;
59-
std::shuffle(ia, ia+N, randomness);
60-
std::sort(ia, ia+M);
61-
std::sort(ia+M, ia+N);
62-
std::inplace_merge(Iter(ia), Iter(ia+M), Iter(ia+N));
63-
if(N > 0)
64-
{
65-
assert(ia[0] == 0);
66-
assert(ia[N-1] == static_cast<value_type>(N-1));
67-
assert(std::is_sorted(ia, ia+N));
68-
}
69-
delete [] ia;
99+
TEST_CONSTEXPR_CXX26 void test_one(unsigned N, unsigned M) {
100+
assert(M <= N);
101+
if (!TEST_IS_CONSTANT_EVALUATED) {
102+
test_one_randomized<Iter>(N, M);
103+
}
104+
test_one_non_randomized<Iter>(N, M);
70105
}
71106

72107
template <class Iter>
73-
void
74-
test(unsigned N)
75-
{
76-
test_one<Iter>(N, 0);
77-
test_one<Iter>(N, N/4);
78-
test_one<Iter>(N, N/2);
79-
test_one<Iter>(N, 3*N/4);
80-
test_one<Iter>(N, N);
108+
TEST_CONSTEXPR_CXX26 void test(unsigned N) {
109+
test_one<Iter>(N, 0);
110+
test_one<Iter>(N, N / 4);
111+
test_one<Iter>(N, N / 2);
112+
test_one<Iter>(N, 3 * N / 4);
113+
test_one<Iter>(N, N);
81114
}
82115

83116
template <class Iter>
84-
void
85-
test()
86-
{
87-
test_one<Iter>(0, 0);
88-
test_one<Iter>(1, 0);
89-
test_one<Iter>(1, 1);
90-
test_one<Iter>(2, 0);
91-
test_one<Iter>(2, 1);
92-
test_one<Iter>(2, 2);
93-
test_one<Iter>(3, 0);
94-
test_one<Iter>(3, 1);
95-
test_one<Iter>(3, 2);
96-
test_one<Iter>(3, 3);
97-
test<Iter>(4);
117+
TEST_CONSTEXPR_CXX26 void test() {
118+
test_one<Iter>(0, 0);
119+
test_one<Iter>(1, 0);
120+
test_one<Iter>(1, 1);
121+
test_one<Iter>(2, 0);
122+
test_one<Iter>(2, 1);
123+
test_one<Iter>(2, 2);
124+
test_one<Iter>(3, 0);
125+
test_one<Iter>(3, 1);
126+
test_one<Iter>(3, 2);
127+
test_one<Iter>(3, 3);
128+
test<Iter>(4);
129+
#if defined(_LIBCPP_HARDENING_MODE)
130+
if (!TEST_IS_CONSTANT_EVALUATED) // avoid blowing past constant evaluation limit
131+
#endif
132+
{
98133
test<Iter>(100);
134+
}
135+
if (!TEST_IS_CONSTANT_EVALUATED) { // avoid blowing past constant evaluation limit
99136
test<Iter>(1000);
137+
}
100138
}
101139

102-
int main(int, char**)
103-
{
104-
test<bidirectional_iterator<int*> >();
105-
test<random_access_iterator<int*> >();
106-
test<int*>();
140+
TEST_CONSTEXPR_CXX26 bool test() {
141+
test<bidirectional_iterator<int*> >();
142+
test<random_access_iterator<int*> >();
143+
test<int*>();
107144

108145
#if TEST_STD_VER >= 11
109-
test<bidirectional_iterator<S*> >();
110-
test<random_access_iterator<S*> >();
111-
test<S*>();
112-
#endif
146+
test<bidirectional_iterator<S*> >();
147+
test<random_access_iterator<S*> >();
148+
test<S*>();
149+
#endif // TEST_STD_VER >= 11
150+
151+
return true;
152+
}
153+
154+
int main(int, char**) {
155+
test();
156+
#if TEST_STD_VER >= 26
157+
static_assert(test());
158+
#endif // TEST_STD_VER >= 26
113159

114160
#if TEST_STD_VER >= 11 && !defined(TEST_HAS_NO_EXCEPTIONS)
115-
{
116-
std::vector<int> vec(150, 3);
117-
getGlobalMemCounter()->throw_after = 0;
118-
std::inplace_merge(vec.begin(), vec.begin() + 100, vec.end());
119-
assert(std::all_of(vec.begin(), vec.end(), [](int i) { return i == 3; }));
120-
}
161+
if (!TEST_IS_CONSTANT_EVALUATED) {
162+
std::vector<int> vec(150, 3);
163+
getGlobalMemCounter()->throw_after = 0;
164+
std::inplace_merge(vec.begin(), vec.begin() + 100, vec.end());
165+
assert(std::all_of(vec.begin(), vec.end(), [](int i) { return i == 3; }));
166+
}
121167
#endif // TEST_STD_VER >= 11 && !defined(TEST_HAS_NO_EXCEPTIONS)
122168

123169
return 0;

0 commit comments

Comments
 (0)