Skip to content

Commit 1b37480

Browse files
[libc++] Implement constexpr std::inplace_merge
1 parent b65e094 commit 1b37480

File tree

6 files changed

+201
-82
lines changed

6 files changed

+201
-82
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: 67 additions & 24 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,21 +23,21 @@
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) {}
3028

31-
S(const S& rhs) : i_(rhs.i_) {}
32-
S( S&& rhs) : i_(rhs.i_) { rhs.i_ = -1; }
29+
TEST_CONSTEXPR_CXX26 S(const S& rhs) : i_(rhs.i_) {}
30+
TEST_CONSTEXPR_CXX26 S( S&& rhs) : i_(rhs.i_) { rhs.i_ = -1; }
3331

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; }
32+
TEST_CONSTEXPR_CXX26 S& operator =(const S& rhs) { i_ = rhs.i_; return *this; }
33+
TEST_CONSTEXPR_CXX26 S& operator =( S&& rhs) { i_ = rhs.i_; rhs.i_ = -2; assert(this != &rhs); return *this; }
34+
TEST_CONSTEXPR_CXX26 S& operator =(int i) { i_ = i; return *this; }
3735

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; }
36+
TEST_CONSTEXPR_CXX26 bool operator <(const S& rhs) const { return i_ < rhs.i_; }
37+
TEST_CONSTEXPR_CXX26 bool operator ==(const S& rhs) const { return i_ == rhs.i_; }
38+
TEST_CONSTEXPR_CXX26 bool operator ==(int i) const { return i_ == i; }
4139

42-
void set(int i) { i_ = i; }
40+
TEST_CONSTEXPR_CXX26 void set(int i) { i_ = i; }
4341

4442
int i_;
4543
};
@@ -49,10 +47,9 @@ std::mt19937 randomness;
4947

5048
template <class Iter>
5149
void
52-
test_one(unsigned N, unsigned M)
50+
test_one_randomized(unsigned N, unsigned M)
5351
{
5452
typedef typename std::iterator_traits<Iter>::value_type value_type;
55-
assert(M <= N);
5653
value_type* ia = new value_type[N];
5754
for (unsigned i = 0; i < N; ++i)
5855
ia[i] = i;
@@ -70,7 +67,36 @@ test_one(unsigned N, unsigned M)
7067
}
7168

7269
template <class Iter>
73-
void
70+
TEST_CONSTEXPR_CXX26 void test_one_non_randomized(unsigned N, unsigned M) {
71+
typedef typename std::iterator_traits<Iter>::value_type value_type;
72+
value_type* ia = new value_type[N];
73+
const unsigned long small_prime = 19937;
74+
const unsigned long large_prime = 212987;
75+
unsigned long product_mod = small_prime;
76+
for (unsigned i = 0; i < N; ++i) {
77+
ia[i] = static_cast<int>(product_mod);
78+
product_mod = product_mod * small_prime % large_prime;
79+
}
80+
std::sort(ia, ia + M);
81+
std::sort(ia + M, ia + N);
82+
std::inplace_merge(Iter(ia), Iter(ia + M), Iter(ia + N));
83+
if (N > 0) {
84+
assert(std::is_sorted(ia, ia + N));
85+
}
86+
delete[] ia;
87+
}
88+
89+
template <class Iter>
90+
TEST_CONSTEXPR_CXX26 void test_one(unsigned N, unsigned M) {
91+
assert(M <= N);
92+
if (!TEST_IS_CONSTANT_EVALUATED) {
93+
test_one_randomized<Iter>(N, M);
94+
}
95+
test_one_non_randomized<Iter>(N, M);
96+
}
97+
98+
template <class Iter>
99+
TEST_CONSTEXPR_CXX26 void
74100
test(unsigned N)
75101
{
76102
test_one<Iter>(N, 0);
@@ -81,7 +107,7 @@ test(unsigned N)
81107
}
82108

83109
template <class Iter>
84-
void
110+
TEST_CONSTEXPR_CXX26 void
85111
test()
86112
{
87113
test_one<Iter>(0, 0);
@@ -95,11 +121,19 @@ test()
95121
test_one<Iter>(3, 2);
96122
test_one<Iter>(3, 3);
97123
test<Iter>(4);
98-
test<Iter>(100);
99-
test<Iter>(1000);
124+
#if defined(_LIBCPP_HARDENING_MODE)
125+
if (!TEST_IS_CONSTANT_EVALUATED) // avoid blowing past constant evaluation limit
126+
#endif
127+
{
128+
test<Iter>(100);
129+
}
130+
if (!TEST_IS_CONSTANT_EVALUATED) { // avoid blowing past constant evaluation limit
131+
test<Iter>(1000);
132+
}
100133
}
101134

102-
int main(int, char**)
135+
TEST_CONSTEXPR_CXX26 bool
136+
test()
103137
{
104138
test<bidirectional_iterator<int*> >();
105139
test<random_access_iterator<int*> >();
@@ -111,8 +145,17 @@ int main(int, char**)
111145
test<S*>();
112146
#endif
113147

148+
return true;
149+
}
150+
151+
int main(int, char**) {
152+
test();
153+
#if TEST_STD_VER >= 26
154+
static_assert(test());
155+
#endif // TEST_STD_VER >= 26
156+
114157
#if TEST_STD_VER >= 11 && !defined(TEST_HAS_NO_EXCEPTIONS)
115-
{
158+
if (!TEST_IS_CONSTANT_EVALUATED) {
116159
std::vector<int> vec(150, 3);
117160
getGlobalMemCounter()->throw_after = 0;
118161
std::inplace_merge(vec.begin(), vec.begin() + 100, vec.end());

0 commit comments

Comments
 (0)