Files
moslab-code/src/l4/pkg/l4re-core/cxx/lib/tl/include/avl_set
2025-09-12 15:55:45 +02:00

482 lines
14 KiB
C++

// vi:set ft=cpp: -*- Mode: C++ -*-
/**
* \file
* \brief AVL set
*/
/*
* (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>,
* Carsten Weinhold <weinhold@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/cxx/std_alloc>
#include <l4/cxx/std_ops>
#include <l4/cxx/type_traits>
#include <l4/cxx/avl_tree>
struct Avl_set_tester;
namespace cxx {
namespace Bits {
/**
* \internal
* \brief Generic iterator for the AVL-tree based set.
* \param Cmp the type of the comparison functor.
* \param Node the type of a node.
* \param Key the type of the item stored in a node.
* \param Node_op the type used to determine the direction of the iterator.
*/
template< typename Node, typename Key, typename Node_op >
class Avl_set_iter : public __Bst_iter_b<Node, Node_op>
{
private:
/// Super-class type
typedef __Bst_iter_b<Node, Node_op> Base;
/// our non-const key type
typedef typename Type_traits<Key>::Non_const_type Non_const_key;
/// our non-const iterator type
typedef Avl_set_iter<Node, Non_const_key, Node_op> Non_const_iter;
using Base::_n;
using Base::_r;
using Base::inc;
public:
/// Create an invalid iterator (end marker)
Avl_set_iter() = default;
/**
* Create an iterator for the given tree.
* \param t the root node of the tree to iterate.
*/
Avl_set_iter(Node const *t) : Base(t) {}
/**
* Create an iterator from a BST iterator.
* \prarm o The BST iterator that shall be copied.
*/
Avl_set_iter(Base const &o) : Base(o) {}
/// Allow copy of non-const iterator to const iterator versions.
Avl_set_iter(Non_const_iter const &o)
: Base(o) {}
/// Allow assignment of non-const iterator to const iterator versions.
Avl_set_iter &operator = (Non_const_iter const &o)
{ Base::operator = (o); return *this; }
/**
* \brief Dereference the iterator and get the item out of the tree.
* \return A reference to the data stored in the AVL tree.
*/
Key &operator * () const { return const_cast<Node*>(_n)->item; }
/**
* \brief Member access to the item the iterator points to.
* \return A pointer to the item in the node.
*/
Key *operator -> () const { return &const_cast<Node*>(_n)->item; }
/**
* \brief Set the iterator to the next element (pre increment).
*/
Avl_set_iter &operator ++ () { inc(); return *this; }
/**
* \brief Set the iterator to the next element (post increment).
*/
Avl_set_iter operator ++ (int)
{ Avl_set_iter tmp = *this; inc(); return tmp; }
};
/// Internal, key-getter for Avl_set nodes.
template<typename KEY_TYPE>
struct Avl_set_get_key
{
typedef KEY_TYPE Key_type;
template<typename NODE>
static Key_type const &key_of(NODE const *n)
{ return n->item; }
};
/**
* Internal: AVL set with internally managed nodes.
*
* Use Avl_set, Avl_map, or Avl_tree in applications.
*
* \tparam ITEM_TYPE The type of the items to be stored in the set.
* \tparam COMPARE The relation to define the partial order, default is
* to use operator '<'.
* \tparam ALLOC The allocator to use for the nodes of the AVL set.
* \tparam GET_KEY Sort-key getter (must provide the `Key_type` and
* sort-key for an item (of `ITEM_TYPE`).
*/
template< typename ITEM_TYPE, class COMPARE,
template<typename A> class ALLOC,
typename GET_KEY>
class Base_avl_set
{
friend struct ::Avl_set_tester;
public:
/**
* Return status constants.
*
* These constants are compatible with the L4 error codes, see
* #l4_error_code_t.
*/
enum
{
E_noent = 2, ///< Item does not exist.
E_exist = 17, ///< Item exists already.
E_nomem = 12, ///< Memory allocation failed.
E_inval = 22 ///< Internal error.
};
/// Type for the items store in the set
typedef ITEM_TYPE Item_type;
/// Key-getter type to derive the sort key of an internal node.
typedef GET_KEY Get_key;
/// Type of the sort key used for the items
typedef typename GET_KEY::Key_type Key_type;
/// Type used for const items within the set
typedef typename Type_traits<Item_type>::Const_type Const_item_type;
/// Type for the comparison functor.
typedef COMPARE Item_compare;
private:
/// Internal representation of a tree node.
class _Node : public Avl_tree_node
{
public:
/// The actual item stored in the node.
Item_type item;
_Node() = default;
_Node(Item_type const &item) : Avl_tree_node(), item(item) {}
template<typename ...ARGS>
_Node(ARGS &&...args) : Avl_tree_node(), item(cxx::forward<ARGS>(args)...)
{}
};
public:
/**
* \brief A smart pointer to a tree item.
*/
class Node
{
private:
struct No_type;
friend class Base_avl_set<ITEM_TYPE, COMPARE, ALLOC, GET_KEY>;
_Node const *_n;
explicit Node(_Node const *n) : _n(n) {}
public:
/// Default construction for NIL pointer.
Node() : _n(0) {}
/**
* Dereference the pointer.
*
* \pre Node is valid.
*/
Item_type const &operator * () { return _n->item; }
/**
* Dereferenced member access.
*
* \pre Node is valid.
*/
Item_type const *operator -> () { return &_n->item; }
/**
* \brief Validity check.
* \return false if the pointer is NIL, true if valid.
*/
bool valid() const { return _n; }
/// Cast to a real item pointer.
operator Item_type const * () { return _n ? &_n->item : 0; }
};
/// Type for the node allocator.
typedef ALLOC<_Node> Node_allocator;
private:
typedef Avl_tree<_Node, GET_KEY, COMPARE> Tree;
Tree _tree;
/// The allocator for new nodes
Node_allocator _alloc;
Base_avl_set &operator = (Base_avl_set const &) = delete;
typedef typename Tree::Fwd_iter_ops Fwd;
typedef typename Tree::Rev_iter_ops Rev;
public:
typedef typename Type_traits<Item_type>::Param_type Item_param_type;
/// Forward iterator for the set.
typedef Avl_set_iter<_Node, Item_type, Fwd> Iterator;
typedef Iterator iterator;
/// Constant forward iterator for the set.
typedef Avl_set_iter<_Node, Const_item_type, Fwd> Const_iterator;
typedef Const_iterator const_iterator;
/// Backward iterator for the set.
typedef Avl_set_iter<_Node, Item_type, Rev> Rev_iterator;
typedef Rev_iterator reverse_iterator;
/// Constant backward iterator for the set.
typedef Avl_set_iter<_Node, Const_item_type, Rev> Const_rev_iterator;
typedef Const_rev_iterator const_reverse_iterator;
/**
* \brief Create a AVL-tree based set.
* \param alloc Node allocator.
*
* Create an empty set (AVL-tree based).
*/
explicit Base_avl_set(Node_allocator const &alloc = Node_allocator())
: _tree(), _alloc(alloc)
{}
~Base_avl_set()
{
_tree.remove_all([this](_Node *n)
{
n->~_Node();
_alloc.free(n);
});
}
/**
* Create a copy of an AVL-tree based set.
*
* \param o The set to copy.
*
* Creates a deep copy of the set with all its items.
*/
inline Base_avl_set(Base_avl_set const &o);
/**
* Insert an item into the set.
*
* \param item The item to insert.
*
* \return A pair of iterator (`first`) and return value (`second`).
* `second` will be 0 if the element was inserted into the set
* and `-#E_exist` if the element was already in the set and
* the set was therefore not updated.
* In both cases, `first` contains an iterator that points to
* the element.
* `second` may also be `-#E_nomem` when memory for the node
* could not be allocated. `first` is then invalid.
*
* Insert a new item into the set, each item can only be once in
* the set.
*/
cxx::Pair<Iterator, int> insert(Item_type const &item);
template<typename... Args>
cxx::Pair<Iterator, int> emplace(Args&&... args);
/**
* Remove an item from the set.
*
* \param item The item to remove.
*
* \retval 0 Success
* \retval -E_noent Item does not exist
*/
int remove(Key_type const &item)
{
_Node *n = _tree.remove(item);
if (n)
{
n->~_Node();
_alloc.free(n);
return 0;
}
return -E_noent;
}
/**
* Erase the item with the given key.
* \param item The key of the item to remove.
*/
int erase(Key_type const &item)
{ return remove(item); }
/**
* Lookup a node equal to `item`.
*
* \param item The value to search for.
*
* \return A smart pointer to the element found.
* If no element was found the smart pointer will be invalid.
*/
Node find_node(Key_type const &item) const
{ return Node(_tree.find_node(item)); }
/**
* Find the first node greater or equal to `key`.
*
* \param key Minimum key to look for.
*
* \return Smart pointer to the first node greater or equal to `key`.
* Will be invalid if no such element was found.
*/
Node lower_bound_node(Key_type const &key) const
{ return Node(_tree.lower_bound_node(key)); }
Node lower_bound_node(Key_type &&key) const
{ return Node(_tree.lower_bound_node(key)); }
/**
* \brief Get the constant forward iterator for the first element in the set.
* \return Constant forward iterator for the first element in the set.
*/
Const_iterator begin() const { return _tree.begin(); }
/**
* \brief Get the end marker for the constant forward iterator.
* \return The end marker for the constant forward iterator.
*/
Const_iterator end() const { return _tree.end(); }
/**
* \brief Get the mutable forward iterator for the first element of the set.
* \return The mutable forward iterator for the first element of the set.
*/
Iterator begin() { return _tree.begin(); }
/**
* \brief Get the end marker for the mutable forward iterator.
* \return The end marker for mutable forward iterator.
*/
Iterator end() { return _tree.end(); }
/**
* \brief Get the constant backward iterator for the last element in the set.
* \return The constant backward iterator for the last element in the set.
*/
Const_rev_iterator rbegin() const { return _tree.rbegin(); }
/**
* \brief Get the end marker for the constant backward iterator.
* \return The end marker for the constant backward iterator.
*/
Const_rev_iterator rend() const { return _tree.rend(); }
/**
* \brief Get the mutable backward iterator for the last element of the set.
* \return The mutable backward iterator for the last element of the set.
*/
Rev_iterator rbegin() { return _tree.rbegin(); }
/**
* \brief Get the end marker for the mutable backward iterator.
* \return The end marker for mutable backward iterator.
*/
Rev_iterator rend() { return _tree.rend(); }
Const_iterator find(Key_type const &item) const
{ return _tree.find(item); }
#ifdef __DEBUG_L4_AVL
bool rec_dump(bool print)
{
return _tree.rec_dump(print);
}
#endif
};
//----------------------------------------------------------------------------
/* Implementation of AVL Tree */
/* Create a copy */
template< typename Item, class Compare, template<typename A> class Alloc, typename KEY_TYPE>
Base_avl_set<Item,Compare,Alloc,KEY_TYPE>::Base_avl_set(Base_avl_set const &o)
: _tree(), _alloc(o._alloc)
{
for (Const_iterator i = o.begin(); i != o.end(); ++i)
insert(*i);
}
/* Insert new _Node. */
template< typename Item, class Compare, template< typename A > class Alloc, typename KEY_TYPE>
Pair<typename Base_avl_set<Item,Compare,Alloc,KEY_TYPE>::Iterator, int>
Base_avl_set<Item,Compare,Alloc,KEY_TYPE>::insert(Item const &item)
{
_Node *n = _alloc.alloc();
if (!n)
return cxx::pair(end(), -E_nomem);
new (n, Nothrow()) _Node(item);
Pair<_Node *, bool> err = _tree.insert(n);
if (!err.second)
{
n->~_Node();
_alloc.free(n);
}
return cxx::pair(Iterator(typename Tree::Iterator(err.first, err.first)), err.second ? 0 : -E_exist);
}
/* In-place insert new _Node. */
template< typename Item, class Compare, template< typename A > class Alloc, typename KEY_TYPE>
template<typename... Args>
Pair<typename Base_avl_set<Item,Compare,Alloc,KEY_TYPE>::Iterator, int>
Base_avl_set<Item,Compare,Alloc,KEY_TYPE>::emplace(Args&&... args)
{
_Node *n = _alloc.alloc();
if (!n)
return cxx::pair(end(), -E_nomem);
new (n, Nothrow()) _Node(cxx::forward<Args>(args)...);
Pair<_Node *, bool> err = _tree.insert(n);
if (!err.second)
{
n->~_Node();
_alloc.free(n);
}
return cxx::pair(Iterator(typename Tree::Iterator(err.first, err.first)), err.second ? 0 : -E_exist);
}
} // namespace Bits
/**
* \brief AVL set for simple comparable items.
*
* The AVL set can store any kind of items where a partial order is defined.
* The default relation is defined by the '<' operator.
*
* \tparam ITEM_TYPE The type of the items to be stored in the set.
* \tparam COMPARE The relation to define the partial order, default is
* to use operator '<'.
* \tparam ALLOC The allocator to use for the nodes of the AVL set.
*/
template< typename ITEM_TYPE, class COMPARE = Lt_functor<ITEM_TYPE>,
template<typename A> class ALLOC = New_allocator>
class Avl_set :
public Bits::Base_avl_set<ITEM_TYPE, COMPARE, ALLOC,
Bits::Avl_set_get_key<ITEM_TYPE> >
{
private:
typedef Bits::Base_avl_set<ITEM_TYPE, COMPARE, ALLOC,
Bits::Avl_set_get_key<ITEM_TYPE> > Base;
public:
typedef typename Base::Node_allocator Node_allocator;
Avl_set() = default;
Avl_set(Node_allocator const &alloc)
: Base(alloc)
{}
};
} // namespace cxx