Added iterator and const_iterator to etl::ipool (#1043)

* Added iterator and const_iterator to etl::ipool

* Adjusted source code format
This commit is contained in:
Roland Reichwein 2025-05-14 20:14:23 +02:00 committed by GitHub
parent fe592d5d19
commit 420474593b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 441 additions and 0 deletions

View File

@ -34,6 +34,7 @@ SOFTWARE.
#include "platform.h"
#include "error_handler.h"
#include "exception.h"
#include "iterator.h"
#include "static_assert.h"
#include "utility.h"
#include "memory.h"
@ -104,6 +105,189 @@ namespace etl
typedef size_t size_type;
private:
//***************************************************************************
/// Iterator helper functions
//***************************************************************************
const char* buffer_end() const
{
return p_buffer + Item_Size * items_initialised;
}
//***************************************************************************
/// Optimization: a candidate for being in free list, but no guarantee
/// if false, cannot be part of free list, and therefore is allocated
/// if true, possibly in free list, but still needs to be checked via free list
//***************************************************************************
bool is_pointing_into_pool_or_end_or_nullptr(const char *address) const
{
return address == ETL_NULLPTR || (p_buffer <= address && address <= buffer_end());
}
//***************************************************************************
/// Iterate free list to confirm specified address is included or not
//***************************************************************************
bool is_in_free_list(const char* address) const
{
const char* i = p_next;
while (i != ETL_NULLPTR)
{
if (address == i)
{
return true;
}
i = *reinterpret_cast<const char* const*>(i);
}
return false;
}
public:
template<bool is_const>
class ipool_iterator
{
public:
friend class ipool;
typedef typename etl::conditional<is_const, const char*, char*>::type value_type;
typedef typename etl::conditional<is_const, const char*&, char*&>::type reference;
typedef typename etl::conditional<is_const, const char**, char**>::type pointer;
typedef ptrdiff_t difference_type;
typedef ETL_OR_STD::forward_iterator_tag iterator_category;
typedef typename etl::conditional<is_const, const void*, void*>::type void_type;
typedef typename etl::conditional<is_const, const ipool, ipool>::type pool_type;
typedef typename etl::conditional<is_const, const char* const*, char**>::type pointer_type;
ipool_iterator(const ipool_iterator& other)
: p_current(other.p_current)
, p_pool(other.p_pool)
{
find_allocated();
}
ipool_iterator& operator ++()
{
p_current = p_current + p_pool->Item_Size;
find_allocated();
return *this;
}
ipool_iterator operator ++(int)
{
ipool_iterator temp(*this);
p_current = p_current + p_pool->Item_Size;
find_allocated();
return temp;
}
ipool_iterator& operator =(const ipool_iterator& other)
{
p_current = other.p_current;
p_pool = other.p_pool;
return *this;
}
void_type operator *() const
{
return p_current;
}
template <typename T>
T& get() const
{
return *reinterpret_cast<T*>(p_current);
}
friend bool operator == (const ipool_iterator& lhs, const ipool_iterator& rhs)
{
return lhs.p_current == rhs.p_current;
}
friend bool operator != (const ipool_iterator& lhs, const ipool_iterator& rhs)
{
return !(lhs == rhs);
}
private:
//***************************************************************************
/// find allocated item by increasing p_current, starting at p_current
/// leave p_current at buffer_end() if no further allocated item found
//***************************************************************************
void find_allocated()
{
while (p_current < p_pool->buffer_end())
{
value_type value = *reinterpret_cast<pointer_type>(p_current);
if (!p_pool->is_pointing_into_pool_or_end_or_nullptr(value))
{
return;
}
if (!p_pool->is_in_free_list(p_current))
{
return;
}
p_current += p_pool->Item_Size;
}
}
ipool_iterator(value_type p, pool_type* pool_)
: p_current(p)
, p_pool(pool_)
{
find_allocated();
}
value_type p_current;
pool_type* p_pool;
};
template<bool is_const>
friend class ipool_iterator;
typedef ipool_iterator<false> iterator;
class const_iterator : public ipool_iterator<true>
{
public:
const_iterator(const ipool_iterator& other) : ipool_iterator(other) {}
const_iterator(const ipool_iterator<false>& other) : ipool_iterator(other.p_current, other.p_pool) {}
const_iterator(value_type p, pool_type* pool_) : ipool_iterator<true>(p, pool_) {}
};
iterator begin()
{
return iterator(p_buffer, this);
}
iterator end()
{
return iterator(p_buffer + Item_Size * items_initialised, this);
}
const_iterator begin() const
{
return const_iterator(p_buffer, this);
}
const_iterator end() const
{
return const_iterator(p_buffer + Item_Size * items_initialised, this);
}
const_iterator cbegin() const
{
return const_iterator(p_buffer, this);
}
const_iterator cend() const
{
return const_iterator(p_buffer + Item_Size * items_initialised, this);
}
//*************************************************************************
/// Allocate storage for an object from the pool.
/// If asserts or exceptions are enabled and there are no more free items an
@ -337,6 +521,7 @@ namespace etl
}
private:
static ETL_CONSTEXPR uintptr_t invalid_item_ptr = 1;
//*************************************************************************
/// Allocate an item from the pool.
@ -371,6 +556,11 @@ namespace etl
// No more left!
p_next = ETL_NULLPTR;
}
// invalid pointer, outside pool
// needs to be different from ETL_NULLPTR since ETL_NULLPTR is used
// as list endmarker
*reinterpret_cast<uintptr_t*>(p_value) = invalid_item_ptr;
}
else
{

View File

@ -34,6 +34,7 @@ SOFTWARE.
#include <vector>
#include <string>
#include "etl/unaligned_type.h"
#include "etl/pool.h"
#include "etl/largest.h"
@ -484,4 +485,254 @@ namespace
CHECK_EQUAL(3, memPool.available());
CHECK_EQUAL(0, memPool.size());
}
//*************************************************************************
TEST(test_iterators)
{
etl::pool<int, 4> pool0;
etl::ipool::iterator begin = pool0.begin();
etl::ipool::iterator end = pool0.end();
CHECK(begin == end);
CHECK(!(begin != end));
CHECK_EQUAL(etl::distance(begin, end), 0);
int* a = pool0.allocate();
*a = 1;
begin = pool0.begin();
end = pool0.end();
CHECK(begin != end);
CHECK(!(begin == end));
CHECK_EQUAL(etl::distance(begin, end), 1);
int* b = pool0.allocate();
*b = 2;
begin = pool0.begin();
end = pool0.end();
CHECK(begin != end);
CHECK(!(begin == end));
CHECK_EQUAL(etl::distance(begin, end), 2);
// post increment
for (auto i = pool0.begin(); i != pool0.end(); i++)
{
CHECK(*reinterpret_cast<int*>(*i) == 1 || *reinterpret_cast<int*>(*i) == 2);
}
// pre increment
for (auto i = pool0.begin(); i != pool0.end(); ++i)
{
CHECK(*reinterpret_cast<int*>(*i) == 1 || *reinterpret_cast<int*>(*i) == 2);
}
int* c = pool0.allocate();
*c = 3;
begin = pool0.begin();
end = pool0.end();
CHECK(begin != end);
CHECK(!(begin == end));
CHECK_EQUAL(etl::distance(begin, end), 3);
pool0.release(b);
begin = pool0.begin();
end = pool0.end();
CHECK(begin != end);
CHECK(!(begin == end));
CHECK_EQUAL(etl::distance(begin, end), 2);
int* d = pool0.allocate();
*d = 4;
begin = pool0.begin();
end = pool0.end();
CHECK(begin != end);
CHECK(!(begin == end));
CHECK_EQUAL(etl::distance(begin, end), 3);
b = pool0.allocate();
*b = 2;
begin = pool0.begin();
end = pool0.end();
CHECK(begin != end);
CHECK(!(begin == end));
CHECK_EQUAL(etl::distance(begin, end), 4);
// post increment
for (auto i = pool0.begin(); i != pool0.end(); i++)
{
CHECK(*reinterpret_cast<int*>(*i) >= 1 && *reinterpret_cast<int*>(*i) <= 4);
}
// pre increment
for (auto i = pool0.begin(); i != pool0.end(); ++i)
{
CHECK(*reinterpret_cast<int*>(*i) >= 1 && *reinterpret_cast<int*>(*i) <= 4);
}
pool0.release(b);
begin = pool0.begin();
end = pool0.end();
CHECK(begin != end);
CHECK(!(begin == end));
CHECK_EQUAL(etl::distance(begin, end), 3);
pool0.release(a);
begin = pool0.begin();
end = pool0.end();
CHECK(begin != end);
CHECK(!(begin == end));
CHECK_EQUAL(etl::distance(begin, end), 2);
pool0.release(d);
begin = pool0.begin();
end = pool0.end();
CHECK(begin != end);
CHECK(!(begin == end));
CHECK_EQUAL(etl::distance(begin, end), 1);
auto& v = begin.get<etl::be_uint32_t>();
v = 1;
pool0.release(c);
begin = pool0.begin();
end = pool0.end();
CHECK(begin == end);
CHECK(!(begin != end));
CHECK_EQUAL(etl::distance(begin, end), 0);
}
//*************************************************************************
TEST(test_const_iterators)
{
etl::pool<int, 4> pool0;
etl::ipool::const_iterator begin = pool0.begin();
etl::ipool::const_iterator end = pool0.end();
CHECK(begin == end);
CHECK(!(begin != end));
CHECK_EQUAL(etl::distance(begin, end), 0);
int* a = pool0.allocate();
*a = 1;
begin = pool0.cbegin();
end = pool0.cend();
CHECK(begin != end);
CHECK(!(begin == end));
CHECK_EQUAL(etl::distance(begin, end), 1);
int* b = pool0.allocate();
*b = 2;
begin = pool0.begin();
end = pool0.end();
CHECK(begin != end);
CHECK(!(begin == end));
CHECK_EQUAL(etl::distance(begin, end), 2);
// post increment
for (auto i = pool0.begin(); i != pool0.end(); i++)
{
CHECK(*reinterpret_cast<int*>(*i) == 1 || *reinterpret_cast<int*>(*i) == 2);
}
// pre increment
for (auto i = pool0.begin(); i != pool0.end(); ++i)
{
CHECK(*reinterpret_cast<int*>(*i) == 1 || *reinterpret_cast<int*>(*i) == 2);
}
int* c = pool0.allocate();
*c = 3;
begin = pool0.cbegin();
end = pool0.cend();
CHECK(begin != end);
CHECK(!(begin == end));
CHECK_EQUAL(etl::distance(begin, end), 3);
pool0.release(b);
begin = pool0.begin();
end = pool0.end();
CHECK(begin != end);
CHECK(!(begin == end));
CHECK_EQUAL(etl::distance(begin, end), 2);
int* d = pool0.allocate();
*d = 4;
begin = pool0.cbegin();
end = pool0.cend();
CHECK(begin != end);
CHECK(!(begin == end));
CHECK_EQUAL(etl::distance(begin, end), 3);
b = pool0.allocate();
*b = 2;
begin = pool0.cbegin();
end = pool0.cend();
CHECK(begin != end);
CHECK(!(begin == end));
CHECK_EQUAL(etl::distance(begin, end), 4);
// post increment
for (auto i = pool0.begin(); i != pool0.end(); i++)
{
CHECK(*reinterpret_cast<int*>(*i) >= 1 && *reinterpret_cast<int*>(*i) <= 4);
}
// pre increment
for (auto i = pool0.cbegin(); i != pool0.cend(); ++i)
{
CHECK(*reinterpret_cast<const int*>(*i) >= 1 && *reinterpret_cast<const int*>(*i) <= 4);
}
pool0.release(b);
begin = pool0.begin();
end = pool0.end();
CHECK(begin != end);
CHECK(!(begin == end));
CHECK_EQUAL(etl::distance(begin, end), 3);
pool0.release(a);
begin = pool0.cbegin();
end = pool0.cend();
CHECK(begin != end);
CHECK(!(begin == end));
CHECK_EQUAL(etl::distance(begin, end), 2);
pool0.release(d);
begin = pool0.begin();
end = pool0.end();
CHECK(begin != end);
CHECK(!(begin == end));
CHECK_EQUAL(etl::distance(begin, end), 1);
const auto& v = begin.get<const etl::be_uint32_t>();
CHECK(v != 0);
pool0.release(c);
begin = pool0.cbegin();
end = pool0.cend();
CHECK(begin == end);
CHECK(!(begin != end));
CHECK_EQUAL(etl::distance(begin, end), 0);
}
}