Skip to content

Commit

Permalink
Extend is specialisation testing (#328)
Browse files Browse the repository at this point in the history
* Extend is specialisation testing

* Run pre-commit
  • Loading branch information
Twon authored Oct 6, 2024
1 parent a080630 commit 7e8353c
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 16 deletions.
11 changes: 8 additions & 3 deletions libraries/core/src/morpheus/core/meta/is_specialisation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,18 @@ struct is_specialisation_of : std::false_type {};
template <template <typename...> class Template, typename... T>
struct is_specialisation_of<Template, Template<T...>> : std::true_type {};

// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2098r0.pdf
/// \var is_specialisation_of_v
/// Provides a meta functions for testing if a type is a specialisation of a given template type.
/// \note
/// Follows the proposed meta function outlined in: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2098r0.pdf
template <template <typename...> class Template, typename T>
inline constexpr bool is_specialisation_of_v = false;

template <template <typename...> class Template, typename... T>
inline constexpr bool is_specialisation_of_v<Template, Template<T...>> = true;
template <template <typename...> class Template, typename... Args>
inline constexpr bool is_specialisation_of_v<Template, Template<Args...>> = true;

/// \concept IsSpecialisationOf
/// Provides a concept of the is_specialisation_of_v meta function.
template <template <typename...> class Template, typename... T>
concept IsSpecialisationOf = is_specialisation_of_v<Template, T...>;

Expand Down
68 changes: 55 additions & 13 deletions libraries/core/tests/meta/is_specialisation.tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@
#include "morpheus/core/meta/is_specialisation.hpp"

#include <catch2/catch_all.hpp>
#include <array>

#include <complex>
#include <list>
#include <optional>
#include <set>
#include <tuple>
#include <unordered_set>
#include <vector>


namespace morpheus::meta
{
Expand All @@ -13,20 +21,54 @@ class TestTemplateWith1Param {};
template <typename T1, typename T2>
class TestTemplateWith2Param {};

template <typename T>
inline constexpr bool isVector = meta::IsSpecialisationOf<std::vector, T>;

TEST_CASE("Meta is specialisation allows the compile time detection of specialisations", "[morpheus.meta.is_specialisation]")
{
// STATIC_REQUIRE(meta::is_specialisation_of<std::array, std::array<int, 5>>::value);
STATIC_REQUIRE(meta::is_specialisation_of<TestTemplateWith1Param, TestTemplateWith1Param<int>>::value);
STATIC_REQUIRE(meta::is_specialisation_of<TestTemplateWith2Param, TestTemplateWith2Param<int,int>>::value);

/*
STATIC_REQUIRE(meta::is_specialisation_of<TestTemplateWith1Param<int>>::value);
STATIC_REQUIRE(meta::is_specialisation_of<TestTemplateWith2Param<int, int>>::value);
STATIC_REQUIRE(meta::is_specialisation_of_v<TestTemplateWith1Param<int>>);
STATIC_REQUIRE(meta::is_specialisation_of_v<TestTemplateWith2Param<int, int>>);
*/
// static_assert(meta::is_specialisation_of<std::array<int, 5>>::value);
// static_assert(meta::is_specialisation_of_v<std::array<int, 5>>);
SECTION("Test against simple types")
{
STATIC_REQUIRE(meta::is_specialisation_of_v<TestTemplateWith1Param, TestTemplateWith1Param<int>>);
STATIC_REQUIRE(meta::is_specialisation_of_v<TestTemplateWith2Param, TestTemplateWith2Param<int, int>>);
}
SECTION("Test against STL types")
{
// 1 arg templates
STATIC_REQUIRE(meta::is_specialisation_of_v<std::complex, std::complex<int>>);
STATIC_REQUIRE(meta::is_specialisation_of_v<std::list, std::list<int>>);
STATIC_REQUIRE(meta::is_specialisation_of_v<std::optional, std::optional<int>>);
STATIC_REQUIRE(meta::is_specialisation_of_v<std::set, std::set<int>>);
STATIC_REQUIRE(meta::is_specialisation_of_v<std::vector, std::vector<int>>);
STATIC_REQUIRE(!meta::is_specialisation_of_v<std::complex, std::list<int>>);
STATIC_REQUIRE(!meta::is_specialisation_of_v<std::list, std::optional<int>>);
STATIC_REQUIRE(!meta::is_specialisation_of_v<std::optional, std::set<int>>);
STATIC_REQUIRE(!meta::is_specialisation_of_v<std::set, std::vector<int>>);
STATIC_REQUIRE(!meta::is_specialisation_of_v<std::vector, std::complex<int>>);

// 2 arg templates
STATIC_REQUIRE(meta::is_specialisation_of_v<std::vector, std::vector<int, std::allocator<int>>>);
STATIC_REQUIRE(!meta::is_specialisation_of_v<std::vector, std::list<int, std::allocator<int>>>);

// 3 arg templates
STATIC_REQUIRE(meta::is_specialisation_of_v<std::set, std::set<int, std::less<int>, std::allocator<int>>>);
STATIC_REQUIRE(!meta::is_specialisation_of_v<std::set, std::tuple<int, std::less<int>, std::allocator<int>>>);

// 4 arg templates
STATIC_REQUIRE(meta::is_specialisation_of_v<std::unordered_set, std::unordered_set<int, std::hash<int>, std::equal_to<int>, std::allocator<int>>>);
STATIC_REQUIRE(!meta::is_specialisation_of_v<std::unordered_set, std::tuple<int, std::hash<int>, std::equal_to<int>, std::allocator<int>>>);
}
SECTION("Create specific meta functions based on higher order is_specialisation_of_v function")
{
// Meta functions checking for a Is vector works for different instanstitations of vector
STATIC_REQUIRE(isVector<std::vector<int>>);
STATIC_REQUIRE(isVector<std::vector<float>>);
STATIC_REQUIRE(isVector<std::vector<double>>);
STATIC_REQUIRE(isVector<std::vector<int, std::allocator<int>>>);

// And detects usage with non vector types.
STATIC_REQUIRE(!isVector<std::list<int>>);
STATIC_REQUIRE(!isVector<std::set<int>>);
}
}

} // namespace morpheus::meta

0 comments on commit 7e8353c

Please sign in to comment.