Skip to content

Commit 446426c

Browse files
committed
add tests for [container.reqmts]
1 parent cfbc617 commit 446426c

File tree

2 files changed

+138
-16
lines changed

2 files changed

+138
-16
lines changed

include/beman/inplace_vector/inplace_vector.hpp

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -100,24 +100,24 @@ struct inplace_vector_destruct_base {
100100
// [containers.sequences.inplace.vector.cons], construct/copy/destroy
101101
constexpr inplace_vector_destruct_base() = default;
102102

103-
inplace_vector_destruct_base(
103+
constexpr inplace_vector_destruct_base(
104104
const inplace_vector_destruct_base
105105
&other) noexcept(std::is_nothrow_copy_constructible_v<T>)
106106
: elems(), size_(other.size_) {}
107107

108-
inplace_vector_destruct_base(
108+
constexpr inplace_vector_destruct_base(
109109
const inplace_vector_destruct_base
110110
&&other) noexcept(std::is_nothrow_move_constructible_v<T>)
111-
: elems(), size_(other.size()) {}
111+
: elems(), size_(other.size_) {}
112112

113-
inplace_vector_destruct_base &
113+
constexpr inplace_vector_destruct_base &
114114
operator=(const inplace_vector_destruct_base &other) noexcept(
115115
std::is_nothrow_copy_constructible_v<T> &&
116116
std::is_nothrow_copy_assignable_v<T>) {
117117
size_ = other.size_;
118118
}
119119

120-
inplace_vector_destruct_base &
120+
constexpr inplace_vector_destruct_base &
121121
operator=(const inplace_vector_destruct_base &&other) noexcept(
122122
std::is_nothrow_move_constructible_v<T> &&
123123
std::is_nothrow_move_assignable_v<T>) {
@@ -142,19 +142,18 @@ struct inplace_vector_base : public inplace_vector_destruct_base<T, Capacity> {
142142

143143
// [containers.sequences.inplace.vector.cons], construct/copy/destroy
144144
constexpr inplace_vector_base() = default;
145-
inplace_vector_base(const inplace_vector_base &other) noexcept(
145+
constexpr inplace_vector_base(const inplace_vector_base &other) noexcept(
146146
std::is_nothrow_copy_constructible_v<T>)
147-
: inplace_vector_destruct_base<T, Capacity>(other.size) {
147+
: inplace_vector_destruct_base<T, Capacity>(other.size_) {
148148
std::copy(other.begin(), other.end(), begin());
149149
}
150-
inplace_vector_base(inplace_vector_base &&other) noexcept(
150+
constexpr inplace_vector_base(inplace_vector_base &&other) noexcept(
151151
Capacity == 0 || std::is_nothrow_move_constructible_v<T>)
152152
: inplace_vector_destruct_base<T, Capacity>(other.size_) {
153153
std::copy(other.begin(), other.end(), begin());
154-
std::destroy(other.begin(), other.end());
155-
other.size_ = 0;
156154
}
157-
inplace_vector_base &operator=(const inplace_vector_base &other) noexcept(
155+
constexpr inplace_vector_base &
156+
operator=(const inplace_vector_base &other) noexcept(
158157
std::is_nothrow_copy_constructible_v<T> &&
159158
std::is_nothrow_copy_assignable_v<T>) {
160159
const auto diff = static_cast<std::ptrdiff_t>(other.size() - size());
@@ -175,7 +174,8 @@ struct inplace_vector_base : public inplace_vector_destruct_base<T, Capacity> {
175174
return *this;
176175
}
177176

178-
inplace_vector_base &operator=(inplace_vector_base &&other) noexcept(
177+
constexpr inplace_vector_base &
178+
operator=(inplace_vector_base &&other) noexcept(
179179
Capacity == 0 || (std::is_nothrow_move_constructible_v<T> &&
180180
std::is_nothrow_move_assignable_v<T>)) {
181181
const auto diff = static_cast<std::ptrdiff_t>(other.size() - size());
@@ -185,13 +185,10 @@ struct inplace_vector_base : public inplace_vector_destruct_base<T, Capacity> {
185185
std::destroy(new_end, end());
186186
// other size is grater than size
187187
} else {
188-
std::move(other, other.begin(), other.begin() + size(), begin());
188+
std::move(other.begin(), other.begin() + size(), begin());
189189
std::move(other.begin() + size(), other.end(), end());
190190
}
191191
this->size_ = other.size();
192-
std::destroy(other.begin(), other.end());
193-
// reset size to zero
194-
other.change_size(-static_cast<std::ptrdiff_t>(other.size()));
195192
return *this;
196193
}
197194
constexpr inplace_vector_base(const size_type size)

tests/beman/inplace_vector/constexpr.test.cpp

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include <algorithm>
12
#include <beman/inplace_vector/inplace_vector.hpp>
23
#include <functional>
34
#include <type_traits>
@@ -148,6 +149,130 @@ static_assert(std::invoke([]() {
148149
}),
149150
"Basic mutation");
150151

152+
// [container.reqmts] General container requirements
153+
using X = inplace_vector<int, 5>;
154+
155+
constexpr bool reqmts_default() {
156+
{
157+
X u;
158+
S_ASSERT(u.empty());
159+
}
160+
{
161+
X u = X();
162+
S_ASSERT(u.empty());
163+
}
164+
165+
return true;
166+
}
167+
168+
static_assert(reqmts_default());
169+
170+
constexpr bool reqmts_copy() {
171+
constexpr X exp{1, 2, 3};
172+
173+
X a{1, 2, 3};
174+
175+
{
176+
X u(a);
177+
S_ASSERT(std::ranges::equal(exp, u));
178+
S_ASSERT(std::ranges::equal(exp, a));
179+
}
180+
{
181+
X u = a;
182+
S_ASSERT(std::ranges::equal(exp, u));
183+
S_ASSERT(std::ranges::equal(exp, a));
184+
}
185+
186+
return true;
187+
}
188+
189+
static_assert(reqmts_copy());
190+
191+
constexpr bool reqmts_move() {
192+
/*
193+
* TODO: Need to keep in check with revision
194+
*
195+
* Move semantics
196+
* A moved-from inplace_vector is left in a valid but unspecified state
197+
* (option 3 below) unless T is trivially-copyable, in which case the size of
198+
* the inplace_vector does not change (array semantics, option 2 below). That
199+
* is:
200+
*
201+
* inplace_vector a(10);
202+
* inplace_vector b(std::move(a));
203+
* assert(a.size() == 10); // MAY FAIL
204+
*
205+
* moves a's elements element-wise into b, and afterwards the size of the
206+
* moved-from inplace_vector may have changed.
207+
*
208+
* This prevents code from relying on the size staying the same (and therefore
209+
* being incompatible with changing an inplace_vector type back to vector)
210+
* without incuring the cost of having to clear the inplace_vector.
211+
*
212+
* When T is trivially-copyable, array semantics are used to provide trivial
213+
* move operations.
214+
*/
215+
216+
{
217+
constexpr X exp{1, 2, 3};
218+
X mov_from(exp);
219+
X u(std::move(mov_from));
220+
S_ASSERT(std::ranges::equal(exp, u));
221+
222+
static_assert(std::is_trivially_copyable_v<X::value_type>);
223+
S_ASSERT(mov_from.size() == exp.size());
224+
}
225+
{
226+
// Note(river): for later non-trivial type implementation, verify:
227+
// Effects: All existing elements of a are either move assigned to or
228+
// destroyed.
229+
constexpr X origin{1, 2, 3};
230+
constexpr X exp{1, 2};
231+
232+
X a(origin);
233+
X mov_from(exp);
234+
a = std::move(mov_from);
235+
236+
S_ASSERT(std::ranges::equal(exp, a));
237+
static_assert(std::is_trivially_copyable_v<X::value_type>);
238+
S_ASSERT(mov_from.size() == exp.size());
239+
}
240+
241+
return true;
242+
}
243+
244+
static_assert(reqmts_move());
245+
246+
// destructor implicilty tested
247+
248+
constexpr bool reqmts_itr() {
249+
constexpr X exp{1, 2, 3};
250+
251+
{
252+
X b = exp;
253+
auto beg = b.begin();
254+
auto end = b.end();
255+
end--;
256+
257+
S_ASSERT(*b.begin() == 1);
258+
S_ASSERT(*end == 3);
259+
}
260+
261+
{
262+
X b = exp;
263+
auto beg = b.cbegin();
264+
auto end = b.cend();
265+
end--;
266+
267+
S_ASSERT(*b.begin() == 1);
268+
S_ASSERT(*end == 3);
269+
}
270+
271+
return true;
272+
}
273+
274+
static_assert(reqmts_itr());
275+
151276
int main() {
152277
// compile means pass
153278
}

0 commit comments

Comments
 (0)