Compare commits

...

4 Commits

Author SHA1 Message Date
John Wellbelove
475abe4d69
Merge branch 'development' into feature/Add-intersect-and-union-actions-to-type_list 2026-06-13 20:05:23 +01:00
John Wellbelove
8cadfc0b10 Corrections from review 2026-06-13 19:57:12 +01:00
Roland Reichwein
20cab32256
Make ipriority_queue non-sized base class (#1459)
* Fix iterator access algorithm.h

Move from operator[] access to operator+ and operator- to prevent
limited compatibility. This worked before for vector because of
iterators being ptrdiff_t (signed), but not for unsigned access
like size_t as in etl::queue.

* Make ipriority_queue non-sized base class

Fixes issue #1457

---------

Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com>
2026-06-13 11:00:39 +02:00
Roland Reichwein
6d9ed143b2
Add etl::infinite_loop (#1458) 2026-06-12 08:04:24 +01:00
10 changed files with 300 additions and 63 deletions

View File

@ -10,7 +10,7 @@ title: "type_list"
## type_list
```cpp
template <typename... Typelists>>
template <typename... Typelists>
struct type_list
```
**Description**
@ -217,7 +217,7 @@ template <typename TTypeList, size_t... Indices>
struct type_list_select
```
**Description**
Selects types from a given `type_list`, according to a list if indices.
Selects types from a given `type_list`, according to a list of indices.
Defines `type` as the modified `type_list`.
---
@ -227,17 +227,17 @@ template <typename TTypeList, size_t... Indices>
type_list_select_t
```
**Description**
Selects types from a given `type_list`, according to a list if indices.
Selects types from a given `type_list`, according to a list of indices.
Defined as the modified `type_list`.
## type_list_select_from_indexes
```cpp
template <typename TTypeList, size_t... Indices
template <typename TTypeList, size_t... Indices>
type_list_select_from_indexes
```
**Description**
`type_list_select_from_indexes` is an alias of `type_list_select` to be more consistent with the naming of other type_list metafunctions.
Selects types from a given `type_list`, according to a list if indices.
Selects types from a given `type_list`, according to a list of indices.
Defines `type` as the modified `type_list`.
## type_list_select_from_index_sequence
@ -596,7 +596,7 @@ constexpr bool type_list_none_of_v
**Description**
Checks that no types in a `type_list` satisfy a unary predicate.
Predicate must be: `template <typename T> struct Pred : etl::bool_constant<...> {};`
Defined` as `true` or `false`.
Defined as `true` or `false`.
From: `C++17`
## type_lists_are_convertible
@ -738,19 +738,19 @@ template <typename T, typename... TypeLists>
struct type_list_in_no_lists
```
**Description**
Checks if a type `T` is present in at least one of the provided `type_lists`.
Inherits from `etl::true_type` if `T` is in any list, otherwise `etl::false_type`.
Checks if a type `T` is present none of the provided `type_lists`.
Inherits from `etl::true_type` if `T` is in no list, otherwise `etl::false_type`.
Since: `20.48.0`
---
```cpp
template <typename T, typename... TypeLists>
constexpr bool type_list_in_no_list_v
constexpr bool type_list_in_no_lists_v
```
**Description**
Checks if a type `T` is present in at least one of the provided `type_lists`.
Defined as `true` if `T` is in any list, otherwise `false`.
Checks if a type `T` is present in none of the provided `type_lists`.
Defined as `true` if `T` is in no list, otherwise `false`.
Since: `20.48.0`
From: `C++17`

View File

@ -0,0 +1,39 @@
---
title: "infinite_loop"
---
{{< callout type="info">}}
Header: `infinite_loop.h`
{{< /callout >}}
A portable infinite loop that will not be optimised away by the compiler.
Before C++26, an empty infinite loop without side effects is considered undefined behaviour and may
be optimised away. This utility uses a compiler memory barrier to prevent that optimisation.
See [P2809R1](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2809r1.html) for background.
## Function
```cpp
[[noreturn]] inline void etl::infinite_loop()
```
**Description**
Enters an infinite loop that is guaranteed not to be removed by the compiler.
On GCC and Clang this is achieved with an inline assembly memory clobber.
On MSVC this uses `_ReadWriteBarrier()`.
## Example
```cpp
#include <etl/infinite_loop.h>
int main()
{
// Initialise hardware...
etl::infinite_loop();
}
```

View File

@ -880,14 +880,14 @@ namespace etl
TDistance parent = (value_index - 1) / 2;
#include "etl/private/diagnostic_array_bounds_push.h"
while ((value_index > top_index) && compare(first[parent], value))
while ((value_index > top_index) && compare(*(first + parent), value))
{
first[value_index] = ETL_MOVE(first[parent]);
value_index = parent;
parent = (value_index - 1) / 2;
*(first + value_index) = ETL_MOVE(*(first + parent));
value_index = parent;
parent = (value_index - 1) / 2;
}
first[value_index] = ETL_MOVE(value);
*(first + value_index) = ETL_MOVE(value);
#include "etl/private/diagnostic_pop.h"
}
@ -900,20 +900,20 @@ namespace etl
while (child2nd < length)
{
if (compare(first[child2nd], first[child2nd - 1]))
if (compare(*(first + child2nd), *(first + (child2nd - 1))))
{
--child2nd;
}
first[value_index] = ETL_MOVE(first[child2nd]);
value_index = child2nd;
child2nd = 2 * (child2nd + 1);
*(first + value_index) = ETL_MOVE(*(first + child2nd));
value_index = child2nd;
child2nd = 2 * (child2nd + 1);
}
if (child2nd == length)
{
first[value_index] = ETL_MOVE(first[child2nd - 1]);
value_index = child2nd - 1;
*(first + value_index) = ETL_MOVE(*(first + (child2nd - 1)));
value_index = child2nd - 1;
}
push_heap(first, value_index, top_index, ETL_MOVE(value), compare);
@ -927,7 +927,7 @@ namespace etl
for (TDistance child = 1; child < n; ++child)
{
if (compare(first[parent], first[child]))
if (compare(*(first + parent), *(first + child)))
{
return false;
}
@ -949,8 +949,8 @@ namespace etl
typedef typename etl::iterator_traits<TIterator>::value_type value_t;
typedef typename etl::iterator_traits<TIterator>::difference_type distance_t;
value_t value = ETL_MOVE(last[-1]);
last[-1] = ETL_MOVE(first[0]);
value_t value = ETL_MOVE(*(last - 1));
*(last - 1) = ETL_MOVE(*first);
private_heap::adjust_heap(first, distance_t(0), distance_t(last - first - 1), ETL_MOVE(value), compare);
}

View File

@ -0,0 +1,65 @@
///\file
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2026 BMW AG
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef ETL_INFINITE_LOOP_INCLUDED
#define ETL_INFINITE_LOOP_INCLUDED
#include "platform.h"
namespace etl
{
//*****************************************************************************
/// An infinite loop that will not be optimised out
///
/// Before C++26, an empty infinite loop without side effects is considered
/// undefined behavior, and may be optimised away by the compiler.
///
/// See also
/// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2809r1.html
//*****************************************************************************
ETL_NORETURN
inline void infinite_loop()
{
while (true)
{
#if ETL_NOT_USING_CPP26
#if defined(ETL_COMPILER_GCC) || defined(ETL_COMPILER_CLANG)
__asm__ __volatile__("" : : : "memory");
#elif defined(ETL_COMPILER_MICROSOFT)
_ReadWriteBarrier();
#else
#error "Infinite loop not supported for this compiler and platform"
#endif
#endif
}
}
} // namespace etl
#endif

View File

@ -33,11 +33,13 @@ SOFTWARE.
#include "platform.h"
#include "algorithm.h"
#include "deque.h"
#include "error_handler.h"
#include "exception.h"
#include "functional.h"
#include "iterator.h"
#include "parameter_type.h"
#include "static_assert.h"
#include "type_traits.h"
#include "utility.h"
#include "vector.h"
@ -109,13 +111,33 @@ namespace etl
}
};
//***************************************************************************
/// Trait to deduce the non-sized interface type of a container.
/// Specialize for containers that can be used with ipriority_queue.
//***************************************************************************
template <typename TContainer>
struct priority_queue_container_interface
{
ETL_STATIC_ASSERT(sizeof(TContainer) == 0, "Unsupported container type for etl::ipriority_queue");
};
template <typename T, const size_t N>
struct priority_queue_container_interface<etl::vector<T, N> >
{
typedef etl::ivector<T> type;
};
template <typename T, const size_t N>
struct priority_queue_container_interface<etl::deque<T, N> >
{
typedef etl::ideque<T> type;
};
//***************************************************************************
///\ingroup queue
///\brief This is the base for all priority queues that contain a particular
/// type. \details Normally a reference to this type will be taken from a
/// derived queue.
/// The TContainer specified must provide the front, push_back, pop_back, and
/// assign methods to work correctly with priority_queue.
///\code
/// etl::priority_queue<int, 10> myPriorityQueue;
/// etl::ipriority_queue<int>& iQueue = myPriorityQueue;
@ -123,24 +145,24 @@ namespace etl
/// \warning This priority queue cannot be used for concurrent access from
/// multiple threads.
/// \tparam T The type of value that the queue holds.
/// \tparam TContainer to hold the T queue values
/// \tparam TContainerBase The non-sized base class of the underlying container (e.g. etl::ivector<T>)
/// \tparam TCompare to use in comparing T values
//***************************************************************************
template <typename T, typename TContainer, typename TCompare = etl::less<T> >
template <typename T, typename TContainerBase = etl::ivector<T>, typename TCompare = etl::less<T> >
class ipriority_queue
{
public:
typedef T value_type; ///< The type stored in the queue.
typedef TContainer container_type; ///< The container type used for priority queue.
typedef TCompare compare_type; ///< The comparison type.
typedef T& reference; ///< A reference to the type used in the queue.
typedef const T& const_reference; ///< A const reference to the type used in the queue.
typedef T value_type; ///< The type stored in the queue.
typedef TCompare compare_type; ///< The comparison type.
typedef TContainerBase container_base_type; ///< The non-sized container base type.
typedef T& reference; ///< A reference to the type used in the queue.
typedef const T& const_reference; ///< A const reference to the type used in the queue.
#if ETL_USING_CPP11
typedef T&& rvalue_reference; ///< An rvalue reference to the type used in the queue.
#endif
typedef typename TContainer::size_type size_type; ///< The type used for determining the size of the queue.
typedef typename etl::iterator_traits< typename TContainer::iterator>::difference_type difference_type;
typedef typename TContainerBase::size_type size_type; ///< The type used for determining the size of the queue.
typedef typename TContainerBase::difference_type difference_type;
//*************************************************************************
/// Gets a reference to the highest priority value in the priority queue.
@ -432,6 +454,21 @@ namespace etl
}
#endif
//*************************************************************************
/// Destructor.
//*************************************************************************
#if defined(ETL_POLYMORPHIC_PRIORITY_QUEUE) || defined(ETL_POLYMORPHIC_CONTAINERS)
public:
virtual ~ipriority_queue() {}
#else
protected:
~ipriority_queue() {}
#endif
protected:
//*************************************************************************
@ -461,7 +498,10 @@ namespace etl
//*************************************************************************
/// The constructor that is called from derived classes.
//*************************************************************************
ipriority_queue() {}
ipriority_queue(TContainerBase& container_)
: container(container_)
{
}
private:
@ -469,7 +509,7 @@ namespace etl
ipriority_queue(const ipriority_queue&);
/// The container specified at instantiation of the priority_queue
TContainer container;
TContainerBase& container;
TCompare compare;
};
@ -483,8 +523,12 @@ namespace etl
//***************************************************************************
template <typename T, const size_t SIZE, typename TContainer = etl::vector<T, SIZE>,
typename TCompare = etl::less<typename TContainer::value_type> >
class priority_queue : public etl::ipriority_queue<T, TContainer, TCompare>
class priority_queue : public etl::ipriority_queue<T, typename etl::priority_queue_container_interface<TContainer>::type, TCompare>
{
private:
typedef etl::ipriority_queue<T, typename etl::priority_queue_container_interface<TContainer>::type, TCompare> base_t;
public:
typedef typename TContainer::size_type size_type;
@ -496,7 +540,7 @@ namespace etl
/// Default constructor.
//*************************************************************************
priority_queue()
: etl::ipriority_queue<T, TContainer, TCompare>()
: base_t(container)
{
}
@ -504,9 +548,9 @@ namespace etl
/// Copy constructor
//*************************************************************************
priority_queue(const priority_queue& rhs)
: etl::ipriority_queue<T, TContainer, TCompare>()
: base_t(container)
{
etl::ipriority_queue<T, TContainer, TCompare>::clone(rhs);
base_t::clone(rhs);
}
#if ETL_USING_CPP11
@ -514,9 +558,9 @@ namespace etl
/// Move constructor
//*************************************************************************
priority_queue(priority_queue&& rhs)
: etl::ipriority_queue<T, TContainer, TCompare>()
: base_t(container)
{
etl::ipriority_queue<T, TContainer, TCompare>::move(etl::move(rhs));
base_t::move(etl::move(rhs));
}
#endif
@ -528,9 +572,9 @@ namespace etl
//*************************************************************************
template <typename TIterator>
priority_queue(TIterator first, TIterator last)
: etl::ipriority_queue<T, TContainer, TCompare>()
: base_t(container)
{
etl::ipriority_queue<T, TContainer, TCompare>::assign(first, last);
base_t::assign(first, last);
}
//*************************************************************************
@ -538,7 +582,7 @@ namespace etl
//*************************************************************************
~priority_queue()
{
etl::ipriority_queue<T, TContainer, TCompare>::clear();
base_t::clear();
}
//*************************************************************************
@ -548,7 +592,7 @@ namespace etl
{
if (&rhs != this)
{
etl::ipriority_queue<T, TContainer, TCompare>::clone(rhs);
base_t::clone(rhs);
}
return *this;
@ -562,13 +606,17 @@ namespace etl
{
if (&rhs != this)
{
etl::ipriority_queue<T, TContainer, TCompare>::clear();
etl::ipriority_queue<T, TContainer, TCompare>::move(etl::move(rhs));
base_t::clear();
base_t::move(etl::move(rhs));
}
return *this;
}
#endif
private:
TContainer container;
};
template <typename T, const size_t SIZE, typename TContainer, typename TCompare>

View File

@ -992,11 +992,11 @@ namespace etl
{
};
// Specialisation if no lists provided.
template <typename T>
struct type_list_in_any_list<T> : etl::false_type
{
};
//// Specialisation if no lists provided.
//template <typename T>
//struct type_list_in_any_list<T> : etl::false_type
//{
//};
#if ETL_USING_CPP17
template <typename T, typename... TypeLists>

View File

@ -67,6 +67,7 @@ SOFTWARE.
#define ETL_POLYMORPHIC_SET
#define ETL_POLYMORPHIC_MULTISET
#define ETL_POLYMORPHIC_QUEUE
#define ETL_POLYMORPHIC_PRIORITY_QUEUE
#define ETL_POLYMORPHIC_STACK
#define ETL_POLYMORPHIC_REFERENCE_FLAT_MAP
#define ETL_POLYMORPHIC_REFERENCE_FLAT_MULTIMAP

View File

@ -243,6 +243,7 @@ target_sources(tests PRIVATE
imemory_block_allocator.h.t.cpp
index_of_type.h.t.cpp
indirect_vector.h.t.cpp
infinite_loop.h.t.cpp
initializer_list.h.t.cpp
inplace_function.h.t.cpp
instance_count.h.t.cpp

View File

@ -0,0 +1,29 @@
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2026 BMW AG
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#include <etl/infinite_loop.h>

View File

@ -101,7 +101,7 @@ namespace
priority_queue_t* ppriority_queue = new etl::priority_queue<int, 4>;
etl::ipriority_queue<int, priority_queue_t::container_type, priority_queue_t::compare_type>* pipriority_queue = ppriority_queue;
etl::ipriority_queue<int>* pipriority_queue = ppriority_queue;
pipriority_queue->push(1);
pipriority_queue->push(2);
@ -577,8 +577,8 @@ namespace
etl::priority_queue<int, SIZE> priority_queue2;
etl::ipriority_queue<int, etl::vector<int, SIZE>>& ipriority_queue1 = priority_queue1;
etl::ipriority_queue<int, etl::vector<int, SIZE>>& ipriority_queue2 = priority_queue2;
etl::ipriority_queue<int>& ipriority_queue1 = priority_queue1;
etl::ipriority_queue<int>& ipriority_queue2 = priority_queue2;
ipriority_queue2 = ipriority_queue1;
@ -621,9 +621,9 @@ namespace
//*************************************************************************
TEST(test_interface)
{
typedef etl::priority_queue<int, SIZE> priority_queue_t;
priority_queue_t priority_queue;
etl::ipriority_queue<int, priority_queue_t::container_type, priority_queue_t::compare_type>& ipriority_queue = priority_queue;
typedef etl::priority_queue<int, SIZE> priority_queue_t;
priority_queue_t priority_queue;
etl::ipriority_queue<int>& ipriority_queue = priority_queue;
std::priority_queue<int> compare_priority_queue;
@ -654,8 +654,8 @@ namespace
etl::priority_queue<int, SIZE, etl::vector<int, SIZE>, std::less<int> > priority_queue2;
etl::ipriority_queue<int, etl::vector<int, SIZE>, std::less<int>>& ipriority_queue1 = priority_queue1;
etl::ipriority_queue<int, etl::vector<int, SIZE>, std::less<int>>& ipriority_queue2 = priority_queue2;
etl::ipriority_queue<int, etl::ivector<int>, std::less<int> >& ipriority_queue1 = priority_queue1;
etl::ipriority_queue<int, etl::ivector<int>, std::less<int> >& ipriority_queue2 = priority_queue2;
ipriority_queue2 = ipriority_queue1;
@ -668,5 +668,59 @@ namespace
priority_queue2.pop();
}
}
//*************************************************************************
TEST(test_deque_container)
{
etl::priority_queue<int, SIZE, etl::deque<int, SIZE> > priority_queue;
CHECK_EQUAL(priority_queue.size(), 0UL);
CHECK_EQUAL(priority_queue.available(), SIZE);
CHECK_EQUAL(priority_queue.max_size(), SIZE);
priority_queue.push(3);
priority_queue.push(1);
priority_queue.push(4);
priority_queue.push(2);
CHECK_EQUAL(4UL, priority_queue.size());
CHECK(priority_queue.full());
CHECK_EQUAL(4, priority_queue.top());
priority_queue.pop();
CHECK_EQUAL(3, priority_queue.top());
priority_queue.pop();
CHECK_EQUAL(2, priority_queue.top());
priority_queue.pop();
CHECK_EQUAL(1, priority_queue.top());
priority_queue.pop();
CHECK(priority_queue.empty());
// Test via ipriority_queue interface
etl::priority_queue<int, SIZE, etl::deque<int, SIZE> > pq1;
pq1.push(10);
pq1.push(30);
pq1.push(20);
etl::ipriority_queue<int, etl::ideque<int> >& ipq = pq1;
CHECK_EQUAL(3UL, ipq.size());
CHECK_EQUAL(30, ipq.top());
etl::priority_queue<int, SIZE, etl::deque<int, SIZE> > pq2;
etl::ipriority_queue<int, etl::ideque<int> >& ipq2 = pq2;
ipq2 = ipq;
CHECK_EQUAL(pq1.size(), pq2.size());
while (!pq1.empty())
{
CHECK_EQUAL(pq1.top(), pq2.top());
pq1.pop();
pq2.pop();
}
}
}
} // namespace