Merge branch 'development' into feature/Add-intersect-and-union-actions-to-type_list

This commit is contained in:
John Wellbelove 2026-06-13 20:05:23 +01:00 committed by GitHub
commit 475abe4d69
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 284 additions and 47 deletions

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

@ -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