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 63namespace 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 70template <class F> 71class final_act 72{ 73public: 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 89private: 90 F f_; 91 bool invoke_; 92}; 93 94// finally() - convenience function to generate a final_act 95template <class F> 96inline final_act<F> finally(const F& f) noexcept 97{ 98 return final_act<F>(f); 99} 100 101template <class F> 102inline 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 109template <class T, class U> 110inline constexpr T narrow_cast(U u) noexcept 111{ 112 return static_cast<T>(u); 113} 114#else 115template <class T, class U> 116inline constexpr T narrow_cast(U&& u) noexcept 117{ 118 return static_cast<T>(std::forward<U>(u)); 119} 120#endif 121 122struct narrowing_error : public std::exception 123{ 124}; 125 126namespace 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 136template <class T, class U> 137inline 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// 154template <class T, size_t N> 155constexpr 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 161template <class T, size_t N> 162constexpr 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 168template <class Cont> 169constexpr 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 175template <class T> 176constexpr 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