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 #ifndef GSL_UTIL_H
     18 #define GSL_UTIL_H
     19 
     20 #include <gsl/gsl_assert> // for Expects
     21 
     22 #include <array>
     23 #include <cstddef>          // for ptrdiff_t, size_t
     24 #include <exception>        // for exception
     25 #include <initializer_list> // for initializer_list
     26 #include <type_traits>      // for is_signed, integral_constant
     27 #include <utility>          // for forward
     28 
     29 #if defined(_MSC_VER) && !defined(__clang__)
     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 #if (defined(_MSC_VER) && _MSC_VER < 1910) || (!defined(__clang__) && defined(__GNUC__) && __GUNC__ < 6)
     41 #define GSL_CONSTEXPR_NARROW 0
     42 #else
     43 #define GSL_CONSTEXPR_NARROW 1
     44 #endif
     45 
     46 namespace gsl
     47 {
     48 //
     49 // GSL.util: utilities
     50 //
     51 
     52 // index type for all container indexes/subscripts/sizes
     53 using index = std::ptrdiff_t;
     54 
     55 // final_action allows you to ensure something gets run at the end of a scope
     56 template <class F>
     57 class final_action
     58 {
     59 public:
     60     explicit final_action(F f) noexcept : f_(std::move(f)) {}
     61 
     62     final_action(final_action&& other) noexcept : f_(std::move(other.f_)), invoke_(other.invoke_)
     63     {
     64         other.invoke_ = false;
     65     }
     66 
     67     final_action(const final_action&) = delete;
     68     final_action& operator=(const final_action&) = delete;
     69     final_action& operator=(final_action&&) = delete;
     70 
     71     GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // terminate if throws
     72     ~final_action() noexcept
     73     {
     74         if (invoke_) f_();
     75     }
     76 
     77 private:
     78     F f_;
     79     bool invoke_{true};
     80 };
     81 
     82 // finally() - convenience function to generate a final_action
     83 template <class F>
     84 final_action<F> finally(const F& f) noexcept
     85 {
     86     return final_action<F>(f);
     87 }
     88 
     89 template <class F>
     90 final_action<F> finally(F&& f) noexcept
     91 {
     92     return final_action<F>(std::forward<F>(f));
     93 }
     94 
     95 // narrow_cast(): a searchable way to do narrowing casts of values
     96 template <class T, class U>
     97 GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
     98 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 } // namespace details
    115 
    116 // narrow() : a checked version of narrow_cast() that throws if the cast changed the value
    117 template <class T, class U>
    118 GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
    119 GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false)
    120 #if GSL_CONSTEXPR_NARROW
    121 constexpr
    122 #endif
    123 T narrow(U u) noexcept(false)
    124 {
    125     T t = narrow_cast<T>(u);
    126     if (static_cast<U>(t) != u) gsl::details::throw_exception(narrowing_error());
    127     if (!details::is_same_signedness<T, U>::value && ((t < T{}) != (u < U{})))
    128         gsl::details::throw_exception(narrowing_error());
    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 GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
    137 GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
    138 constexpr T& at(T (&arr)[N], const index i)
    139 {
    140     Expects(i >= 0 && i < narrow_cast<index>(N));
    141     return arr[narrow_cast<std::size_t>(i)];
    142 }
    143 
    144 template <class Cont>
    145 GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
    146 GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
    147 constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()])
    148 {
    149     Expects(i >= 0 && i < narrow_cast<index>(cont.size()));
    150     using size_type = decltype(cont.size());
    151     return cont[narrow_cast<size_type>(i)];
    152 }
    153 
    154 template <class T>
    155 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
    156 constexpr T at(const std::initializer_list<T> cont, const index i)
    157 {
    158     Expects(i >= 0 && i < narrow_cast<index>(cont.size()));
    159     return *(cont.begin() + i);
    160 }
    161 
    162 } // namespace gsl
    163 
    164 #if defined(_MSC_VER) && !defined(__clang__)
    165 #if _MSC_VER < 1910
    166 #undef constexpr
    167 #pragma pop_macro("constexpr")
    168 
    169 #endif // _MSC_VER < 1910
    170 
    171 #pragma warning(pop)
    172 
    173 #endif // _MSC_VER
    174 
    175 #endif // GSL_UTIL_H
    176