From e70d7c928a47798a44c07f39b8aaacf89e410633 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Thu, 11 Jun 2026 12:50:23 +0200 Subject: [PATCH 1/2] 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. --- include/etl/algorithm.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/include/etl/algorithm.h b/include/etl/algorithm.h index 91252319..57c58da2 100644 --- a/include/etl/algorithm.h +++ b/include/etl/algorithm.h @@ -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::value_type value_t; typedef typename etl::iterator_traits::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); } From b853ea5505070c741e9646334c530b775d6ac460 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Mon, 8 Jun 2026 17:55:40 +0200 Subject: [PATCH 2/2] Make ipriority_queue non-sized base class Fixes issue #1457 --- include/etl/priority_queue.h | 98 +++++++++++++++++++++++++++--------- test/etl_profile.h | 1 + test/test_priority_queue.cpp | 70 +++++++++++++++++++++++--- 3 files changed, 136 insertions(+), 33 deletions(-) diff --git a/include/etl/priority_queue.h b/include/etl/priority_queue.h index 2623fc07..ea9df835 100644 --- a/include/etl/priority_queue.h +++ b/include/etl/priority_queue.h @@ -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 + struct priority_queue_container_interface + { + ETL_STATIC_ASSERT(sizeof(TContainer) == 0, "Unsupported container type for etl::ipriority_queue"); + }; + + template + struct priority_queue_container_interface > + { + typedef etl::ivector type; + }; + + template + struct priority_queue_container_interface > + { + typedef etl::ideque 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 myPriorityQueue; /// etl::ipriority_queue& 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) /// \tparam TCompare to use in comparing T values //*************************************************************************** - template > + template , typename TCompare = etl::less > 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 TCompare = etl::less > - class priority_queue : public etl::ipriority_queue + class priority_queue : public etl::ipriority_queue::type, TCompare> { + private: + + typedef etl::ipriority_queue::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() + : base_t(container) { } @@ -504,9 +548,9 @@ namespace etl /// Copy constructor //************************************************************************* priority_queue(const priority_queue& rhs) - : etl::ipriority_queue() + : base_t(container) { - etl::ipriority_queue::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() + : base_t(container) { - etl::ipriority_queue::move(etl::move(rhs)); + base_t::move(etl::move(rhs)); } #endif @@ -528,9 +572,9 @@ namespace etl //************************************************************************* template priority_queue(TIterator first, TIterator last) - : etl::ipriority_queue() + : base_t(container) { - etl::ipriority_queue::assign(first, last); + base_t::assign(first, last); } //************************************************************************* @@ -538,7 +582,7 @@ namespace etl //************************************************************************* ~priority_queue() { - etl::ipriority_queue::clear(); + base_t::clear(); } //************************************************************************* @@ -548,7 +592,7 @@ namespace etl { if (&rhs != this) { - etl::ipriority_queue::clone(rhs); + base_t::clone(rhs); } return *this; @@ -562,13 +606,17 @@ namespace etl { if (&rhs != this) { - etl::ipriority_queue::clear(); - etl::ipriority_queue::move(etl::move(rhs)); + base_t::clear(); + base_t::move(etl::move(rhs)); } return *this; } #endif + + private: + + TContainer container; }; template diff --git a/test/etl_profile.h b/test/etl_profile.h index 6c908cf4..83ddcd7c 100644 --- a/test/etl_profile.h +++ b/test/etl_profile.h @@ -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 diff --git a/test/test_priority_queue.cpp b/test/test_priority_queue.cpp index bf5988bc..7de04c5e 100644 --- a/test/test_priority_queue.cpp +++ b/test/test_priority_queue.cpp @@ -101,7 +101,7 @@ namespace priority_queue_t* ppriority_queue = new etl::priority_queue; - etl::ipriority_queue* pipriority_queue = ppriority_queue; + etl::ipriority_queue* pipriority_queue = ppriority_queue; pipriority_queue->push(1); pipriority_queue->push(2); @@ -577,8 +577,8 @@ namespace etl::priority_queue priority_queue2; - etl::ipriority_queue>& ipriority_queue1 = priority_queue1; - etl::ipriority_queue>& ipriority_queue2 = priority_queue2; + etl::ipriority_queue& ipriority_queue1 = priority_queue1; + etl::ipriority_queue& ipriority_queue2 = priority_queue2; ipriority_queue2 = ipriority_queue1; @@ -621,9 +621,9 @@ namespace //************************************************************************* TEST(test_interface) { - typedef etl::priority_queue priority_queue_t; - priority_queue_t priority_queue; - etl::ipriority_queue& ipriority_queue = priority_queue; + typedef etl::priority_queue priority_queue_t; + priority_queue_t priority_queue; + etl::ipriority_queue& ipriority_queue = priority_queue; std::priority_queue compare_priority_queue; @@ -654,8 +654,8 @@ namespace etl::priority_queue, std::less > priority_queue2; - etl::ipriority_queue, std::less>& ipriority_queue1 = priority_queue1; - etl::ipriority_queue, std::less>& ipriority_queue2 = priority_queue2; + etl::ipriority_queue, std::less >& ipriority_queue1 = priority_queue1; + etl::ipriority_queue, std::less >& ipriority_queue2 = priority_queue2; ipriority_queue2 = ipriority_queue1; @@ -668,5 +668,59 @@ namespace priority_queue2.pop(); } } + + //************************************************************************* + TEST(test_deque_container) + { + etl::priority_queue > 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 > pq1; + pq1.push(10); + pq1.push(30); + pq1.push(20); + + etl::ipriority_queue >& ipq = pq1; + CHECK_EQUAL(3UL, ipq.size()); + CHECK_EQUAL(30, ipq.top()); + + etl::priority_queue > pq2; + etl::ipriority_queue >& ipq2 = pq2; + ipq2 = ipq; + + CHECK_EQUAL(pq1.size(), pq2.size()); + + while (!pq1.empty()) + { + CHECK_EQUAL(pq1.top(), pq2.top()); + pq1.pop(); + pq2.pop(); + } + } } } // namespace