libcruft-util/list/node.hpp

225 lines
5.6 KiB
C++

/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright 2019 Danny Robson <danny@nerdcruft.net>
*/
#pragma once
#include <cruft/util/cast.hpp>
#include <utility>
namespace cruft::list::node {
/// A node that stores the value and successor in the same object together
template <typename ValueT>
struct compound {
using value_type = ValueT;
compound *next;
ValueT data;
};
/// Return a pointer to the successor node, or NULL if there isn't one.
template <typename ValueT>
compound<ValueT>*
next (compound<ValueT> *obj)
{
return obj->next;
}
/// Return a pointer to the successor node, or NULL if there isn't one.
template <typename ValueT>
compound<ValueT> const*
next (compound<ValueT> const *obj)
{
return obj->next;
}
/// Set the successor node and return a pointer to it.
template <typename ValueT>
compound<ValueT>*
next (compound<ValueT> *obj, compound<ValueT> *val)
{
return obj->next = val;
}
/// Clear the successor node and return a null pointer.
template <typename ValueT>
compound<ValueT>*
next (compound<ValueT> *obj, std::nullptr_t)
{
return obj->next = nullptr;
}
/// Return a reference to the node's data
template <typename ValueT>
ValueT&
data (compound<ValueT> *obj)
{
return obj->data;
}
/// Return a reference to the node's data
template <typename ValueT>
ValueT const&
data (compound<ValueT> const *obj)
{
return obj->data;
}
/// A node that stores either a value, or a successor pointer. Not both.
///
/// This is quite useful for node based pool allocators and similar.
///
/// The copying semantics of this node assume that the live member is
/// always only the 'next' pointer; it is the user's responsibility to
/// manage the lifetime of the `data` member and prevent copying of nodes
/// with a live `data` member.
template <typename ValueT>
struct disjoint {
using value_type = ValueT;
alignas(ValueT) std::byte bytes[sizeof(ValueT)];
};
/// Return a pointer to the successor node, or NULL if there isn't one.
template <typename ValueT>
disjoint<ValueT>*
next (disjoint<ValueT> *obj)
{
disjoint<ValueT> *res;
memcpy (&res, &obj->bytes, sizeof (res));
return res;
}
/// Return a pointer to the successor node, or NULL if there isn't one.
template <typename ValueT>
disjoint<ValueT> const*
next (disjoint<ValueT> const *obj)
{
disjoint<ValueT> *res;
memcpy (&res, &obj->bytes, sizeof (res));
return res;
}
/// Set the successor node and return a pointer to it.
template <typename ValueT>
disjoint<ValueT>*
next (disjoint<ValueT> *obj, disjoint<ValueT> *val)
{
static_assert (
sizeof (disjoint<ValueT>) >= sizeof (obj),
"There must be enough room to store a pointer in the node"
);
memcpy (&obj->bytes, &val, sizeof (val));
return val;
}
/// Clear the successor node and return a null pointer.
template <typename ValueT>
compound<ValueT>*
next (disjoint<ValueT> *obj, std::nullptr_t)
{
memset (&obj->bytes, 0, sizeof (ValueT*));
return nullptr;
}
/// Return a reference to the node's data
template <typename ValueT>
ValueT const&
data (disjoint<ValueT> const *obj)
{
static_assert (
sizeof (ValueT) == sizeof (*obj),
"Sizes must be equal to allow pointer indexing"
);
static_assert (
alignof (ValueT) == alignof (decltype (*obj)),
"Alignment must be equal to allow pointer indexing"
);
return *reinterpret_cast<ValueT const*> (&obj->bytes);
}
/// Return a reference to the node's data
template <typename ValueT>
ValueT&
data (disjoint<ValueT> *obj)
{
static_assert (
sizeof (ValueT) == sizeof (*obj),
"Sizes must be equal to allow pointer indexing"
);
static_assert (
alignof (ValueT) == alignof (decltype (*obj)),
"Alignment must be equal to allow pointer indexing"
);
return *cast::alignment<ValueT*> (&obj->bytes);
}
/// A comparator object that returns the result of a supplied child
/// comparator on the data members of two node pointers.
template <typename ComparatorT>
class value_comparator {
public:
value_comparator (ComparatorT &&_comparator)
: m_comparator (std::move (_comparator))
{ ; }
value_comparator (ComparatorT const &_comparator)
: m_comparator (_comparator)
{ ; }
template <typename NodeT>
constexpr bool
operator() [[gnu::nonnull]] (
NodeT const *a,
NodeT const *b
) {
return m_comparator (data (a), data (b));
}
private:
ComparatorT m_comparator;
};
/// A comparator that returns true if the pointer to the first node is
/// less than the pointer to the second node.
///
/// This is useful for sorting pool allocator nodes for further
/// processing.
struct pointer_comparator {
template <typename NodeT>
constexpr bool
operator() [[gnu::nonnull]] (
NodeT const *a,
NodeT const *b
) {
return a < b;
}
};
};