225 lines
5.6 KiB
C++
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;
|
|
}
|
|
};
|
|
};
|