gsl_util 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2015 Microsoft Corporation. All rights reserved.
  4. //
  5. // This code is licensed under the MIT License (MIT).
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  8. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  9. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  10. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  11. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  12. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  13. // THE SOFTWARE.
  14. //
  15. ///////////////////////////////////////////////////////////////////////////////
  16. #ifndef GSL_UTIL_H
  17. #define GSL_UTIL_H
  18. #include <gsl/gsl_assert> // for Expects
  19. #include <array>
  20. #include <cstddef> // for ptrdiff_t, size_t
  21. #include <initializer_list> // for initializer_list
  22. #include <type_traits> // for is_signed, integral_constant
  23. #include <utility> // for exchange, forward
  24. #if defined(_MSC_VER) && !defined(__clang__)
  25. #pragma warning(push)
  26. #pragma warning(disable : 4127) // conditional expression is constant
  27. #endif // _MSC_VER
  28. namespace gsl
  29. {
  30. //
  31. // GSL.util: utilities
  32. //
  33. // index type for all container indexes/subscripts/sizes
  34. using index = std::ptrdiff_t;
  35. // final_action allows you to ensure something gets run at the end of a scope
  36. template <class F>
  37. class final_action
  38. {
  39. public:
  40. explicit final_action(F f) noexcept : f_(std::move(f)) {}
  41. final_action(final_action&& other) noexcept : f_(std::move(other.f_)), invoke_(std::exchange(other.invoke_, false)) {}
  42. final_action(const final_action&) = delete;
  43. final_action& operator=(const final_action&) = delete;
  44. final_action& operator=(final_action&&) = delete;
  45. GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // terminate if throws
  46. ~final_action() noexcept
  47. {
  48. if (invoke_) f_();
  49. }
  50. private:
  51. F f_;
  52. bool invoke_{true};
  53. };
  54. // finally() - convenience function to generate a final_action
  55. template <class F>
  56. final_action<F> finally(const F& f) noexcept
  57. {
  58. return final_action<F>(f);
  59. }
  60. template <class F>
  61. final_action<F> finally(F&& f) noexcept
  62. {
  63. return final_action<F>(std::forward<F>(f));
  64. }
  65. // narrow_cast(): a searchable way to do narrowing casts of values
  66. template <class T, class U>
  67. GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
  68. constexpr T narrow_cast(U&& u) noexcept
  69. {
  70. return static_cast<T>(std::forward<U>(u));
  71. }
  72. struct narrowing_error : public std::exception
  73. {
  74. };
  75. namespace details
  76. {
  77. template <class T, class U>
  78. struct is_same_signedness
  79. : public std::integral_constant<bool, std::is_signed<T>::value == std::is_signed<U>::value>
  80. {
  81. };
  82. } // namespace details
  83. // narrow() : a checked version of narrow_cast() that throws if the cast changed the value
  84. template <class T, class U>
  85. GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
  86. GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false)
  87. constexpr
  88. T narrow(U u) noexcept(false)
  89. {
  90. T t = narrow_cast<T>(u);
  91. if (static_cast<U>(t) != u) throw narrowing_error{};
  92. if (!details::is_same_signedness<T, U>::value && ((t < T{}) != (u < U{})))
  93. throw narrowing_error{};
  94. return t;
  95. }
  96. //
  97. // at() - Bounds-checked way of accessing builtin arrays, std::array, std::vector
  98. //
  99. template <class T, std::size_t N>
  100. GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
  101. GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
  102. constexpr T& at(T (&arr)[N], const index i)
  103. {
  104. Expects(i >= 0 && i < narrow_cast<index>(N));
  105. return arr[narrow_cast<std::size_t>(i)];
  106. }
  107. template <class Cont>
  108. GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
  109. GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
  110. constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()])
  111. {
  112. Expects(i >= 0 && i < narrow_cast<index>(cont.size()));
  113. using size_type = decltype(cont.size());
  114. return cont[narrow_cast<size_type>(i)];
  115. }
  116. template <class T>
  117. GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
  118. constexpr T at(const std::initializer_list<T> cont, const index i)
  119. {
  120. Expects(i >= 0 && i < narrow_cast<index>(cont.size()));
  121. return *(cont.begin() + i);
  122. }
  123. } // namespace gsl
  124. #if defined(_MSC_VER) && !defined(__clang__)
  125. #pragma warning(pop)
  126. #endif // _MSC_VER
  127. #endif // GSL_UTIL_H