extension of bounded_vector unit test and fix of compilation issues

- now bounded_vector::resize(N) works for move-only types
- bounded_vector assertions now print error messages
- fixed move ctor/assignment of bounded_vector
- created a unit test for bounded_vectors of move-only types
master
Francisco 4 years ago committed by Andre Puschmann
parent 2598989f7d
commit 5cce2e4dc7

@ -32,7 +32,7 @@ public:
template <typename std::enable_if<std::is_default_constructible<T>::value, int>::type = 0> template <typename std::enable_if<std::is_default_constructible<T>::value, int>::type = 0>
bounded_vector(size_type N) bounded_vector(size_type N)
{ {
append(N, T()); append(N);
} }
template <typename U, typename std::enable_if<std::is_constructible<T, U>::value, int>::type = 0> template <typename U, typename std::enable_if<std::is_constructible<T, U>::value, int>::type = 0>
bounded_vector(size_type N, const U& init_val) bounded_vector(size_type N, const U& init_val)
@ -42,9 +42,7 @@ public:
bounded_vector(const bounded_vector& other) { append(other.begin(), other.end()); } bounded_vector(const bounded_vector& other) { append(other.begin(), other.end()); }
bounded_vector(bounded_vector&& other) noexcept bounded_vector(bounded_vector&& other) noexcept
{ {
for (size_type i = 0; i < other.size(); ++i) { std::uninitialized_copy(std::make_move_iterator(other.begin()), std::make_move_iterator(other.end()), end());
new (&buffer[i]) T(std::move(other[i]));
}
size_ = other.size(); size_ = other.size();
other.clear(); other.clear();
} }
@ -69,12 +67,12 @@ public:
// move already constructed elements // move already constructed elements
auto it = std::move(other.begin(), other.begin() + min_common_size, begin()); auto it = std::move(other.begin(), other.begin() + min_common_size, begin());
destroy(it, end()); destroy(it, end());
size_ = min_common_size; } else {
clear();
} }
// append the rest // append the rest
for (size_t i = size_; i < other.size(); ++i) { std::uninitialized_copy(
new (&buffer[i]) T(std::move(other[i])); std::make_move_iterator(other.begin() + min_common_size), std::make_move_iterator(other.end()), end());
}
size_ = other.size(); size_ = other.size();
other.clear(); other.clear();
return *this; return *this;
@ -95,12 +93,12 @@ public:
// Element access // Element access
T& operator[](std::size_t i) T& operator[](std::size_t i)
{ {
assert(i < size_); assert(i < size_ && "Array index is out of bounds.");
return reinterpret_cast<T&>(buffer[i]); return reinterpret_cast<T&>(buffer[i]);
} }
const T& operator[](std::size_t i) const const T& operator[](std::size_t i) const
{ {
assert(i < size_); assert(i < size_ && "Array index is out of bounds.");
return reinterpret_cast<const T&>(buffer[i]); return reinterpret_cast<const T&>(buffer[i]);
} }
T& back() { return (*this)[size_ - 1]; } T& back() { return (*this)[size_ - 1]; }
@ -112,9 +110,9 @@ public:
// Iterators // Iterators
iterator begin() { return reinterpret_cast<iterator>(&buffer[0]); } iterator begin() { return reinterpret_cast<iterator>(&buffer[0]); }
iterator end() { return reinterpret_cast<iterator>(&buffer[size_]); } iterator end() { return begin() + size_; }
const_iterator begin() const { return reinterpret_cast<const_iterator>(&buffer[0]); } const_iterator begin() const { return reinterpret_cast<const_iterator>(&buffer[0]); }
const_iterator end() const { return reinterpret_cast<const_iterator>(&buffer[size_]); } const_iterator end() const { return begin() + size_; }
// Capacity // Capacity
bool empty() const { return size_ == 0; } bool empty() const { return size_ == 0; }
@ -170,7 +168,7 @@ public:
} }
void pop_back() void pop_back()
{ {
assert(size_ > 0); assert(size_ > 0 && "Trying to erase element from empty vector.");
back().~T(); back().~T();
size_--; size_--;
} }
@ -189,6 +187,7 @@ public:
{ {
return other.size() == size() and std::equal(begin(), end(), other.begin()); return other.size() == size() and std::equal(begin(), end(), other.begin());
} }
bool operator!=(const bounded_vector& other) const { return not(*this == other); }
private: private:
void destroy(iterator it_start, iterator it_end) void destroy(iterator it_start, iterator it_end)
@ -197,12 +196,6 @@ private:
it->~T(); it->~T();
} }
} }
void construct_(iterator it_start, iterator it_end, const T& value)
{
for (auto it = it_start; it != it_end; ++it) {
new (it) T(value);
}
}
void append(const_iterator it_begin, const_iterator it_end) void append(const_iterator it_begin, const_iterator it_end)
{ {
size_type N = std::distance(it_begin, it_end); size_type N = std::distance(it_begin, it_end);
@ -216,6 +209,14 @@ private:
std::uninitialized_fill_n(end(), N, element); std::uninitialized_fill_n(end(), N, element);
size_ += N; size_ += N;
} }
void append(size_type N)
{
assert(N + size_ <= MAX_N);
for (size_type i = size_; i < size_ + N; ++i) {
new (&buffer[i]) T();
}
size_ += N;
}
std::size_t size_ = 0; std::size_t size_ = 0;
typename std::aligned_storage<sizeof(T), alignof(T)>::type buffer[MAX_N]; typename std::aligned_storage<sizeof(T), alignof(T)>::type buffer[MAX_N];

@ -46,6 +46,12 @@ int C::nof_value_ctor = 0;
int C::nof_move_ctor = 0; int C::nof_move_ctor = 0;
int C::nof_dtor = 0; int C::nof_dtor = 0;
struct moveonly {
moveonly() = default;
moveonly(moveonly&&) noexcept = default;
moveonly& operator=(moveonly&&) noexcept = default;
};
int test_ctor() int test_ctor()
{ {
// TEST: default ctor // TEST: default ctor
@ -113,22 +119,24 @@ int test_obj_add_rem()
a.back() = 4; a.back() = 4;
TESTASSERT(not std::equal(a.begin(), a.end(), a2.begin())); TESTASSERT(not std::equal(a.begin(), a.end(), a2.begin()));
a2 = a; a2 = a;
TESTASSERT(std::equal(a.begin(), a.end(), a2.begin())); TESTASSERT(a == a2);
// TEST: assign // TEST: assign
a.resize(5); a.resize(5);
a2.assign(a.begin(), a.end()); a2.assign(a.begin(), a.end());
TESTASSERT(a2.size() == 5); TESTASSERT(a2.size() == 5);
TESTASSERT(std::equal(a.begin(), a.end(), a2.begin())); TESTASSERT(a == a2);
// TEST: pop_back // TEST: pop_back
int last_nof_dtor = C::nof_dtor; int last_nof_dtor = C::nof_dtor;
a.pop_back(); a.pop_back();
TESTASSERT(a.size() == 4 and last_nof_dtor == C::nof_dtor - 1); TESTASSERT(a.size() == 4 and last_nof_dtor == C::nof_dtor - 1);
TESTASSERT(a != a2);
// TEST: erase // TEST: erase
a.erase(a.begin() + 1); a.erase(a.begin() + 1);
TESTASSERT(std::equal(a.begin(), a.end(), std::initializer_list<C>{1, 3, 3}.begin())); srslte::bounded_vector<C, 10> test = {1, 3, 3};
TESTASSERT(a == test);
// TEST: clear // TEST: clear
last_nof_dtor = C::nof_dtor; last_nof_dtor = C::nof_dtor;
@ -139,6 +147,34 @@ int test_obj_add_rem()
TESTASSERT(a2.size() == 5); TESTASSERT(a2.size() == 5);
a = std::move(a2); a = std::move(a2);
TESTASSERT(a.size() == 5 and a2.empty()); TESTASSERT(a.size() == 5 and a2.empty());
test = {1, 2, 3, 3, 3};
TESTASSERT(a == test);
// TEST: move assignment from empty array
a2.clear();
a = std::move(a2);
TESTASSERT(a.empty() and a2.empty());
return SRSLTE_SUCCESS;
}
int test_move_only_type()
{
bounded_vector<moveonly, 10> a(5);
TESTASSERT(a.size() == 5);
bounded_vector<moveonly, 10> a2(std::move(a));
TESTASSERT(a2.size() == 5 and a.empty());
a2[0] = moveonly();
moveonly c;
a2[1] = std::move(c);
a2.emplace_back();
TESTASSERT(a2.size() == 6);
a2.push_back(moveonly());
TESTASSERT(a2.size() == 7);
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
@ -155,6 +191,7 @@ int main()
{ {
TESTASSERT(srslte::test_ctor() == SRSLTE_SUCCESS); TESTASSERT(srslte::test_ctor() == SRSLTE_SUCCESS);
TESTASSERT(srslte::test_obj_add_rem() == SRSLTE_SUCCESS); TESTASSERT(srslte::test_obj_add_rem() == SRSLTE_SUCCESS);
TESTASSERT(srslte::test_move_only_type() == SRSLTE_SUCCESS);
TESTASSERT(srslte::assert_dtor_consistency() == SRSLTE_SUCCESS); TESTASSERT(srslte::assert_dtor_consistency() == SRSLTE_SUCCESS);
printf("Success\n"); printf("Success\n");
return 0; return 0;

Loading…
Cancel
Save