Home | History | Annotate | Download | only in gsl
      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