272 lines
6.3 KiB
C++
272 lines
6.3 KiB
C++
// vi:set ft=cpp: -*- Mode: C++ -*-
|
|
/*
|
|
* (c) 2011 Alexander Warg <warg@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 "bits/list_basics.h"
|
|
#include "type_traits"
|
|
|
|
namespace cxx {
|
|
|
|
/**
|
|
* Basic element type for a double-linked H_list.
|
|
*
|
|
* \tparam ELEM_TYPE Base class of the list element.
|
|
*/
|
|
template<typename ELEM_TYPE>
|
|
class H_list_item_t
|
|
{
|
|
public:
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* Creates an element that is not in any list.
|
|
*/
|
|
H_list_item_t() : _n(0), _pn(0) {}
|
|
/**
|
|
* Destructor.
|
|
*
|
|
* Automatically removes the element from any list it still might be
|
|
* enchained in.
|
|
*/
|
|
~H_list_item_t() noexcept { l_remove(); }
|
|
|
|
private:
|
|
H_list_item_t(H_list_item_t const &) = delete;
|
|
|
|
template<typename T, typename P> friend class H_list;
|
|
template<typename T, typename X> friend struct Bits::Basic_list_policy;
|
|
|
|
void l_remove() noexcept
|
|
{
|
|
if (!_pn)
|
|
return;
|
|
|
|
*_pn = _n;
|
|
if (_n)
|
|
_n->_pn = _pn;
|
|
|
|
_pn = 0;
|
|
}
|
|
|
|
H_list_item_t *_n, **_pn;
|
|
};
|
|
|
|
/** Untyped list item. */
|
|
typedef H_list_item_t<void> H_list_item;
|
|
|
|
/**
|
|
* General double-linked list of unspecified cxx::H_list_item elements.
|
|
*
|
|
* Most of the time, you want to use H_list_t.
|
|
*/
|
|
template< typename T, typename POLICY = Bits::Basic_list_policy< T, H_list_item> >
|
|
class H_list : public Bits::Basic_list<POLICY>
|
|
{
|
|
private:
|
|
typedef typename POLICY::Item_type Item;
|
|
typedef Bits::Basic_list<POLICY> Base;
|
|
H_list(H_list const &);
|
|
void operator = (H_list const &);
|
|
|
|
public:
|
|
typedef typename Base::Iterator Iterator;
|
|
|
|
// BSS allocation
|
|
explicit H_list(bool x) : Base(x) {}
|
|
H_list() : Base() {}
|
|
|
|
/**
|
|
* Return an iterator for an arbitrary list element
|
|
*
|
|
* \param c List element to start the iteration.
|
|
*
|
|
* \return A mutable forward iterator.
|
|
*
|
|
* \pre The element must be in a list.
|
|
*/
|
|
static Iterator iter(T *c) { return Base::__iter(c->Item::_pn); }
|
|
|
|
/// Check if the given element is currently part of a list.
|
|
static bool in_list(T const *e) { return e->Item::_pn; }
|
|
|
|
/// Add element to the front of the list.
|
|
void add(T *e)
|
|
{
|
|
if (this->_f)
|
|
this->_f->_pn = &e->Item::_n;
|
|
e->Item::_n = this->_f;
|
|
e->Item::_pn = &this->_f;
|
|
this->_f = static_cast<Item*>(e);
|
|
}
|
|
|
|
/// Add element to the front of the list.
|
|
void push_front(T *e) { add(e); }
|
|
|
|
/**
|
|
* Remove and return the head element of the list.
|
|
*
|
|
* \pre The list must not be empty or the behaviour will be undefined.
|
|
*/
|
|
T *pop_front()
|
|
{
|
|
T *r = this->front();
|
|
remove(r);
|
|
return r;
|
|
}
|
|
|
|
/**
|
|
* Insert an element at the iterator position.
|
|
*
|
|
* \param e New Element to be inserted
|
|
* \param pred Iterator pointing to the element after which the
|
|
* element will be inserted. If end() is given, the
|
|
* element will be inserted at the beginning of the queue.
|
|
*
|
|
* \return Iterator pointing to the newly inserted element.
|
|
*/
|
|
Iterator insert(T *e, Iterator const &pred)
|
|
{
|
|
Item **x = &this->_f;
|
|
if (pred != Base::end())
|
|
x = &(*pred)->_n;
|
|
|
|
e->Item::_n = *x;
|
|
|
|
if (*x)
|
|
(*x)->_pn = &(e->Item::_n);
|
|
|
|
e->Item::_pn = x;
|
|
*x = static_cast<Item*>(e);
|
|
return iter(e);
|
|
}
|
|
|
|
/**
|
|
* Insert an element after the iterator position.
|
|
*
|
|
* \param e New element to be inserted.
|
|
* \param pred Iterator pointing to the element after which the
|
|
* element will be inserted. Must not be end().
|
|
*
|
|
* \return Iterator pointing to the newly inserted element.
|
|
*
|
|
* \pre The list must not be empty.
|
|
*/
|
|
static Iterator insert_after(T *e, Iterator const &pred)
|
|
{
|
|
Item **x = &(*pred)->_n;
|
|
e->Item::_n = *x;
|
|
|
|
if (*x)
|
|
(*x)->_pn = &(e->Item::_n);
|
|
|
|
e->Item::_pn = x;
|
|
*x = static_cast<Item*>(e);
|
|
return iter(e);
|
|
}
|
|
|
|
/**
|
|
* Insert an element before the iterator position.
|
|
*
|
|
* \param e New element to be inserted.
|
|
* \param succ Iterator pointing to the element before which the
|
|
* element will be inserted. Must not be end().
|
|
*/
|
|
static void insert_before(T *e, Iterator const &succ)
|
|
{
|
|
Item **x = Base::__get_internal(succ);
|
|
|
|
e->Item::_n = *x;
|
|
e->Item::_pn = x;
|
|
|
|
if (*x)
|
|
(*x)->_pn = &e->Item::_n;
|
|
|
|
*x = static_cast<Item*>(e);
|
|
}
|
|
|
|
/**
|
|
* Replace an element in a list with a new element.
|
|
*
|
|
* \param p Element in list to be replaced.
|
|
* \param e Replacement element, must not yet be in a list.
|
|
*
|
|
* \pre `p` and `e` must not be NULL.
|
|
*
|
|
* After the operation the p element is no longer in the
|
|
* list and may be reused.
|
|
*/
|
|
static void replace(T *p, T *e)
|
|
{
|
|
e->Item::_n = p->Item::_n;
|
|
e->Item::_pn = p->Item::_pn;
|
|
*(p->Item::_pn) = static_cast<Item*>(e);
|
|
if (e->Item::_n)
|
|
e->Item::_n->_pn = &(e->Item::_n);
|
|
|
|
p->Item::_pn = 0;
|
|
}
|
|
|
|
/**
|
|
* Remove the given element from its list.
|
|
*
|
|
* \param e Element to be removed. Must be in a list.
|
|
*/
|
|
static void remove(T *e)
|
|
{ e->Item::l_remove(); }
|
|
|
|
/**
|
|
* Remove the element at the given iterator position.
|
|
*
|
|
* \param e Iterator pointing to the element to be removed. Must not
|
|
* point to end().
|
|
*
|
|
* \return New iterator pointing to the element after the removed one.
|
|
*
|
|
* \note The hlist implementation guarantees that the original iterator
|
|
* is still valid after the element has been removed. In fact, the
|
|
* iterator returned is the same as the one supplied in the `e`
|
|
* parameter.
|
|
*/
|
|
static Iterator erase(Iterator const &e)
|
|
{ e->Item::l_remove(); return e; }
|
|
};
|
|
|
|
/**
|
|
* Double-linked list of typed H_list_item_t elements.
|
|
*
|
|
* \note H_lists are not self-cleaning. Elements that are still chained
|
|
* during destruction are not removed and will therefore be in an
|
|
* undefined state after the destruction.
|
|
*/
|
|
template< typename T >
|
|
struct H_list_t : H_list<T, Bits::Basic_list_policy< T, H_list_item_t<T> > >
|
|
{
|
|
H_list_t() = default;
|
|
H_list_t(bool b)
|
|
: H_list<T, Bits::Basic_list_policy< T, H_list_item_t<T> > >(b)
|
|
{};
|
|
};
|
|
|
|
template< typename T >
|
|
class H_list_bss : public H_list<T>
|
|
{
|
|
public:
|
|
H_list_bss() : H_list<T>(true) {}
|
|
};
|
|
|
|
template< typename T >
|
|
class H_list_t_bss : public H_list_t<T>
|
|
{
|
|
public:
|
|
H_list_t_bss() : H_list_t<T>(true) {}
|
|
};
|
|
|
|
|
|
}
|