Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions include/gz/physics/FeatureList.hh
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ namespace gz
// Forward declarations
template <typename...> struct CombineLists;
template <bool, typename...> struct SelfConflict;
template <typename> struct IterateTuple;
template <typename> struct IterateList;
}

/////////////////////////////////////////////////
Expand All @@ -58,15 +58,29 @@ namespace gz
/// using AdvancedList = FeatureList<BasicList, AdvancedA, AdvancedB>;
/// \endcode
template <typename... FeaturesT>
struct FeatureList : detail::IterateTuple<std::tuple<FeaturesT...>>
struct FeatureList : detail::IterateList<TypeList<FeaturesT...>>
{
/// FlatFeatureTypeList is a TypeList containing all the feature classes
/// that are bundled in this list. This list is fully seralialized; any
/// hierarchy that was used to construct this FeatureList will be
/// collapsed in this member.
public: using FlatFeatureTypeList =
typename detail::CombineLists<FeaturesT...>::Result;

/// Features is a std::tuple containing all the feature classes that are
/// bundled in this list. This list is fully seralialized; any hierarchy
/// that was used to construct this FeatureList will be collapsed in this
/// member.
/// \note This type is the same as FlatFeatureTypeList but the features
/// are contained in a std::tuple. Users are encouraged to use
/// FlatFeatureTypeList since it provides faster build times
public: using Features =
typename detail::CombineLists<FeaturesT...>::Result;
typename detail::ToTuple<FlatFeatureTypeList>::type;

/// \brief TypeList containing the raw list of features
public: using FeatureTypeList = TypeList<FeaturesT...>;

/// \brief std::tuple containing the raw list of features
public: using FeatureTuple = std::tuple<FeaturesT...>;

/// \brief A static constexpr function which indicates whether a given
Expand All @@ -79,7 +93,7 @@ namespace gz

/// \brief A static constexpr function which indicates whether any
/// features in SomeFeatureList conflict with any features in
/// SomeFeatureList.
/// this list.
///
/// \tparam SomeFeatureList
/// The list to compare against for conflicts.
Expand Down
2 changes: 1 addition & 1 deletion include/gz/physics/FindFeatures.hh
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ namespace gz
template <typename FeaturePolicyT, typename FeatureListT>
struct FindFeatures
{
// Tuple of features that are being requested
// List of features that are being requested
using Features = FeatureListT;

/// \brief Find a set of plugins that satisfy the requested list of
Expand Down
2 changes: 1 addition & 1 deletion include/gz/physics/RequestEngine.hh
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ namespace gz
// Forward declaration of the Engine type that will be returned
using EnginePtrType = EnginePtr<FeaturePolicyT, FeatureListT>;

// Tuple of features that are being requested
// List of features that are being requested
using Features = FeatureListT;

/// \brief Get an Engine from the given physics plugin.
Expand Down
69 changes: 69 additions & 0 deletions include/gz/physics/TemplateHelpers.hh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#ifndef GZ_PHYSICS_TEMPLATEHELPERS_HH_
#define GZ_PHYSICS_TEMPLATEHELPERS_HH_

#include <tuple>
#include <type_traits>

namespace gz
Expand All @@ -31,6 +32,74 @@ namespace gz
/// is useful for template metaprogramming.
template <class... T> struct type { };

/// \brief A minimal variadic template container for types.
/// This is used instead of std::tuple for intermediate template
/// metaprogramming to drastically reduce compiler memory and instantiation
/// times.
template <typename... Ts>
struct TypeList {
static constexpr std::size_t size = sizeof...(Ts);
};

/// \brief Concatenate multiple TypeLists into a single TypeList.
///
/// This uses an O(log N) tree-based recursion instead of an O(N) linear
/// recursion. When concatenating many lists (e.g., during feature
/// flattening), a linear recursion would instantiate a deeply nested stack
/// of templates, which can quickly exceed the compiler's maximum
/// instantiation depth or heap space limits (especially on MSVC).
/// By pairing elements and recursing down, we keep the instantiation stack
/// shallow and dramatically reduce compiler memory consumption.
template <typename... Lists>
struct TypeListCat;

template <>
struct TypeListCat<> {
using type = TypeList<>;
};

template <typename... Ts>
struct TypeListCat<TypeList<Ts...>> {
using type = TypeList<Ts...>;
};

template <typename... T1, typename... T2>
struct TypeListCat<TypeList<T1...>, TypeList<T2...>> {
using type = TypeList<T1..., T2...>;
};

// We explicitly require at least 3 lists (L1, L2, L3) to use this
// recursive specialization. This prevents an ambiguity error with the
// 2-element base case `TypeListCat<TypeList<T1...>, TypeList<T2...>>`
// when exactly 2 lists are provided.
template <typename L1, typename L2, typename L3, typename... Rest>
struct TypeListCat<L1, L2, L3, Rest...> {
using type = typename TypeListCat<
typename TypeListCat<L1, L2>::type,
typename TypeListCat<L3, Rest...>::type>::type;
};

namespace detail
{
/// \brief Convert a TypeList to a std::tuple
template <typename T>
struct ToTuple;

template <typename... Ts>
struct ToTuple<TypeList<Ts...>> {
using type = std::tuple<Ts...>;
};

/// \brief Convert a std::tuple to a TypeList
template <typename T>
struct TupleToTypeList;

template <typename... Ts>
struct TupleToTypeList<std::tuple<Ts...>> {
using type = TypeList<Ts...>;
};
}

/////////////////////////////////////////////////
/// \brief Contains a static constexpr field named `value` which will be
/// true if the type `From` has a const-quality less than or equal to the
Expand Down
69 changes: 31 additions & 38 deletions include/gz/physics/detail/Entity.hh
Original file line number Diff line number Diff line change
Expand Up @@ -35,55 +35,48 @@ namespace gz
/////////////////////////////////////////////////
/// \private Inspired by https://stackoverflow.com/a/26288164
/// This class provides a static constexpr member named `value` which is
/// true if T is one of the entries of Tuple, and false otherwise.
template <typename T, typename Tuple>
struct TupleContainsBase;
/// true if T is one of the entries of List, and false otherwise.
template <typename T, typename List>
struct TypeListContainsBase;

/// \private This specialization implements TupleContainsBase. It only
/// works if Tuple is a std::tuple; any other type for the second template
/// argument will fail to compile.
/// \private This specialization implements TypeListContainsBase for
/// TypeList.
template <typename T, typename... Types>
struct TupleContainsBase<T, std::tuple<Types...>>
: std::integral_constant<bool,
!std::is_same<
std::tuple<typename std::conditional<
std::is_base_of<T, Types>::value, Empty, Types>::type...>,
std::tuple<Types...>
>::value> { };
struct TypeListContainsBase<T, TypeList<Types...>>
: std::integral_constant<bool, (std::is_base_of_v<T, Types> || ...)>
{
};

/// \private This specialization implements TypeListContainsBase for
/// std::tuple.
template <typename T, typename... Types>
struct TypeListContainsBase<T, std::tuple<Types...>>
: std::integral_constant<bool, (std::is_base_of_v<T, Types> || ...)>
{
};

/////////////////////////////////////////////////
template <typename ToFeatureTuple, typename FromFeatureList>
template <typename ToFeatureList, typename FromFeatureList>
struct HasAllFeaturesImpl;

template <typename FromFeatureList,
typename ToFeature1, typename... RemainingFeatures>
struct HasAllFeaturesImpl<
std::tuple<ToFeature1, RemainingFeatures...>, FromFeatureList>
template <typename... ToFeatures, typename FromFeatureList>
struct HasAllFeaturesImpl<TypeList<ToFeatures...>, FromFeatureList>
{
static constexpr bool innerValue =
FromFeatureList::template HasFeature<ToFeature1>();

static constexpr bool value = innerValue
&& HasAllFeaturesImpl<std::tuple<RemainingFeatures...>,
FromFeatureList>::value;

// Note: For an empty TypeList (base case), the C++17 fold expression
// over `&&` evaluates to `true` by definition.
// See: https://en.cppreference.com/w/cpp/language/fold
static constexpr bool value =
(FromFeatureList::template HasFeature<ToFeatures>() && ...);
static_assert(
innerValue,
value || sizeof...(ToFeatures) == 0,
"YOU CANNOT IMPLICITLY UPCAST TO THIS ENTITY TYPE, BECAUSE IT "
"CONTAINS A FEATURE THAT IS NOT INCLUDED IN THE ENTITY THAT YOU "
"ARE CASTING FROM.");
};

/////////////////////////////////////////////////
template <typename FromFeatureList>
struct HasAllFeaturesImpl<std::tuple<>, FromFeatureList>
{
static constexpr bool value = true;
};

/////////////////////////////////////////////////
/// \brief The entity type "From" must contain all the features that are
/// found within the enttiy type "To" in order for an upcast to be valid.
/// found within the entity type "To" in order for an upcast to be valid.
template <typename To, typename From>
struct HasAllFeatures
{
Expand All @@ -92,7 +85,7 @@ namespace gz

static constexpr bool value =
HasAllFeaturesImpl<
typename ToFeatures::Features,
typename ToFeatures::FlatFeatureTypeList,
FromFeatures>::value;
};

Expand All @@ -101,7 +94,7 @@ namespace gz
struct CheckForDowncastableMessage
{
static constexpr bool value =
TupleContainsBase<typename To::Identifier,
TypeListContainsBase<typename To::Identifier,
typename From::UpcastIdentifiers>::value;

static_assert(
Expand All @@ -116,7 +109,7 @@ namespace gz
struct CheckForDowncastableMessage<To, From, true>
{
static constexpr bool value =
TupleContainsBase<typename To::Identifier,
TypeListContainsBase<typename To::Identifier,
typename From::UpcastIdentifiers>::value;

static_assert(
Expand All @@ -140,7 +133,7 @@ namespace gz
static_assert(HasAllFeatures<To, From>::value);

static_assert(CheckForDowncastableMessage<To, From,
TupleContainsBase<
TypeListContainsBase<
typename From::Identifier,
typename To::UpcastIdentifiers>::value>::value);

Expand Down
Loading
Loading