Skip to content

Commit

Permalink
[Type] Simplification of the Rebind trait using concepts (#5200)
Browse files Browse the repository at this point in the history
* [Type] Simplification of the Rebind trait using concepts

* fix

* fix and test

* parentheses
  • Loading branch information
alxbilger authored Jan 19, 2025
1 parent 1f11bee commit aedc7ff
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 32 deletions.
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: contact@sofa-framework.org *
******************************************************************************/
#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

0 comments on commit aedc7ff

Please sign in to comment.