Skip to content
multi_span 78.2 KiB
Newer Older
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
///////////////////////////////////////////////////////////////////////////////

#pragma once

#ifndef GSL_MULTI_SPAN_H
#define GSL_MULTI_SPAN_H

#include "gsl_assert"
#include "gsl_byte"
#include "gsl_util"
#include <algorithm>
#include <array>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <iterator>
#include <limits>
#include <new>
#include <numeric>
#include <stdexcept>
#include <type_traits>
#include <utility>

#ifdef _MSC_VER

// turn off some warnings that are noisy about our Expects statements
#pragma warning(push)
#pragma warning(disable : 4127) // conditional expression is constant

// No MSVC does constexpr fully yet
#pragma push_macro("constexpr")
#define constexpr /*constexpr*/

// VS 2013 workarounds
#if _MSC_VER <= 1800

#define GSL_MSVC_HAS_VARIADIC_CTOR_BUG
#define GSL_MSVC_NO_SUPPORT_FOR_MOVE_CTOR_DEFAULT

// noexcept is not understood
#ifndef GSL_THROW_ON_CONTRACT_VIOLATION
#pragma push_macro("noexcept")
#define noexcept /*noexcept*/
#endif

// turn off some misguided warnings
#pragma warning(push)
#pragma warning(disable : 4351) // warns about newly introduced aggregate initializer behavior
#pragma warning(disable : 4512) // warns that assignment op could not be generated

#endif // _MSC_VER <= 1800

#endif // _MSC_VER

#ifdef GSL_THROW_ON_CONTRACT_VIOLATION

#ifdef _MSC_VER
#pragma push_macro("noexcept")
#endif

#define noexcept /*noexcept*/

#endif // GSL_THROW_ON_CONTRACT_VIOLATION

namespace gsl
{

/*
** begin definitions of index and bounds
*/
namespace details
{
    template <typename SizeType>
    struct SizeTypeTraits
    {
        static const SizeType max_value = std::numeric_limits<SizeType>::max();
    };

    template <typename... Ts>
    class are_integral : public std::integral_constant<bool, true>
    {
    };

    template <typename T, typename... Ts>
    class are_integral<T, Ts...>
        : public std::integral_constant<bool,
                                        std::is_integral<T>::value && are_integral<Ts...>::value>
    {
    };
}

template <size_t Rank>
class index final
{
    static_assert(Rank > 0, "Rank must be greater than 0!");

    template <size_t OtherRank>
    friend class index;

public:
    static const size_t rank = Rank;
    using value_type = std::ptrdiff_t;
    using size_type = value_type;
    using reference = std::add_lvalue_reference_t<value_type>;
    using const_reference = std::add_lvalue_reference_t<std::add_const_t<value_type>>;

    constexpr index() noexcept {}

    constexpr index(const value_type (&values)[Rank]) noexcept
    {
        std::copy(values, values + Rank, elems);
    }

#ifdef GSL_MSVC_HAS_VARIADIC_CTOR_BUG
    template <
        typename T, typename... Ts,
        typename = std::enable_if_t<((sizeof...(Ts) + 1) == Rank) && std::is_integral<T>::value &&
                                    details::are_integral<Ts...>::value>>
    constexpr index(T t, Ts... ds)
        : index({narrow_cast<value_type>(t), narrow_cast<value_type>(ds)...})
    {
    }
#else
    template <typename... Ts, typename = std::enable_if_t<(sizeof...(Ts) == Rank) &&
                                                          details::are_integral<Ts...>::value>>
    constexpr index(Ts... ds) noexcept : elems{narrow_cast<value_type>(ds)...}
    {
    }
#endif

    constexpr index(const index& other) noexcept = default;

    constexpr index& operator=(const index& rhs) noexcept = default;

    // Preconditions: component_idx < rank
    constexpr reference operator[](size_t component_idx)
    {
        Expects(component_idx < Rank); // Component index must be less than rank
        return elems[component_idx];
    }

    // Preconditions: component_idx < rank
    constexpr const_reference operator[](size_t component_idx) const noexcept
    {
        Expects(component_idx < Rank); // Component index must be less than rank
        return elems[component_idx];
    }

    constexpr bool operator==(const index& rhs) const noexcept
    {
        return std::equal(elems, elems + rank, rhs.elems);
    }

    constexpr bool operator!=(const index& rhs) const noexcept { return !(this == rhs); }

    constexpr index operator+() const noexcept { return *this; }

    constexpr index operator-() const noexcept
    {
        index ret = *this;
        std::transform(ret, ret + rank, ret, std::negate<value_type>{});
        return ret;
    }

    constexpr index operator+(const index& rhs) const noexcept
    {
        index ret = *this;
        ret += rhs;
        return ret;
    }

    constexpr index operator-(const index& rhs) const noexcept
    {
        index ret = *this;
        ret -= rhs;
        return ret;
    }

    constexpr index& operator+=(const index& rhs) noexcept
    {
        std::transform(elems, elems + rank, rhs.elems, elems, std::plus<value_type>{});
        return *this;
    }

    constexpr index& operator-=(const index& rhs) noexcept
Loading full blame...