select_most_precise.hpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
  4. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
  5. // This file was modified by Oracle on 2014-2020.
  6. // Modifications copyright (c) 2014-2020 Oracle and/or its affiliates.
  7. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  8. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
  9. // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
  10. // Use, modification and distribution is subject to the Boost Software License,
  11. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  12. // http://www.boost.org/LICENSE_1_0.txt)
  13. #ifndef BOOST_GEOMETRY_UTIL_SELECT_MOST_PRECISE_HPP
  14. #define BOOST_GEOMETRY_UTIL_SELECT_MOST_PRECISE_HPP
  15. #include <type_traits>
  16. namespace boost { namespace geometry
  17. {
  18. #ifndef DOXYGEN_NO_DETAIL
  19. namespace detail { namespace select_most_precise
  20. {
  21. // 0 - void
  22. // 1 - integral
  23. // 2 - floating point
  24. // 3 - non-fundamental
  25. template <typename T>
  26. struct type_priority
  27. : std::conditional_t
  28. <
  29. std::is_void<T>::value,
  30. std::integral_constant<int, 0>,
  31. std::conditional_t
  32. <
  33. std::is_fundamental<T>::value,
  34. std::conditional_t
  35. <
  36. std::is_floating_point<T>::value,
  37. std::integral_constant<int, 2>,
  38. std::integral_constant<int, 1>
  39. >,
  40. std::integral_constant<int, 3>
  41. >
  42. >
  43. {};
  44. template <typename T>
  45. struct type_size
  46. : std::integral_constant<std::size_t, sizeof(T)>
  47. {};
  48. template <>
  49. struct type_size<void>
  50. : std::integral_constant<std::size_t, 0>
  51. {};
  52. }} // namespace detail::select_most_precise
  53. #endif // DOXYGEN_NO_DETAIL
  54. /*!
  55. \brief Meta-function to select the most accurate type for
  56. calculations
  57. \ingroup utility
  58. \details select_most_precise classes, compares types on compile time.
  59. For example, if an addition must be done with a double and an integer, the
  60. result must be a double.
  61. If both types are integer, the result can be an integer.
  62. \note It is different from the "promote" class, already in boost. That
  63. class promotes e.g. a (one) float to a double. This class selects a
  64. type from two types. It takes the most accurate, but does not promote
  65. afterwards.
  66. \note If the input is a non-fundamental type, it might be a calculation
  67. type such as a GMP-value or another high precision value. Therefore,
  68. if one is non-fundamental, that one is chosen.
  69. \note If both types are non-fundamental, the result is indeterminate and
  70. currently the first one is chosen.
  71. */
  72. template <typename ...Types>
  73. struct select_most_precise
  74. {
  75. typedef void type;
  76. };
  77. template <typename T>
  78. struct select_most_precise<T>
  79. {
  80. typedef T type;
  81. };
  82. template <typename T1, typename T2>
  83. struct select_most_precise<T1, T2>
  84. {
  85. static const int priority1 = detail::select_most_precise::type_priority<T1>::value;
  86. static const int priority2 = detail::select_most_precise::type_priority<T2>::value;
  87. static const std::size_t size1 = detail::select_most_precise::type_size<T1>::value;
  88. static const std::size_t size2 = detail::select_most_precise::type_size<T2>::value;
  89. typedef std::conditional_t
  90. <
  91. (priority1 > priority2),
  92. T1,
  93. std::conditional_t
  94. <
  95. (priority2 > priority1),
  96. T2,
  97. std::conditional_t // priority1 == priority2
  98. <
  99. (priority1 == 0 || priority1 == 3), // both void or non-fundamental
  100. T1,
  101. std::conditional_t // both fundamental
  102. <
  103. (size2 > size1),
  104. T2,
  105. T1
  106. >
  107. >
  108. >
  109. > type;
  110. };
  111. template <typename T1, typename T2, typename ...Types>
  112. struct select_most_precise<T1, T2, Types...>
  113. {
  114. typedef typename select_most_precise
  115. <
  116. typename select_most_precise<T1, T2>::type,
  117. typename select_most_precise<Types...>::type
  118. >::type type;
  119. };
  120. }} // namespace boost::geometry
  121. #endif // BOOST_GEOMETRY_UTIL_SELECT_MOST_PRECISE_HPP