diff --git a/src/intrusive_queue.h b/src/intrusive_queue.h new file mode 100644 index 00000000..6889d784 --- /dev/null +++ b/src/intrusive_queue.h @@ -0,0 +1,256 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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_INTRUSIVE_QUEUE__ +#define __ETL_INTRUSIVE_QUEUE__ + +#error In Development. Do not use. + +#include + +#include "type_traits.h" +#include "error_handler.h" +#include "intrusive_links.h" +#include "private/counter_type.h" + +namespace etl +{ + //*************************************************************************** + /// Exception base for intrusive queue + ///\ingroup intrusive_queue + //*************************************************************************** + class intrusive_queue_exception : public etl::exception + { + public: + + intrusive_queue_exception(string_type what, string_type file_name, numeric_type line_number) + : exception(what, file_name, line_number) + { + } + }; + + //*************************************************************************** + /// intrusive_queue empty exception. + ///\ingroup intrusive_queue + //*************************************************************************** + class intrusive_queue_empty : public intrusive_queue_exception + { + public: + + intrusive_queue_empty(string_type file_name, numeric_type line_number) + : intrusive_queue_exception(ETL_ERROR_TEXT("intrusive_queue:empty", ETL_FILE"A"), file_name, line_number) + { + } + }; + + //*************************************************************************** + ///\ingroup queue + /// An intrusive queue. Stores elements derived from etl::forward_link + /// \warning This queue cannot be used for concurrent access from multiple threads. + /// \tparam TValue The type of value that the queue holds. + /// \tparam TLink The link type that the value is derived from. + //*************************************************************************** + template + class intrusive_queue + { + public: + + // Node typedef. + typedef TLink link_type; + + // STL style typedefs. + typedef TValue value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef size_t size_type; + + enum + { + // The count option is based on the type of link. + COUNT_OPTION = ((TLink::OPTION == etl::link_option::AUTO) || (TLink::OPTION == etl::link_option::CHECKED)) ? + etl::count_option::SLOW_COUNT : + etl::count_option::FAST_COUNT + }; + + //************************************************************************* + /// Constructor + //************************************************************************* + intrusive_queue() + : p_front(nullptr), + p_back(nullptr) + { + } + + //************************************************************************* + /// Gets a reference to the value at the front of the queue. + /// Undefined behaviour if the queue is empty. + /// \return A reference to the value at the front of the queue. + //************************************************************************* + reference front() + { + return *static_cast(p_front); + } + + //************************************************************************* + /// Gets a reference to the value at the back of the queue. + /// Undefined behaviour if the queue is empty. + /// \return A reference to the value at the back of the queue. + //************************************************************************* + reference back() + { + return *static_cast(p_back); + } + + //************************************************************************* + /// Gets a const reference to the value at the front of the queue. + /// Undefined behaviour if the queue is empty. + /// \return A const reference to the value at the front of the queue. + //************************************************************************* + const_reference front() const + { + return *static_cast(p_front); + } + + //************************************************************************* + /// Gets a reference to the value at the back of the queue. + /// Undefined behaviour if the queue is empty. + /// \return A reference to the value at the back of the queue. + //************************************************************************* + const_reference back() const + { + return *static_cast(p_back); + } + + //************************************************************************* + /// Adds a value to the queue. + ///\param value The value to push to the queue. + //************************************************************************* + void push(link_type& value) + { + if (p_back != nullptr) + { + etl::link(p_front, value); + } + else + { + p_front = &value; + } + + p_back = &value; + + ++current_size; + } + + //************************************************************************* + /// Removes the oldest item from the queue. + /// Undefined behaviour if the queue is already empty. + //************************************************************************* + void pop() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!empty(), ETL_ERROR(intrusive_queue_empty)); +#endif + link_type* p_next = p_front->etl_next; + p_front->clear(); + p_front = p_next; + + // Now empty? + if (p_front == nullptr) + { + p_back == nullptr; + } + + --current_size; + } + + //************************************************************************* + /// Clears the queue to the empty state. + //************************************************************************* + void clear() + { + while (!empty()) + { + pop(); + } + current_size = 0; + } + + //************************************************************************* + /// Checks if the queue is in the empty state. + //************************************************************************* + bool empty() const + { + return p_front == nullptr; + } + + //************************************************************************* + /// Returns the number of elements. + //************************************************************************* + size_t size() const + { + if (COUNT_OPTION == etl::count_option::SLOW_COUNT) + { + size_t count = 0; + + if (p_front != nullptr) + { + link_type* p_link = p_front; + + while (p_link != nullptr) + { + ++count; + p_link = p_link->etl_next; + } + } + + return count; + } + else + { + return current_size.get_count(); + } + } + + private: + + // Disable copy construction and assignment. + intrusive_queue(const intrusive_queue&); + intrusive_queue& operator = (const intrusive_queue& rhs); + + link_type* p_front; // The current front of the queue. + link_type* p_back; // The current back of the queue. + + etl::counter_type current_size; ///< Counts the number of elements in the list. + }; +} + +#endif