2 * Copyright 2017-present Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 #include <type_traits>
23 #include <folly/Traits.h>
24 #include <folly/Utility.h>
28 template <typename Pointer>
29 class propagate_const;
31 template <typename Pointer>
32 constexpr Pointer& get_underlying(propagate_const<Pointer>& obj) {
36 template <typename Pointer>
37 constexpr Pointer const& get_underlying(propagate_const<Pointer> const& obj) {
43 struct is_propagate_const : std::false_type {};
44 template <typename Pointer>
45 struct is_propagate_const<propagate_const<Pointer>> : std::true_type {};
47 using is_decay_propagate_const = is_propagate_const<_t<std::decay<T>>>;
49 namespace propagate_const_adl {
52 auto adl_swap(T& a, T& b) noexcept(noexcept(swap(a, b)))
53 -> decltype(swap(a, b)) {
56 } // namespace propagate_const_adl
59 // mimic: std::experimental::propagate_const, C++ Library Fundamentals TS v2
60 template <typename Pointer>
61 class propagate_const {
64 _t<std::remove_reference<decltype(*std::declval<Pointer&>())>>;
66 constexpr propagate_const() = default;
67 constexpr propagate_const(propagate_const&&) = default;
68 constexpr propagate_const(propagate_const const&) = delete;
71 typename OtherPointer,
73 std::is_constructible<Pointer, OtherPointer&&>::value &&
74 !std::is_convertible<OtherPointer&&, Pointer>::value,
76 constexpr explicit propagate_const(propagate_const<OtherPointer>&& other)
77 : pointer_(static_cast<OtherPointer&&>(other.pointer_)) {}
80 typename OtherPointer,
82 std::is_constructible<Pointer, OtherPointer&&>::value &&
83 std::is_convertible<OtherPointer&&, Pointer>::value,
85 constexpr propagate_const(propagate_const<OtherPointer>&& other)
86 : pointer_(static_cast<OtherPointer&&>(other.pointer_)) {}
89 typename OtherPointer,
91 !detail::is_decay_propagate_const<OtherPointer>::value &&
92 std::is_constructible<Pointer, OtherPointer&&>::value &&
93 !std::is_convertible<OtherPointer&&, Pointer>::value,
95 constexpr explicit propagate_const(OtherPointer&& other)
96 : pointer_(static_cast<OtherPointer&&>(other)) {}
99 typename OtherPointer,
101 !detail::is_decay_propagate_const<OtherPointer>::value &&
102 std::is_constructible<Pointer, OtherPointer&&>::value &&
103 std::is_convertible<OtherPointer&&, Pointer>::value,
105 constexpr propagate_const(OtherPointer&& other)
106 : pointer_(static_cast<OtherPointer&&>(other)) {}
108 constexpr propagate_const& operator=(propagate_const&&) = default;
109 constexpr propagate_const& operator=(propagate_const const&) = delete;
112 typename OtherPointer,
114 std::enable_if<std::is_convertible<OtherPointer&&, Pointer>::value>>>
115 FOLLY_CPP14_CONSTEXPR propagate_const& operator=(
116 propagate_const<OtherPointer>&& other) {
117 pointer_ = static_cast<OtherPointer&&>(other.pointer_);
121 typename OtherPointer,
122 typename = _t<std::enable_if<
123 !detail::is_decay_propagate_const<OtherPointer>::value &&
124 std::is_convertible<OtherPointer&&, Pointer>::value>>>
125 FOLLY_CPP14_CONSTEXPR propagate_const& operator=(OtherPointer&& other) {
126 pointer_ = static_cast<OtherPointer&&>(other);
129 FOLLY_CPP14_CONSTEXPR void swap(propagate_const& other) noexcept(
130 noexcept(detail::propagate_const_adl::adl_swap(
131 std::declval<Pointer&>(),
133 detail::propagate_const_adl::adl_swap(pointer_, other.pointer_);
136 constexpr element_type* get() {
137 return get_(pointer_);
140 constexpr element_type const* get() const {
141 return get_(pointer_);
144 constexpr explicit operator bool() const {
145 return static_cast<bool>(pointer_);
148 constexpr element_type& operator*() {
152 constexpr element_type const& operator*() const {
156 constexpr element_type* operator->() {
160 constexpr element_type const* operator->() const {
165 typename OtherPointer = Pointer,
166 typename = _t<std::enable_if<
167 std::is_pointer<OtherPointer>::value ||
168 std::is_convertible<OtherPointer, element_type*>::value>>>
169 constexpr operator element_type*() {
174 typename OtherPointer = Pointer,
175 typename = _t<std::enable_if<
176 std::is_pointer<OtherPointer>::value ||
177 std::is_convertible<OtherPointer, element_type const*>::value>>>
178 constexpr operator element_type const*() const {
183 friend Pointer& get_underlying<>(propagate_const&);
184 friend Pointer const& get_underlying<>(propagate_const const&);
186 template <typename T>
187 static T* get_(T* t) {
190 template <typename T>
191 static auto get_(T& t) -> decltype(t.get()) {
198 template <typename Pointer>
199 FOLLY_CPP14_CONSTEXPR void swap(
200 propagate_const<Pointer>& a,
201 propagate_const<Pointer>& b) noexcept(noexcept(a.swap(b))) {
205 template <typename Pointer>
206 constexpr bool operator==(propagate_const<Pointer> const& a, std::nullptr_t) {
207 return get_underlying(a) == nullptr;
210 template <typename Pointer>
211 constexpr bool operator==(std::nullptr_t, propagate_const<Pointer> const& a) {
212 return nullptr == get_underlying(a);
215 template <typename Pointer>
216 constexpr bool operator!=(propagate_const<Pointer> const& a, std::nullptr_t) {
217 return get_underlying(a) != nullptr;
220 template <typename Pointer>
221 constexpr bool operator!=(std::nullptr_t, propagate_const<Pointer> const& a) {
222 return nullptr != get_underlying(a);
225 template <typename Pointer>
226 constexpr bool operator==(
227 propagate_const<Pointer> const& a,
228 propagate_const<Pointer> const& b) {
229 return get_underlying(a) == get_underlying(b);
232 template <typename Pointer>
233 constexpr bool operator!=(
234 propagate_const<Pointer> const& a,
235 propagate_const<Pointer> const& b) {
236 return get_underlying(a) != get_underlying(b);
239 template <typename Pointer>
240 constexpr bool operator<(
241 propagate_const<Pointer> const& a,
242 propagate_const<Pointer> const& b) {
243 return get_underlying(a) < get_underlying(b);
246 template <typename Pointer>
247 constexpr bool operator<=(
248 propagate_const<Pointer> const& a,
249 propagate_const<Pointer> const& b) {
250 return get_underlying(a) <= get_underlying(b);
253 template <typename Pointer>
254 constexpr bool operator>(
255 propagate_const<Pointer> const& a,
256 propagate_const<Pointer> const& b) {
257 return get_underlying(a) > get_underlying(b);
260 template <typename Pointer>
261 constexpr bool operator>=(
262 propagate_const<Pointer> const& a,
263 propagate_const<Pointer> const& b) {
264 return get_underlying(a) >= get_underlying(b);
267 // Note: contrary to the specification, the heterogeneous comparison operators
268 // only participate in overload resolution when the equivalent heterogeneous
269 // comparison operators on the underlying pointers, as returned by invocation
270 // of get_underlying, would also participate in overload resolution.
272 template <typename Pointer, typename Other>
273 constexpr auto operator==(propagate_const<Pointer> const& a, Other const& b)
274 -> decltype(get_underlying(a) == b, false) {
275 return get_underlying(a) == b;
278 template <typename Pointer, typename Other>
279 constexpr auto operator!=(propagate_const<Pointer> const& a, Other const& b)
280 -> decltype(get_underlying(a) != b, false) {
281 return get_underlying(a) != b;
284 template <typename Pointer, typename Other>
285 constexpr auto operator<(propagate_const<Pointer> const& a, Other const& b)
286 -> decltype(get_underlying(a) < b, false) {
287 return get_underlying(a) < b;
290 template <typename Pointer, typename Other>
291 constexpr auto operator<=(propagate_const<Pointer> const& a, Other const& b)
292 -> decltype(get_underlying(a) <= b, false) {
293 return get_underlying(a) <= b;
296 template <typename Pointer, typename Other>
297 constexpr auto operator>(propagate_const<Pointer> const& a, Other const& b)
298 -> decltype(get_underlying(a) > b, false) {
299 return get_underlying(a) > b;
302 template <typename Pointer, typename Other>
303 constexpr auto operator>=(propagate_const<Pointer> const& a, Other const& b)
304 -> decltype(get_underlying(a) >= b, false) {
305 return get_underlying(a) >= b;
308 template <typename Other, typename Pointer>
309 constexpr auto operator==(Other const& a, propagate_const<Pointer> const& b)
310 -> decltype(a == get_underlying(b), false) {
311 return a == get_underlying(b);
314 template <typename Other, typename Pointer>
315 constexpr auto operator!=(Other const& a, propagate_const<Pointer> const& b)
316 -> decltype(a != get_underlying(b), false) {
317 return a != get_underlying(b);
320 template <typename Other, typename Pointer>
321 constexpr auto operator<(Other const& a, propagate_const<Pointer> const& b)
322 -> decltype(a < get_underlying(b), false) {
323 return a < get_underlying(b);
326 template <typename Other, typename Pointer>
327 constexpr auto operator<=(Other const& a, propagate_const<Pointer> const& b)
328 -> decltype(a <= get_underlying(b), false) {
329 return a <= get_underlying(b);
332 template <typename Other, typename Pointer>
333 constexpr auto operator>(Other const& a, propagate_const<Pointer> const& b)
334 -> decltype(a > get_underlying(b), false) {
335 return a > get_underlying(b);
338 template <typename Other, typename Pointer>
339 constexpr auto operator>=(Other const& a, propagate_const<Pointer> const& b)
340 -> decltype(a >= get_underlying(b), false) {
341 return a >= get_underlying(b);
348 template <typename Pointer>
349 struct hash<folly::propagate_const<Pointer>> : private hash<Pointer> {
350 using hash<Pointer>::hash;
352 size_t operator()(folly::propagate_const<Pointer> const& obj) const {
353 return hash<Pointer>::operator()(folly::get_underlying(obj));
357 template <typename Pointer>
358 struct equal_to<folly::propagate_const<Pointer>> : private equal_to<Pointer> {
359 using equal_to<Pointer>::equal_to;
361 constexpr bool operator()(
362 folly::propagate_const<Pointer> const& a,
363 folly::propagate_const<Pointer> const& b) {
364 return equal_to<Pointer>::operator()(
365 folly::get_underlying(a), folly::get_underlying(b));
369 template <typename Pointer>
370 struct not_equal_to<folly::propagate_const<Pointer>>
371 : private not_equal_to<Pointer> {
372 using not_equal_to<Pointer>::not_equal_to;
374 constexpr bool operator()(
375 folly::propagate_const<Pointer> const& a,
376 folly::propagate_const<Pointer> const& b) {
377 return not_equal_to<Pointer>::operator()(
378 folly::get_underlying(a), folly::get_underlying(b));
382 template <typename Pointer>
383 struct less<folly::propagate_const<Pointer>> : private less<Pointer> {
384 using less<Pointer>::less;
386 constexpr bool operator()(
387 folly::propagate_const<Pointer> const& a,
388 folly::propagate_const<Pointer> const& b) {
389 return less<Pointer>::operator()(
390 folly::get_underlying(a), folly::get_underlying(b));
394 template <typename Pointer>
395 struct greater<folly::propagate_const<Pointer>> : private greater<Pointer> {
396 using greater<Pointer>::greater;
398 constexpr bool operator()(
399 folly::propagate_const<Pointer> const& a,
400 folly::propagate_const<Pointer> const& b) {
401 return greater<Pointer>::operator()(
402 folly::get_underlying(a), folly::get_underlying(b));
406 template <typename Pointer>
407 struct less_equal<folly::propagate_const<Pointer>>
408 : private less_equal<Pointer> {
409 using less_equal<Pointer>::less_equal;
411 constexpr bool operator()(
412 folly::propagate_const<Pointer> const& a,
413 folly::propagate_const<Pointer> const& b) {
414 return less_equal<Pointer>::operator()(
415 folly::get_underlying(a), folly::get_underlying(b));
419 template <typename Pointer>
420 struct greater_equal<folly::propagate_const<Pointer>>
421 : private greater_equal<Pointer> {
422 using greater_equal<Pointer>::greater_equal;
424 constexpr bool operator()(
425 folly::propagate_const<Pointer> const& a,
426 folly::propagate_const<Pointer> const& b) {
427 return greater_equal<Pointer>::operator()(
428 folly::get_underlying(a), folly::get_underlying(b));