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.

330 lines
11 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: stlsoft/conversion/union_cast.hpp (originally MLTypCnv.h, ::SynesisStd)
  3. *
  4. * Purpose: A powerful cast operator that limits the danger of
  5. * reinterpret_cast, while avoiding the spurious warnings issued by
  6. * some compilers.
  7. *
  8. * Created: 2nd May 1997
  9. * Updated: 10th August 2009
  10. *
  11. * Home: http://stlsoft.org/
  12. *
  13. * Copyright (c) 1997-2009, Matthew Wilson and Synesis Software
  14. * All rights reserved.
  15. *
  16. * Redistribution and use in source and binary forms, with or without
  17. * modification, are permitted provided that the following conditions are met:
  18. *
  19. * - Redistributions of source code must retain the above copyright notice, this
  20. * list of conditions and the following disclaimer.
  21. * - Redistributions in binary form must reproduce the above copyright notice,
  22. * this list of conditions and the following disclaimer in the documentation
  23. * and/or other materials provided with the distribution.
  24. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  25. * any contributors may be used to endorse or promote products derived from
  26. * this software without specific prior written permission.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  29. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  30. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  31. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  32. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  33. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  34. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  35. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  36. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  37. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  38. * POSSIBILITY OF SUCH DAMAGE.
  39. *
  40. * ////////////////////////////////////////////////////////////////////// */
  41. /** \file stlsoft/conversion/union_cast.hpp
  42. *
  43. * \brief [C++ only] Definition of the stlsoft::union_cast cast
  44. * (\ref group__library__conversion "Conversion" Library).
  45. */
  46. #ifndef STLSOFT_INCL_STLSOFT_CONVERSION_HPP_UNION_CAST
  47. #define STLSOFT_INCL_STLSOFT_CONVERSION_HPP_UNION_CAST
  48. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  49. # define STLSOFT_VER_STLSOFT_CONVERSION_HPP_UNION_CAST_MAJOR 5
  50. # define STLSOFT_VER_STLSOFT_CONVERSION_HPP_UNION_CAST_MINOR 0
  51. # define STLSOFT_VER_STLSOFT_CONVERSION_HPP_UNION_CAST_REVISION 3
  52. # define STLSOFT_VER_STLSOFT_CONVERSION_HPP_UNION_CAST_EDIT 64
  53. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  54. /* /////////////////////////////////////////////////////////////////////////
  55. * Includes
  56. */
  57. #ifndef STLSOFT_INCL_STLSOFT_H_STLSOFT
  58. # include <stlsoft/stlsoft.h>
  59. #endif /* !STLSOFT_INCL_STLSOFT_H_STLSOFT */
  60. #ifndef STLSOFT_INCL_STLSOFT_UTIL_HPP_CONSTRAINTS
  61. # include <stlsoft/util/constraints.hpp>
  62. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_HPP_CONSTRAINTS */
  63. #if defined(STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT)
  64. # ifndef STLSOFT_INCL_STLSOFT_META_HPP_BASE_TYPE_TRAITS
  65. # include <stlsoft/meta/base_type_traits.hpp>
  66. # endif /* !STLSOFT_INCL_STLSOFT_META_HPP_BASE_TYPE_TRAITS */
  67. #endif /* STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT */
  68. /* /////////////////////////////////////////////////////////////////////////
  69. * Namespace
  70. */
  71. #ifndef _STLSOFT_NO_NAMESPACE
  72. namespace stlsoft
  73. {
  74. #endif /* _STLSOFT_NO_NAMESPACE */
  75. /* /////////////////////////////////////////////////////////////////////////
  76. * Classes
  77. */
  78. /** \brief Cast class used by the \link stlsoft::union_cast union_cast\endlink
  79. * cast function.
  80. *
  81. * \ingroup group__library__conversion
  82. *
  83. * This class (union) effects conversion from one type to another, without
  84. * the use of casts.
  85. *
  86. * \param TO The type to cast to
  87. * \param FROM The type to cast from
  88. * \param B_CHECK_ALIGN Determines the default checking behaviour. If 0, no checking on alignment is conducted
  89. *
  90. * \note This technique is non-portable, and you use this class at your own
  91. * risk. Notwithstanding that, the TO and FROM types have to be the same
  92. * size, so the technique is widely usable.
  93. */
  94. template< ss_typename_param_k TO
  95. , ss_typename_param_k FROM
  96. #if defined(STLSOFT_COMPILER_IS_GCC) && \
  97. __GNUC__ < 3
  98. , ss_bool_t B_CHECK_ALIGN /* = true */
  99. #else /* ? compiler */
  100. , ss_bool_t B_CHECK_ALIGN = true
  101. #endif /* compiler */
  102. >
  103. union union_caster
  104. {
  105. /// \name Member Types
  106. /// @{
  107. public:
  108. /// \brief The type to cast to.
  109. typedef TO to_type;
  110. /// \brief The type to cast from.
  111. typedef FROM from_type;
  112. /// \brief The current instantiation of the type.
  113. typedef union_caster<TO, FROM, B_CHECK_ALIGN> class_type;
  114. /// @}
  115. /// \name Construction
  116. /// @{
  117. public:
  118. /// \brief Conversion constructor
  119. ss_explicit_k union_caster(from_type const from, ss_bool_t bCheckAlign = B_CHECK_ALIGN)
  120. : m_from(from)
  121. {
  122. // The body of the constructor constrains the type conversion according
  123. // to the following:
  124. //
  125. // (i) Sizes must be the same
  126. // (ii) Both must be of POD type
  127. // (iii) There must be either a change of const/volatile, or a change
  128. // of type, but not both.
  129. // (iv) Both must be non-pointers, or must point to POD types
  130. #if !defined(STLSOFT_COMPILER_IS_DMC) || \
  131. __DMC__ >= 0x0833
  132. // (i) Sizes must be the same
  133. STLSOFT_STATIC_ASSERT(sizeof(from_type) == sizeof(to_type));
  134. // (ii) Both must be of POD type
  135. stlsoft_constraint_must_be_pod(from_type);
  136. stlsoft_constraint_must_be_pod(to_type);
  137. # if defined(STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT)
  138. // (iii) There must be either a change of const/volatile,
  139. /// or a change of type, but not both.
  140. // STLSOFT_STATIC_ASSERT( (1 == is_same_type<from_type, to_type>::value) ||
  141. // ( base_type_traits<from_type>::is_const == base_type_traits<to_type>::is_const &&
  142. // base_type_traits<from_type>::is_volatile == base_type_traits<to_type>::is_volatile));
  143. // (iv) Both must be non-pointers, or must point to POD types
  144. typedef ss_typename_type_k base_type_traits<from_type>::base_type from_base_type;
  145. typedef ss_typename_type_k base_type_traits<to_type>::base_type to_base_type;
  146. stlsoft_constraint_must_be_pod_or_void(from_base_type);
  147. stlsoft_constraint_must_be_pod_or_void(to_base_type);
  148. if( !base_type_traits<from_type>::is_pointer &&
  149. base_type_traits<to_type>::is_pointer &&
  150. 0 != from)
  151. {
  152. ss_size_t to_size = size_of<to_base_type>::value;
  153. union U
  154. {
  155. ss_size_t size_;
  156. from_type from_;
  157. # if !defined(STLSOFT_COMPILER_IS_MSVC) || \
  158. _MSC_VER < 1310
  159. inline U(from_type from)
  160. : from_(from)
  161. {}
  162. } u_(from); // Can't be anonymous, otherwise GCC has an ICE!
  163. # else /* ? compiler */
  164. } u_;
  165. u_.from_ = from;
  166. # endif /* compiler */
  167. ss_size_t from_value = u_.size_;
  168. STLSOFT_SUPPRESS_UNUSED(to_size);
  169. STLSOFT_SUPPRESS_UNUSED(from_value);
  170. // Need to add to_size, since Metrowerks warns of constant division by zero
  171. STLSOFT_MESSAGE_ASSERT( "Misalignment in conversion from non-pointer to pointer", (!bCheckAlign || (0 == to_size) || (0 == ((from_value + to_size) % to_size))));
  172. }
  173. # endif /* STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT */
  174. #else /* ? compiler */
  175. // Sizes must be the same
  176. STLSOFT_ASSERT(sizeof(from_type) == sizeof(to_type));
  177. #endif /* compiler */
  178. STLSOFT_SUPPRESS_UNUSED(bCheckAlign);
  179. }
  180. /// @}
  181. /// \name Conversion
  182. /// @{
  183. public:
  184. /// Implicit conversion operator
  185. operator to_type () const
  186. {
  187. return m_to;
  188. }
  189. /// @}
  190. /// \name Members
  191. /// @{
  192. private:
  193. from_type const m_from;
  194. to_type m_to;
  195. /// @}
  196. /// \name Not to be implemented
  197. /// @{
  198. private:
  199. class_type& operator =(class_type const&);
  200. /// @}
  201. };
  202. /* /////////////////////////////////////////////////////////////////////////
  203. * Shims
  204. */
  205. #if !defined(STLSOFT_COMPILER_IS_WATCOM)
  206. /** \brief A powerful cast operator that limits the danger of
  207. * reinterpret_cast, while avoiding the spurious warnings issued by some
  208. * compilers.
  209. *
  210. * \ingroup group__library__conversion
  211. *
  212. * A union cast would be applied as follows:
  213. *
  214. \code
  215. // This assumes sizeof(int) == sizeof(short*)
  216. short *ps;
  217. int i = stlsoft::union_cast<int>(ps); // Ok: same size
  218. double d = stlsoft::union_cast<double>(ps); // Compile error: different size
  219. \endcode
  220. */
  221. template< ss_typename_param_k TO
  222. , ss_typename_param_k FROM
  223. >
  224. inline union_caster<TO, FROM, true> union_cast(FROM const from, ss_bool_t bCheckAlign = true)
  225. {
  226. return union_caster<TO, FROM, true>(from, bCheckAlign);
  227. }
  228. /** \brief [DEPRECATED] Synonym for stlsoft::union_cast().
  229. *
  230. * \ingroup group__library__conversion
  231. *
  232. * \deprecated This function is now deprecated in favour of the new function
  233. * \link stlsoft::union_cast union_cast\endlink.
  234. */
  235. template< ss_typename_param_k TO
  236. , ss_typename_param_k FROM
  237. >
  238. inline union_caster<TO, FROM, true> make_union_cast(FROM const from, ss_bool_t bCheckAlign = true)
  239. {
  240. return union_caster<TO, FROM, true>(from, bCheckAlign);
  241. }
  242. #endif /* compiler */
  243. /* /////////////////////////////////////////////////////////////////////////
  244. * Operators
  245. */
  246. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  247. template< ss_typename_param_k TO
  248. , ss_typename_param_k FROM
  249. , ss_bool_t B_CHECK_ALIGN
  250. >
  251. inline ss_bool_t operator < (union_caster<TO, FROM, B_CHECK_ALIGN> const& lhs, TO const& rhs)
  252. {
  253. TO const lhs_ = lhs;
  254. return lhs_ < rhs;
  255. }
  256. template< ss_typename_param_k TO
  257. , ss_typename_param_k FROM
  258. , ss_bool_t B_CHECK_ALIGN
  259. >
  260. inline ss_bool_t operator < (TO const& lhs, union_caster<TO, FROM, B_CHECK_ALIGN> const& rhs)
  261. {
  262. TO const rhs_ = rhs;
  263. return lhs < rhs_;
  264. }
  265. template< ss_typename_param_k TO
  266. , ss_typename_param_k FROM
  267. , ss_bool_t B_CHECK_ALIGN
  268. >
  269. inline ss_bool_t operator < (union_caster<TO, FROM, B_CHECK_ALIGN> const& lhs, union_caster<TO, FROM, B_CHECK_ALIGN> const& rhs)
  270. {
  271. TO const lhs_ = lhs;
  272. TO const rhs_ = rhs;
  273. return lhs_ < rhs_;
  274. }
  275. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  276. ////////////////////////////////////////////////////////////////////////////
  277. // Unit-testing
  278. #ifdef STLSOFT_UNITTEST
  279. # include "./unittest/union_cast_unittest_.h"
  280. #endif /* STLSOFT_UNITTEST */
  281. /* ////////////////////////////////////////////////////////////////////// */
  282. #ifndef _STLSOFT_NO_NAMESPACE
  283. } // namespace stlsoft
  284. #endif /* _STLSOFT_NO_NAMESPACE */
  285. /* ////////////////////////////////////////////////////////////////////// */
  286. #endif /* !STLSOFT_INCL_STLSOFT_CONVERSION_HPP_UNION_CAST */
  287. /* ///////////////////////////// end of file //////////////////////////// */