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
This commit is contained in:
Francisco 2020-12-03 16:55:43 +00:00 committed by Andre Puschmann
parent 2598989f7d
commit 5cce2e4dc7
2 changed files with 60 additions and 22 deletions

View File

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

View File

@ -46,6 +46,12 @@ int C::nof_value_ctor = 0;
int C::nof_move_ctor = 0;
int C::nof_dtor = 0;
struct moveonly {
moveonly() = default;
moveonly(moveonly&&) noexcept = default;
moveonly& operator=(moveonly&&) noexcept = default;
};
int test_ctor()
{
// TEST: default ctor
@ -113,22 +119,24 @@ int test_obj_add_rem()
a.back() = 4;
TESTASSERT(not std::equal(a.begin(), a.end(), a2.begin()));
a2 = a;
TESTASSERT(std::equal(a.begin(), a.end(), a2.begin()));
TESTASSERT(a == a2);
// TEST: assign
a.resize(5);
a2.assign(a.begin(), a.end());
TESTASSERT(a2.size() == 5);
TESTASSERT(std::equal(a.begin(), a.end(), a2.begin()));
TESTASSERT(a == a2);
// TEST: pop_back
int last_nof_dtor = C::nof_dtor;
a.pop_back();
TESTASSERT(a.size() == 4 and last_nof_dtor == C::nof_dtor - 1);
TESTASSERT(a != a2);
// TEST: erase
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
last_nof_dtor = C::nof_dtor;
@ -139,6 +147,34 @@ int test_obj_add_rem()
TESTASSERT(a2.size() == 5);
a = std::move(a2);
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;
}
@ -155,6 +191,7 @@ int main()
{
TESTASSERT(srslte::test_ctor() == 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);
printf("Success\n");
return 0;