Skip to content

Commit

Permalink
feat: introduce typelist (#2656)
Browse files Browse the repository at this point in the history
This PR introduces a minimal implementation of a C++ typelist to be used many in grid I/O (Json/Svg) in order to allow casting to a dedicated grid type.

It follows relatively closely to what @niermann999 has done for detray, but omits the `at[index]` access as it aims to allow type iteration and not individual type casting.
  • Loading branch information
asalzburger authored Nov 14, 2023
1 parent 478abb0 commit 6352ad8
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 0 deletions.
96 changes: 96 additions & 0 deletions Core/include/Acts/Utilities/detail/TypeList.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// This file is part of the Acts project.
//
// Copyright (C) 2023 CERN for the benefit of the Acts project
//
// 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/.

#pragma once

#include <type_traits>

namespace Acts {

namespace detail {

/// @brief type list implementation
/// @see https://www.codingwiththomas.com/blog/getting-started-with-typelists
template <typename... Ts>
struct TypeList {};

/// Number of types in the list
/// @{
template <typename = void>
struct getSize {};

template <typename... Ts>
struct getSize<TypeList<Ts...>>
: std::integral_constant<size_t, sizeof...(Ts)> {};

template <typename L>
constexpr inline size_t size{getSize<L>()};
/// @}

/// Access the first type
/// @{
template <typename = void>
struct getFront {};

template <typename T, typename... Ts>
struct getFront<TypeList<T, Ts...>> {
using type = T;
};

template <typename L>
using front = typename getFront<L>::type;
/// @}

/// Access the last type
/// @{
template <typename = void>
struct getBack {};

template <typename T, typename... Ts>
struct getBack<TypeList<T, Ts...>> {
using type = std::conditional_t<sizeof...(Ts) == 0, T,
typename getBack<TypeList<Ts...>>::type>;
};
// Base case
template <>
struct getBack<TypeList<>> {
using type = void;
};
template <typename L>
using back = typename getBack<L>::type;
/// @}

/// Append a type
/// @{
template <typename N, typename = void>
struct doPushBack {};

template <typename N, typename... Ts>
struct doPushBack<N, TypeList<Ts...>> {
using type = TypeList<Ts..., N>;
};
template <typename L, typename N>
using push_back = typename doPushBack<N, L>::type;
/// @}

/// Prepend a type
/// @{
template <typename N, typename = void>
struct doPushFront {};

template <typename N, typename... Ts>
struct doPushFront<N, TypeList<Ts...>> {
using type = TypeList<N, Ts...>;
};

template <typename L, typename N>
using push_front = typename doPushFront<N, L>::type;
/// @}

} // namespace detail
} // namespace Acts
1 change: 1 addition & 0 deletions Tests/UnitTests/Core/Utilities/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ add_unittest(Ray RayTest.cpp)
add_unittest(RealQuadraticEquation RealQuadraticEquationTests.cpp)
add_unittest(Result ResultTests.cpp)
add_unittest(Subspace SubspaceTests.cpp)
add_unittest(TypeList TypeListTests.cpp)
add_unittest(TypeTraits TypeTraitsTest.cpp)
add_unittest(UnitVectors UnitVectorsTests.cpp)
add_unittest(Delegate DelegateTests.cpp)
Expand Down
78 changes: 78 additions & 0 deletions Tests/UnitTests/Core/Utilities/TypeListTests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// This file is part of the Acts project.
//
// Copyright (C) 2023 CERN for the benefit of the Acts project
//
// 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/.

#include <boost/test/data/test_case.hpp>
#include <boost/test/unit_test.hpp>

#include "Acts/Utilities/detail/TypeList.hpp"

#include <type_traits>
#include <typeinfo>

namespace bdata = boost::unit_test::data;
namespace tt = boost::test_tools;

BOOST_AUTO_TEST_SUITE(Utilities)

BOOST_AUTO_TEST_CASE(TypeListCreation) {
struct A {};

using MyList = Acts::detail::TypeList<float, int, double, A>;

bool frontIsFloat = std::is_same_v<Acts::detail::front<MyList>, float>;
BOOST_CHECK(frontIsFloat);

bool backIsA = std::is_same_v<Acts::detail::back<MyList>, A>;
BOOST_CHECK(backIsA);

BOOST_CHECK_EQUAL(Acts::detail::size<MyList>, 4);
}

BOOST_AUTO_TEST_CASE(TypeListPushFront) {
class A {};
class B {};
class C {};

using BcList = Acts::detail::TypeList<B, C>;
auto abc = Acts::detail::push_front<BcList, A>{};
bool frontIsA = std::is_same_v<Acts::detail::front<decltype(abc)>, A>;
BOOST_CHECK(frontIsA);
}

BOOST_AUTO_TEST_CASE(TypeListPushBack) {
class A {};
class B {};
class C {};

using AbList = Acts::detail::TypeList<A, B>;
auto abc = Acts::detail::push_back<AbList, C>{};
bool backIsC = std::is_same_v<Acts::detail::back<decltype(abc)>, C>;
BOOST_CHECK(backIsC);
}

template <typename Head, typename... Tail>
void printTypes(
[[maybe_unused]] const Acts::detail::TypeList<Head, Tail...>& t) {
std::cout << typeid(Head).name() << '\n';
if constexpr (sizeof...(Tail) > 0) {
Acts::detail::TypeList<Tail...> remainingTypes;
printTypes(remainingTypes);
}
}

BOOST_AUTO_TEST_CASE(TypeListPrintType) {
class A {};
class B {};
class C {};

using AbcList = Acts::detail::TypeList<A, B, C>;
AbcList a{};
printTypes(a);
}

BOOST_AUTO_TEST_SUITE_END()

0 comments on commit 6352ad8

Please sign in to comment.