list: prefer use of queries over direct use of members
This commit is contained in:
parent
2258279518
commit
b0bf064fdd
127
list/node.hpp
127
list/node.hpp
@ -22,6 +22,60 @@ namespace cruft::list::node {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// 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.
|
/// A node that stores either a value, or a successor pointer. Not both.
|
||||||
///
|
///
|
||||||
/// This is quite useful for node based pool allocators and similar.
|
/// This is quite useful for node based pool allocators and similar.
|
||||||
@ -31,21 +85,69 @@ namespace cruft::list::node {
|
|||||||
/// manage the lifetime of the `data` member and prevent copying of nodes
|
/// manage the lifetime of the `data` member and prevent copying of nodes
|
||||||
/// with a live `data` member.
|
/// with a live `data` member.
|
||||||
template <typename ValueT>
|
template <typename ValueT>
|
||||||
union disjoint {
|
struct disjoint {
|
||||||
using value_type = ValueT;
|
using value_type = ValueT;
|
||||||
|
|
||||||
disjoint () { }
|
std::aligned_storage_t<sizeof (ValueT), alignof (ValueT)> bytes;
|
||||||
|
|
||||||
disjoint (disjoint const &rhs) { next = rhs.next; }
|
|
||||||
disjoint& operator= (disjoint const &rhs) { next = rhs.next; }
|
|
||||||
|
|
||||||
~disjoint () { }
|
|
||||||
|
|
||||||
disjoint *next;
|
|
||||||
ValueT data;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// 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)
|
||||||
|
{
|
||||||
|
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&
|
||||||
|
data (disjoint<ValueT> *obj)
|
||||||
|
{
|
||||||
|
static_assert (
|
||||||
|
sizeof (ValueT) >= sizeof (*obj),
|
||||||
|
"ValueT < disjoint* prevents array indexing of nodes"
|
||||||
|
);
|
||||||
|
|
||||||
|
return *reinterpret_cast<ValueT*> (&obj->bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// A comparator object that returns the result of a supplied child
|
/// A comparator object that returns the result of a supplied child
|
||||||
/// comparator on the data members of two node pointers.
|
/// comparator on the data members of two node pointers.
|
||||||
template <typename ComparatorT>
|
template <typename ComparatorT>
|
||||||
@ -75,6 +177,11 @@ namespace cruft::list::node {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// 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 {
|
struct pointer_comparator {
|
||||||
template <typename NodeT>
|
template <typename NodeT>
|
||||||
constexpr bool
|
constexpr bool
|
||||||
|
@ -27,7 +27,7 @@ namespace cruft::list {
|
|||||||
|
|
||||||
while (head) {
|
while (head) {
|
||||||
++count;
|
++count;
|
||||||
head = head->next;
|
head = next (head);
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
@ -45,8 +45,8 @@ namespace cruft::list {
|
|||||||
{
|
{
|
||||||
CHECK (head);
|
CHECK (head);
|
||||||
|
|
||||||
while (head->next)
|
while (next (head))
|
||||||
head = head->next;
|
head = next (head);
|
||||||
return head;
|
return head;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,15 +71,15 @@ namespace cruft::list {
|
|||||||
// Pre-increment the fast node to trigger a preference for the earlier
|
// Pre-increment the fast node to trigger a preference for the earlier
|
||||||
// of the middle nodes.
|
// of the middle nodes.
|
||||||
auto slow = first;
|
auto slow = first;
|
||||||
auto fast = first->next;
|
auto fast = next (first);
|
||||||
|
|
||||||
while (fast != last->next) {
|
while (fast != next (last)) {
|
||||||
fast = fast->next;
|
fast = next (fast);
|
||||||
if (fast == last->next)
|
if (fast == next (last))
|
||||||
return slow;
|
return slow;
|
||||||
|
|
||||||
fast = fast->next;
|
fast = next (fast);
|
||||||
slow = slow->next;
|
slow = next (slow);
|
||||||
}
|
}
|
||||||
|
|
||||||
return slow;
|
return slow;
|
||||||
@ -123,7 +123,7 @@ namespace cruft::list {
|
|||||||
auto extract = [&first, &middle, &cmp] () {
|
auto extract = [&first, &middle, &cmp] () {
|
||||||
auto &target = cmp (first, middle) ? first : middle;
|
auto &target = cmp (first, middle) ? first : middle;
|
||||||
auto res = target;
|
auto res = target;
|
||||||
target = target->next;
|
target = next (target);
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -132,17 +132,17 @@ namespace cruft::list {
|
|||||||
|
|
||||||
// Keep adding the lowest node to the new list until we exhaust one
|
// Keep adding the lowest node to the new list until we exhaust one
|
||||||
// or both of our sources.
|
// or both of our sources.
|
||||||
while (first && middle && first != middle && middle != last->next) {
|
while (first && middle && first != middle && middle != next (last)) {
|
||||||
auto target = extract ();
|
auto target = extract ();
|
||||||
cursor->next = target;
|
next (cursor, target);
|
||||||
cursor = target;
|
cursor = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append the remaining data to the new list.
|
// Append the remaining data to the new list.
|
||||||
if (first == middle || !first)
|
if (first == middle || !first)
|
||||||
cursor->next = middle;
|
next (cursor, middle);
|
||||||
else if (middle == last->next || !middle)
|
else if (middle == next (last) || !middle)
|
||||||
cursor->next = first;
|
next (cursor, first);
|
||||||
|
|
||||||
#if defined(COMPILER_CLANG)
|
#if defined(COMPILER_CLANG)
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
@ -171,8 +171,8 @@ namespace cruft::list {
|
|||||||
return first;
|
return first;
|
||||||
|
|
||||||
auto a_end = ::cruft::list::midpoint (first, last);
|
auto a_end = ::cruft::list::midpoint (first, last);
|
||||||
auto middle = a_end->next;
|
auto middle = next (a_end);
|
||||||
a_end->next = nullptr;
|
next (a_end, nullptr);
|
||||||
|
|
||||||
auto a = ::cruft::list::sort (first, a_end, cmp);
|
auto a = ::cruft::list::sort (first, a_end, cmp);
|
||||||
auto b = ::cruft::list::sort (middle, last, cmp);
|
auto b = ::cruft::list::sort (middle, last, cmp);
|
||||||
@ -201,18 +201,18 @@ namespace cruft::list {
|
|||||||
is_sorted [[gnu::nonnull]] (
|
is_sorted [[gnu::nonnull]] (
|
||||||
NodeT const *head
|
NodeT const *head
|
||||||
) {
|
) {
|
||||||
if (!head->next)
|
if (!next (head))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
auto a = head;
|
auto a = head;
|
||||||
auto b = head->next;
|
auto b = next (head);
|
||||||
|
|
||||||
while (b) {
|
while (b) {
|
||||||
if (b->data < a->data)
|
if (b->data < a->data)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
a = a->next;
|
a = next (a);
|
||||||
b = b->next;
|
b = next (b);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
Loading…
Reference in New Issue
Block a user