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 <tuple>
#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...>;
public:
// inherit constructors
using parent_t::parent_t;
/*
* Get number of descendant leaf nodes.
*/
static constexpr size_t GetSize() {
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& Get() {
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 {
return const_cast<this_t *>(this)->Get<RemainingSteps, ChildIndex>();
}
/*
* Is the Query type contained in the subtree?
*/
template<typename Query>
static constexpr bool HasType() {
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() {
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 {
return const_cast<this_t *>(this)->Get<Query, SearchIndex>();
}
/*
* Set all child nodes to value-initialized state.
*/
void Reset() {
// 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