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 #pragma once 18 19 #ifndef GSL_UTIL_H 20 #define GSL_UTIL_H 21 22 #include <gsl/gsl_assert> // Ensures/Expects 23 24 #include <array> 25 #include <exception> 26 #include <type_traits> 27 #include <utility> 28 29 #if defined(_MSC_VER) 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 // AFAIK there's no way to detect in GCC or MSVC. GCC has an __EXCEPTIONS macro, 41 // but that is only defined if `-fexceptions` is *explicitly* passed on the 42 // command line; defaulting to exceptions enabled will not set this macro. 43 // 44 // Non-Clang users will need to defined GSL_NO_EXCEPTIONS explicitly from the 45 // command line if they are building with exceptions disabled. 46 #if defined(__clang__) && !__has_feature(cxx_exceptions) 47 // If building with -fno-exceptions, we'll fall back to gsl::Ensures in places 48 // where we would have normally thrown an exception. 49 #define GSL_NO_EXCEPTIONS 50 #endif // defined(__has_feature) && !__has_feature(cxx_exceptions) 51 52 namespace gsl 53 { 54 // 55 // GSL.util: utilities 56 // 57 58 // final_act allows you to ensure something gets run at the end of a scope 59 template <class F> 60 class final_act 61 { 62 public: 63 explicit final_act(F f) noexcept : f_(std::move(f)), invoke_(true) {} 64 65 final_act(final_act&& other) noexcept : f_(std::move(other.f_)), invoke_(other.invoke_) 66 { 67 other.invoke_ = false; 68 } 69 70 final_act(const final_act&) = delete; 71 final_act& operator=(const final_act&) = delete; 72 73 ~final_act() noexcept 74 { 75 if (invoke_) f_(); 76 } 77 78 private: 79 F f_; 80 bool invoke_; 81 }; 82 83 // finally() - convenience function to generate a final_act 84 template <class F> 85 inline final_act<F> finally(const F& f) noexcept 86 { 87 return final_act<F>(f); 88 } 89 90 template <class F> 91 inline final_act<F> finally(F&& f) noexcept 92 { 93 return final_act<F>(std::forward<F>(f)); 94 } 95 96 // narrow_cast(): a searchable way to do narrowing casts of values 97 template <class T, class U> 98 inline 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 } 115 116 // narrow() : a checked version of narrow_cast() that throws if the cast changed the value 117 template <class T, class U> 118 inline T narrow(U u) 119 { 120 T t = narrow_cast<T>(u); 121 #ifndef GSL_NO_EXCEPTIONS 122 if (static_cast<U>(t) != u) throw narrowing_error(); 123 if (!details::is_same_signedness<T, U>::value && ((t < T{}) != (u < U{}))) 124 throw narrowing_error(); 125 #else 126 Ensures(static_cast<U>(t) == u); 127 Ensures(!(!details::is_same_signedness<T, U>::value && ((t < T{}) != (u < U{})))); 128 #endif 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 inline constexpr T& at(T (&arr)[N], const std::ptrdiff_t index) 137 { 138 Expects(index >= 0 && index < narrow_cast<std::ptrdiff_t>(N)); 139 return arr[static_cast<std::size_t>(index)]; 140 } 141 142 template <class Cont> 143 inline constexpr auto at(Cont& cont, const std::ptrdiff_t index) -> decltype(cont[cont.size()]) 144 { 145 Expects(index >= 0 && index < narrow_cast<std::ptrdiff_t>(cont.size())); 146 using size_type = decltype(cont.size()); 147 return cont[static_cast<size_type>(index)]; 148 } 149 150 template <class T> 151 inline constexpr T at(const std::initializer_list<T> cont, const std::ptrdiff_t index) 152 { 153 Expects(index >= 0 && index < narrow_cast<std::ptrdiff_t>(cont.size())); 154 return *(cont.begin() + index); 155 } 156 157 } // namespace gsl 158 159 #if defined(_MSC_VER) 160 #if _MSC_VER < 1910 161 #undef constexpr 162 #pragma pop_macro("constexpr") 163 164 #endif // _MSC_VER < 1910 165 166 #pragma warning(pop) 167 168 #endif // _MSC_VER 169 170 #endif // GSL_UTIL_H 171