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 17 #ifndef GSL_UTIL_H 18 #define GSL_UTIL_H 19 20 #include <gsl/gsl_assert> // for Expects 21 22 #include <array> 23 #include <cstddef> // for ptrdiff_t, size_t 24 #include <exception> // for exception 25 #include <initializer_list> // for initializer_list 26 #include <type_traits> // for is_signed, integral_constant 27 #include <utility> // for forward 28 29 #if defined(_MSC_VER) && !defined(__clang__) 30 31 #pragma warning(push) 32 #pragma warning(disable : 4127) // conditional expression is constant 33 34 #if _MSC_VER < 1910 35 #pragma push_macro("constexpr") 36 #define constexpr /*constexpr*/ 37 #endif // _MSC_VER < 1910 38 #endif // _MSC_VER 39 40 #if (defined(_MSC_VER) && _MSC_VER < 1910) || (!defined(__clang__) && defined(__GNUC__) && __GUNC__ < 6) 41 #define GSL_CONSTEXPR_NARROW 0 42 #else 43 #define GSL_CONSTEXPR_NARROW 1 44 #endif 45 46 namespace gsl 47 { 48 // 49 // GSL.util: utilities 50 // 51 52 // index type for all container indexes/subscripts/sizes 53 using index = std::ptrdiff_t; 54 55 // final_action allows you to ensure something gets run at the end of a scope 56 template <class F> 57 class final_action 58 { 59 public: 60 explicit final_action(F f) noexcept : f_(std::move(f)) {} 61 62 final_action(final_action&& other) noexcept : f_(std::move(other.f_)), invoke_(other.invoke_) 63 { 64 other.invoke_ = false; 65 } 66 67 final_action(const final_action&) = delete; 68 final_action& operator=(const final_action&) = delete; 69 final_action& operator=(final_action&&) = delete; 70 71 GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // terminate if throws 72 ~final_action() noexcept 73 { 74 if (invoke_) f_(); 75 } 76 77 private: 78 F f_; 79 bool invoke_{true}; 80 }; 81 82 // finally() - convenience function to generate a final_action 83 template <class F> 84 final_action<F> finally(const F& f) noexcept 85 { 86 return final_action<F>(f); 87 } 88 89 template <class F> 90 final_action<F> finally(F&& f) noexcept 91 { 92 return final_action<F>(std::forward<F>(f)); 93 } 94 95 // narrow_cast(): a searchable way to do narrowing casts of values 96 template <class T, class U> 97 GSL_SUPPRESS(type.1) // NO-FORMAT: attribute 98 constexpr T narrow_cast(U&& u) noexcept 99 { 100 return static_cast<T>(std::forward<U>(u)); 101 } 102 103 struct narrowing_error : public std::exception 104 { 105 }; 106 107 namespace details 108 { 109 template <class T, class U> 110 struct is_same_signedness 111 : public std::integral_constant<bool, std::is_signed<T>::value == std::is_signed<U>::value> 112 { 113 }; 114 } // namespace details 115 116 // narrow() : a checked version of narrow_cast() that throws if the cast changed the value 117 template <class T, class U> 118 GSL_SUPPRESS(type.1) // NO-FORMAT: attribute 119 GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false) 120 #if GSL_CONSTEXPR_NARROW 121 constexpr 122 #endif 123 T narrow(U u) noexcept(false) 124 { 125 T t = narrow_cast<T>(u); 126 if (static_cast<U>(t) != u) gsl::details::throw_exception(narrowing_error()); 127 if (!details::is_same_signedness<T, U>::value && ((t < T{}) != (u < U{}))) 128 gsl::details::throw_exception(narrowing_error()); 129 return t; 130 } 131 132 // 133 // at() - Bounds-checked way of accessing builtin arrays, std::array, std::vector 134 // 135 template <class T, std::size_t N> 136 GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute 137 GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute 138 constexpr T& at(T (&arr)[N], const index i) 139 { 140 Expects(i >= 0 && i < narrow_cast<index>(N)); 141 return arr[narrow_cast<std::size_t>(i)]; 142 } 143 144 template <class Cont> 145 GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute 146 GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute 147 constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()]) 148 { 149 Expects(i >= 0 && i < narrow_cast<index>(cont.size())); 150 using size_type = decltype(cont.size()); 151 return cont[narrow_cast<size_type>(i)]; 152 } 153 154 template <class T> 155 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute 156 constexpr T at(const std::initializer_list<T> cont, const index i) 157 { 158 Expects(i >= 0 && i < narrow_cast<index>(cont.size())); 159 return *(cont.begin() + i); 160 } 161 162 } // namespace gsl 163 164 #if defined(_MSC_VER) && !defined(__clang__) 165 #if _MSC_VER < 1910 166 #undef constexpr 167 #pragma pop_macro("constexpr") 168 169 #endif // _MSC_VER < 1910 170 171 #pragma warning(pop) 172 173 #endif // _MSC_VER 174 175 #endif // GSL_UTIL_H 176