mirror of
https://github.com/ETLCPP/etl.git
synced 2026-06-26 20:38:45 +08:00
1780 lines
59 KiB
C++
1780 lines
59 KiB
C++
///\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 <iterator>
|
|
#include <algorithm>
|
|
#include <functional>
|
|
#include <stddef.h>
|
|
|
|
#include "nullptr.h"
|
|
#include "map_base.h"
|
|
#include "type_traits.h"
|
|
#include "parameter_type.h"
|
|
#include "pool.h"
|
|
|
|
#include <iostream> // FIXME: Remove with std::cout
|
|
|
|
#if WIN32
|
|
#undef min
|
|
#endif
|
|
|
|
namespace etl
|
|
{
|
|
//***************************************************************************
|
|
/// A templated base for all etl::map types.
|
|
///\ingroup map
|
|
//***************************************************************************
|
|
template <typename TKey, typename TMapped, typename TKeyCompare>
|
|
class imap : public map_base
|
|
{
|
|
public:
|
|
|
|
typedef std::pair<TKey, TMapped> 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<TKey>::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<Data_Node>* 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<Data_Node*>(p_node);
|
|
}
|
|
|
|
//*************************************************************************
|
|
/// Downcast a Node& to a Data_Node&
|
|
//*************************************************************************
|
|
static Data_Node& data_cast(Node& node)
|
|
{
|
|
return static_cast<Data_Node&>(node);
|
|
}
|
|
|
|
//*************************************************************************
|
|
/// Downcast a const Node* to a const Data_Node*
|
|
//*************************************************************************
|
|
static const Data_Node* data_cast(const Node* p_node)
|
|
{
|
|
return static_cast<const Data_Node*>(p_node);
|
|
}
|
|
|
|
//*************************************************************************
|
|
/// Downcast a const Node& to a const Data_Node&
|
|
//*************************************************************************
|
|
static const Data_Node& data_cast(const Node& node)
|
|
{
|
|
return static_cast<const Data_Node&>(node);
|
|
}
|
|
|
|
public:
|
|
//*************************************************************************
|
|
/// iterator.
|
|
//*************************************************************************
|
|
class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type>
|
|
{
|
|
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<std::bidirectional_iterator_tag, const value_type>
|
|
{
|
|
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<iterator>::difference_type difference_type;
|
|
|
|
typedef std::reverse_iterator<iterator> reverse_iterator;
|
|
typedef std::reverse_iterator<const_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 <typename TIterator>
|
|
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<iterator, iterator> equal_range(const key_type& key)
|
|
{
|
|
return std::make_pair<iterator, iterator>(
|
|
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<const_iterator, const_iterator> equal_range(const key_type& key) const
|
|
{
|
|
return std::make_pair<const_iterator, const_iterator>(
|
|
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<iterator, bool> 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 <class TIterator>
|
|
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<Data_Node>& 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 <b>true</b> if the arrays are equal, otherwise <b>false</b>
|
|
///\ingroup lookup
|
|
//***************************************************************************
|
|
template <typename TKey, typename TMapped, typename TKeyCompare>
|
|
bool operator ==(const etl::imap<TKey, TMapped, TKeyCompare>& lhs, const etl::imap<TKey, TMapped, TKeyCompare>& 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 <b>true</b> if the arrays are not equal, otherwise <b>false</b>
|
|
///\ingroup lookup
|
|
//***************************************************************************
|
|
template <typename TKey, typename TMapped, typename TKeyCompare>
|
|
bool operator !=(const etl::imap<TKey, TMapped, TKeyCompare>& lhs, const etl::imap<TKey, TMapped, TKeyCompare>& rhs)
|
|
{
|
|
return !(lhs == rhs);
|
|
}
|
|
|
|
//*************************************************************************
|
|
/// Less than operator.
|
|
///\param lhs Reference to the first list.
|
|
///\param rhs Reference to the second list.
|
|
///\return <b>true</b> if the first list is lexicographically less than the
|
|
/// second, otherwise <b>false</b>.
|
|
//*************************************************************************
|
|
template <typename TKey, typename TMapped, typename TKeyCompare>
|
|
bool operator <(const etl::imap<TKey, TMapped, TKeyCompare>& lhs, const etl::imap<TKey, TMapped, TKeyCompare>& 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 <b>true</b> if the first list is lexicographically greater than the
|
|
/// second, otherwise <b>false</b>.
|
|
//*************************************************************************
|
|
template <typename TKey, typename TMapped, typename TKeyCompare>
|
|
bool operator >(const etl::imap<TKey, TMapped, TKeyCompare>& lhs, const etl::imap<TKey, TMapped, TKeyCompare>& rhs)
|
|
{
|
|
return std::lexicographical_compare(lhs.begin(),
|
|
lhs.end(),
|
|
rhs.begin(),
|
|
rhs.end(),
|
|
std::greater<TMapped>());
|
|
}
|
|
|
|
//*************************************************************************
|
|
/// Less than or equal operator.
|
|
///\param lhs Reference to the first list.
|
|
///\param rhs Reference to the second list.
|
|
///\return <b>true</b> if the first list is lexicographically less than or equal
|
|
/// to the second, otherwise <b>false</b>.
|
|
//*************************************************************************
|
|
template <typename TKey, typename TMapped, typename TKeyCompare>
|
|
bool operator <=(const etl::imap<TKey, TMapped, TKeyCompare>& lhs, const etl::imap<TKey, TMapped, TKeyCompare>& 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 <b>true</b> if the first list is lexicographically greater than or
|
|
/// equal to the second, otherwise <b>false</b>.
|
|
//*************************************************************************
|
|
template <typename TKey, typename TMapped, typename TKeyCompare>
|
|
bool operator >=(const etl::imap<TKey, TMapped, TKeyCompare>& lhs, const etl::imap<TKey, TMapped, TKeyCompare>& rhs)
|
|
{
|
|
return !operator <(lhs, rhs);
|
|
}
|
|
|
|
#if WIN32
|
|
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
|
#endif
|
|
|
|
#undef __ETL_IN_IMAP_H__
|
|
|
|
#endif
|