diff --git a/library.properties b/library.properties index 91f49221..2e0be5a4 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Embedded Template Library -version=9.6.0 +version=9.6.1 author= John Wellbelove maintainer=John Wellbelove sentence=A C++ template library tailored for embedded systems. diff --git a/src/intrusive_queue.h b/src/intrusive_queue.h index ca977b68..176fca44 100644 --- a/src/intrusive_queue.h +++ b/src/intrusive_queue.h @@ -126,6 +126,19 @@ namespace etl --current_size; } + //************************************************************************* + /// Removes the oldest item from the queue and pushes it to the destination. + /// Undefined behaviour if the queue is already empty. + /// NOTE: The destination must be an intrusize container that supports a push(TLink) member function. + //************************************************************************* + template + void pop_into(TContainer& destination) + { + link_type* p_link = p_front; + pop(); + destination.push(*p_link); + } + //************************************************************************* /// Clears the queue to the empty state. //************************************************************************* diff --git a/src/intrusive_stack.h b/src/intrusive_stack.h index e9482ff3..7b00af72 100644 --- a/src/intrusive_stack.h +++ b/src/intrusive_stack.h @@ -114,6 +114,39 @@ namespace etl --current_size; } + //************************************************************************* + /// Removes the oldest item from the queue and pushes it to the destination. + /// Undefined behaviour if the queue is already empty. + /// NOTE: The destination must be an intrusize container that supports a push(TLink) member function. + //************************************************************************* + template + void pop_into(TContainer& destination) + { + link_type* p_link = p_top; + pop(); + destination.push(*p_link); + } + + //************************************************************************* + /// Reverses the stack order. + //************************************************************************* + void reverse() + { + link_type* previous = nullptr; + link_type* current = p_top; + link_type* next; + + while (current != nullptr) + { + next = current->etl_next; + current->etl_next = previous; + previous = current; + current = next; + } + + p_top = previous; + } + //************************************************************************* /// Clears the stack to the empty state. //************************************************************************* diff --git a/src/queue.h b/src/queue.h index 4580a299..7e9b35fe 100644 --- a/src/queue.h +++ b/src/queue.h @@ -7,7 +7,7 @@ Embedded Template Library. https://github.com/ETLCPP/etl http://www.etlcpp.com -Copyright(c) 2014 jwellbelove +Copyright(c) 2014 jwellbelove, Mark Kitson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal @@ -157,12 +157,39 @@ namespace etl //************************************************************************* queue_base(size_type max_size) : in(0), - out(0), - current_size(0), - CAPACITY(max_size) + out(0), + current_size(0), + CAPACITY(max_size) { } + //************************************************************************* + /// Increments (and wraps) the 'in' index value to record a queue addition. + //************************************************************************* + void add_in() + { + if (++in == CAPACITY) + { + in = 0; + } + + ++current_size; + ++construct_count; + } + + //************************************************************************* + /// Decrements (and wraps) the 'out' index value to record a queue deletion. + //************************************************************************* + void del_out() + { + if (++out == CAPACITY) + { + out = 0; + } + --current_size; + --construct_count; + } + size_type in; ///< Where to input new data. size_type out; ///< Where to get the oldest data. size_type current_size; ///< The number of items in the queue. @@ -196,6 +223,7 @@ namespace etl private: typedef typename etl::parameter_type::type parameter_t; + typedef typename etl::queue_base base_t; public: @@ -246,9 +274,7 @@ namespace etl ETL_ASSERT(!full(), ETL_ERROR(queue_full)); #endif ::new (&p_buffer[in]) T(value); - in = (in == (CAPACITY - 1)) ? 0 : in + 1; - ++current_size; - ++construct_count; + base_t::add_in(); } //************************************************************************* @@ -265,10 +291,7 @@ namespace etl #if defined(ETL_CHECK_PUSH_POP) ETL_ASSERT(!full(), ETL_ERROR(queue_full)); #endif - ::new (&p_buffer[in]) T(); - in = (in == (CAPACITY - 1)) ? 0 : in + 1; - ++current_size; - ++construct_count; + base_t::add_in(); return p_buffer[next]; } @@ -285,9 +308,7 @@ namespace etl ETL_ASSERT(!full(), ETL_ERROR(queue_full)); #endif ::new (&p_buffer[in]) T(value1); - in = (in == (CAPACITY - 1)) ? 0 : in + 1; - ++current_size; - ++construct_count; + base_t::add_in(); } //************************************************************************* @@ -302,9 +323,7 @@ namespace etl ETL_ASSERT(!full(), ETL_ERROR(queue_full)); #endif ::new (&p_buffer[in]) T(value1, value2); - in = (in == (CAPACITY - 1)) ? 0 : in + 1; - ++current_size; - ++construct_count; + base_t::add_in(); } //************************************************************************* @@ -319,9 +338,7 @@ namespace etl ETL_ASSERT(!full(), ETL_ERROR(queue_full)); #endif ::new (&p_buffer[in]) T(value1, value2, value3); - in = (in == (CAPACITY - 1)) ? 0 : in + 1; - ++current_size; - ++construct_count; + base_t::add_in(); } //************************************************************************* @@ -336,9 +353,7 @@ namespace etl ETL_ASSERT(!full(), ETL_ERROR(queue_full)); #endif ::new (&p_buffer[in]) T(value1, value2, value3, value4); - in = (in == (CAPACITY - 1)) ? 0 : in + 1; - ++current_size; - ++construct_count; + base_t::add_in(); } //************************************************************************* @@ -349,9 +364,7 @@ namespace etl while (current_size > 0) { p_buffer[out].~T(); - out = (out == (CAPACITY - 1)) ? 0 : out + 1; - --current_size; - --construct_count; + base_t::del_out(); } in = 0; @@ -369,9 +382,7 @@ namespace etl ETL_ASSERT(!empty(), ETL_ERROR(queue_empty)); #endif p_buffer[out].~T(); - out = (out == (CAPACITY - 1)) ? 0 : out + 1; - --current_size; - --construct_count; + base_t::del_out(); } //************************************************************************* @@ -384,6 +395,19 @@ namespace etl pop(); } + //************************************************************************* + /// Gets the oldest value and removes it from the front of the queue and + /// pushes it to the destination container. + /// If asserts or exceptions are enabled, throws an etl::queue_empty if the queue is empty. + /// NOTE: The destination must support a push(T) member function. + //************************************************************************* + template + void pop_into(TContainer& destination) + { + destination.push(front()); + pop(); + } + //************************************************************************* /// Assignment operator. //************************************************************************* @@ -391,6 +415,7 @@ namespace etl { if (&rhs != this) { + clear(); clone(rhs); } @@ -404,6 +429,8 @@ namespace etl //************************************************************************* void clone(const iqueue& other) { + clear(); + size_t index = other.out; for (size_t i = 0; i < other.size(); ++i) diff --git a/src/stack.h b/src/stack.h index b5aabf82..d41e38b3 100644 --- a/src/stack.h +++ b/src/stack.h @@ -7,7 +7,7 @@ Embedded Template Library. https://github.com/ETLCPP/etl http://www.etlcpp.com -Copyright(c) 2014 jwellbelove +Copyright(c) 2014 jwellbelove, Mark Kitson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal @@ -163,6 +163,25 @@ namespace etl { } + //************************************************************************* + /// Increments the indexes value to record a stack addition. + //************************************************************************* + void add_in() + { + top_index = current_size++; + ++construct_count; + } + + //************************************************************************* + /// Decrements the indexes value to record a queue deletion. + //************************************************************************* + void del_out() + { + --top_index; + --current_size; + --construct_count; + } + size_type top_index; ///< The index of the top of the stack. size_type current_size; ///< The number of items in the stack. const size_type CAPACITY; ///< The maximum number of items in the stack. @@ -174,8 +193,8 @@ namespace etl ///\brief This is the base for all stacks that contain a particular type. ///\details Normally a reference to this type will be taken from a derived stack. ///\code - /// etl::stack myQueue; - /// etl::istack& iQueue = myQueue; + /// etl::stack myStack; + /// etl::istack& iStack = myStack; ///\endcode /// \warning This stack cannot be used for concurrent access from multiple threads. /// \tparam T The type of value that the stack holds. @@ -195,6 +214,7 @@ namespace etl private: typedef typename etl::parameter_type::type parameter_t; + typedef typename etl::stack_base base_t; public: @@ -217,9 +237,8 @@ namespace etl #if defined(ETL_CHECK_PUSH_POP) ETL_ASSERT(!full(), ETL_ERROR(stack_full)); #endif - top_index = current_size++; + base_t::add_in(); ::new (&p_buffer[top_index]) T(value); - ++construct_count; } //************************************************************************* @@ -233,9 +252,8 @@ namespace etl #if defined(ETL_CHECK_PUSH_POP) ETL_ASSERT(!full(), ETL_ERROR(stack_full)); #endif - top_index = current_size++; + base_t::add_in(); ::new (&p_buffer[top_index]) T(value1); - ++construct_count; } //************************************************************************* @@ -249,9 +267,8 @@ namespace etl #if defined(ETL_CHECK_PUSH_POP) ETL_ASSERT(!full(), ETL_ERROR(stack_full)); #endif - top_index = current_size++; + base_t::add_in(); ::new (&p_buffer[top_index]) T(value1, value2); - ++construct_count; } //************************************************************************* @@ -265,9 +282,8 @@ namespace etl #if defined(ETL_CHECK_PUSH_POP) ETL_ASSERT(!full(), ETL_ERROR(stack_full)); #endif - top_index = current_size++; + base_t::add_in(); ::new (&p_buffer[top_index]) T(value1, value2, value3); - ++construct_count; } //************************************************************************* @@ -281,9 +297,8 @@ namespace etl #if defined(ETL_CHECK_PUSH_POP) ETL_ASSERT(!full(), ETL_ERROR(stack_full)); #endif - top_index = current_size++; + base_t::add_in(); ::new (&p_buffer[top_index]) T(value1, value2, value3, value4); - ++construct_count; } //************************************************************************* @@ -298,9 +313,7 @@ namespace etl #if defined(ETL_CHECK_PUSH_POP) ETL_ASSERT(!full(), ETL_ERROR(stack_full)); #endif - top_index = current_size++; - ::new (&p_buffer[top_index]) T(); - ++construct_count; + base_t::add_in(); return p_buffer[top_index]; } @@ -322,9 +335,7 @@ namespace etl while (current_size > 0) { p_buffer[top_index].~T(); - --top_index; - --current_size; - --construct_count; + base_t::del_out(); } } @@ -337,9 +348,7 @@ namespace etl ETL_ASSERT(!empty(), ETL_ERROR(stack_empty)); #endif p_buffer[top_index].~T(); - --top_index; - --current_size; - --construct_count; + base_t::del_out(); } //************************************************************************* @@ -351,6 +360,26 @@ namespace etl pop(); } + //************************************************************************* + /// Removes the oldest item from the top of the stack and pushes it to the + /// destination container. + /// NOTE: The destination must support a push(T) member function. + //************************************************************************* + template + void pop_into(TContainer& destination) + { + destination.push(top()); + pop(); + } + + //************************************************************************* + /// Reverses the stack. + //************************************************************************* + void reverse() + { + std::reverse(p_buffer, p_buffer + current_size); + } + //************************************************************************* /// Assignment operator. //************************************************************************* @@ -358,6 +387,7 @@ namespace etl { if (&rhs != this) { + clear(); clone(rhs); } diff --git a/test/test_intrusive_queue.cpp b/test/test_intrusive_queue.cpp index 213fbdc0..8fd06207 100644 --- a/test/test_intrusive_queue.cpp +++ b/test/test_intrusive_queue.cpp @@ -213,6 +213,44 @@ namespace CHECK(queueC.empty()); } + //************************************************************************* + TEST(test_pop_into) + { + Data data1(1); + Data data2(2); + Data data3(3); + + etl::intrusive_queue queue1; + etl::intrusive_queue queue2; + + queue1.push(data1); + queue1.push(data2); + queue1.push(data3); + + queue1.pop_into(queue2); + CHECK_EQUAL(2U, queue1.size()); + CHECK_EQUAL(data2, queue1.front()); + + CHECK_EQUAL(1U, queue2.size()); + CHECK_EQUAL(data1, queue2.front()); + CHECK_EQUAL(data1, queue2.back()); + + queue1.pop_into(queue2); + CHECK_EQUAL(1U, queue1.size()); + CHECK_EQUAL(data3, queue1.front()); + + CHECK_EQUAL(2U, queue2.size()); + CHECK_EQUAL(data1, queue2.front()); + CHECK_EQUAL(data2, queue2.back()); + + queue1.pop_into(queue2); + CHECK_EQUAL(0U, queue1.size()); + + CHECK_EQUAL(3U, queue2.size()); + CHECK_EQUAL(data1, queue2.front()); + CHECK_EQUAL(data3, queue2.back()); + } + //************************************************************************* TEST(test_front_const) { diff --git a/test/test_intrusive_stack.cpp b/test/test_intrusive_stack.cpp index eec9802e..7d595d7c 100644 --- a/test/test_intrusive_stack.cpp +++ b/test/test_intrusive_stack.cpp @@ -202,6 +202,41 @@ namespace CHECK(stackC.empty()); } + //************************************************************************* + TEST(test_pop_into) + { + Data data1(1); + Data data2(2); + Data data3(3); + + etl::intrusive_stack stack1; + etl::intrusive_stack stack2; + + stack1.push(data1); + stack1.push(data2); + stack1.push(data3); + + stack1.pop_into(stack2); + CHECK_EQUAL(2U, stack1.size()); + CHECK_EQUAL(data2, stack1.top()); + + CHECK_EQUAL(1U, stack2.size()); + CHECK_EQUAL(data3, stack2.top()); + + stack1.pop_into(stack2); + CHECK_EQUAL(1U, stack1.size()); + CHECK_EQUAL(data1, stack1.top()); + + CHECK_EQUAL(2U, stack2.size()); + CHECK_EQUAL(data2, stack2.top()); + + stack1.pop_into(stack2); + CHECK_EQUAL(0U, stack1.size()); + + CHECK_EQUAL(3U, stack2.size()); + CHECK_EQUAL(data1, stack2.top()); + } + //************************************************************************* TEST(test_top_const) { @@ -222,5 +257,56 @@ namespace stackD.pop(); CHECK_EQUAL(stackD.top(), stackDR.top()); } + + //************************************************************************* + TEST(test_reverse1) + { + Data data1(1); + + etl::intrusive_stack stack; + + stack.push(data1); + + stack.reverse(); + + CHECK_EQUAL(1U, stack.size()); + CHECK_EQUAL(stack.top(), data1); + } + + //************************************************************************* + TEST(test_reverse5) + { + Data data1(1); + Data data2(2); + Data data3(3); + Data data4(4); + Data data5(5); + + etl::intrusive_stack stack; + + stack.push(data1); + stack.push(data2); + stack.push(data3); + stack.push(data4); + stack.push(data5); + + stack.reverse(); + + CHECK_EQUAL(5U, stack.size()); + + CHECK_EQUAL(stack.top(), data1); + stack.pop(); + + CHECK_EQUAL(stack.top(), data2); + stack.pop(); + + CHECK_EQUAL(stack.top(), data3); + stack.pop(); + + CHECK_EQUAL(stack.top(), data4); + stack.pop(); + + CHECK_EQUAL(stack.top(), data5); + } }; } diff --git a/test/test_queue.cpp b/test/test_queue.cpp index c9724135..16cdbced 100644 --- a/test/test_queue.cpp +++ b/test/test_queue.cpp @@ -353,15 +353,65 @@ namespace queue.pop_into(i); CHECK_EQUAL(1, i); + CHECK_EQUAL(3U, queue.size()); queue.pop_into(i); CHECK_EQUAL(2, i); + CHECK_EQUAL(2U, queue.size()); queue.pop_into(i); CHECK_EQUAL(3, i); + CHECK_EQUAL(1U, queue.size()); queue.pop_into(i); CHECK_EQUAL(4, i); + CHECK_EQUAL(0U, queue.size()); + } + + //************************************************************************* + TEST(test_pop_into_queue) + { + etl::queue queue1; + etl::queue queue2; + + queue1.push(1); + queue1.push(2); + queue1.push(3); + queue1.push(4); + + queue1.pop_into(queue2); + CHECK_EQUAL(1U, queue2.size()); + CHECK_EQUAL(1, queue2.front()); + CHECK_EQUAL(1, queue2.back()); + + queue1.pop_into(queue2); + CHECK_EQUAL(2U, queue2.size()); + CHECK_EQUAL(1, queue2.front()); + CHECK_EQUAL(2, queue2.back()); + + queue1.pop_into(queue2); + CHECK_EQUAL(3U, queue2.size()); + CHECK_EQUAL(1, queue2.front()); + CHECK_EQUAL(3, queue2.back()); + + queue1.pop_into(queue2); + CHECK_EQUAL(4U, queue2.size()); + CHECK_EQUAL(1, queue2.front()); + CHECK_EQUAL(4, queue2.back()); + + int i; + + queue2.pop_into(i); + CHECK_EQUAL(1, i); + + queue2.pop_into(i); + CHECK_EQUAL(2, i); + + queue2.pop_into(i); + CHECK_EQUAL(3, i); + + queue2.pop_into(i); + CHECK_EQUAL(4, i); } //************************************************************************* diff --git a/test/test_stack.cpp b/test/test_stack.cpp index 49e352ce..49a5da9c 100644 --- a/test/test_stack.cpp +++ b/test/test_stack.cpp @@ -228,24 +228,70 @@ namespace { etl::stack stack; - int i; - stack.push(1); stack.push(2); stack.push(3); stack.push(4); + int i; + stack.pop_into(i); CHECK_EQUAL(4, i); + CHECK_EQUAL(3U, stack.size()); stack.pop_into(i); CHECK_EQUAL(3, i); + CHECK_EQUAL(2U, stack.size()); stack.pop_into(i); CHECK_EQUAL(2, i); + CHECK_EQUAL(1U, stack.size()); stack.pop_into(i); CHECK_EQUAL(1, i); + CHECK_EQUAL(0U, stack.size()); + } + + //************************************************************************* + TEST(test_pop_into_stack) + { + etl::stack stack1; + etl::stack stack2; + + stack1.push(1); + stack1.push(2); + stack1.push(3); + stack1.push(4); + + stack1.pop_into(stack2); + CHECK_EQUAL(1U, stack2.size()); + CHECK_EQUAL(4, stack2.top()); + + stack1.pop_into(stack2); + CHECK_EQUAL(2U, stack2.size()); + CHECK_EQUAL(3, stack2.top()); + + stack1.pop_into(stack2); + CHECK_EQUAL(3U, stack2.size()); + CHECK_EQUAL(2, stack2.top()); + + stack1.pop_into(stack2); + CHECK_EQUAL(4U, stack2.size()); + CHECK_EQUAL(1, stack2.top()); + + int i; + + stack2.pop_into(i); + CHECK_EQUAL(1, i); + + stack2.pop_into(i); + CHECK_EQUAL(2, i); + + stack2.pop_into(i); + CHECK_EQUAL(3, i); + + stack2.pop_into(i); + CHECK_EQUAL(4, i); } //************************************************************************* @@ -447,5 +493,32 @@ namespace CHECK_EQUAL(1, stack.top()); stack.pop(); } + + //************************************************************************* + TEST(test_reverse) + { + etl::stack stack; + + stack.push(1); + stack.push(2); + stack.push(3); + stack.push(4); + + stack.reverse(); + + int i; + + stack.pop_into(i); + CHECK_EQUAL(1, i); + + stack.pop_into(i); + CHECK_EQUAL(2, i); + + stack.pop_into(i); + CHECK_EQUAL(3, i); + + stack.pop_into(i); + CHECK_EQUAL(4, i); + } }; }