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_assert" // Ensures/Expects 23 #include <array> 24 #include <exception> 25 #include <type_traits> 26 #include <utility> 27 28 #ifdef _MSC_VER 29 30 // No MSVC does constexpr fully yet 31 #pragma push_macro("constexpr") 32 #define constexpr /*constexpr*/ 33 34 #pragma warning(push) 35 #pragma warning(disable : 4127) // conditional expression is constant 36 37 // MSVC 2013 workarounds 38 #if _MSC_VER <= 1800 39 // noexcept is not understood 40 #pragma push_macro("noexcept") 41 #define noexcept /*noexcept*/ 42 43 // turn off some misguided warnings 44 #pragma warning(push) 45 #pragma warning(disable : 4351) // warns about newly introduced aggregate initializer behavior 46 47 #endif // _MSC_VER <= 1800 48 49 #endif // _MSC_VER 50 51 // AFAIK there's no way to detect in GCC or MSVC. GCC has an __EXCEPTIONS macro, 52 // but that is only defined if `-fexceptions` is *explicitly* passed on the 53 // command line; defaulting to exceptions enabled will not set this macro. 54 // 55 // Non-Clang users will need to defined GSL_NO_EXCEPTIONS explicitly from the 56 // command line if they are building with exceptions disabled. 57 #if defined(__clang__) && !__has_feature(cxx_exceptions) 58 // If building with -fno-exceptions, we'll fall back to gsl::Ensures in places 59 // where we would have normally thrown an exception. 60 #define GSL_NO_EXCEPTIONS 61 #endif // defined(__has_feature) && !__has_feature(cxx_exceptions) 62 63 namespace gsl 64 { 65 // 66 // GSL.util: utilities 67 // 68 69 // final_act allows you to ensure something gets run at the end of a scope 70 template <class F> 71 class final_act 72 { 73 public: 74 explicit final_act(F f) noexcept : f_(std::move(f)), invoke_(true) {} 75 76 final_act(final_act&& other) noexcept : f_(std::move(other.f_)), invoke_(other.invoke_) 77 { 78 other.invoke_ = false; 79 } 80 81 final_act(const final_act&) = delete; 82 final_act& operator=(const final_act&) = delete; 83 84 ~final_act() noexcept 85 { 86 if (invoke_) f_(); 87 } 88 89 private: 90 F f_; 91 bool invoke_; 92 }; 93 94 // finally() - convenience function to generate a final_act 95 template <class F> 96 inline final_act<F> finally(const F& f) noexcept 97 { 98 return final_act<F>(f); 99 } 100 101 template <class F> 102 inline final_act<F> finally(F&& f) noexcept 103 { 104 return final_act<F>(std::forward<F>(f)); 105 } 106 107 // narrow_cast(): a searchable way to do narrowing casts of values 108 #if _MSC_VER <= 1800 109 template <class T, class U> 110 inline constexpr T narrow_cast(U u) noexcept 111 { 112 return static_cast<T>(u); 113 } 114 #else 115 template <class T, class U> 116 inline constexpr T narrow_cast(U&& u) noexcept 117 { 118 return static_cast<T>(std::forward<U>(u)); 119 } 120 #endif 121 122 struct narrowing_error : public std::exception 123 { 124 }; 125 126 namespace details 127 { 128 template <class T, class U> 129 struct is_same_signedness 130 : public std::integral_constant<bool, std::is_signed<T>::value == std::is_signed<U>::value> 131 { 132 }; 133 } 134 135 // narrow() : a checked version of narrow_cast() that throws if the cast changed the value 136 template <class T, class U> 137 inline T narrow(U u) 138 { 139 T t = narrow_cast<T>(u); 140 #ifndef GSL_NO_EXCEPTIONS 141 if (static_cast<U>(t) != u) throw narrowing_error(); 142 if (!details::is_same_signedness<T, U>::value && ((t < T{}) != (u < U{}))) 143 throw narrowing_error(); 144 #else 145 Ensures(static_cast<U>(t) == u); 146 Ensures(!(!details::is_same_signedness<T, U>::value && ((t < T{}) != (u < U{})))); 147 #endif 148 return t; 149 } 150 151 // 152 // at() - Bounds-checked way of accessing static arrays, std::array, std::vector 153 // 154 template <class T, size_t N> 155 constexpr T& at(T (&arr)[N], std::ptrdiff_t index) 156 { 157 Expects(index >= 0 && index < narrow_cast<std::ptrdiff_t>(N)); 158 return arr[static_cast<size_t>(index)]; 159 } 160 161 template <class T, size_t N> 162 constexpr T& at(std::array<T, N>& arr, std::ptrdiff_t index) 163 { 164 Expects(index >= 0 && index < narrow_cast<std::ptrdiff_t>(N)); 165 return arr[static_cast<size_t>(index)]; 166 } 167 168 template <class Cont> 169 constexpr typename Cont::value_type& at(Cont& cont, std::ptrdiff_t index) 170 { 171 Expects(index >= 0 && index < narrow_cast<std::ptrdiff_t>(cont.size())); 172 return cont[static_cast<typename Cont::size_type>(index)]; 173 } 174 175 template <class T> 176 constexpr const T& at(std::initializer_list<T> cont, std::ptrdiff_t index) 177 { 178 Expects(index >= 0 && index < narrow_cast<std::ptrdiff_t>(cont.size())); 179 return *(cont.begin() + index); 180 } 181 182 } // namespace gsl 183 184 #ifdef _MSC_VER 185 186 #pragma warning(pop) 187 188 #undef constexpr 189 #pragma pop_macro("constexpr") 190 191 #if _MSC_VER <= 1800 192 193 #undef noexcept 194 #pragma pop_macro("noexcept") 195 196 #pragma warning(pop) 197 198 #endif // _MSC_VER <= 1800 199 200 #endif // _MSC_VER 201 202 #endif // GSL_UTIL_H 203