You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

748 line
39KB

  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_COMMON_INCLUDED
  12. #define __WIL_COMMON_INCLUDED
  13. #if defined(_KERNEL_MODE ) && !defined(__WIL_MIN_KERNEL)
  14. // This define indicates that the WIL usage is in a kernel mode context where
  15. // a high degree of WIL functionality is desired.
  16. //
  17. // Use (sparingly) to change behavior based on whether WIL is being used in kernel
  18. // mode or user mode.
  19. #define WIL_KERNEL_MODE
  20. #endif
  21. // Defining WIL_HIDE_DEPRECATED will hide everything deprecated.
  22. // Each wave of deprecation will add a new WIL_HIDE_DEPRECATED_YYMM number that can be used to lock deprecation at
  23. // a particular point, allowing components to avoid backslide and catch up to the current independently.
  24. #ifdef WIL_HIDE_DEPRECATED
  25. #define WIL_HIDE_DEPRECATED_1809
  26. #endif
  27. #ifdef WIL_HIDE_DEPRECATED_1809
  28. #define WIL_HIDE_DEPRECATED_1612
  29. #endif
  30. #ifdef WIL_HIDE_DEPRECATED_1612
  31. #define WIL_HIDE_DEPRECATED_1611
  32. #endif
  33. // Implementation side note: ideally the deprecation would be done with the function-level declspec
  34. // as it allows you to utter the error text when used. The declspec works, but doing it selectively with
  35. // a macro makes intellisense deprecation comments not work. So we just use the #pragma deprecation.
  36. #ifdef WIL_WARN_DEPRECATED
  37. #define WIL_WARN_DEPRECATED_1809
  38. #endif
  39. #ifdef WIL_WARN_DEPRECATED_1809
  40. #define WIL_WARN_DEPRECATED_1612
  41. #endif
  42. #ifdef WIL_WARN_DEPRECATED_1612
  43. #define WIL_WARN_DEPRECATED_1611
  44. #endif
  45. #ifdef WIL_WARN_DEPRECATED_1809
  46. #define WIL_WARN_DEPRECATED_1809_PRAGMA(...) __pragma(deprecated(__VA_ARGS__))
  47. #else
  48. #define WIL_WARN_DEPRECATED_1809_PRAGMA(...)
  49. #endif
  50. #ifdef WIL_WARN_DEPRECATED_1611
  51. #define WIL_WARN_DEPRECATED_1611_PRAGMA(...) __pragma(deprecated(__VA_ARGS__))
  52. #else
  53. #define WIL_WARN_DEPRECATED_1611_PRAGMA(...)
  54. #endif
  55. #ifdef WIL_WARN_DEPRECATED_1612
  56. #define WIL_WARN_DEPRECATED_1612_PRAGMA(...) __pragma(deprecated(__VA_ARGS__))
  57. #else
  58. #define WIL_WARN_DEPRECATED_1612_PRAGMA(...)
  59. #endif
  60. #if defined(_MSVC_LANG)
  61. #define __WI_SUPPRESS_4127_S __pragma(warning(push)) __pragma(warning(disable:4127)) __pragma(warning(disable:26498)) __pragma(warning(disable:4245))
  62. #define __WI_SUPPRESS_4127_E __pragma(warning(pop))
  63. #define __WI_SUPPRESS_NULLPTR_ANALYSIS __pragma(warning(suppress:28285)) __pragma(warning(suppress:6504))
  64. #define __WI_SUPPRESS_NONINIT_ANALYSIS __pragma(warning(suppress:26495))
  65. #define __WI_SUPPRESS_NOEXCEPT_ANALYSIS __pragma(warning(suppress:26439))
  66. #else
  67. #define __WI_SUPPRESS_4127_S
  68. #define __WI_SUPPRESS_4127_E
  69. #define __WI_SUPPRESS_NULLPTR_ANALYSIS
  70. #define __WI_SUPPRESS_NONINIT_ANALYSIS
  71. #define __WI_SUPPRESS_NOEXCEPT_ANALYSIS
  72. #endif
  73. #if !defined(__cplusplus) || defined(__WIL_MIN_KERNEL)
  74. #define WI_ODR_PRAGMA(NAME, TOKEN)
  75. #define WI_NOEXCEPT
  76. #else
  77. #pragma warning(push)
  78. #pragma warning(disable:4714) // __forceinline not honored
  79. // DO NOT add *any* further includes to this file -- there should be no dependencies from its usage
  80. #include <sal.h>
  81. #include "wistd_type_traits.h"
  82. //! This macro inserts ODR violation protection; the macro allows it to be compatible with straight "C" code
  83. #define WI_ODR_PRAGMA(NAME, TOKEN) __pragma(detect_mismatch("ODR_violation_" NAME "_mismatch", TOKEN))
  84. #ifdef WIL_KERNEL_MODE
  85. WI_ODR_PRAGMA("WIL_KERNEL_MODE", "1")
  86. #else
  87. WI_ODR_PRAGMA("WIL_KERNEL_MODE", "0")
  88. #endif
  89. // Some SAL remapping / decoration to better support Doxygen. Macros that look like function calls can
  90. // confuse Doxygen when they are used to decorate a function or variable. We simplify some of these to
  91. // basic macros without the function for common use cases.
  92. /// @cond
  93. #define _Success_return_ _Success_(return)
  94. #define _Success_true_ _Success_(true)
  95. #define __declspec_noinline_ __declspec(noinline)
  96. #define __declspec_selectany_ __declspec(selectany)
  97. /// @endcond
  98. #if defined(_CPPUNWIND) && !defined(WIL_SUPPRESS_EXCEPTIONS)
  99. /** This define is automatically set when exceptions are enabled within wil.
  100. It is automatically defined when your code is compiled with exceptions enabled (via checking for the built-in
  101. _CPPUNWIND flag) unless you explicitly define WIL_SUPPRESS_EXCEPTIONS ahead of including your first wil
  102. header. All exception-based WIL methods and classes are included behind:
  103. ~~~~
  104. #ifdef WIL_ENABLE_EXCEPTIONS
  105. // code
  106. #endif
  107. ~~~~
  108. This enables exception-free code to directly include WIL headers without worrying about exception-based
  109. routines suddenly becoming available. */
  110. #define WIL_ENABLE_EXCEPTIONS
  111. #endif
  112. /// @endcond
  113. /// @cond
  114. #if defined(WIL_EXCEPTION_MODE)
  115. static_assert(WIL_EXCEPTION_MODE <= 2, "Invalid exception mode");
  116. #elif !defined(WIL_LOCK_EXCEPTION_MODE)
  117. #define WIL_EXCEPTION_MODE 0 // default, can link exception-based and non-exception based libraries together
  118. #pragma detect_mismatch("ODR_violation_WIL_EXCEPTION_MODE_mismatch", "0")
  119. #elif defined(WIL_ENABLE_EXCEPTIONS)
  120. #define WIL_EXCEPTION_MODE 1 // new code optimization: ONLY support linking libraries together that have exceptions enabled
  121. #pragma detect_mismatch("ODR_violation_WIL_EXCEPTION_MODE_mismatch", "1")
  122. #else
  123. #define WIL_EXCEPTION_MODE 2 // old code optimization: ONLY support linking libraries that are NOT using exceptions
  124. #pragma detect_mismatch("ODR_violation_WIL_EXCEPTION_MODE_mismatch", "2")
  125. #endif
  126. #if WIL_EXCEPTION_MODE == 1 && !defined(WIL_ENABLE_EXCEPTIONS)
  127. #error Must enable exceptions when WIL_EXCEPTION_MODE == 1
  128. #endif
  129. // block for documentation only
  130. #if defined(WIL_DOXYGEN)
  131. /** This define can be explicitly set to disable exception usage within wil.
  132. Normally this define is never needed as the WIL_ENABLE_EXCEPTIONS macro is enabled automatically by looking
  133. at _CPPUNWIND. If your code compiles with exceptions enabled, but does not want to enable the exception-based
  134. classes and methods from WIL, define this macro ahead of including the first WIL header. */
  135. #define WIL_SUPPRESS_EXCEPTIONS
  136. /** This define can be explicitly set to lock the process exception mode to WIL_ENABLE_EXCEPTIONS.
  137. Locking the exception mode provides optimizations to exception barriers, staging hooks and DLL load costs as it eliminates the need to
  138. do copy-on-write initialization of various function pointers and the necessary indirection that's done within WIL to avoid ODR violations
  139. when linking libraries together with different exception handling semantics. */
  140. #define WIL_LOCK_EXCEPTION_MODE
  141. /** This define explicit sets the exception mode for the process to control optimizations.
  142. Three exception modes are available:
  143. 0) This is the default. This enables a binary to link both exception-based and non-exception based libraries together that
  144. use WIL. This adds overhead to exception barriers, DLL copy on write pages and indirection through function pointers to avoid ODR
  145. violations when linking libraries together with different exception handling semantics.
  146. 1) Prefer this setting when it can be used. This locks the binary to only supporting libraries which were built with exceptions enabled.
  147. 2) This locks the binary to libraries built without exceptions. */
  148. #define WIL_EXCEPTION_MODE
  149. #endif
  150. #if (__cplusplus >= 201703) || (_MSVC_LANG >= 201703)
  151. #define WIL_HAS_CXX_17 1
  152. #else
  153. #define WIL_HAS_CXX_17 0
  154. #endif
  155. // Until we'll have C++17 enabled in our code base, we're falling back to SAL
  156. #define WI_NODISCARD __WI_LIBCPP_NODISCARD_ATTRIBUTE
  157. //! @defgroup macrobuilding Macro Composition
  158. //! The following macros are building blocks primarily intended for authoring other macros.
  159. //! @{
  160. //! Re-state a macro value (indirection for composition)
  161. #define WI_FLATTEN(...) __VA_ARGS__
  162. /// @cond
  163. #define __WI_PASTE_imp(a, b) a##b
  164. /// @endcond
  165. //! This macro is for use in other macros to paste two tokens together, such as a constant and the __LINE__ macro.
  166. #define WI_PASTE(a, b) __WI_PASTE_imp(a, b)
  167. /// @cond
  168. #define __WI_HAS_VA_OPT_IMPL(F, T, ...) T
  169. #define __WI_HAS_VA_OPT_(...) __WI_HAS_VA_OPT_IMPL(__VA_OPT__(0,) 1, 0)
  170. /// @endcond
  171. //! Evaluates to '1' when support for '__VA_OPT__' is available, else '0'
  172. #define WI_HAS_VA_OPT __WI_HAS_VA_OPT_(unused)
  173. /// @cond
  174. #define __WI_ARGS_COUNT1(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27, A28, A29, \
  175. A30, A31, A32, A33, A34, A35, A36, A37, A38, A39, A40, A41, A42, A43, A44, A45, A46, A47, A48, A49, A50, A51, A52, A53, A54, A55, A56, A57, A58, A59, \
  176. A60, A61, A62, A63, A64, A65, A66, A67, A68, A69, A70, A71, A72, A73, A74, A75, A76, A77, A78, A79, A80, A81, A82, A83, A84, A85, A86, A87, A88, A89, \
  177. A90, A91, A92, A93, A94, A95, A96, A97, A98, A99, count, ...) count
  178. #define __WI_ARGS_COUNT0(...) WI_FLATTEN(__WI_ARGS_COUNT1(__VA_ARGS__, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, \
  179. 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \
  180. 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
  181. #define __WI_ARGS_COUNT_PREFIX(...) 0, __VA_ARGS__
  182. /// @endcond
  183. //! This variadic macro returns the number of arguments passed to it (up to 99).
  184. #if WI_HAS_VA_OPT
  185. #define WI_ARGS_COUNT(...) __WI_ARGS_COUNT0(0 __VA_OPT__(, __VA_ARGS__))
  186. #else
  187. #define WI_ARGS_COUNT(...) __WI_ARGS_COUNT0(__WI_ARGS_COUNT_PREFIX(__VA_ARGS__))
  188. #endif
  189. /// @cond
  190. #define __WI_FOR_imp0( fn)
  191. #define __WI_FOR_imp1( fn, arg) fn(arg)
  192. #define __WI_FOR_imp2( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp1(fn, __VA_ARGS__))
  193. #define __WI_FOR_imp3( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp2(fn, __VA_ARGS__))
  194. #define __WI_FOR_imp4( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp3(fn, __VA_ARGS__))
  195. #define __WI_FOR_imp5( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp4(fn, __VA_ARGS__))
  196. #define __WI_FOR_imp6( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp5(fn, __VA_ARGS__))
  197. #define __WI_FOR_imp7( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp6(fn, __VA_ARGS__))
  198. #define __WI_FOR_imp8( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp7(fn, __VA_ARGS__))
  199. #define __WI_FOR_imp9( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp8(fn, __VA_ARGS__))
  200. #define __WI_FOR_imp10(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp9(fn, __VA_ARGS__))
  201. #define __WI_FOR_imp11(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp10(fn, __VA_ARGS__))
  202. #define __WI_FOR_imp12(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp11(fn, __VA_ARGS__))
  203. #define __WI_FOR_imp13(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp12(fn, __VA_ARGS__))
  204. #define __WI_FOR_imp14(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp13(fn, __VA_ARGS__))
  205. #define __WI_FOR_imp15(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp14(fn, __VA_ARGS__))
  206. #define __WI_FOR_imp16(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp15(fn, __VA_ARGS__))
  207. #define __WI_FOR_imp17(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp16(fn, __VA_ARGS__))
  208. #define __WI_FOR_imp18(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp17(fn, __VA_ARGS__))
  209. #define __WI_FOR_imp19(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp18(fn, __VA_ARGS__))
  210. #define __WI_FOR_imp20(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp19(fn, __VA_ARGS__))
  211. #define __WI_FOR_imp21(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp20(fn, __VA_ARGS__))
  212. #define __WI_FOR_imp22(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp21(fn, __VA_ARGS__))
  213. #define __WI_FOR_imp23(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp22(fn, __VA_ARGS__))
  214. #define __WI_FOR_imp24(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp23(fn, __VA_ARGS__))
  215. #define __WI_FOR_imp25(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp24(fn, __VA_ARGS__))
  216. #define __WI_FOR_imp26(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp25(fn, __VA_ARGS__))
  217. #define __WI_FOR_imp27(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp26(fn, __VA_ARGS__))
  218. #define __WI_FOR_imp28(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp27(fn, __VA_ARGS__))
  219. #define __WI_FOR_imp29(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp28(fn, __VA_ARGS__))
  220. #define __WI_FOR_imp30(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp29(fn, __VA_ARGS__))
  221. #define __WI_FOR_imp31(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp30(fn, __VA_ARGS__))
  222. #define __WI_FOR_imp32(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp31(fn, __VA_ARGS__))
  223. #define __WI_FOR_imp33(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp32(fn, __VA_ARGS__))
  224. #define __WI_FOR_imp34(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp33(fn, __VA_ARGS__))
  225. #define __WI_FOR_imp35(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp34(fn, __VA_ARGS__))
  226. #define __WI_FOR_imp36(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp35(fn, __VA_ARGS__))
  227. #define __WI_FOR_imp37(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp36(fn, __VA_ARGS__))
  228. #define __WI_FOR_imp38(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp37(fn, __VA_ARGS__))
  229. #define __WI_FOR_imp39(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp38(fn, __VA_ARGS__))
  230. #define __WI_FOR_imp40(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp39(fn, __VA_ARGS__))
  231. #define __WI_FOR_imp41(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp40(fn, __VA_ARGS__))
  232. #define __WI_FOR_imp42(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp41(fn, __VA_ARGS__))
  233. #define __WI_FOR_imp43(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp42(fn, __VA_ARGS__))
  234. #define __WI_FOR_imp44(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp43(fn, __VA_ARGS__))
  235. #define __WI_FOR_imp45(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp44(fn, __VA_ARGS__))
  236. #define __WI_FOR_imp46(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp45(fn, __VA_ARGS__))
  237. #define __WI_FOR_imp47(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp46(fn, __VA_ARGS__))
  238. #define __WI_FOR_imp48(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp47(fn, __VA_ARGS__))
  239. #define __WI_FOR_imp49(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp48(fn, __VA_ARGS__))
  240. #define __WI_FOR_imp50(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp49(fn, __VA_ARGS__))
  241. #define __WI_FOR_imp51(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp50(fn, __VA_ARGS__))
  242. #define __WI_FOR_imp52(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp51(fn, __VA_ARGS__))
  243. #define __WI_FOR_imp53(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp52(fn, __VA_ARGS__))
  244. #define __WI_FOR_imp54(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp53(fn, __VA_ARGS__))
  245. #define __WI_FOR_imp55(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp54(fn, __VA_ARGS__))
  246. #define __WI_FOR_imp56(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp55(fn, __VA_ARGS__))
  247. #define __WI_FOR_imp57(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp56(fn, __VA_ARGS__))
  248. #define __WI_FOR_imp58(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp57(fn, __VA_ARGS__))
  249. #define __WI_FOR_imp59(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp58(fn, __VA_ARGS__))
  250. #define __WI_FOR_imp60(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp59(fn, __VA_ARGS__))
  251. #define __WI_FOR_imp61(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp60(fn, __VA_ARGS__))
  252. #define __WI_FOR_imp62(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp61(fn, __VA_ARGS__))
  253. #define __WI_FOR_imp63(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp62(fn, __VA_ARGS__))
  254. #define __WI_FOR_imp64(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp63(fn, __VA_ARGS__))
  255. #define __WI_FOR_imp65(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp64(fn, __VA_ARGS__))
  256. #define __WI_FOR_imp66(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp65(fn, __VA_ARGS__))
  257. #define __WI_FOR_imp67(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp66(fn, __VA_ARGS__))
  258. #define __WI_FOR_imp68(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp67(fn, __VA_ARGS__))
  259. #define __WI_FOR_imp69(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp68(fn, __VA_ARGS__))
  260. #define __WI_FOR_imp70(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp69(fn, __VA_ARGS__))
  261. #define __WI_FOR_imp71(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp70(fn, __VA_ARGS__))
  262. #define __WI_FOR_imp72(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp71(fn, __VA_ARGS__))
  263. #define __WI_FOR_imp73(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp72(fn, __VA_ARGS__))
  264. #define __WI_FOR_imp74(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp73(fn, __VA_ARGS__))
  265. #define __WI_FOR_imp75(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp74(fn, __VA_ARGS__))
  266. #define __WI_FOR_imp76(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp75(fn, __VA_ARGS__))
  267. #define __WI_FOR_imp77(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp76(fn, __VA_ARGS__))
  268. #define __WI_FOR_imp78(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp77(fn, __VA_ARGS__))
  269. #define __WI_FOR_imp79(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp78(fn, __VA_ARGS__))
  270. #define __WI_FOR_imp80(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp79(fn, __VA_ARGS__))
  271. #define __WI_FOR_imp81(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp80(fn, __VA_ARGS__))
  272. #define __WI_FOR_imp82(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp81(fn, __VA_ARGS__))
  273. #define __WI_FOR_imp83(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp82(fn, __VA_ARGS__))
  274. #define __WI_FOR_imp84(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp83(fn, __VA_ARGS__))
  275. #define __WI_FOR_imp85(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp84(fn, __VA_ARGS__))
  276. #define __WI_FOR_imp86(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp85(fn, __VA_ARGS__))
  277. #define __WI_FOR_imp87(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp86(fn, __VA_ARGS__))
  278. #define __WI_FOR_imp88(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp87(fn, __VA_ARGS__))
  279. #define __WI_FOR_imp89(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp88(fn, __VA_ARGS__))
  280. #define __WI_FOR_imp90(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp89(fn, __VA_ARGS__))
  281. #define __WI_FOR_imp91(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp90(fn, __VA_ARGS__))
  282. #define __WI_FOR_imp92(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp91(fn, __VA_ARGS__))
  283. #define __WI_FOR_imp93(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp92(fn, __VA_ARGS__))
  284. #define __WI_FOR_imp94(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp93(fn, __VA_ARGS__))
  285. #define __WI_FOR_imp95(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp94(fn, __VA_ARGS__))
  286. #define __WI_FOR_imp96(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp95(fn, __VA_ARGS__))
  287. #define __WI_FOR_imp97(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp96(fn, __VA_ARGS__))
  288. #define __WI_FOR_imp98(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp97(fn, __VA_ARGS__))
  289. #define __WI_FOR_imp99(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp98(fn, __VA_ARGS__))
  290. #define __WI_FOR_imp(n, fnAndArgs) WI_PASTE(__WI_FOR_imp, n) fnAndArgs
  291. /// @endcond
  292. //! Iterates through each of the given arguments invoking the specified macro against each one.
  293. #define WI_FOREACH(fn, ...) __WI_FOR_imp(WI_ARGS_COUNT(__VA_ARGS__), (fn, ##__VA_ARGS__))
  294. //! Dispatches a single macro name to separate macros based on the number of arguments passed to it.
  295. #define WI_MACRO_DISPATCH(name, ...) WI_PASTE(WI_PASTE(name, WI_ARGS_COUNT(__VA_ARGS__)), (__VA_ARGS__))
  296. //! @} // Macro composition helpers
  297. #define __R_ENABLE_IF_IS_CLASS(ptrType) wistd::enable_if_t<wistd::is_class<ptrType>::value, void*> = (void*)0
  298. #define __R_ENABLE_IF_IS_NOT_CLASS(ptrType) wistd::enable_if_t<!wistd::is_class<ptrType>::value, void*> = (void*)0
  299. //! @defgroup bitwise Bitwise Inspection and Manipulation
  300. //! Bitwise helpers to improve readability and reduce the error rate of bitwise operations.
  301. //! Several macros have been constructed to assist with bitwise inspection and manipulation. These macros exist
  302. //! for two primary purposes:
  303. //!
  304. //! 1. To improve the readability of bitwise comparisons and manipulation.
  305. //!
  306. //! The macro names are the more concise, readable form of what's being done and do not require that any flags
  307. //! or variables be specified multiple times for the comparisons.
  308. //!
  309. //! 2. To reduce the error rate associated with bitwise operations.
  310. //!
  311. //! The readability improvements naturally lend themselves to this by cutting down the number of concepts.
  312. //! Using `WI_IsFlagSet(var, MyEnum::Flag)` rather than `((var & MyEnum::Flag) == MyEnum::Flag)` removes the comparison
  313. //! operator and repetition in the flag value.
  314. //!
  315. //! Additionally, these macros separate single flag operations (which tend to be the most common) from multi-flag
  316. //! operations so that compile-time errors are generated for bitwise operations which are likely incorrect,
  317. //! such as: `WI_IsFlagSet(var, MyEnum::None)` or `WI_IsFlagSet(var, MyEnum::ValidMask)`.
  318. //!
  319. //! Note that the single flag helpers should be used when a compile-time constant single flag is being manipulated. These
  320. //! helpers provide compile-time errors on misuse and should be preferred over the multi-flag helpers. The multi-flag helpers
  321. //! should be used when multiple flags are being used simultaneously or when the flag values are not compile-time constants.
  322. //!
  323. //! Common example usage (manipulation of flag variables):
  324. //! ~~~~
  325. //! WI_SetFlag(m_flags, MyFlags::Foo); // Set a single flag in the given variable
  326. //! WI_SetAllFlags(m_flags, MyFlags::Foo | MyFlags::Bar); // Set one or more flags
  327. //! WI_ClearFlagIf(m_flags, MyFlags::Bar, isBarClosed); // Conditionally clear a single flag based upon a bool
  328. //! WI_ClearAllFlags(m_flags, MyFlags::Foo | MyFlags::Bar); // Clear one or more flags from the given variable
  329. //! WI_ToggleFlag(m_flags, MyFlags::Foo); // Toggle (change to the opposite value) a single flag
  330. //! WI_UpdateFlag(m_flags, MyFlags::Bar, isBarClosed); // Sets or Clears a single flag from the given variable based upon a bool value
  331. //! WI_UpdateFlagsInMask(m_flags, flagsMask, newFlagValues); // Sets or Clears the flags in flagsMask to the masked values from newFlagValues
  332. //! ~~~~
  333. //! Common example usage (inspection of flag variables):
  334. //! ~~~~
  335. //! if (WI_IsFlagSet(m_flags, MyFlags::Foo)) // Is a single flag set in the given variable?
  336. //! if (WI_IsAnyFlagSet(m_flags, MyFlags::Foo | MyFlags::Bar)) // Is at least one flag from the given mask set?
  337. //! if (WI_AreAllFlagsClear(m_flags, MyFlags::Foo | MyFlags::Bar)) // Are all flags in the given list clear?
  338. //! if (WI_IsSingleFlagSet(m_flags)) // Is *exactly* one flag set in the given variable?
  339. //! ~~~~
  340. //! @{
  341. //! Returns the unsigned type of the same width and numeric value as the given enum
  342. #define WI_EnumValue(val) static_cast<::wil::integral_from_enum<decltype(val)>>(val)
  343. //! Validates that exactly ONE bit is set in compile-time constant `flag`
  344. #define WI_StaticAssertSingleBitSet(flag) static_cast<decltype(flag)>(::wil::details::verify_single_flag_helper<static_cast<unsigned long long>(WI_EnumValue(flag))>::value)
  345. //! @name Bitwise manipulation macros
  346. //! @{
  347. //! Set zero or more bitflags specified by `flags` in the variable `var`.
  348. #define WI_SetAllFlags(var, flags) ((var) |= (flags))
  349. //! Set a single compile-time constant `flag` in the variable `var`.
  350. #define WI_SetFlag(var, flag) WI_SetAllFlags(var, WI_StaticAssertSingleBitSet(flag))
  351. //! Conditionally sets a single compile-time constant `flag` in the variable `var` only if `condition` is true.
  352. #define WI_SetFlagIf(var, flag, condition) do { if (wil::verify_bool(condition)) { WI_SetFlag(var, flag); } } while ((void)0, 0)
  353. //! Clear zero or more bitflags specified by `flags` from the variable `var`.
  354. #define WI_ClearAllFlags(var, flags) ((var) &= ~(flags))
  355. //! Clear a single compile-time constant `flag` from the variable `var`.
  356. #define WI_ClearFlag(var, flag) WI_ClearAllFlags(var, WI_StaticAssertSingleBitSet(flag))
  357. //! Conditionally clear a single compile-time constant `flag` in the variable `var` only if `condition` is true.
  358. #define WI_ClearFlagIf(var, flag, condition) do { if (wil::verify_bool(condition)) { WI_ClearFlag(var, flag); } } while ((void)0, 0)
  359. //! Changes a single compile-time constant `flag` in the variable `var` to be set if `isFlagSet` is true or cleared if `isFlagSet` is false.
  360. #define WI_UpdateFlag(var, flag, isFlagSet) (wil::verify_bool(isFlagSet) ? WI_SetFlag(var, flag) : WI_ClearFlag(var, flag))
  361. //! Changes only the flags specified by `flagsMask` in the variable `var` to match the corresponding flags in `newFlags`.
  362. #define WI_UpdateFlagsInMask(var, flagsMask, newFlags) wil::details::UpdateFlagsInMaskHelper(var, flagsMask, newFlags)
  363. //! Toggles (XOR the value) of multiple bitflags specified by `flags` in the variable `var`.
  364. #define WI_ToggleAllFlags(var, flags) ((var) ^= (flags))
  365. //! Toggles (XOR the value) of a single compile-time constant `flag` in the variable `var`.
  366. #define WI_ToggleFlag(var, flag) WI_ToggleAllFlags(var, WI_StaticAssertSingleBitSet(flag))
  367. //! @} // bitwise manipulation macros
  368. //! @name Bitwise inspection macros
  369. //! @{
  370. //! Evaluates as true if every bitflag specified in `flags` is set within `val`.
  371. #define WI_AreAllFlagsSet(val, flags) wil::details::AreAllFlagsSetHelper(val, flags)
  372. //! Evaluates as true if one or more bitflags specified in `flags` are set within `val`.
  373. #define WI_IsAnyFlagSet(val, flags) (static_cast<decltype((val) & (flags))>(WI_EnumValue(val) & WI_EnumValue(flags)) != static_cast<decltype((val) & (flags))>(0))
  374. //! Evaluates as true if a single compile-time constant `flag` is set within `val`.
  375. #define WI_IsFlagSet(val, flag) WI_IsAnyFlagSet(val, WI_StaticAssertSingleBitSet(flag))
  376. //! Evaluates as true if every bitflag specified in `flags` is clear within `val`.
  377. #define WI_AreAllFlagsClear(val, flags) (static_cast<decltype((val) & (flags))>(WI_EnumValue(val) & WI_EnumValue(flags)) == static_cast<decltype((val) & (flags))>(0))
  378. //! Evaluates as true if one or more bitflags specified in `flags` are clear within `val`.
  379. #define WI_IsAnyFlagClear(val, flags) (!wil::details::AreAllFlagsSetHelper(val, flags))
  380. //! Evaluates as true if a single compile-time constant `flag` is clear within `val`.
  381. #define WI_IsFlagClear(val, flag) WI_AreAllFlagsClear(val, WI_StaticAssertSingleBitSet(flag))
  382. //! Evaluates as true if exactly one bit (any bit) is set within `val`.
  383. #define WI_IsSingleFlagSet(val) wil::details::IsSingleFlagSetHelper(val)
  384. //! Evaluates as true if exactly one bit from within the specified `mask` is set within `val`.
  385. #define WI_IsSingleFlagSetInMask(val, mask) wil::details::IsSingleFlagSetHelper((val) & (mask))
  386. //! Evaluates as true if exactly one bit (any bit) is set within `val` or if there are no bits set within `val`.
  387. #define WI_IsClearOrSingleFlagSet(val) wil::details::IsClearOrSingleFlagSetHelper(val)
  388. //! Evaluates as true if exactly one bit from within the specified `mask` is set within `val` or if there are no bits from `mask` set within `val`.
  389. #define WI_IsClearOrSingleFlagSetInMask(val, mask) wil::details::IsClearOrSingleFlagSetHelper((val) & (mask))
  390. //! @}
  391. #if defined(WIL_DOXYGEN)
  392. /** This macro provides a C++ header with a guaranteed initialization function.
  393. Normally, were a global object's constructor used for this purpose, the optimizer/linker might throw
  394. the object away if it's unreferenced (which throws away the side-effects that the initialization function
  395. was trying to achieve). Using this macro forces linker inclusion of a variable that's initialized by the
  396. provided function to elide that optimization.
  397. //!
  398. This functionality is primarily provided as a building block for header-based libraries (such as WIL)
  399. to be able to layer additional functionality into other libraries by their mere inclusion. Alternative models
  400. of initialization should be used whenever they are available.
  401. ~~~~
  402. #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
  403. WI_HEADER_INITITALIZATION_FUNCTION(InitializeDesktopFamilyApis, []
  404. {
  405. g_pfnGetModuleName = GetCurrentModuleName;
  406. g_pfnFailFastInLoaderCallout = FailFastInLoaderCallout;
  407. return 1;
  408. });
  409. #endif
  410. ~~~~
  411. The above example is used within WIL to decide whether or not the library containing WIL is allowed to use
  412. desktop APIs. Building this functionality as #IFDEFs within functions would create ODR violations, whereas
  413. doing it with global function pointers and header initialization allows a runtime determination. */
  414. #define WI_HEADER_INITITALIZATION_FUNCTION(name, fn)
  415. #elif defined(_M_IX86)
  416. #define WI_HEADER_INITITALIZATION_FUNCTION(name, fn) \
  417. extern "C" { __declspec(selectany) unsigned char g_header_init_ ## name = static_cast<unsigned char>(fn()); } \
  418. __pragma(comment(linker, "/INCLUDE:_g_header_init_" #name))
  419. #elif defined(_M_IA64) || defined(_M_AMD64) || defined(_M_ARM) || defined(_M_ARM64)
  420. #define WI_HEADER_INITITALIZATION_FUNCTION(name, fn) \
  421. extern "C" { __declspec(selectany) unsigned char g_header_init_ ## name = static_cast<unsigned char>(fn()); } \
  422. __pragma(comment(linker, "/INCLUDE:g_header_init_" #name))
  423. #else
  424. #error linker pragma must include g_header_init variation
  425. #endif
  426. /** All Windows Implementation Library classes and functions are located within the "wil" namespace.
  427. The 'wil' namespace is an intentionally short name as the intent is for code to be able to reference
  428. the namespace directly (example: `wil::srwlock lock;`) without a using statement. Resist adding a using
  429. statement for wil to avoid introducing potential name collisions between wil and other namespaces. */
  430. namespace wil
  431. {
  432. /// @cond
  433. namespace details
  434. {
  435. template <typename T>
  436. class pointer_range
  437. {
  438. public:
  439. pointer_range(T begin_, T end_) : m_begin(begin_), m_end(end_) {}
  440. T begin() const { return m_begin; }
  441. T end() const { return m_end; }
  442. private:
  443. T m_begin;
  444. T m_end;
  445. };
  446. }
  447. /// @endcond
  448. /** Enables using range-based for between a begin and end object pointer.
  449. ~~~~
  450. for (auto& obj : make_range(objPointerBegin, objPointerEnd)) { }
  451. ~~~~ */
  452. template <typename T>
  453. details::pointer_range<T> make_range(T begin, T end)
  454. {
  455. return details::pointer_range<T>(begin, end);
  456. }
  457. /** Enables using range-based for on a range when given the base pointer and the number of objects in the range.
  458. ~~~~
  459. for (auto& obj : make_range(objPointer, objCount)) { }
  460. ~~~~ */
  461. template <typename T>
  462. details::pointer_range<T> make_range(T begin, size_t count)
  463. {
  464. return details::pointer_range<T>(begin, begin + count);
  465. }
  466. //! @defgroup outparam Output Parameters
  467. //! Improve the conciseness of assigning values to optional output parameters.
  468. //! @{
  469. /** Assign the given value to an optional output parameter.
  470. Makes code more concise by removing trivial `if (outParam)` blocks. */
  471. template <typename T>
  472. inline void assign_to_opt_param(_Out_opt_ T *outParam, T val)
  473. {
  474. if (outParam != nullptr)
  475. {
  476. *outParam = val;
  477. }
  478. }
  479. /** Assign NULL to an optional output pointer parameter.
  480. Makes code more concise by removing trivial `if (outParam)` blocks. */
  481. template <typename T>
  482. inline void assign_null_to_opt_param(_Out_opt_ T *outParam)
  483. {
  484. if (outParam != nullptr)
  485. {
  486. *outParam = nullptr;
  487. }
  488. }
  489. //! @} // end output parameter helpers
  490. /** Performs a logical or of the given variadic template parameters allowing indirect compile-time boolean evaluation.
  491. Example usage:
  492. ~~~~
  493. template <unsigned int... Rest>
  494. struct FeatureRequiredBy
  495. {
  496. static const bool enabled = wil::variadic_logical_or<WilFeature<Rest>::enabled...>::value;
  497. };
  498. ~~~~ */
  499. template <bool...> struct variadic_logical_or;
  500. /// @cond
  501. template <> struct variadic_logical_or<> : wistd::false_type { };
  502. template <bool... Rest> struct variadic_logical_or<true, Rest...> : wistd::true_type { };
  503. template <bool... Rest> struct variadic_logical_or<false, Rest...> : variadic_logical_or<Rest...>::type { };
  504. /// @endcond
  505. /// @cond
  506. namespace details
  507. {
  508. template <unsigned long long flag>
  509. struct verify_single_flag_helper
  510. {
  511. static_assert((flag != 0) && ((flag & (flag - 1)) == 0), "Single flag expected, zero or multiple flags found");
  512. static const unsigned long long value = flag;
  513. };
  514. }
  515. /// @endcond
  516. //! @defgroup typesafety Type Validation
  517. //! Helpers to validate variable types to prevent accidental, but allowed type conversions.
  518. //! These helpers are most useful when building macros that accept a particular type. Putting these functions around the types accepted
  519. //! prior to pushing that type through to a function (or using it within the macro) allows the macro to add an additional layer of type
  520. //! safety that would ordinarily be stripped away by C++ implicit conversions. This system is extensively used in the error handling helper
  521. //! macros to validate the types given to various macro parameters.
  522. //! @{
  523. /** Verify that `val` can be evaluated as a logical bool.
  524. Other types will generate an intentional compilation error. Allowed types for a logical bool are bool, BOOL,
  525. boolean, BOOLEAN, and classes with an explicit bool cast.
  526. @param val The logical bool expression
  527. @return A C++ bool representing the evaluation of `val`. */
  528. template <typename T, __R_ENABLE_IF_IS_CLASS(T)>
  529. _Post_satisfies_(return == static_cast<bool>(val))
  530. __forceinline constexpr bool verify_bool(const T& val)
  531. {
  532. return static_cast<bool>(val);
  533. }
  534. template <typename T, __R_ENABLE_IF_IS_NOT_CLASS(T)>
  535. __forceinline constexpr bool verify_bool(T /*val*/)
  536. {
  537. static_assert(!wistd::is_same<T, T>::value, "Wrong Type: bool/BOOL/BOOLEAN/boolean expected");
  538. return false;
  539. }
  540. template <>
  541. _Post_satisfies_(return == val)
  542. __forceinline constexpr bool verify_bool<bool>(bool val)
  543. {
  544. return val;
  545. }
  546. template <>
  547. _Post_satisfies_(return == (val != 0))
  548. __forceinline constexpr bool verify_bool<int>(int val)
  549. {
  550. return (val != 0);
  551. }
  552. template <>
  553. _Post_satisfies_(return == !!val)
  554. __forceinline constexpr bool verify_bool<unsigned char>(unsigned char val)
  555. {
  556. return !!val;
  557. }
  558. /** Verify that `val` is a Win32 BOOL value.
  559. Other types (including other logical bool expressions) will generate an intentional compilation error. Note that this will
  560. accept any `int` value as long as that is the underlying typedef behind `BOOL`.
  561. @param val The Win32 BOOL returning expression
  562. @return A Win32 BOOL representing the evaluation of `val`. */
  563. template <typename T>
  564. _Post_satisfies_(return == val)
  565. __forceinline constexpr int verify_BOOL(T val)
  566. {
  567. // Note: Written in terms of 'int' as BOOL is actually: typedef int BOOL;
  568. static_assert((wistd::is_same<T, int>::value), "Wrong Type: BOOL expected");
  569. return val;
  570. }
  571. /** Verify that `hr` is an HRESULT value.
  572. Other types will generate an intentional compilation error. Note that this will accept any `long` value as that is the
  573. underlying typedef behind HRESULT.
  574. //!
  575. Note that occasionally you might run into an HRESULT which is directly defined with a #define, such as:
  576. ~~~~
  577. #define UIA_E_NOTSUPPORTED 0x80040204
  578. ~~~~
  579. Though this looks like an `HRESULT`, this is actually an `unsigned long` (the hex specification forces this). When
  580. these are encountered and they are NOT in the public SDK (have not yet shipped to the public), then you should change
  581. their definition to match the manner in which `HRESULT` constants are defined in winerror.h:
  582. ~~~~
  583. #define E_NOTIMPL _HRESULT_TYPEDEF_(0x80004001L)
  584. ~~~~
  585. When these are encountered in the public SDK, their type should not be changed and you should use a static_cast
  586. to use this value in a macro that utilizes `verify_hresult`, for example:
  587. ~~~~
  588. RETURN_HR_IF(static_cast<HRESULT>(UIA_E_NOTSUPPORTED), (patternId != UIA_DragPatternId));
  589. ~~~~
  590. @param val The HRESULT returning expression
  591. @return An HRESULT representing the evaluation of `val`. */
  592. template <typename T>
  593. _Post_satisfies_(return == hr)
  594. inline constexpr long verify_hresult(T hr)
  595. {
  596. // Note: Written in terms of 'int' as HRESULT is actually: typedef _Return_type_success_(return >= 0) long HRESULT
  597. static_assert(wistd::is_same<T, long>::value, "Wrong Type: HRESULT expected");
  598. return hr;
  599. }
  600. /// @} // end type validation routines
  601. /// @cond
  602. // Implementation details for macros and helper functions... do not use directly.
  603. namespace details
  604. {
  605. // Use size-specific casts to avoid sign extending numbers -- avoid warning C4310: cast truncates constant value
  606. #define __WI_MAKE_UNSIGNED(val) \
  607. (__pragma(warning(push)) __pragma(warning(disable: 4310 4309)) (sizeof(val) == 1 ? static_cast<unsigned char>(val) : \
  608. sizeof(val) == 2 ? static_cast<unsigned short>(val) : \
  609. sizeof(val) == 4 ? static_cast<unsigned long>(val) : \
  610. static_cast<unsigned long long>(val)) __pragma(warning(pop)))
  611. #define __WI_IS_UNSIGNED_SINGLE_FLAG_SET(val) ((val) && !((val) & ((val) - 1)))
  612. #define __WI_IS_SINGLE_FLAG_SET(val) __WI_IS_UNSIGNED_SINGLE_FLAG_SET(__WI_MAKE_UNSIGNED(val))
  613. template <typename TVal, typename TFlags>
  614. __forceinline constexpr bool AreAllFlagsSetHelper(TVal val, TFlags flags)
  615. {
  616. return ((val & flags) == static_cast<decltype(val & flags)>(flags));
  617. }
  618. template <typename TVal>
  619. __forceinline constexpr bool IsSingleFlagSetHelper(TVal val)
  620. {
  621. return __WI_IS_SINGLE_FLAG_SET(val);
  622. }
  623. template <typename TVal>
  624. __forceinline constexpr bool IsClearOrSingleFlagSetHelper(TVal val)
  625. {
  626. return ((val == static_cast<wistd::remove_reference_t<TVal>>(0)) || IsSingleFlagSetHelper(val));
  627. }
  628. template <typename TVal, typename TMask, typename TFlags>
  629. __forceinline constexpr void UpdateFlagsInMaskHelper(_Inout_ TVal& val, TMask mask, TFlags flags)
  630. {
  631. val = static_cast<wistd::remove_reference_t<TVal>>((val & ~mask) | (flags & mask));
  632. }
  633. template <long>
  634. struct variable_size;
  635. template <>
  636. struct variable_size<1>
  637. {
  638. typedef unsigned char type;
  639. };
  640. template <>
  641. struct variable_size<2>
  642. {
  643. typedef unsigned short type;
  644. };
  645. template <>
  646. struct variable_size<4>
  647. {
  648. typedef unsigned long type;
  649. };
  650. template <>
  651. struct variable_size<8>
  652. {
  653. typedef unsigned long long type;
  654. };
  655. template <typename T>
  656. struct variable_size_mapping
  657. {
  658. typedef typename variable_size<sizeof(T)>::type type;
  659. };
  660. } // details
  661. /// @endcond
  662. /** Defines the unsigned type of the same width (1, 2, 4, or 8 bytes) as the given type.
  663. This allows code to generically convert any enum class to it's corresponding underlying type. */
  664. template <typename T>
  665. using integral_from_enum = typename details::variable_size_mapping<T>::type;
  666. } // wil
  667. #pragma warning(pop)
  668. #endif // __cplusplus
  669. #endif // __WIL_COMMON_INCLUDED