Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Type] Simplification of the Rebind trait using concepts #5200

Merged
merged 4 commits into from
Jan 19, 2025
Merged
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
36 changes: 11 additions & 25 deletions Sofa/framework/Type/src/sofa/type/trait/Rebind.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,18 @@

namespace sofa::type
{
// primary template handles types that have no nested ::rebind_to member:
template< class T, class OtherType, class = void >
struct HasRebindTypedef : std::false_type { };
template<class T, class OtherType>
concept CanTypeRebind = requires
{
typename T::template rebind_to<OtherType>;
};

// specialization recognizes types that do have a nested ::rebind_to member:
template< class T, class OtherType >
struct HasRebindTypedef<T, OtherType, std::void_t<typename T::template rebind_to<OtherType> > > : std::true_type { };

/**
* Depending on the type _T, has a public member typedef to. Otherwise, there is no member typedef (this is the
* case of this implementation).
*/
template<class _T, class _OtherType, class Enable = void>
template<class _T, class _OtherType>
struct Rebind {};

/**
Expand All @@ -45,33 +44,20 @@ namespace sofa::type
* \tparam _T Type that does have a nested ::rebind_to member
*/
template<class _T, class _OtherType>
struct Rebind<_T, _OtherType, std::enable_if_t<HasRebindTypedef<_T, _OtherType>::value > >
requires CanTypeRebind<_T, _OtherType>
struct Rebind<_T, _OtherType>
{
using to = typename _T::template rebind_to<_OtherType>;
};

template <class...>
inline constexpr auto deny = false;

/**
* \brief Specialization for types that do NOT have a nested ::rebind_to member. In this implementation, Rebind has
* no public member typedef \ref to. If this implementation is chosen by the compiler (the number of template
* parameters is probably different from 1), a compilation error occurs.
* \tparam _T Type that does NOT have a nested ::rebind_to member
*/
template<class _T, class _OtherType>
struct Rebind<_T, _OtherType, std::enable_if_t<!HasRebindTypedef<_T, _OtherType>::value > >
{
static_assert(deny<_T>, "_T must match _T<A>");
};

/**
* \brief Specialization for types that do NOT have a nested ::rebind_to member. In this implementation, Rebind has
* a public member typedef \ref to.
* \tparam _T Type that does NOT have a nested ::rebind_to member
*/
template<template<class> class _T, class A, class _OtherType>
struct Rebind<_T<A>, _OtherType, std::enable_if_t<!HasRebindTypedef<_T<A>, _OtherType >::value > >
requires (!CanTypeRebind<_T<A>, _OtherType>)
struct Rebind<_T<A>, _OtherType>
{
using to = _T<_OtherType>;
};
Expand All @@ -83,7 +69,7 @@ namespace sofa::type
* 1) sofa::type::rebind_to< sofa::type::vector<int>, float> is of type sofa::type::vector<float>. In this example,
* sofa::type::vector has a typedef rebind_to that will be used to deduce the type.
* 2) sofa::type::rebind_to< sofa::type::Quat<float>, double> is of type sofa::type::Quat<double>. In this example,
* sofa::type::Quat does not have a typdef rebind_to.
* sofa::type::Quat does not have a typedef rebind_to.
* 3) It makes no sense to use sofa::type::rebind on types having more than one template parameter, such as
* sofa::type::fixed_array. A compilation error would occur.
*/
Expand Down
1 change: 1 addition & 0 deletions Sofa/framework/Type/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ set(SOURCE_FILES
MatTypes_test.cpp
Material_test.cpp
Quater_test.cpp
Rebind_test.cpp
RGBAColor_test.cpp
StrongType_test.cpp
SVector_test.cpp
Expand Down
59 changes: 59 additions & 0 deletions Sofa/framework/Type/test/Rebind_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/******************************************************************************
* SOFA, Simulation Open-Framework Architecture *
* (c) 2006 INRIA, USTL, UJF, CNRS, MGH *
* *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as published by *
* the Free Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
* for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*******************************************************************************
* Authors: The SOFA Team and external contributors (see Authors.txt) *
* *
* Contact information: [email protected] *
******************************************************************************/
#include <sofa/type/trait/Rebind.h>
#include <sofa/type/vector.h>

static_assert(sofa::type::CanTypeRebind<sofa::type::vector<float>, int>);
static_assert(sofa::type::CanTypeRebind<sofa::type::vector<int>, int>);

static_assert(
std::is_same_v<
sofa::type::rebind_to<sofa::type::vector<float>, int>,
sofa::type::vector<int>
>);
static_assert(
std::is_same_v<
sofa::type::rebind_to<sofa::type::vector<int>, int>,
sofa::type::vector<int>
>);

template<class T>
struct DummyNoRebind{};

static_assert(!sofa::type::CanTypeRebind<DummyNoRebind<float>, int>);

static_assert(
std::is_same_v<
sofa::type::rebind_to<DummyNoRebind<float>, int>,
DummyNoRebind<int>
>);

template<class T>
struct DummyWithConstraintRebind
{
template<class U>
requires std::is_integral_v<U>
using rebind_to = U;
};

static_assert(sofa::type::CanTypeRebind<DummyWithConstraintRebind<float>, int>);
static_assert(!sofa::type::CanTypeRebind<DummyWithConstraintRebind<float>, std::string>);
18 changes: 11 additions & 7 deletions Sofa/framework/Type/test/vector_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class vector_test : public NumericTest<>,
void checkVector(const std::vector<std::string>& params) ;
void checkVectorAccessFailure() const;

void checkRebind();
void checkRebind() const;
};

template<class T>
Expand Down Expand Up @@ -103,14 +103,18 @@ void vector_test<T>::checkVectorAccessFailure() const
}

template <class T>
void vector_test<T>::checkRebind()
void vector_test<T>::checkRebind() const
{
constexpr bool hasRebind = sofa::type::HasRebindTypedef<vector<T>, int>::value;
constexpr bool hasRebind = sofa::type::CanTypeRebind<vector<T>, int>;
static_assert(hasRebind);
EXPECT_TRUE(hasRebind);
using rebinded = typename sofa::type::Rebind<vector<T>, int >::to;
using vec_int = vector<int>;
constexpr bool isRebindOK = std::is_same_v<rebinded, vec_int >;
EXPECT_TRUE(isRebindOK);
if constexpr (hasRebind)
{
using rebinded = typename sofa::type::Rebind<vector<T>, int >::to;
using vec_int = vector<int>;
constexpr bool isRebindOK = std::is_same_v<rebinded, vec_int >;
EXPECT_TRUE(isRebindOK);
}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down
Loading