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/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