YSTest: swap.hpp 源文件

YSTest PreAlpha_b900_20201012 The YSLib Test Project

swap.hpp
浏览该文件的文档.
1 /*
2 © 2014-2020 FrankHB.
3
4 This file is part of the YSLib project, and may only be used,
5 modified, and distributed under the terms of the YSLib project
6 license, LICENSE.TXT. By continuing to use, modify, or distribute
7 this file you indicate that you have read the license and
8 understand and accept it fully.
9 */
10
28 #ifndef YB_INC_ystdex_swap_hpp_
29 #define YB_INC_ystdex_swap_hpp_ 1
30
31 #include "type_pun.hpp" // for internal "type_pun.hpp", enable_if_t,
32 // is_move_constructible, is_move_assignable, and_, std::move, std::declval,
33 // false_, bool_, is_referenceable, true_, is_class, is_enum, bool_, is_void,
34 // is_nothrow_constructible, is_nothrow_assignable, add_volatile_t,
35 // std::addressof, is_standard_layout, pun_storage_t, aligned_replace_cast;
36
37 #if __cpp_lib_is_swappable >= 201603L
38 # define YB_Impl_Swap_Traits true
39 # define YB_Impl_Swap_ns std
40 #else
41 # define YB_Impl_Swap_Traits false
42 # define YB_Impl_Swap_ns ystdex
43 #endif
44
45 namespace ystdex
46 {
47
49
50
52 // XXX: No %tuple is instantiated in namespace %ystdex, so no tuple check like
53 // libstdc++.
54 template<typename _type>
55 using is_swap_movable = and_<is_move_constructible<_type>,
56 is_move_assignable<_type>>;
57
58 template<typename _type>
59 using is_nothrow_swap_movable = and_<is_nothrow_move_constructible<_type>,
60 is_nothrow_move_assignable<_type>>;
62
64 template<typename _tSwapped, typename _type = void>
65 using enable_if_swap_movable_t
66 = enable_if_t<is_swap_movable<_tSwapped>::value, _type>;
67
68
69 #if !YB_Impl_Swap_Traits
70 inline namespace cpp2017
71 {
72
73 template<typename>
74 struct is_swappable;
75
76 template<typename>
77 struct is_nothrow_swappable;
78
79 } // inline namespace cpp2017;
80 #endif
81
82
83 } // namespace ystdex;
84
86 namespace ystdex_swap
87 {
88
89 yimpl(using ystdex::enable_if_swap_movable_t);
90 yimpl(using ystdex::is_nothrow_swap_movable);
91 yimpl(using ystdex::enable_if_t);
92 using YB_Impl_Swap_ns::is_swappable;
93 using YB_Impl_Swap_ns::is_nothrow_swappable;
94
115 template<typename _type>
117 yconstfn_relaxed yimpl(enable_if_swap_movable_t)<_type>
118 swap(_type& a, _type& b) ynoexcept(is_nothrow_swap_movable<_type>::value)
119 {
120 _type tmp = std::move(a);
121
122 a = std::move(b);
123 b = std::move(tmp);
124 }
126 template<typename _type, size_t _vN>
127 yconstfn_relaxed yimpl(enable_if_t)<is_swappable<_type>::value>
128 swap(_type(&a)[_vN], _type(&b)[_vN])
129 ynoexcept(is_nothrow_swappable<_type>::value);
131
136 template<typename _tFwd1, typename _tFwd2>
137 yconstfn_relaxed void
138 iter_swap(_tFwd1 a, _tFwd1 b)
139 // NOTE: This is similar to libc++.
140 yimpl(ynoexcept_spec(swap(*std::declval<_tFwd1>(),
141 *std::declval<_tFwd2>())))
142 {
143 // XXX: No iterator dereferenceable check for simplicity here.
144 swap(*a, *b);
145 }
146
151 template<typename _tFwd1, typename _tFwd2>
152 yconstfn_relaxed _tFwd2
153 swap_ranges(_tFwd1 first1, _tFwd1 last1, _tFwd2 first2)
154 {
155 // XXX: Excessive order refinment by ','?
156 for(; first1 != last1; ++first1, static_cast<void>(++first2))
157 ystdex_swap::iter_swap(first1, first2);
158 return first2;
159 }
161
162 template<typename _type, size_t _vN>
163 yconstfn_relaxed yimpl(enable_if_t)<is_swappable<_type>::value>
164 swap(_type(&a)[_vN], _type(&b)[_vN])
165 ynoexcept(is_nothrow_swappable<_type>::value)
166 {
167 ystdex_swap::swap_ranges(a, a + _vN, b);
168 }
169
175 namespace dep_swap
176 {
177
179
180 yimpl(using ystdex::nonesuch);
181 yimpl(using ystdex::any_constructible);
182 yimpl(using ystdex::is_same);
183
184 using ystdex_swap::swap;
186 nonesuch
188 swap(any_constructible, any_constructible);
189
191
192
194 template<typename _type, typename _type2>
195 using swap_t = decltype(swap(std::declval<_type>(), std::declval<_type2>()));
196
197
198 template<typename, typename, typename = void>
199 struct well_formed_swap : ystdex::false_
200 {};
201
202 template<typename _type, typename _type2>
203 struct well_formed_swap<_type, _type2, ystdex::void_t<swap_t<_type, _type2>>>
204 : ystdex::true_
205 {};
207
208 // XXX: The order of instantiation is significant. Whether in the primary
209 // template or in an additional explicit specialziation, the fallback one has
210 // to be the first, because the template is instantiated in the call sites need
211 // to see the fallback before failed in a non-immediate context (that is, the
212 // class-body here). The wrong order can actually cause ambiguity with G++ 8
213 // '-std=c++14' (tested for 'ystdex' container with 'std::less'), while Clang++
214 // 7 is permissive.
215 template<typename _type, typename _type2,
216 bool = well_formed_swap<_type, _type2>::value>
217 struct yimpl(helper)
218 {
219 static yconstexpr const bool value = !is_same<decltype(
220 ystdex_swap::swap(std::declval<_type>(), std::declval<_type2>())),
221 nonesuch>::value;
222
223 helper() ynoexcept_spec(ystdex_swap::swap(std::declval<_type>(),
224 std::declval<_type2>()))
225 {}
226 };
227
228 template<typename _type, typename _type2>
229 struct yimpl(helper)<_type, _type2, true>
230 {
232 static yconstexpr const bool value
233 = !is_same<swap_t<_type, _type2>, nonesuch>::value;
234
236 helper()
237 ynoexcept_spec(swap(std::declval<_type>(), std::declval<_type2>()))
238 {}
239 };
241
242 } // namespace dep_swap;
243
244 } // namespace ystdex_swap;
245
246 namespace ystdex
247 {
248
250 inline namespace cpp2017
251 {
252
259 #if YB_Impl_Swap_Traits
260 using std::is_swappable_with;
261 using std::is_swappable;
262 using std::is_nothrow_swappable_with;
263 using std::is_nothrow_swappable;
264 #else
265
267
269
271 template<typename _type, typename _type2>
273 struct is_swappable_with
274 : bool_<yimpl(ystdex_swap::dep_swap::helper<_type, _type2>::value)>
275 {};
276
277
279 template<typename _type>
280 struct is_swappable
281 : and_<is_referenceable<_type>, is_swappable_with<_type&, _type&>>
282 {};
284
285
287
288 template<typename _type, typename _type2>
289 struct is_nothrow_swappable_with : is_nothrow_default_constructible<
290 yimpl(ystdex_swap::dep_swap::helper<_type, _type2>)>
291 {};
292
293
294 template<typename _type>
295 struct is_nothrow_swappable
296 : and_<is_referenceable<_type>, is_nothrow_swappable_with<_type&, _type&>>
297 {};
299
300
301 #endif
302
303
304 } // inline namespace cpp2017;
305
307 using ystdex_swap::iter_swap;
308
310 using ystdex_swap::swap_ranges;
311
313 namespace details
314 {
315
317
318 namespace yimpl(swap_dep_impl)
319 {
320
321 template<typename _type, typename = enable_if_t<is_void<_type>::value>>
322 void
323 swap(_type&);
324
325 template<typename _type, typename _tDummy>
326 yconstfn_relaxed void
327 swap_dep(_type& x, _type& y, _tDummy&&)
328 {
329 ystdex_swap::swap(x, y);
330 }
331 template<typename _type>
332 yconstfn_relaxed auto
333 swap_dep(_type& x, _type& y, true_)
334 -> decltype(static_cast<void>(swap(x, y)))
335 {
336 swap(x, y);
337 }
338
339 } // namespace yimpl(swap_dep_impl);
341
342 } // namespace details;
343
369 template<typename _type>
370 yconstfn_relaxed void
371 swap_dependent(_type& x, _type& y) ynothrow(is_nothrow_swappable<_type>())
372 {
373 details::yimpl(swap_dep_impl)::swap_dep(x, y,
374 // XXX: This has to be exactly %true_ for ADL overload.
375 bool_<is_class<_type>::value || is_enum<_type>::value>());
376 }
377
384 template<typename _type>
385 yimpl(enable_if_t)<is_nothrow_constructible<_type, volatile _type>()
386 && is_nothrow_assignable<_type&, volatile _type&&>()
387 && is_nothrow_assignable<volatile _type&, _type&&>()>
388 swap_volatile(_type& x, volatile _type& y)
389 ynoexcept(is_nothrow_constructible<_type, volatile _type&>()
390 && noexcept(x = std::move(y)) && noexcept(y = std::move(x)))
391 {
392 auto t(std::move(x));
393
394 x = std::move(y);
395 y = std::move(t);
396 }
397 template<typename _type>
398 inline auto
399 swap_volatile(volatile _type& x, _type& y)
400 ynoexcept_spec(ystdex::swap_volatile(y, x))
401 -> decltype(ystdex::swap_volatile(y, x))
402 {
403 ystdex::swap_volatile(y, x);
404 }
405 template<typename _type, size_t _vN>
406 void
407 swap_volatile(_type(&x)[_vN], add_volatile_t<_type[_vN]>& y)
408 ynoexcept(noexcept(ystdex::swap_volatile(x[0], y[0])))
409 {
410 auto first(std::addressof(x[0]));
411 auto first2(std::addressof(y[0]));
412
413 for(const auto last(first + _vN); first != last; yunseq(++first, ++first2))
414 ystdex::swap_volatile(*first, *first2);
415 }
417
419 namespace details
420 {
421
422 template<typename _type, typename _type2>
423 using swap_volatile_avail = bool_<is_volatile<remove_reference_t<_type>>::value
424 != is_volatile<remove_reference_t<_type2>>::value>;
425
426 #if YB_HAS_NOEXCEPT
427 template<typename _type, typename _type2>
428 using swap_volatile_noexcept = and_<swap_volatile_avail<_type, _type2>, bool_<
429 noexcept(swap_volatile(std::declval<_type>(), std::declval<_type2>()))>>;
430 #else
431 template<typename _type, typename _type2>
432 using swap_volatile_noexcept = swap_volatile_avail<_type, _type2>;
433 #endif
434
435 } // namespace details;
436
441 template<typename _type>
442 void
443 swap_underlying(_type& x, _type& y) ynothrow
444 {
445 static_assert(is_standard_layout<_type>(),
446 "Invalid underlying type found.");
447 using utype = pun_storage_t<_type>;
448
449 ystdex_swap::swap(ystdex::aligned_replace_cast<utype&>(x),
450 ystdex::aligned_replace_cast<utype&>(y));
451 }
452
459 template<typename _type, typename _type2, yimpl(typename
461 = enable_if_t<!details::swap_volatile_avail<_type, _type2>::value>)>
462 void
463 vswap(_type&& x, _type2&& y)
464 ynoexcept(is_nothrow_swappable_with<_type&&, _type2&&>())
465 {
466 ystdex::swap_dependent(yforward(x), yforward(y));
467 }
469
470 template<typename _type, typename _type2>
471 inline auto
472 vswap(_type&& x, _type2&& y) ynoexcept(detected_or_t<false_,
473 details::swap_volatile_noexcept, _type, _type2>())
474 -> yimpl(enable_if_t)<details::swap_volatile_avail<_type, _type2>::value>
475 {
476 swap_volatile(yforward(x), yforward(y));
477 }
479
480
481
495 template<typename _type, typename... _tParams>
496 inline _type&
497 create_and_swap(_type& obj, _tParams&&... args)
498 {
499 auto t(yforward(args)...);
500
501 ystdex::swap_dependent(t, obj);
502 return obj;
503 }
504
512 template<typename _type, typename _type2 = _type>
513 YB_ATTR(always_inline) inline _type&
514 copy_and_swap(_type& obj, const _type2& new_val)
515 {
516 return ystdex::create_and_swap(obj, new_val);
517 }
519
520 inline namespace cpp2014
521 {
522
523 #if __cpp_lib_exchange_function >= 201304L
524 using std::exchange;
525 #else
526
533 template<typename _type, typename _type2 = _type>
534 _type
535 exchange(_type& obj, _type2&& new_val)
536 {
537 _type old_val = std::move(obj);
538
539 obj = yforward(new_val);
540 return old_val;
541 }
542 #endif
543
544 } // inline namespace cpp2014;
545
546 } // namespace ystdex;
547
548 #endif
549
ystdex_swap::iter_swap
void iter_swap(_tFwd1 a, _tFwd1 b)
符合 ISO C++20 要求的 std::iter_swap 替代实现。
Definition: swap.hpp:138
ystdex::pun_storage_t
aligned_storage_t< sizeof(_type), _vAlign > pun_storage_t
显式转换的替代对齐存储对齐存储类型。
Definition: type_pun.hpp:114
ystdex::cpp2017::is_nothrow_swappable
Definition: swap.hpp:77
x
const EncapsulationBase & x
Definition: NPLA1Forms.cpp:1536
ystdex::any_constructible
接受任意参数类型构造的类型。
Definition: meta.hpp:332
yconstexpr
#define yconstexpr
指定编译时常量表达式。
Definition: ydef.h:1072
ystdex::detected_or_t
_t< detected_or< _tDefault, _gOp, _tParams... > > detected_or_t
Definition: meta.hpp:407
ystdex::cpp2017::is_swappable_with
判断是否可以调用 swap 。
Definition: swap.hpp:275
ystdex_swap::dep_swap::helper< _type, _type2, true >::helper
helper()
Definition: swap.hpp:236
ystdex::cpp2014::enable_if_t
typename enable_if< _bCond, _type >::type enable_if_t
Definition: meta.hpp:199
ystdex_swap::dep_swap::swap_t
decltype(swap(std::declval< _type >(), std::declval< _type2 >())) swap_t
Definition: swap.hpp:195
ystdex_swap
Definition: swap.hpp:87
ynoexcept_spec
#define ynoexcept_spec(...)
表达式 noexcept 异常规范。
Definition: ydef.h:1181
ystdex::copy_and_swap
_type & copy_and_swap(_type &obj, const _type2 &new_val)
复制对象并交换。
Definition: swap.hpp:514
yconstfn_relaxed
#define yconstfn_relaxed
指定编译时没有 C++11 限制和隐式成员 const 的常量函数。
Definition: ydef.h:1097
ystdex::swap_dependent
void swap_dependent(_type &x, _type &y)(is_nothrow_swappable< _type >())
支持基于 ystdex_swap::swap 的 ADL 的左值交换。
Definition: swap.hpp:371
ystdex::swap_volatile
void swap_volatile(_type(&x)[_vN], add_volatile_t< _type[_vN]> &y)
Definition: swap.hpp:407
CHRLib::args
YB_ATTR_nodiscard _tParams && args
Definition: CharacterProcessing.h:649
ystdex::bool_
integral_constant< bool, _vInt > bool_
Definition: integral_constant.hpp:93
ystdex::cpp2017::void_t
well_formed_t< void, _types... > void_t
Definition: meta.hpp:292
ystdex::details::_type2
_type2
Definition: operators.hpp:241
ystdex::swap_volatile
enable_if_t< is_nothrow_constructible< _type, volatile _type >) &&is_nothrow_assignable< _type &, volatile _type && >) &&is_nothrow_assignable< volatile _type &, _type && >)> swap_volatile(_type &x, volatile _type &y)
交换非 volatile 左值和 volatile 左值。
Definition: swap.hpp:388
ystdex_swap::dep_swap::helper::helper
helper()
Definition: swap.hpp:223
ystdex::cpp2017::is_swappable
Definition: swap.hpp:74
ystdex::enable_if_swap_movable_t
enable_if_t< is_swap_movable< _tSwapped >::value, _type > enable_if_swap_movable_t
Definition: swap.hpp:66
yforward
#define yforward(_expr)
根据参数类型使用 std::forward 转发对应参数。
Definition: ydef.h:1508
ystdex::create_and_swap
_type & create_and_swap(_type &obj, _tParams &&... args)
创建对象并交换。
Definition: swap.hpp:497
ystdex::swap_underlying
void swap_underlying(_type &x, _type &y)
交换相同标准布局类型可修改左值的存储。
Definition: swap.hpp:443
std
Definition: optional.h:982
YB_ATTR
#define YB_ATTR(...)
GNU 风格属性。
Definition: ydef.h:567
ystdex_swap::dep_swap::well_formed_swap
Definition: swap.hpp:200
ystdex::details::swap_dep_impl::swap_dep
auto swap_dep(_type &x, _type &y, true_) -> decltype(static_cast< void >(swap(x, y)))
Definition: swap.hpp:333
ystdex_swap::swap
enable_if_swap_movable_t< _type > swap(_type &a, _type &b)
符合 ISO C++20 要求的 std::swap 替代实现。
Definition: swap.hpp:118
yunseq
#define yunseq
无序列依赖表达式组求值。
Definition: ydef.h:1535
ystdex::details::swap_volatile_avail
bool_< is_volatile< remove_reference_t< _type > >::value !=is_volatile< remove_reference_t< _type2 > >::value > swap_volatile_avail
Definition: swap.hpp:424
YSLib::UI::y
SPos SPos y
Definition: YWidget.cpp:44
ystdex::true_
bool_< true > true_
Definition: integral_constant.hpp:109
ystdex::nonesuch
不接受任意参数类型构造的类型。
Definition: meta.hpp:343
ystdex::cpp2017::is_nothrow_swappable_with
判断是否可以无抛出地调用 swap 。
Definition: swap.hpp:291
type_pun.hpp
共享存储和直接转换。
ystdex::details::swap_volatile_noexcept
swap_volatile_avail< _type, _type2 > swap_volatile_noexcept
Definition: swap.hpp:432
ystdex_swap::swap_ranges
_tFwd2 swap_ranges(_tFwd1 first1, _tFwd1 last1, _tFwd2 first2)
符合 ISO C++20 要求的 std::swap_ranges 替代实现。
Definition: swap.hpp:153
ystdex::cpp2014::add_volatile_t
typename add_volatile< _type >::type add_volatile_t
Definition: meta.hpp:148
ystdex
<memory> 特性测试宏。
Definition: ydef.h:1262
YSLib::_tParams
YB_ATTR_nodiscard YB_PURE typename _tParams
Definition: ValueNode.h:1294
ystdex_swap::dep_swap::swap
nonesuch swap(any_constructible, any_constructible)
ystdex::addressof
enable_if_t< has_no_overloaded_addressof< _type >::value, _type * > addressof(_type &r)
尝试对非重载 operator& 提供 constexpr 的 std::addressof 替代。
Definition: addressof.hpp:131
ystdex::cpp2014::exchange
_type exchange(_type &obj, _type2 &&new_val)
交换值并返回旧值。
Definition: swap.hpp:535
yimpl
#define yimpl(...)
实现标签。
Definition: ydef.h:413
ystdex::false_
bool_< false > false_
Definition: integral_constant.hpp:110
ynothrow
#define ynothrow
YSLib 无异常抛出保证：若支持 noexcept 关键字， 指定特定的 noexcept 异常规范。
Definition: ydef.h:1199
ystdex::vswap
auto vswap(_type &&x, _type2 &&y) -> enable_if_t< details::swap_volatile_avail< _type, _type2 >::value >
Definition: swap.hpp:472
ynoexcept
#define ynoexcept(...)
YSLib 无异常抛出保证：指定特定的异常规范。
Definition: ydef.h:1151
YSLib::a
YB_PURE const _type * a
Definition: YCoreUtilities.h:168
ystdex::and_< is_move_constructible< _type >, is_move_assignable< _type > >