Skip to content

Commit

Permalink
Fix common_reference for reference_wrapper types
Browse files Browse the repository at this point in the history
  • Loading branch information
lackhole committed Oct 17, 2024
1 parent f584851 commit c0003c7
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 92 deletions.
135 changes: 47 additions & 88 deletions include/preview/__type_traits/basic_common_reference.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,116 +5,75 @@
#ifndef PREVIEW_TYPE_TRAITS_BASIC_COMMON_REFERENCE_H_
#define PREVIEW_TYPE_TRAITS_BASIC_COMMON_REFERENCE_H_

#include <tuple>
#include <type_traits>

#include "preview/__core/inline_variable.h"
#include "preview/__functional/is_reference_wrapper.h"
#include "preview/__tuple/tuple_like.h"
#include "preview/__type_traits/bool_constant.h"
#include "preview/__type_traits/common_reference.h"
#include "preview/__type_traits/conditional.h"
#include "preview/__type_traits/conjunction.h"
#include "preview/__type_traits/detail/tag.h"
#include "preview/__type_traits/disjunction.h"
#include "preview/__type_traits/is_specialization.h"
#include "preview/__type_traits/negation.h"
#include "preview/__type_traits/no_traits.h"
#include "preview/__type_traits/type_identity.h"

namespace preview {
namespace detail {

template<typename T, typename U, template<typename> class TQual, template<typename> class UQual,
bool = conjunction<tuple_like<T>, tuple_like<U>>::value /* false */>
struct basic_common_reference_tuple_like : no_traits {};

template<typename TTuple, typename UTuple, template<typename> class TQual, template<typename> class UQual, typename Index>
struct basic_common_reference_tuple_like_impl_2;

template<typename TTuple, typename UTuple, template<typename> class TQual, template<typename> class UQual, std::size_t... I>
struct basic_common_reference_tuple_like_impl_2<TTuple, UTuple, TQual, UQual, std::index_sequence<I...>> {
using type = std::tuple<
common_reference_t<
TQual< std::tuple_element_t<I, TTuple> >,
UQual< std::tuple_element_t<I, UTuple> >
>... >;
namespace bcr_specialization {

// TODO: Concept
// true specialization is defined in basic_common_reference_std_specializations.h
template<class R, class T, class RQ, class TQ, bool = /* false */ is_reference_wrapper<R>::value>
struct ref_wrap_common_reference_exists_with : std::false_type {};

enum category_t : int {
kDefault = 0,
kTupleLike = 1,
kPair = 2,
kReferenceWrapper = 3,
};

template<typename TTuple, typename UTuple, template<typename> class TQual, template<typename> class UQual, typename Index>
struct basic_common_reference_tuple_like_impl_1;

template<typename TTuple, typename UTuple, template<typename> class TQual, template<typename> class UQual, std::size_t... I>
struct basic_common_reference_tuple_like_impl_1<TTuple, UTuple, TQual, UQual, std::index_sequence<I...>>
: std::conditional_t<
conjunction<
has_typename_type< common_reference<TQual<std::tuple_element_t<I, TTuple>>,
UQual<std::tuple_element_t<I, UTuple>>> >...
>::value,
basic_common_reference_tuple_like_impl_2<TTuple, UTuple, TQual, UQual, std::index_sequence<I...>>,
no_traits
> {};
template<typename T, typename U, template<typename> class TQual, template<typename> class UQual,
bool SatisfyRequires = /* false */ conjunction_v<tuple_like<T>, tuple_like<U>>>
struct satisfy_tuple_like_constraints : std::false_type {};

template<typename T, typename U, template<typename> class TQual, template<typename> class UQual>
struct satisfy_pair_constraints : std::false_type {};

template<typename TTuple, typename UTuple, template<typename> class TQual, template<typename> class UQual>
struct basic_common_reference_tuple_like<TTuple, UTuple, TQual, UQual, true>
: std::conditional_t<
conjunction<
disjunction< is_specialization<TTuple, std::tuple>, is_specialization<UTuple, std::tuple> >,
std::is_same<TTuple, std::decay_t<TTuple>>,
std::is_same<UTuple, std::decay_t<UTuple>>,
bool_constant<(std::tuple_size<remove_cvref_t<TTuple>>::value == std::tuple_size<remove_cvref_t<UTuple>>::value)>
>::value,
basic_common_reference_tuple_like_impl_1<TTuple, UTuple, TQual, UQual, std::make_index_sequence<std::tuple_size<remove_cvref_t<TTuple>>::value>>,
no_traits
> {};
template<typename T, typename U, template<typename> class TQual, template<typename> class UQual,
bool SatisfyRequires = /* false */(
(ref_wrap_common_reference_exists_with<T, U, TQual<T>, UQual<U>>::value &&
!ref_wrap_common_reference_exists_with<U, T, UQual<U>, TQual<T>>::value) ||
(ref_wrap_common_reference_exists_with<U, T, UQual<U>, TQual<T>>::value &&
!ref_wrap_common_reference_exists_with<T, U, TQual<T>, UQual<U>>::value)
)>
struct satisfy_ref_wrap_constraints : bool_constant<SatisfyRequires> {};

template<typename T, typename U, template<typename> class TQual, template<typename> class UQual, bool /* false */>
struct basic_common_reference_pair {};
template<typename T, typename U, template<typename> class TQual, template<typename> class UQual>
PREVIEW_INLINE_VARIABLE constexpr int category = preview::conditional_t<
satisfy_tuple_like_constraints <T, U, TQual, UQual>, tag_v<kTupleLike>,
satisfy_pair_constraints <T, U, TQual, UQual>, tag_v<kPair>,
satisfy_ref_wrap_constraints <T, U, TQual, UQual>, tag_v<kReferenceWrapper>,
tag_v<kDefault>
>::value;

template<typename T1, typename T2, typename U1, typename U2, template<typename> class TQual, template<typename> class UQual>
struct basic_common_reference_pair<std::pair<T1, T2>, std::pair<U1, U2>, TQual, UQual, true> {
using type = std::pair< common_reference_t<TQual<T1>, UQual<U1>>,
common_reference_t<TQual<T2>, UQual<U2>> >;
};
template<typename T, typename U, template<typename> class TQual, template<typename> class UQual, int Tag>
struct basic_common_reference_base;

template<typename R, typename T, typename RQ, typename TQ,
bool = conjunction<
negation< is_specialization<T, std::reference_wrapper> >,
has_typename_type< common_reference<R&, TQ> >
>::value /* false */>
struct basic_common_reference_ref_wrap {};

template<typename R, typename T, typename RQ, typename TQ>
struct basic_common_reference_ref_wrap<R, T, RQ, TQ, true>
: std::conditional_t<
convertible_to<RQ, common_reference_t<R&, TQ>>::value,
type_identity<common_reference_t<R&, TQ>>,
no_traits
> {};
template<typename T, typename U, template<typename> class TQual, template<typename> class UQual>
struct basic_common_reference_base<T, U, TQual, UQual, kDefault> {};

} // namespace bcr_specialization
} // namespace detail

// Primary template
template<typename T, typename U, template<typename> class TQual, template<typename> class UQual>
struct basic_common_reference : detail::basic_common_reference_tuple_like<T, U, TQual, UQual> {};

// specializations of basic_common_reference
template<typename T1, typename T2, typename U1, typename U2,
template<typename> class TQual, template<typename> class UQual>
struct basic_common_reference<std::pair<T1, T2>, std::pair<U1, U2>, TQual, UQual>
: detail::basic_common_reference_pair<
std::pair<T1, T2>, std::pair<U1, U2>,
struct basic_common_reference
: detail::bcr_specialization::basic_common_reference_base<
T, U,
TQual, UQual,
conjunction<
has_typename_type< common_reference< TQual<T1>, UQual<U1> > >,
has_typename_type< common_reference< TQual<T2>, UQual<U2> > >
>::value
detail::bcr_specialization::category<T, U, TQual, UQual>
> {};

template<typename R, typename T, template<typename> class RQual, template<typename> class TQual>
struct basic_common_reference<std::reference_wrapper<R>, T, RQual, TQual>
: detail::basic_common_reference_ref_wrap<R, T, RQual<R>, TQual<T>> {};

template<typename R, typename T, template<typename> class RQual, template<typename> class TQual>
struct basic_common_reference<T, std::reference_wrapper<R>, TQual, RQual>
: detail::basic_common_reference_ref_wrap<R, T, RQual<R>, TQual<T>> {};


} // namespace preview

#endif // PREVIEW_TYPE_TRAITS_BASIC_COMMON_REFERENCE_H_
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
//
// Created by yonggyulee on 2024. 10. 17.
//

#ifndef PREVIEW_TYPE_TRAITS_BASIC_COMMON_REFERENCE_STD_SPECIALIZATIONS_H_
#define PREVIEW_TYPE_TRAITS_BASIC_COMMON_REFERENCE_STD_SPECIALIZATIONS_H_

#include <tuple>
#include <type_traits>
#include <utility>

#include "preview/__concepts/convertible_to.h"
#include "preview/__tuple/tuple_like.h"
#include "preview/__tuple/tuple_integer_sequence.h"
#include "preview/__type_traits/basic_common_reference.h"
#include "preview/__type_traits/common_reference.h"
#include "preview/__type_traits/disjunction.h"
#include "preview/__type_traits/has_typename_type.h"
#include "preview/__type_traits/is_specialization.h"

namespace preview {
namespace detail {
namespace bcr_specialization {

// basic_common_reference<tuple-like>

template<typename TTuple, typename UTuple, template<typename> class TQual, template<typename> class UQual, typename IndexSequence>
struct satisfy_tuple_like_constraints_impl_3;
template<typename TTuple, typename UTuple, template<typename> class TQual, template<typename> class UQual, std::size_t... I>
struct satisfy_tuple_like_constraints_impl_3<TTuple, UTuple, TQual, UQual, std::index_sequence<I...>> : conjunction<
has_typename_type<
common_reference<TQual<std::tuple_element_t<I, TTuple>>,
UQual<std::tuple_element_t<I, UTuple>>>
>...
> {};

template<typename TTuple, typename UTuple, template<typename> class TQual, template<typename> class UQual,
bool = /* false */ (std::tuple_size<TTuple>::value == std::tuple_size<UTuple>::value)>
struct satisfy_tuple_like_constraints_impl_2 : std::false_type {};

template<typename TTuple, typename UTuple, template<typename> class TQual, template<typename> class UQual>
struct satisfy_tuple_like_constraints_impl_2<TTuple, UTuple, TQual, UQual, true>
: satisfy_tuple_like_constraints_impl_3<TTuple, UTuple, TQual, UQual, tuple_index_sequence<TTuple>> {};

template<typename TTuple, typename UTuple, template<typename> class TQual, template<typename> class UQual,
bool = /* false */ conjunction_v<
disjunction<is_specialization<TTuple, std::tuple>, is_specialization<UTuple, std::tuple>>,
std::is_same<TTuple, std::decay_t<TTuple>>,
std::is_same<UTuple, std::decay_t<UTuple>>
>
>
struct satisfy_tuple_like_constraints_impl : std::false_type {};

template<typename TTuple, typename UTuple, template<typename> class TQual, template<typename> class UQual>
struct satisfy_tuple_like_constraints_impl<TTuple, UTuple, TQual, UQual, true>
: satisfy_tuple_like_constraints_impl_2<TTuple, UTuple, TQual, UQual> {};

template<typename TTuple, typename UTuple, template<typename> class TQual, template<typename> class UQual>
struct satisfy_tuple_like_constraints<TTuple, UTuple, TQual, UQual, true>
: satisfy_tuple_like_constraints_impl<TTuple, UTuple, TQual, UQual> {};

template<typename TTuple, typename UTuple, template<typename> class TQual, template<typename> class UQual, typename ISeq>
struct basic_common_reference_base_tuple_like;

template<typename TTuple, typename UTuple, template<typename> class TQual, template<typename> class UQual, std::size_t... I>
struct basic_common_reference_base_tuple_like<TTuple, UTuple, TQual, UQual, std::index_sequence<I...>> {
using type = std::tuple<
common_reference_t<std::tuple_element_t<I, TTuple>,
std::tuple_element_t<I, UTuple>>
...
>;
};

template<typename TTuple, typename UTuple, template<typename> class TQual, template<typename> class UQual>
struct basic_common_reference_base<TTuple, UTuple, TQual, UQual, kTupleLike>
: basic_common_reference_base_tuple_like<TTuple, UTuple, TQual, UQual, tuple_index_sequence<TTuple>> {};



// basic_const_reference<pair>

template<typename T1, typename T2, typename U1, typename U2, template<typename> class TQual, template<typename> class UQual>
struct satisfy_pair_constraints<std::pair<T1, T2>, std::pair<U1, U2>, TQual, UQual> : conjunction<
has_typename_type<common_reference<TQual<T1>, UQual<U1>>>,
has_typename_type<common_reference<TQual<T2>, UQual<U2>>>
> {};

template<typename T1, typename T2, typename U1, typename U2, template<typename> class TQual, template<typename> class UQual>
struct basic_common_reference_base<std::pair<T1, T2>, std::pair<U1, U2>, TQual, UQual, kPair> {
using type = std::pair<common_reference_t<T1, U1>, common_reference_t<T2, U2>>;
};



// basic_const_reference<std::reference_wrapper>
// basic_const_reference<preview::reference_wrapper>

template<class R, class T, class RQ, class TQ, bool = /* false */ has_typename_type<common_reference<typename R::type&, TQ>>::value>
struct ref_wrap_common_reference_exists_with_impl : std::false_type {};

template<class R, class T, class RQ, class TQ>
struct ref_wrap_common_reference_exists_with_impl<R, T, RQ, TQ, true>
: convertible_to<RQ, common_reference_t<typename R::type&, TQ>> {};

template<class R, class T, class RQ, class TQ>
struct ref_wrap_common_reference_exists_with<R, T, RQ, TQ, true>
: ref_wrap_common_reference_exists_with_impl<R, T, RQ, TQ> {};

template<class R, class T, template<class> class RQual, template<class> class TQual>
struct basic_common_reference_ref_wrap {
using type = common_reference_t<typename R::type&, TQual<T>>;
};

template<class T, class U, template<class> class TQual, template<class> class UQual>
struct basic_common_reference_base<T, U, TQual, UQual, kReferenceWrapper> : std::conditional_t<
(ref_wrap_common_reference_exists_with<T, U, TQual<T>, UQual<U>>::value &&
!ref_wrap_common_reference_exists_with<U, T, UQual<U>, TQual<T>>::value),
basic_common_reference_ref_wrap<T, U, TQual, UQual>,
basic_common_reference_ref_wrap<U, T, UQual, TQual>
> {};

} // namespace bcr_specialization
} // namespace detail
} // namespace preview

#endif // PREVIEW_TYPE_TRAITS_BASIC_COMMON_REFERENCE_STD_SPECIALIZATIONS_H_
7 changes: 3 additions & 4 deletions include/preview/__type_traits/common_reference.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <utility>

#include "preview/__concepts/convertible_to.h"
#include "preview/__type_traits/basic_common_reference.h"
#include "preview/__type_traits/conjunction.h"
#include "preview/__type_traits/common_type.h"
#include "preview/__type_traits/copy_cvref.h"
Expand All @@ -20,10 +21,6 @@

namespace preview {

// forward declare
template<typename T, typename U, template<typename> class TQual, template<typename> class UQual>
struct basic_common_reference;

template<typename...>
struct common_reference;

Expand Down Expand Up @@ -155,4 +152,6 @@ using common_reference_t = typename common_reference<T...>::type;

} // namespace preview

#include "preview/__type_traits/basic_common_reference_std_specializations.h"

#endif // PREVIEW_TYPE_TRAITS_COMMON_REFERENCE_H_

0 comments on commit c0003c7

Please sign in to comment.