The Webview Univeral Flutter package for Appeto SDK.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 
 

370 lignes
19 KiB

  1. //*********************************************************
  2. //
  3. // Copyright (c) Microsoft. All rights reserved.
  4. // This code is licensed under the MIT License.
  5. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
  6. // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  7. // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  8. // PARTICULAR PURPOSE AND NONINFRINGEMENT.
  9. //
  10. //*********************************************************
  11. #ifndef __WIL_SAFECAST_INCLUDED
  12. #define __WIL_SAFECAST_INCLUDED
  13. #include "result_macros.h"
  14. #include <intsafe.h>
  15. #include "wistd_config.h"
  16. #include "wistd_type_traits.h"
  17. namespace wil
  18. {
  19. namespace details
  20. {
  21. // Default error case for undefined conversions in intsafe.h
  22. template<typename OldT, typename NewT> constexpr wistd::nullptr_t intsafe_conversion = nullptr;
  23. // is_known_safe_static_cast_v determines if a conversion is known to be safe or not. Known
  24. // safe conversions can be handled by static_cast, this includes conversions between the same
  25. // type, when the new type is larger than the old type but is not a signed to unsigned
  26. // conversion, and when the two types are the same size and signed/unsigned. All other
  27. // conversions will be assumed to be potentially unsafe, and the conversion must be handled
  28. // by intsafe and checked.
  29. template <typename NewT, typename OldT>
  30. constexpr bool is_known_safe_static_cast_v =
  31. (sizeof(NewT) > sizeof(OldT) && !(wistd::is_signed_v<OldT> && wistd::is_unsigned_v<NewT>)) ||
  32. (sizeof(NewT) == sizeof(OldT) && ((wistd::is_signed_v<NewT> && wistd::is_signed_v<OldT>) || (wistd::is_unsigned_v<NewT> && wistd::is_unsigned_v<OldT>)));
  33. // Helper template to determine that NewT and OldT are both integral types. The safe_cast
  34. // operation only supports conversions between integral types.
  35. template <typename NewT, typename OldT>
  36. constexpr bool both_integral_v = wistd::is_integral<NewT>::value && wistd::is_integral<OldT>::value;
  37. // Note on native wchar_t (__wchar_t):
  38. // Intsafe.h does not currently handle native wchar_t. When compiling with /Zc:wchar_t-, this is fine as wchar_t is
  39. // typedef'd to unsigned short. However, when compiling with /Zc:wchar_t or wchar_t as a native type, the lack of
  40. // support for native wchar_t in intsafe.h becomes an issue. To work around this, we treat native wchar_t as an
  41. // unsigned short when passing it to intsafe.h, because the two on the Windows platform are the same size and
  42. // share the same range according to MSDN. If the cast is to a native wchar_t, the result from intsafe.h is cast
  43. // to a native wchar_t.
  44. // Intsafe does not have a defined conversion for native wchar_t
  45. template <typename NewT, typename OldT>
  46. constexpr bool neither_native_wchar_v = !wistd::is_same<NewT, __wchar_t>::value && !wistd::is_same<OldT, __wchar_t>::value;
  47. // Check to see if the cast is a conversion to native wchar_t
  48. template <typename NewT, typename OldT>
  49. constexpr bool is_cast_to_wchar_v = wistd::is_same<NewT, __wchar_t>::value && !wistd::is_same<OldT, __wchar_t>::value;
  50. // Check to see if the cast is a conversion from native wchar_t
  51. template <typename NewT, typename OldT>
  52. constexpr bool is_cast_from_wchar_v = !wistd::is_same<NewT, __wchar_t>::value && wistd::is_same<OldT, __wchar_t>::value;
  53. // Validate the conversion to be performed has a defined mapping to an intsafe conversion
  54. template <typename NewT, typename OldT>
  55. constexpr bool is_supported_intsafe_cast_v = intsafe_conversion<OldT, NewT> != nullptr;
  56. // True when the conversion is between integral types and can be handled by static_cast
  57. template <typename NewT, typename OldT>
  58. constexpr bool is_supported_safe_static_cast_v = both_integral_v<NewT, OldT> && is_known_safe_static_cast_v<NewT, OldT>;
  59. // True when the conversion is between integral types, does not involve native wchar, has
  60. // a mapped intsafe conversion, and is unsafe.
  61. template <typename NewT, typename OldT>
  62. constexpr bool is_supported_unsafe_cast_no_wchar_v =
  63. both_integral_v<NewT, OldT> &&
  64. !is_known_safe_static_cast_v<NewT, OldT> &&
  65. neither_native_wchar_v<NewT, OldT> &&
  66. is_supported_intsafe_cast_v<NewT, OldT>;
  67. // True when the conversion is between integral types, is a cast to native wchar_t, has
  68. // a mapped intsafe conversion, and is unsafe.
  69. template <typename NewT, typename OldT>
  70. constexpr bool is_supported_unsafe_cast_to_wchar_v =
  71. both_integral_v<NewT, OldT> &&
  72. !is_known_safe_static_cast_v<NewT, OldT> &&
  73. is_cast_to_wchar_v<NewT, OldT> &&
  74. is_supported_intsafe_cast_v<unsigned short, OldT>;
  75. // True when the conversion is between integral types, is a cast from native wchar_t, has
  76. // a mapped intsafe conversion, and is unsafe.
  77. template <typename NewT, typename OldT>
  78. constexpr bool is_supported_unsafe_cast_from_wchar_v =
  79. both_integral_v<NewT, OldT> &&
  80. !is_known_safe_static_cast_v<NewT, OldT> &&
  81. is_cast_from_wchar_v<NewT, OldT> &&
  82. is_supported_intsafe_cast_v<NewT, unsigned short>;
  83. // True when the conversion is supported and unsafe, and may or may not involve
  84. // native wchar_t.
  85. template <typename NewT, typename OldT>
  86. constexpr bool is_supported_unsafe_cast_v =
  87. is_supported_unsafe_cast_no_wchar_v<NewT, OldT> ||
  88. is_supported_unsafe_cast_to_wchar_v<NewT, OldT> ||
  89. is_supported_unsafe_cast_from_wchar_v<NewT, OldT>;
  90. // True when T is any one of the primitive types that the variably sized types are defined as.
  91. template <typename T>
  92. constexpr bool is_potentially_variably_sized_type_v =
  93. wistd::is_same<T, int>::value ||
  94. wistd::is_same<T, unsigned int>::value ||
  95. wistd::is_same<T, long>::value ||
  96. wistd::is_same<T, unsigned long>::value ||
  97. wistd::is_same<T, __int64>::value ||
  98. wistd::is_same<T, unsigned __int64>::value;
  99. // True when either type is potentialy variably sized (e.g. size_t, ptrdiff_t)
  100. template <typename OldT, typename NewT>
  101. constexpr bool is_potentially_variably_sized_cast_v =
  102. is_potentially_variably_sized_type_v<OldT> ||
  103. is_potentially_variably_sized_type_v<NewT>;
  104. // Mappings of all conversions defined in intsafe.h to intsafe_conversion
  105. // Note: Uppercase types (UINT, DWORD, SIZE_T, etc) and architecture dependent types resolve
  106. // to the base types. The base types are used since they do not vary based on architecture.
  107. template<> constexpr auto intsafe_conversion<__int64, char> = LongLongToChar;
  108. template<> constexpr auto intsafe_conversion<__int64, int> = LongLongToInt;
  109. template<> constexpr auto intsafe_conversion<__int64, long> = LongLongToLong;
  110. template<> constexpr auto intsafe_conversion<__int64, short> = LongLongToShort;
  111. template<> constexpr auto intsafe_conversion<__int64, signed char> = LongLongToInt8;
  112. template<> constexpr auto intsafe_conversion<__int64, unsigned __int64> = LongLongToULongLong;
  113. template<> constexpr auto intsafe_conversion<__int64, unsigned char> = LongLongToUChar;
  114. template<> constexpr auto intsafe_conversion<__int64, unsigned int> = LongLongToUInt;
  115. template<> constexpr auto intsafe_conversion<__int64, unsigned long> = LongLongToULong;
  116. template<> constexpr auto intsafe_conversion<__int64, unsigned short> = LongLongToUShort;
  117. template<> constexpr auto intsafe_conversion<int, char> = IntToChar;
  118. template<> constexpr auto intsafe_conversion<int, short> = IntToShort;
  119. template<> constexpr auto intsafe_conversion<int, signed char> = IntToInt8;
  120. template<> constexpr auto intsafe_conversion<int, unsigned __int64> = IntToULongLong;
  121. template<> constexpr auto intsafe_conversion<int, unsigned char> = IntToUChar;
  122. template<> constexpr auto intsafe_conversion<int, unsigned int> = IntToUInt;
  123. template<> constexpr auto intsafe_conversion<int, unsigned long> = IntToULong;
  124. template<> constexpr auto intsafe_conversion<int, unsigned short> = IntToUShort;
  125. template<> constexpr auto intsafe_conversion<long, char> = LongToChar;
  126. template<> constexpr auto intsafe_conversion<long, int> = LongToInt;
  127. template<> constexpr auto intsafe_conversion<long, short> = LongToShort;
  128. template<> constexpr auto intsafe_conversion<long, signed char> = LongToInt8;
  129. template<> constexpr auto intsafe_conversion<long, unsigned __int64> = LongToULongLong;
  130. template<> constexpr auto intsafe_conversion<long, unsigned char> = LongToUChar;
  131. template<> constexpr auto intsafe_conversion<long, unsigned int> = LongToUInt;
  132. template<> constexpr auto intsafe_conversion<long, unsigned long> = LongToULong;
  133. template<> constexpr auto intsafe_conversion<long, unsigned short> = LongToUShort;
  134. template<> constexpr auto intsafe_conversion<short, char> = ShortToChar;
  135. template<> constexpr auto intsafe_conversion<short, signed char> = ShortToInt8;
  136. template<> constexpr auto intsafe_conversion<short, unsigned __int64> = ShortToULongLong;
  137. template<> constexpr auto intsafe_conversion<short, unsigned char> = ShortToUChar;
  138. template<> constexpr auto intsafe_conversion<short, unsigned int> = ShortToUInt;
  139. template<> constexpr auto intsafe_conversion<short, unsigned long> = ShortToULong;
  140. template<> constexpr auto intsafe_conversion<short, unsigned short> = ShortToUShort;
  141. template<> constexpr auto intsafe_conversion<signed char, unsigned __int64> = Int8ToULongLong;
  142. template<> constexpr auto intsafe_conversion<signed char, unsigned char> = Int8ToUChar;
  143. template<> constexpr auto intsafe_conversion<signed char, unsigned int> = Int8ToUInt;
  144. template<> constexpr auto intsafe_conversion<signed char, unsigned long> = Int8ToULong;
  145. template<> constexpr auto intsafe_conversion<signed char, unsigned short> = Int8ToUShort;
  146. template<> constexpr auto intsafe_conversion<unsigned __int64, __int64> = ULongLongToLongLong;
  147. template<> constexpr auto intsafe_conversion<unsigned __int64, char> = ULongLongToChar;
  148. template<> constexpr auto intsafe_conversion<unsigned __int64, int> = ULongLongToInt;
  149. template<> constexpr auto intsafe_conversion<unsigned __int64, long> = ULongLongToLong;
  150. template<> constexpr auto intsafe_conversion<unsigned __int64, short> = ULongLongToShort;
  151. template<> constexpr auto intsafe_conversion<unsigned __int64, signed char> = ULongLongToInt8;
  152. template<> constexpr auto intsafe_conversion<unsigned __int64, unsigned char> = ULongLongToUChar;
  153. template<> constexpr auto intsafe_conversion<unsigned __int64, unsigned int> = ULongLongToUInt;
  154. template<> constexpr auto intsafe_conversion<unsigned __int64, unsigned long> = ULongLongToULong;
  155. template<> constexpr auto intsafe_conversion<unsigned __int64, unsigned short> = ULongLongToUShort;
  156. template<> constexpr auto intsafe_conversion<unsigned char, char> = UInt8ToChar;
  157. template<> constexpr auto intsafe_conversion<unsigned char, signed char> = UIntToInt8;
  158. template<> constexpr auto intsafe_conversion<unsigned int, char> = UIntToChar;
  159. template<> constexpr auto intsafe_conversion<unsigned int, int> = UIntToInt;
  160. template<> constexpr auto intsafe_conversion<unsigned int, long> = UIntToLong;
  161. template<> constexpr auto intsafe_conversion<unsigned int, short> = UIntToShort;
  162. template<> constexpr auto intsafe_conversion<unsigned int, signed char> = UIntToInt8;
  163. template<> constexpr auto intsafe_conversion<unsigned int, unsigned char> = UIntToUChar;
  164. template<> constexpr auto intsafe_conversion<unsigned int, unsigned short> = UIntToUShort;
  165. template<> constexpr auto intsafe_conversion<unsigned long, char> = ULongToChar;
  166. template<> constexpr auto intsafe_conversion<unsigned long, int> = ULongToInt;
  167. template<> constexpr auto intsafe_conversion<unsigned long, long> = ULongToLong;
  168. template<> constexpr auto intsafe_conversion<unsigned long, short> = ULongToShort;
  169. template<> constexpr auto intsafe_conversion<unsigned long, signed char> = ULongToInt8;
  170. template<> constexpr auto intsafe_conversion<unsigned long, unsigned char> = ULongToUChar;
  171. template<> constexpr auto intsafe_conversion<unsigned long, unsigned int> = ULongToUInt;
  172. template<> constexpr auto intsafe_conversion<unsigned long, unsigned short> = ULongToUShort;
  173. template<> constexpr auto intsafe_conversion<unsigned short, char> = UShortToChar;
  174. template<> constexpr auto intsafe_conversion<unsigned short, short> = UShortToShort;
  175. template<> constexpr auto intsafe_conversion<unsigned short, signed char> = UShortToInt8;
  176. template<> constexpr auto intsafe_conversion<unsigned short, unsigned char> = UShortToUChar;
  177. }
  178. // Unsafe conversion where failure results in fail fast.
  179. template <
  180. typename NewT,
  181. typename OldT,
  182. wistd::enable_if_t<details::is_supported_unsafe_cast_no_wchar_v<NewT, OldT>, int> = 0
  183. >
  184. NewT safe_cast_failfast(const OldT var)
  185. {
  186. NewT newVar;
  187. FAIL_FAST_IF_FAILED((details::intsafe_conversion<OldT, NewT>(var, &newVar)));
  188. return newVar;
  189. }
  190. // Unsafe conversion where failure results in fail fast.
  191. template <
  192. typename NewT,
  193. typename OldT,
  194. wistd::enable_if_t<details::is_supported_unsafe_cast_from_wchar_v<NewT, OldT>, int> = 0
  195. >
  196. NewT safe_cast_failfast(const OldT var)
  197. {
  198. NewT newVar;
  199. FAIL_FAST_IF_FAILED((details::intsafe_conversion<unsigned short, NewT>(static_cast<unsigned short>(var), &newVar)));
  200. return newVar;
  201. }
  202. // Unsafe conversion where failure results in fail fast.
  203. template <
  204. typename NewT,
  205. typename OldT,
  206. wistd::enable_if_t<details::is_supported_unsafe_cast_to_wchar_v<NewT, OldT>, int> = 0
  207. >
  208. NewT safe_cast_failfast(const OldT var)
  209. {
  210. unsigned short newVar;
  211. FAIL_FAST_IF_FAILED((details::intsafe_conversion<OldT, unsigned short>(var, &newVar)));
  212. return static_cast<__wchar_t>(newVar);
  213. }
  214. // This conversion is always safe, therefore a static_cast is fine.
  215. template <
  216. typename NewT,
  217. typename OldT,
  218. wistd::enable_if_t<details::is_supported_safe_static_cast_v<NewT, OldT>, int> = 0
  219. >
  220. NewT safe_cast_failfast(const OldT var)
  221. {
  222. return static_cast<NewT>(var);
  223. }
  224. #ifdef WIL_ENABLE_EXCEPTIONS
  225. // Unsafe conversion where failure results in a thrown exception.
  226. template <
  227. typename NewT,
  228. typename OldT,
  229. wistd::enable_if_t<details::is_supported_unsafe_cast_no_wchar_v<NewT, OldT>, int> = 0
  230. >
  231. NewT safe_cast(const OldT var)
  232. {
  233. NewT newVar;
  234. THROW_IF_FAILED((details::intsafe_conversion<OldT, NewT>(var, &newVar)));
  235. return newVar;
  236. }
  237. // Unsafe conversion where failure results in a thrown exception.
  238. template <
  239. typename NewT,
  240. typename OldT,
  241. wistd::enable_if_t<details::is_supported_unsafe_cast_from_wchar_v<NewT, OldT>, int> = 0
  242. >
  243. NewT safe_cast(const OldT var)
  244. {
  245. NewT newVar;
  246. THROW_IF_FAILED((details::intsafe_conversion<unsigned short, NewT>(static_cast<unsigned short>(var), &newVar)));
  247. return newVar;
  248. }
  249. // Unsafe conversion where failure results in a thrown exception.
  250. template <
  251. typename NewT,
  252. typename OldT,
  253. wistd::enable_if_t<details::is_supported_unsafe_cast_to_wchar_v<NewT, OldT>, int> = 0
  254. >
  255. NewT safe_cast(const OldT var)
  256. {
  257. unsigned short newVar;
  258. THROW_IF_FAILED((details::intsafe_conversion<OldT, unsigned short>(var, &newVar)));
  259. return static_cast<__wchar_t>(newVar);
  260. }
  261. // This conversion is always safe, therefore a static_cast is fine.
  262. template <
  263. typename NewT,
  264. typename OldT,
  265. wistd::enable_if_t<details::is_supported_safe_static_cast_v<NewT, OldT>, int> = 0
  266. >
  267. NewT safe_cast(const OldT var)
  268. {
  269. return static_cast<NewT>(var);
  270. }
  271. #endif
  272. // This conversion is unsafe, therefore the two parameter version of safe_cast_nothrow must be used
  273. template <
  274. typename NewT,
  275. typename OldT,
  276. wistd::enable_if_t<details::is_supported_unsafe_cast_v<NewT, OldT>, int> = 0
  277. >
  278. NewT safe_cast_nothrow(const OldT /*var*/)
  279. {
  280. static_assert(!wistd::is_same_v<NewT, NewT>, "This cast has the potential to fail, use the two parameter safe_cast_nothrow instead");
  281. }
  282. // This conversion is always safe, therefore a static_cast is fine.
  283. template <
  284. typename NewT,
  285. typename OldT,
  286. wistd::enable_if_t<details::is_supported_safe_static_cast_v<NewT, OldT>, int> = 0
  287. >
  288. NewT safe_cast_nothrow(const OldT var)
  289. {
  290. return static_cast<NewT>(var);
  291. }
  292. // Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT
  293. template <
  294. typename NewT,
  295. typename OldT,
  296. wistd::enable_if_t<details::is_supported_unsafe_cast_no_wchar_v<NewT, OldT>, int> = 0
  297. >
  298. HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult)
  299. {
  300. return details::intsafe_conversion<OldT, NewT>(var, newTResult);
  301. }
  302. // Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT
  303. template <
  304. typename NewT,
  305. typename OldT,
  306. wistd::enable_if_t<details::is_supported_unsafe_cast_from_wchar_v<NewT, OldT>, int> = 0
  307. >
  308. HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult)
  309. {
  310. return details::intsafe_conversion<unsigned short, NewT>(static_cast<unsigned short>(var), newTResult);
  311. }
  312. // Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT
  313. template <
  314. typename NewT,
  315. typename OldT,
  316. wistd::enable_if_t<details::is_supported_unsafe_cast_to_wchar_v<NewT, OldT>, int> = 0
  317. >
  318. HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult)
  319. {
  320. return details::intsafe_conversion<OldT, unsigned short>(var, reinterpret_cast<unsigned short *>(newTResult));
  321. }
  322. // This conversion is always safe, therefore a static_cast is fine. If it can be determined the conversion
  323. // does not involve a variably sized type, then the compilation will fail and say the single parameter version
  324. // of safe_cast_nothrow should be used instead.
  325. template <
  326. typename NewT,
  327. typename OldT,
  328. wistd::enable_if_t<details::is_supported_safe_static_cast_v<NewT, OldT>, int> = 0
  329. >
  330. HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult)
  331. {
  332. static_assert(details::is_potentially_variably_sized_cast_v<OldT, NewT>, "This cast is always safe; use safe_cast_nothrow<T>(value) to avoid unnecessary error handling.");
  333. *newTResult = static_cast<NewT>(var);
  334. return S_OK;
  335. }
  336. }
  337. #endif // __WIL_SAFECAST_INCLUDED