YSTest: cast.hpp 源文件

YSTest PreAlpha_b900_20201012 The YSLib Test Project

cast.hpp
浏览该文件的文档.
1 /*
2 © 2010-2017, 2019-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_cast_hpp_
29 #define YB_INC_ystdex_cast_hpp_ 1
30
31 #include "type_op.hpp" // for decay_t, is_same,
32 // have_common_nonempty_virtual_base, false_, true_, _t;
33 #include <limits> // for std::numeric_limits;
34 #include "exception.h" // for narrowing_error, std::addressof;
35 #include <typeinfo> // for std::bad_cast;
36 #include "cassert.h" // for yassume, YAssert;
37
39 namespace ystdex
40 {
41
53 template<typename _tSrc, typename _tDst = const decay_t<_tSrc>&&>
55 YB_ATTR_nodiscard yconstfn _tDst
56 qualify(_tSrc&& arg) ynothrow
57 {
58 static_assert(is_same<decay_t<_tSrc>, decay_t<_tDst>>(),
59 "Non-qualification conversion found.");
60
61 return static_cast<_tDst>(arg);
62 }
63
64
66
67
69 template<typename _tDst, typename _tSrc>
70 using is_narrowing_from_floating_to_integer
71 = and_<is_integral<_tDst>, is_floating_point<_tSrc>>;
72
73 template<typename _tDst, typename _tSrc>
74 using is_narrowing_from_floating_to_floating
75 = and_<is_floating_point<_tDst>, is_floating_point<_tSrc>,
76 is_same<common_type_t<_tDst, _tSrc>, _tSrc>>;
77
78 template<typename _tDst, typename _tSrc>
79 using is_narrowing_from_floating
80 = or_<is_narrowing_from_floating_to_integer<_tDst, _tSrc>,
81 is_narrowing_from_floating_to_floating<_tDst, _tSrc>>;
83
84 namespace details
85 {
86
87 template<typename _tDst>
88 struct narrow_test
89 {
90 _tDst i;
91
93 YB_ATTR_nodiscard yconstfn false_
94 get() const ynothrow
95 {
96 return {};
97 }
98 };
99
100 template<typename _tDst, typename _tSrc>
101 YB_ATTR_nodiscard yconstfn auto
102 test_narrow(_tSrc v) ynothrow -> decltype(narrow_test<_tDst>{v}.get())
103 {
104 return narrow_test<_tDst>{v}.get();
105 }
107 template<typename>
108 YB_ATTR_nodiscard yconstfn true_
109 test_narrow(...) ynothrow
110 {
111 return {};
112 }
113
114 } // namespace details;
116
118
119 template<typename _tDst, typename _tSrc>
121 YB_ATTR_nodiscard YB_PURE yconstfn _tDst
122 narrow_cast(_tSrc v) ynothrow
123 {
124 static_assert(is_arithmetic<_tDst>(), "Invalid destination type found.");
125 static_assert(is_arithmetic<_tSrc>(), "Invalid source type found.");
126 static_assert(is_narrowing_from_floating<_tDst, _tSrc>()
127 || details::test_narrow<_tDst>(std::numeric_limits<_tSrc>::max())
128 || details::test_narrow<_tDst>(std::numeric_limits<_tSrc>::min()),
129 "Invalid types found.");
130
131 return static_cast<_tDst>(v);
132 }
133
135 template<typename _tDst, typename _tSrc>
136 YB_ATTR_nodiscard YB_PURE inline _tDst
137 narrow(_tSrc v)
138 {
139 const auto d(narrow_cast<_tDst>(v));
140
141 if(static_cast<_tSrc>(d) == v && ((is_signed<_tDst>()
142 == is_signed<_tSrc>()) || (d < _tDst()) == (v < _tSrc())))
143 return d;
144 throw narrowing_error();
145 }
147
149
150 namespace details
151 {
152
153 template<typename _tDst, typename _tSrc>
154 YB_ATTR_nodiscard YB_PURE yconstfn _tDst
155 not_widen_cast(_tSrc v, true_) ynothrow
156 {
157 return narrow_cast<_tDst>(v);
158 }
159 template<typename _tDst, typename _tSrc>
160 YB_ATTR_nodiscard YB_PURE yconstfn _tDst
161 not_widen_cast(_tSrc v, false_) ynothrow
162 {
163 static_assert(is_arithmetic<_tDst>(), "Invalid destination type found.");
164 static_assert(is_arithmetic<_tSrc>(), "Invalid source type found.");
165 static_assert(std::numeric_limits<_tSrc>::max() == std::numeric_limits<
166 _tDst>::max() || std::numeric_limits<_tSrc>::min()
167 == std::numeric_limits<_tDst>::min(), "Invalid types found.");
168 return v;
169 }
170
171 } // namespace details;
172
177 template<typename _tDst, typename _tSrc>
178 YB_ATTR_nodiscard YB_PURE yconstfn _tDst
179 not_widen_cast(_tSrc v) ynothrow
180 {
181 return details::not_widen_cast<_tDst>(v,
182 bool_<is_narrowing_from_floating<_tDst, _tSrc>()
183 || details::test_narrow<_tDst>(std::numeric_limits<_tSrc>::max())
184 || details::test_narrow<_tDst>(std::numeric_limits<_tSrc>::min())>());
185 }
186
188 template<typename _tDst, typename _tSrc>
189 YB_ATTR_nodiscard YB_PURE inline _tDst
190 not_widen(_tSrc v)
191 {
192 const auto d(not_widen_cast<_tDst>(v));
193
194 if(static_cast<_tSrc>(d) == v && ((is_signed<_tDst>()
195 == is_signed<_tSrc>()) || (d < _tDst()) == (v < _tSrc())))
196 return d;
197 throw narrowing_error();
198 }
200
201
211 template<typename _pDst, class _tSrc>
212 YB_ATTR_nodiscard YB_PURE inline _pDst
213 polymorphic_cast(_tSrc* v)
214 {
215 static_assert(is_polymorphic<_tSrc>(), "Non-polymorphic class found.");
216 static_assert(is_pointer<_pDst>(), "Non-pointer destination found.");
217
218 if(const auto p = dynamic_cast<_pDst>(v))
219 return p;
220 throw std::bad_cast();
221 }
222
236 template<typename _pDst, class _tSrc>
237 YB_ATTR_nodiscard YB_PURE inline _pDst
238 polymorphic_downcast(_tSrc* v) ynothrowv
239 {
240 static_assert(is_polymorphic<_tSrc>(), "Non-polymorphic class found.");
241 static_assert(is_pointer<_pDst>(), "Non-pointer destination found.");
242 static_assert(is_base_of<_tSrc, remove_cv_t<
243 remove_pointer_t<_pDst>>>(), "Wrong destination type found.");
244
245 YAssert(dynamic_cast<_pDst>(v) == v, "Invalid source operand found.");
246 return static_cast<_pDst>(v);
247 }
253 template<typename _rDst, class _tSrc>
254 YB_ATTR_nodiscard YB_PURE yconstfn
255 yimpl(enable_if_t)<is_lvalue_reference<_rDst>::value, _rDst>
256 polymorphic_downcast(_tSrc& v) ynothrowv
257 {
258 return *ystdex::polymorphic_downcast<remove_reference_t<_rDst>*>(
259 std::addressof(v));
260 }
266 template<typename _rDst, class _tSrc>
267 YB_ATTR_nodiscard YB_PURE yconstfn yimpl(enable_if_t)<
268 is_rvalue_reference<_rDst>::value && !is_reference<_tSrc>::value, _rDst>
269 polymorphic_downcast(_tSrc&& v) ynothrowv
270 {
271 return std::move(ystdex::polymorphic_downcast<_rDst&>(v));
272 }
281 template<class _tDst, typename _tSrc, typename _tDeleter>
282 YB_ATTR_nodiscard YB_PURE inline yimpl(enable_if_t)<!is_reference<_tDst>::value
283 && !is_array<_tDst>::value, std::unique_ptr<_tDst, _tDeleter>>
284 polymorphic_downcast(std::unique_ptr<_tSrc, _tDeleter>&& v) ynothrowv
285 {
286 using dst_type = std::unique_ptr<_tDst, _tDeleter>;
287 using pointer = typename dst_type::pointer;
288 auto ptr(v.release());
289 ynoexcept_assert("Invalid cast found.", polymorphic_downcast<pointer>(ptr));
290
291 yassume(bool(ptr));
292 return dst_type(polymorphic_downcast<pointer>(ptr),
293 std::move(v.get_deleter()));
294 }
300 template<class _tDst, typename _tSrc>
301 YB_ATTR_nodiscard YB_PURE inline yimpl(enable_if_t)<!is_reference<_tDst>::value
302 && !is_array<_tDst>::value, std::shared_ptr<_tDst>>
303 polymorphic_downcast(const std::unique_ptr<_tSrc>& v) ynothrowv
304 {
305 YAssert(dynamic_cast<_tDst*>(v.get()) == v.get(),
306 "Invalid source operand found.");
307 return std::static_pointer_cast<_tDst>(v);
308 }
310
312
313
323 template<typename _pDst, class _tSrc>
324 YB_ATTR_nodiscard YB_PURE inline _pDst
325 polymorphic_crosscast(_tSrc* v)
326 {
327 static_assert(is_polymorphic<_tSrc>(), "Non-polymorphic class found.");
328 static_assert(is_pointer<_pDst>(), "Non-pointer destination found.");
329
330 auto p(dynamic_cast<_pDst>(v));
331
332 yassume(p);
333 return p;
334 }
341 template<typename _rDst, class _tSrc>
342 YB_ATTR_nodiscard YB_PURE yconstfn _rDst
343 polymorphic_crosscast(_tSrc& v)
344 {
345 static_assert(is_lvalue_reference<_rDst>(),
346 "Invalid destination type found.");
347
348 return *ystdex::polymorphic_crosscast<remove_reference_t<_rDst>*>(
349 std::addressof(v));
350 }
357 template<typename _rDst, class _tSrc>
358 YB_ATTR_nodiscard YB_PURE yconstfn
359 enable_if_t<!is_reference<_tSrc>::value, _rDst>
360 polymorphic_crosscast(_tSrc&& v)
361 {
362 static_assert(is_rvalue_reference<_rDst>(),
363 "Invalid destination type found.");
364
365 return std::move(ystdex::polymorphic_crosscast<_rDst&>(v));
366 }
368
369
370 namespace details
371 {
372
374
375 template<typename _tFrom, typename _tTo, bool _bNonVirtualDownCast>
376 struct general_polymorphic_cast_helper
377 {
378 YB_ATTR_nodiscard YB_PURE static yconstfn _tTo
379 cast(_tFrom v)
380 {
381 return ystdex::polymorphic_downcast<_tTo>(v);
382 }
383 };
384
385 template<typename _tFrom, typename _tTo>
386 struct general_polymorphic_cast_helper<_tFrom, _tTo, false>
387 {
388 YB_ATTR_nodiscard YB_PURE static yconstfn _tTo
389 cast(_tFrom v)
390 {
391 return dynamic_cast<_tTo>(v);
392 }
393 };
394
395
396 template<typename _tFrom, typename _tTo, bool _bUseStaticCast>
397 struct general_cast_helper
398 {
399 static yconstfn _tTo
400 cast(_tFrom v)
401 {
402 return _tTo(v);
403 }
404 };
405
406 template<typename _tFrom, typename _tTo>
407 struct general_cast_helper<_tFrom, _tTo, false>
408 {
409 static yconstfn _tTo
410 cast(_tFrom v)
411 {
412 return general_polymorphic_cast_helper<_tFrom, _tTo, and_<is_base_of<
413 _tFrom, _tTo>, not_<have_common_nonempty_virtual_base<
414 _t<remove_rp<_tFrom>>, _t<remove_rp<_tTo>>>>>::value>::cast(v);
415 }
416 };
417
418 template<typename _type>
419 struct general_cast_helper<_type, _type, true>
420 {
421 static _type
422 cast(_type v)
423 {
424 return v;
425 }
426 };
427
428 template<typename _type>
429 struct general_cast_helper<_type, _type, false>
430 {
431 static yconstfn _type
432 cast(_type v)
433 {
434 return v;
435 }
436 };
437
438 template<typename _tFrom, typename _tTo>
439 struct general_cast_type_helper : is_convertible<_tFrom, _tTo>
440 {};
442
443 } // namespace details;
444
457 template<typename _tDst, typename _tSrc>
458 yconstfn _tDst
459 general_cast(_tSrc* v)
460 {
461 return details::general_cast_helper<_tSrc*, _tDst,
462 details::general_cast_type_helper<_tSrc*, _tDst>::value>::cast(v);
463 }
464 template<typename _tDst, typename _tSrc>
465 yconstfn _tDst
466 general_cast(_tSrc& v)
467 {
468 return details::general_cast_helper<_tSrc&, _tDst,
469 details::general_cast_type_helper<_tSrc&, _tDst>::value>::cast(v);
470 }
471 template<typename _tDst, typename _tSrc>
472 yconstfn const _tDst
473 general_cast(const _tSrc& v)
474 {
475 return details::general_cast_helper<const _tSrc&, _tDst, details
476 ::general_cast_type_helper<const _tSrc&, const _tDst>::value>::cast(v);
477 }
479
480
481 } // namespace ystdex;
482
483 #endif
484
ystdex::details::not_widen_cast
_tDst not_widen_cast(_tSrc v, true_)
Definition: cast.hpp:155
ystdex::details::general_cast_helper< _tFrom, _tTo, false >::cast
static _tTo cast(_tFrom v)
Definition: cast.hpp:410
YB_ATTR_nodiscard
#define YB_ATTR_nodiscard
标记返回值不被忽略的属性。
Definition: ydef.h:715
ystdex::narrow_cast
_tDst narrow_cast(_tSrc v)
可能缩小数值范围的显式转换。
Definition: cast.hpp:122
YB_PURE
#define YB_PURE
指示函数或函数模板实例为纯函数。
Definition: ydef.h:919
ystdex::details::narrow_test::get
false_ get() const
Definition: cast.hpp:94
ystdex::general_cast
_tDst general_cast(_tSrc *v)
一般类型转换。
Definition: cast.hpp:459
ystdex::cpp2014::min
const _type & min(const _type &a, const _type &b, _fComp comp=less< _type >())
取较小的元素。
Definition: algorithm.hpp:614
ystdex::narrow
_tDst narrow(_tSrc v)
Definition: cast.hpp:137
ynoexcept_assert
#define ynoexcept_assert(_msg,...)
表达式 noexcept 静态断言。
Definition: ydef.h:1152
ystdex::cpp2014::enable_if_t
typename enable_if< _bCond, _type >::type enable_if_t
Definition: meta.hpp:199
ystdex::details::general_cast_helper::cast
static _tTo cast(_tFrom v)
Definition: cast.hpp:400
ystdex::polymorphic_cast
_pDst polymorphic_cast(_tSrc *v)
多态类指针类型转换。
Definition: cast.hpp:213
CHRLib::d
_tDst * d
Definition: CharacterProcessing.h:142
ystdex::cpp2014::remove_pointer_t
typename remove_pointer< _type >::type remove_pointer_t
Definition: meta.hpp:179
ystdex::polymorphic_downcast
_pDst polymorphic_downcast(_tSrc *v)
多态类指针向派生类指针转换。
Definition: cast.hpp:238
ystdex::cpp2014::max
const _type & max(const _type &a, const _type &b, _fComp comp=less< _type >())
取较大的元素。
Definition: algorithm.hpp:635
ystdex::details::general_polymorphic_cast_helper::cast
static _tTo cast(_tFrom v)
Definition: cast.hpp:379
ystdex::details::have_common_nonempty_virtual_base
Definition: type_op.hpp:103
ystdex::details::general_cast_type_helper
Definition: cast.hpp:440
ystdex::details::general_polymorphic_cast_helper< _tFrom, _tTo, false >::cast
static _tTo cast(_tFrom v)
Definition: cast.hpp:389
ystdex::details::narrow_test::i
_tDst i
Definition: cast.hpp:90
YAssert
#define YAssert(_expr, _msg)
Definition: cassert.h:154
ystdex::details::general_cast_helper< _type, _type, true >::cast
static _type cast(_type v)
Definition: cast.hpp:422
ystdex::details::test_narrow
auto test_narrow(_tSrc v) -> decltype(narrow_test< _tDst >
Definition: cast.hpp:102
ystdex::bool_
integral_constant< bool, _vInt > bool_
Definition: integral_constant.hpp:93
yassume
#define yassume(_expr)
假定：环境语义。
Definition: cassert.h:96
ystdex::cpp2014::decay_t
typename decay< _type >::type decay_t
Definition: meta.hpp:196
ystdex::not_widen_cast
_tDst not_widen_cast(_tSrc v)
可能缩小数值范围或数值范围最大和最小值保持不变的转换。
Definition: cast.hpp:179
ystdex::or_
逻辑或。
Definition: integral_constant.hpp:172
ystdex::polymorphic_crosscast
_pDst polymorphic_crosscast(_tSrc *v)
多态类指针交叉转换。
Definition: cast.hpp:325
ystdex::not_widen
_tDst not_widen(_tSrc v)
Definition: cast.hpp:190
type_op.hpp
C++ 类型操作。
ystdex::cpp2014::remove_cv_t
typename remove_cv< _type >::type remove_cv_t
Definition: meta.hpp:142
ystdex::true_
bool_< true > true_
Definition: integral_constant.hpp:109
exception.h
标准库异常扩展接口。
ystdex::details::general_polymorphic_cast_helper
Definition: cast.hpp:377
ystdex::details::general_cast_helper< _type, _type, false >::cast
static _type cast(_type v)
Definition: cast.hpp:432
v
byte v
Definition: CharRenderer.cpp:76
ynothrowv
#define ynothrowv
YSLib 无异常抛出保证验证：有条件地使用无异常抛出规范。
Definition: ydef.h:1219
ystdex
<memory> 特性测试宏。
Definition: ydef.h:1262
ystdex::addressof
enable_if_t< has_no_overloaded_addressof< _type >::value, _type * > addressof(_type &r)
尝试对非重载 operator& 提供 constexpr 的 std::addressof 替代。
Definition: addressof.hpp:131
ystdex::_t
typename _type::type _t
嵌套类型别名。
Definition: meta.hpp:45
ystdex::details::general_cast_helper
Definition: cast.hpp:398
platform::p
return p p
Definition: YCLib/FileSystem.h:209
ystdex::qualify
_tDst qualify(_tSrc &&arg)
允许添加限定符转换。
Definition: cast.hpp:56
const
const Decapsulate const Decapsulate &y ynothrow ContextNode &ctx const
Definition: NPLA1Forms.cpp:1629
yimpl
#define yimpl(...)
实现标签。
Definition: ydef.h:413
cassert.h
ISO C 断言/调试跟踪扩展。
ystdex::not_
逻辑非。
Definition: integral_constant.hpp:193
ystdex::false_
bool_< false > false_
Definition: integral_constant.hpp:110
ynothrow
#define ynothrow
YSLib 无异常抛出保证：若支持 noexcept 关键字， 指定特定的 noexcept 异常规范。
Definition: ydef.h:1199
ystdex::details::narrow_test
Definition: cast.hpp:89
ystdex::narrowing_error
异常：无法表示数值范围的转换。
Definition: ystdex/exception.h:157
yconstfn
#define yconstfn
指定编译时常量函数。
Definition: ydef.h:1073
ystdex::and_
逻辑操作元函数。
Definition: integral_constant.hpp:151