mirror of
https://github.com/ETLCPP/etl.git
synced 2026-10-28 18:07:10 +08:00
circular_buffer: add initialization and assignment overloads (#1556)
* feat(circular_buffer): add initialization and assignment overloads * fix(circular_buffer): handle self-referential assignment * docs: document constructors and assign methods --------- Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com>
This commit is contained in:
parent
1a72c88d47
commit
ffd64f374b
@ -69,11 +69,19 @@ const_reverse_iterator reverse_iterator<const_iterator>
|
||||
```cpp
|
||||
circular_buffer<typename T, size_t SIZE>();
|
||||
|
||||
circular_buffer<typename T, size_t SIZE>(size_t initial_size);
|
||||
|
||||
circular_buffer<typename T, size_t SIZE>(size_t initial_size, const_reference value);
|
||||
|
||||
circular_buffer<typename T, size_t SIZE>(const etl::circular_buffer<typename T, size_t SIZE>& other);
|
||||
|
||||
circular_buffer<typename T, size_t SIZE>(etl::circular_buffer<typename T, size_t SIZE>&& other);
|
||||
```
|
||||
|
||||
The `initial_size` constructor fills the buffer with default-constructed values.
|
||||
The `initial_size` and `value` constructor fills the buffer with copies of `value`.
|
||||
If `initial_size` exceeds `SIZE`, the buffer is filled to its capacity.
|
||||
|
||||
---
|
||||
|
||||
```cpp
|
||||
@ -81,6 +89,10 @@ circular_buffer_ext(void* buffer, size_t max_size)
|
||||
|
||||
circular_buffer_ext(size_t max_size) 20.32.1
|
||||
|
||||
circular_buffer_ext(size_t initial_size, void* buffer, size_t max_size)
|
||||
|
||||
circular_buffer_ext(size_t initial_size, const_reference value, void* buffer, size_t max_size)
|
||||
|
||||
template <typename TIterator>
|
||||
circular_buffer_ext(TIterator first, const TIterator& last, void* buffer, size_t max_size)
|
||||
|
||||
@ -89,6 +101,10 @@ circular_buffer_ext(std::initializer_list<T> init, void* buffer, size_t max_size
|
||||
circular_buffer_ext(const circular_buffer_ext& other, void* buffer, size_t max_size)
|
||||
```
|
||||
|
||||
The `initial_size` constructor fills the buffer with default-constructed values.
|
||||
The `initial_size` and `value` constructor fills the buffer with copies of `value`.
|
||||
If `initial_size` exceeds `max_size`, the buffer is filled to its capacity. The external storage must contain at least `max_size + 1` elements.
|
||||
|
||||
## Status
|
||||
|
||||
```cpp
|
||||
@ -225,6 +241,26 @@ Returns the remaining available capacity in the `circular_buffer`.
|
||||
|
||||
## Modifiers
|
||||
|
||||
```cpp
|
||||
void assign(iterator first, const iterator& last)
|
||||
void assign(const_iterator first, const const_iterator& last)
|
||||
|
||||
template <typename TIterator>
|
||||
void assign(TIterator first, const TIterator& last)
|
||||
```
|
||||
**Description**
|
||||
Replaces the contents of the circular buffer with the elements in the range `[first, last)`. If the range exceeds the capacity, only the last `capacity()` elements are retained. The range may refer to the circular buffer being assigned.
|
||||
|
||||
---
|
||||
|
||||
```cpp
|
||||
void assign(size_type n, const_reference value)
|
||||
```
|
||||
**Description**
|
||||
Replaces the contents of the circular buffer with `n` copies of `value`. If `n` exceeds the capacity, the buffer is filled to its capacity. `value` may refer to an element in the circular buffer being assigned.
|
||||
|
||||
---
|
||||
|
||||
```cpp
|
||||
void set_buffer(void* buffer)
|
||||
```
|
||||
|
||||
@ -900,6 +900,53 @@ namespace etl
|
||||
return pbuffer[(out + index) % buffer_size];
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Assigns an iterator range to the circular buffer.
|
||||
//*************************************************************************
|
||||
void assign(iterator first, const iterator& last)
|
||||
{
|
||||
assign_range(first, last);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Assigns a const iterator range to the circular buffer.
|
||||
//*************************************************************************
|
||||
void assign(const_iterator first, const const_iterator& last)
|
||||
{
|
||||
assign_range(first, last);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Assigns a range to the circular buffer.
|
||||
//*************************************************************************
|
||||
template <typename TIterator>
|
||||
typename etl::enable_if<!etl::is_integral<TIterator>::value, void>::type assign(TIterator first, const TIterator& last)
|
||||
{
|
||||
clear();
|
||||
push(first, last);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Assigns 'n' copies of a value to the circular buffer.
|
||||
//*************************************************************************
|
||||
void assign(size_type n, const_reference value)
|
||||
{
|
||||
if (n == 0U)
|
||||
{
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
|
||||
const T value_copy(value);
|
||||
|
||||
clear();
|
||||
|
||||
while (n-- != 0U)
|
||||
{
|
||||
push(value_copy);
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// push.
|
||||
/// Adds an item to the buffer.
|
||||
@ -1036,6 +1083,43 @@ namespace etl
|
||||
|
||||
protected:
|
||||
|
||||
//*************************************************************************
|
||||
/// Assigns a circular buffer iterator range.
|
||||
//*************************************************************************
|
||||
template <typename TIterator>
|
||||
void assign_range(TIterator first, const TIterator& last)
|
||||
{
|
||||
const bool is_self_range = (&first.container() == this) && (&last.container() == this);
|
||||
|
||||
if (!is_self_range)
|
||||
{
|
||||
clear();
|
||||
push(first, last);
|
||||
}
|
||||
else
|
||||
{
|
||||
const size_type first_index = static_cast<size_type>(first.get_index());
|
||||
const size_type last_index = static_cast<size_type>(last.get_index());
|
||||
|
||||
while (out != first_index)
|
||||
{
|
||||
pop();
|
||||
}
|
||||
|
||||
while (in != last_index)
|
||||
{
|
||||
if (in == 0U)
|
||||
{
|
||||
in = buffer_size;
|
||||
}
|
||||
|
||||
--in;
|
||||
pbuffer[in].~T();
|
||||
ETL_DECREMENT_DEBUG_COUNT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Protected constructor.
|
||||
//*************************************************************************
|
||||
@ -1127,6 +1211,24 @@ namespace etl
|
||||
{
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Constructor, with size.
|
||||
//*************************************************************************
|
||||
explicit circular_buffer(size_t initial_size)
|
||||
: icircular_buffer<T>(reinterpret_cast<T*>(buffer.raw), MAX_SIZE)
|
||||
{
|
||||
this->assign(initial_size, T());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Constructor, from initial size and value.
|
||||
//*************************************************************************
|
||||
circular_buffer(size_t initial_size, typename etl::icircular_buffer<T>::const_reference value)
|
||||
: icircular_buffer<T>(reinterpret_cast<T*>(buffer.raw), MAX_SIZE)
|
||||
{
|
||||
this->assign(initial_size, value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Constructor.
|
||||
/// Constructs a buffer from an iterator range.
|
||||
@ -1274,6 +1376,24 @@ namespace etl
|
||||
{
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Constructor, with size.
|
||||
//*************************************************************************
|
||||
explicit circular_buffer_ext(size_t initial_size, void* buffer, size_t max_size)
|
||||
: icircular_buffer<T>(reinterpret_cast<T*>(buffer), max_size)
|
||||
{
|
||||
this->assign(initial_size, T());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Constructor, from initial size and value.
|
||||
//*************************************************************************
|
||||
circular_buffer_ext(size_t initial_size, typename etl::icircular_buffer<T>::const_reference value, void* buffer, size_t max_size)
|
||||
: icircular_buffer<T>(reinterpret_cast<T*>(buffer), max_size)
|
||||
{
|
||||
this->assign(initial_size, value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Constructor.
|
||||
/// Constructs a buffer from an iterator range.
|
||||
|
||||
@ -67,6 +67,123 @@ namespace
|
||||
CHECK(data.crbegin() == data.crend());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_constructor_with_size)
|
||||
{
|
||||
etl::circular_buffer<int, SIZE> data(5U);
|
||||
|
||||
CHECK_EQUAL(5U, data.size());
|
||||
CHECK(std::all_of(data.begin(), data.end(), [](int value) { return value == 0; }));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_constructor_with_excess_size)
|
||||
{
|
||||
etl::circular_buffer<int, SIZE> data(SIZE + 3U);
|
||||
|
||||
CHECK(data.full());
|
||||
CHECK_EQUAL(SIZE, data.size());
|
||||
CHECK(std::all_of(data.begin(), data.end(), [](int value) { return value == 0; }));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_constructor_with_size_and_value)
|
||||
{
|
||||
const Ndc value("value");
|
||||
Data data(5U, value);
|
||||
|
||||
CHECK_EQUAL(5U, data.size());
|
||||
CHECK(std::all_of(data.begin(), data.end(), [&value](const Ndc& item) { return item == value; }));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_constructor_with_excess_size_and_value)
|
||||
{
|
||||
const Ndc value("value");
|
||||
Data data(SIZE + 3U, value);
|
||||
|
||||
CHECK(data.full());
|
||||
CHECK_EQUAL(SIZE, data.size());
|
||||
CHECK(std::all_of(data.begin(), data.end(), [&value](const Ndc& item) { return item == value; }));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_assign_size_and_value)
|
||||
{
|
||||
Data data;
|
||||
data.push(Ndc("old"));
|
||||
|
||||
const Ndc value("value");
|
||||
data.assign(5U, value);
|
||||
|
||||
CHECK_EQUAL(5U, data.size());
|
||||
CHECK(std::all_of(data.begin(), data.end(), [&value](const Ndc& item) { return item == value; }));
|
||||
|
||||
data.assign(0U, value);
|
||||
CHECK(data.empty());
|
||||
|
||||
data.assign(SIZE + 3U, value);
|
||||
CHECK(data.full());
|
||||
CHECK_EQUAL(SIZE, data.size());
|
||||
CHECK(std::all_of(data.begin(), data.end(), [&value](const Ndc& item) { return item == value; }));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_assign_range)
|
||||
{
|
||||
Compare input{Ndc("0"), Ndc("1"), Ndc("2"), Ndc("3"), Ndc("4"), Ndc("5"), Ndc("6"),
|
||||
Ndc("7"), Ndc("8"), Ndc("9"), Ndc("10"), Ndc("11"), Ndc("12")};
|
||||
Compare expected(input.end() - SIZE, input.end());
|
||||
Data data;
|
||||
data.push(Ndc("old"));
|
||||
|
||||
data.assign(input.begin(), input.end());
|
||||
|
||||
CHECK(data.full());
|
||||
CHECK_EQUAL(expected.size(), data.size());
|
||||
CHECK(std::equal(expected.begin(), expected.end(), data.begin()));
|
||||
|
||||
data.assign(input.begin(), input.begin());
|
||||
CHECK(data.empty());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_assign_self_range)
|
||||
{
|
||||
Compare input{Ndc("0"), Ndc("1"), Ndc("2"), Ndc("3"), Ndc("4"), Ndc("5"), Ndc("6"),
|
||||
Ndc("7"), Ndc("8"), Ndc("9"), Ndc("10"), Ndc("11"), Ndc("12")};
|
||||
Compare expected(input.end() - SIZE, input.end());
|
||||
Data data(input.begin(), input.end());
|
||||
|
||||
data.assign(data.begin(), data.end());
|
||||
|
||||
CHECK(data.full());
|
||||
CHECK_EQUAL(expected.size(), data.size());
|
||||
CHECK(std::equal(expected.begin(), expected.end(), data.begin()));
|
||||
|
||||
Data::const_iterator first = data.cbegin() + 2;
|
||||
Data::const_iterator last = data.cend() - 2;
|
||||
Compare partial_expected(expected.begin() + 2, expected.end() - 2);
|
||||
|
||||
data.assign(first, last);
|
||||
|
||||
CHECK_EQUAL(partial_expected.size(), data.size());
|
||||
CHECK(std::equal(partial_expected.begin(), partial_expected.end(), data.begin()));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_assign_aliased_value)
|
||||
{
|
||||
Compare input{Ndc("0"), Ndc("1"), Ndc("2"), Ndc("3"), Ndc("4")};
|
||||
Data data(input.begin(), input.end());
|
||||
|
||||
const Ndc expected(data.front());
|
||||
data.assign(7U, data.front());
|
||||
|
||||
CHECK_EQUAL(7U, data.size());
|
||||
CHECK(std::all_of(data.begin(), data.end(), [&expected](const Ndc& item) { return item == expected; }));
|
||||
}
|
||||
|
||||
#if ETL_HAS_INITIALIZER_LIST
|
||||
//*************************************************************************
|
||||
TEST(test_constructor_from_literal)
|
||||
|
||||
@ -78,6 +78,131 @@ namespace
|
||||
CHECK(data.crbegin() == data.crend());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_constructor_with_size)
|
||||
{
|
||||
etl::uninitialized_buffer_of<int, SIZE + 1> buffer1;
|
||||
etl::circular_buffer_ext<int> data(5U, buffer1.raw, SIZE);
|
||||
|
||||
CHECK_EQUAL(5U, data.size());
|
||||
CHECK(std::all_of(data.begin(), data.end(), [](int value) { return value == 0; }));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_constructor_with_excess_size)
|
||||
{
|
||||
etl::uninitialized_buffer_of<int, SIZE + 1> buffer1;
|
||||
etl::circular_buffer_ext<int> data(SIZE + 3U, buffer1.raw, SIZE);
|
||||
|
||||
CHECK(data.full());
|
||||
CHECK_EQUAL(SIZE, data.size());
|
||||
CHECK(std::all_of(data.begin(), data.end(), [](int value) { return value == 0; }));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_constructor_with_size_and_value)
|
||||
{
|
||||
Buffer_t buffer1;
|
||||
const Ndc value("value");
|
||||
Data data(5U, value, buffer1.raw, SIZE);
|
||||
|
||||
CHECK_EQUAL(5U, data.size());
|
||||
CHECK(std::all_of(data.begin(), data.end(), [&value](const Ndc& item) { return item == value; }));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_constructor_with_excess_size_and_value)
|
||||
{
|
||||
Buffer_t buffer1;
|
||||
const Ndc value("value");
|
||||
Data data(SIZE + 3U, value, buffer1.raw, SIZE);
|
||||
|
||||
CHECK(data.full());
|
||||
CHECK_EQUAL(SIZE, data.size());
|
||||
CHECK(std::all_of(data.begin(), data.end(), [&value](const Ndc& item) { return item == value; }));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_assign_size_and_value)
|
||||
{
|
||||
Buffer_t buffer1;
|
||||
Data data(buffer1.raw, SIZE);
|
||||
data.push(Ndc("old"));
|
||||
|
||||
const Ndc value("value");
|
||||
data.assign(5U, value);
|
||||
|
||||
CHECK_EQUAL(5U, data.size());
|
||||
CHECK(std::all_of(data.begin(), data.end(), [&value](const Ndc& item) { return item == value; }));
|
||||
|
||||
data.assign(0U, value);
|
||||
CHECK(data.empty());
|
||||
|
||||
data.assign(SIZE + 3U, value);
|
||||
CHECK(data.full());
|
||||
CHECK_EQUAL(SIZE, data.size());
|
||||
CHECK(std::all_of(data.begin(), data.end(), [&value](const Ndc& item) { return item == value; }));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_assign_range)
|
||||
{
|
||||
Buffer_t buffer1;
|
||||
Compare input{Ndc("0"), Ndc("1"), Ndc("2"), Ndc("3"), Ndc("4"), Ndc("5"), Ndc("6"),
|
||||
Ndc("7"), Ndc("8"), Ndc("9"), Ndc("10"), Ndc("11"), Ndc("12")};
|
||||
Compare expected(input.end() - SIZE, input.end());
|
||||
Data data(buffer1.raw, SIZE);
|
||||
data.push(Ndc("old"));
|
||||
|
||||
data.assign(input.begin(), input.end());
|
||||
|
||||
CHECK(data.full());
|
||||
CHECK_EQUAL(expected.size(), data.size());
|
||||
CHECK(std::equal(expected.begin(), expected.end(), data.begin()));
|
||||
|
||||
data.assign(input.begin(), input.begin());
|
||||
CHECK(data.empty());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_assign_self_range)
|
||||
{
|
||||
Buffer_t buffer1;
|
||||
Compare input{Ndc("0"), Ndc("1"), Ndc("2"), Ndc("3"), Ndc("4"), Ndc("5"), Ndc("6"),
|
||||
Ndc("7"), Ndc("8"), Ndc("9"), Ndc("10"), Ndc("11"), Ndc("12")};
|
||||
Compare expected(input.end() - SIZE, input.end());
|
||||
Data data(input.begin(), input.end(), buffer1.raw, SIZE);
|
||||
|
||||
data.assign(data.begin(), data.end());
|
||||
|
||||
CHECK(data.full());
|
||||
CHECK_EQUAL(expected.size(), data.size());
|
||||
CHECK(std::equal(expected.begin(), expected.end(), data.begin()));
|
||||
|
||||
Data::const_iterator first = data.cbegin() + 2;
|
||||
Data::const_iterator last = data.cend() - 2;
|
||||
Compare partial_expected(expected.begin() + 2, expected.end() - 2);
|
||||
|
||||
data.assign(first, last);
|
||||
|
||||
CHECK_EQUAL(partial_expected.size(), data.size());
|
||||
CHECK(std::equal(partial_expected.begin(), partial_expected.end(), data.begin()));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_assign_aliased_value)
|
||||
{
|
||||
Buffer_t buffer1;
|
||||
Compare input{Ndc("0"), Ndc("1"), Ndc("2"), Ndc("3"), Ndc("4")};
|
||||
Data data(input.begin(), input.end(), buffer1.raw, SIZE);
|
||||
|
||||
const Ndc expected(data.front());
|
||||
data.assign(7U, data.front());
|
||||
|
||||
CHECK_EQUAL(7U, data.size());
|
||||
CHECK(std::all_of(data.begin(), data.end(), [&expected](const Ndc& item) { return item == expected; }));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_set_buffer_after_default_constructor)
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user