-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
322 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
187 changes: 187 additions & 0 deletions
187
src/tools/std20/type_traits/details/common_reference.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
namespace detail { | ||
|
||
template < typename T, typename U > | ||
struct copy_cv { | ||
using type = U; | ||
}; | ||
|
||
template < typename T, typename U > | ||
struct copy_cv< const T, U > { | ||
using type = std::add_const_t< U >; | ||
}; | ||
|
||
template < typename T, typename U> | ||
struct copy_cv<volatile T, U> { | ||
using type = std::add_volatile_t< U >; | ||
}; | ||
|
||
template < typename T, typename U > | ||
struct copy_cv< const volatile T, U > { | ||
using type = std::add_cv_t< U >; | ||
}; | ||
|
||
template < typename T, typename U > | ||
using copy_cv_t = typename copy_cv< T, U >::type; | ||
|
||
template < typename T, typename U > | ||
using cond_res_t = decltype( false ? std::declval< T (&)()>()() | ||
: std::declval< U (&)()>()() ); | ||
|
||
template < typename A, typename B, | ||
typename X = std::remove_reference_t< A >, | ||
typename Y = std::remove_reference_t< B >, | ||
typename = void > | ||
struct common_ref {}; | ||
|
||
template < typename A, typename B > | ||
using common_ref_t = typename common_ref< A, B >::type; | ||
|
||
template < typename A, typename B, | ||
typename X = std::remove_reference_t< A >, | ||
typename Y = std::remove_reference_t< B >, | ||
typename = void > | ||
struct lval_common_ref {}; | ||
|
||
template < typename A, typename B, typename X, typename Y > | ||
struct lval_common_ref< | ||
A, B, X, Y, | ||
std::enable_if_t< | ||
std::is_reference_v< cond_res_t< copy_cv_t< X, Y >&, | ||
copy_cv_t< Y, X >& > > > > { | ||
|
||
using type = cond_res_t<copy_cv_t<X, Y>&, copy_cv_t<Y, X>&>; | ||
}; | ||
|
||
template < typename A, typename B > | ||
using lval_common_ref_t = typename lval_common_ref< A, B >::type; | ||
|
||
template < typename A, typename B, typename X, typename Y > | ||
struct common_ref< A&, B&, X, Y> : lval_common_ref< A&, B& > {}; | ||
|
||
template < typename X, typename Y > | ||
using rref_cr_helper_t = std::remove_reference_t< lval_common_ref_t< X&, Y& > >&&; | ||
|
||
template < typename A, typename B, typename X, typename Y > | ||
struct common_ref< | ||
A&&, B&&, X, Y, | ||
std::enable_if_t< | ||
std::is_convertible_v< A&&, rref_cr_helper_t< X, Y > > && | ||
std::is_convertible_v< B&&, rref_cr_helper_t< X, Y > > > > { | ||
|
||
using type = rref_cr_helper_t< X, Y >; | ||
}; | ||
|
||
template < typename A, typename B, typename X, typename Y > | ||
struct common_ref< | ||
A&&, B&, X, Y, | ||
std::enable_if_t< | ||
std::is_convertible_v< A&&, lval_common_ref_t< const X&, Y& > > > > { | ||
|
||
using type = lval_common_ref_t<const X&, Y&>; | ||
}; | ||
|
||
template < typename A, typename B, typename X, typename Y > | ||
struct common_ref< A&, B&&, X, Y > : common_ref< B&&, A& > {}; | ||
|
||
template < typename > | ||
struct xref { | ||
|
||
template <typename U> using type = U; | ||
}; | ||
|
||
template < typename A > | ||
struct xref< A& > { | ||
|
||
template < typename U > | ||
using type = std::add_lvalue_reference_t< typename xref< A >::template type< U > >; | ||
}; | ||
|
||
template < typename A > | ||
struct xref< A&& > { | ||
|
||
template < typename U > | ||
using type = std::add_rvalue_reference_t< typename xref< A >::template type< U > >; | ||
}; | ||
|
||
template < typename A > | ||
struct xref< const A > { | ||
|
||
template < typename U > | ||
using type = std::add_const_t< typename xref< A >::template type< U > >; | ||
}; | ||
|
||
template < typename A > | ||
struct xref< volatile A > { | ||
|
||
template < typename U > | ||
using type = std::add_volatile_t< typename xref< A >::template type< U > >; | ||
}; | ||
|
||
template < typename A > | ||
struct xref< const volatile A > { | ||
|
||
template < typename U > | ||
using type = std::add_cv_t< typename xref< A >::template type< U > >; | ||
}; | ||
|
||
template < template < typename... > typename AliasT, typename... Args > | ||
auto exists_helper( long ) -> std::false_type; | ||
|
||
template < template < typename...> typename AliasT, typename... Args, | ||
typename = AliasT< Args... > > | ||
auto exists_helper(int) -> std::true_type; | ||
|
||
template < template < typename... > typename AliasT, typename... Args > | ||
inline constexpr bool exists_v = decltype( exists_helper< AliasT, Args... >(0) )::value; | ||
|
||
template < typename T, typename U > | ||
inline constexpr bool has_common_ref_v = exists_v< common_ref_t, T, U >; | ||
|
||
template <typename T, typename U> | ||
using basic_common_ref_t = | ||
typename basic_common_reference< remove_cvref_t< T >, | ||
remove_cvref_t< U >, | ||
detail::xref< T >::template type, | ||
detail::xref< U >::template type >::type; | ||
|
||
template < typename T, typename U > | ||
inline constexpr bool has_basic_common_ref_v = exists_v< basic_common_ref_t, T, U >; | ||
|
||
template < typename T, typename U > | ||
inline constexpr bool has_cond_res_v = exists_v< cond_res_t, T, U >; | ||
|
||
template < typename T, typename U, typename = void > | ||
struct binary_common_ref : std::common_type< T, U > {}; | ||
|
||
template < typename T, typename U > | ||
struct binary_common_ref< T, U, std::enable_if_t< has_common_ref_v< T, U > > > | ||
: common_ref< T, U > {}; | ||
|
||
template < typename T, typename U > | ||
struct binary_common_ref< | ||
T, U, | ||
std::enable_if_t< has_basic_common_ref_v< T, U > && | ||
! has_common_ref_v< T, U > > > { | ||
|
||
using type = basic_common_ref_t< T, U >; | ||
}; | ||
|
||
template < typename T, typename U > | ||
struct binary_common_ref< | ||
T, U, | ||
std::enable_if_t< has_cond_res_v< T, U > && | ||
! has_basic_common_ref_v< T, U > && | ||
! has_common_ref_v< T, U > > > { | ||
|
||
using type = cond_res_t< T, U >; | ||
}; | ||
|
||
template < typename, typename T1, typename T2, typename... Rest > | ||
struct multiple_common_reference {}; | ||
|
||
template < typename T1, typename T2, typename... Rest > | ||
struct multiple_common_reference< | ||
std::void_t< common_reference_t< T1, T2 > >, | ||
T1, T2, Rest... > : common_reference< common_reference_t< T1, T2 >, Rest... > {}; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
add_cpp_test( std20.type_traits.remove_cvref remove_cvref.test.cpp ) | ||
add_cpp_test( std20.type_traits.type_identity type_identity.test.cpp ) | ||
add_cpp_test( std20.type_traits.remove_cvref remove_cvref.test.cpp ) | ||
add_cpp_test( std20.type_traits.type_identity type_identity.test.cpp ) | ||
add_cpp_test( std20.type_traits.common_reference common_reference.test.cpp ) |
87 changes: 87 additions & 0 deletions
87
src/tools/std20/type_traits/test/common_reference.test.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// include Catch2 | ||
#include <catch2/catch_test_macros.hpp> | ||
|
||
// what we are testing | ||
#include "tools/std20/type_traits.hpp" | ||
|
||
// other includes | ||
|
||
// convenience typedefs | ||
using namespace njoy::tools; | ||
|
||
class Base {}; | ||
class First : public Base {}; | ||
class Second : public Base {}; | ||
|
||
SCENARIO( "common_reference and common_reference_t" ) { | ||
|
||
CHECK( std::is_same_v< std20::common_reference< int >::type, int > ); | ||
CHECK( std::is_same_v< std20::common_reference< int&, int& >::type, int& > ); | ||
CHECK( std::is_same_v< std20::common_reference< const int&, int& >::type, const int& > ); | ||
CHECK( std::is_same_v< std20::common_reference< int&, const int& >::type, const int& > ); | ||
CHECK( std::is_same_v< std20::common_reference< int&&, int& >::type, const int& > ); | ||
CHECK( std::is_same_v< std20::common_reference< int&&, const int& >::type, const int& > ); | ||
CHECK( std::is_same_v< std20::common_reference< int&, int&& >::type, const int& > ); | ||
CHECK( std::is_same_v< std20::common_reference< const int&, int&& >::type, const int& > ); | ||
CHECK( std::is_same_v< std20::common_reference< int&&, int&& >::type, int&& > ); | ||
CHECK( std::is_same_v< std20::common_reference< const int&&, int&& >::type, const int&& > ); | ||
CHECK( std::is_same_v< std20::common_reference< int&&, const int&& >::type, const int&& > ); | ||
|
||
CHECK( std::is_same_v< std20::common_reference< volatile int >::type, volatile int > ); | ||
CHECK( std::is_same_v< std20::common_reference< volatile int&, int& >::type, volatile int& > ); | ||
CHECK( std::is_same_v< std20::common_reference< volatile int&, const int& >::type, const volatile int& > ); | ||
CHECK( std::is_same_v< std20::common_reference< const volatile int&, int& >::type, const volatile int& > ); | ||
CHECK( std::is_same_v< std20::common_reference< int&, volatile int& >::type, volatile int& > ); | ||
CHECK( std::is_same_v< std20::common_reference< const int&, volatile int& >::type, const volatile int& > ); | ||
CHECK( std::is_same_v< std20::common_reference< int&, const volatile int& >::type, const volatile int& > ); | ||
|
||
CHECK( std::is_same_v< std20::common_reference< Base& >::type, Base& > ); | ||
CHECK( std::is_same_v< std20::common_reference< Base&, First& >::type, Base& > ); | ||
CHECK( std::is_same_v< std20::common_reference< Base&, Second& >::type, Base& > ); | ||
CHECK( std::is_same_v< std20::common_reference< Base&, First&, Second& >::type, Base& > ); | ||
CHECK( std::is_same_v< std20::common_reference< Base&&, First&& >::type, Base&& > ); | ||
CHECK( std::is_same_v< std20::common_reference< Base&&, Second&& >::type, Base&& > ); | ||
CHECK( std::is_same_v< std20::common_reference< Base&&, First&&, Second&& >::type, Base&& > ); | ||
CHECK( std::is_same_v< std20::common_reference< Base&, First&& >::type, const Base& > ); | ||
CHECK( std::is_same_v< std20::common_reference< Base&&, First& >::type, const Base& > ); | ||
CHECK( std::is_same_v< std20::common_reference< Base&, First&, Second& >::type, Base& > ); | ||
CHECK( std::is_same_v< std20::common_reference< Base&&, First&& >::type, Base&& > ); | ||
CHECK( std::is_same_v< std20::common_reference< Base&&, Second&& >::type, Base&& > ); | ||
CHECK( std::is_same_v< std20::common_reference< Base&&, First&&, Second&& >::type, Base&& > ); | ||
CHECK( std::is_same_v< std20::common_reference< Base&, First&&, Second&& >::type, const Base& > ); | ||
|
||
CHECK( std::is_same_v< std20::common_reference_t< int >, int > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< int&, int& >, int& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< const int&, int& >, const int& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< int&, const int& >, const int& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< int&&, int& >, const int& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< int&&, const int& >, const int& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< int&, int&& >, const int& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< const int&, int&& >, const int& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< int&&, int&& >, int&& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< const int&&, int&& >, const int&& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< int&&, const int&& >, const int&& > ); | ||
|
||
CHECK( std::is_same_v< std20::common_reference_t< volatile int >, volatile int > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< volatile int&, int& >, volatile int& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< volatile int&, const int& >, const volatile int& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< const volatile int&, int& >, const volatile int& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< int&, volatile int& >, volatile int& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< const int&, volatile int& >, const volatile int& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< int&, const volatile int& >, const volatile int& > ); | ||
|
||
CHECK( std::is_same_v< std20::common_reference_t< Base& >, Base& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< Base&, First& >, Base& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< Base&, Second& >, Base& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< Base&, First&, Second& >, Base& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< Base&&, First&& >, Base&& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< Base&&, Second&& >, Base&& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< Base&&, First&&, Second&& >, Base&& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< Base&, First&& >, const Base& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< Base&&, First& >, const Base& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< Base&, First&, Second& >, Base& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< Base&&, First&& >, Base&& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< Base&&, Second&& >, Base&& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< Base&&, First&&, Second&& >, Base&& > ); | ||
CHECK( std::is_same_v< std20::common_reference_t< Base&, First&&, Second&& >, const Base& > ); | ||
} // SCENARIO |