diff --git a/basic_intrusive_forward_list.h b/basic_intrusive_forward_list.h new file mode 100644 index 00000000..66bce0a6 --- /dev/null +++ b/basic_intrusive_forward_list.h @@ -0,0 +1,577 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl + +Copyright(c) 2015 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. +******************************************************************************/ + +//***************************************************************************** +// This forward list is intended for internal library use. +// It may be used as a very low cost intrusive forward list. +// Elements in the list are accessed as basic_intrusive_forward_list_node. +// Code using this list will be required to cast to the real data type. +// etl::basic_intrusive_forward_list will throw no exceptions or errors. +//***************************************************************************** + +#ifndef __ETL_BASIC_INTRUSIVE_FORWARD_LIST__ +#define __ETL_BASIC_INTRUSIVE_FORWARD_LIST__ + +#include +#include + +#include "nullptr.h" +#include "type_traits.h" +#include "basic_intrusive_forward_list_node.h" + +namespace etl +{ + //*************************************************************************** + /// An intrusive forward list. + ///\ingroup basic_intrusive_forward_list + //*************************************************************************** + class basic_intrusive_forward_list + { + public: + + // Node typedef. + typedef basic_intrusive_forward_list_node node_t; + + // STL style typedefs. + typedef node_t value_type; + typedef node_t* pointer; + typedef const node_t* const_pointer; + typedef node_t& reference; + typedef const node_t& const_reference; + typedef size_t size_type; + + public: + + //************************************************************************* + /// iterator. + //************************************************************************* + class iterator : public std::iterator + { + public: + + friend class basic_intrusive_forward_list; + + iterator() + : p_node(nullptr) + { + } + + iterator(node_t& node) + : p_node(&node) + { + } + + iterator(const iterator& other) + : p_node(other.p_node) + { + } + + iterator& operator ++() + { + p_node = p_node->next; + return *this; + } + + iterator operator ++(int) + { + iterator temp(*this); + p_node = p_node->next; + return temp; + } + + iterator operator =(const iterator& other) + { + p_node = other.p_node; + return *this; + } + + reference operator *() + { + return *p_node; + } + + const_reference operator *() const + { + return *p_node; + } + + pointer operator &() + { + return p_node; + } + + const_pointer operator &() const + { + return p_node; + } + + pointer operator ->() + { + return p_node; + } + + const_pointer operator ->() const + { + return p_node; + } + + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.p_node == rhs.p_node; + } + + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + template + T& ref_cast() + { + return static_cast(*p_node); + } + + template + const T& ref_cast() const + { + return static_cast(*p_node); + } + + private: + + node_t* p_node; + }; + + //************************************************************************* + /// const_iterator + //************************************************************************* + class const_iterator : public std::iterator + { + public: + + friend class basic_intrusive_forward_list; + + const_iterator() + : p_node(nullptr) + { + } + + const_iterator(node_t& node) + : p_node(&node) + { + } + + const_iterator(const node_t& node) + : p_node(&node) + { + } + + const_iterator(const basic_intrusive_forward_list::iterator& other) + : p_node(other.p_node) + { + } + + const_iterator(const const_iterator& other) + : p_node(other.p_node) + { + } + + const_iterator& operator ++() + { + p_node = p_node->next; + return *this; + } + + const_iterator operator ++(int) + { + const_iterator temp(*this); + p_node = p_node->next; + return temp; + } + + const_iterator operator =(const const_iterator& other) + { + p_node = other.p_node; + return *this; + } + + const_reference operator *() const + { + return *p_node; + } + + const_pointer operator &() const + { + return p_node; + } + + const_pointer operator ->() const + { + return p_node; + } + + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.p_node == rhs.p_node; + } + + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + template + const T& ref_cast() const + { + return static_cast(*p_node); + } + + private: + + const node_t* p_node; + }; + + typedef std::iterator_traits::difference_type difference_type; + + //************************************************************************* + /// Constructor. + //************************************************************************* + basic_intrusive_forward_list() + { + initialise(); + } + + //************************************************************************* + /// Constructor from range + //************************************************************************* + template + basic_intrusive_forward_list(TIterator first, TIterator last) + { + assign(first, last); + } + + //************************************************************************* + /// Gets the beginning of the basic_intrusive_forward_list. + //************************************************************************* + iterator begin() + { + return iterator(get_head()); + } + + //************************************************************************* + /// Gets the beginning of the basic_intrusive_forward_list. + //************************************************************************* + const_iterator begin() const + { + return const_iterator(get_head()); + } + + //************************************************************************* + /// Gets before the beginning of the basic_intrusive_forward_list. + //************************************************************************* + iterator before_begin() + { + return iterator(start_node); + } + + //************************************************************************* + /// Gets before the beginning of the basic_intrusive_forward_list. + //************************************************************************* + const_iterator before_begin() const + { + return const_iterator(start_node); + } + + //************************************************************************* + /// Gets the beginning of the basic_intrusive_forward_list. + //************************************************************************* + const_iterator cbegin() const + { + return const_iterator(get_head()); + } + + //************************************************************************* + /// Gets the end of the basic_intrusive_forward_list. + //************************************************************************* + iterator end() + { + return iterator(); + } + + //************************************************************************* + /// Gets the end of the basic_intrusive_forward_list. + //************************************************************************* + const_iterator end() const + { + return const_iterator(); + } + + //************************************************************************* + /// Gets the end of the basic_intrusive_forward_list. + //************************************************************************* + const_iterator cend() const + { + return const_iterator(); + } + + //************************************************************************* + /// Clears the basic_intrusive_forward_list. + //************************************************************************* + void clear() + { + initialise(); + } + + //************************************************************************* + /// Gets a reference to the first element. + //************************************************************************* + template + T& front() + { + return static_cast(get_head()); + } + + //************************************************************************* + /// Gets a const reference to the first element. + //************************************************************************* + template + const_reference front() const + { + return static_cast(get_head()); + } + + //************************************************************************* + /// Assigns a range of values to the basic_intrusive_forward_list. + //************************************************************************* + template + void assign(TIterator first, TIterator last) + { + initialise(); + + node_t* p_last_node = &start_node; + + // Add all of the elements. + while (first != last) + { + node_t& node = *first++; + join(p_last_node, &node); + join(&node, nullptr); + p_last_node = &node; + } + } + + //************************************************************************* + /// Pushes a value to the front of the basic_intrusive_forward_list. + //************************************************************************* + void push_front(node_t& value) + { + insert_node_after(start_node, value); + } + + //************************************************************************* + /// Removes a value from the front of the basic_intrusive_forward_list. + //************************************************************************* + void pop_front() + { + if (!empty()) + { + remove_node_after(start_node); + } + } + + //************************************************************************* + /// Reverses the basic_intrusive_forward_list. + //************************************************************************* + void reverse() + { + if ((start_node.next == nullptr) || (start_node.next->next == nullptr)) + { + return; + } + + node_t* first = nullptr; // To keep first node + node_t* second = start_node.next; // To keep second node + node_t* track = start_node.next; // Track the list + + while (track != NULL) + { + track = track->next; // Track point to next node; + second->next = first; // Second node point to first + first = second; // Move first node to next + second = track; // Move second node to next + } + + join(&start_node, first); + } + + //************************************************************************* + /// Inserts a value to the basic_intrusive_forward_list after the specified position. + //************************************************************************* + iterator insert_after(iterator position, node_t& value) + { + insert_node_after(*position.p_node, value); + + return iterator(value); + } + + //************************************************************************* + /// Inserts a range of values to the basic_intrusive_forward_list after the specified position. + //************************************************************************* + template + void insert_after(iterator position, TIterator first, TIterator last) + { + while (first != last) + { + // Set up the next free node. + insert_node_after(*position.p_node, *first++); + ++position; + } + } + + //************************************************************************* + /// Erases the value at the specified position. + //************************************************************************* + iterator erase_after(iterator position) + { + iterator next(position); + ++next; + ++next; + + remove_node_after(*position.p_node); + + return next; + } + + //************************************************************************* + /// Erases a range of elements. + //************************************************************************* + iterator erase_after(iterator first, iterator last) + { + node_t* p_first = first.p_node; + node_t* p_last = last.p_node; + node_t* p_next = p_first->next; + + // Join the ends. + join(p_first, p_last); + + p_first = p_next; + + // Erase the ones in between. + while (p_first != p_last) + { + p_next = p_first->next; // Remember the next node. + p_first = p_next; // Move to the next node. + } + + if (p_next == nullptr) + { + return end(); + } + else + { + return iterator(*p_last); + } + } + + //************************************************************************* + /// Returns true if the list has no elements. + //************************************************************************* + bool empty() const + { + return start_node.next == nullptr; + } + + private: + + node_t start_node; ///< The node that acts as the basic_intrusive_forward_list start. + + //************************************************************************* + /// Join two nodes. + //************************************************************************* + void join(node_t* left, node_t* right) + { + left->next = right; + } + + //************************************************************************* + /// Insert a node. + //************************************************************************* + void insert_node_after(node_t& position, node_t& node) + { + // Connect to the basic_intrusive_forward_list. + join(&node, position.next); + join(&position, &node); + } + + //************************************************************************* + /// Remove a node. + //************************************************************************* + void remove_node_after(node_t& node) + { + // The node to erase. + node_t* p_node = node.next; + + if (p_node != nullptr) + { + // Disconnect the node from the basic_intrusive_forward_list. + join(&node, p_node->next); + } + } + + //************************************************************************* + /// Get the head node. + //************************************************************************* + node_t& get_head() + { + return *start_node.next; + } + + //************************************************************************* + /// Get the head node. + //************************************************************************* + const node_t& get_head() const + { + return *start_node.next; + } + + //************************************************************************* + /// Initialise the basic_intrusive_forward_list. + //************************************************************************* + void initialise() + { + start_node.next = nullptr; + } + + // Disabled. + basic_intrusive_forward_list(const basic_intrusive_forward_list& other); + basic_intrusive_forward_list& operator = (const basic_intrusive_forward_list& rhs); + }; +} + +#endif diff --git a/basic_intrusive_forward_list_node.h b/basic_intrusive_forward_list_node.h new file mode 100644 index 00000000..2de530cd --- /dev/null +++ b/basic_intrusive_forward_list_node.h @@ -0,0 +1,45 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl + +Copyright(c) 2015 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_BASIC_INTRUSIVE_FORWARD_LIST_NODE__ +#define __ETL_BASIC_INTRUSIVE_FORWARD_LIST_NODE__ + +namespace etl +{ + //*************************************************************************** + /// The node element in the basic_intrusive_forward_list. + /// Derive intrusive node data elements from this. + //*************************************************************************** + struct basic_intrusive_forward_list_node + { + basic_intrusive_forward_list_node* next; + }; +} + +#endif diff --git a/bitset.h b/bitset.h index f6d5dbc1..8b0ed1aa 100644 --- a/bitset.h +++ b/bitset.h @@ -33,20 +33,12 @@ SOFTWARE. #include #include #include -#include #include #include "integral_limits.h" -#include "smallest.h" -#include "array.h" #include "nullptr.h" #include "log.h" #include "ibitset.h" -#include "binary.h" - -#if WIN32 -#undef min -#endif #if defined(COMPILER_KEIL) #pragma diag_suppress 1300 @@ -70,501 +62,22 @@ namespace etl template class bitset : public ibitset { - // The type used for each element in the array. - typedef typename smallest_uint_for_bits::type element_t; - static const element_t ALL_SET = etl::integral_limits::max; - static const element_t ALL_CLEAR = 0; - static const size_t BITS_PER_ELEMENT = etl::integral_limits::bits; - static const size_t ARRAY_SIZE = (N % BITS_PER_ELEMENT == 0) ? N / BITS_PER_ELEMENT : N / BITS_PER_ELEMENT + 1; + static const size_t ARRAY_SIZE = (N % BITS_PER_ELEMENT == 0) ? N / BITS_PER_ELEMENT : N / BITS_PER_ELEMENT + 1; public: - static const size_t TOTAL_BITS = ARRAY_SIZE * BITS_PER_ELEMENT; - - private: - - static const size_t TOP_MASK_SHIFT = ((BITS_PER_ELEMENT - (TOTAL_BITS - N)) % BITS_PER_ELEMENT); - static const element_t TOP_MASK = element_t(TOP_MASK_SHIFT == 0 ? ALL_SET : ~(ALL_SET << TOP_MASK_SHIFT)); + static const size_t ALLOCATED_BITS = ARRAY_SIZE * BITS_PER_ELEMENT; public: - //************************************************************************* - /// The reference type returned. - //************************************************************************* - class bit_reference - { - public: - friend class bitset; - - //******************************* - /// Conversion operator. - //******************************* - operator bool() const - { - return p_bitset->test(position); - } - - //******************************* - /// Assignment operator. - //******************************* - bit_reference& operator = (bool b) - { - p_bitset->set(position, b); - return *this; - } - - //******************************* - /// Assignment operator. - //******************************* - bit_reference& operator = (const bit_reference& r) - { - p_bitset->set(position, bool(r)); - return *this; - } - - //******************************* - /// Flip the bit. - //******************************* - bit_reference& flip() - { - p_bitset->flip(position); - return *this; - } - - //******************************* - /// Return the logical inverse of the bit. - //******************************* - bool operator~() const - { - return !p_bitset->test(position); - } - - private: - - //******************************* - /// Default constructor. - //******************************* - bit_reference() - : p_bitset(nullptr), - position(0) - { - } - - //******************************* - /// Constructor. - //******************************* - bit_reference(bitset& r_bitset, size_t position) - : p_bitset(&r_bitset), - position(position) - { - } - - bitset* p_bitset; ///< The bitset. - size_t position; ///< The position in the bitset. - }; - - //************************************************************************* - /// The iterator type. - //************************************************************************* - class iterator : public std::iterator - { - public: - - friend class bitset; - friend class const_iterator; - - //******************************* - /// Constructor - //******************************* - iterator() - : position(0) - { - } - - //******************************* - /// Copy constructor - //******************************* - iterator(const iterator& other) - : position(other.position) - { - } - - //******************************* - /// ++ operator (pre) - //******************************* - iterator& operator ++() - { - ++position; - return *this; - } - - //******************************* - /// ++ operator (post) - //******************************* - iterator operator ++(int) - { - iterator temp(*this); - ++position; - return temp; - } - - //******************************* - /// -- operator (pre) - //******************************* - iterator& operator --() - { - --position; - return *this; - } - - //******************************* - /// -- operator (post) - //******************************* - iterator operator --(int) - { - iterator temp(*this); - --position; - return temp; - } - - //******************************* - /// * operator - //******************************* - bit_reference operator *() - { - return bit_reference(*p_bitset, position); - } - - //******************************* - /// * operator const - //******************************* - bool operator *() const - { - return p_bitset->test(position); - } - - //******************************* - /// += operator - //******************************* - iterator& operator +=(int i) - { - position += i; - return *this; - } - - //******************************* - /// -= operator - //******************************* - iterator& operator -=(int i) - { - position -= i; - return *this; - } - - //******************************* - /// = operator - //******************************* - iterator& operator =(const iterator& other) - { - position = other.position; - p_bitset = other.p_bitset; - return *this; - } - - //******************************* - /// + operator - //******************************* - friend iterator operator +(const iterator& other, int i) - { - iterator temp(other); - temp += i; - return temp; - } - - //******************************* - /// - operator - //******************************* - friend iterator operator -(const iterator& other, int i) - { - iterator temp(other); - temp -= i; - return temp; - } - - //******************************* - /// - operator - //******************************* - friend long operator -(const iterator& lhs, const iterator& rhs) - { - return long(lhs.position) - long(rhs.position); - } - - //******************************* - /// == operator - //******************************* - friend bool operator ==(const iterator& lhs, const iterator& rhs) - { - return lhs.position == rhs.position; - } - - //******************************* - /// != operator - //******************************* - friend bool operator !=(const iterator& lhs, const iterator& rhs) - { - return lhs.position != rhs.position; - } - - //******************************* - /// < operator - //******************************* - friend bool operator <(const iterator& lhs, const iterator& rhs) - { - return lhs.position < rhs.position; - } - - //******************************* - /// > operator - //******************************* - friend bool operator >(const iterator& lhs, const iterator& rhs) - { - return lhs.position > rhs.position; - } - - //******************************* - /// <= operator - //******************************* - friend bool operator <=(const iterator& lhs, const iterator& rhs) - { - return lhs.position <= rhs.position; - } - - //******************************* - /// >= operator - //******************************* - friend bool operator >=(const iterator& lhs, const iterator& rhs) - { - return lhs.position >-rhs.position; - } - - private: - - //******************************* - /// Constructor - //******************************* - iterator(bitset& r_bitset, size_t position) - : p_bitset(&r_bitset), - position(position) - {} - - bitset* p_bitset; - size_t position; - }; - - //************************************************************************* - /// The const_iterator type. - //************************************************************************* - class const_iterator : public std::iterator - { - public: - - friend class bitset; - - //******************************* - /// Constructor - //******************************* - const_iterator() - : position(0) - { - } - - //******************************* - /// Copy constructor from iterator - //******************************* - const_iterator(const typename bitset::iterator& other) - : position(other.position) - { - } - - //******************************* - /// Copy constructor - //******************************* - const_iterator(const const_iterator& other) - : position(other.position) - { - } - - //******************************* - /// ++ operator (pre) - //******************************* - const_iterator& operator ++() - { - ++position; - return *this; - } - - //******************************* - /// ++ operator (post) - //******************************* - const_iterator operator ++(int) - { - const_iterator temp(*this); - ++position; - return temp; - } - - //******************************* - /// -- operator (pre) - //******************************* - const_iterator& operator --() - { - --position; - return *this; - } - - //******************************* - /// -- operator (post) - //******************************* - const_iterator operator --(int) - { - const_iterator temp(*this); - --position; - return temp; - } - - //******************************* - /// * operator const - //******************************* - bool operator *() const - { - return p_bitset->test(position); - } - - //******************************* - /// += operator - //******************************* - const_iterator& operator +=(int i) - { - position += i; - return *this; - } - - //******************************* - /// -= operator - //******************************* - const_iterator& operator -=(int i) - { - position -= i; - return *this; - } - - //******************************* - /// = operator - //******************************* - const_iterator& operator =(const const_iterator& other) - { - position = other.position; - p_bitset = other.p_bitset; - return *this; - } - - //******************************* - /// + operator - //******************************* - friend const_iterator operator +(const const_iterator& other, int i) - { - const_iterator temp(other); - temp += i; - return temp; - } - - //******************************* - /// - operator - //******************************* - friend const_iterator operator -(const const_iterator& other, int i) - { - const_iterator temp(other); - temp -= i; - return temp; - } - - //******************************* - /// - operator - //******************************* - friend long operator -(const const_iterator& lhs, const const_iterator& rhs) - { - return long(lhs.position) - long(rhs.position); - } - - //******************************* - /// == operator - //******************************* - friend bool operator ==(const const_iterator& lhs, const const_iterator& rhs) - { - return lhs.position == rhs.position; - } - - //******************************* - /// != operator - //******************************* - friend bool operator !=(const const_iterator& lhs, const const_iterator& rhs) - { - return lhs.position != rhs.position; - } - - //******************************* - /// < operator - //******************************* - friend bool operator <(const const_iterator& lhs, const const_iterator& rhs) - { - return lhs.position < rhs.position; - } - - //******************************* - /// > operator - //******************************* - friend bool operator >(const const_iterator& lhs, const const_iterator& rhs) - { - return lhs.position > rhs.position; - } - - //******************************* - /// <= operator - //******************************* - friend bool operator <=(const const_iterator& lhs, const const_iterator& rhs) - { - return lhs.position <= rhs.position; - } - - //******************************* - /// >= operator - //******************************* - friend bool operator >=(const const_iterator& lhs, const const_iterator& rhs) - { - return lhs.position >- rhs.position; - } - - private: - - //******************************* - /// Constructor - //******************************* - const_iterator(bitset& r_bitset, size_t position) - : p_bitset(&r_bitset), - position(position) - { - } - - bitset* p_bitset; - size_t position; - }; //************************************************************************* /// Default constructor. //************************************************************************* bitset() + : ibitset(N, ARRAY_SIZE, data) { reset(); } @@ -573,14 +86,16 @@ namespace etl /// Copy constructor. //************************************************************************* bitset(const bitset& other) + : ibitset(N, ARRAY_SIZE, data) { - data = other.data; + std::copy(other.data, other.data + ARRAY_SIZE, data); } //************************************************************************* /// Construct from a value. //************************************************************************* bitset(unsigned long long value) + : ibitset(N, ARRAY_SIZE, data) { reset(); @@ -602,22 +117,16 @@ namespace etl } } - data.back() &= TOP_MASK; + data[ARRAY_SIZE - 1] &= TOP_MASK; } //************************************************************************* /// Construct from a string. //************************************************************************* bitset(const char* text) + : ibitset(N, ARRAY_SIZE, data) { - reset(); - - size_t i = std::min(N, strlen(text)); - - while (i > 0) - { - set(--i, *text++ == '1'); - } + set(text); } //************************************************************************* @@ -625,9 +134,7 @@ namespace etl //************************************************************************* bitset& set() { - data.fill(ALL_SET); - data.back() &= TOP_MASK; - + ibitset::set(); return *this; } @@ -636,32 +143,7 @@ namespace etl //************************************************************************* bitset& set(size_t position, bool value = true) { - if (position < N) - { - size_t index; - element_t bit; - - if (ARRAY_SIZE == 1) - { - index = 0; - bit = element_t(1) << position; - } - else - { - index = position >> log2::value; - bit = element_t(1) << (position & (BITS_PER_ELEMENT - 1)); - } - - if (value) - { - data[index] |= bit; - } - else - { - data[index] &= ~bit; - } - } - + ibitset::set(position, value); return *this; } @@ -670,15 +152,7 @@ namespace etl //************************************************************************* bitset& set(const char* text) { - reset(); - - size_t i = std::min(N, strlen(text)); - - while (i > 0) - { - set(--i, *text++ == '1'); - } - + ibitset::set(text); return *this; } @@ -687,7 +161,7 @@ namespace etl //************************************************************************* bitset& reset() { - data.fill(ALL_CLEAR); + ibitset::reset(); return *this; } @@ -696,25 +170,7 @@ namespace etl //************************************************************************* bitset& reset(size_t position) { - if (position < N) - { - size_t index; - element_t bit; - - if (ARRAY_SIZE == 1) - { - index = 0; - bit = element_t(1) << position; - } - else - { - index = position >> log2::value; - bit = element_t(1) << (position & (BITS_PER_ELEMENT - 1)); - } - - data[index] &= ~bit; - } - + ibitset::reset(position); return *this; } @@ -723,13 +179,7 @@ namespace etl //************************************************************************* bitset& flip() { - for (size_t i = 0; i < ARRAY_SIZE; ++i) - { - data[i] = ~data[i]; - } - - data.back() &= TOP_MASK; - + ibitset::flip(); return *this; } @@ -738,216 +188,21 @@ namespace etl //************************************************************************* bitset& flip(size_t position) { - if (position < N) - { - size_t index; - element_t bit; - - if (ARRAY_SIZE == 1) - { - index = 0; - bit = element_t(1) << position; - } - else - { - index = position >> log2::value; - bit = element_t(1) << (position & (BITS_PER_ELEMENT - 1)); - } - - data[index] ^= bit; - } - + ibitset::flip(position); return *this; } //************************************************************************* - /// Read [] operator. + /// operator = //************************************************************************* - bool operator[] (size_t position) const - { - return test(position); - } - - //************************************************************************* - /// Write [] operator. - //************************************************************************* - bit_reference operator [] (size_t position) - { - return bit_reference(*this, position); - } - - //************************************************************************* - /// Tests a bit at a position. - /// Positions greater than the number of configured bits will return false. - //************************************************************************* - bool test(size_t position) const - { - if (position < N) - { - size_t index; - element_t mask; - - if (ARRAY_SIZE == 1) - { - index = 0; - mask = element_t(1) << position; - } - else - { - index = position >> log2::value; - mask = element_t(1) << (position & (BITS_PER_ELEMENT - 1)); - } - - return (data[index] & mask) != 0; - } - else - { - return false; - } - } - - //************************************************************************* - // Are all the bits sets? - //************************************************************************* - bool all() const - { - // All but the last. - for (size_t i = 0; i < (ARRAY_SIZE - 1); ++i) - { - if (data[i] != ALL_SET) - { - return false; - } - } - - // The last. - if (data[ARRAY_SIZE - 1] != (ALL_SET & TOP_MASK)) - { - return false; - } - - return true; - } - - //************************************************************************* - /// Are any of the bits set? - //************************************************************************* - bool any() const - { - return !none(); - } - - //************************************************************************* - /// Are none of the bits set? - //************************************************************************* - bool none() const + bitset& operator =(const bitset& other) { for (size_t i = 0; i < ARRAY_SIZE; ++i) { - if (data[i] != 0) - { - return false; - } + data[i] = other.data[i]; } - return true; - } - - //************************************************************************* - /// Count the number of bits set. - //************************************************************************* - size_t count() const - { - size_t n = 0; - - for (size_t i = 0; i < ARRAY_SIZE; ++i) - { - n += etl::count_bits(data[i]); - } - - return n; - } - - //************************************************************************* - /// The size of the bitset. - //************************************************************************* - size_t size() const - { - return N; - } - - //************************************************************************* - /// Finds the first bit in the specified state. - ///\param state The state to search for. - ///\returns The position of the bit or size() if none were found. - //************************************************************************* - size_t find_first(bool state) const - { - return find_next(state, 0); - } - - //************************************************************************* - /// Finds the next bit in the specified state. - ///\param state The state to search for. - ///\param position The position to start from. - ///\returns The position of the bit or size() if none were found. - //************************************************************************* - size_t find_next(bool state, size_t position) const - { - // Where to start. - size_t index; - size_t bit; - - if (ARRAY_SIZE == 1) - { - index = 0; - bit = position; - } - else - { - index = position >> log2::value; - bit = position & (BITS_PER_ELEMENT - 1); - } - - element_t mask = 1 << bit; - - // For each element in the bitset... - while (index < ARRAY_SIZE) - { - element_t value = data[index]; - - // Needs checking? - if (( state && (value != ALL_CLEAR)) || - (!state && (value != ALL_SET))) - { - // For each bit in the element... - while ((bit < BITS_PER_ELEMENT) && (position < N)) - { - // Equal to the required state? - if (((value & mask) != 0) == state) - { - return position; - } - - // Move on to the next bit. - mask <<= 1; - ++position; - ++bit; - } - } - else - { - position += BITS_PER_ELEMENT; - } - - // Start at the beginning for all other elements. - bit = 0; - mask = 1; - - ++index; - } - - return ibitset::npos; + return *this; } //************************************************************************* @@ -1115,58 +370,12 @@ namespace etl //************************************************************************* void swap(bitset& other) { - data.swap(other.data); + for (size_t i = 0; i < ARRAY_SIZE; ++i) + { + std::swap(data, other.data); + } } - //************************************************************************* - /// begin - //************************************************************************* - iterator begin() - { - return iterator(*this, 0); - } - - //************************************************************************* - /// begin - //************************************************************************* - const_iterator begin() const - { - return const_iterator(*this, 0); - } - - //************************************************************************* - /// cbegin - //************************************************************************* - const_iterator cbegin() - { - return const_iterator(*this, 0); - } - - //************************************************************************* - /// end - //************************************************************************* - iterator end() - { - return iterator(*this, N); - } - - //************************************************************************* - /// end - //************************************************************************* - const_iterator end() const - { - return const_iterator(*this, N); - } - - //************************************************************************* - /// cend - //************************************************************************* - const_iterator cend() - { - return const_iterator(*this, N); - } - - //************************************************************************* /// operator == //************************************************************************* @@ -1185,7 +394,7 @@ namespace etl private: - etl::array data; + element_t data[ARRAY_SIZE]; }; //*************************************************************************** @@ -1244,8 +453,4 @@ void swap(etl::bitset& lhs, etl::bitset& rhs) lhs.swap(rhs); } -#if WIN32 -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#endif - #endif diff --git a/bloom_filter.h b/bloom_filter.h index 18086b86..aaa16e68 100644 --- a/bloom_filter.h +++ b/bloom_filter.h @@ -83,7 +83,7 @@ namespace etl enum { // Make the most efficient use of the bitset. - WIDTH = etl::bitset::TOTAL_BITS + WIDTH = etl::bitset::ALLOCATED_BITS }; //*************************************************************************** diff --git a/forward_list_base.h b/forward_list_base.h index ce7f746f..cb764730 100644 --- a/forward_list_base.h +++ b/forward_list_base.h @@ -87,6 +87,21 @@ namespace etl //*************************************************************************** class forward_list_base { + protected: + + //************************************************************************* + /// The node element in the forward_list. + //************************************************************************* + struct Node + { + Node() + : next(nullptr) + { + } + + Node* next; + }; + public: typedef size_t size_type; ///< The type used for determining the size of forward_list. @@ -132,6 +147,34 @@ namespace etl return max_size() - size(); } + //************************************************************************* + /// Reverses the forward_list. + //************************************************************************* + void reverse() + { + if (is_trivial_list()) + { + return; + } + + Node* p_last = &start_node; + Node* p_current = p_last->next; + Node* p_next = p_current->next; + + p_current->next = nullptr; + + while (p_next != nullptr) + { + p_last = p_current; + p_current = p_next; + p_next = p_current->next; + + p_current->next = p_last; + } + + join(&start_node, p_current); + } + protected: //************************************************************************* @@ -144,6 +187,53 @@ namespace etl { } + //************************************************************************* + /// Get the head node. + //************************************************************************* + Node& get_head() + { + return *start_node.next; + } + + //************************************************************************* + /// Get the head node. + //************************************************************************* + const Node& get_head() const + { + return *start_node.next; + } + + //************************************************************************* + /// Insert a node. + //************************************************************************* + void insert_node_after(Node& position, Node& node) + { + // Connect to the forward_list. + node.next = position.next; + + join(&position, &node); + + // One more. + ++current_size; + } + + //************************************************************************* + /// Is the forward_list a trivial length? + //************************************************************************* + bool is_trivial_list() const + { + return (size() < 2); + } + + //************************************************************************* + /// Join two nodes. + //************************************************************************* + void join(Node* left, Node* right) + { + left->next = right; + } + + Node start_node; ///< The node that acts as the forward_list start. size_type next_free; ///< The index of the next free node. size_type current_size; ///< The number of items in the list. const size_type MAX_SIZE; ///< The maximum size of the forward_list. diff --git a/ibitset.h b/ibitset.h index 8ca437d8..a649e521 100644 --- a/ibitset.h +++ b/ibitset.h @@ -30,7 +30,15 @@ SOFTWARE. #ifndef __ETL_IBITSET__ #define __ETL_IBITSET__ +#include +#include + #include "integral_limits.h" +#include "binary.h" + +#if WIN32 +#undef min +#endif namespace etl { @@ -40,58 +48,343 @@ namespace etl //************************************************************************* class ibitset { + protected: + + // The type used for each element in the array. + typedef uint8_t element_t; + public: + static const element_t ALL_SET = etl::integral_limits::max; + static const element_t ALL_CLEAR = 0; + + static const size_t BITS_PER_ELEMENT = etl::integral_limits::bits; + enum { npos = etl::integral_limits::max }; //************************************************************************* - /// Default constructor. + /// The reference type returned. //************************************************************************* - ibitset() + class bit_reference { - } + public: - //************************************************************************* - /// Destructor. - //************************************************************************* - virtual ~ibitset() - { - } + friend class ibitset; + + //******************************* + /// Conversion operator. + //******************************* + operator bool() const + { + return p_bitset->test(position); + } + + //******************************* + /// Assignment operator. + //******************************* + bit_reference& operator = (bool b) + { + p_bitset->set(position, b); + return *this; + } + + //******************************* + /// Assignment operator. + //******************************* + bit_reference& operator = (const bit_reference& r) + { + p_bitset->set(position, bool(r)); + return *this; + } + + //******************************* + /// Flip the bit. + //******************************* + bit_reference& flip() + { + p_bitset->flip(position); + return *this; + } + + //******************************* + /// Return the logical inverse of the bit. + //******************************* + bool operator~() const + { + return !p_bitset->test(position); + } + + private: + + //******************************* + /// Default constructor. + //******************************* + bit_reference() + : p_bitset(nullptr), + position(0) + { + } + + //******************************* + /// Constructor. + //******************************* + bit_reference(ibitset& r_bitset, size_t position) + : p_bitset(&r_bitset), + position(position) + { + } + + ibitset* p_bitset; ///< The bitset. + size_t position; ///< The position in the bitset. + }; //************************************************************************* /// The size of the bitset. //************************************************************************* - virtual size_t size() const = 0; + size_t size() const + { + return NBITS; + } //************************************************************************* - /// Check the bit at the position. + /// Count the number of bits set. //************************************************************************* - virtual bool test(size_t position) const = 0; + size_t count() const + { + size_t n = 0; + + for (size_t i = 0; i < SIZE; ++i) + { + n += etl::count_bits(pdata[i]); + } + + return n; + } + + //************************************************************************* + /// Tests a bit at a position. + /// Positions greater than the number of configured bits will return false. + //************************************************************************* + bool test(size_t position) const + { + size_t index; + element_t mask; + + if (SIZE == 1) + { + index = 0; + mask = element_t(1) << position; + } + else + { + index = position >> etl::log2::value; + mask = element_t(1) << (position & (BITS_PER_ELEMENT - 1)); + } + + return (pdata[index] & mask) != 0; + } //************************************************************************* /// Set the bit at the position. //************************************************************************* - virtual ibitset& set(size_t position, bool value = true) = 0; + ibitset& set() + { + for (size_t i = 0; i < SIZE; ++i) + { + pdata[i] = ALL_SET; + } + + pdata[SIZE - 1] &= TOP_MASK; + + return *this; + } + + //************************************************************************* + /// Set the bit at the position. + //************************************************************************* + ibitset& set(size_t position, bool value = true) + { + size_t index; + element_t bit; + + if (SIZE == 1) + { + index = 0; + bit = element_t(1) << position; + } + else + { + index = position >> etl::log2::value; + bit = element_t(1) << (position & (BITS_PER_ELEMENT - 1)); + } + + if (value) + { + pdata[index] |= bit; + } + else + { + pdata[index] &= ~bit; + } + + return *this; + } + + //************************************************************************* + /// Set from a string. + //************************************************************************* + ibitset& set(const char* text) + { + reset(); + + size_t i = std::min(NBITS, strlen(text)); + + while (i > 0) + { + set(--i, *text++ == '1'); + } + + return *this; + } + + //************************************************************************* + /// Resets the bitset. + //************************************************************************* + ibitset& reset() + { + for (size_t i = 0; i < SIZE; ++i) + { + pdata[i] = ALL_CLEAR; + } + + return *this; + } //************************************************************************* /// Reset the bit at the position. //************************************************************************* - virtual ibitset& reset(size_t position) = 0; + ibitset& reset(size_t position) + { + size_t index; + element_t bit; + + if (SIZE == 1) + { + index = 0; + bit = element_t(1) << position; + } + else + { + index = position >> etl::log2::value; + bit = element_t(1) << (position & (BITS_PER_ELEMENT - 1)); + } + + pdata[index] &= ~bit; + + return *this; + } //************************************************************************* - /// Reset all the bits. + /// Flip all of the bits. //************************************************************************* - virtual ibitset& reset() = 0; + ibitset& flip() + { + for (size_t i = 0; i < SIZE; ++i) + { + pdata[i] = ~pdata[i]; + } + + pdata[SIZE - 1] &= TOP_MASK; + + return *this; + } + + //************************************************************************* + /// Flip the bit at the position. + //************************************************************************* + ibitset& flip(size_t position) + { + if (position < NBITS) + { + size_t index; + element_t bit; + + if (SIZE == 1) + { + index = 0; + bit = element_t(1) << position; + } + else + { + index = position >> log2::value; + bit = element_t(1) << (position & (BITS_PER_ELEMENT - 1)); + } + + pdata[index] ^= bit; + } + + return *this; + } + + //************************************************************************* + // Are all the bits sets? + //************************************************************************* + bool all() const + { + // All but the last. + for (size_t i = 0; i < (SIZE - 1); ++i) + { + if (pdata[i] != ALL_SET) + { + return false; + } + } + + // The last. + if (pdata[SIZE - 1] != (ALL_SET & TOP_MASK)) + { + return false; + } + + return true; + } + + //************************************************************************* + /// Are any of the bits set? + //************************************************************************* + bool any() const + { + return !none(); + } + + //************************************************************************* + /// Are none of the bits set? + //************************************************************************* + bool none() const + { + for (size_t i = 0; i < SIZE; ++i) + { + if (pdata[i] != 0) + { + return false; + } + } + + return true; + } //************************************************************************* /// Finds the first bit in the specified state. ///\param state The state to search for. ///\returns The position of the bit or SIZE if none were found. //************************************************************************* - virtual size_t find_first(bool state) const = 0; + size_t find_first(bool state) const + { + return find_next(state, 0); + } //************************************************************************* /// Finds the next bit in the specified state. @@ -99,8 +392,116 @@ namespace etl ///\param position The position to start from. ///\returns The position of the bit or SIZE if none were found. //************************************************************************* - virtual size_t find_next(bool state, size_t position) const = 0; + size_t find_next(bool state, size_t position) const + { + // Where to start. + size_t index; + size_t bit; + + if (SIZE == 1) + { + index = 0; + bit = position; + } + else + { + index = position >> log2::value; + bit = position & (BITS_PER_ELEMENT - 1); + } + + element_t mask = 1 << bit; + + // For each element in the bitset... + while (index < SIZE) + { + element_t value = pdata[index]; + + // Needs checking? + if (( state && (value != ALL_CLEAR)) || + (!state && (value != ALL_SET))) + { + // For each bit in the element... + while ((bit < BITS_PER_ELEMENT) && (position < NBITS)) + { + // Equal to the required state? + if (((value & mask) != 0) == state) + { + return position; + } + + // Move on to the next bit. + mask <<= 1; + ++position; + ++bit; + } + } + else + { + position += BITS_PER_ELEMENT; + } + + // Start at the beginning for all other elements. + bit = 0; + mask = 1; + + ++index; + } + + return ibitset::npos; + } + + //************************************************************************* + /// Read [] operator. + //************************************************************************* + bool operator[] (size_t position) const + { + return test(position); + } + + //************************************************************************* + /// Write [] operator. + //************************************************************************* + bit_reference operator [] (size_t position) + { + return bit_reference(*this, position); + } + + protected: + + //************************************************************************* + /// Gets a reference to the specified bit. + //************************************************************************* + bit_reference get_bit_reference(size_t position) + { + return bit_reference(*this, position); + } + + //************************************************************************* + /// Constructor. + //************************************************************************* + ibitset(size_t nbits, size_t size, element_t* pdata) + : NBITS(nbits), + SIZE(size), + pdata(pdata) + { + size_t allocated_bits = SIZE * BITS_PER_ELEMENT; + size_t top_mask_shift = ((BITS_PER_ELEMENT - (allocated_bits - NBITS)) % BITS_PER_ELEMENT); + TOP_MASK = element_t(top_mask_shift == 0 ? ALL_SET : ~(ALL_SET << top_mask_shift)); + } + + element_t TOP_MASK; + + private: + + const size_t NBITS; + const size_t SIZE; + element_t* pdata; }; } + +#if WIN32 +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + #endif diff --git a/ideque.h b/ideque.h index 3c9fe774..eea7ab83 100644 --- a/ideque.h +++ b/ideque.h @@ -38,10 +38,7 @@ SOFTWARE. #include "type_traits.h" #include "deque_base.h" #include "parameter_type.h" - -#ifndef ETL_THROW_EXCEPTIONS #include "error_handler.h" -#endif namespace etl { @@ -496,17 +493,13 @@ namespace etl { if (n > MAX_SIZE) { -#ifdef ETL_THROW_EXCEPTIONS - throw deque_full(); -#else - error_handler::error(deque_full()); -#endif + ETL_ERROR(deque_full()); } initialise(); - first.index = 0; - last.index = 0; + _begin.index = 0; + _end.index = 0; while (n > 0) { @@ -524,14 +517,10 @@ namespace etl { if (index >= current_size) { -#ifdef ETL_THROW_EXCEPTIONS - throw deque_out_of_bounds(); -#else - error_handler::error((deque_out_of_bounds())); -#endif + ETL_ERROR(deque_out_of_bounds()); } - iterator result(first); + iterator result(_begin); result += index; return *result; @@ -546,14 +535,10 @@ namespace etl { if (index >= current_size) { -#ifdef ETL_THROW_EXCEPTIONS - throw deque_out_of_bounds(); -#else - error_handler::error((deque_out_of_bounds())); -#endif + ETL_ERROR(deque_out_of_bounds()); } - iterator result(first); + iterator result(_begin); result += index; return *result; @@ -565,7 +550,7 @@ namespace etl //************************************************************************* reference operator [](size_t index) { - iterator result(first); + iterator result(_begin); result += index; return *result; @@ -577,7 +562,7 @@ namespace etl //************************************************************************* const_reference operator [](size_t index) const { - iterator result(first); + iterator result(_begin); result += index; return *result; @@ -589,7 +574,7 @@ namespace etl //************************************************************************* reference front() { - return *first; + return *_begin; } //************************************************************************* @@ -598,7 +583,7 @@ namespace etl //************************************************************************* const_reference front() const { - return *first; + return *_begin; } //************************************************************************* @@ -607,7 +592,7 @@ namespace etl //************************************************************************* reference back() { - return *last; + return *(_end - 1); } //************************************************************************* @@ -616,7 +601,7 @@ namespace etl //************************************************************************* const_reference back() const { - return *last; + return *(_end - 1); } //************************************************************************* @@ -624,7 +609,7 @@ namespace etl //************************************************************************* iterator begin() { - return first; + return _begin; } //************************************************************************* @@ -632,7 +617,7 @@ namespace etl //************************************************************************* const_iterator begin() const { - return first; + return _begin; } //************************************************************************* @@ -640,7 +625,7 @@ namespace etl //************************************************************************* const_iterator cbegin() const { - return first; + return _begin; } //************************************************************************* @@ -648,7 +633,7 @@ namespace etl //************************************************************************* iterator end() { - return ++iterator(last); + return iterator(_end); } //************************************************************************* @@ -656,7 +641,7 @@ namespace etl //************************************************************************* const_iterator end() const { - return ++iterator(last); + return iterator(_end); } //************************************************************************* @@ -664,7 +649,7 @@ namespace etl //************************************************************************* const_iterator cend() const { - return ++const_iterator(last); + return const_iterator(_end); } //************************************************************************* @@ -738,34 +723,34 @@ namespace etl if (insert_position == begin()) { create_element_front(value); - position = first; + position = _begin; } else if (insert_position == end()) { create_element_back(value); - position = last; + position = _end - 1; } else { // Are we closer to the front? - if (std::distance(first, position) < std::distance(position, last)) + if (std::distance(_begin, position) < std::distance(position, _end - 1)) { - // Construct the first. - create_element_front(*first); + // Construct the _begin. + create_element_front(*_begin); // Move the values. - std::copy(first + 1, position, first); + std::copy(_begin + 1, position, _begin); // Write the new value. *--position = value; } else { - // Construct the last. - create_element_back(*last); + // Construct the _end. + create_element_back(*(_end - 1)); // Move the values. - std::copy_backward(position, last - 1, last); + std::copy_backward(position, _end - 2, _end - 1); // Write the new value. *position = value; @@ -774,11 +759,7 @@ namespace etl } else { -#ifdef ETL_THROW_EXCEPTIONS - throw deque_full(); -#else - error_handler::error(deque_full()); -#endif + ETL_ERROR(deque_full()); } return position; @@ -804,7 +785,7 @@ namespace etl create_element_front(value); } - position = first; + position = _begin; } else if (insert_position == end()) { @@ -813,7 +794,7 @@ namespace etl create_element_back(value); } - position = last - (n - 1); + position = _end - n; } else { @@ -821,7 +802,7 @@ namespace etl position = iterator(insert_position.index, *this, p_buffer); // Are we closer to the front? - if (distance(first, insert_position) <= difference_type(current_size / 2)) + if (distance(_begin, insert_position) <= difference_type(current_size / 2)) { size_t insert_index = std::distance(begin(), position); size_t n_insert = n; @@ -832,7 +813,7 @@ namespace etl size_t n_copy_old = n_move - n_create_copy; // Remember the original start. - iterator from = first + n_create_copy - 1; + iterator from = _begin + n_create_copy - 1; iterator to; // Create new. @@ -849,14 +830,14 @@ namespace etl // Copy old. from = position - n_copy_old; - to = first + n_create_copy; + to = _begin + n_create_copy; etl::copy_n(from, n_copy_old, to); // Copy new. to = position - n_create_copy; std::fill_n(to, n_copy_new, value); - position = first + n_move; + position = _begin + n_move; } else { @@ -892,11 +873,7 @@ namespace etl } else { -#ifdef ETL_THROW_EXCEPTIONS - throw deque_full(); -#else - error_handler::error(deque_full()); -#endif + ETL_ERROR(deque_full()); } return position; @@ -923,7 +900,7 @@ namespace etl { create_element_front(n, range_begin); - position = first; + position = _begin; } else if (insert_position == end()) { @@ -932,7 +909,7 @@ namespace etl create_element_back(*range_begin++); } - position = last - (n - 1); + position = _end - n; } else { @@ -940,7 +917,7 @@ namespace etl position = iterator(insert_position.index, *this, p_buffer); // Are we closer to the front? - if (distance(first, insert_position) < difference_type(current_size / 2)) + if (distance(_begin, insert_position) < difference_type(current_size / 2)) { size_t insert_index = std::distance(begin(), position); size_t n_insert = n; @@ -958,11 +935,11 @@ namespace etl create_element_front(n_create_new, range_begin); // Create copy. - create_element_front(n_create_copy, first + n_create_new); + create_element_front(n_create_copy, _begin + n_create_new); // Copy old. from = position - n_copy_old; - to = first + n_create_copy; + to = _begin + n_create_copy; etl::copy_n(from, n_copy_old, to); // Copy new. @@ -970,7 +947,7 @@ namespace etl range_begin += n_create_new; etl::copy_n(range_begin, n_copy_new, to); - position = first + n_move; + position = _begin + n_move; } else { @@ -1008,11 +985,7 @@ namespace etl } else { -#ifdef ETL_THROW_EXCEPTIONS - throw deque_full(); -#else - error_handler::error(deque_full()); -#endif + ETL_ERROR(deque_full()); } return position; @@ -1029,12 +1002,12 @@ namespace etl if (distance(position) <= difference_type(current_size)) { - if (position == first) + if (position == _begin) { destroy_element_front(); position = begin(); } - else if (position == last) + else if (position == _end - 1) { destroy_element_back(); position = end(); @@ -1042,26 +1015,22 @@ namespace etl else { // Are we closer to the front? - if (distance(first, position) < difference_type(current_size / 2)) + if (distance(_begin, position) < difference_type(current_size / 2)) { - std::copy_backward(first, position, position + 1); + std::copy_backward(_begin, position, position + 1); destroy_element_front(); ++position; } else { - std::copy(position + 1, last + 1, position); + std::copy(position + 1, _end, position); destroy_element_back(); } } } else { -#ifdef ETL_THROW_EXCEPTIONS - throw deque_out_of_bounds(); -#else - error_handler::error(deque_out_of_bounds()); -#endif + ETL_ERROR(deque_out_of_bounds()); } return position; @@ -1084,7 +1053,7 @@ namespace etl size_t length = std::distance(range_begin, range_end); // At the beginning? - if (position == first) + if (position == _begin) { for (size_t i = 0; i < length; ++i) { @@ -1094,7 +1063,7 @@ namespace etl position = begin(); } // At the end? - else if (position == last - length + 1) + else if (position == _end - length) { for (size_t i = 0; i < length; ++i) { @@ -1107,10 +1076,10 @@ namespace etl { // Copy the smallest number of items. // Are we closer to the front? - if (distance(first, position) < difference_type(current_size / 2)) + if (distance(_begin, position) < difference_type(current_size / 2)) { // Move the items. - std::copy_backward(first, position, position + length); + std::copy_backward(_begin, position, position + length); for (size_t i = 0; i < length; ++i) { @@ -1123,7 +1092,7 @@ namespace etl // Must be closer to the back. { // Move the items. - std::copy(position + length, last + 1, position); + std::copy(position + length, _end, position); for (size_t i = 0; i < length; ++i) { @@ -1134,11 +1103,7 @@ namespace etl } else { -#ifdef ETL_THROW_EXCEPTIONS - throw deque_out_of_bounds(); -#else - error_handler::error(deque_out_of_bounds()); -#endif + ETL_ERROR(deque_out_of_bounds()); } return position; @@ -1157,11 +1122,7 @@ namespace etl } else { -#ifdef ETL_THROW_EXCEPTIONS - throw deque_full(); -#else - error_handler::error(deque_full()); -#endif + ETL_ERROR(deque_full()); } } @@ -1172,7 +1133,7 @@ namespace etl //************************************************************************* reference push_back() { - reference r = *last; + reference r = *_end; if (!full()) { @@ -1180,14 +1141,10 @@ namespace etl } else { -#ifdef ETL_THROW_EXCEPTIONS - throw deque_full(); -#else - error_handler::error(deque_full()); -#endif + ETL_ERROR(deque_full()); } - return *last; + return r; } //************************************************************************* @@ -1214,11 +1171,7 @@ namespace etl } else { -#ifdef ETL_THROW_EXCEPTIONS - throw deque_full(); -#else - error_handler::error(deque_full()); -#endif + ETL_ERROR(deque_full()); } } @@ -1235,14 +1188,10 @@ namespace etl } else { -#ifdef ETL_THROW_EXCEPTIONS - throw deque_full(); -#else - error_handler::error(deque_full()); -#endif + ETL_ERROR(deque_full()); } - return *first; + return *_begin; } //************************************************************************* @@ -1285,14 +1234,9 @@ namespace etl } } } - else { -#ifdef ETL_THROW_EXCEPTIONS - throw deque_out_of_bounds(); -#else - error_handler::error(deque_out_of_bounds()); -#endif + ETL_ERROR(deque_out_of_bounds()); } } @@ -1340,8 +1284,8 @@ namespace etl clear(); } - iterator first; ///Iterator to the first item in the deque. - iterator last; ///Iterator to the last item in the deque. + iterator _begin; ///Iterator to the _begin item in the deque. + iterator _end; ///Iterator to the _end item in the deque. pointer p_buffer; ///The buffer for the deque. private: @@ -1353,10 +1297,10 @@ namespace etl { if (!empty()) { - --first; + --_begin; } - new(&(*first)) T(); + new(&(*_begin)) T(); ++current_size; } @@ -1373,16 +1317,16 @@ namespace etl if (!empty()) { - --first; + --_begin; --n; } if (n > 0) { - first -= n; + _begin -= n; } - iterator item = first; + iterator item = _begin; do { @@ -1397,12 +1341,8 @@ namespace etl //********************************************************************* void create_element_back() { - if (!empty()) - { - ++last; - } - - new(&(*last)) T(); + new(&(*_end)) T(); + ++_end; ++current_size; } @@ -1411,12 +1351,8 @@ namespace etl //********************************************************************* void create_element_front(parameter_t value) { - if (!empty()) - { - --first; - } - - new(&(*first)) T(value); + --_begin; + new(&(*_begin)) T(value); ++current_size; } @@ -1425,12 +1361,8 @@ namespace etl //********************************************************************* void create_element_back(parameter_t value) { - if (!empty()) - { - ++last; - } - - new(&(*last)) T(value); + new(&(*_end)) T(value); + ++_end; ++current_size; } @@ -1439,13 +1371,9 @@ namespace etl //********************************************************************* void destroy_element_front() { - (*first).~T(); + (*_begin).~T(); --current_size; - - if (!empty()) - { - ++first; - } + ++_begin; } //********************************************************************* @@ -1453,8 +1381,8 @@ namespace etl //********************************************************************* void destroy_element_back() { - (*last).~T(); - --last; + --_end; + (*_end).~T(); --current_size; } @@ -1468,8 +1396,8 @@ namespace etl destroy_element_back(); } - first = iterator(0, *this, p_buffer); - last = iterator(0, *this, p_buffer); + _begin = iterator(0, *this, p_buffer); + _end = iterator(0, *this, p_buffer); } //************************************************************************* @@ -1485,13 +1413,13 @@ namespace etl } //************************************************************************* - /// Measures the distance from the first iterator to the specified iterator. + /// Measures the distance from the _begin iterator to the specified iterator. //************************************************************************* template static difference_type distance(const TIterator& other) { const difference_type index = other.get_index(); - const difference_type reference_index = other.get_deque().first.index; + const difference_type reference_index = other.get_deque()._begin.index; const size_t buffer_size = other.get_deque().BUFFER_SIZE; if (index < reference_index) @@ -1508,7 +1436,7 @@ namespace etl //*************************************************************************** /// Equal operator. -///\param lhs Reference to the first deque. +///\param lhs Reference to the _begin deque. ///\param rhs Reference to the second deque. ///\return true if the arrays are equal, otherwise false ///\ingroup deque @@ -1521,7 +1449,7 @@ bool operator ==(const etl::ideque& lhs, const etl::ideque& rhs) //*************************************************************************** /// Not equal operator. -///\param lhs Reference to the first deque. +///\param lhs Reference to the _begin deque. ///\param rhs Reference to the second deque. ///\return true if the arrays are not equal, otherwise false ///\ingroup deque @@ -1534,9 +1462,9 @@ bool operator !=(const etl::ideque& lhs, const etl::ideque& rhs) //*************************************************************************** /// Less than operator. -///\param lhs Reference to the first deque. +///\param lhs Reference to the _begin deque. ///\param rhs Reference to the second deque. -///\return true if the first deque is lexigraphically less than the second, otherwise false +///\return true if the _begin deque is lexigraphically less than the second, otherwise false ///\ingroup deque //*************************************************************************** template @@ -1550,9 +1478,9 @@ bool operator <(const etl::ideque& lhs, const etl::ideque& rhs) //*************************************************************************** /// Less than or equal operator. -///\param lhs Reference to the first deque. +///\param lhs Reference to the _begin deque. ///\param rhs Reference to the second deque. -///\return true if the first deque is lexigraphically less than or equal to the second, otherwise false +///\return true if the _begin deque is lexigraphically less than or equal to the second, otherwise false ///\ingroup deque //*************************************************************************** template @@ -1563,9 +1491,9 @@ bool operator <=(const etl::ideque& lhs, const etl::ideque& rhs) //*************************************************************************** /// Greater than operator. -///\param lhs Reference to the first deque. +///\param lhs Reference to the _begin deque. ///\param rhs Reference to the second deque. -///\return true if the first deque is lexigraphically greater than the second, otherwise false +///\return true if the _begin deque is lexigraphically greater than the second, otherwise false ///\ingroup deque //*************************************************************************** template @@ -1580,9 +1508,9 @@ bool operator >(const etl::ideque& lhs, const etl::ideque& rhs) //*************************************************************************** /// Greater than or equal operator. -///\param "lhs Reference to the first deque. +///\param "lhs Reference to the _begin deque. ///\param "rhs Reference to the second deque. -///\return true if the first deque is lexigraphically greater than or equal to the second, otherwise false +///\return true if the _begin deque is lexigraphically greater than or equal to the second, otherwise false ///\ingroup deque //*************************************************************************** template diff --git a/iflat_map.h b/iflat_map.h index 878add80..2d3e15dc 100644 --- a/iflat_map.h +++ b/iflat_map.h @@ -273,8 +273,8 @@ namespace etl //********************************************************************* /// Assigns values to the flat_map. - /// If ETL_THROW_EXCEPTIONS is defined, emits flat_map_full if the flat_map does not have enough free space. - /// If ETL_THROW_EXCEPTIONS is defined, emits flat_map_iterator if the iterators are reversed. + /// If ETL_THROW_EXCEPTIONS & _DEBUG are defined, emits flat_map_full if the flat_map does not have enough free space. + /// If ETL_THROW_EXCEPTIONS & _DEBUG are defined, emits flat_map_iterator if the iterators are reversed. ///\param first The iterator to the first element. ///\param last The iterator to the last element + 1. //********************************************************************* @@ -286,7 +286,12 @@ namespace etl if (count < 0) { - ETL_ERROR(flat_map_iterator()); + ETL_ERROR(flat_map_iterator()); + } + + if (count > difference_type(capacity())) + { + ETL_ERROR(flat_map_full()); } #endif @@ -314,7 +319,7 @@ namespace etl // At the end. if (buffer.full()) { - ETL_ERROR(flat_map_full()); + ETL_ERROR(flat_map_full()); } else { @@ -339,7 +344,7 @@ namespace etl // A new one. if (buffer.full()) { - ETL_ERROR(flat_map_full()); + ETL_ERROR(flat_map_full()); } else { diff --git a/iforward_list.h b/iforward_list.h index ac89f0af..976bd342 100644 --- a/iforward_list.h +++ b/iforward_list.h @@ -68,21 +68,6 @@ namespace etl typedef typename parameter_type::value || is_pointer::value>::type parameter_t; - //************************************************************************* - /// The node element in the forward_list. - //************************************************************************* - struct Data_Node; - - struct Node - { - Node() - : next(nullptr) - { - } - - Node* next; - }; - //************************************************************************* /// The data node element in the forward_list. //************************************************************************* @@ -561,34 +546,6 @@ namespace etl #endif } - //************************************************************************* - /// Reverses the forward_list. - //************************************************************************* - void reverse() - { - if (is_trivial_list()) - { - return; - } - - Node* p_last = &start_node; - Node* p_current = p_last->next; - Node* p_next = p_current->next; - - p_current->next = nullptr; - - while (p_next != nullptr) - { - p_last = p_current; - p_current = p_next; - p_next = p_current->next; - - p_current->next = p_last; - } - - join(&start_node, p_current); - } - //************************************************************************* /// Inserts a value to the forward_list after the specified position. //************************************************************************* @@ -942,8 +899,6 @@ namespace etl initialise(); } - Node start_node; ///< The node that acts as the forward_list start. - private: /// The pool of data nodes used in the list. @@ -981,44 +936,6 @@ namespace etl return static_cast(node); } - //************************************************************************* - /// Join two nodes. - //************************************************************************* - void join(Node* left, Node* right) - { - left->next = static_cast(right); - } - - //************************************************************************* - /// Join two nodes. - //************************************************************************* - void join(Data_Node* left, Data_Node* right) - { - left->next = right; - } - - //************************************************************************* - /// Is the forward_list a trivial length? - //************************************************************************* - bool is_trivial_list() const - { - return (size() < 2); - } - - //************************************************************************* - /// Insert a node. - //************************************************************************* - void insert_node_after(Node& position, Node& node) - { - // Connect to the forward_list. - node.next = position.next; - - join(&position, &node); - - // One more. - ++current_size; - } - //************************************************************************* /// Remove a node. //************************************************************************* @@ -1040,22 +957,6 @@ namespace etl } } - //************************************************************************* - /// Get the head node. - //************************************************************************* - Node& get_head() - { - return *start_node.next; - } - - //************************************************************************* - /// Get the head node. - //************************************************************************* - const Node& get_head() const - { - return *start_node.next; - } - //************************************************************************* /// Initialise the forward_list. //************************************************************************* diff --git a/imap.h b/imap.h index f31f634c..5698985d 100644 --- a/imap.h +++ b/imap.h @@ -90,39 +90,6 @@ namespace etl }; protected: - static const uint8_t kLeft = 0; - static const uint8_t kRight = 1; - static const uint8_t kNeither = 2; - - //************************************************************************* - /// The node element in the map. - //************************************************************************* - struct Node - { - //*********************************************************************** - /// Constructor - //*********************************************************************** - Node() : - weight(kNeither), - dir(kNeither) - { - } - - //*********************************************************************** - /// Marks the node as a leaf. - //*********************************************************************** - void mark_as_leaf() - { - weight = kNeither; - dir = kNeither; - children[0] = nullptr; - children[1] = nullptr; - } - - Node* children[2]; - uint8_t weight; - uint8_t dir; - }; //************************************************************************* /// The data node element in the map. @@ -161,9 +128,6 @@ namespace etl /// The pool of data nodes used in the map. ipool* p_node_pool; - /// The node that acts as the map root. - Node* root_node; - //************************************************************************* /// Downcast a Node* to a Data_Node* //************************************************************************* @@ -197,6 +161,7 @@ namespace etl } public: + //************************************************************************* /// iterator. //************************************************************************* @@ -315,6 +280,7 @@ namespace etl // Pointer to the current node for this iterator Node* p_node; }; + friend iterator; //************************************************************************* @@ -425,6 +391,7 @@ namespace etl // Pointer to the current node for this iterator const Node* p_node; }; + friend const_iterator; typedef typename std::iterator_traits::difference_type difference_type; @@ -895,7 +862,6 @@ namespace etl imap(ipool& node_pool, size_t max_size_) : map_base(max_size_) , p_node_pool(&node_pool) - , root_node(nullptr) { initialise(); } @@ -932,108 +898,6 @@ namespace etl root_node = nullptr; } - //************************************************************************* - /// Attach the provided node to the position provided - //************************************************************************* - void attach_node(Node*& position, Data_Node& node) - { - // Mark new node as leaf on attach to tree at position provided - node.mark_as_leaf(); - - // Add the node here - position = &node; - - // One more. - ++current_size; - } - - //************************************************************************* - /// Balance the critical node at the position provided as needed - //************************************************************************* - void balance_node(Node*& critical_node) - { - // Step 1: Update weights for all children of the critical node up to the - // newly inserted node. This step is costly (in terms of traversing nodes - // multiple times during insertion) but doesn't require as much recursion - Node* weight_node = critical_node->children[critical_node->dir]; - while (weight_node) - { - // Keep going until we reach a terminal node (dir == kNeither) - if (kNeither != weight_node->dir) - { - // Does this insert balance the previous weight factor value? - if (weight_node->weight == 1 - weight_node->dir) - { - weight_node->weight = kNeither; - } - else - { - weight_node->weight = weight_node->dir; - } - - // Update weight factor node to point to next node - weight_node = weight_node->children[weight_node->dir]; - } - else - { - // Stop loop, terminal node found - break; - } - } // while(weight_node) - - // Step 2: Update weight for critical_node or rotate tree to balance node - if (kNeither == critical_node->weight) - { - critical_node->weight = critical_node->dir; - } - // If direction is different than weight, then it will now be balanced - else if (critical_node->dir != critical_node->weight) - { - critical_node->weight = kNeither; - } - // Rotate is required to balance the tree at the critical node - else - { - // If critical node matches child node direction then perform a two - // node rotate in the direction of the critical node - if (critical_node->weight == critical_node->children[critical_node->dir]->dir) - { - rotate_2node(critical_node, critical_node->dir); - } - // Otherwise perform a three node rotation in the direction of the - // critical node - else - { - rotate_3node(critical_node, critical_node->dir, - critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir); - } - } - } - - //************************************************************************* - /// Detach the node at the position provided - //************************************************************************* - void detach_node(Node*& position, Node*& replacement) - { - // Make temporary copy of actual nodes involved because we might lose - // their references in the process (e.g. position is the same as - // replacement or replacement is a child of position) - Node* detached = position; - Node* swap = replacement; - - // Update current position to point to swap (replacement) node first - position = swap; - - // Update replacement node to point to child in opposite direction - // otherwise we might lose the other child of the swap node - replacement = swap->children[1 - swap->dir]; - - // Point swap node to detached node's children and weight - swap->children[kLeft] = detached->children[kLeft]; - swap->children[kRight] = detached->children[kRight]; - swap->weight = detached->weight; - } - //************************************************************************* /// Find the value matching the node provided //************************************************************************* @@ -1145,40 +1009,6 @@ namespace etl return root_node; } - //************************************************************************* - /// Find the node whose key would go before all the other keys from the - /// position provided - //************************************************************************* - Node* find_limit_node(Node* position, const int8_t dir) const - { - // Something at this position and in the direction specified? keep going - Node* limit_node = position; - while (limit_node && limit_node->children[dir]) - { - limit_node = limit_node->children[dir]; - } - - // Return the limit node position found - return limit_node; - } - - //************************************************************************* - /// Find the node whose key would go before all the other keys from the - /// position provided - //************************************************************************* - const Node* find_limit_node(const Node* position, const int8_t dir) const - { - // Something at this position and in the direction specified? keep going - Node* limit_node = position; - while (limit_node && limit_node->children[dir]) - { - limit_node = limit_node->children[dir]; - } - - // Return the limit node position found - return limit_node; - } - //************************************************************************* /// Find the parent node that contains the node provided in its left or /// right tree @@ -1795,76 +1625,6 @@ namespace etl // Return node found (might be nullptr) return found; } - - //************************************************************************* - /// Rotate two nodes at the position provided the to balance the tree - //************************************************************************* - void rotate_2node(Node*& position, uint8_t dir) - { - // A C A B - // B C -> A E OR B C -> D A - // D E B D D E E C - // C (new position) becomes the root - // A (position) takes ownership of D as its children[kRight] child - // C (new position) takes ownership of A as its left child - // OR - // B (new position) becomes the root - // A (position) takes ownership of E as its left child - // B (new position) takes ownership of A as its right child - - // Capture new root - Node* new_root = position->children[dir]; - // Replace position's previous child with new root's other child - position->children[dir] = new_root->children[1 - dir]; - // New root now becomes parent of current position - new_root->children[1 - dir] = position; - // Clear weight factor from current position - position->weight = kNeither; - // Newly detached right now becomes current position - position = new_root; - // Clear weight factor from new root - position->weight = kNeither; - } - - //************************************************************************* - /// Rotate three nodes at the position provided the to balance the tree - //************************************************************************* - void rotate_3node(Node*& position, uint8_t dir, uint8_t third) - { - // __A__ __E__ __A__ __D__ - // _B_ C -> B A OR B _C_ -> A C - // D E D F G C D E B F G E - // F G F G - // E (new position) becomes the root - // B (position) takes ownership of F as its left child - // A takes ownership of G as its right child - // OR - // D (new position) becomes the root - // A (position) takes ownership of F as its right child - // C takes ownership of G as its left child - - // Capture new root (either E or D depending on dir) - Node* new_root = position->children[dir]->children[1 - dir]; - // Set weight factor for B or C based on F or G existing and being a different than dir - position->children[dir]->weight = third != kNeither && third != dir ? dir : kNeither; - - // Detach new root from its tree (replace with new roots child) - position->children[dir]->children[1 - dir] = - new_root->children[dir]; - // Attach current left tree to new root - new_root->children[dir] = position->children[dir]; - // Set weight factor for A based on F or G - position->weight = third != kNeither && third == dir ? 1 - dir : kNeither; - - // Move new root's right tree to current roots left tree - position->children[dir] = new_root->children[1 - dir]; - // Attach current root to new roots right tree - new_root->children[1 - dir] = position; - // Replace current position with new root - position = new_root; - // Clear weight factor for new current position - position->weight = kNeither; - } }; } diff --git a/imultimap.h b/imultimap.h index 9fad67ab..63ba491f 100644 --- a/imultimap.h +++ b/imultimap.h @@ -37,7 +37,7 @@ SOFTWARE. #include #include "nullptr.h" -#include "map_base.h" +#include "multimap_base.h" #include "type_traits.h" #include "parameter_type.h" #include "pool.h" @@ -53,7 +53,7 @@ namespace etl ///\ingroup map //*************************************************************************** template - class imultimap : public map_base + class imultimap : public multimap_base { public: @@ -90,41 +90,6 @@ namespace etl }; protected: - static const uint8_t kLeft = 0; - static const uint8_t kRight = 1; - static const uint8_t kNeither = 2; - - //************************************************************************* - /// The node element in the multimap. - //************************************************************************* - struct Node - { - //*********************************************************************** - /// Constructor - //*********************************************************************** - Node() : - weight(kNeither), - dir(kNeither) - { - } - - //*********************************************************************** - /// Marks the node as a leaf. - //*********************************************************************** - void mark_as_leaf() - { - weight = kNeither; - dir = kNeither; - parent = nullptr; - children[0] = nullptr; - children[1] = nullptr; - } - - Node* parent; - Node* children[2]; - uint8_t weight; - uint8_t dir; - }; //************************************************************************* /// The data node element in the multimap. @@ -149,10 +114,12 @@ namespace etl { return key_compare()(node1.value.first, node2.value.first); } + bool node_comp(const Data_Node& node, const key_value_parameter_t& key) const { return key_compare()(node.value.first, key); } + bool node_comp(const key_value_parameter_t& key, const Data_Node& node) const { return key_compare()(key, node.value.first); @@ -163,9 +130,6 @@ namespace etl /// The pool of data nodes used in the multimap. ipool* p_node_pool; - /// The node that acts as the multimap root. - Node* root_node; - //************************************************************************* /// Downcast a Node* to a Data_Node* //************************************************************************* @@ -702,9 +666,9 @@ namespace etl else { #ifdef ETL_THROW_EXCEPTIONS - throw map_full(); + throw multimap_full(); #else - error_handler::error(map_full()); + error_handler::error(multimap_full()); #endif } @@ -807,9 +771,8 @@ namespace etl /// Constructor. //************************************************************************* imultimap(ipool& node_pool, size_t max_size_) - : map_base(max_size_) + : multimap_base(max_size_) , p_node_pool(&node_pool) - , root_node(nullptr) { initialise(); } @@ -846,87 +809,6 @@ namespace etl root_node = nullptr; } - //************************************************************************* - /// Attach the provided node to the position provided - //************************************************************************* - void attach_node(Node* parent, Node*& position, Data_Node& node) - { - // Mark new node as leaf on attach to tree at position provided - node.mark_as_leaf(); - - // Keep track of this node's parent - node.parent = parent; - - // Add the node here - position = &node; - - // One more. - ++current_size; - } - - //************************************************************************* - /// Balance the critical node at the position provided as needed - //************************************************************************* - void balance_node(Node*& critical_node) - { - // Step 1: Update weights for all children of the critical node up to the - // newly inserted node. This step is costly (in terms of traversing nodes - // multiple times during insertion) but doesn't require as much recursion - Node* weight_node = critical_node->children[critical_node->dir]; - while (weight_node) - { - // Keep going until we reach a terminal node (dir == kNeither) - if (kNeither != weight_node->dir) - { - // Does this insert balance the previous weight factor value? - if (weight_node->weight == 1 - weight_node->dir) - { - weight_node->weight = kNeither; - } - else - { - weight_node->weight = weight_node->dir; - } - - // Update weight factor node to point to next node - weight_node = weight_node->children[weight_node->dir]; - } - else - { - // Stop loop, terminal node found - break; - } - } // while(weight_node) - - // Step 2: Update weight for critical_node or rotate tree to balance node - if (kNeither == critical_node->weight) - { - critical_node->weight = critical_node->dir; - } - // If direction is different than weight, then it will now be balanced - else if (critical_node->dir != critical_node->weight) - { - critical_node->weight = kNeither; - } - // Rotate is required to balance the tree at the critical node - else - { - // If critical node matches child node direction then perform a two - // node rotate in the direction of the critical node - if (critical_node->weight == critical_node->children[critical_node->dir]->dir) - { - rotate_2node(critical_node, critical_node->dir); - } - // Otherwise perform a three node rotation in the direction of the - // critical node - else - { - rotate_3node(critical_node, critical_node->dir, - critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir); - } - } - } - //************************************************************************* /// Count the nodes that match the key provided //************************************************************************* @@ -959,39 +841,6 @@ namespace etl return result; } - //************************************************************************* - /// Detach the node at the position provided - //************************************************************************* - void detach_node(Node*& position, Node*& replacement) - { - // Make temporary copy of actual nodes involved because we might lose - // their references in the process (e.g. position is the same as - // replacement or replacement is a child of position) - Node* detached = position; - Node* swap = replacement; - - // Update current position to point to swap (replacement) node first - position = swap; - - // Update replacement node to point to child in opposite direction - // otherwise we might lose the other child of the swap node - replacement = swap->children[1 - swap->dir]; - - // Point swap node to detached node's parent, children and weight - swap->parent = detached->parent; - swap->children[kLeft] = detached->children[kLeft]; - swap->children[kRight] = detached->children[kRight]; - if (swap->children[kLeft]) - { - swap->children[kLeft]->parent = swap; - } - if (swap->children[kRight]) - { - swap->children[kRight]->parent = swap; - } - swap->weight = detached->weight; - } - //************************************************************************* /// Find the value matching the node provided //************************************************************************* @@ -1058,23 +907,6 @@ namespace etl return found; } - //************************************************************************* - /// Find the node whose key would go before all the other keys from the - /// position provided - //************************************************************************* - Node* find_limit_node(Node* position, const int8_t dir) const - { - // Something at this position and in the direction specified? keep going - Node* limit_node = position; - while (limit_node && limit_node->children[dir]) - { - limit_node = limit_node->children[dir]; - } - - // Return the limit node position found - return limit_node; - } - //************************************************************************* /// Find the node whose key is not considered to go before the key provided //************************************************************************* @@ -1250,7 +1082,7 @@ namespace etl } else { - // Attatch node to current position (which is assumed to be root) + // Attach node to current position (which is assumed to be root) attach_node(nullptr, position, node); // Return newly added node at current position @@ -1261,146 +1093,6 @@ namespace etl return found; } - //************************************************************************* - /// Find the next node in sequence from the node provided - //************************************************************************* - void next_node(Node*& position) const - { - if (position) - { - // Is there a tree on the right? then find the minimum of that tree - if (position->children[kRight]) - { - // Return minimum node found - position = find_limit_node(position->children[kRight], kLeft); - } - // Otherwise find the parent of this node - else - { - // Start with current position as parent - Node* parent = position; - do { - // Update current position as previous parent - position = parent; - // Find parent of current position - parent = position->parent; // find_parent_node(root_node, position); - // Repeat while previous position was on right side of parent tree - } while (parent && parent->children[kRight] == position); - - // Set parent node as the next position - position = parent; - } - } - } - - //************************************************************************* - /// Find the next node in sequence from the node provided - //************************************************************************* - void next_node(const Node*& position) const - { - if (position) - { - // Is there a tree on the right? then find the minimum of that tree - if (position->children[kRight]) - { - // Return minimum node found - position = find_limit_node(position->children[kRight], kLeft); - } - // Otherwise find the parent of this node - else - { - // Start with current position as parent - const Node* parent = position; - do { - // Update current position as previous parent - position = parent; - // Find parent of current position - parent = position->parent; - // Repeat while previous position was on right side of parent tree - } while (parent && parent->children[kRight] == position); - - // Set parent node as the next position - position = parent; - } - } - } - - //************************************************************************* - /// Find the previous node in sequence from the node provided - //************************************************************************* - void prev_node(Node*& position) const - { - // If starting at the terminal end, the previous node is the maximum node - // from the root - if (!position) - { - position = find_limit_node(root_node, kRight); - } - else - { - // Is there a tree on the left? then find the maximum of that tree - if (position->children[kLeft]) - { - // Return maximum node found - position = find_limit_node(position->children[kLeft], kRight); - } - // Otherwise find the parent of this node - else - { - // Start with current position as parent - Node* parent = position; - do { - // Update current position as previous parent - position = parent; - // Find parent of current position - parent = position->parent; - // Repeat while previous position was on left side of parent tree - } while (parent && parent->children[kLeft] == position); - - // Set parent node as the next position - position = parent; - } - } - } - - //************************************************************************* - /// Find the previous node in sequence from the node provided - //************************************************************************* - void prev_node(const Node*& position) const - { - // If starting at the terminal end, the previous node is the maximum node - // from the root - if (!position) - { - position = find_limit_node(root_node, kRight); - } - else - { - // Is there a tree on the left? then find the maximum of that tree - if (position->children[kLeft]) - { - // Return maximum node found - position = find_limit_node(position->children[kLeft], kRight); - } - // Otherwise find the parent of this node - else - { - // Start with current position as parent - const Node* parent = position; - do { - // Update current position as previous parent - position = parent; - // Find parent of current position - parent = position->parent; - // Repeat while previous position was on left side of parent tree - } while (parent && parent->children[kLeft] == position); - - // Set parent node as the next position - position = parent; - } - } - } - //************************************************************************* /// Remove the node specified from somewhere starting at the position /// provided @@ -1635,104 +1327,6 @@ namespace etl destroy_data_node(data_node); } // if(found) } - - //************************************************************************* - /// Rotate two nodes at the position provided the to balance the tree - //************************************************************************* - void rotate_2node(Node*& position, uint8_t dir) - { - // A C A B - // B C -> A E OR B C -> D A - // D E B D D E E C - // C (new position) becomes the root - // A (position) takes ownership of D as its children[kRight] child - // C (new position) takes ownership of A as its left child - // OR - // B (new position) becomes the root - // A (position) takes ownership of E as its left child - // B (new position) takes ownership of A as its right child - - // Capture new root (either B or C depending on dir) and its parent - Node* new_root = position->children[dir]; - - // Replace position's previous child with new root's other child - position->children[dir] = new_root->children[1 - dir]; - // Update new root's other child parent pointer - if (position->children[dir]) - { - position->children[dir]->parent = position; - } - - // New root's parent becomes current position's parent - new_root->parent = position->parent; - new_root->children[1 - dir] = position; - new_root->dir = 1 - dir; - - // Clear weight factor from current position - position->weight = kNeither; - // Position's parent becomes new_root - position->parent = new_root; - position = new_root; - // Clear weight factor from new root - position->weight = kNeither; - } - - //************************************************************************* - /// Rotate three nodes at the position provided the to balance the tree - //************************************************************************* - void rotate_3node(Node*& position, uint8_t dir, uint8_t third) - { - // __A__ __E__ __A__ __D__ - // _B_ C -> B A OR B _C_ -> A C - // D E D F G C D E B F G E - // F G F G - // E (new position) becomes the root - // B (position) takes ownership of F as its left child - // A takes ownership of G as its right child - // OR - // D (new position) becomes the root - // A (position) takes ownership of F as its right child - // C takes ownership of G as its left child - - // Capture new root (either E or D depending on dir) - Node* new_root = position->children[dir]->children[1 - dir]; - // Set weight factor for B or C based on F or G existing and being a different than dir - position->children[dir]->weight = third != kNeither && third != dir ? dir : kNeither; - - // Detach new root from its tree (replace with new roots child) - position->children[dir]->children[1 - dir] = new_root->children[dir]; - // Update new roots child parent pointer - if (new_root->children[dir]) - { - new_root->children[dir]->parent = position->children[dir]; - } - - // Attach current left tree to new root and update its parent - new_root->children[dir] = position->children[dir]; - position->children[dir]->parent = new_root; - - // Set weight factor for A based on F or G - position->weight = third != kNeither && third == dir ? 1 - dir : kNeither; - - // Move new root's right tree to current roots left tree - position->children[dir] = new_root->children[1 - dir]; - if (new_root->children[1 - dir]) - { - new_root->children[1 - dir]->parent = position; - } - - // Attach current root to new roots right tree and assume its parent - new_root->parent = position->parent; - new_root->children[1 - dir] = position; - new_root->dir = 1 - dir; - - // Update current position's parent and replace with new root - position->parent = new_root; - position = new_root; - // Clear weight factor for new current position - position->weight = kNeither; - } - }; } diff --git a/imultiset.h b/imultiset.h index d843f508..d35b62dd 100644 --- a/imultiset.h +++ b/imultiset.h @@ -37,7 +37,7 @@ SOFTWARE. #include #include "nullptr.h" -#include "set_base.h" +#include "multiset_base.h" #include "type_traits.h" #include "parameter_type.h" #include "pool.h" @@ -53,7 +53,7 @@ namespace etl ///\ingroup set //*************************************************************************** template - class imultiset : public set_base + class imultiset : public multiset_base { public: @@ -88,41 +88,6 @@ namespace etl }; protected: - static const uint8_t kLeft = 0; - static const uint8_t kRight = 1; - static const uint8_t kNeither = 2; - - //************************************************************************* - /// The node element in the multiset. - //************************************************************************* - struct Node - { - //*********************************************************************** - /// Constructor - //*********************************************************************** - Node() : - weight(kNeither), - dir(kNeither) - { - } - - //*********************************************************************** - /// Marks the node as a leaf. - //*********************************************************************** - void mark_as_leaf() - { - weight = kNeither; - dir = kNeither; - parent = nullptr; - children[0] = nullptr; - children[1] = nullptr; - } - - Node* parent; - Node* children[2]; - uint8_t weight; - uint8_t dir; - }; //************************************************************************* /// The data node element in the multiset. @@ -161,9 +126,6 @@ namespace etl /// The pool of data nodes used in the multiset. ipool* p_node_pool; - /// The node that acts as the multiset root. - Node* root_node; - //************************************************************************* /// Downcast a Node* to a Data_Node* //************************************************************************* @@ -685,9 +647,9 @@ namespace etl else { #ifdef ETL_THROW_EXCEPTIONS - throw set_full(); + throw multiset_full(); #else - error_handler::error(set_full()); + error_handler::error(multiset_full()); #endif } @@ -790,9 +752,8 @@ namespace etl /// Constructor. //************************************************************************* imultiset(ipool& node_pool, size_t max_size_) - : set_base(max_size_) + : multiset_base(max_size_) , p_node_pool(&node_pool) - , root_node(nullptr) { initialise(); } @@ -829,87 +790,6 @@ namespace etl root_node = nullptr; } - //************************************************************************* - /// Attach the provided node to the position provided - //************************************************************************* - void attach_node(Node* parent, Node*& position, Data_Node& node) - { - // Mark new node as leaf on attach to tree at position provided - node.mark_as_leaf(); - - // Keep track of this node's parent - node.parent = parent; - - // Add the node here - position = &node; - - // One more. - ++current_size; - } - - //************************************************************************* - /// Balance the critical node at the position provided as needed - //************************************************************************* - void balance_node(Node*& critical_node) - { - // Step 1: Update weights for all children of the critical node up to the - // newly inserted node. This step is costly (in terms of traversing nodes - // multiple times during insertion) but doesn't require as much recursion - Node* weight_node = critical_node->children[critical_node->dir]; - while (weight_node) - { - // Keep going until we reach a terminal node (dir == kNeither) - if (kNeither != weight_node->dir) - { - // Does this insert balance the previous weight factor value? - if (weight_node->weight == 1 - weight_node->dir) - { - weight_node->weight = kNeither; - } - else - { - weight_node->weight = weight_node->dir; - } - - // Update weight factor node to point to next node - weight_node = weight_node->children[weight_node->dir]; - } - else - { - // Stop loop, terminal node found - break; - } - } // while(weight_node) - - // Step 2: Update weight for critical_node or rotate tree to balance node - if (kNeither == critical_node->weight) - { - critical_node->weight = critical_node->dir; - } - // If direction is different than weight, then it will now be balanced - else if (critical_node->dir != critical_node->weight) - { - critical_node->weight = kNeither; - } - // Rotate is required to balance the tree at the critical node - else - { - // If critical node matches child node direction then perform a two - // node rotate in the direction of the critical node - if (critical_node->weight == critical_node->children[critical_node->dir]->dir) - { - rotate_2node(critical_node, critical_node->dir); - } - // Otherwise perform a three node rotation in the direction of the - // critical node - else - { - rotate_3node(critical_node, critical_node->dir, - critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir); - } - } - } - //************************************************************************* /// Count the nodes that match the key provided //************************************************************************* @@ -942,39 +822,6 @@ namespace etl return result; } - //************************************************************************* - /// Detach the node at the position provided - //************************************************************************* - void detach_node(Node*& position, Node*& replacement) - { - // Make temporary copy of actual nodes involved because we might lose - // their references in the process (e.g. position is the same as - // replacement or replacement is a child of position) - Node* detached = position; - Node* swap = replacement; - - // Update current position to point to swap (replacement) node first - position = swap; - - // Update replacement node to point to child in opposite direction - // otherwise we might lose the other child of the swap node - replacement = swap->children[1 - swap->dir]; - - // Point swap node to detached node's parent, children and weight - swap->parent = detached->parent; - swap->children[kLeft] = detached->children[kLeft]; - swap->children[kRight] = detached->children[kRight]; - if (swap->children[kLeft]) - { - swap->children[kLeft]->parent = swap; - } - if (swap->children[kRight]) - { - swap->children[kRight]->parent = swap; - } - swap->weight = detached->weight; - } - //************************************************************************* /// Find the value matching the node provided //************************************************************************* @@ -1041,23 +888,6 @@ namespace etl return found; } - //************************************************************************* - /// Find the node whose key would go before all the other keys from the - /// position provided - //************************************************************************* - Node* find_limit_node(Node* position, const int8_t dir) const - { - // Something at this position and in the direction specified? keep going - Node* limit_node = position; - while (limit_node && limit_node->children[dir]) - { - limit_node = limit_node->children[dir]; - } - - // Return the limit node position found - return limit_node; - } - //************************************************************************* /// Find the node whose key is not considered to go before the key provided //************************************************************************* @@ -1244,146 +1074,6 @@ namespace etl return found; } - //************************************************************************* - /// Find the next node in sequence from the node provided - //************************************************************************* - void next_node(Node*& position) const - { - if (position) - { - // Is there a tree on the right? then find the minimum of that tree - if (position->children[kRight]) - { - // Return minimum node found - position = find_limit_node(position->children[kRight], kLeft); - } - // Otherwise find the parent of this node - else - { - // Start with current position as parent - Node* parent = position; - do { - // Update current position as previous parent - position = parent; - // Find parent of current position - parent = position->parent; // find_parent_node(root_node, position); - // Repeat while previous position was on right side of parent tree - } while (parent && parent->children[kRight] == position); - - // Set parent node as the next position - position = parent; - } - } - } - - //************************************************************************* - /// Find the next node in sequence from the node provided - //************************************************************************* - void next_node(const Node*& position) const - { - if (position) - { - // Is there a tree on the right? then find the minimum of that tree - if (position->children[kRight]) - { - // Return minimum node found - position = find_limit_node(position->children[kRight], kLeft); - } - // Otherwise find the parent of this node - else - { - // Start with current position as parent - const Node* parent = position; - do { - // Update current position as previous parent - position = parent; - // Find parent of current position - parent = position->parent; - // Repeat while previous position was on right side of parent tree - } while (parent && parent->children[kRight] == position); - - // Set parent node as the next position - position = parent; - } - } - } - - //************************************************************************* - /// Find the previous node in sequence from the node provided - //************************************************************************* - void prev_node(Node*& position) const - { - // If starting at the terminal end, the previous node is the maximum node - // from the root - if (!position) - { - position = find_limit_node(root_node, kRight); - } - else - { - // Is there a tree on the left? then find the maximum of that tree - if (position->children[kLeft]) - { - // Return maximum node found - position = find_limit_node(position->children[kLeft], kRight); - } - // Otherwise find the parent of this node - else - { - // Start with current position as parent - Node* parent = position; - do { - // Update current position as previous parent - position = parent; - // Find parent of current position - parent = position->parent; - // Repeat while previous position was on left side of parent tree - } while (parent && parent->children[kLeft] == position); - - // Set parent node as the next position - position = parent; - } - } - } - - //************************************************************************* - /// Find the previous node in sequence from the node provided - //************************************************************************* - void prev_node(const Node*& position) const - { - // If starting at the terminal end, the previous node is the maximum node - // from the root - if (!position) - { - position = find_limit_node(root_node, kRight); - } - else - { - // Is there a tree on the left? then find the maximum of that tree - if (position->children[kLeft]) - { - // Return maximum node found - position = find_limit_node(position->children[kLeft], kRight); - } - // Otherwise find the parent of this node - else - { - // Start with current position as parent - const Node* parent = position; - do { - // Update current position as previous parent - position = parent; - // Find parent of current position - parent = position->parent; - // Repeat while previous position was on left side of parent tree - } while (parent && parent->children[kLeft] == position); - - // Set parent node as the next position - position = parent; - } - } - } - //************************************************************************* /// Remove the node specified from somewhere starting at the position /// provided @@ -1618,104 +1308,6 @@ namespace etl destroy_data_node(data_node); } // if(found) } - - //************************************************************************* - /// Rotate two nodes at the position provided the to balance the tree - //************************************************************************* - void rotate_2node(Node*& position, uint8_t dir) - { - // A C A B - // B C -> A E OR B C -> D A - // D E B D D E E C - // C (new position) becomes the root - // A (position) takes ownership of D as its children[kRight] child - // C (new position) takes ownership of A as its left child - // OR - // B (new position) becomes the root - // A (position) takes ownership of E as its left child - // B (new position) takes ownership of A as its right child - - // Capture new root (either B or C depending on dir) and its parent - Node* new_root = position->children[dir]; - - // Replace position's previous child with new root's other child - position->children[dir] = new_root->children[1 - dir]; - // Update new root's other child parent pointer - if (position->children[dir]) - { - position->children[dir]->parent = position; - } - - // New root's parent becomes current position's parent - new_root->parent = position->parent; - new_root->children[1 - dir] = position; - new_root->dir = 1 - dir; - - // Clear weight factor from current position - position->weight = kNeither; - // Position's parent becomes new_root - position->parent = new_root; - position = new_root; - // Clear weight factor from new root - position->weight = kNeither; - } - - //************************************************************************* - /// Rotate three nodes at the position provided the to balance the tree - //************************************************************************* - void rotate_3node(Node*& position, uint8_t dir, uint8_t third) - { - // __A__ __E__ __A__ __D__ - // _B_ C -> B A OR B _C_ -> A C - // D E D F G C D E B F G E - // F G F G - // E (new position) becomes the root - // B (position) takes ownership of F as its left child - // A takes ownership of G as its right child - // OR - // D (new position) becomes the root - // A (position) takes ownership of F as its right child - // C takes ownership of G as its left child - - // Capture new root (either E or D depending on dir) - Node* new_root = position->children[dir]->children[1 - dir]; - // Set weight factor for B or C based on F or G existing and being a different than dir - position->children[dir]->weight = third != kNeither && third != dir ? dir : kNeither; - - // Detach new root from its tree (replace with new roots child) - position->children[dir]->children[1 - dir] = new_root->children[dir]; - // Update new roots child parent pointer - if (new_root->children[dir]) - { - new_root->children[dir]->parent = position->children[dir]; - } - - // Attach current left tree to new root and update its parent - new_root->children[dir] = position->children[dir]; - position->children[dir]->parent = new_root; - - // Set weight factor for A based on F or G - position->weight = third != kNeither && third == dir ? 1 - dir : kNeither; - - // Move new root's right tree to current roots left tree - position->children[dir] = new_root->children[1 - dir]; - if (new_root->children[1 - dir]) - { - new_root->children[1 - dir]->parent = position; - } - - // Attach current root to new roots right tree and assume its parent - new_root->parent = position->parent; - new_root->children[1 - dir] = position; - new_root->dir = 1 - dir; - - // Update current position's parent and replace with new root - position->parent = new_root; - position = new_root; - // Clear weight factor for new current position - position->weight = kNeither; - } - }; } diff --git a/intrusive_forward_list.h b/intrusive_forward_list.h index c7f0d6c7..f6875116 100644 --- a/intrusive_forward_list.h +++ b/intrusive_forward_list.h @@ -41,7 +41,7 @@ SOFTWARE. #include "nullptr.h" #include "type_traits.h" -#include "array.h" +#include "intrusive_forward_list_node.h" namespace etl { @@ -87,66 +87,6 @@ namespace etl } }; - namespace __private_intrusive_forward_list__ - { - //*************************************************************************** - /// The node element in the intrusive_forward_list. - //*************************************************************************** - class intrusive_forward_list_node_base - { - public: - - virtual intrusive_forward_list_node_base* get_next(size_t index) const - { - return base_next; - } - - virtual void set_next(size_t index, intrusive_forward_list_node_base* pnext) - { - base_next = pnext; - } - - private: - - intrusive_forward_list_node_base* base_next; - }; - } - - //*************************************************************************** - /// The node element in the intrusive_forward_list. - //*************************************************************************** - template - struct intrusive_forward_list_node : public __private_intrusive_forward_list__::intrusive_forward_list_node_base - { - public: - - __private_intrusive_forward_list__::intrusive_forward_list_node_base* get_next(size_t index) const - { -#ifdef _DEBUG - if (index >= SIZE) - { - ETL_ERROR(intrusive_forward_list_index_exception()); - } -#endif - return next[index]; - } - - void set_next(size_t index, __private_intrusive_forward_list__::intrusive_forward_list_node_base* pnext) - { -#ifdef _DEBUG - if (index >= SIZE) - { - ETL_ERROR(intrusive_forward_list_index_exception()); - } -#endif - next[index] = pnext; - } - - private: - - etl::array<__private_intrusive_forward_list__::intrusive_forward_list_node_base*, SIZE> next; - }; - //*************************************************************************** /// An intrusive forward list. ///\ingroup intrusive_forward_list @@ -518,23 +458,20 @@ namespace etl { return; } - - node_t* p_last = &start_node; - node_t* p_current = p_last->get_next(index); - node_t* p_next = p_current->get_next(index); - p_current->set_next(index, nullptr); + node_t* first = nullptr; // To keep first node + node_t* second = start_node.get_next(index); // To keep second node + node_t* track = start_node.get_next(index); // Track the list - while (p_next != nullptr) + while (track != NULL) { - p_last = p_current; - p_current = p_next; - p_next = p_current->get_next(index); - - p_current->set_next(index, p_last); + track = track->get_next(index); // Track point to next node; + second->set_next(index, first); // Second node point to first + first = second; // Move first node to next + second = track; // Move second node to next } - join(&start_node, p_current); + join(&start_node, first); } //************************************************************************* diff --git a/intrusive_forward_list_node.h b/intrusive_forward_list_node.h new file mode 100644 index 00000000..052f83a2 --- /dev/null +++ b/intrusive_forward_list_node.h @@ -0,0 +1,99 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl + +Copyright(c) 2015 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_FORWARD_LIST_NODE__ +#define __ETL_INTRUSIVE_FORWARD_LIST_NODE__ + +#include "error_handler.h" +#include "array.h" + +namespace etl +{ + namespace __private_intrusive_forward_list__ + { + //*************************************************************************** + /// The node element in the intrusive_forward_list. + //*************************************************************************** + class intrusive_forward_list_node_base + { + public: + + virtual intrusive_forward_list_node_base* get_next(size_t index) const + { + return base_next; + } + + virtual void set_next(size_t index, intrusive_forward_list_node_base* pnext) + { + base_next = pnext; + } + + private: + + intrusive_forward_list_node_base* base_next; + }; + } + + //*************************************************************************** + /// The node element in the intrusive_forward_list. + //*************************************************************************** + template + struct intrusive_forward_list_node : public __private_intrusive_forward_list__::intrusive_forward_list_node_base + { + public: + + __private_intrusive_forward_list__::intrusive_forward_list_node_base* get_next(size_t index) const + { +#ifdef _DEBUG + if (index >= SIZE) + { + ETL_ERROR(intrusive_forward_list_index_exception()); + } +#endif + return next[index]; + } + + void set_next(size_t index, __private_intrusive_forward_list__::intrusive_forward_list_node_base* pnext) + { +#ifdef _DEBUG + if (index >= SIZE) + { + ETL_ERROR(intrusive_forward_list_index_exception()); + } +#endif + next[index] = pnext; + } + + private: + + etl::array<__private_intrusive_forward_list__::intrusive_forward_list_node_base*, SIZE> next; + }; +} + +#endif diff --git a/iset.h b/iset.h index 6e584b34..03ab618f 100644 --- a/iset.h +++ b/iset.h @@ -88,39 +88,6 @@ namespace etl }; protected: - static const uint8_t kLeft = 0; - static const uint8_t kRight = 1; - static const uint8_t kNeither = 2; - - //************************************************************************* - /// The node element in the set. - //************************************************************************* - struct Node - { - //*********************************************************************** - /// Constructor - //*********************************************************************** - Node() : - weight(kNeither), - dir(kNeither) - { - } - - //*********************************************************************** - /// Marks the node as a leaf. - //*********************************************************************** - void mark_as_leaf() - { - weight = kNeither; - dir = kNeither; - children[0] = nullptr; - children[1] = nullptr; - } - - Node* children[2]; - uint8_t weight; - uint8_t dir; - }; //************************************************************************* /// The data node element in the set. @@ -159,9 +126,6 @@ namespace etl /// The pool of data nodes used in the set. ipool* p_node_pool; - /// The node that acts as the set root. - Node* root_node; - //************************************************************************* /// Downcast a Node* to a Data_Node* //************************************************************************* @@ -822,7 +786,6 @@ namespace etl iset(ipool& node_pool, size_t max_size_) : set_base(max_size_) , p_node_pool(&node_pool) - , root_node(nullptr) { initialise(); } @@ -859,108 +822,6 @@ namespace etl root_node = nullptr; } - //************************************************************************* - /// Attach the provided node to the position provided - //************************************************************************* - void attach_node(Node*& position, Data_Node& node) - { - // Mark new node as leaf on attach to tree at position provided - node.mark_as_leaf(); - - // Add the node here - position = &node; - - // One more. - ++current_size; - } - - //************************************************************************* - /// Balance the critical node at the position provided as needed - //************************************************************************* - void balance_node(Node*& critical_node) - { - // Step 1: Update weights for all children of the critical node up to the - // newly inserted node. This step is costly (in terms of traversing nodes - // multiple times during insertion) but doesn't require as much recursion - Node* weight_node = critical_node->children[critical_node->dir]; - while (weight_node) - { - // Keep going until we reach a terminal node (dir == kNeither) - if (kNeither != weight_node->dir) - { - // Does this insert balance the previous weight factor value? - if (weight_node->weight == 1 - weight_node->dir) - { - weight_node->weight = kNeither; - } - else - { - weight_node->weight = weight_node->dir; - } - - // Update weight factor node to point to next node - weight_node = weight_node->children[weight_node->dir]; - } - else - { - // Stop loop, terminal node found - break; - } - } // while(weight_node) - - // Step 2: Update weight for critical_node or rotate tree to balance node - if (kNeither == critical_node->weight) - { - critical_node->weight = critical_node->dir; - } - // If direction is different than weight, then it will now be balanced - else if (critical_node->dir != critical_node->weight) - { - critical_node->weight = kNeither; - } - // Rotate is required to balance the tree at the critical node - else - { - // If critical node matches child node direction then perform a two - // node rotate in the direction of the critical node - if (critical_node->weight == critical_node->children[critical_node->dir]->dir) - { - rotate_2node(critical_node, critical_node->dir); - } - // Otherwise perform a three node rotation in the direction of the - // critical node - else - { - rotate_3node(critical_node, critical_node->dir, - critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir); - } - } - } - - //************************************************************************* - /// Detach the node at the position provided - //************************************************************************* - void detach_node(Node*& position, Node*& replacement) - { - // Make temporary copy of actual nodes involved because we might lose - // their references in the process (e.g. position is the same as - // replacement or replacement is a child of position) - Node* detached = position; - Node* swap = replacement; - - // Update current position to point to swap (replacement) node first - position = swap; - - // Update replacement node to point to child in opposite direction - // otherwise we might lose the other child of the swap node - replacement = swap->children[1 - swap->dir]; - - // Point swap node to detached node's children and weight - swap->children[kLeft] = detached->children[kLeft]; - swap->children[kRight] = detached->children[kRight]; - swap->weight = detached->weight; - } - //************************************************************************* /// Find the value matching the node provided //************************************************************************* @@ -1072,40 +933,6 @@ namespace etl return root_node; } - //************************************************************************* - /// Find the node whose key would go before all the other keys from the - /// position provided - //************************************************************************* - Node* find_limit_node(Node* position, const int8_t dir) const - { - // Something at this position and in the direction specified? keep going - Node* limit_node = position; - while (limit_node && limit_node->children[dir]) - { - limit_node = limit_node->children[dir]; - } - - // Return the limit node position found - return limit_node; - } - - //************************************************************************* - /// Find the node whose key would go before all the other keys from the - /// position provided - //************************************************************************* - const Node* find_limit_node(const Node* position, const int8_t dir) const - { - // Something at this position and in the direction specified? keep going - Node* limit_node = position; - while (limit_node && limit_node->children[dir]) - { - limit_node = limit_node->children[dir]; - } - - // Return the limit node position found - return limit_node; - } - //************************************************************************* /// Find the parent node that contains the node provided in its left or /// right tree @@ -1722,76 +1549,6 @@ namespace etl // Return node found (might be nullptr) return found; } - - //************************************************************************* - /// Rotate two nodes at the position provided the to balance the tree - //************************************************************************* - void rotate_2node(Node*& position, uint8_t dir) - { - // A C A B - // B C -> A E OR B C -> D A - // D E B D D E E C - // C (new position) becomes the root - // A (position) takes ownership of D as its children[kRight] child - // C (new position) takes ownership of A as its left child - // OR - // B (new position) becomes the root - // A (position) takes ownership of E as its left child - // B (new position) takes ownership of A as its right child - - // Capture new root - Node* new_root = position->children[dir]; - // Replace position's previous child with new root's other child - position->children[dir] = new_root->children[1 - dir]; - // New root now becomes parent of current position - new_root->children[1 - dir] = position; - // Clear weight factor from current position - position->weight = kNeither; - // Newly detached right now becomes current position - position = new_root; - // Clear weight factor from new root - position->weight = kNeither; - } - - //************************************************************************* - /// Rotate three nodes at the position provided the to balance the tree - //************************************************************************* - void rotate_3node(Node*& position, uint8_t dir, uint8_t third) - { - // __A__ __E__ __A__ __D__ - // _B_ C -> B A OR B _C_ -> A C - // D E D F G C D E B F G E - // F G F G - // E (new position) becomes the root - // B (position) takes ownership of F as its left child - // A takes ownership of G as its right child - // OR - // D (new position) becomes the root - // A (position) takes ownership of F as its right child - // C takes ownership of G as its left child - - // Capture new root (either E or D depending on dir) - Node* new_root = position->children[dir]->children[1 - dir]; - // Set weight factor for B or C based on F or G existing and being a different than dir - position->children[dir]->weight = third != kNeither && third != dir ? dir : kNeither; - - // Detach new root from its tree (replace with new roots child) - position->children[dir]->children[1 - dir] = - new_root->children[dir]; - // Attach current left tree to new root - new_root->children[dir] = position->children[dir]; - // Set weight factor for A based on F or G - position->weight = third != kNeither && third == dir ? 1 - dir : kNeither; - - // Move new root's right tree to current roots left tree - position->children[dir] = new_root->children[1 - dir]; - // Attach current root to new roots right tree - new_root->children[1 - dir] = position; - // Replace current position with new root - position = new_root; - // Clear weight factor for new current position - position->weight = kNeither; - } }; } diff --git a/map_base.h b/map_base.h index 411d7d0e..12264f9d 100644 --- a/map_base.h +++ b/map_base.h @@ -27,8 +27,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ******************************************************************************/ -#if !defined(__ETL_IN_IMAP_H__) && !defined(__ETL_IN_IMULTIMAP_H__) -#error This header is a private element of etl::map, etl::multimap & etl::imap, etl::imultimap +#if !defined(__ETL_IN_IMAP_H__) +#error This header is a private element of etl::map & etl::imap #endif #ifndef __ETL_MAP_BASE__ @@ -157,18 +157,260 @@ namespace etl protected: + static const uint8_t kLeft = 0; + static const uint8_t kRight = 1; + static const uint8_t kNeither = 2; + + //************************************************************************* + /// The node element in the map. + //************************************************************************* + struct Node + { + //*********************************************************************** + /// Constructor + //*********************************************************************** + Node() : + weight(kNeither), + dir(kNeither) + { + } + + //*********************************************************************** + /// Marks the node as a leaf. + //*********************************************************************** + void mark_as_leaf() + { + weight = kNeither; + dir = kNeither; + children[0] = nullptr; + children[1] = nullptr; + } + + Node* children[2]; + uint8_t weight; + uint8_t dir; + }; + //************************************************************************* /// The constructor that is called from derived classes. //************************************************************************* map_base(size_type max_size) : current_size(0) , MAX_SIZE(max_size) + , root_node(nullptr) { } + //************************************************************************* + /// Balance the critical node at the position provided as needed + //************************************************************************* + void balance_node(Node*& critical_node) + { + // Step 1: Update weights for all children of the critical node up to the + // newly inserted node. This step is costly (in terms of traversing nodes + // multiple times during insertion) but doesn't require as much recursion + Node* weight_node = critical_node->children[critical_node->dir]; + while (weight_node) + { + // Keep going until we reach a terminal node (dir == kNeither) + if (kNeither != weight_node->dir) + { + // Does this insert balance the previous weight factor value? + if (weight_node->weight == 1 - weight_node->dir) + { + weight_node->weight = kNeither; + } + else + { + weight_node->weight = weight_node->dir; + } + + // Update weight factor node to point to next node + weight_node = weight_node->children[weight_node->dir]; + } + else + { + // Stop loop, terminal node found + break; + } + } // while(weight_node) + + // Step 2: Update weight for critical_node or rotate tree to balance node + if (kNeither == critical_node->weight) + { + critical_node->weight = critical_node->dir; + } + // If direction is different than weight, then it will now be balanced + else if (critical_node->dir != critical_node->weight) + { + critical_node->weight = kNeither; + } + // Rotate is required to balance the tree at the critical node + else + { + // If critical node matches child node direction then perform a two + // node rotate in the direction of the critical node + if (critical_node->weight == critical_node->children[critical_node->dir]->dir) + { + rotate_2node(critical_node, critical_node->dir); + } + // Otherwise perform a three node rotation in the direction of the + // critical node + else + { + rotate_3node(critical_node, critical_node->dir, + critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir); + } + } + } + + //************************************************************************* + /// Rotate two nodes at the position provided the to balance the tree + //************************************************************************* + void rotate_2node(Node*& position, uint8_t dir) + { + // A C A B + // B C -> A E OR B C -> D A + // D E B D D E E C + // C (new position) becomes the root + // A (position) takes ownership of D as its children[kRight] child + // C (new position) takes ownership of A as its left child + // OR + // B (new position) becomes the root + // A (position) takes ownership of E as its left child + // B (new position) takes ownership of A as its right child + + // Capture new root + Node* new_root = position->children[dir]; + // Replace position's previous child with new root's other child + position->children[dir] = new_root->children[1 - dir]; + // New root now becomes parent of current position + new_root->children[1 - dir] = position; + // Clear weight factor from current position + position->weight = kNeither; + // Newly detached right now becomes current position + position = new_root; + // Clear weight factor from new root + position->weight = kNeither; + } + + //************************************************************************* + /// Rotate three nodes at the position provided the to balance the tree + //************************************************************************* + void rotate_3node(Node*& position, uint8_t dir, uint8_t third) + { + // __A__ __E__ __A__ __D__ + // _B_ C -> B A OR B _C_ -> A C + // D E D F G C D E B F G E + // F G F G + // E (new position) becomes the root + // B (position) takes ownership of F as its left child + // A takes ownership of G as its right child + // OR + // D (new position) becomes the root + // A (position) takes ownership of F as its right child + // C takes ownership of G as its left child + + // Capture new root (either E or D depending on dir) + Node* new_root = position->children[dir]->children[1 - dir]; + // Set weight factor for B or C based on F or G existing and being a different than dir + position->children[dir]->weight = third != kNeither && third != dir ? dir : kNeither; + + // Detach new root from its tree (replace with new roots child) + position->children[dir]->children[1 - dir] = + new_root->children[dir]; + // Attach current left tree to new root + new_root->children[dir] = position->children[dir]; + // Set weight factor for A based on F or G + position->weight = third != kNeither && third == dir ? 1 - dir : kNeither; + + // Move new root's right tree to current roots left tree + position->children[dir] = new_root->children[1 - dir]; + // Attach current root to new roots right tree + new_root->children[1 - dir] = position; + // Replace current position with new root + position = new_root; + // Clear weight factor for new current position + position->weight = kNeither; + } + + //************************************************************************* + /// Find the node whose key would go before all the other keys from the + /// position provided + //************************************************************************* + Node* find_limit_node(Node* position, const int8_t dir) const + { + // Something at this position and in the direction specified? keep going + Node* limit_node = position; + while (limit_node && limit_node->children[dir]) + { + limit_node = limit_node->children[dir]; + } + + // Return the limit node position found + return limit_node; + } + + //************************************************************************* + /// Find the node whose key would go before all the other keys from the + /// position provided + //************************************************************************* + const Node* find_limit_node(const Node* position, const int8_t dir) const + { + // Something at this position and in the direction specified? keep going + const Node* limit_node = position; + while (limit_node && limit_node->children[dir]) + { + limit_node = limit_node->children[dir]; + } + + // Return the limit node position found + return limit_node; + } + + //************************************************************************* + /// Attach the provided node to the position provided + //************************************************************************* + void attach_node(Node*& position, Node& node) + { + // Mark new node as leaf on attach to tree at position provided + node.mark_as_leaf(); + + // Add the node here + position = &node; + + // One more. + ++current_size; + } + + //************************************************************************* + /// Detach the node at the position provided + //************************************************************************* + void detach_node(Node*& position, Node*& replacement) + { + // Make temporary copy of actual nodes involved because we might lose + // their references in the process (e.g. position is the same as + // replacement or replacement is a child of position) + Node* detached = position; + Node* swap = replacement; + + // Update current position to point to swap (replacement) node first + position = swap; + + // Update replacement node to point to child in opposite direction + // otherwise we might lose the other child of the swap node + replacement = swap->children[1 - swap->dir]; + + // Point swap node to detached node's children and weight + swap->children[kLeft] = detached->children[kLeft]; + swap->children[kRight] = detached->children[kRight]; + swap->weight = detached->weight; + } + size_type current_size; ///< The number of the used nodes. const size_type MAX_SIZE; ///< The maximum size of the map. + Node* root_node; ///< The node that acts as the map root. }; } diff --git a/multimap_base.h b/multimap_base.h new file mode 100644 index 00000000..b9201f32 --- /dev/null +++ b/multimap_base.h @@ -0,0 +1,581 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl + +Copyright(c) 2014 jwellbelove, rlindeman + +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. +******************************************************************************/ + +#if !defined(__ETL_IN_IMULTIMAP_H__) +#error This header is a private element of etl::multimap & etl::imultimap +#endif + +#ifndef __ETL_MULTIMAP_BASE__ +#define __ETL_MULTIMAP_BASE__ + +#include +#include "exception.h" + +namespace etl +{ + //*************************************************************************** + /// Exception for the map. + ///\ingroup map + //*************************************************************************** + class multimap_exception : public exception + { + public: + + multimap_exception(const char* what) + : exception(what) + { + } + }; + + //*************************************************************************** + /// Full exception for the map. + ///\ingroup map + //*************************************************************************** + class multimap_full : public multimap_exception + { + public: + + multimap_full() + : multimap_exception("multimap: full") + { + } + }; + + //*************************************************************************** + /// Map out of bounds exception. + ///\ingroup map + //*************************************************************************** + class multimap_out_of_bounds : public multimap_exception + { + public: + + multimap_out_of_bounds() + : multimap_exception("multimap: out of bounds") + { + } + }; + + //*************************************************************************** + /// Iterator exception for the map. + ///\ingroup map + //*************************************************************************** + class multimap_iterator : public multimap_exception + { + public: + + multimap_iterator() + : multimap_exception("multimap: iterator problem") + { + } + }; + + //*************************************************************************** + /// The base class for all maps. + ///\ingroup map + //*************************************************************************** + class multimap_base + { + public: + + typedef size_t size_type; ///< The type used for determining the size of map. + + //************************************************************************* + /// Gets the size of the map. + //************************************************************************* + size_type size() const + { + return current_size; + } + + //************************************************************************* + /// Gets the maximum possible size of the map. + //************************************************************************* + size_type max_size() const + { + return MAX_SIZE; + } + + //************************************************************************* + /// Checks to see if the map is empty. + //************************************************************************* + bool empty() const + { + return current_size == 0; + } + + //************************************************************************* + /// Checks to see if the map is full. + //************************************************************************* + bool full() const + { + return current_size == MAX_SIZE; + } + + //************************************************************************* + /// Returns the capacity of the vector. + ///\return The capacity of the vector. + //************************************************************************* + size_type capacity() const + { + return MAX_SIZE; + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return max_size() - size(); + } + + protected: + + static const uint8_t kLeft = 0; + static const uint8_t kRight = 1; + static const uint8_t kNeither = 2; + + //************************************************************************* + /// The node element in the multimap. + //************************************************************************* + struct Node + { + //*********************************************************************** + /// Constructor + //*********************************************************************** + Node() : + weight(kNeither), + dir(kNeither) + { + } + + //*********************************************************************** + /// Marks the node as a leaf. + //*********************************************************************** + void mark_as_leaf() + { + weight = kNeither; + dir = kNeither; + parent = nullptr; + children[0] = nullptr; + children[1] = nullptr; + } + + Node* parent; + Node* children[2]; + uint8_t weight; + uint8_t dir; + }; + + //************************************************************************* + /// The constructor that is called from derived classes. + //************************************************************************* + multimap_base(size_type max_size) + : current_size(0) + , MAX_SIZE(max_size) + , root_node(nullptr) + + { + } + + //************************************************************************* + /// Balance the critical node at the position provided as needed + //************************************************************************* + void balance_node(Node*& critical_node) + { + // Step 1: Update weights for all children of the critical node up to the + // newly inserted node. This step is costly (in terms of traversing nodes + // multiple times during insertion) but doesn't require as much recursion + Node* weight_node = critical_node->children[critical_node->dir]; + while (weight_node) + { + // Keep going until we reach a terminal node (dir == kNeither) + if (kNeither != weight_node->dir) + { + // Does this insert balance the previous weight factor value? + if (weight_node->weight == 1 - weight_node->dir) + { + weight_node->weight = kNeither; + } + else + { + weight_node->weight = weight_node->dir; + } + + // Update weight factor node to point to next node + weight_node = weight_node->children[weight_node->dir]; + } + else + { + // Stop loop, terminal node found + break; + } + } // while(weight_node) + + // Step 2: Update weight for critical_node or rotate tree to balance node + if (kNeither == critical_node->weight) + { + critical_node->weight = critical_node->dir; + } + // If direction is different than weight, then it will now be balanced + else if (critical_node->dir != critical_node->weight) + { + critical_node->weight = kNeither; + } + // Rotate is required to balance the tree at the critical node + else + { + // If critical node matches child node direction then perform a two + // node rotate in the direction of the critical node + if (critical_node->weight == critical_node->children[critical_node->dir]->dir) + { + rotate_2node(critical_node, critical_node->dir); + } + // Otherwise perform a three node rotation in the direction of the + // critical node + else + { + rotate_3node(critical_node, critical_node->dir, + critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir); + } + } + } + + //************************************************************************* + /// Rotate two nodes at the position provided the to balance the tree + //************************************************************************* + void rotate_2node(Node*& position, uint8_t dir) + { + // A C A B + // B C -> A E OR B C -> D A + // D E B D D E E C + // C (new position) becomes the root + // A (position) takes ownership of D as its children[kRight] child + // C (new position) takes ownership of A as its left child + // OR + // B (new position) becomes the root + // A (position) takes ownership of E as its left child + // B (new position) takes ownership of A as its right child + + // Capture new root (either B or C depending on dir) and its parent + Node* new_root = position->children[dir]; + + // Replace position's previous child with new root's other child + position->children[dir] = new_root->children[1 - dir]; + // Update new root's other child parent pointer + if (position->children[dir]) + { + position->children[dir]->parent = position; + } + + // New root's parent becomes current position's parent + new_root->parent = position->parent; + new_root->children[1 - dir] = position; + new_root->dir = 1 - dir; + + // Clear weight factor from current position + position->weight = kNeither; + // Position's parent becomes new_root + position->parent = new_root; + position = new_root; + // Clear weight factor from new root + position->weight = kNeither; + } + + //************************************************************************* + /// Rotate three nodes at the position provided the to balance the tree + //************************************************************************* + void rotate_3node(Node*& position, uint8_t dir, uint8_t third) + { + // __A__ __E__ __A__ __D__ + // _B_ C -> B A OR B _C_ -> A C + // D E D F G C D E B F G E + // F G F G + // E (new position) becomes the root + // B (position) takes ownership of F as its left child + // A takes ownership of G as its right child + // OR + // D (new position) becomes the root + // A (position) takes ownership of F as its right child + // C takes ownership of G as its left child + + // Capture new root (either E or D depending on dir) + Node* new_root = position->children[dir]->children[1 - dir]; + // Set weight factor for B or C based on F or G existing and being a different than dir + position->children[dir]->weight = third != kNeither && third != dir ? dir : kNeither; + + // Detach new root from its tree (replace with new roots child) + position->children[dir]->children[1 - dir] = new_root->children[dir]; + // Update new roots child parent pointer + if (new_root->children[dir]) + { + new_root->children[dir]->parent = position->children[dir]; + } + + // Attach current left tree to new root and update its parent + new_root->children[dir] = position->children[dir]; + position->children[dir]->parent = new_root; + + // Set weight factor for A based on F or G + position->weight = third != kNeither && third == dir ? 1 - dir : kNeither; + + // Move new root's right tree to current roots left tree + position->children[dir] = new_root->children[1 - dir]; + if (new_root->children[1 - dir]) + { + new_root->children[1 - dir]->parent = position; + } + + // Attach current root to new roots right tree and assume its parent + new_root->parent = position->parent; + new_root->children[1 - dir] = position; + new_root->dir = 1 - dir; + + // Update current position's parent and replace with new root + position->parent = new_root; + position = new_root; + // Clear weight factor for new current position + position->weight = kNeither; + } + + //************************************************************************* + /// Find the next node in sequence from the node provided + //************************************************************************* + void next_node(Node*& position) const + { + if (position) + { + // Is there a tree on the right? then find the minimum of that tree + if (position->children[kRight]) + { + // Return minimum node found + position = find_limit_node(position->children[kRight], kLeft); + } + // Otherwise find the parent of this node + else + { + // Start with current position as parent + Node* parent = position; + do { + // Update current position as previous parent + position = parent; + // Find parent of current position + parent = position->parent; // find_parent_node(root_node, position); + // Repeat while previous position was on right side of parent tree + } while (parent && parent->children[kRight] == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Find the next node in sequence from the node provided + //************************************************************************* + void next_node(const Node*& position) const + { + if (position) + { + // Is there a tree on the right? then find the minimum of that tree + if (position->children[kRight]) + { + // Return minimum node found + position = find_limit_node(position->children[kRight], kLeft); + } + // Otherwise find the parent of this node + else + { + // Start with current position as parent + const Node* parent = position; + do { + // Update current position as previous parent + position = parent; + // Find parent of current position + parent = position->parent; + // Repeat while previous position was on right side of parent tree + } while (parent && parent->children[kRight] == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Find the previous node in sequence from the node provided + //************************************************************************* + void prev_node(Node*& position) const + { + // If starting at the terminal end, the previous node is the maximum node + // from the root + if (!position) + { + position = find_limit_node(root_node, kRight); + } + else + { + // Is there a tree on the left? then find the maximum of that tree + if (position->children[kLeft]) + { + // Return maximum node found + position = find_limit_node(position->children[kLeft], kRight); + } + // Otherwise find the parent of this node + else + { + // Start with current position as parent + Node* parent = position; + do { + // Update current position as previous parent + position = parent; + // Find parent of current position + parent = position->parent; + // Repeat while previous position was on left side of parent tree + } while (parent && parent->children[kLeft] == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Find the previous node in sequence from the node provided + //************************************************************************* + void prev_node(const Node*& position) const + { + // If starting at the terminal end, the previous node is the maximum node + // from the root + if (!position) + { + position = find_limit_node(root_node, kRight); + } + else + { + // Is there a tree on the left? then find the maximum of that tree + if (position->children[kLeft]) + { + // Return maximum node found + position = find_limit_node(position->children[kLeft], kRight); + } + // Otherwise find the parent of this node + else + { + // Start with current position as parent + const Node* parent = position; + do { + // Update current position as previous parent + position = parent; + // Find parent of current position + parent = position->parent; + // Repeat while previous position was on left side of parent tree + } while (parent && parent->children[kLeft] == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Find the node whose key would go before all the other keys from the + /// position provided + //************************************************************************* + Node* find_limit_node(Node* position, const int8_t dir) const + { + // Something at this position and in the direction specified? keep going + Node* limit_node = position; + while (limit_node && limit_node->children[dir]) + { + limit_node = limit_node->children[dir]; + } + + // Return the limit node position found + return limit_node; + } + + //************************************************************************* + /// Attach the provided node to the position provided + //************************************************************************* + void attach_node(Node* parent, Node*& position, Node& node) + { + // Mark new node as leaf on attach to tree at position provided + node.mark_as_leaf(); + + // Keep track of this node's parent + node.parent = parent; + + // Add the node here + position = &node; + + // One more. + ++current_size; + } + + //************************************************************************* + /// Detach the node at the position provided + //************************************************************************* + void detach_node(Node*& position, Node*& replacement) + { + // Make temporary copy of actual nodes involved because we might lose + // their references in the process (e.g. position is the same as + // replacement or replacement is a child of position) + Node* detached = position; + Node* swap = replacement; + + // Update current position to point to swap (replacement) node first + position = swap; + + // Update replacement node to point to child in opposite direction + // otherwise we might lose the other child of the swap node + replacement = swap->children[1 - swap->dir]; + + // Point swap node to detached node's parent, children and weight + swap->parent = detached->parent; + swap->children[kLeft] = detached->children[kLeft]; + swap->children[kRight] = detached->children[kRight]; + if (swap->children[kLeft]) + { + swap->children[kLeft]->parent = swap; + } + if (swap->children[kRight]) + { + swap->children[kRight]->parent = swap; + } + swap->weight = detached->weight; + } + + size_type current_size; ///< The number of the used nodes. + const size_type MAX_SIZE; ///< The maximum size of the map. + Node* root_node; ///< The node that acts as the multimap root. + }; +} + +#endif diff --git a/multiset_base.h b/multiset_base.h new file mode 100644 index 00000000..6e0827d8 --- /dev/null +++ b/multiset_base.h @@ -0,0 +1,580 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl + +Copyright(c) 2015 jwellbelove, rlindeman + +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. +******************************************************************************/ + +#if !defined(__ETL_IN_IMULTISET_H__) +#error This header is a private element of etl::multiset & etl::imultiset +#endif + +#ifndef __ETL_MULTISET_BASE__ +#define __ETL_MULTISET_BASE__ + +#include +#include "exception.h" + +namespace etl +{ + //*************************************************************************** + /// Exception for the set. + ///\ingroup set + //*************************************************************************** + class multiset_exception : public exception + { + public: + + multiset_exception(const char* what) + : exception(what) + { + } + }; + + //*************************************************************************** + /// Full exception for the set. + ///\ingroup set + //*************************************************************************** + class multiset_full : public multiset_exception + { + public: + + multiset_full() + : multiset_exception("multiset: full") + { + } + }; + + //*************************************************************************** + /// Map out of bounds exception. + ///\ingroup set + //*************************************************************************** + class multiset_out_of_bounds : public multiset_exception + { + public: + + multiset_out_of_bounds() + : multiset_exception("multiset: out of bounds") + { + } + }; + + //*************************************************************************** + /// Iterator exception for the set. + ///\ingroup set + //*************************************************************************** + class multiset_iterator : public multiset_exception + { + public: + + multiset_iterator() + : multiset_exception("multiset: iterator problem") + { + } + }; + + //*************************************************************************** + /// The base class for all sets. + ///\ingroup set + //*************************************************************************** + class multiset_base + { + public: + + typedef size_t size_type; ///< The type used for determining the size of set. + + //************************************************************************* + /// Gets the size of the set. + //************************************************************************* + size_type size() const + { + return current_size; + } + + //************************************************************************* + /// Gets the maximum possible size of the set. + //************************************************************************* + size_type max_size() const + { + return MAX_SIZE; + } + + //************************************************************************* + /// Checks to see if the set is empty. + //************************************************************************* + bool empty() const + { + return current_size == 0; + } + + //************************************************************************* + /// Checks to see if the set is full. + //************************************************************************* + bool full() const + { + return current_size == MAX_SIZE; + } + + //************************************************************************* + /// Returns the capacity of the vector. + ///\return The capacity of the vector. + //************************************************************************* + size_type capacity() const + { + return MAX_SIZE; + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return max_size() - size(); + } + + protected: + + static const uint8_t kLeft = 0; + static const uint8_t kRight = 1; + static const uint8_t kNeither = 2; + + //************************************************************************* + /// The node element in the multiset. + //************************************************************************* + struct Node + { + //*********************************************************************** + /// Constructor + //*********************************************************************** + Node() : + weight(kNeither), + dir(kNeither) + { + } + + //*********************************************************************** + /// Marks the node as a leaf. + //*********************************************************************** + void mark_as_leaf() + { + weight = kNeither; + dir = kNeither; + parent = nullptr; + children[0] = nullptr; + children[1] = nullptr; + } + + Node* parent; + Node* children[2]; + uint8_t weight; + uint8_t dir; + }; + + //************************************************************************* + /// The constructor that is called from derived classes. + //************************************************************************* + multiset_base(size_type max_size) + : current_size(0) + , MAX_SIZE(max_size) + , root_node(nullptr) + { + } + + //************************************************************************* + /// Attach the provided node to the position provided + //************************************************************************* + void attach_node(Node* parent, Node*& position, Node& node) + { + // Mark new node as leaf on attach to tree at position provided + node.mark_as_leaf(); + + // Keep track of this node's parent + node.parent = parent; + + // Add the node here + position = &node; + + // One more. + ++current_size; + } + + //************************************************************************* + /// Detach the node at the position provided + //************************************************************************* + void detach_node(Node*& position, Node*& replacement) + { + // Make temporary copy of actual nodes involved because we might lose + // their references in the process (e.g. position is the same as + // replacement or replacement is a child of position) + Node* detached = position; + Node* swap = replacement; + + // Update current position to point to swap (replacement) node first + position = swap; + + // Update replacement node to point to child in opposite direction + // otherwise we might lose the other child of the swap node + replacement = swap->children[1 - swap->dir]; + + // Point swap node to detached node's parent, children and weight + swap->parent = detached->parent; + swap->children[kLeft] = detached->children[kLeft]; + swap->children[kRight] = detached->children[kRight]; + if (swap->children[kLeft]) + { + swap->children[kLeft]->parent = swap; + } + if (swap->children[kRight]) + { + swap->children[kRight]->parent = swap; + } + swap->weight = detached->weight; + } + + //************************************************************************* + /// Balance the critical node at the position provided as needed + //************************************************************************* + void balance_node(Node*& critical_node) + { + // Step 1: Update weights for all children of the critical node up to the + // newly inserted node. This step is costly (in terms of traversing nodes + // multiple times during insertion) but doesn't require as much recursion + Node* weight_node = critical_node->children[critical_node->dir]; + while (weight_node) + { + // Keep going until we reach a terminal node (dir == kNeither) + if (kNeither != weight_node->dir) + { + // Does this insert balance the previous weight factor value? + if (weight_node->weight == 1 - weight_node->dir) + { + weight_node->weight = kNeither; + } + else + { + weight_node->weight = weight_node->dir; + } + + // Update weight factor node to point to next node + weight_node = weight_node->children[weight_node->dir]; + } + else + { + // Stop loop, terminal node found + break; + } + } // while(weight_node) + + // Step 2: Update weight for critical_node or rotate tree to balance node + if (kNeither == critical_node->weight) + { + critical_node->weight = critical_node->dir; + } + // If direction is different than weight, then it will now be balanced + else if (critical_node->dir != critical_node->weight) + { + critical_node->weight = kNeither; + } + // Rotate is required to balance the tree at the critical node + else + { + // If critical node matches child node direction then perform a two + // node rotate in the direction of the critical node + if (critical_node->weight == critical_node->children[critical_node->dir]->dir) + { + rotate_2node(critical_node, critical_node->dir); + } + // Otherwise perform a three node rotation in the direction of the + // critical node + else + { + rotate_3node(critical_node, critical_node->dir, + critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir); + } + } + } + + //************************************************************************* + /// Find the node whose key would go before all the other keys from the + /// position provided + //************************************************************************* + Node* find_limit_node(Node* position, const int8_t dir) const + { + // Something at this position and in the direction specified? keep going + Node* limit_node = position; + while (limit_node && limit_node->children[dir]) + { + limit_node = limit_node->children[dir]; + } + + // Return the limit node position found + return limit_node; + } + + //************************************************************************* + /// Find the next node in sequence from the node provided + //************************************************************************* + void next_node(Node*& position) const + { + if (position) + { + // Is there a tree on the right? then find the minimum of that tree + if (position->children[kRight]) + { + // Return minimum node found + position = find_limit_node(position->children[kRight], kLeft); + } + // Otherwise find the parent of this node + else + { + // Start with current position as parent + Node* parent = position; + do { + // Update current position as previous parent + position = parent; + // Find parent of current position + parent = position->parent; // find_parent_node(root_node, position); + // Repeat while previous position was on right side of parent tree + } while (parent && parent->children[kRight] == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Find the next node in sequence from the node provided + //************************************************************************* + void next_node(const Node*& position) const + { + if (position) + { + // Is there a tree on the right? then find the minimum of that tree + if (position->children[kRight]) + { + // Return minimum node found + position = find_limit_node(position->children[kRight], kLeft); + } + // Otherwise find the parent of this node + else + { + // Start with current position as parent + const Node* parent = position; + do { + // Update current position as previous parent + position = parent; + // Find parent of current position + parent = position->parent; + // Repeat while previous position was on right side of parent tree + } while (parent && parent->children[kRight] == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Find the previous node in sequence from the node provided + //************************************************************************* + void prev_node(Node*& position) const + { + // If starting at the terminal end, the previous node is the maximum node + // from the root + if (!position) + { + position = find_limit_node(root_node, kRight); + } + else + { + // Is there a tree on the left? then find the maximum of that tree + if (position->children[kLeft]) + { + // Return maximum node found + position = find_limit_node(position->children[kLeft], kRight); + } + // Otherwise find the parent of this node + else + { + // Start with current position as parent + Node* parent = position; + do { + // Update current position as previous parent + position = parent; + // Find parent of current position + parent = position->parent; + // Repeat while previous position was on left side of parent tree + } while (parent && parent->children[kLeft] == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Find the previous node in sequence from the node provided + //************************************************************************* + void prev_node(const Node*& position) const + { + // If starting at the terminal end, the previous node is the maximum node + // from the root + if (!position) + { + position = find_limit_node(root_node, kRight); + } + else + { + // Is there a tree on the left? then find the maximum of that tree + if (position->children[kLeft]) + { + // Return maximum node found + position = find_limit_node(position->children[kLeft], kRight); + } + // Otherwise find the parent of this node + else + { + // Start with current position as parent + const Node* parent = position; + do { + // Update current position as previous parent + position = parent; + // Find parent of current position + parent = position->parent; + // Repeat while previous position was on left side of parent tree + } while (parent && parent->children[kLeft] == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Rotate two nodes at the position provided the to balance the tree + //************************************************************************* + void rotate_2node(Node*& position, uint8_t dir) + { + // A C A B + // B C -> A E OR B C -> D A + // D E B D D E E C + // C (new position) becomes the root + // A (position) takes ownership of D as its children[kRight] child + // C (new position) takes ownership of A as its left child + // OR + // B (new position) becomes the root + // A (position) takes ownership of E as its left child + // B (new position) takes ownership of A as its right child + + // Capture new root (either B or C depending on dir) and its parent + Node* new_root = position->children[dir]; + + // Replace position's previous child with new root's other child + position->children[dir] = new_root->children[1 - dir]; + // Update new root's other child parent pointer + if (position->children[dir]) + { + position->children[dir]->parent = position; + } + + // New root's parent becomes current position's parent + new_root->parent = position->parent; + new_root->children[1 - dir] = position; + new_root->dir = 1 - dir; + + // Clear weight factor from current position + position->weight = kNeither; + // Position's parent becomes new_root + position->parent = new_root; + position = new_root; + // Clear weight factor from new root + position->weight = kNeither; + } + + //************************************************************************* + /// Rotate three nodes at the position provided the to balance the tree + //************************************************************************* + void rotate_3node(Node*& position, uint8_t dir, uint8_t third) + { + // __A__ __E__ __A__ __D__ + // _B_ C -> B A OR B _C_ -> A C + // D E D F G C D E B F G E + // F G F G + // E (new position) becomes the root + // B (position) takes ownership of F as its left child + // A takes ownership of G as its right child + // OR + // D (new position) becomes the root + // A (position) takes ownership of F as its right child + // C takes ownership of G as its left child + + // Capture new root (either E or D depending on dir) + Node* new_root = position->children[dir]->children[1 - dir]; + // Set weight factor for B or C based on F or G existing and being a different than dir + position->children[dir]->weight = third != kNeither && third != dir ? dir : kNeither; + + // Detach new root from its tree (replace with new roots child) + position->children[dir]->children[1 - dir] = new_root->children[dir]; + // Update new roots child parent pointer + if (new_root->children[dir]) + { + new_root->children[dir]->parent = position->children[dir]; + } + + // Attach current left tree to new root and update its parent + new_root->children[dir] = position->children[dir]; + position->children[dir]->parent = new_root; + + // Set weight factor for A based on F or G + position->weight = third != kNeither && third == dir ? 1 - dir : kNeither; + + // Move new root's right tree to current roots left tree + position->children[dir] = new_root->children[1 - dir]; + if (new_root->children[1 - dir]) + { + new_root->children[1 - dir]->parent = position; + } + + // Attach current root to new roots right tree and assume its parent + new_root->parent = position->parent; + new_root->children[1 - dir] = position; + new_root->dir = 1 - dir; + + // Update current position's parent and replace with new root + position->parent = new_root; + position = new_root; + // Clear weight factor for new current position + position->weight = kNeither; + } + + size_type current_size; ///< The number of the used nodes. + const size_type MAX_SIZE; ///< The maximum size of the set. + Node* root_node; ///< The node that acts as the multiset root. + }; +} + +#endif diff --git a/set_base.h b/set_base.h index f33d3fe6..1148bfac 100644 --- a/set_base.h +++ b/set_base.h @@ -6,7 +6,7 @@ The MIT License(MIT) Embedded Template Library. https://github.com/ETLCPP/etl -Copyright(c) 2014 jwellbelove, rlindeman +Copyright(c) 2015 jwellbelove, rlindeman Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal @@ -27,8 +27,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ******************************************************************************/ -#if !defined(__ETL_IN_ISET_H__) && !defined(__ETL_IN_IMULTISET_H__) -#error This header is a private element of etl::set, etl::multiset & etl::iset, etl::imultiset +#if !defined(__ETL_IN_ISET_H__) +#error This header is a private element of etl::set & etl::iset #endif #ifndef __ETL_SET_BASE__ @@ -157,18 +157,261 @@ namespace etl protected: + static const uint8_t kLeft = 0; + static const uint8_t kRight = 1; + static const uint8_t kNeither = 2; + + //************************************************************************* + /// The node element in the set. + //************************************************************************* + struct Node + { + //*********************************************************************** + /// Constructor + //*********************************************************************** + Node() : + weight(kNeither), + dir(kNeither) + { + } + + //*********************************************************************** + /// Marks the node as a leaf. + //*********************************************************************** + void mark_as_leaf() + { + weight = kNeither; + dir = kNeither; + children[0] = nullptr; + children[1] = nullptr; + } + + Node* children[2]; + uint8_t weight; + uint8_t dir; + }; + //************************************************************************* /// The constructor that is called from derived classes. //************************************************************************* set_base(size_type max_size) : current_size(0) , MAX_SIZE(max_size) + , root_node(nullptr) { } + //************************************************************************* + /// Attach the provided node to the position provided + //************************************************************************* + void attach_node(Node*& position, Node& node) + { + // Mark new node as leaf on attach to tree at position provided + node.mark_as_leaf(); + + // Add the node here + position = &node; + + // One more. + ++current_size; + } + + //************************************************************************* + /// Detach the node at the position provided + //************************************************************************* + void detach_node(Node*& position, Node*& replacement) + { + // Make temporary copy of actual nodes involved because we might lose + // their references in the process (e.g. position is the same as + // replacement or replacement is a child of position) + Node* detached = position; + Node* swap = replacement; + + // Update current position to point to swap (replacement) node first + position = swap; + + // Update replacement node to point to child in opposite direction + // otherwise we might lose the other child of the swap node + replacement = swap->children[1 - swap->dir]; + + // Point swap node to detached node's children and weight + swap->children[kLeft] = detached->children[kLeft]; + swap->children[kRight] = detached->children[kRight]; + swap->weight = detached->weight; + } + + //************************************************************************* + /// Balance the critical node at the position provided as needed + //************************************************************************* + void balance_node(Node*& critical_node) + { + // Step 1: Update weights for all children of the critical node up to the + // newly inserted node. This step is costly (in terms of traversing nodes + // multiple times during insertion) but doesn't require as much recursion + Node* weight_node = critical_node->children[critical_node->dir]; + while (weight_node) + { + // Keep going until we reach a terminal node (dir == kNeither) + if (kNeither != weight_node->dir) + { + // Does this insert balance the previous weight factor value? + if (weight_node->weight == 1 - weight_node->dir) + { + weight_node->weight = kNeither; + } + else + { + weight_node->weight = weight_node->dir; + } + + // Update weight factor node to point to next node + weight_node = weight_node->children[weight_node->dir]; + } + else + { + // Stop loop, terminal node found + break; + } + } // while(weight_node) + + // Step 2: Update weight for critical_node or rotate tree to balance node + if (kNeither == critical_node->weight) + { + critical_node->weight = critical_node->dir; + } + // If direction is different than weight, then it will now be balanced + else if (critical_node->dir != critical_node->weight) + { + critical_node->weight = kNeither; + } + // Rotate is required to balance the tree at the critical node + else + { + // If critical node matches child node direction then perform a two + // node rotate in the direction of the critical node + if (critical_node->weight == critical_node->children[critical_node->dir]->dir) + { + rotate_2node(critical_node, critical_node->dir); + } + // Otherwise perform a three node rotation in the direction of the + // critical node + else + { + rotate_3node(critical_node, critical_node->dir, + critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir); + } + } + } + + //************************************************************************* + /// Find the node whose key would go before all the other keys from the + /// position provided + //************************************************************************* + Node* find_limit_node(Node* position, const int8_t dir) const + { + // Something at this position and in the direction specified? keep going + Node* limit_node = position; + while (limit_node && limit_node->children[dir]) + { + limit_node = limit_node->children[dir]; + } + + // Return the limit node position found + return limit_node; + } + + //************************************************************************* + /// Find the node whose key would go before all the other keys from the + /// position provided + //************************************************************************* + const Node* find_limit_node(const Node* position, const int8_t dir) const + { + // Something at this position and in the direction specified? keep going + const Node* limit_node = position; + while (limit_node && limit_node->children[dir]) + { + limit_node = limit_node->children[dir]; + } + + // Return the limit node position found + return limit_node; + } + + //************************************************************************* + /// Rotate two nodes at the position provided the to balance the tree + //************************************************************************* + void rotate_2node(Node*& position, uint8_t dir) + { + // A C A B + // B C -> A E OR B C -> D A + // D E B D D E E C + // C (new position) becomes the root + // A (position) takes ownership of D as its children[kRight] child + // C (new position) takes ownership of A as its left child + // OR + // B (new position) becomes the root + // A (position) takes ownership of E as its left child + // B (new position) takes ownership of A as its right child + + // Capture new root + Node* new_root = position->children[dir]; + // Replace position's previous child with new root's other child + position->children[dir] = new_root->children[1 - dir]; + // New root now becomes parent of current position + new_root->children[1 - dir] = position; + // Clear weight factor from current position + position->weight = kNeither; + // Newly detached right now becomes current position + position = new_root; + // Clear weight factor from new root + position->weight = kNeither; + } + + //************************************************************************* + /// Rotate three nodes at the position provided the to balance the tree + //************************************************************************* + void rotate_3node(Node*& position, uint8_t dir, uint8_t third) + { + // __A__ __E__ __A__ __D__ + // _B_ C -> B A OR B _C_ -> A C + // D E D F G C D E B F G E + // F G F G + // E (new position) becomes the root + // B (position) takes ownership of F as its left child + // A takes ownership of G as its right child + // OR + // D (new position) becomes the root + // A (position) takes ownership of F as its right child + // C takes ownership of G as its left child + + // Capture new root (either E or D depending on dir) + Node* new_root = position->children[dir]->children[1 - dir]; + // Set weight factor for B or C based on F or G existing and being a different than dir + position->children[dir]->weight = third != kNeither && third != dir ? dir : kNeither; + + // Detach new root from its tree (replace with new roots child) + position->children[dir]->children[1 - dir] = + new_root->children[dir]; + // Attach current left tree to new root + new_root->children[dir] = position->children[dir]; + // Set weight factor for A based on F or G + position->weight = third != kNeither && third == dir ? 1 - dir : kNeither; + + // Move new root's right tree to current roots left tree + position->children[dir] = new_root->children[1 - dir]; + // Attach current root to new roots right tree + new_root->children[1 - dir] = position; + // Replace current position with new root + position = new_root; + // Clear weight factor for new current position + position->weight = kNeither; + } + + size_type current_size; ///< The number of the used nodes. const size_type MAX_SIZE; ///< The maximum size of the set. + Node* root_node; ///< The node that acts as the set root. }; } diff --git a/test/test_basic_intrusive_forward_list.cpp b/test/test_basic_intrusive_forward_list.cpp new file mode 100644 index 00000000..30ee12d1 --- /dev/null +++ b/test/test_basic_intrusive_forward_list.cpp @@ -0,0 +1,582 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl + +Copyright(c) 2015 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. +******************************************************************************/ + +#include +#include "ExtraCheckMacros.h" + +#include "data.h" + +#include "../basic_intrusive_forward_list.h" + +#include +#include +#include +#include +#include +#include + +typedef TestDataDC ItemDC; +typedef TestDataNDC ItemNDC; + +namespace +{ + class ItemDCNode : public etl::basic_intrusive_forward_list_node + { + public: + + ItemDCNode(const std::string& text) + : data(text) + { + } + + ItemDC data; + }; + + class ItemNDCNode : public etl::basic_intrusive_forward_list_node + { + public: + + ItemNDCNode(const std::string& text) + : data(text) + { + } + + bool operator <(const ItemNDCNode& other) const + { + return data < other.data; + } + + ItemNDC data; + }; + + bool operator ==(const ItemDCNode& lhs, const ItemDCNode& rhs) + { + return lhs.data == rhs.data; + } + + bool operator ==(const ItemNDCNode& lhs, const ItemNDCNode& rhs) + { + return lhs.data == rhs.data; + } + + std::ostream& operator << (std::ostream& os, const ItemNDCNode& node) + { + os << node.data; + return os; + } + + struct CompareItemNDCNode + { + bool operator ()(const ItemNDCNode& lhs, const ItemNDCNode& rhs) const + { + return lhs.data < rhs.data; + } + }; + + struct EqualItemNDCNode + { + bool operator ()(const ItemNDCNode& lhs, const ItemNDCNode& rhs) const + { + return lhs.data == rhs.data; + } + }; +} + +namespace +{ + SUITE(test_forward_list) + { + typedef etl::basic_intrusive_forward_list DataDC; + typedef etl::basic_intrusive_forward_list DataNDC; + + typedef std::vector InitialDataNDC; + + InitialDataNDC unsorted_data; + InitialDataNDC sorted_data; + InitialDataNDC non_unique_data; + InitialDataNDC unique_data; + InitialDataNDC small_data; + + bool are_equal; + + //************************************************************************* + struct SetupFixture + { + SetupFixture() + { + unsorted_data = { ItemNDCNode("1"), ItemNDCNode("0"), ItemNDCNode("3"), ItemNDCNode("2"), ItemNDCNode("5"), ItemNDCNode("4"), ItemNDCNode("7"), ItemNDCNode("6"), ItemNDCNode("9"), ItemNDCNode("8") }; + sorted_data = { ItemNDCNode("0"), ItemNDCNode("1"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("4"), ItemNDCNode("5"), ItemNDCNode("6"), ItemNDCNode("7"), ItemNDCNode("8"), ItemNDCNode("9") }; + non_unique_data = { ItemNDCNode("0"), ItemNDCNode("0"), ItemNDCNode("1"), ItemNDCNode("1"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("3"), ItemNDCNode("3"), ItemNDCNode("4"), ItemNDCNode("5") }; + unique_data = { ItemNDCNode("0"), ItemNDCNode("1"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("4"), ItemNDCNode("5") }; + small_data = { ItemNDCNode("0"), ItemNDCNode("1"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("4"), ItemNDCNode("5") }; + } + }; + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_default_constructor) + { + DataNDC data; + DataNDC data1; + + CHECK(data.empty()); + CHECK(data1.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_constructor_range) + { + DataNDC data(sorted_data.begin(), sorted_data.end()); + + CHECK(!data.empty()); + } + + ////************************************************************************* + TEST_FIXTURE(SetupFixture, test_iterator) + { + DataNDC data(sorted_data.begin(), sorted_data.end()); + + InitialDataNDC::iterator isorted = sorted_data.begin(); + DataNDC::iterator idata = data.begin(); + + while (isorted != sorted_data.end()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *isorted; + CHECK(are_equal); + ++idata; + ++isorted; + } + } + + ////************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_iterator) + { + DataNDC data(sorted_data.begin(), sorted_data.end()); + + InitialDataNDC::const_iterator isorted = sorted_data.cbegin(); + DataNDC::const_iterator idata = data.cbegin(); + + while (isorted != sorted_data.cend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *isorted; + CHECK(are_equal); + ++idata; + ++isorted; + } + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_clear) + { + DataNDC data(sorted_data.begin(), sorted_data.end()); + data.clear(); + + CHECK(data.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_assign_range) + { + DataNDC data; + + // Do it twice. We should only get one copy. + data.assign(sorted_data.begin(), sorted_data.end()); + data.assign(sorted_data.begin(), sorted_data.end()); + + InitialDataNDC::const_iterator isorted = sorted_data.cbegin(); + DataNDC::const_iterator idata = data.cbegin(); + + while (isorted != sorted_data.cend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *isorted; + CHECK(are_equal); + ++idata; + ++isorted; + } + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_after_position_value) + { + ItemNDCNode INSERT_VALUE1 = ItemNDCNode("1"); + ItemNDCNode INSERT_VALUE2 = ItemNDCNode("2"); + + std::vector compare_data(sorted_data.begin(), sorted_data.end()); + DataNDC data(sorted_data.begin(), sorted_data.end()); + + size_t offset = 2; + + DataNDC::iterator i_data = data.begin(); + std::advance(i_data, offset); + + std::vector::iterator i_compare_data = compare_data.begin(); + std::advance(i_compare_data, offset + 1); + + data.insert_after(i_data, INSERT_VALUE1); + compare_data.insert(i_compare_data, INSERT_VALUE1); + + InitialDataNDC::const_iterator icompare = compare_data.cbegin(); + DataNDC::const_iterator idata = data.cbegin(); + + while (icompare != compare_data.cend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *icompare; + CHECK(are_equal); + ++idata; + ++icompare; + } + CHECK_EQUAL(compare_data.size(), std::distance(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_after_range) + { + std::vector test1 = { ItemNDCNode("0"), ItemNDCNode("1"), ItemNDCNode("2"), ItemNDCNode("3"), ItemNDCNode("4") }; + std::vector test2 = { ItemNDCNode("5"), ItemNDCNode("6"), ItemNDCNode("7"), ItemNDCNode("8"), ItemNDCNode("9") }; + std::vector compare(test2); + compare.insert(compare.end(), test1.begin(), test1.end()); + + size_t final_size = test1.size() + test2.size(); + + DataNDC data(test1.begin(), test1.end()); + + data.insert_after(data.before_begin(), test2.begin(), test2.end()); + + InitialDataNDC::const_iterator icompare = compare.cbegin(); + DataNDC::const_iterator idata = data.cbegin(); + + while (icompare != compare.cend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *icompare; + CHECK(are_equal); + ++idata; + ++icompare; + } + + CHECK_EQUAL(final_size, std::distance(data.begin(), data.end())); + + compare.assign(test1.begin(), test1.end()); + data.assign(test1.begin(), test1.end()); + + std::vector::iterator icd = compare.begin(); + DataNDC::iterator id = data.begin(); + + std::advance(icd, 4); + std::advance(id, 3); + + compare.insert(icd, test2.begin(), test2.end()); + data.insert_after(id, test2.begin(), test2.end()); + + icompare = compare.cbegin(); + idata = data.cbegin(); + + while (icompare != compare.cend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *icompare; + CHECK(are_equal); + ++idata; + ++icompare; + } + + CHECK_EQUAL(final_size, std::distance(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_push_front) + { + std::list compare_data; + DataNDC data; + + ItemNDCNode node1("1"); + ItemNDCNode node2("2"); + ItemNDCNode node3("3"); + ItemNDCNode node4("4"); + ItemNDCNode node5("5"); + ItemNDCNode node6("6"); + + compare_data.push_front(node1); + compare_data.push_front(node2); + compare_data.push_front(node3); + compare_data.push_front(node4); + compare_data.push_front(node5); + compare_data.push_front(node6); + + data.push_front(node1); + data.push_front(node2); + data.push_front(node3); + data.push_front(node4); + data.push_front(node5); + data.push_front(node6); + + std::list::const_iterator icompare = compare_data.cbegin(); + DataNDC::const_iterator idata = data.cbegin(); + + while (icompare != compare_data.cend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *icompare; + CHECK(are_equal); + ++idata; + ++icompare; + } + CHECK_EQUAL(6, std::distance(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_push_front_pop_front) + { + DataNDC data; + + ItemNDCNode node1("1"); + ItemNDCNode node2("2"); + ItemNDCNode node3("3"); + ItemNDCNode node4("4"); + ItemNDCNode node5("5"); + ItemNDCNode node6("6"); + + data.push_front(node1); + data.push_front(node2); + data.push_front(node3); + data.push_front(node4); + data.push_front(node5); + data.push_front(node6); + + CHECK_EQUAL(6, std::distance(data.begin(), data.end())); + CHECK(!data.empty()); + + data.pop_front(); + data.pop_front(); + data.pop_front(); + data.pop_front(); + data.pop_front(); + + CHECK_EQUAL(1, std::distance(data.begin(), data.end())); + CHECK(!data.empty()); + + data.pop_front(); + + CHECK_EQUAL(0, std::distance(data.begin(), data.end())); + CHECK(data.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_after_single) + { + std::vector compare_data(sorted_data.begin(), sorted_data.end()); + DataNDC data(sorted_data.begin(), sorted_data.end()); + + DataNDC::iterator i_data = data.begin(); + std::advance(i_data, 2); + + std::vector::iterator i_compare_data = compare_data.begin(); + std::advance(i_compare_data, 3); + + i_compare_data = compare_data.erase(i_compare_data); + i_data = data.erase_after(i_data); + + std::vector::const_iterator icompare = compare_data.cbegin(); + DataNDC::const_iterator idata = data.cbegin(); + + while (icompare != compare_data.cend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *icompare; + CHECK(are_equal); + ++idata; + ++icompare; + } + + CHECK(*i_compare_data == i_data.ref_cast()); + + i_compare_data = compare_data.erase(compare_data.begin() + 1); + i_data = data.erase_after(data.begin()); + + icompare = compare_data.cbegin(); + idata = data.cbegin(); + + while (icompare != compare_data.cend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *icompare; + CHECK(are_equal); + ++idata; + ++icompare; + } + + CHECK_EQUAL(compare_data.size(), std::distance(data.begin(), data.end())); + + // Move to the last value and erase. + i_compare_data = compare_data.begin() + 1; + i_compare_data = compare_data.erase(i_compare_data); + + i_data = data.begin(); + i_data = data.erase_after(i_data); + + icompare = compare_data.cbegin(); + idata = data.cbegin(); + + while (icompare != compare_data.cend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *icompare; + CHECK(are_equal); + ++idata; + ++icompare; + } + + CHECK_EQUAL(compare_data.size(), std::distance(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_after_range) + { + std::vector compare_data(sorted_data.begin(), sorted_data.end()); + DataNDC data(sorted_data.begin(), sorted_data.end()); + + DataNDC::iterator i_data_1 = data.begin(); + std::advance(i_data_1, 2); + + DataNDC::iterator i_data_2 = data.begin(); + std::advance(i_data_2, 4); + + std::vector::iterator i_compare_data_1 = compare_data.begin(); + std::advance(i_compare_data_1, 3); + + std::vector::iterator i_compare_data_2 = compare_data.begin(); + std::advance(i_compare_data_2, 4); + + std::vector::iterator i_compare_result = compare_data.erase(i_compare_data_1, i_compare_data_2); + + DataNDC::iterator i_result = data.erase_after(i_data_1, i_data_2); + + CHECK_EQUAL(*i_compare_result, i_result.ref_cast()); + + std::vector::const_iterator icompare = compare_data.cbegin(); + DataNDC::const_iterator idata = data.cbegin(); + + while (icompare != compare_data.cend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *icompare; + CHECK(are_equal); + ++idata; + ++icompare; + } + + CHECK_EQUAL(compare_data.size(), std::distance(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_after_range_end) + { + std::vector compare_data(sorted_data.begin(), sorted_data.end()); + DataNDC data(sorted_data.begin(), sorted_data.end()); + + DataNDC::iterator i_data = data.begin(); + std::advance(i_data, 4); + + std::vector::iterator i_compare_data = compare_data.begin(); + std::advance(i_compare_data, 5); + + std::vector::iterator i_compare_result = compare_data.erase(i_compare_data, compare_data.end()); + + DataNDC::iterator i_result = data.erase_after(i_data, data.end()); + + CHECK(i_result == data.end()); + + std::vector::const_iterator icompare = compare_data.cbegin(); + DataNDC::const_iterator idata = data.cbegin(); + + while (icompare != compare_data.cend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *icompare; + CHECK(are_equal); + ++idata; + ++icompare; + } + + CHECK_EQUAL(compare_data.size(), std::distance(data.begin(), data.end())); + + icompare = compare_data.cbegin(); + idata = data.cbegin(); + + while (icompare != compare_data.cend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *icompare; + CHECK(are_equal); + ++idata; + ++icompare; + } + + CHECK_EQUAL(compare_data.size(), std::distance(data.begin(), data.end())); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_after_all) + { + DataNDC data(sorted_data.begin(), sorted_data.end()); + + data.erase_after(data.before_begin(), data.end()); + + CHECK(data.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_front) + { + DataNDC data(sorted_data.begin(), sorted_data.end()); + + CHECK_EQUAL(sorted_data.front(), data.front()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_reverse) + { + DataNDC data(sorted_data.begin(), sorted_data.end()); + data.reverse(); + + InitialDataNDC::const_reverse_iterator isorted = sorted_data.crbegin(); + DataNDC::const_iterator idata = data.cbegin(); + + while (isorted != sorted_data.crend()) + { + const ItemNDCNode& item = idata.ref_cast(); + are_equal = item == *isorted; + CHECK(are_equal); + ++idata; + ++isorted; + } + } + }; +} diff --git a/test/test_bitset.cpp b/test/test_bitset.cpp index e832dced..2ad08c82 100644 --- a/test/test_bitset.cpp +++ b/test/test_bitset.cpp @@ -141,6 +141,29 @@ namespace } } + //************************************************************************* + TEST(test_base_set) + { + std::bitset<60> compare; + etl::bitset<60> data; + + etl::ibitset& idata = data; + + compare.set(); + idata.set(); + + CHECK_EQUAL(compare.size(), idata.size()); + CHECK_EQUAL(compare.count(), idata.count()); + CHECK_EQUAL(compare.none(), idata.none()); + CHECK_EQUAL(compare.any(), idata.any()); + CHECK_EQUAL(compare.all(), idata.all()); + + for (size_t i = 0; i < data.size(); ++i) + { + CHECK_EQUAL(compare.test(i), idata.test(i)); + } + } + //************************************************************************* TEST(test_string_set) { @@ -192,20 +215,44 @@ namespace etl::bitset<60> data(0xFFFFFFFFFFFFFFF); compare.reset(); - data.reset(); + etl::bitset<60>& rdata = data.reset(); - CHECK_EQUAL(compare.size(), data.size()); - CHECK_EQUAL(compare.count(), data.count()); - CHECK_EQUAL(compare.none(), data.none()); - CHECK_EQUAL(compare.any(), data.any()); - CHECK_EQUAL(compare.all(), data.all()); + CHECK_EQUAL(compare.size(), rdata.size()); + CHECK_EQUAL(compare.count(), rdata.count()); + CHECK_EQUAL(compare.none(), rdata.none()); + CHECK_EQUAL(compare.any(), rdata.any()); + CHECK_EQUAL(compare.all(), rdata.all()); - for (size_t i = 0; i < data.size(); ++i) + for (size_t i = 0; i < rdata.size(); ++i) { - CHECK_EQUAL(compare.test(i), data.test(i)); + CHECK_EQUAL(compare.test(i), rdata.test(i)); } } + //************************************************************************* + TEST(test_base_reset) + { + std::bitset<60> compare(0xFFFFFFFFFFFFFFF); + etl::bitset<60> data(0xFFFFFFFFFFFFFFF); + etl::ibitset& idata = data; + + etl::ibitset& ridata = idata.reset(); + + compare.reset(); + + CHECK_EQUAL(compare.size(), ridata.size()); + CHECK_EQUAL(compare.count(), ridata.count()); + CHECK_EQUAL(compare.none(), ridata.none()); + CHECK_EQUAL(compare.any(), ridata.any()); + CHECK_EQUAL(compare.all(), ridata.all()); + + for (size_t i = 0; i < ridata.size(); ++i) + { + CHECK_EQUAL(compare.test(i), ridata.test(i)); + } + } + + //************************************************************************* TEST(test_position_reset) { @@ -328,6 +375,23 @@ namespace } } + //************************************************************************* + TEST(test_base_flip) + { + std::bitset<60> compare; + etl::bitset<60> data; + + etl::ibitset& idata = data; + + compare.flip(); + idata.flip(); + + for (size_t i = 0; i < idata.size(); ++i) + { + CHECK_EQUAL(compare.test(i), idata.test(i)); + } + } + //************************************************************************* TEST(test_flip_position) { @@ -561,6 +625,37 @@ namespace CHECK(data2 == data3); } + //************************************************************************* + TEST(test_index_operator) + { + etl::bitset<60> data1(0x123456781234567); + etl::bitset<60> data2; + + for (size_t i = 0; i < data1.size(); ++i) + { + data2[i] = data1[i]; + } + + CHECK(data1 == data2); + } + + //************************************************************************* + TEST(test_base_index_operator) + { + etl::bitset<60> data1(0x123456781234567); + etl::bitset<60> data2; + + etl::ibitset& idata1 = data1; + etl::ibitset& idata2 = data2; + + for (size_t i = 0; i < idata1.size(); ++i) + { + idata2[i] = idata1[i]; + } + + CHECK(data1 == data2); + } + //************************************************************************* TEST(test_big_bitset) { @@ -679,66 +774,5 @@ namespace CHECK(data1 == compare2); CHECK(data2 == compare1); } - - //************************************************************************* - TEST(test_iterator) - { - typedef etl::bitset<16> Bitset; - - Bitset data("1111000011001010"); - Bitset data2(data); - - int i; - - // Read - Bitset::iterator b1 = data.begin(); - Bitset::iterator e1 = data.end(); - - CHECK_EQUAL(16, std::distance(b1, e1)); - - i = 0; - while (b1 != e1) - { - CHECK_EQUAL(data[i], *b1); - ++b1; - ++i; - } - - Bitset::iterator b2 = data2.begin(); - Bitset::iterator e2 = data2.end(); - - CHECK_EQUAL(16, std::distance(b2, e2)); - - // Write - i = 0; - while (b2 != e2) - { - *b2 = !*b2; - CHECK_EQUAL(!data[i], *b2); - ++b2; - ++i; - } - } - - //************************************************************************* - TEST(test_const_iterator) - { - typedef etl::bitset<16> Bitset; - Bitset data("1111000011001010"); - - // const_iterator - Bitset::const_iterator b1 = data.cbegin(); - Bitset::const_iterator e1 = data.cend(); - - CHECK_EQUAL(16, std::distance(b1, e1)); - - int i = 0; - while (b1 != e1) - { - CHECK_EQUAL(data[i], *b1); - ++b1; - ++i; - } - } }; } diff --git a/test/test_compile.cpp b/test/test_compile.cpp index 3f6a1bcd..9cd4f01b 100644 --- a/test/test_compile.cpp +++ b/test/test_compile.cpp @@ -142,18 +142,18 @@ void test_array() //***************************************************************************** void test_bitset() { - etl::bitset<7> b7; // uint8_t - etl::bitset<8> b8; // uint8_t - etl::bitset<9> b9; // uint16_t - etl::bitset<15> b15; // uint16_t - etl::bitset<16> b16; // uint16_t - etl::bitset<17> b17; // uint32_t - etl::bitset<31> b31; // uint32_t - etl::bitset<32> b32; // uint32_t - etl::bitset<33> b33; // uint64_t - etl::bitset<63> b63; // uint64_t - etl::bitset<64> b64; // uint64_t - etl::bitset<65> b65; // 2 * uint64_t + etl::bitset<7> b7; + etl::bitset<8> b8; + etl::bitset<9> b9; + etl::bitset<15> b15; + etl::bitset<16> b16; + etl::bitset<17> b17; + etl::bitset<31> b31; + etl::bitset<32> b32; + etl::bitset<33> b33; + etl::bitset<63> b63; + etl::bitset<64> b64; + etl::bitset<65> b65; b65.set(); b65.set(4, true); @@ -165,20 +165,16 @@ void test_bitset() b65.flip(); b65.flip(5); - etl::bitset<7>::iterator b1 = b7.begin(); - etl::bitset<7>::iterator e1 = b7.end(); - etl::bitset<7>::const_iterator b2 = b7.cbegin(); - etl::bitset<7>::const_iterator e2 = b7.cend(); + etl::ibitset& ib = b65; - ++b1; - --e1; - b2 += 2; - e2 -= 2; - - *b1 = true; - - const etl::bitset<7>::iterator b3 = b7.begin(); - bool t = *b3; + ib.set(); + ib.set(4, true); + ib.reset(); + ib.reset(37); + b = ib[4]; + b = ib[64]; + ib.flip(); + ib.flip(5); } //***************************************************************************** diff --git a/test/test_deque.cpp b/test/test_deque.cpp index ed804c69..7ea2f25d 100644 --- a/test/test_deque.cpp +++ b/test/test_deque.cpp @@ -1460,5 +1460,16 @@ namespace CHECK(deque1 != deque2); } + + //************************************************************************* + TEST(test_iterator_comparison_empty) + { + DataNDC data; + + CHECK(data.begin() == data.end()); + CHECK(data.cbegin() == data.cend()); + CHECK(data.rbegin() == data.rend()); + CHECK(data.crbegin() == data.crend()); + } }; } diff --git a/test/test_intrusive_forward_list.cpp b/test/test_intrusive_forward_list.cpp index c389c660..a8472c16 100644 --- a/test/test_intrusive_forward_list.cpp +++ b/test/test_intrusive_forward_list.cpp @@ -41,69 +41,71 @@ SOFTWARE. typedef TestDataDC ItemDC; typedef TestDataNDC ItemNDC; - -class ItemDCNode : public etl::intrusive_forward_list_node<2> +namespace { -public: - - ItemDCNode(const std::string& text) - : data(text) + class ItemDCNode : public etl::intrusive_forward_list_node<2> { - } + public: - ItemDC data; -}; + ItemDCNode(const std::string& text) + : data(text) + { + } -const size_t INDEXES = 2; + ItemDC data; + }; -class ItemNDCNode : public etl::intrusive_forward_list_node -{ -public: + const size_t INDEXES = 2; - ItemNDCNode(const std::string& text) - : data(text) + class ItemNDCNode : public etl::intrusive_forward_list_node { - } + public: - bool operator <(const ItemNDCNode& other) const - { - return data < other.data; - } + ItemNDCNode(const std::string& text) + : data(text) + { + } - ItemNDC data; -}; + bool operator <(const ItemNDCNode& other) const + { + return data < other.data; + } -bool operator ==(const ItemDCNode& lhs, const ItemDCNode& rhs) -{ - return lhs.data == rhs.data; -} + ItemNDC data; + }; -bool operator ==(const ItemNDCNode& lhs, const ItemNDCNode& rhs) -{ - return lhs.data == rhs.data; -} - -std::ostream& operator << (std::ostream& os, const ItemNDCNode& node) -{ - os << node.data; - return os; -} - -struct CompareItemNDCNode -{ - bool operator ()(const ItemNDCNode& lhs, const ItemNDCNode& rhs) const - { - return lhs.data < rhs.data; - } -}; - -struct EqualItemNDCNode -{ - bool operator ()(const ItemNDCNode& lhs, const ItemNDCNode& rhs) const + bool operator ==(const ItemDCNode& lhs, const ItemDCNode& rhs) { return lhs.data == rhs.data; } -}; + + bool operator ==(const ItemNDCNode& lhs, const ItemNDCNode& rhs) + { + return lhs.data == rhs.data; + } + + std::ostream& operator << (std::ostream& os, const ItemNDCNode& node) + { + os << node.data; + return os; + } + + struct CompareItemNDCNode + { + bool operator ()(const ItemNDCNode& lhs, const ItemNDCNode& rhs) const + { + return lhs.data < rhs.data; + } + }; + + struct EqualItemNDCNode + { + bool operator ()(const ItemNDCNode& lhs, const ItemNDCNode& rhs) const + { + return lhs.data == rhs.data; + } + }; +} namespace { diff --git a/test/test_multimap.cpp b/test/test_multimap.cpp index 5194384e..180ce8d0 100644 --- a/test/test_multimap.cpp +++ b/test/test_multimap.cpp @@ -396,7 +396,7 @@ namespace { Data data(initial_data.begin(), initial_data.end()); - CHECK_THROW(data.insert(std::make_pair(std::string("10"), 10)), etl::map_full); + CHECK_THROW(data.insert(std::make_pair(std::string("10"), 10)), etl::multimap_full); } //************************************************************************* @@ -436,7 +436,7 @@ namespace { Data data; - CHECK_THROW(data.insert(excess_data.begin(), excess_data.end()), etl::map_full); + CHECK_THROW(data.insert(excess_data.begin(), excess_data.end()), etl::multimap_full); } //************************************************************************* diff --git a/test/test_multiset.cpp b/test/test_multiset.cpp index 04d2638a..7ba863ef 100644 --- a/test/test_multiset.cpp +++ b/test/test_multiset.cpp @@ -371,7 +371,7 @@ namespace { Data data(initial_data.begin(), initial_data.end()); - CHECK_THROW(data.insert(10), etl::set_full); + CHECK_THROW(data.insert(10), etl::multiset_full); } //************************************************************************* @@ -411,7 +411,7 @@ namespace { Data data; - CHECK_THROW(data.insert(excess_data.begin(), excess_data.end()), etl::set_full); + CHECK_THROW(data.insert(excess_data.begin(), excess_data.end()), etl::multiset_full); } //************************************************************************* diff --git a/test/test_vector.cpp b/test/test_vector.cpp index e6adc3ed..bdd2ca47 100644 --- a/test/test_vector.cpp +++ b/test/test_vector.cpp @@ -79,6 +79,17 @@ namespace CHECK_EQUAL(data.max_size(), SIZE); } + //************************************************************************* + TEST(test_iterator_comparison_empty) + { + Data data; + + CHECK(data.begin() == data.end()); + CHECK(data.cbegin() == data.cend()); + CHECK(data.rbegin() == data.rend()); + CHECK(data.crbegin() == data.crend()); + } + //************************************************************************* TEST_FIXTURE(SetupFixture, test_constructor_size) { diff --git a/test/vs2015/etl.vcxproj b/test/vs2015/etl.vcxproj index 04b94e74..79f31dcb 100644 --- a/test/vs2015/etl.vcxproj +++ b/test/vs2015/etl.vcxproj @@ -120,6 +120,8 @@ + + @@ -171,6 +173,7 @@ + @@ -193,7 +196,9 @@ + + @@ -262,6 +267,7 @@ ../../../unittest-cpp false + @@ -323,8 +329,6 @@ - - diff --git a/test/vs2015/etl.vcxproj.filters b/test/vs2015/etl.vcxproj.filters index ae59a793..848a444d 100644 --- a/test/vs2015/etl.vcxproj.filters +++ b/test/vs2015/etl.vcxproj.filters @@ -450,6 +450,21 @@ ETL\Containers + + ETL\Containers + + + ETL\Containers + + + ETL\Containers + + + ETL\Containers + + + ETL\Containers + @@ -692,12 +707,13 @@ Source Files + + Source Files + Header Files - - \ No newline at end of file