/* * 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 */ #pragma once #include namespace cruft::list::node { /// A node that stores the value and successor in the same object together template 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 compound* next (compound *obj) { return obj->next; } /// Return a pointer to the successor node, or NULL if there isn't one. template compound const* next (compound const *obj) { return obj->next; } /// Set the successor node and return a pointer to it. template compound* next (compound *obj, compound *val) { return obj->next = val; } /// Clear the successor node and return a null pointer. template compound* next (compound *obj, std::nullptr_t) { return obj->next = nullptr; } /// Return a reference to the node's data template ValueT& data (compound *obj) { return obj->data; } /// Return a reference to the node's data template ValueT const& data (compound 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 struct disjoint { using value_type = ValueT; std::aligned_storage_t bytes; }; /// Return a pointer to the successor node, or NULL if there isn't one. template disjoint* next (disjoint *obj) { disjoint *res; memcpy (&res, &obj->bytes, sizeof (res)); return res; } /// Return a pointer to the successor node, or NULL if there isn't one. template disjoint const* next (disjoint const *obj) { disjoint *res; memcpy (&res, &obj->bytes, sizeof (res)); return res; } /// Set the successor node and return a pointer to it. template disjoint* next (disjoint *obj, disjoint *val) { static_assert ( sizeof (disjoint) >= 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 compound* next (disjoint *obj, std::nullptr_t) { memset (&obj->bytes, 0, sizeof (ValueT*)); return nullptr; } /// Return a reference to the node's data template ValueT const& data (disjoint 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 (&obj->bytes); } /// Return a reference to the node's data template ValueT& data (disjoint *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 (&obj->bytes); } /// A comparator object that returns the result of a supplied child /// comparator on the data members of two node pointers. template class value_comparator { public: value_comparator (ComparatorT &&_comparator) : m_comparator (std::move (_comparator)) { ; } value_comparator (ComparatorT const &_comparator) : m_comparator (_comparator) { ; } template 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 constexpr bool operator() [[gnu::nonnull]] ( NodeT const *a, NodeT const *b ) { return a < b; } }; };