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 52namespace 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 59template <class F> 60class final_act 61{ 62public: 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 78private: 79 F f_; 80 bool invoke_; 81}; 82 83// finally() - convenience function to generate a final_act 84template <class F> 85inline final_act<F> finally(const F& f) noexcept 86{ 87 return final_act<F>(f); 88} 89 90template <class F> 91inline 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 97template <class T, class U> 98inline constexpr T narrow_cast(U&& u) noexcept 99{ 100 return static_cast<T>(std::forward<U>(u)); 101} 102 103struct narrowing_error : public std::exception 104{ 105}; 106 107namespace 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 117template <class T, class U> 118inline 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// 135template <class T, std::size_t N> 136inline 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 142template <class Cont> 143inline 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 150template <class T> 151inline 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