diff --git a/imap.h b/imap.h new file mode 100644 index 00000000..22ef529e --- /dev/null +++ b/imap.h @@ -0,0 +1,1779 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. + +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. +******************************************************************************/ + +#ifndef __ETL_IMAP__ +#define __ETL_IMAP__ +#define __ETL_IN_IMAP_H__ + +#include +#include +#include +#include + +#include "nullptr.h" +#include "map_base.h" +#include "type_traits.h" +#include "parameter_type.h" +#include "pool.h" + +#include // FIXME: Remove with std::cout + +#if WIN32 +#undef min +#endif + +namespace etl +{ + //*************************************************************************** + /// A templated base for all etl::map types. + ///\ingroup map + //*************************************************************************** + template + class imap : public map_base + { + public: + + typedef std::pair value_type; + typedef TKey key_type; + typedef TMapped mapped_type; + typedef TKeyCompare key_compare; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef size_t size_type; + + //************************************************************************* + /// How to compare two key elements. + //************************************************************************* + struct key_comp + { + bool operator ()(const key_type& key1, const key_type& key2) const + { + return key_compare()(key1, key2); + } + }; + + //************************************************************************* + /// How to compare two value elements. + //************************************************************************* + struct value_comp + { + bool operator ()(const value_type& value1, const value_type& value2) const + { + return key_compare()(value1.first, value2.first); + } + }; + + protected: + //************************************************************************* + /// The node element in the map. + //************************************************************************* + struct Node + { + //*********************************************************************** + /// Constructor + //*********************************************************************** + Node() + : left(nullptr) + , right(nullptr) + { + } + + //*********************************************************************** + /// Determines if the node is a leaf. + //*********************************************************************** + bool is_leaf() const + { + return left == nullptr && right == nullptr; + } + + //*********************************************************************** + /// Marks the node as a leaf. + //*********************************************************************** + void mark_as_leaf() + { + left = nullptr; + right = nullptr; + } + + + Node* left; + Node* right; + }; + + //************************************************************************* + /// The data node element in the map. + //************************************************************************* + struct Data_Node : public Node + { + explicit Data_Node(value_type value) + : value(value) + { + } + + value_type value; + }; + + /// Defines the key value parameter type + typedef typename parameter_type::type key_value_parameter_t; + + //************************************************************************* + /// How to compare node elements. + //************************************************************************* + bool node_comp(const Data_Node& node1, const Data_Node& node2) const + { + 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); + } + + private: + + /// 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* + //************************************************************************* + static Data_Node* data_cast(Node* p_node) + { + return static_cast(p_node); + } + + //************************************************************************* + /// Downcast a Node& to a Data_Node& + //************************************************************************* + static Data_Node& data_cast(Node& node) + { + return static_cast(node); + } + + //************************************************************************* + /// Downcast a const Node* to a const Data_Node* + //************************************************************************* + static const Data_Node* data_cast(const Node* p_node) + { + return static_cast(p_node); + } + + //************************************************************************* + /// Downcast a const Node& to a const Data_Node& + //************************************************************************* + static const Data_Node& data_cast(const Node& node) + { + return static_cast(node); + } + + public: + //************************************************************************* + /// iterator. + //************************************************************************* + class iterator : public std::iterator + { + public: + + friend class imap; + + iterator() + : p_map(nullptr) + , p_node(nullptr) + { + } + + iterator(imap& map) + : p_map(&map) + , p_node(nullptr) + { + } + + iterator(imap& map, Node* node) + : p_map(&map) + , p_node(node) + { + } + + iterator(const iterator& other) + : p_map(other.p_map) + , p_node(other.p_node) + { + } + + ~iterator() + { + } + + iterator& operator ++() + { + p_map->next_node(p_node); + return *this; + } + + iterator operator ++(int) + { + iterator temp(*this); + p_map->next_node(p_node); + return temp; + } + + iterator& operator --() + { + p_map->prev_node(p_node); + return *this; + } + + iterator operator --(int) + { + iterator temp(*this); + p_map->prev_node(p_node); + return temp; + } + + iterator operator =(const iterator& other) + { + p_map = other.p_map; + p_node = other.p_node; + return *this; + } + + reference operator *() + { + return imap::data_cast(p_node)->value; + } + + const_reference operator *() const + { + return imap::data_cast(p_node)->value; + } + + pointer operator &() + { + return &(imap::data_cast(p_node)->value); + } + + const_pointer operator &() const + { + return &(imap::data_cast(p_node)->value); + } + + pointer operator ->() + { + return &(imap::data_cast(p_node)->value); + } + + const_pointer operator ->() const + { + return &(imap::data_cast(p_node)->value); + } + + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.p_map == rhs.p_map && lhs.p_node == rhs.p_node; + } + + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + // Pointer to map associated with this iterator + imap* p_map; + + // Pointer to the current node for this iterator + Node* p_node; + }; + friend iterator; + + //************************************************************************* + /// const_iterator + //************************************************************************* + class const_iterator : public std::iterator + { + public: + + friend class imap; + + const_iterator() + : p_map(nullptr) + , p_node(nullptr) + { + } + + const_iterator(const imap& map) + : p_map(&map) + , p_node(nullptr) + { + } + + const_iterator(const imap& map, const Node* node) + : p_map(&map) + , p_node(node) + { + } + + const_iterator(const typename imap::iterator& other) + : p_map(other.p_map) + , p_node(other.p_node) + { + } + + const_iterator(const const_iterator& other) + : p_map(other.p_map) + , p_node(other.p_node) + { + } + + ~const_iterator() + { + } + + const_iterator& operator ++() + { + p_map->next_node(p_node); + return *this; + } + + const_iterator operator ++(int) + { + const_iterator temp(*this); + p_map->next_node(p_node); + return temp; + } + + const_iterator& operator --() + { + p_map->prev_node(p_node); + return *this; + } + + const_iterator operator --(int) + { + const_iterator temp(*this); + p_map->prev_node(p_node); + return temp; + } + + const_iterator operator =(const const_iterator& other) + { + p_map = other.p_map; + p_node = other.p_node; + return *this; + } + + const_reference operator *() const + { + return imap::data_cast(p_node)->value; + } + + const_pointer operator &() const + { + return imap::data_cast(p_node)->value; + } + + const_pointer operator ->() const + { + return &(imap::data_cast(p_node)->value); + } + + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.p_map == rhs.p_map && lhs.p_node == rhs.p_node; + } + + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + private: + // Pointer to map associated with this iterator + const imap* p_map; + + // Pointer to the current node for this iterator + const Node* p_node; + }; + friend const_iterator; + + typedef typename std::iterator_traits::difference_type difference_type; + + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + imap& operator = (const imap& rhs) + { + assign(rhs.cbegin(), rhs.cend()); + + return *this; + } + + //************************************************************************* + /// Gets the beginning of the map. + //************************************************************************* + iterator begin() + { + return iterator(*this, lower_node(root_node)); + } + + //************************************************************************* + /// Gets the beginning of the map. + //************************************************************************* + const_iterator begin() const + { + return const_iterator(*this, lower_node(root_node)); + } + + //************************************************************************* + /// Gets the end of the map. + //************************************************************************* + iterator end() + { + return iterator(*this); + } + + //************************************************************************* + /// Gets the end of the map. + //************************************************************************* + const_iterator end() const + { + return const_iterator(*this); + } + + //************************************************************************* + /// Gets the beginning of the map. + //************************************************************************* + const_iterator cbegin() const + { + return const_iterator(*this, lower_node(root_node)); + } + + //************************************************************************* + /// Gets the end of the map. + //************************************************************************* + const_iterator cend() const + { + return const_iterator(*this); + } + + //************************************************************************* + /// Gets the reverse beginning of the list. + //************************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(iterator(*this)); + } + + //************************************************************************* + /// Gets the reverse beginning of the list. + //************************************************************************* + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(const_iterator(*this)); + } + + //************************************************************************* + /// Gets the reverse end of the list. + //************************************************************************* + reverse_iterator rend() + { + return reverse_iterator(iterator(*this, lower_node(root_node))); + } + + //************************************************************************* + /// Gets the reverse end of the list. + //************************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(iterator(*this, lower_node(root_node))); + } + + //************************************************************************* + /// Gets the reverse beginning of the list. + //************************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(const_iterator(*this)); + } + + //************************************************************************* + /// Gets the reverse end of the list. + //************************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(const_iterator(*this, lower_node(root_node))); + } + + //********************************************************************* + /// Returns a reference to the value at index 'key' + ///\param i The index. + ///\return A reference to the value at index 'key' + //********************************************************************* + mapped_type& operator [](const key_value_parameter_t key) + { + iterator i_element = find(key); + + if (!i_element.p_node) + { + // Doesn't exist, so create a new one. + i_element = insert(std::make_pair(key, mapped_type())).first; + } + + return i_element->second; + } + + //********************************************************************* + /// Returns a reference to the value at index 'key' + /// If ETL_THROW_EXCEPTIONS is defined, emits an etl::lookup_out_of_bounds if the key is not in the range. + ///\param i The index. + ///\return A reference to the value at index 'key' + //********************************************************************* + mapped_type& at(const key_value_parameter_t key) + { + iterator i_element = find(key); + + if (!i_element.p_node) + { + // Doesn't exist. +#if ETL_THROW_EXCEPTIONS + throw map_out_of_bounds(); +#else + error_handler::error(map_out_of_bounds()); + +#endif + } + + return i_element->second; + } + + //********************************************************************* + /// Returns a const reference to the value at index 'key' + /// If ETL_THROW_EXCEPTIONS is defined, emits an etl::lookup_out_of_bounds if the key is not in the range. + ///\param i The index. + ///\return A const reference to the value at index 'key' + //********************************************************************* + const mapped_type& at(const key_value_parameter_t key) const + { + const_iterator i_element = find(key); + + if (!i_element.p_node) + { + // Doesn't exist. +#if ETL_THROW_EXCEPTIONS + throw map_out_of_bounds(); +#else + error_handler::error(map_out_of_bounds()); + +#endif + } + + return i_element->second; + } + + //********************************************************************* + /// Assigns values to the map. + /// If ETL_THROW_EXCEPTIONS is defined, emits map_full if the map does not have enough free space. + /// If ETL_THROW_EXCEPTIONS is defined, emits map_iterator if the iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template + void assign(TIterator first, TIterator last) + { + initialise(); + insert(first, last); + } + + //************************************************************************* + /// Clears the map. + //************************************************************************* + void clear() + { + initialise(); + } + + //********************************************************************* + /// Counts the number of elements that contain the key specified. + ///\param key The key to search for. + ///\return 1 if element was found, 0 otherwise. + //********************************************************************* + size_type count(const key_value_parameter_t key) const + { + return find_node(root_node, key) ? 1 : 0; + } + + //************************************************************************* + /// Returns two iterators with bounding (lower bound, upper bound) the key + /// provided + //************************************************************************* + std::pair equal_range(const key_type& key) + { + return std::make_pair( + iterator(*this, lower_node(root_node, key)), + iterator(*this, upper_node(root_node, key))); + } + + //************************************************************************* + /// Returns two const iterators with bounding (lower bound, upper bound) + /// the key provided. + //************************************************************************* + std::pair equal_range(const key_type& key) const + { + return std::make_pair( + const_iterator(*this, lower_node(root_node, key)), + const_iterator(*this, upper_node(root_node, key))); + } + + //************************************************************************* + /// Erases the value at the specified position. + //************************************************************************* + void erase(iterator position) + { + // Remove the node by its key + erase((*position).first); + } + + //************************************************************************* + /// Erases the value at the specified position. + //************************************************************************* + iterator erase(const_iterator position) + { + // Find the parent node to be removed + Node* found_parent = find_parent_node(root_node, position.p_node); + iterator next(*this, found_parent->left == position.p_node ? + found_parent->left : found_parent->right); + ++next; + + remove_node(found_parent->left == position.p_node ? + found_parent->left : found_parent->right, position->first); + + return next; + } + + //************************************************************************* + // Erase the key specified. + //************************************************************************* + size_type erase(const key_value_parameter_t key) + { + // Return 1 if key value was found and removed + return remove_node(root_node, key) ? 1 : 0; + } + + //************************************************************************* + /// Erases a range of elements. + //************************************************************************* + iterator erase(iterator first, iterator last) + { + while (first != last) + { + erase(first++); + } + + return last; + } + + //************************************************************************* + /// Erases a range of elements. + //************************************************************************* + iterator erase(const_iterator first, const_iterator last) + { + iterator next; + while (first != last) + { + next = erase(first++); + } + + return next; + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + iterator find(const key_value_parameter_t key) + { + return iterator(*this, find_node(root_node, key)); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + const_iterator find(const key_value_parameter_t key) const + { + return const_iterator(*this, find_node(root_node, key)); + } + + //********************************************************************* + /// Inserts a value to the map. + /// If ETL_THROW_EXCEPTIONS is defined, emits map_full if the map is already full. + ///\param value The value to insert. + //********************************************************************* + std::pair insert(const value_type& value) + { + // Default to no inserted node + Node* inserted_node = nullptr; + bool inserted = false; + + if (!full()) + { + // Get next available free node + Data_Node& node = allocate_data_node(value); + + // Obtain the inserted node (might be nullptr if node was a duplicate) + inserted_node = insert_node(root_node, node); + inserted = inserted_node == &node; + } + else + { +#ifdef ETL_THROW_EXCEPTIONS + throw map_full(); +#else + error_handler::error(map_full()); +#endif + } + + // Insert node into tree and return iterator to new node location in tree + return std::make_pair(iterator(*this, inserted_node), inserted); + } + + //********************************************************************* + /// Inserts a value to the map starting at the position recommended. + /// If ETL_THROW_EXCEPTIONS is defined, emits map_full if the map is already full. + ///\param position The position that would preceed the value to insert. + ///\param value The value to insert. + //********************************************************************* + iterator insert(iterator position, const value_type& value) + { + // Default to no inserted node + Node* inserted_node = nullptr; + + if (!full()) + { + // Get next available free node + Data_Node& node = allocate_data_node(value); + + // Obtain the inserted node (might be nullptr if node was a duplicate) + inserted_node = insert_node(find_node(root_node, position.p_node), node); + } + else + { +#ifdef ETL_THROW_EXCEPTIONS + throw map_full(); +#else + error_handler::error(map_full()); +#endif + } + + // Insert node into tree and return iterator to new node location in tree + return iterator(*this, inserted_node); + } + + //********************************************************************* + /// Inserts a value to the map starting at the position recommended. + /// If ETL_THROW_EXCEPTIONS is defined, emits map_full if the map is already full. + ///\param position The position that would preceed the value to insert. + ///\param value The value to insert. + //********************************************************************* + iterator insert(const_iterator position, const value_type& value) + { + // Default to no inserted node + Node* inserted_node = nullptr; + + if (!full()) + { + // Get next available free node + Data_Node& node = allocate_data_node(value); + + // Obtain the inserted node (might be nullptr if node was a duplicate) + inserted_node = insert_node(find_node(root_node, position.p_node), node); + } + else + { +#ifdef ETL_THROW_EXCEPTIONS + throw map_full(); +#else + error_handler::error(map_full()); +#endif + } + + // Insert node into tree and return iterator to new node location in tree + return iterator(*this, inserted_node); + } + + //********************************************************************* + /// Inserts a range of values to the map. + /// If ETL_THROW_EXCEPTIONS is defined, emits map_full if the map does not have enough free space. + ///\param position The position to insert at. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template + void insert(TIterator first, TIterator last) + { + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Returns an iterator pointing to the first element in the container + /// whose key is not considered to go before the key provided or end() + /// if all keys are considered to go before the key provided. + ///\return An iterator pointing to the element not before key or end() + //********************************************************************* + iterator lower_bound(const key_value_parameter_t key) + { + return iterator(*this, lower_node(root_node, key)); + } + + //********************************************************************* + /// Returns a const_iterator pointing to the first element in the + /// container whose key is not considered to go before the key provided + /// or end() if all keys are considered to go before the key provided. + ///\return An const_iterator pointing to the element not before key or end() + //********************************************************************* + const_iterator lower_bound(const key_value_parameter_t key) const + { + return const_iterator(*this, lower_node(root_node, key)); + } + + //********************************************************************* + /// Returns an iterator pointing to the first element in the container + /// whose key is not considered to go after the key provided or end() + /// if all keys are considered to go after the key provided. + ///\return An iterator pointing to the element after key or end() + //********************************************************************* + iterator upper_bound(const key_value_parameter_t key) + { + return iterator(*this, upper_node(root_node, key)); + } + + //********************************************************************* + /// Returns a const_iterator pointing to the first element in the + /// container whose key is not considered to go after the key provided + /// or end() if all keys are considered to go after the key provided. + ///\return An const_iterator pointing to the element after key or end() + //********************************************************************* + const_iterator upper_bound(const key_value_parameter_t key) const + { + return const_iterator(*this, upper_node(root_node, key)); + } + + protected: + + //************************************************************************* + /// Constructor. + //************************************************************************* + imap(ipool& node_pool, size_t max_size_) + : map_base(max_size_) + , p_node_pool(&node_pool) + , root_node(nullptr) + { + initialise(); + } + + private: + + //************************************************************************* + /// Allocate a Data_Node. + //************************************************************************* + Data_Node& allocate_data_node(value_type value) const + { + return *(p_node_pool->allocate(Data_Node(value))); + } + + //************************************************************************* + /// Destroy a Data_Node. + //************************************************************************* + void destroy_data_node(Data_Node& node) const + { + p_node_pool->release(&node); + } + + //************************************************************************* + /// Initialise the map. + //************************************************************************* + void initialise() + { + if (!empty()) + { + p_node_pool->release_all(); + } + + current_size = 0; + 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; + } + + //************************************************************************* + /// Detach the node at the position provided + //************************************************************************* + Node* detach_node(Node*& position) + { + // The node being detached + Node* detached = position; + + // The node to be swapped with current position (might be nullptr) + Node* swap_node = nullptr; + + // Found the node to be removed, does it have other nodes on the left? + if (position->left) + { + // Find the upper node and its parent from the left of the current position + Node* upper_parent_node = position; + Node* upper_node = position->left; + while (upper_node && upper_node->right) + { + upper_parent_node = upper_node; + upper_node = upper_node->right; + } + + // Recursively call detach_node for the upper node found above + swap_node = detach_node(upper_parent_node->left == upper_node ? + upper_parent_node->left : upper_parent_node->right); + } + // Found the node to be removed, does it have other nodes on the right? + else if (position->right) + { + // Find the lower node and its parent from the right of the current position + Node* lower_parent_node = position; + Node* lower_node = position->right; + while (lower_node && lower_node->left) + { + lower_parent_node = lower_node; + lower_node = lower_node->left; + } + // Cast lower node into a data node to retrieve the key value + Data_Node* lower_data_node = imap::data_cast(lower_node); + + // Recursively call detach_node for the lower node found + swap_node = detach_node(lower_parent_node->left == lower_node ? + lower_parent_node->left : lower_parent_node->right); + } + + // If a swap node was provided above, update its child trees + if (swap_node) + { + // Move children of position as new children of swap node + swap_node->left = position->left; + swap_node->right = position->right; + } + + // Update current position to point to swap node + position = swap_node; + + // Return the detached node + return detached; + } + + //************************************************************************* + /// Find the value matching the node provided + //************************************************************************* + Node* find_node(Node* position, const key_value_parameter_t key) + { + Node* found = position; + while (found) + { + // Downcast found to Data_Node class for comparison and other operations + Data_Node& found_data_node = imap::data_cast(*found); + + // Compare the node value to the current position value + if (node_comp(key, found_data_node)) + { + // Keep searching for the node on the left + found = found->left; + } + else if (node_comp(found_data_node, key)) + { + // Keep searching for the node on the right + found = found->right; + } + else + { + // Node that matches the key provided was found, exit loop + break; + } + } + + // Return the node found (might be nullptr) + return found; + } + + //************************************************************************* + /// Find the value matching the node provided + //************************************************************************* + const Node* find_node(const Node* position, const key_value_parameter_t key) const + { + const Node* found = position; + while (found) + { + // Downcast found to Data_Node class for comparison and other operations + const Data_Node& found_data_node = imap::data_cast(*found); + + // Compare the node value to the current position value + if (node_comp(key, found_data_node)) + { + // Keep searching for the node on the left + found = found->left; + } + else if (node_comp(found_data_node, key)) + { + // Keep searching for the node on the right + found = found->right; + } + else + { + // Node that matches the key provided was found, exit loop + break; + } + } + + // Return the node found (might be nullptr) + return found; + } + + //************************************************************************* + /// Find the reference node matching the node provided + //************************************************************************* + Node*& find_node(Node*& position, const Node* node) + { + Node* found = position; + while (found) + { + if (found->left == node) + { + return found->left; + } + else if (found->right == node) + { + return found->right; + } + else + { + // Downcast found to Data_Node class for comparison and other operations + Data_Node& found_data_node = imap::data_cast(*found); + const Data_Node& data_node = imap::data_cast(*node); + + // Compare the node value to the current position value + if (node_comp(data_node, found_data_node)) + { + // Keep searching for the node on the left + found = found->left; + } + else if (node_comp(found_data_node, data_node)) + { + // Keep searching for the node on the right + found = found->right; + } + else + { + // Exit loop if duplicate was found + break; + } + } + } + + // Return the initial position provided if node not found + return position; + } + + //************************************************************************* + /// Find the parent node that contains the node provided in its left or + /// right tree + //************************************************************************* + Node* find_parent_node(Node* position, const Node* node) + { + // Default to no parent node found + Node* found = nullptr; + + // If the position provided is the same as the node then there is no parent + if (position && node && position != node) + { + while (position) + { + // Is this position not the parent of the node we are looking for? + if (position->left != node && position->right != node) + { + // Downcast node and position to Data_Node references for key comparisons + const Data_Node& node_data_node = imap::data_cast(*node); + Data_Node& position_data_node = imap::data_cast(*position); + // Compare the node value to the current position value + if (node_comp(node_data_node, position_data_node)) + { + // Keep looking for parent on the left + position = position->left; + } + else if (node_comp(position_data_node, node_data_node)) + { + // Keep looking for parent on the right + position = position->right; + } + } + else + { + // Return the current position as the parent node found + found = position; + + // Parent node found, exit loop + break; + } + } + } + + // Return the parent node found (might be nullptr) + return found; + } + + //************************************************************************* + /// Find the parent node that contains the node provided in its left or + /// right tree + //************************************************************************* + const Node* find_parent_node(const Node* position, const Node* node) const + { + // Default to no parent node found + const Node* found = nullptr; + + // If the position provided is the same as the node then there is no parent + if (position && node && position != node) + { + while (position) + { + // Is this position not the parent of the node we are looking for? + if (position->left != node && position->right != node) + { + // Downcast node and position to Data_Node references for key comparisons + const Data_Node& node_data_node = imap::data_cast(*node); + const Data_Node& position_data_node = imap::data_cast(*position); + // Compare the node value to the current position value + if (node_comp(node_data_node, position_data_node)) + { + // Keep looking for parent on the left + position = position->left; + } + else if (node_comp(position_data_node, node_data_node)) + { + // Keep looking for parent on the right + position = position->right; + } + } + else + { + // Return the current position as the parent node found + found = position; + + // Parent node found, exit loop + break; + } + } + } + + // Return the parent node found (might be nullptr) + return found; + } + + //************************************************************************* + /// Insert a node. + //************************************************************************* + Node* insert_node(Node*& position, Data_Node& node) + { + // Find the location where the node belongs + Node* found = position; + + // Was position provided not empty? then find where the node belongs + if (position) + { + while (found) + { + // Downcast found to Data_Node class for comparison and other operations + Data_Node& found_data_node = imap::data_cast(*found); + + // Is the node provided to the left of the current position? + if (node_comp(node, found_data_node)) + { + if (found->left) + { + // Node should be put on the left + found = found->left; + } + else + { + // Attatch node to left + attach_node(found->left, node); + + // Return newly added node + found = found->left; + + // Exit loop + break; + } + } + // Is the node provided to the right of the current position? + else if (node_comp(found_data_node, node)) + { + if (found->right) + { + // Node should be put on the right + found = found->right; + } + else + { + // Attatch node to right + attach_node(found->right, node); + + // Return newly added node + found = found->right; + + // Exit loop + break; + } + } + else + { + // Destroy the node provided (its a duplicate) + destroy_data_node(node); + + // Exit loop, duplicate node found + break; + } + } + } + else + { + // Attatch node to current position + attach_node(position, node); + + // Return newly added node at current position + found = position; + } + + // Return the node found (might be nullptr) + return found; + } + + //************************************************************************* + /// Find the node whose key would go before all the other keys from the + /// position provided + //************************************************************************* + Node* lower_node(Node* position) const + { + // Something at this position and on the left? keep going + Node* lower_node = position; + while (lower_node && lower_node->left) + { + lower_node = lower_node->left; + } + + // Return the lower node position found + return lower_node; + } + + //************************************************************************* + /// Find the node whose key is not considered to go before the key provided + //************************************************************************* + Node* lower_node(Node* position, const key_value_parameter_t key) const + { + // Something at this position? keep going + Node* lower_node = position; + while (lower_node) + { + // Downcast lower node to Data_Node reference for key comparisons + Data_Node& lower_data_node = imap::data_cast(*lower_node); + // Compare the key value to the current lower node key value + if (!node_comp(lower_data_node, key)) + { + break; + } + else + { + lower_node = lower_node->right; + } + } + + // Return the lower node position found + return lower_node; + } + + //************************************************************************* + /// Find the node whose key would go before all the other keys from the + /// position provided + //************************************************************************* + const Node* lower_node(const Node* position) const + { + // Something at this position and on the left? keep going + const Node* lower_node = position; + while (lower_node && lower_node->left) + { + lower_node = lower_node->left; + } + + // Return the lower node position found + return lower_node; + } + + //************************************************************************* + /// Find the node whose key is not considered to go before the key provided + //************************************************************************* + const Node& lower_node(const Node* position, const key_value_parameter_t key) const + { + // Something at this position? keep going + const Node* lower_node = position; + while (lower_node) + { + // Downcast lower node to Data_Node reference for key comparisons + const Data_Node& lower_data_node = imap::data_cast(*lower_node); + // Compare the key value to the current lower node key value + if (!node_comp(lower_data_node, key)) + { + break; + } + else + { + lower_node = lower_node->right; + } + } + + // Return the lower node position found + return lower_node; + } + + //************************************************************************* + /// Find the next node in sequence from the node provided + //************************************************************************* + void next_node(Node*&position) + { + if (position) + { + // Is there a tree on the right? then find the minimum of that tree + if (position->right) + { + // Return minimum node found + position = lower_node(position->right); + } + // 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 = find_parent_node(root_node, position); + // Repeat while previous position was on right side of parent tree + } while (parent && parent->right == 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->right) + { + // Return minimum node found + position = lower_node(position->right); + } + // 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 = find_parent_node(root_node, position); + // Repeat while previous position was on right side of parent tree + } while (parent && parent->right == 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) + { + // If starting at the terminal end, the previous node is the maximum node + // from the root + if (!position) + { + position = upper_node(root_node); + } + else + { + // Is there a tree on the left? then find the maximum of that tree + if (position->left) + { + // Return maximum node found + position = upper_node(position->left); + } + // 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 = find_parent_node(root_node, position); + // Repeat while previous position was on left side of parent tree + } while (parent && parent->left == 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 = upper_node(root_node); + } + else + { + // Is there a tree on the left? then find the maximum of that tree + if (position->left) + { + // Return maximum node found + position = upper_node(position->left); + } + // 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 = find_parent_node(root_node, position); + // Repeat while previous position was on left side of parent tree + } while (parent && parent->left == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Remove the node specified from somewhere starting at the position provided + //************************************************************************* + Node* remove_node(Node*& position, const key_value_parameter_t key) + { + // Step 1: Find the Node to be removed that matches the key provided + Node* found_parent = nullptr; + Node* found = position; + while (found) + { + // Downcast found to Data_Node class for comparison and other operations + Data_Node& found_data_node = imap::data_cast(*found); + + // Compare the node value to the current position value + if (node_comp(key, found_data_node)) + { + // Keep searching for the node to remove on the left + found_parent = found; + found = found->left; + } + else if (node_comp(found_data_node, key)) + { + // Keep searching for the node to remove on the right + found_parent = found; + found = found->right; + } + else + { + // Node that matches the key provided was found, exit loop + break; + } + } + + // Step 2: If the node was found, begin the remove process + if (found) + { + // Does found and position point to the same memory address? then proceed with remove + if (found == position) + { + // Detach the node at the current position + detach_node(position); + } + else + { + // Detach the node using a reference provided by the parent of the node + // found + detach_node(found_parent->left == found ? + found_parent->left : found_parent->right); + } + + // Downcast found into data node + Data_Node& found_data_node = imap::data_cast(*found); + + // One less. + --current_size; + + // Destroy the node removed + destroy_data_node(found_data_node); + } + + // If this is reached, the key value was not found and removed + return nullptr; + } + + //************************************************************************* + /// Find the node whose key would go before all the other keys from the + /// position provided + //************************************************************************* + Node* upper_node(Node* position) const + { + // Something at this position and on the right? keep going + Node* upper_node = position; + while (upper_node && upper_node->right) + { + upper_node = upper_node->right; + } + + // Return the upper node position found + return upper_node; + } + + //************************************************************************* + /// Find the node whose key is considered to go before the key provided + //************************************************************************* + Node* upper_node(Node* position, const key_value_parameter_t key) const + { + // Something at this position and on the right? keep going + Node* upper_node = position; + while (upper_node) + { + // Downcast position to Data_Node reference for key comparisons + Data_Node& upper_data_node = imap::data_cast(*upper_node); + // Compare the key value to the current upper node key value + if (!node_comp(key, upper_data_node)) + { + upper_node = upper_node->right; + } + else + { + break; + } + } + + // Return the upper node position found + return upper_node; + } + + //************************************************************************* + /// Find the node whose key would go before all the other keys from the + /// position provided + //************************************************************************* + const Node* upper_node(const Node* position) const + { + // Something at this position and on the right? keep going + Node* upper_node = position; + while (upper_node && upper_node->right) + { + upper_node = upper_node->right; + } + + // Return the upper node position found + return upper_node; + } + + //************************************************************************* + /// Find the node whose key is considered to go before the key provided + //************************************************************************* + const Node* upper_node(const Node* position, const key_value_parameter_t key) const + { + // Something at this position and on the right? keep going + const Node* upper_node = position; + while (upper_node) + { + // Downcast position to Data_Node reference for key comparisons + const Data_Node& upper_data_node = imap::data_cast(*upper_node); + // Compare the key value to the current upper node key value + if (!node_comp(key, upper_data_node)) + { + upper_node = upper_node->right; + } + else + { + break; + } + } + + // Return the upper node position found + return upper_node; + } + + }; +} + +//*************************************************************************** +/// Equal operator. +///\param lhs Reference to the first lookup. +///\param rhs Reference to the second lookup. +///\return true if the arrays are equal, otherwise false +///\ingroup lookup +//*************************************************************************** +template +bool operator ==(const etl::imap& lhs, const etl::imap& rhs) +{ + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); +} + +//*************************************************************************** +/// Not equal operator. +///\param lhs Reference to the first lookup. +///\param rhs Reference to the second lookup. +///\return true if the arrays are not equal, otherwise false +///\ingroup lookup +//*************************************************************************** +template +bool operator !=(const etl::imap& lhs, const etl::imap& rhs) +{ + return !(lhs == rhs); +} + +//************************************************************************* +/// Less than operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return true if the first list is lexicographically less than the +/// second, otherwise false. +//************************************************************************* +template +bool operator <(const etl::imap& lhs, const etl::imap& rhs) +{ + return std::lexicographical_compare(lhs.begin(), + lhs.end(), + rhs.begin(), + rhs.end()); +} + +//************************************************************************* +/// Greater than operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return true if the first list is lexicographically greater than the +/// second, otherwise false. +//************************************************************************* +template +bool operator >(const etl::imap& lhs, const etl::imap& rhs) +{ + return std::lexicographical_compare(lhs.begin(), + lhs.end(), + rhs.begin(), + rhs.end(), + std::greater()); +} + +//************************************************************************* +/// Less than or equal operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return true if the first list is lexicographically less than or equal +/// to the second, otherwise false. +//************************************************************************* +template +bool operator <=(const etl::imap& lhs, const etl::imap& rhs) +{ + return !operator >(lhs, rhs); +} + +//************************************************************************* +/// Greater than or equal operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return true if the first list is lexicographically greater than or +/// equal to the second, otherwise false. +//************************************************************************* +template +bool operator >=(const etl::imap& lhs, const etl::imap& rhs) +{ + return !operator <(lhs, rhs); +} + +#if WIN32 +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#undef __ETL_IN_IMAP_H__ + +#endif diff --git a/map.h b/map.h new file mode 100644 index 00000000..288ac794 --- /dev/null +++ b/map.h @@ -0,0 +1,110 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. + +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. +******************************************************************************/ + +#ifndef __ETL_MAP__ +#define __ETL_MAP__ + +#include +#include +#include + +#include "imap.h" +#include "container.h" +#include "pool.h" + +//***************************************************************************** +///\defgroup map map +/// A map with the capacity defined at compile time. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //************************************************************************* + /// A templated map implementation that uses a fixed size buffer. + //************************************************************************* + template > + class map : public imap + { + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Default constructor. + //************************************************************************* + map() + : imap(node_pool, MAX_SIZE) + { + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + explicit map(const map& other) + : imap(node_pool, MAX_SIZE) + { + imap::assign(other.cbegin(), other.cend()); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template + map(TIterator first, TIterator last) + : imap(node_pool, MAX_SIZE) + { + imap::insert(first, last); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + map& operator = (const map& rhs) + { + // Skip if doing self assignment + if (this != &rhs) + { + imap::assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + private: + + /// The pool of data nodes used for the map. + pool::Data_Node, MAX_SIZE> node_pool; + }; + +} + +#endif diff --git a/map_base.h b/map_base.h new file mode 100644 index 00000000..cbfb429a --- /dev/null +++ b/map_base.h @@ -0,0 +1,174 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. + +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. +******************************************************************************/ + +#ifndef __ETL_IN_IMAP_H__ +#error This header is a private element of etl::map & etl::imap +#endif + +#ifndef __ETL_MAP_BASE__ +#define __ETL_MAP_BASE__ + +#include +#include "exception.h" + +namespace etl +{ + //*************************************************************************** + /// Exception for the map. + ///\ingroup map + //*************************************************************************** + class map_exception : public exception + { + public: + + map_exception(const char* what) + : exception(what) + { + } + }; + + //*************************************************************************** + /// Full exception for the map. + ///\ingroup map + //*************************************************************************** + class map_full : public map_exception + { + public: + + map_full() + : map_exception("map: full") + { + } + }; + + //*************************************************************************** + /// Map out of bounds exception. + ///\ingroup map + //*************************************************************************** + class map_out_of_bounds : public map_exception + { + public: + + map_out_of_bounds() + : map_exception("map: out of bounds") + { + } + }; + + //*************************************************************************** + /// Iterator exception for the map. + ///\ingroup map + //*************************************************************************** + class map_iterator : public map_exception + { + public: + + map_iterator() + : map_exception("map: iterator problem") + { + } + }; + + //*************************************************************************** + /// The base class for all maps. + ///\ingroup map + //*************************************************************************** + class map_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: + + //************************************************************************* + /// The constructor that is called from derived classes. + //************************************************************************* + map_base(size_type max_size) + : current_size(0) + , MAX_SIZE(max_size) + + { + } + + size_type current_size; ///< The number of the used nodes. + const size_type MAX_SIZE; ///< The maximum size of the map. + }; +} + +#endif diff --git a/test/codeblocks/ETL.cbp b/test/codeblocks/ETL.cbp index 88f67df1..b922aa41 100644 --- a/test/codeblocks/ETL.cbp +++ b/test/codeblocks/ETL.cbp @@ -149,6 +149,7 @@ + @@ -160,6 +161,8 @@ + + @@ -203,6 +206,7 @@ + diff --git a/test/codeblocks/ETL.depend b/test/codeblocks/ETL.depend index 68e9b472..bce351d3 100644 --- a/test/codeblocks/ETL.depend +++ b/test/codeblocks/ETL.depend @@ -340,6 +340,16 @@ +1421601674 source:u:\users\john\documents\programming\github\etl\test\test_map.cpp + + "ExtraCheckMacros.h" + "../map.h" + "data.h" + + + + + 1418906586 u:\users\john\documents\programming\github\etl\test\extracheckmacros.h @@ -358,6 +368,12 @@ "container.h" "pool.h" +1421601517 u:\users\john\documents\programming\github\etl\map.h + + "imap.h" + "container.h" + "pool.h" + 1421608839 u:\users\john\documents\programming\github\etl\ilist.h @@ -369,10 +385,25 @@ "parameter_type.h" "pool.h" +1421608839 u:\users\john\documents\programming\github\etl\imap.h + + + + + "nullptr.h" + "map_base.h" + "type_traits.h" + "parameter_type.h" + "pool.h" + 1421068120 u:\users\john\documents\programming\github\etl\list_base.h "exception.h" +1421068120 u:\users\john\documents\programming\github\etl\map_base.h + + "exception.h" + 1414930704 source:u:\users\john\documents\programming\github\etl\test\test_math.cpp "../log.h" diff --git a/test/codeblocks/ETL.layout b/test/codeblocks/ETL.layout index 2a4844f1..bcdecb8b 100644 --- a/test/codeblocks/ETL.layout +++ b/test/codeblocks/ETL.layout @@ -31,6 +31,11 @@ + + + + + @@ -96,6 +101,11 @@ + + + + + diff --git a/test/iar/etl.dep b/test/iar/etl.dep index 3aec121a..c5851792 100644 --- a/test/iar/etl.dep +++ b/test/iar/etl.dep @@ -42,6 +42,7 @@ $PROJ_DIR$\..\..\ideque.h $PROJ_DIR$\..\..\iforward_list.h $PROJ_DIR$\..\..\ilist.h + $PROJ_DIR$\..\..\imap.h $PROJ_DIR$\..\..\ipool.h $PROJ_DIR$\..\..\integral_limits.h $PROJ_DIR$\..\..\iqueue.h @@ -52,6 +53,8 @@ $PROJ_DIR$\..\..\list.h $PROJ_DIR$\..\..\list_base.h $PROJ_DIR$\..\..\log.h + $PROJ_DIR$\..\..\map.h + $PROJ_DIR$\..\..\map_base.h $PROJ_DIR$\..\..\nullptr.h $PROJ_DIR$\..\..\observer.h $PROJ_DIR$\..\..\parameter_type.h diff --git a/test/iar/etl.ewp b/test/iar/etl.ewp index 69e419b6..7113198b 100644 --- a/test/iar/etl.ewp +++ b/test/iar/etl.ewp @@ -1994,6 +1994,9 @@ $PROJ_DIR$\..\..\ilist.h + + $PROJ_DIR$\..\..\imap.h + $PROJ_DIR$\..\..\integral_limits.h @@ -2018,6 +2021,12 @@ $PROJ_DIR$\..\..\list_base.h + + $PROJ_DIR$\..\..\map.h + + + $PROJ_DIR$\..\..\map_base.h + $PROJ_DIR$\..\..\log.h diff --git a/test/iar/etl.ewt b/test/iar/etl.ewt index 55ae1f95..3feeaf98 100644 --- a/test/iar/etl.ewt +++ b/test/iar/etl.ewt @@ -277,6 +277,9 @@ $PROJ_DIR$\..\..\ilist.h + + $PROJ_DIR$\..\..\imap.h + $PROJ_DIR$\..\..\integral_limits.h @@ -301,6 +304,12 @@ $PROJ_DIR$\..\..\list_base.h + + $PROJ_DIR$\..\..\map.h + + + $PROJ_DIR$\..\..\map_base.h + $PROJ_DIR$\..\..\log.h diff --git a/test/keil/Test1.uvoptx b/test/keil/Test1.uvoptx index d838d6fe..ceeeccbd 100644 --- a/test/keil/Test1.uvoptx +++ b/test/keil/Test1.uvoptx @@ -642,6 +642,19 @@ 0 0 0 + ..\..\imap.h + imap.h + 0 + 0 + + + 3 + 36 + 5 + 0 + 0 + 0 + 0 ..\..\integral_limits.h integral_limits.h 0 @@ -649,7 +662,7 @@ 3 - 36 + 37 5 0 0 @@ -662,7 +675,7 @@ 3 - 37 + 38 5 0 0 @@ -675,7 +688,7 @@ 3 - 38 + 39 5 0 0 @@ -688,7 +701,7 @@ 3 - 39 + 40 5 0 0 @@ -701,7 +714,7 @@ 3 - 40 + 41 5 0 0 @@ -714,7 +727,7 @@ 3 - 41 + 42 5 0 0 @@ -727,7 +740,7 @@ 3 - 42 + 43 5 0 0 @@ -740,7 +753,33 @@ 3 - 43 + 44 + 5 + 0 + 0 + 0 + 0 + ..\..\map.h + map.h + 0 + 0 + + + 3 + 45 + 5 + 0 + 0 + 0 + 0 + ..\..\map_base.h + map_base.h + 0 + 0 + + + 3 + 46 5 0 0 @@ -753,7 +792,7 @@ 3 - 44 + 47 5 0 0 @@ -766,7 +805,7 @@ 3 - 45 + 48 5 0 0 @@ -779,7 +818,7 @@ 3 - 46 + 49 5 0 0 @@ -792,7 +831,7 @@ 3 - 47 + 50 5 0 0 @@ -805,7 +844,7 @@ 3 - 48 + 51 5 0 0 @@ -818,7 +857,7 @@ 3 - 49 + 52 5 0 0 @@ -831,7 +870,7 @@ 3 - 50 + 53 5 0 0 @@ -844,7 +883,7 @@ 3 - 51 + 54 5 0 0 @@ -857,7 +896,7 @@ 3 - 52 + 55 5 0 0 @@ -870,7 +909,7 @@ 3 - 53 + 56 5 0 0 @@ -883,7 +922,7 @@ 3 - 54 + 57 5 0 0 @@ -896,7 +935,7 @@ 3 - 55 + 58 5 0 0 @@ -909,7 +948,7 @@ 3 - 56 + 59 5 0 0 @@ -922,7 +961,7 @@ 3 - 57 + 60 5 0 0 @@ -935,7 +974,7 @@ 3 - 58 + 61 5 0 0 @@ -948,7 +987,7 @@ 3 - 59 + 62 5 0 0 @@ -961,7 +1000,7 @@ 3 - 60 + 63 5 0 0 @@ -974,7 +1013,7 @@ 3 - 61 + 64 8 0 0 @@ -987,7 +1026,7 @@ 3 - 62 + 65 8 0 0 @@ -1000,7 +1039,7 @@ 3 - 63 + 66 8 0 0 @@ -1013,7 +1052,7 @@ 3 - 64 + 67 8 0 0 @@ -1026,7 +1065,7 @@ 3 - 65 + 68 8 0 0 @@ -1039,7 +1078,7 @@ 3 - 66 + 69 8 0 0 diff --git a/test/keil/Test1.uvprojx b/test/keil/Test1.uvprojx index c4c09e31..dc575780 100644 --- a/test/keil/Test1.uvprojx +++ b/test/keil/Test1.uvprojx @@ -588,6 +588,11 @@ 5 ..\..\ilist.h + + imap.h + 5 + ..\..\imap.h + integral_limits.h 5 @@ -628,6 +633,16 @@ 5 ..\..\list_base.h + + map.h + 5 + ..\..\map.h + + + map_base.h + 5 + ..\..\map_base.h + log.h 5 diff --git a/test/test_map.cpp b/test/test_map.cpp new file mode 100644 index 00000000..b0df7a05 --- /dev/null +++ b/test/test_map.cpp @@ -0,0 +1,786 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. + +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. +******************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include // FIXME: remove with cout + +#include "../map.h" + +static const size_t SIZE = 10; + +//typedef etl::map > Data; +//typedef std::map > Compare_Data; +typedef etl::map > Data; +typedef std::map > Compare_Data; +typedef Data::iterator Data_iterator; +typedef Data::const_iterator Data_const_iterator; + +//************************************************************************* +std::ostream& operator << (std::ostream& os, const Data_iterator& it) +{ + os << (*it).first << " " << (*it).second; + + return os; +} + +//************************************************************************* +std::ostream& operator << (std::ostream& os, const Data_const_iterator& it) +{ + os << (*it).first << " " << (*it).second; + + return os; +} + +namespace +{ + SUITE(test_map) + { + std::vector initial_data; + std::vector excess_data; + std::vector different_data; + + //************************************************************************* + template + bool Check_Equal(T1 begin1, T1 end1, T2 begin2) + { + while (begin1 != end1) + { + if ((begin1->first != begin2->first) || (begin1->second != begin2->second)) + { + return false; + } + + ++begin1; + ++begin2; + } + + return true; + } + + //************************************************************************* + struct SetupFixture + { + SetupFixture() + { + Data::value_type n[] = + { + { std::string("0"), 0 }, + { std::string("1"), 1 }, + { std::string("2"), 2 }, + { std::string("3"), 3 }, + { std::string("4"), 4 }, + { std::string("5"), 5 }, + { std::string("6"), 6 }, + { std::string("7"), 7 }, + { std::string("8"), 8 }, + { std::string("9"), 9 }, + }; + + Data::value_type n2[] = + { + { std::string("0"), 0 }, + { std::string("1"), 1 }, + { std::string("2"), 2 }, + { std::string("3"), 3 }, + { std::string("4"), 4 }, + { std::string("5"), 5 }, + { std::string("6"), 6 }, + { std::string("7"), 7 }, + { std::string("8"), 8 }, + { std::string("9"), 9 }, + { std::string("10"), 10 }, + }; + + Data::value_type n3[] = + { + { std::string("10"), 10 }, + { std::string("11"), 11 }, + { std::string("12"), 12 }, + { std::string("13"), 13 }, + { std::string("14"), 14 }, + { std::string("15"), 15 }, + { std::string("16"), 16 }, + { std::string("17"), 17 }, + { std::string("18"), 18 }, + { std::string("19"), 19 }, + }; + + initial_data.assign(std::begin(n), std::end(n)); + excess_data.assign(std::begin(n2), std::end(n2)); + different_data.assign(std::begin(n3), std::end(n3)); + } + }; + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_default_constructor) + { + Data data; + + CHECK_EQUAL(data.size(), size_t(0)); + CHECK(data.empty()); + CHECK_EQUAL(data.capacity(), SIZE); + CHECK_EQUAL(data.max_size(), SIZE); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_constructor_range) + { + Compare_Data compare_data(initial_data.begin(), initial_data.end()); + + Data data(compare_data.begin(), compare_data.end()); + + CHECK(data.size() == SIZE); + CHECK(!data.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_assignment) + { + Data data(initial_data.begin(), initial_data.end()); + Data otherData; + + otherData = data; + + bool isEqual = Check_Equal(data.begin(), + data.end(), + otherData.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_begin) + { + Data data(initial_data.begin(), initial_data.end()); + const Data constData(data); + + CHECK_EQUAL(data.begin(), std::begin(data)); + CHECK_EQUAL(constData.begin(), std::begin(constData)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_end) + { + Data data(initial_data.begin(), initial_data.end()); + const Data constData(data); + + CHECK_EQUAL(data.end(), std::end(data)); + CHECK_EQUAL(constData.end(), std::end(constData)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_empty) + { + Data data; + data.insert(initial_data.begin(), initial_data.end()); + + CHECK(data.full()); + CHECK(!data.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_full) + { + Data data; + + CHECK(!data.full()); + CHECK(data.empty()); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_index) + { + Compare_Data compare_data(initial_data.begin(), initial_data.end()); + + Data data(compare_data.begin(), compare_data.end()); + + CHECK_EQUAL(data["0"], compare_data["0"]); + CHECK_EQUAL(data["1"], compare_data["1"]); + CHECK_EQUAL(data["2"], compare_data["2"]); + CHECK_EQUAL(data["3"], compare_data["3"]); + CHECK_EQUAL(data["4"], compare_data["4"]); + CHECK_EQUAL(data["5"], compare_data["5"]); + CHECK_EQUAL(data["6"], compare_data["6"]); + CHECK_EQUAL(data["7"], compare_data["7"]); + CHECK_EQUAL(data["8"], compare_data["8"]); + CHECK_EQUAL(data["9"], compare_data["9"]); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_at) + { + Compare_Data compare_data(initial_data.begin(), initial_data.end()); + Data data(initial_data.begin(), initial_data.end()); + + CHECK_EQUAL(data.at("0"), compare_data.at("0")); + CHECK_EQUAL(data.at("1"), compare_data.at("1")); + CHECK_EQUAL(data.at("2"), compare_data.at("2")); + CHECK_EQUAL(data.at("3"), compare_data.at("3")); + CHECK_EQUAL(data.at("4"), compare_data.at("4")); + CHECK_EQUAL(data.at("5"), compare_data.at("5")); + CHECK_EQUAL(data.at("6"), compare_data.at("6")); + CHECK_EQUAL(data.at("7"), compare_data.at("7")); + CHECK_EQUAL(data.at("8"), compare_data.at("8")); + CHECK_EQUAL(data.at("9"), compare_data.at("9")); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_at_const) + { + const Compare_Data compare_data(initial_data.begin(), initial_data.end()); + const Data data(initial_data.begin(), initial_data.end()); + + CHECK_EQUAL(data.at("0"), compare_data.at("0")); + CHECK_EQUAL(data.at("1"), compare_data.at("1")); + CHECK_EQUAL(data.at("2"), compare_data.at("2")); + CHECK_EQUAL(data.at("3"), compare_data.at("3")); + CHECK_EQUAL(data.at("4"), compare_data.at("4")); + CHECK_EQUAL(data.at("5"), compare_data.at("5")); + CHECK_EQUAL(data.at("6"), compare_data.at("6")); + CHECK_EQUAL(data.at("7"), compare_data.at("7")); + CHECK_EQUAL(data.at("8"), compare_data.at("8")); + CHECK_EQUAL(data.at("9"), compare_data.at("9")); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_assign_range) + { + Compare_Data compare_data(initial_data.begin(), initial_data.end()); + + Data data; + + data.assign(compare_data.begin(), compare_data.end()); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_value) + { + Compare_Data compare_data; + Data data; + + std::pair data_result = + data.insert(Data::value_type(std::string("0"), 0)); + std::pair compare_result = + compare_data.insert(std::make_pair(std::string("0"), 0)); + + // Check that both return successful return results + CHECK_EQUAL(data_result.first->first, compare_result.first->first); + CHECK_EQUAL(data_result.second, compare_result.second); + + // Try adding a duplicate (should return iterator pointing to duplicate) + data_result = data.insert(Data::value_type(std::string("0"), 0)); + compare_result = compare_data.insert(std::make_pair(std::string("0"), 0)); + + // Check that both return successful return results + CHECK_EQUAL(data_result.first->first, compare_result.first->first); + CHECK_EQUAL(data_result.second, compare_result.second); + + // Check that elements in map are the same + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + CHECK(isEqual); + + data.insert(std::make_pair(std::string("2"), 2)); + compare_data.insert(std::make_pair(std::string("2"), 2)); + + isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + + data.insert(std::make_pair(std::string("1"), 1)); + compare_data.insert(std::make_pair(std::string("1"), 1)); + + isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_hint_value) + { + Compare_Data compare_data; + Data data; + + std::pair data_result = + data.insert(Data::value_type(std::string("2"), 2)); + std::pair compare_result = + compare_data.insert(std::make_pair(std::string("2"), 2)); + + // Check that both return successful return results + CHECK_EQUAL(data_result.first->first, compare_result.first->first); + CHECK_EQUAL(data_result.second, compare_result.second); + + // Check that elements in map are the same + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + CHECK(isEqual); + + data.insert(data_result.first, std::make_pair(std::string("1"), 1)); + compare_data.insert(compare_result.first, std::make_pair(std::string("1"), 1)); + + isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_const_hint_value) + { + Compare_Data compare_data; + Data data; + + std::pair data_result = + data.insert(Data::value_type(std::string("2"), 2)); + std::pair compare_result = + compare_data.insert(std::make_pair(std::string("2"), 2)); + + // Check that both return successful return results + CHECK_EQUAL(data_result.first->first, compare_result.first->first); + CHECK_EQUAL(data_result.second, compare_result.second); + + // Check that elements in map are the same + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + CHECK(isEqual); + + data.insert(Data::const_iterator(data_result.first), + std::make_pair(std::string("1"), 1)); + compare_data.insert(Compare_Data::const_iterator(compare_result.first), + std::make_pair(std::string("1"), 1)); + + isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_value_excess) + { + Data data(initial_data.begin(), initial_data.end()); + + CHECK_THROW(data.insert(std::make_pair(std::string("10"), 10)), etl::map_full); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_range) + { + Compare_Data compare_data; + Data data; + + data.insert(initial_data.begin(), initial_data.end()); + compare_data.insert(initial_data.begin(), initial_data.end()); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_insert_range_excess) + { + Data data; + + CHECK_THROW(data.insert(excess_data.begin(), excess_data.end()), etl::map_full); + } + + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_equal_range) + { + Compare_Data compare_data(initial_data.begin(), initial_data.end()); + Data data(initial_data.begin(), initial_data.end()); + + std::pair data_result = + data.equal_range("2"); + std::pair compare_result = + compare_data.equal_range("2"); + + // Check that both return the same return results + CHECK_EQUAL(data_result.first->first, compare_result.first->first); + CHECK_EQUAL(data_result.first->second, compare_result.first->second); + CHECK_EQUAL(data_result.second->first, compare_result.second->first); + CHECK_EQUAL(data_result.second->second, compare_result.second->second); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_equal_range) + { + const Compare_Data compare_data(initial_data.begin(), initial_data.end()); + const Data data(initial_data.begin(), initial_data.end()); + + std::pair data_result = + data.equal_range("2"); + std::pair compare_result = + compare_data.equal_range("2"); + + // Check that both return the same return results + CHECK_EQUAL(data_result.first->first, compare_result.first->first); + CHECK_EQUAL(data_result.first->second, compare_result.first->second); + CHECK_EQUAL(data_result.second->first, compare_result.second->first); + CHECK_EQUAL(data_result.second->second, compare_result.second->second); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_value) + { + Compare_Data compare_data(initial_data.begin(), initial_data.end()); + Data data(initial_data.begin(), initial_data.end()); + + compare_data.erase("5"); + data.erase("5"); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_single) + { + Compare_Data compare_data(initial_data.begin(), initial_data.end()); + Data data(initial_data.begin(), initial_data.end()); + + Compare_Data::iterator i_compare = compare_data.begin(); + Data::iterator i_data = data.begin(); + + std::advance(i_compare, 2); + std::advance(i_data, 2); + + compare_data.erase(i_compare); + data.erase(i_data); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_erase_single) + { + Compare_Data compare_data(initial_data.begin(), initial_data.end()); + Data data(initial_data.begin(), initial_data.end()); + + Compare_Data::const_iterator i_compare = compare_data.begin(); + Data::const_iterator i_data = data.begin(); + + std::advance(i_compare, 2); + std::advance(i_data, 2); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + + Compare_Data::const_iterator i_compare1 = compare_data.erase(i_compare); + Data::const_iterator i_data1 = data.erase(i_data); + + CHECK_EQUAL(i_compare1->second, i_data1->second); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_erase_range) + { + Compare_Data compare_data(initial_data.begin(), initial_data.end()); + Data data(initial_data.begin(), initial_data.end()); + + Compare_Data::iterator i_compare = compare_data.begin(); + Data::iterator i_data = data.begin(); + + Compare_Data::iterator i_compare_end = compare_data.begin(); + Data::iterator i_data_end = data.begin(); + + std::advance(i_compare, 2); + std::advance(i_data, 2); + + std::advance(i_compare_end, 4); + std::advance(i_data_end, 4); + + compare_data.erase(i_compare, i_compare_end); + data.erase(i_data, i_data_end); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_erase_range) + { + Compare_Data compare_data(initial_data.begin(), initial_data.end()); + Data data(initial_data.begin(), initial_data.end()); + + Compare_Data::const_iterator i_compare = compare_data.begin(); + Data::const_iterator i_data = data.begin(); + + Compare_Data::const_iterator i_compare_end = compare_data.begin(); + Data::const_iterator i_data_end = data.begin(); + + std::advance(i_compare, 2); + std::advance(i_data, 2); + + std::advance(i_compare_end, 4); + std::advance(i_data_end, 4); + + compare_data.erase(i_compare, i_compare_end); + data.erase(i_data, i_data_end); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_clear) + { + Compare_Data compare_data(initial_data.begin(), initial_data.end()); + + Data data(compare_data.begin(), compare_data.end()); + data.clear(); + + CHECK_EQUAL(data.size(), size_t(0)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_count) + { + const Data data(initial_data.begin(), initial_data.end()); + + CHECK_EQUAL(data.count("3"), size_t(1)); + + CHECK_EQUAL(data.count("A"), size_t(0)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_iterator) + { + Compare_Data compare_data(initial_data.begin(), initial_data.end()); + + Data data(compare_data.begin(), compare_data.end()); + + bool isEqual = Check_Equal(data.begin(), + data.end(), + compare_data.begin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_iterator) + { + Compare_Data compare_data(initial_data.begin(), initial_data.end()); + + Data data(compare_data.begin(), compare_data.end()); + + bool isEqual = Check_Equal(data.cbegin(), + data.cend(), + compare_data.cbegin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_reverse_iterator) + { + Compare_Data compare_data(initial_data.begin(), initial_data.end()); + + Data data(compare_data.begin(), compare_data.end()); + + bool isEqual = Check_Equal(data.rbegin(), + data.rend(), + compare_data.rbegin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_const_reverse_iterator) + { + Compare_Data compare_data(initial_data.begin(), initial_data.end()); + + Data data(compare_data.begin(), compare_data.end()); + + bool isEqual = Check_Equal(data.crbegin(), + data.crend(), + compare_data.crbegin()); + + CHECK(isEqual); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_find) + { + Data data(initial_data.begin(), initial_data.end()); + + Data::iterator it = data.find("3"); + CHECK_EQUAL(3, it->second); + + it = data.find("A"); + CHECK_EQUAL(data.end(), it); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_find_const) + { + const Data data(initial_data.begin(), initial_data.end()); + + Data::const_iterator it = data.find("3"); + CHECK_EQUAL(3, it->second); + + it = data.find("A"); + CHECK_EQUAL(data.end(), it); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_equal) + { + const Data initial1(initial_data.begin(), initial_data.end()); + const Data initial2(initial_data.begin(), initial_data.end()); + + CHECK(initial1 == initial2); + + const Data different(different_data.begin(), different_data.end()); + + CHECK(!(initial1 == different)); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_not_equal) + { + const Data initial1(initial_data.begin(), initial_data.end()); + const Data initial2(initial_data.begin(), initial_data.end()); + + CHECK(!(initial1 != initial2)); + + const Data different(different_data.begin(), different_data.end()); + + CHECK(initial1 != different); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_lower_bound) + { + Compare_Data compare_data(initial_data.begin(), initial_data.end()); + Data data(initial_data.begin(), initial_data.end()); + + Compare_Data::iterator i_compare = compare_data.lower_bound("3"); + Data::iterator i_data = data.lower_bound("3"); + CHECK_EQUAL(i_compare->second, i_data->second); + + i_data = data.lower_bound("A"); + CHECK_EQUAL(data.end(), i_data); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_lower_bound_const) + { + Compare_Data compare_data(initial_data.begin(), initial_data.end()); + const Data data(initial_data.begin(), initial_data.end()); + + Compare_Data::const_iterator i_compare = compare_data.lower_bound("3"); + Data::const_iterator i_data = data.lower_bound("3"); + CHECK_EQUAL(i_compare->second, i_data->second); + + i_data = data.lower_bound("A"); + CHECK_EQUAL(data.end(), i_data); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_upper_bound) + { + Compare_Data compare_data(initial_data.begin(), initial_data.end()); + Data data(initial_data.begin(), initial_data.end()); + + Compare_Data::iterator i_compare = compare_data.upper_bound("7"); + Data::iterator i_data = data.upper_bound("7"); + CHECK_EQUAL(i_compare->second, i_data->second); + + i_data = data.upper_bound("A"); + CHECK_EQUAL(data.end(), i_data); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_upper_bound_const) + { + Compare_Data compare_data(initial_data.begin(), initial_data.end()); + const Data data(initial_data.begin(), initial_data.end()); + + Compare_Data::const_iterator i_compare = compare_data.upper_bound("7"); + Data::const_iterator i_data = data.upper_bound("7"); + CHECK_EQUAL(i_compare->second, i_data->second); + + i_data = data.upper_bound("A"); + CHECK_EQUAL(data.end(), i_data); + } + + }; +} diff --git a/test/vs2013/etl.vcxproj b/test/vs2013/etl.vcxproj index 71efd252..7ea4bf28 100644 --- a/test/vs2013/etl.vcxproj +++ b/test/vs2013/etl.vcxproj @@ -146,6 +146,7 @@ + @@ -159,6 +160,8 @@ + + @@ -235,6 +238,7 @@ + diff --git a/test/vs2013/etl.vcxproj.filters b/test/vs2013/etl.vcxproj.filters index a3bde832..82c79d15 100644 --- a/test/vs2013/etl.vcxproj.filters +++ b/test/vs2013/etl.vcxproj.filters @@ -204,6 +204,15 @@ ETL\Containers + + ETL\Containers + + + ETL\Containers + + + ETL\Containers + ETL\Maths @@ -428,6 +437,9 @@ Source Files + + Source Files + Source Files