Horizon
associated_types.hpp
1 // Range v3 library
2 //
3 // Copyright Eric Niebler 2013-2014, 2016-present
4 // Copyright Casey Carter 2016
5 //
6 // Use, modification and distribution is subject to the
7 // Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
10 //
11 // Project home: https://github.com/ericniebler/range-v3
12 //
13 
14 #ifndef RANGES_V3_STD_DETAIL_ASSOCIATED_TYPES_HPP
15 #define RANGES_V3_STD_DETAIL_ASSOCIATED_TYPES_HPP
16 
17 #include <climits>
18 #include <cstdint>
19 
20 #include <range/v3/detail/config.hpp>
21 
22 #include <range/v3/detail/prologue.hpp>
23 
24 namespace ranges
25 {
28 
31  namespace detail
32  {
33  struct nil_
34  {};
35 
36  template<typename T, typename...>
37  using always_ = T;
38 
39 #if defined(_MSC_VER) && !defined(__clang__) && !defined(__EDG__)
40  // MSVC laughs at your silly micro-optimizations and implements
41  // conditional_t, enable_if_t, is_object_v, and is_integral_v in the
42  // compiler.
43  using std::conditional_t;
44  using std::enable_if;
45  using std::enable_if_t;
46 #else // ^^^ MSVC / not MSVC vvv
47  template<bool>
48  struct _cond
49  {
50  template<typename, typename U>
51  using invoke = U;
52  };
53  template<>
54  struct _cond<true>
55  {
56  template<typename T, typename>
57  using invoke = T;
58  };
59  template<bool B, typename T, typename U>
60  using conditional_t = typename _cond<B>::template invoke<T, U>;
61 
62  template<bool>
63  struct enable_if
64  {};
65  template<>
66  struct enable_if<true>
67  {
68  template<typename T>
69  using invoke = T;
70  };
71  template<bool B, typename T = void>
72  using enable_if_t = typename enable_if<B>::template invoke<T>;
73 
74 #ifndef __clang__
75  // NB: insufficient for MSVC, which (non-conformingly) allows function
76  // pointers to implicitly convert to void*.
77  void is_objptr_(void const volatile *);
78 
79  // std::is_object, optimized for compile time.
80  template<typename T>
81  constexpr bool is_object_(long)
82  {
83  return false;
84  }
85  template<typename T>
86  constexpr bool is_object_(int, T * (*q)(T &) = nullptr, T * p = nullptr,
87  decltype(detail::is_objptr_(q(*p))) * = nullptr)
88  {
89  return (void)p, (void)q, true;
90  }
91 #endif // !__clang__
92 
93  template<typename T>
94  constexpr bool is_integral_(...)
95  {
96  return false;
97  }
98  template<typename T, T = 1>
99  constexpr bool is_integral_(long)
100  {
101  return true;
102  }
103 #if defined(__cpp_nontype_template_parameter_class) && \
104  __cpp_nontype_template_parameter_class > 0
105  template<typename T>
106  constexpr bool is_integral_(int, int T::* = nullptr)
107  {
108  return false;
109  }
110 #endif
111 #endif // detect MSVC
112 
113  template<typename T>
114  struct with_difference_type_
115  {
116  using difference_type = T;
117  };
118 
119  template<typename T>
120  using difference_result_t =
121  decltype(std::declval<T const &>() - std::declval<T const &>());
122 
123  template<typename, typename = void>
124  struct incrementable_traits_2_
125  {};
126 
127  template<typename T>
128  struct incrementable_traits_2_<
129  T,
130 #if defined(_MSC_VER) && !defined(__clang__) && !defined(__EDG__)
131  std::enable_if_t<std::is_integral_v<difference_result_t<T>>>>
132 #elif defined(RANGES_WORKAROUND_GCC_91923)
133  std::enable_if_t<std::is_integral<difference_result_t<T>>::value>>
134 #else
135  always_<void, int[is_integral_<difference_result_t<T>>(0)]>>
136 #endif // detect MSVC
137  {
138  using difference_type = std::make_signed_t<difference_result_t<T>>;
139  };
140 
141  template<typename T, typename = void>
142  struct incrementable_traits_1_ : incrementable_traits_2_<T>
143  {};
144 
145  template<typename T>
146  struct incrementable_traits_1_<T *>
147 #ifdef __clang__
148  : conditional_t<__is_object(T), with_difference_type_<std::ptrdiff_t>, nil_>
149 #elif defined(_MSC_VER) && !defined(__EDG__)
150  : conditional_t<std::is_object_v<T>, with_difference_type_<std::ptrdiff_t>, nil_>
151 #else // ^^^ MSVC / not MSVC vvv
152  : conditional_t<is_object_<T>(0), with_difference_type_<std::ptrdiff_t>, nil_>
153 #endif // detect MSVC
154  {};
155 
156  template<typename T>
157  struct incrementable_traits_1_<T, always_<void, typename T::difference_type>>
158  {
159  using difference_type = typename T::difference_type;
160  };
161  } // namespace detail
163 
164  template<typename T>
165  struct incrementable_traits : detail::incrementable_traits_1_<T>
166  {};
167 
168  template<typename T>
170  {};
171 
173  namespace detail
174  {
175 #ifdef __clang__
176  template<typename T, bool = __is_object(T)>
177 #elif defined(_MSC_VER) && !defined(__EDG__)
178  template<typename T, bool = std::is_object_v<T>>
179 #else // ^^^ MSVC / not MSVC vvv
180  template<typename T, bool = is_object_<T>(0)>
181 #endif // detect MSVC
182  struct with_value_type_
183  {};
184  template<typename T>
185  struct with_value_type_<T, true>
186  {
187  using value_type = T;
188  };
189  template<typename T>
190  struct with_value_type_<T const, true>
191  {
192  using value_type = T;
193  };
194  template<typename T>
195  struct with_value_type_<T volatile, true>
196  {
197  using value_type = T;
198  };
199  template<typename T>
200  struct with_value_type_<T const volatile, true>
201  {
202  using value_type = T;
203  };
204  template<typename, typename = void>
205  struct readable_traits_2_
206  {};
207  template<typename T>
208  struct readable_traits_2_<T, always_<void, typename T::element_type>>
209  : with_value_type_<typename T::element_type>
210  {};
211  template<typename T, typename = void>
212  struct readable_traits_1_ : readable_traits_2_<T>
213  {};
214  template<typename T>
215  struct readable_traits_1_<T[]> : with_value_type_<T>
216  {};
217  template<typename T, std::size_t N>
218  struct readable_traits_1_<T[N]> : with_value_type_<T>
219  {};
220  template<typename T>
221  struct readable_traits_1_<T *> : detail::with_value_type_<T>
222  {};
223  template<typename T>
224  struct readable_traits_1_<T, always_<void, typename T::value_type>>
225  : with_value_type_<typename T::value_type>
226  {};
227  } // namespace detail
229 
231  // Not to spec:
232  // * For class types with both member value_type and element_type, value_type is
233  // preferred (see ericniebler/stl2#299).
234  template<typename T>
235  struct indirectly_readable_traits : detail::readable_traits_1_<T>
236  {};
237 
238  template<typename T>
240  {};
241 
243  namespace detail
244  {
245  template<typename D = std::ptrdiff_t>
246  struct std_output_iterator_traits
247  {
248  using iterator_category = std::output_iterator_tag;
249  using difference_type = D;
250  using value_type = void;
251  using reference = void;
252  using pointer = void;
253  };
254 
255  // For testing whether a particular instantiation of std::iterator_traits
256  // is user-specified or not.
257 #if defined(_MSVC_STL_UPDATE) && defined(__cpp_lib_concepts) && _MSVC_STL_UPDATE >= 201908L
258  template<typename I>
259  inline constexpr bool is_std_iterator_traits_specialized_v =
260  !std::_Is_from_primary<std::iterator_traits<I>>;
261 #else
262 #if defined(__GLIBCXX__)
263  template<typename I>
264  char (&is_std_iterator_traits_specialized_impl_(std::__iterator_traits<I> *))[2];
265  template<typename I>
266  char is_std_iterator_traits_specialized_impl_(void *);
267 #elif defined(_LIBCPP_VERSION)
268  // In older versions of libc++, the base template inherits from std::__iterator_traits<typename, bool>.
269  template<template<typename, bool> class IteratorTraitsBase, typename I, bool B>
270  char (&libcpp_iterator_traits_base_impl(IteratorTraitsBase<I, B> *))[2];
271  template<template<typename, bool> class IteratorTraitsBase, typename I>
272  char libcpp_iterator_traits_base_impl(void *);
273 
274  // In newer versions, the base template has only one template parameter and provides the
275  // __primary_template typedef which aliases the iterator_traits specialization.
276  template<template<typename> class, typename I>
277  char (&libcpp_iterator_traits_base_impl(typename std::iterator_traits<I>::__primary_template *))[2];
278  template<template<typename> class, typename I>
279  char libcpp_iterator_traits_base_impl(void *);
280 
281  template<typename I>
282  auto is_std_iterator_traits_specialized_impl_(std::iterator_traits<I>* traits)
283  -> decltype(libcpp_iterator_traits_base_impl<std::__iterator_traits, I>(traits));
284 #elif defined(_MSVC_STL_VERSION)
285  template<typename I>
286  char (&is_std_iterator_traits_specialized_impl_(
287  std::_Iterator_traits_base<I> *))[2];
288  template<typename I>
289  char is_std_iterator_traits_specialized_impl_(void *);
290 #else
291  template<typename I>
292  char (&is_std_iterator_traits_specialized_impl_(void *))[2];
293 #endif
294  template<typename, typename T>
295  char (&is_std_iterator_traits_specialized_impl_(std::iterator_traits<T *> *))[2];
296 
297  template<typename I>
298  RANGES_INLINE_VAR constexpr bool is_std_iterator_traits_specialized_v =
299  1 == sizeof(is_std_iterator_traits_specialized_impl_<I>(
300  static_cast<std::iterator_traits<I> *>(nullptr)));
301 #endif
302  // The standard iterator_traits<T *> specialization(s) do not count
303  // as user-specialized. This will no longer be necessary in C++20.
304  // This helps with `T volatile*` and `void *`.
305  template<typename T>
306  RANGES_INLINE_VAR constexpr bool is_std_iterator_traits_specialized_v<T *> =
307  false;
308  } // namespace detail
310 } // namespace ranges
311 
312 #include <range/v3/detail/epilogue.hpp>
313 
314 #endif
template(typename ActionFn, typename Rng)(concept(invocable_action_closure_)(ActionFn
\concept invocable_action_closure_
typename Fn::template invoke< Args... > invoke
Evaluate the invocable Fn with the arguments Args.
Definition: meta.hpp:541
typename detail::_cond< If >::template invoke< Then, Else > conditional_t
Select one type or another depending on a compile-time Boolean.
Definition: meta.hpp:1148
Definition: associated_types.hpp:166
Definition: associated_types.hpp:236