Program Listing for File PodInternalNode.hpp¶
↰ Return to documentation for file (include/uitsl/datastructs/PodInternalNode.hpp)
#pragma once
#ifndef UITSL_DATASTRUCTS_PODINTERNALNODE_HPP_INCLUDE
#define UITSL_DATASTRUCTS_PODINTERNALNODE_HPP_INCLUDE
#include <cassert>
#include <cstddef>
#include <tuple>
#include <type_traits>
#include "../meta/tuple_has_type.hpp"
namespace uitsl {
template<typename First, typename... Rest>
class PodInternalNode : public std::tuple<First, Rest...> {
using parent_t = std::tuple<First, Rest...>;
using this_t = PodInternalNode<First, Rest...>;
template<typename Arg1, typename... Args> friend class PodInternalNode;
friend struct Workaround;
// clang workaround, see https://stackoverflow.com/a/52884963
struct Workaround {
/*
* Metaprogramming utility.
*/
template<size_t RemainingSteps, size_t ChildIndex=0>
static constexpr auto GetLeafType() noexcept {
assert( false && "GetLeafType should not be run" );
using Child = typename std::tuple_element<ChildIndex, parent_t>::type;
constexpr size_t ChildSteps = Child::GetSize();
if constexpr ( RemainingSteps < ChildSteps ) {
if constexpr ( Child::IsLeaf() ) return Child{};
else return Child::Workaround::template GetLeafType<RemainingSteps>();
} else return GetLeafType<RemainingSteps - ChildSteps, ChildIndex + 1>();
}
template<size_t RemainingSteps, size_t ChildIndex=0>
static constexpr size_t GetLeafIndex() noexcept {
using Child = typename std::tuple_element<ChildIndex, parent_t>::type;
constexpr size_t ChildSteps = Child::GetSize();
if constexpr ( RemainingSteps < ChildSteps ) {
if constexpr ( Child::IsLeaf() ) return RemainingSteps;
else return Child::Workaround::template GetLeafIndex<RemainingSteps>();
} else return GetLeafIndex<RemainingSteps - ChildSteps, ChildIndex + 1>();
}
};
public:
// inherit constructors
using parent_t::parent_t;
template< size_t Index >
using leaf_t = decltype( Workaround::template GetLeafType<Index>() );
/*
* Get index into leaf node.
*/
template<size_t Index>
static constexpr size_t GetLeafIndex() noexcept {
return Workaround::template GetLeafIndex< Index >();
}
static constexpr bool IsLeaf() noexcept { return false; }
/*
* Get number of descendant leaf nodes.
*/
static constexpr size_t GetSize() noexcept {
if constexpr ( sizeof...(Rest) > 0 ) {
return First::GetSize() + PodInternalNode<Rest...>::GetSize();
} else return First::GetSize();
}
/*
* Get leaf by index.
*/
template<size_t RemainingSteps, size_t ChildIndex=0>
constexpr auto& GetByIndex() noexcept {
using Child = typename std::tuple_element<ChildIndex, parent_t>::type;
constexpr size_t ChildSteps = Child::GetSize();
if constexpr ( RemainingSteps < ChildSteps ) {
return std::get<ChildIndex>(*this).template
GetByIndex<RemainingSteps>();
} else return GetByIndex<RemainingSteps - ChildSteps, ChildIndex + 1>();
}
/*
* Get leaf by index.
*/
template<size_t RemainingSteps, size_t ChildIndex=0>
constexpr auto& Get() noexcept {
using Child = typename std::tuple_element<ChildIndex, parent_t>::type;
constexpr size_t ChildSteps = Child::GetSize();
if constexpr ( RemainingSteps < ChildSteps ) {
return std::get<ChildIndex>(*this).template Get<RemainingSteps>();
} else return Get<RemainingSteps - ChildSteps, ChildIndex + 1>();
}
/*
* Get leaf by index.
*/
template<size_t RemainingSteps, size_t ChildIndex=0>
constexpr const auto& Get() const noexcept {
return const_cast<this_t *>(this)->Get<RemainingSteps, ChildIndex>();
}
/*
* Is the Query type contained in the subtree?
*/
template<typename Query>
static constexpr bool HasType() noexcept {
if constexpr ( sizeof...(Rest) > 0 ) {
return (
std::is_same<First, Query>() // is this node the Query?
|| First::template HasType<Query>() // does first child contain Query?
// does a subsequent node contain Query?
|| PodInternalNode<Rest...>::template HasType<Query>()
);
} else return (
std::is_same<First, Query>() // is this node the Query?
|| First::template HasType<Query>() // does first child contain Query?
);
}
/*
* Get leaf by type.
* Returns first leaf of Query type.
*/
template<typename Query, size_t SearchIndex=0>
constexpr Query& Get() noexcept {
using Child = typename std::tuple_element<SearchIndex, parent_t>::type;
if constexpr ( uitsl::tuple_has_type<Query, parent_t>::value ) {
// if one of immediate children is Query
return std::get<Query>(*this);
} else if constexpr ( Child::template HasType<Query>() ) {
// if is one of child's children
return std::get<SearchIndex>(*this).template Get<Query>();
} else { // check the next child
return Get<Query, SearchIndex + 1>();
}
}
/*
* Get leaf by type.
* Returns first leaf with Query type.
*/
template<typename Query, size_t SearchIndex=0>
constexpr const Query& Get() const noexcept {
return const_cast<this_t *>(this)->Get<Query, SearchIndex>();
}
/*
* Set all child nodes to value-initialized state.
*/
void Reset() noexcept {
// adapted from https://stackoverflow.com/a/45498003
std::apply(
[](auto& ...x){ (..., [](auto& v){ v.Reset(); }(x)); },
*static_cast<parent_t*>(this)
);
}
};
} // namespace uitsl
#endif // #ifndef UITSL_DATASTRUCTS_PODINTERNALNODE_HPP_INCLUDE