Reworked span to match GSL design.
diff --git a/include/span.h b/include/span.h
index 0c67d22..4f0de0b 100644
--- a/include/span.h
+++ b/include/span.h
@@ -1,17 +1,17 @@
-/////////////////////////////////////////////////////////////////////////////// 
-// 
-// 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. 
-// 
+///////////////////////////////////////////////////////////////////////////////
+//
+// 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
@@ -19,8 +19,11 @@
 #ifndef GSL_SPAN_H
 #define GSL_SPAN_H
 
+#include "gsl_assert.h"
+#include "gsl_util.h"
 #include <algorithm>
 #include <array>
+#include <cassert>
 #include <cstddef>
 #include <cstdint>
 #include <functional>
@@ -31,14 +34,12 @@
 #include <stdexcept>
 #include <type_traits>
 #include <utility>
-#include <cassert>
-#include "gsl_assert.h"
 
 #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
+#pragma warning(disable : 4127) // conditional expression is constant
 
 // No MSVC does constexpr fully yet
 #pragma push_macro("constexpr")
@@ -47,19 +48,19 @@
 // VS 2013 workarounds
 #if _MSC_VER <= 1800
 
-// needed in span.h
-#define GSL_MSVC_HAS_VARIADIC_CTOR_BUG 
+#define GSL_MSVC_HAS_VARIADIC_CTOR_BUG
+#define GSL_MSVC_NO_SUPPORT_FOR_MOVE_CTOR_DEFAULT
 
-// noexcept is not understood 
+// noexcept is not understood
 #ifndef GSL_THROWS_ON_CONTRACT_VIOLATION
 #pragma push_macro("noexcept")
-#define noexcept /* nothing */ 
+#define noexcept /* nothing */
 #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
+#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
 
@@ -71,12 +72,12 @@
 #pragma push_macro("noexcept")
 #endif
 
-#define noexcept /* nothing */ 
+#define noexcept /* nothing */
 
-#endif // GSL_THROW_ON_CONTRACT_VIOLATION 
+#endif // GSL_THROW_ON_CONTRACT_VIOLATION
 
-
-namespace gsl {
+namespace gsl
+{
 
 /*
 ** begin definitions of index and bounds
@@ -89,12 +90,17 @@
         static const SizeType max_value = std::numeric_limits<SizeType>::max();
     };
 
+    template <typename... Ts>
+    class are_integral : public std::integral_constant<bool, true>
+    {
+    };
 
-    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 <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>
@@ -112,26 +118,28 @@
     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() noexcept {}
 
-    constexpr index(const value_type(&values)[Rank]) 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({ static_cast<value_type>(t), static_cast<value_type>(ds)... })
-    {}
+    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{ static_cast<value_type>(ds)... }
-    {}
+    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;
@@ -157,15 +165,9 @@
         return std::equal(elems, elems + rank, rhs.elems);
     }
 
-    constexpr bool operator!=(const index& rhs) const noexcept
-    {
-        return !(this == rhs);
-    }
+    constexpr bool operator!=(const index& rhs) const noexcept { return !(this == rhs); }
 
-    constexpr index operator+() const noexcept
-    {
-        return *this;
-    }
+    constexpr index operator+() const noexcept { return *this; }
 
     constexpr index operator-() const noexcept
     {
@@ -221,13 +223,15 @@
 
     constexpr index& operator*=(value_type v) noexcept
     {
-        std::transform(elems, elems + rank, elems, [v](value_type x) { return std::multiplies<value_type>{}(x, v); });
+        std::transform(elems, elems + rank, elems,
+                       [v](value_type x) { return std::multiplies<value_type>{}(x, v); });
         return *this;
     }
 
     constexpr index& operator/=(value_type v) noexcept
     {
-        std::transform(elems, elems + rank, elems, [v](value_type x) { return std::divides<value_type>{}(x, v); });
+        std::transform(elems, elems + rank, elems,
+                       [v](value_type x) { return std::divides<value_type>{}(x, v); });
         return *this;
     }
 
@@ -242,31 +246,30 @@
     template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
     constexpr operator T() const noexcept
     {
-        return static_cast<T>(-1);
+        return narrow_cast<T>(-1);
     }
 
     template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
-    constexpr bool operator ==(T other) const noexcept
+    constexpr bool operator==(T other) const noexcept
     {
-        return static_cast<T>(-1) == other;
+        return narrow_cast<T>(-1) == other;
     }
 
     template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
-    constexpr bool operator !=(T other) const noexcept
+    constexpr bool operator!=(T other) const noexcept
     {
-        return static_cast<T>(-1) != other;
+        return narrow_cast<T>(-1) != other;
     }
-
 };
 
 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
-constexpr bool operator ==(T left, static_bounds_dynamic_range_t right) noexcept
+constexpr bool operator==(T left, static_bounds_dynamic_range_t right) noexcept
 {
     return right == left;
 }
 
 template <typename T, typename Dummy = std::enable_if_t<std::is_integral<T>::value>>
-constexpr bool operator !=(T left, static_bounds_dynamic_range_t right) noexcept
+constexpr bool operator!=(T left, static_bounds_dynamic_range_t right) noexcept
 {
     return right != left;
 }
@@ -276,8 +279,12 @@
 const std::ptrdiff_t dynamic_range = -1;
 #endif
 
-struct generalized_mapping_tag {};
-struct contiguous_mapping_tag : generalized_mapping_tag {};
+struct generalized_mapping_tag
+{
+};
+struct contiguous_mapping_tag : generalized_mapping_tag
+{
+};
 
 namespace details
 {
@@ -289,8 +296,9 @@
     };
 
     template <std::ptrdiff_t... Ranges>
-    struct BoundsRanges {
-            using size_type = std::ptrdiff_t;
+    struct BoundsRanges
+    {
+        using size_type = std::ptrdiff_t;
         static const size_type Depth = 0;
         static const size_type DynamicNum = 0;
         static const size_type CurrentRange = 1;
@@ -299,54 +307,53 @@
         // TODO : following signature is for work around VS bug
         template <typename OtherRange>
         BoundsRanges(const OtherRange&, bool /* firstLevel */)
-        {}
-        
-        BoundsRanges (const BoundsRanges&) = default;
-        BoundsRanges& operator=(const BoundsRanges&) = default;
-        BoundsRanges(const std::ptrdiff_t* const) { }
-        BoundsRanges() = default;
+        {
+        }
 
+        BoundsRanges(const BoundsRanges&) = default;
+        BoundsRanges& operator=(const BoundsRanges&) = default;
+        BoundsRanges(const std::ptrdiff_t* const) {}
+        BoundsRanges() = default;
 
         template <typename T, size_t Dim>
         void serialize(T&) const
-        {}
+        {
+        }
 
         template <typename T, size_t Dim>
         size_type linearize(const T&) const
-        { 
+        {
             return 0;
         }
 
         template <typename T, size_t Dim>
         bool contains(const T&) const
         {
-            return 0;
+            return false;
         }
 
-        size_type totalSize() const noexcept
-        {
-            return TotalSize;
-        }
+        size_type elementNum(size_t) const noexcept { return 0; }
 
-        bool operator==(const BoundsRanges&) const noexcept
-        {
-            return true;
-        }
+        size_type totalSize() const noexcept { return TotalSize; }
+
+        bool operator==(const BoundsRanges&) const noexcept { return true; }
     };
 
     template <std::ptrdiff_t... RestRanges>
-    struct BoundsRanges <dynamic_range, RestRanges...> : BoundsRanges<RestRanges...>{
-        using Base = BoundsRanges <RestRanges... >;
-            using size_type = std::ptrdiff_t;
+    struct BoundsRanges<dynamic_range, RestRanges...> : BoundsRanges<RestRanges...>
+    {
+        using Base = BoundsRanges<RestRanges...>;
+        using size_type = std::ptrdiff_t;
         static const size_t Depth = Base::Depth + 1;
         static const size_t DynamicNum = Base::DynamicNum + 1;
         static const size_type CurrentRange = dynamic_range;
         static const size_type TotalSize = dynamic_range;
         const size_type m_bound;
 
-        BoundsRanges (const BoundsRanges&) = default;
-        
-            BoundsRanges(const std::ptrdiff_t* const arr) : Base(arr + 1), m_bound(*arr * this->Base::totalSize())
+        BoundsRanges(const BoundsRanges&) = default;
+
+        BoundsRanges(const std::ptrdiff_t* const arr)
+            : Base(arr + 1), m_bound(*arr * this->Base::totalSize())
         {
             Expects(0 <= *arr);
         }
@@ -354,9 +361,12 @@
         BoundsRanges() : m_bound(0) {}
 
         template <std::ptrdiff_t OtherRange, std::ptrdiff_t... RestOtherRanges>
-            BoundsRanges(const BoundsRanges<OtherRange, RestOtherRanges...>& other, bool /* firstLevel */ = true) :
-                Base(static_cast<const BoundsRanges<RestOtherRanges...>&>(other), false), m_bound(other.totalSize())
-            {}
+        BoundsRanges(const BoundsRanges<OtherRange, RestOtherRanges...>& other,
+                     bool /* firstLevel */ = true)
+            : Base(static_cast<const BoundsRanges<RestOtherRanges...>&>(other), false)
+            , m_bound(other.totalSize())
+        {
+        }
 
         template <typename T, size_t Dim = 0>
         void serialize(T& arr) const
@@ -367,101 +377,24 @@
 
         template <typename T, size_t Dim = 0>
         size_type linearize(const T& arr) const
-        { 
+        {
             const size_type index = this->Base::totalSize() * arr[Dim];
             Expects(index < m_bound);
             return index + this->Base::template linearize<T, Dim + 1>(arr);
         }
-        
-        template <typename T, size_t Dim = 0>
-        size_type contains(const T & arr) const
-        {
-            const ptrdiff_t last = this->Base::template contains<T, Dim + 1>(arr);
-            if (last == -1)
-                return -1;
-            const ptrdiff_t cur = this->Base::totalSize() * arr[Dim];
-            return cur < m_bound ? cur + last : -1;
-        }
-        
-        size_type totalSize() const noexcept
-        {
-            return m_bound;
-        }
-        
-        size_type elementNum() const noexcept
-        {
-            return totalSize() / this->Base::totalSize();
-        }
-        
-        size_type elementNum(size_t dim) const noexcept
-        {
-            if (dim > 0)
-                return this->Base::elementNum(dim - 1);
-            else
-                return elementNum();
-        }
-
-        bool operator == (const BoundsRanges & rhs) const noexcept
-        {
-            return m_bound == rhs.m_bound && static_cast<const Base&>(*this) == static_cast<const Base&>(rhs);
-        }
-    };
-
-    template <std::ptrdiff_t CurRange, std::ptrdiff_t... RestRanges>
-    struct BoundsRanges <CurRange, RestRanges...> : BoundsRanges<RestRanges...>
-    {
-        using Base = BoundsRanges <RestRanges... >;
-            using size_type = std::ptrdiff_t;
-        static const size_t Depth = Base::Depth + 1;
-        static const size_t DynamicNum = Base::DynamicNum;
-        static const size_type CurrentRange = CurRange;
-        static const size_type TotalSize = Base::TotalSize == dynamic_range ? dynamic_range : CurrentRange * Base::TotalSize;
-
-        BoundsRanges (const BoundsRanges&) = default;
-        BoundsRanges(const std::ptrdiff_t* const arr) : Base(arr) { }
-        BoundsRanges() = default;
-
-        template <std::ptrdiff_t OtherRange, std::ptrdiff_t... RestOtherRanges>
-        BoundsRanges(const BoundsRanges<OtherRange, RestOtherRanges...>&other, bool firstLevel = true) : Base(static_cast<const BoundsRanges<RestOtherRanges...>&>(other), false)
-        {            
-            Expects((firstLevel && totalSize() <= other.totalSize()) || totalSize() == other.totalSize());
-            (void)firstLevel;
-        }
-
-        template <typename T, size_t Dim = 0>
-        void serialize(T& arr) const
-        {
-            arr[Dim] = elementNum();
-            this->Base::template serialize<T, Dim + 1>(arr);
-        }
-
-        template <typename T, size_t Dim = 0>
-        size_type linearize(const T& arr) const
-        {  
-            Expects(arr[Dim] < CurrentRange); // Index is out of range
-            return this->Base::totalSize() * arr[Dim] + this->Base::template linearize<T, Dim + 1>(arr);
-        }
 
         template <typename T, size_t Dim = 0>
         size_type contains(const T& arr) const
         {
-            if (arr[Dim] >= CurrentRange)
-                return -1;
-            const size_type last = this->Base::template contains<T, Dim + 1>(arr);
-            if (last == -1)
-                return -1;
-            return this->Base::totalSize() * arr[Dim] + last;
+            const ptrdiff_t last = this->Base::template contains<T, Dim + 1>(arr);
+            if (last == -1) return -1;
+            const ptrdiff_t cur = this->Base::totalSize() * arr[Dim];
+            return cur < m_bound ? cur + last : -1;
         }
 
-        size_type totalSize() const noexcept
-        {
-            return CurrentRange * this->Base::totalSize();
-        }
+        size_type totalSize() const noexcept { return m_bound; }
 
-        size_type elementNum() const noexcept
-        {
-            return CurrentRange;
-        }
+        size_type elementNum() const noexcept { return totalSize() / this->Base::totalSize(); }
 
         size_type elementNum(size_t dim) const noexcept
         {
@@ -471,72 +404,126 @@
                 return elementNum();
         }
 
-        bool operator== (const BoundsRanges& rhs) const noexcept
+        bool operator==(const BoundsRanges& rhs) const noexcept
         {
-            return static_cast<const Base &>(*this) == static_cast<const Base &>(rhs);
+            return m_bound == rhs.m_bound &&
+                   static_cast<const Base&>(*this) == static_cast<const Base&>(rhs);
         }
     };
 
-    template <typename SourceType, typename TargetType, size_t Rank>
-    struct BoundsRangeConvertible2;
+    template <std::ptrdiff_t CurRange, std::ptrdiff_t... RestRanges>
+    struct BoundsRanges<CurRange, RestRanges...> : BoundsRanges<RestRanges...>
+    {
+        using Base = BoundsRanges<RestRanges...>;
+        using size_type = std::ptrdiff_t;
+        static const size_t Depth = Base::Depth + 1;
+        static const size_t DynamicNum = Base::DynamicNum;
+        static const size_type CurrentRange = CurRange;
+        static const size_type TotalSize =
+            Base::TotalSize == dynamic_range ? dynamic_range : CurrentRange * Base::TotalSize;
 
-    template <size_t Rank, typename SourceType, typename TargetType, typename Ret = BoundsRangeConvertible2<typename SourceType::Base, typename TargetType::Base, Rank>>
-    auto helpBoundsRangeConvertible(SourceType, TargetType, std::true_type) -> Ret;
+        BoundsRanges(const BoundsRanges&) = default;
 
-    template <size_t Rank, typename SourceType, typename TargetType>
-    auto helpBoundsRangeConvertible(SourceType, TargetType, ...) -> std::false_type;
-    
-    template <typename SourceType, typename TargetType, size_t Rank>
-    struct BoundsRangeConvertible2 : decltype(helpBoundsRangeConvertible<Rank - 1>(SourceType(), TargetType(), 
-        std::integral_constant<bool, SourceType::Depth == TargetType::Depth 
-        && (SourceType::CurrentRange == TargetType::CurrentRange || TargetType::CurrentRange == dynamic_range || SourceType::CurrentRange == dynamic_range)>())) 
-    {};
+        BoundsRanges(const std::ptrdiff_t* const arr) : Base(arr) {}
+        BoundsRanges() = default;
+
+        template <std::ptrdiff_t OtherRange, std::ptrdiff_t... RestOtherRanges>
+        BoundsRanges(const BoundsRanges<OtherRange, RestOtherRanges...>& other,
+                     bool firstLevel = true)
+            : Base(static_cast<const BoundsRanges<RestOtherRanges...>&>(other), false)
+        {
+            (void) firstLevel;
+        }
+
+        template <typename T, size_t Dim = 0>
+        void serialize(T& arr) const
+        {
+            arr[Dim] = elementNum();
+            this->Base::template serialize<T, Dim + 1>(arr);
+        }
+
+        template <typename T, size_t Dim = 0>
+        size_type linearize(const T& arr) const
+        {
+            Expects(arr[Dim] < CurrentRange); // Index is out of range
+            return this->Base::totalSize() * arr[Dim] +
+                   this->Base::template linearize<T, Dim + 1>(arr);
+        }
+
+        template <typename T, size_t Dim = 0>
+        size_type contains(const T& arr) const
+        {
+            if (arr[Dim] >= CurrentRange) return -1;
+            const size_type last = this->Base::template contains<T, Dim + 1>(arr);
+            if (last == -1) return -1;
+            return this->Base::totalSize() * arr[Dim] + last;
+        }
+
+        size_type totalSize() const noexcept { return CurrentRange * this->Base::totalSize(); }
+
+        size_type elementNum() const noexcept { return CurrentRange; }
+
+        size_type elementNum(size_t dim) const noexcept
+        {
+            if (dim > 0)
+                return this->Base::elementNum(dim - 1);
+            else
+                return elementNum();
+        }
+
+        bool operator==(const BoundsRanges& rhs) const noexcept
+        {
+            return static_cast<const Base&>(*this) == static_cast<const Base&>(rhs);
+        }
+    };
 
     template <typename SourceType, typename TargetType>
-    struct BoundsRangeConvertible2<SourceType, TargetType, 0> : std::true_type {};
-
-    template <typename SourceType, typename TargetType, std::ptrdiff_t Rank = TargetType::Depth>
-    struct BoundsRangeConvertible : decltype(helpBoundsRangeConvertible<Rank - 1>(SourceType(), TargetType(), 
-        std::integral_constant<bool, SourceType::Depth == TargetType::Depth 
-        && (!LessThan<SourceType::CurrentRange, TargetType::CurrentRange>::value || TargetType::CurrentRange == dynamic_range || SourceType::CurrentRange == dynamic_range)>())) 
-    {};
-    template <typename SourceType, typename TargetType>
-    struct BoundsRangeConvertible<SourceType, TargetType, 0> : std::true_type {};
+    struct BoundsRangeConvertible
+        : public std::integral_constant<bool, (SourceType::TotalSize >= TargetType::TotalSize ||
+                                               TargetType::TotalSize == dynamic_range ||
+                                               SourceType::TotalSize == dynamic_range ||
+                                               TargetType::TotalSize == 0)>
+    {
+    };
 
     template <typename TypeChain>
     struct TypeListIndexer
     {
-        const TypeChain & obj;
-        TypeListIndexer(const TypeChain & obj) :obj(obj){}
-        template<size_t N>
-        const TypeChain & getObj(std::true_type)
-        {
-            return obj;
-        }
-        template<size_t N, typename MyChain = TypeChain, typename MyBase = typename MyChain::Base>
-        auto getObj(std::false_type) -> decltype(TypeListIndexer<MyBase>(static_cast<const MyBase &>(obj)).template get<N>())
-        {
-            return TypeListIndexer<MyBase>(static_cast<const MyBase &>(obj)).template get<N>();
-        }
+        const TypeChain& obj_;
+        TypeListIndexer(const TypeChain& obj) : obj_(obj) {}
+
         template <size_t N>
-        auto get() -> decltype(getObj<N - 1>(std::integral_constant<bool, true>()))
+        const TypeChain& getObj(std::true_type)
+        {
+            return obj_;
+        }
+
+        template <size_t N, typename MyChain = TypeChain, typename MyBase = typename MyChain::Base>
+        auto getObj(std::false_type)
+            -> decltype(TypeListIndexer<MyBase>(static_cast<const MyBase&>(obj_)).template get<N>())
+        {
+            return TypeListIndexer<MyBase>(static_cast<const MyBase&>(obj_)).template get<N>();
+        }
+
+        template <size_t N>
+        auto get() -> decltype(getObj<N - 1>(std::integral_constant<bool, N == 0>()))
         {
             return getObj<N - 1>(std::integral_constant<bool, N == 0>());
         }
     };
 
     template <typename TypeChain>
-    TypeListIndexer<TypeChain> createTypeListIndexer(const TypeChain &obj)
+    TypeListIndexer<TypeChain> createTypeListIndexer(const TypeChain& obj)
     {
         return TypeListIndexer<TypeChain>(obj);
     }
 
-    template <size_t Rank, bool Enabled = (Rank > 1), typename Ret = std::enable_if_t<Enabled, index<Rank - 1>>>
+    template <size_t Rank, bool Enabled = (Rank > 1),
+              typename Ret = std::enable_if_t<Enabled, index<Rank - 1>>>
     constexpr Ret shift_left(const index<Rank>& other) noexcept
     {
         Ret ret{};
-        for (size_t i = 0; i < Rank - 1; ++i)
-        {
+        for (size_t i = 0; i < Rank - 1; ++i) {
             ret[i] = other[i + 1];
         }
         return ret;
@@ -550,19 +537,17 @@
 class static_bounds
 {
 public:
-    static_bounds(const details::BoundsRanges<Ranges...>&) {
-    }
+    static_bounds(const details::BoundsRanges<Ranges...>&) {}
 };
 
 template <std::ptrdiff_t FirstRange, std::ptrdiff_t... RestRanges>
 class static_bounds<FirstRange, RestRanges...>
 {
-    using MyRanges = details::BoundsRanges<FirstRange, RestRanges... >;
+    using MyRanges = details::BoundsRanges<FirstRange, RestRanges...>;
 
     MyRanges m_ranges;
-    constexpr static_bounds(const MyRanges& range) : m_ranges(range)
-    {}
-    
+    constexpr static_bounds(const MyRanges& range) : m_ranges(range) {}
+
     template <std::ptrdiff_t... OtherRanges>
     friend class static_bounds;
 
@@ -581,94 +566,144 @@
     using mapping_type = contiguous_mapping_tag;
 
     constexpr static_bounds(const static_bounds&) = default;
-    
-    template <std::ptrdiff_t... Ranges, typename Dummy = std::enable_if_t<
-        details::BoundsRangeConvertible<details::BoundsRanges<Ranges...>, details::BoundsRanges <FirstRange, RestRanges... >>::value>>
+
+    template <typename SourceType, typename TargetType, size_t Rank>
+    struct BoundsRangeConvertible2;
+
+    template <size_t Rank, typename SourceType, typename TargetType,
+              typename Ret = BoundsRangeConvertible2<typename SourceType::Base,
+                                                     typename TargetType::Base, Rank>>
+    static auto helpBoundsRangeConvertible(SourceType, TargetType, std::true_type) -> Ret;
+
+    template <size_t Rank, typename SourceType, typename TargetType>
+    static auto helpBoundsRangeConvertible(SourceType, TargetType, ...) -> std::false_type;
+
+    template <typename SourceType, typename TargetType, size_t Rank>
+    struct BoundsRangeConvertible2
+        : decltype(helpBoundsRangeConvertible<Rank - 1>(
+              SourceType(), TargetType(),
+              std::integral_constant<bool,
+                                     SourceType::Depth == TargetType::Depth &&
+                                         (SourceType::CurrentRange == TargetType::CurrentRange ||
+                                          TargetType::CurrentRange == dynamic_range ||
+                                          SourceType::CurrentRange == dynamic_range)>()))
+    {
+    };
+
+    template <typename SourceType, typename TargetType>
+    struct BoundsRangeConvertible2<SourceType, TargetType, 0> : std::true_type
+    {
+    };
+
+    template <typename SourceType, typename TargetType, std::ptrdiff_t Rank = TargetType::Depth>
+    struct BoundsRangeConvertible
+        : decltype(helpBoundsRangeConvertible<Rank - 1>(
+              SourceType(), TargetType(),
+              std::integral_constant<bool,
+                                     SourceType::Depth == TargetType::Depth &&
+                                         (!details::LessThan<SourceType::CurrentRange,
+                                                             TargetType::CurrentRange>::value ||
+                                          TargetType::CurrentRange == dynamic_range ||
+                                          SourceType::CurrentRange == dynamic_range)>()))
+    {
+    };
+
+    template <typename SourceType, typename TargetType>
+    struct BoundsRangeConvertible<SourceType, TargetType, 0> : std::true_type
+    {
+    };
+
+    template <std::ptrdiff_t... Ranges,
+              typename = std::enable_if_t<details::BoundsRangeConvertible<
+                  details::BoundsRanges<Ranges...>,
+                  details::BoundsRanges<FirstRange, RestRanges...>>::value>>
     constexpr static_bounds(const static_bounds<Ranges...>& other) : m_ranges(other.m_ranges)
-    {}
-                                                       
-    constexpr static_bounds(std::initializer_list<size_type> il) : m_ranges((const std::ptrdiff_t*)il.begin())
+    {
+        Expects((MyRanges::DynamicNum == 0 && details::BoundsRanges<Ranges...>::DynamicNum == 0) ||
+                MyRanges::DynamicNum > 0 || other.m_ranges.totalSize() >= m_ranges.totalSize());
+    }
+
+    constexpr static_bounds(std::initializer_list<size_type> il)
+        : m_ranges(static_cast<const std::ptrdiff_t*>(il.begin()))
     {
         // Size of the initializer list must match the rank of the array
-        Expects((MyRanges::DynamicNum == 0 && il.size() == 1 && *il.begin() == static_size) || MyRanges::DynamicNum == il.size()); 
+        Expects((MyRanges::DynamicNum == 0 && il.size() == 1 && *il.begin() == static_size) ||
+                MyRanges::DynamicNum == il.size());
         // Size of the range must be less than the max element of the size type
-        Expects(m_ranges.totalSize() <= PTRDIFF_MAX); 
+        Expects(m_ranges.totalSize() <= PTRDIFF_MAX);
     }
-    
+
     constexpr static_bounds() = default;
 
     constexpr static_bounds& operator=(const static_bounds& otherBounds)
     {
-        new(&m_ranges) MyRanges (otherBounds.m_ranges);
+        new (&m_ranges) MyRanges(otherBounds.m_ranges);
         return *this;
     }
 
     constexpr sliced_type slice() const noexcept
     {
-        return sliced_type{static_cast<const details::BoundsRanges<RestRanges...> &>(m_ranges)};
+        return sliced_type{static_cast<const details::BoundsRanges<RestRanges...>&>(m_ranges)};
     }
 
-    constexpr size_type stride() const noexcept
-    {
-        return rank > 1 ? slice().size() : 1;
-    }
-    
-    constexpr size_type size() const noexcept
-    {
-        return m_ranges.totalSize();
-    }
+    constexpr size_type stride() const noexcept { return rank > 1 ? slice().size() : 1; }
 
-    constexpr size_type total_size() const noexcept
-    {
-        return m_ranges.totalSize();
-    }
-    
-    constexpr size_type linearize(const index_type & idx) const
-    {
-        return m_ranges.linearize(idx);
-    }
-    
+    constexpr size_type size() const noexcept { return m_ranges.totalSize(); }
+
+    constexpr size_type total_size() const noexcept { return m_ranges.totalSize(); }
+
+    constexpr size_type linearize(const index_type& idx) const { return m_ranges.linearize(idx); }
+
     constexpr bool contains(const index_type& idx) const noexcept
     {
         return m_ranges.contains(idx) != -1;
     }
-    
+
     constexpr size_type operator[](size_t index) const noexcept
     {
         return m_ranges.elementNum(index);
     }
-    
+
     template <size_t Dim = 0>
     constexpr size_type extent() const noexcept
     {
-        static_assert(Dim < rank, "dimension should be less than rank (dimension count starts from 0)");
+        static_assert(Dim < rank,
+                      "dimension should be less than rank (dimension count starts from 0)");
         return details::createTypeListIndexer(m_ranges).template get<Dim>().elementNum();
     }
-    
+
+    template <typename IntType>
+    constexpr size_type extent(IntType dim) const noexcept
+    {
+        static_assert(std::is_integral<IntType>::value,
+                      "Dimension parameter must be supplied as an integral type.");
+        auto real_dim = narrow_cast<size_t>(dim);
+        Expects(real_dim < rank);
+
+        return m_ranges.elementNum(real_dim);
+    }
+
     constexpr index_type index_bounds() const noexcept
     {
         size_type extents[rank] = {};
         m_ranges.serialize(extents);
-        return{ extents };
+        return {extents};
     }
-    
+
     template <std::ptrdiff_t... Ranges>
-    constexpr bool operator == (const static_bounds<Ranges...>& rhs) const noexcept
+    constexpr bool operator==(const static_bounds<Ranges...>& rhs) const noexcept
     {
         return this->size() == rhs.size();
     }
-    
+
     template <std::ptrdiff_t... Ranges>
-    constexpr bool operator != (const static_bounds<Ranges...>& rhs) const noexcept
+    constexpr bool operator!=(const static_bounds<Ranges...>& rhs) const noexcept
     {
         return !(*this == rhs);
     }
-    
-    constexpr const_iterator begin() const noexcept
-    {
-        return const_iterator(*this, index_type{});
-    }
-    
+
+    constexpr const_iterator begin() const noexcept { return const_iterator(*this, index_type{}); }
+
     constexpr const_iterator end() const noexcept
     {
         return const_iterator(*this, this->index_bounds());
@@ -676,19 +711,19 @@
 };
 
 template <size_t Rank>
-class strided_bounds 
+class strided_bounds
 {
     template <size_t OtherRank>
     friend class strided_bounds;
 
 public:
     static const size_t rank = Rank;
-    using value_type      = std::ptrdiff_t;
-    using reference       = std::add_lvalue_reference_t<value_type>;
+    using value_type = std::ptrdiff_t;
+    using reference = std::add_lvalue_reference_t<value_type>;
     using const_reference = std::add_const_t<reference>;
-    using size_type       = value_type;
+    using size_type = value_type;
     using difference_type = value_type;
-    using index_type      = index<rank>;
+    using index_type = index<rank>;
     using const_index_type = std::add_const_t<index_type>;
     using iterator = bounds_iterator<const_index_type>;
     using const_iterator = bounds_iterator<const_index_type>;
@@ -697,49 +732,45 @@
     using sliced_type = std::conditional_t<rank != 0, strided_bounds<rank - 1>, void>;
     using mapping_type = generalized_mapping_tag;
 
-    constexpr strided_bounds(const strided_bounds &) noexcept = default;
+    constexpr strided_bounds(const strided_bounds&) noexcept = default;
 
-    constexpr strided_bounds & operator=(const strided_bounds &) noexcept = default;
+    constexpr strided_bounds& operator=(const strided_bounds&) noexcept = default;
 
-    constexpr strided_bounds(const value_type(&values)[rank], index_type strides)
+    constexpr strided_bounds(const value_type (&values)[rank], index_type strides)
         : m_extents(values), m_strides(std::move(strides))
-    {}
-
-    constexpr strided_bounds(const index_type &extents, const index_type &strides) noexcept
-        : m_extents(extents), m_strides(strides)
-    {}
-
-    constexpr index_type strides() const noexcept
     {
-        return m_strides;
     }
 
+    constexpr strided_bounds(const index_type& extents, const index_type& strides) noexcept
+        : m_extents(extents),
+          m_strides(strides)
+    {
+    }
+
+    constexpr index_type strides() const noexcept { return m_strides; }
+
     constexpr size_type total_size() const noexcept
     {
         size_type ret = 0;
-        for (size_t i = 0; i < rank; ++i)
-        {
+        for (size_t i = 0; i < rank; ++i) {
             ret += (m_extents[i] - 1) * m_strides[i];
         }
         return ret + 1;
     }
-    
+
     constexpr size_type size() const noexcept
     {
         size_type ret = 1;
-        for (size_t i = 0; i < rank; ++i)
-        {
+        for (size_t i = 0; i < rank; ++i) {
             ret *= m_extents[i];
         }
         return ret;
     }
-    
+
     constexpr bool contains(const index_type& idx) const noexcept
     {
-        for (size_t i = 0; i < rank; ++i)
-        {
-            if (idx[i] < 0 || idx[i] >= m_extents[i])
-                return false;
+        for (size_t i = 0; i < rank; ++i) {
+            if (idx[i] < 0 || idx[i] >= m_extents[i]) return false;
         }
         return true;
     }
@@ -747,45 +778,33 @@
     constexpr size_type linearize(const index_type& idx) const noexcept
     {
         size_type ret = 0;
-        for (size_t i = 0; i < rank; i++)
-        {
+        for (size_t i = 0; i < rank; i++) {
             Expects(idx[i] < m_extents[i]); // index is out of bounds of the array
             ret += idx[i] * m_strides[i];
         }
         return ret;
     }
-    
-    constexpr size_type stride() const noexcept
-    {
-        return m_strides[0];
-    }
-    
+
+    constexpr size_type stride() const noexcept { return m_strides[0]; }
+
     template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
     constexpr sliced_type slice() const
     {
-        return{ details::shift_left(m_extents), details::shift_left(m_strides) };
+        return {details::shift_left(m_extents), details::shift_left(m_strides)};
     }
-    
+
     template <size_t Dim = 0>
     constexpr size_type extent() const noexcept
     {
-        static_assert(Dim < Rank, "dimension should be less than rank (dimension count starts from 0)");
+        static_assert(Dim < Rank,
+                      "dimension should be less than rank (dimension count starts from 0)");
         return m_extents[Dim];
     }
-    
-    constexpr index_type index_bounds() const noexcept
-    {
-        return m_extents;
-    }
-    constexpr const_iterator begin() const noexcept
-    {
-        return const_iterator{ *this, index_type{} };
-    }
-    
-    constexpr const_iterator end() const noexcept
-    {
-        return const_iterator{ *this, index_bounds() };
-    }
+
+    constexpr index_type index_bounds() const noexcept { return m_extents; }
+    constexpr const_iterator begin() const noexcept { return const_iterator{*this, index_type{}}; }
+
+    constexpr const_iterator end() const noexcept { return const_iterator{*this, index_bounds()}; }
 
 private:
     index_type m_extents;
@@ -793,17 +812,23 @@
 };
 
 template <typename T>
-struct is_bounds : std::integral_constant<bool, false> {};
+struct is_bounds : std::integral_constant<bool, false>
+{
+};
 template <std::ptrdiff_t... Ranges>
-struct is_bounds<static_bounds<Ranges...>> : std::integral_constant<bool, true> {};
+struct is_bounds<static_bounds<Ranges...>> : std::integral_constant<bool, true>
+{
+};
 template <size_t Rank>
-struct is_bounds<strided_bounds<Rank>> : std::integral_constant<bool, true> {};
+struct is_bounds<strided_bounds<Rank>> : std::integral_constant<bool, true>
+{
+};
 
 template <typename IndexType>
-class bounds_iterator: public std::iterator<std::random_access_iterator_tag, IndexType>
+class bounds_iterator : public std::iterator<std::random_access_iterator_tag, IndexType>
 {
 private:
-    using Base = std::iterator <std::random_access_iterator_tag, IndexType>;
+    using Base = std::iterator<std::random_access_iterator_tag, IndexType>;
 
 public:
     static const size_t rank = IndexType::rank;
@@ -815,27 +840,20 @@
     using index_size_type = typename IndexType::value_type;
     template <typename Bounds>
     explicit bounds_iterator(const Bounds& bnd, value_type curr) noexcept
-        : boundary(bnd.index_bounds()), curr(std::move(curr))
+        : boundary(bnd.index_bounds()),
+          curr(std::move(curr))
     {
         static_assert(is_bounds<Bounds>::value, "Bounds type must be provided");
     }
 
-    constexpr reference operator*() const noexcept
-    {
-        return curr;
-    }
+    constexpr reference operator*() const noexcept { return curr; }
 
-    constexpr pointer operator->() const noexcept
-    {
-        return &curr;
-    }
+    constexpr pointer operator->() const noexcept { return &curr; }
 
     constexpr bounds_iterator& operator++() noexcept
     {
-        for (size_t i = rank; i-- > 0;)
-        {
-            if (curr[i] < boundary[i] - 1)
-            {
+        for (size_t i = rank; i-- > 0;) {
+            if (curr[i] < boundary[i] - 1) {
                 curr[i]++;
                 return *this;
             }
@@ -855,19 +873,15 @@
 
     constexpr bounds_iterator& operator--() noexcept
     {
-        if (!less(curr, boundary))
-        {
+        if (!less(curr, boundary)) {
             // if at the past-the-end, set to last element
-            for (size_t i = 0; i < rank; ++i)
-            {
+            for (size_t i = 0; i < rank; ++i) {
                 curr[i] = boundary[i] - 1;
             }
             return *this;
         }
-        for (size_t i = rank; i-- > 0;)
-        {
-            if (curr[i] >= 1)
-            {
+        for (size_t i = rank; i-- > 0;) {
+            if (curr[i] >= 1) {
                 curr[i]--;
                 return *this;
             }
@@ -875,7 +889,7 @@
         }
         // If we're here the preconditions were violated
         // "pre: there exists s such that r == ++s"
-        Expects(false); 
+        Expects(false);
         return *this;
     }
 
@@ -888,7 +902,7 @@
 
     constexpr bounds_iterator operator+(difference_type n) const noexcept
     {
-        bounds_iterator ret{ *this };
+        bounds_iterator ret{*this};
         return ret += n;
     }
 
@@ -897,83 +911,62 @@
         auto linear_idx = linearize(curr) + n;
         std::remove_const_t<value_type> stride = 0;
         stride[rank - 1] = 1;
-        for (size_t i = rank - 1; i-- > 0;)
-        {
+        for (size_t i = rank - 1; i-- > 0;) {
             stride[i] = stride[i + 1] * boundary[i + 1];
         }
-        for (size_t i = 0; i < rank; ++i)
-        {
+        for (size_t i = 0; i < rank; ++i) {
             curr[i] = linear_idx / stride[i];
             linear_idx = linear_idx % stride[i];
         }
-        //index is out of bounds of the array
+        // index is out of bounds of the array
         Expects(!less(curr, index_type{}) && !less(boundary, curr));
         return *this;
     }
 
     constexpr bounds_iterator operator-(difference_type n) const noexcept
     {
-        bounds_iterator ret{ *this };
+        bounds_iterator ret{*this};
         return ret -= n;
     }
 
-    constexpr bounds_iterator& operator-=(difference_type n) noexcept
-    {
-        return *this += -n;
-    }
+    constexpr bounds_iterator& operator-=(difference_type n) noexcept { return * this += -n; }
 
     constexpr difference_type operator-(const bounds_iterator& rhs) const noexcept
     {
         return linearize(curr) - linearize(rhs.curr);
     }
 
-    constexpr value_type operator[](difference_type n) const noexcept
-    {
-        return *(*this + n);
-    }
+    constexpr value_type operator[](difference_type n) const noexcept { return *(*this + n); }
 
     constexpr bool operator==(const bounds_iterator& rhs) const noexcept
     {
         return curr == rhs.curr;
     }
 
-    constexpr bool operator!=(const bounds_iterator& rhs) const noexcept
-    {
-        return !(*this == rhs);
-    }
+    constexpr bool operator!=(const bounds_iterator& rhs) const noexcept { return !(*this == rhs); }
 
     constexpr bool operator<(const bounds_iterator& rhs) const noexcept
     {
         return less(curr, rhs.curr);
     }
 
-    constexpr bool operator<=(const bounds_iterator& rhs) const noexcept
-    {
-        return !(rhs < *this);
-    }
+    constexpr bool operator<=(const bounds_iterator& rhs) const noexcept { return !(rhs < *this); }
 
-    constexpr bool operator>(const bounds_iterator& rhs) const noexcept
-    {
-        return rhs < *this;
-    }
+    constexpr bool operator>(const bounds_iterator& rhs) const noexcept { return rhs < *this; }
 
-    constexpr bool operator>=(const bounds_iterator& rhs) const noexcept
-    {
-        return !(rhs > *this);
-    }
+    constexpr bool operator>=(const bounds_iterator& rhs) const noexcept { return !(rhs > *this); }
 
     void swap(bounds_iterator& rhs) noexcept
     {
         std::swap(boundary, rhs.boundary);
         std::swap(curr, rhs.curr);
     }
+
 private:
     constexpr bool less(index_type& one, index_type& other) const noexcept
     {
-        for (size_t i = 0; i < rank; ++i)
-        {
-            if (one[i] < other[i])
-                return true;
+        for (size_t i = 0; i < rank; ++i) {
+            if (one[i] < other[i]) return true;
         }
         return false;
     }
@@ -984,19 +977,16 @@
         // Check if past-the-end
         index_size_type multiplier = 1;
         index_size_type res = 0;
-        if (!less(idx, boundary))
-        {
+        if (!less(idx, boundary)) {
             res = 1;
-            for (size_t i = rank; i-- > 0;)
-            {
+            for (size_t i = rank; i-- > 0;) {
                 res += (idx[i] - 1) * multiplier;
                 multiplier *= boundary[i];
             }
         }
         else
         {
-            for (size_t i = rank; i-- > 0;)
-            {
+            for (size_t i = rank; i-- > 0;) {
                 res += idx[i] * multiplier;
                 multiplier *= boundary[i];
             }
@@ -1009,54 +999,63 @@
 };
 
 template <typename IndexType>
-bounds_iterator<IndexType> operator+(typename bounds_iterator<IndexType>::difference_type n, const bounds_iterator<IndexType>& rhs) noexcept
+bounds_iterator<IndexType> operator+(typename bounds_iterator<IndexType>::difference_type n,
+                                     const bounds_iterator<IndexType>& rhs) noexcept
 {
     return rhs + n;
 }
 
-//
-// begin definitions of basic_span
-//
 namespace details
 {
     template <typename Bounds>
-    constexpr std::enable_if_t<std::is_same<typename Bounds::mapping_type, generalized_mapping_tag>::value, typename Bounds::index_type> make_stride(const Bounds& bnd) noexcept
+    constexpr std::enable_if_t<
+        std::is_same<typename Bounds::mapping_type, generalized_mapping_tag>::value,
+        typename Bounds::index_type>
+    make_stride(const Bounds& bnd) noexcept
     {
         return bnd.strides();
     }
 
     // Make a stride vector from bounds, assuming contiguous memory.
     template <typename Bounds>
-    constexpr std::enable_if_t<std::is_same<typename Bounds::mapping_type, contiguous_mapping_tag>::value, typename Bounds::index_type> make_stride(const Bounds& bnd) noexcept
+    constexpr std::enable_if_t<
+        std::is_same<typename Bounds::mapping_type, contiguous_mapping_tag>::value,
+        typename Bounds::index_type>
+    make_stride(const Bounds& bnd) noexcept
     {
         auto extents = bnd.index_bounds();
         typename Bounds::size_type stride[Bounds::rank] = {};
 
         stride[Bounds::rank - 1] = 1;
-        for (size_t i = 1; i < Bounds::rank; ++i)
-        {
+        for (size_t i = 1; i < Bounds::rank; ++i) {
             stride[Bounds::rank - i - 1] = stride[Bounds::rank - i] * extents[Bounds::rank - i];
         }
-        return{ stride };
+        return {stride};
     }
 
     template <typename BoundsSrc, typename BoundsDest>
-    void verifyBoundsReshape(const BoundsSrc &src, const BoundsDest &dest)
+    void verifyBoundsReshape(const BoundsSrc& src, const BoundsDest& dest)
     {
-        static_assert(is_bounds<BoundsSrc>::value && is_bounds<BoundsDest>::value, "The src type and dest type must be bounds");
-        static_assert(std::is_same<typename BoundsSrc::mapping_type, contiguous_mapping_tag>::value, "The source type must be a contiguous bounds");
-        static_assert(BoundsDest::static_size == dynamic_range || BoundsSrc::static_size == dynamic_range || BoundsDest::static_size == BoundsSrc::static_size, "The source bounds must have same size as dest bounds");
+        static_assert(is_bounds<BoundsSrc>::value && is_bounds<BoundsDest>::value,
+                      "The src type and dest type must be bounds");
+        static_assert(std::is_same<typename BoundsSrc::mapping_type, contiguous_mapping_tag>::value,
+                      "The source type must be a contiguous bounds");
+        static_assert(BoundsDest::static_size == dynamic_range ||
+                          BoundsSrc::static_size == dynamic_range ||
+                          BoundsDest::static_size == BoundsSrc::static_size,
+                      "The source bounds must have same size as dest bounds");
         Expects(src.size() == dest.size());
     }
 
-
 } // namespace details
 
 template <typename Span>
 class contiguous_span_iterator;
 template <typename Span>
 class general_span_iterator;
-enum class byte : std::uint8_t {};
+enum class byte : std::uint8_t
+{
+};
 
 template <std::ptrdiff_t DimSize = dynamic_range>
 struct dim
@@ -1071,7 +1070,8 @@
     dim(std::ptrdiff_t size) : dvalue(size) {}
 };
 
-template <typename ValueType, std::ptrdiff_t FirstDimension = dynamic_range, std::ptrdiff_t... RestDimensions>
+template <typename ValueType, std::ptrdiff_t FirstDimension = dynamic_range,
+          std::ptrdiff_t... RestDimensions>
 class span;
 
 template <typename ValueType, size_t Rank>
@@ -1087,14 +1087,15 @@
     };
 
     template <typename Traits>
-    struct SpanTypeTraits<Traits, typename std::is_reference<typename Traits::span_traits &>::type>
+    struct SpanTypeTraits<Traits, typename std::is_reference<typename Traits::span_traits&>::type>
     {
         using value_type = typename Traits::span_traits::value_type;
         using size_type = typename Traits::span_traits::size_type;
     };
 
     template <typename T, std::ptrdiff_t... Ranks>
-    struct SpanArrayTraits {
+    struct SpanArrayTraits
+    {
         using type = span<T, Ranks...>;
         using value_type = T;
         using bounds_type = static_bounds<Ranks...>;
@@ -1102,46 +1103,53 @@
         using reference = T&;
     };
     template <typename T, std::ptrdiff_t N, std::ptrdiff_t... Ranks>
-    struct SpanArrayTraits<T[N], Ranks...> : SpanArrayTraits<T, Ranks..., N> {};
+    struct SpanArrayTraits<T[N], Ranks...> : SpanArrayTraits<T, Ranks..., N>
+    {
+    };
 
     template <typename BoundsType>
     BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::true_type) // dynamic size
     {
-        Expects(totalSize <= PTRDIFF_MAX);
+        Expects(totalSize >= 0 && totalSize <= PTRDIFF_MAX);
         return BoundsType{totalSize};
     }
     template <typename BoundsType>
     BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::false_type) // static size
     {
-        Expects(BoundsType::static_size == totalSize);
+        Expects(BoundsType::static_size <= totalSize);
         return {};
     }
     template <typename BoundsType>
     BoundsType newBoundsHelper(std::ptrdiff_t totalSize)
     {
         static_assert(BoundsType::dynamic_rank <= 1, "dynamic rank must less or equal to 1");
-        return newBoundsHelperImpl<BoundsType>(totalSize, std::integral_constant<bool, BoundsType::dynamic_rank == 1>());
+        return newBoundsHelperImpl<BoundsType>(
+            totalSize, std::integral_constant<bool, BoundsType::dynamic_rank == 1>());
     }
-    
-    struct Sep{};
-    
+
+    struct Sep
+    {
+    };
+
     template <typename T, typename... Args>
     T static_as_span_helper(Sep, Args... args)
     {
-        return T{static_cast<typename T::size_type>(args)...};
+        return T{narrow_cast<typename T::size_type>(args)...};
     }
     template <typename T, typename Arg, typename... Args>
-    std::enable_if_t<!std::is_same<Arg, dim<dynamic_range>>::value && !std::is_same<Arg, Sep>::value, T> static_as_span_helper(Arg, Args... args)
+    std::enable_if_t<
+        !std::is_same<Arg, dim<dynamic_range>>::value && !std::is_same<Arg, Sep>::value, T>
+        static_as_span_helper(Arg, Args... args)
     {
         return static_as_span_helper<T>(args...);
     }
     template <typename T, typename... Args>
-    T static_as_span_helper(dim<dynamic_range> val, Args ... args)
+    T static_as_span_helper(dim<dynamic_range> val, Args... args)
     {
         return static_as_span_helper<T>(args..., val.dvalue);
     }
 
-    template <typename ...Dimensions>
+    template <typename... Dimensions>
     struct static_as_span_static_bounds_helper
     {
         using type = static_bounds<(Dimensions::value)...>;
@@ -1149,32 +1157,36 @@
 
     template <typename T>
     struct is_span_oracle : std::false_type
-    {};
+    {
+    };
 
     template <typename ValueType, std::ptrdiff_t FirstDimension, std::ptrdiff_t... RestDimensions>
     struct is_span_oracle<span<ValueType, FirstDimension, RestDimensions...>> : std::true_type
-    {};
-    
+    {
+    };
+
     template <typename ValueType, std::ptrdiff_t Rank>
     struct is_span_oracle<strided_span<ValueType, Rank>> : std::true_type
-    {};
-    
+    {
+    };
+
     template <typename T>
     struct is_span : is_span_oracle<std::remove_cv_t<T>>
-    {};
-
+    {
+    };
 }
 
-
 template <typename ValueType, std::ptrdiff_t FirstDimension, std::ptrdiff_t... RestDimensions>
 class span
 {
-    template <typename ValueType2, std::ptrdiff_t FirstDimension2, std::ptrdiff_t... RestDimensions2>
+    // TODO do we still need this?
+    template <typename ValueType2, std::ptrdiff_t FirstDimension2,
+              std::ptrdiff_t... RestDimensions2>
     friend class span;
 
 public:
     using bounds_type = static_bounds<FirstDimension, RestDimensions...>;
-    static const size_t rank = bounds_type::rank;
+    static const size_t Rank = bounds_type::rank;
     using size_type = typename bounds_type::size_type;
     using index_type = typename bounds_type::index_type;
     using value_type = ValueType;
@@ -1186,405 +1198,549 @@
     using const_iterator = contiguous_span_iterator<const_span>;
     using reverse_iterator = std::reverse_iterator<iterator>;
     using const_reverse_iterator = std::reverse_iterator<const_iterator>;
-    using sliced_type = std::conditional_t<rank == 1, value_type, span<value_type, RestDimensions...>>;
+    using sliced_type =
+        std::conditional_t<Rank == 1, value_type, span<value_type, RestDimensions...>>;
 
 private:
-    pointer m_pdata;
-    bounds_type m_bounds;
+    pointer data_;
+    bounds_type bounds_;
 
     friend iterator;
     friend const_iterator;
 
 public:
-
-    constexpr span(pointer data, bounds_type bounds) noexcept
-        : m_pdata(data), m_bounds(std::move(bounds))
+    // default constructor - same as constructing from nullptr_t
+    constexpr span() noexcept : span(nullptr, bounds_type{})
     {
-        Expects((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0);
+        static_assert(bounds_type::dynamic_rank != 0 ||
+                          (bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0),
+                      "Default construction of span<T> only possible "
+                      "for dynamic or fixed, zero-length spans.");
     }
 
-    constexpr span(pointer ptr, size_type size) noexcept
-        : span(ptr, bounds_type{ size })
-    {}
-
-    constexpr span(std::nullptr_t) noexcept
-        : span(nullptr, bounds_type{})
-    {}
-
-    constexpr span(std::nullptr_t, size_type size) noexcept
-        : span(nullptr, bounds_type{})
+    // construct from nullptr - get an empty span
+    constexpr span(std::nullptr_t) noexcept : span(nullptr, bounds_type{})
     {
+        static_assert(bounds_type::dynamic_rank != 0 ||
+                          (bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0),
+                      "nullptr_t construction of span<T> only possible "
+                      "for dynamic or fixed, zero-length spans.");
+    }
+
+    // construct from nullptr with size of 0 (helps with template function calls)
+    template <class IntType, typename = std::enable_if_t<std::is_integral<IntType>::value>>
+    constexpr span(std::nullptr_t, IntType size) noexcept : span(nullptr, bounds_type{})
+    {
+        static_assert(bounds_type::dynamic_rank != 0 ||
+                          (bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0),
+                      "nullptr_t construction of span<T> only possible "
+                      "for dynamic or fixed, zero-length spans.");
         Expects(size == 0);
     }
 
-    // default
-    template <std::ptrdiff_t DynamicRank = bounds_type::dynamic_rank, typename = std::enable_if_t<DynamicRank != 0>>
-    constexpr span() noexcept
-        : span(nullptr, bounds_type())
-    {}
-
-    // from n-dimensions dynamic array (e.g. new int[m][4]) (precedence will be lower than the 1-dimension pointer)
-    template <typename T, typename Helper = details::SpanArrayTraits<T, dynamic_range>,
-        typename Dummy = std::enable_if_t<std::is_same<value_type, std::remove_all_extents_t<T>>::value>
-        /*typename Dummy = std::enable_if_t<std::is_convertible<Helper::value_type (*)[], value_type (*)[]>::value>*/
-    >
-    constexpr span(T* const& data, size_type size) : span(reinterpret_cast<pointer>(data), typename Helper::bounds_type{size})
-    {}
-
-    // from n-dimensions static array
-    template <typename T, size_t N, typename Helper = details::SpanArrayTraits<T, N>,
-        typename = std::enable_if_t<std::is_convertible<typename Helper::value_type(*)[], value_type(*)[]>::value>
-    >
-    constexpr span (T (&arr)[N]) : span(reinterpret_cast<pointer>(arr), typename Helper::bounds_type())
-    {}
-
-    // from n-dimensions static array with size
-    template <typename T, size_t N, typename Helper = details::SpanArrayTraits<T, N>,
-        typename = std::enable_if_t<std::is_convertible<typename Helper::value_type(*)[], value_type(*)[]>::value>
-    >
-    constexpr span(T(&arr)[N], size_type size) : span(arr, typename Helper::bounds_type{size})
+    // construct from a single element
+    constexpr span(reference data) noexcept : span(&data, bounds_type{1})
     {
-        Expects(size <= N);
+        static_assert(bounds_type::dynamic_rank > 0 || bounds_type::static_size == 0 ||
+                          bounds_type::static_size == 1,
+                      "Construction from a single element only possible "
+                      "for dynamic or fixed spans of length 0 or 1.");
     }
 
-    // from std array
-    template <size_t N, 
-       typename Dummy = std::enable_if_t<std::is_convertible<static_bounds<N>, bounds_type>::value>
-    >
-    constexpr span (std::array<std::remove_const_t<value_type>, N> & arr) : span(arr.data(), static_bounds<N>())
-    {}
+    // prevent constructing from temporaries for single-elements
+    constexpr span(value_type&&) = delete;
 
-    template <size_t N,
-        typename Dummy = std::enable_if_t<std::is_convertible<static_bounds<N>, bounds_type>::value
-        && std::is_const<value_type>::value>
-    >
-    constexpr span (const std::array<std::remove_const_t<value_type>, N> & arr) : span(arr.data(), static_bounds<N>())
-    {}
-    
-    // from begin, end pointers. We don't provide iterator pair since no way to guarantee the contiguity 
+    // construct from pointer + length
+    constexpr span(pointer ptr, size_type size) noexcept : span(ptr, bounds_type{size}) {}
+
+    // construct from pointer + length - multidimensional
+    constexpr span(pointer data, bounds_type bounds) noexcept : data_(data),
+                                                                bounds_(std::move(bounds))
+    {
+        Expects((bounds_.size() > 0 && data != nullptr) || bounds_.size() == 0);
+    }
+
+    // construct from begin,end pointer pair
     template <typename Ptr,
-        typename Dummy = std::enable_if_t<std::is_convertible<Ptr, pointer>::value
-        && details::LessThan<bounds_type::dynamic_rank, 2>::value>
-    > // remove literal 0 case
-    constexpr span (pointer begin, Ptr end) : span(begin, details::newBoundsHelper<bounds_type>(static_cast<pointer>(end) - begin))
-    {}
+              typename = std::enable_if_t<std::is_convertible<Ptr, pointer>::value &&
+                                          details::LessThan<bounds_type::dynamic_rank, 2>::value>>
+    constexpr span(pointer begin, Ptr end)
+        : span(begin, details::newBoundsHelper<bounds_type>(static_cast<pointer>(end) - begin))
+    {
+        Expects(begin != nullptr && end != nullptr && begin <= static_cast<pointer>(end));
+    }
 
-    // from containers. It must has .size() and .data() two function signatures
+    // construct from n-dimensions static array
+    template <typename T, size_t N, typename Helper = details::SpanArrayTraits<T, N>>
+    constexpr span(T (&arr)[N])
+        : span(reinterpret_cast<pointer>(arr), bounds_type{typename Helper::bounds_type{}})
+    {
+        static_assert(
+            std::is_convertible<typename Helper::value_type(*) [], value_type(*) []>::value,
+            "Cannot convert from source type to target span type.");
+        static_assert(std::is_convertible<typename Helper::bounds_type, bounds_type>::value,
+                      "Cannot construct a span from an array with fewer elements.");
+    }
+
+    // construct from n-dimensions dynamic array (e.g. new int[m][4])
+    // (precedence will be lower than the 1-dimension pointer)
+    template <typename T, typename Helper = details::SpanArrayTraits<T, dynamic_range>>
+    constexpr span(T* const& data, size_type size)
+        : span(reinterpret_cast<pointer>(data), typename Helper::bounds_type{size})
+    {
+        static_assert(
+            std::is_convertible<typename Helper::value_type(*) [], value_type(*) []>::value,
+            "Cannot convert from source type to target span type.");
+    }
+
+    // construct from std::array
+    template <typename T, size_t N>
+    constexpr span(std::array<T, N>& arr) : span(arr.data(), bounds_type{static_bounds<N>{}})
+    {
+        static_assert(
+            std::is_convertible<T(*) [], typename std::remove_const_t<value_type>(*) []>::value,
+            "Cannot convert from source type to target span type.");
+        static_assert(std::is_convertible<static_bounds<N>, bounds_type>::value,
+                      "You cannot construct a span from a std::array of smaller size.");
+    }
+
+    // construct from const std::array
+    template <typename T, size_t N>
+    constexpr span(const std::array<std::remove_const_t<value_type>, N>& arr)
+        : span(arr.data(), static_bounds<N>())
+    {
+        static_assert(std::is_convertible<T(*) [], std::remove_const_t<value_type>>::value,
+                      "Cannot convert from source type to target span type.");
+        static_assert(std::is_convertible<static_bounds<N>, bounds_type>::value,
+                      "You cannot construct a span from a std::array of smaller size.");
+    }
+
+    // prevent constructing from temporary std::array
+    template <typename T, size_t N>
+    constexpr span(std::array<T, N>&& arr) = delete;
+
+    // construct from containers
+    // future: could use contiguous_iterator_traits to identify only contiguous containers
+    // type-requirements: container must have .size(), operator[] which are value_type compatible
     template <typename Cont, typename DataType = typename Cont::value_type,
-        typename Dummy = std::enable_if_t<!details::is_span<Cont>::value
-        && std::is_convertible<DataType (*)[], value_type (*)[]>::value
-        && std::is_same<std::decay_t<decltype(std::declval<Cont>().size(), *std::declval<Cont>().data())>, DataType>::value>
-    >
-    constexpr span (Cont& cont) : span(static_cast<pointer>(cont.data()), details::newBoundsHelper<bounds_type>(static_cast<size_type>(cont.size())))
-    {}
+              typename = std::enable_if_t<
+                  !details::is_span<Cont>::value &&
+                  std::is_convertible<DataType (*)[], value_type (*)[]>::value &&
+                  std::is_same<std::decay_t<decltype(std::declval<Cont>().size(),
+                                                     *std::declval<Cont>().data())>,
+                               DataType>::value>>
+    constexpr span(Cont& cont)
+        : span(static_cast<pointer>(cont.data()),
+               details::newBoundsHelper<bounds_type>(narrow_cast<size_type>(cont.size())))
+    {
+    }
 
-    constexpr span(const span &) = default;
+    // prevent constructing from temporary containers
+    template <typename Cont, typename DataType = typename Cont::value_type,
+              typename = std::enable_if_t<
+                  !details::is_span<Cont>::value &&
+                  std::is_convertible<DataType (*)[], value_type (*)[]>::value &&
+                  std::is_same<std::decay_t<decltype(std::declval<Cont>().size(),
+                                                     *std::declval<Cont>().data())>,
+                               DataType>::value>>
+    explicit constexpr span(Cont&& cont) = delete;
 
-    // convertible
+    // construct from a convertible span
     template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
-        typename OtherBounds = static_bounds<OtherDimensions...>,
-        typename Dummy = std::enable_if_t<std::is_convertible<OtherValueType, ValueType>::value && std::is_convertible<OtherBounds, bounds_type>::value>
-    >
-    constexpr span(const span<OtherValueType, OtherDimensions...>& other) noexcept
-        : m_pdata(other.m_pdata), m_bounds(other.m_bounds)
-    {}
-
-    // reshape
-    // DimCount here is a workaround for a bug in MSVC 2015
-    template <typename... Dimensions2, size_t DimCount = sizeof...(Dimensions2), bool Enabled = (DimCount > 0), typename Dummy = std::enable_if_t<Enabled>>
-    constexpr span<ValueType, Dimensions2::value...> as_span(Dimensions2... dims)
+              typename OtherBounds = static_bounds<OtherDimensions...>,
+              typename = std::enable_if_t<std::is_convertible<OtherValueType, ValueType>::value &&
+                                          std::is_convertible<OtherBounds, bounds_type>::value>>
+    constexpr span(span<OtherValueType, OtherDimensions...> other) noexcept : data_(other.data_),
+                                                                              bounds_(other.bounds_)
     {
-        using BoundsType = typename span<ValueType, (Dimensions2::value)...>::bounds_type;
-        auto tobounds = details::static_as_span_helper<BoundsType>(dims..., details::Sep{});
-        details::verifyBoundsReshape(this->bounds(), tobounds);
-        return {this->data(), tobounds};
     }
 
-    // to bytes array
-    template <bool Enabled = std::is_standard_layout<std::decay_t<ValueType>>::value>
-    auto as_bytes() const noexcept -> span<const byte>
-    {
-        static_assert(Enabled, "The value_type of span must be standarded layout");
-        return { reinterpret_cast<const byte*>(this->data()), this->bytes() };
-    }
+// trivial copy and move
+#ifndef GSL_MSVC_NO_SUPPORT_FOR_MOVE_CTOR_DEFAULT
+    constexpr span(span&&) = default;
+#endif
+    constexpr span(const span&) = default;
 
-    template <bool Enabled = std::is_standard_layout<std::decay_t<ValueType>>::value>
-    auto as_writeable_bytes() const noexcept -> span<byte>
-    {
-        static_assert(Enabled, "The value_type of span must be standarded layout");
-        return { reinterpret_cast<byte*>(this->data()), this->bytes() };
-    }
+// trivial assignment
+#ifndef GSL_MSVC_NO_SUPPORT_FOR_MOVE_CTOR_DEFAULT
+    constexpr span& operator=(span&&) = default;
+#endif
+    constexpr span& operator=(const span&) = default;
 
-    // from bytes array
-    template<typename U, bool IsByte = std::is_same<value_type, const byte>::value, typename = std::enable_if_t<IsByte && sizeof...(RestDimensions) == 0>>
-    constexpr auto as_span() const noexcept -> span<const U, (bounds_type::static_size != dynamic_range ? static_cast<std::ptrdiff_t>(static_cast<size_t>(bounds_type::static_size) / sizeof(U)) : dynamic_range)>
-    {
-        static_assert(std::is_standard_layout<U>::value && (bounds_type::static_size == dynamic_range || bounds_type::static_size % static_cast<size_type>(sizeof(U)) == 0),
-            "Target type must be standard layout and its size must match the byte array size");
-        Expects((this->bytes() % sizeof(U)) == 0 && (this->bytes() / sizeof(U)) < PTRDIFF_MAX);
-        return { reinterpret_cast<const U*>(this->data()), this->bytes() / static_cast<size_type>(sizeof(U)) };
-    }
-
-    template<typename U, bool IsByte = std::is_same<value_type, byte>::value, typename = std::enable_if_t<IsByte && sizeof...(RestDimensions) == 0>>
-    constexpr auto as_span() const noexcept -> span<U, (bounds_type::static_size != dynamic_range ? static_cast<ptrdiff_t>(static_cast<size_t>(bounds_type::static_size) / sizeof(U)) : dynamic_range)>
-    {
-        static_assert(std::is_standard_layout<U>::value && (bounds_type::static_size == dynamic_range || bounds_type::static_size % static_cast<size_t>(sizeof(U)) == 0),
-            "Target type must be standard layout and its size must match the byte array size");
-        Expects((this->bytes() % sizeof(U)) == 0);
-        return { reinterpret_cast<U*>(this->data()), this->bytes() / static_cast<size_type>(sizeof(U)) };
-    }
-
-    // section on linear space
-    template<std::ptrdiff_t Count>
+    // first() - extract the first Count elements into a new span
+    template <std::ptrdiff_t Count>
     constexpr span<ValueType, Count> first() const noexcept
     {
-        static_assert(bounds_type::static_size == dynamic_range || Count <= bounds_type::static_size, "Index is out of bound");
-        Expects(bounds_type::static_size != dynamic_range || Count <= this->size()); 
-        return { this->data(), Count };
+        static_assert(Count >= 0, "Count must be >= 0.");
+        static_assert(bounds_type::static_size == dynamic_range ||
+                          Count <= bounds_type::static_size,
+                      "Count is out of bounds.");
+
+        Expects(bounds_type::static_size != dynamic_range || Count <= this->size());
+        return {this->data(), Count};
     }
 
+    // first() - extract the first count elements into a new span
     constexpr span<ValueType, dynamic_range> first(size_type count) const noexcept
     {
-        Expects(count <= this->size());
-        return { this->data(), count };
+        Expects(count >= 0 && count <= this->size());
+        return {this->data(), count};
     }
 
-    template<std::ptrdiff_t Count>
+    // last() - extract the last Count elements into a new span
+    template <std::ptrdiff_t Count>
     constexpr span<ValueType, Count> last() const noexcept
     {
-        static_assert(bounds_type::static_size == dynamic_range || Count <= bounds_type::static_size, "Index is out of bound");
+        static_assert(Count >= 0, "Count must be >= 0.");
+        static_assert(bounds_type::static_size == dynamic_range ||
+                          Count <= bounds_type::static_size,
+                      "Count is out of bounds.");
+
         Expects(bounds_type::static_size != dynamic_range || Count <= this->size());
-        return { this->data() + this->size() - Count, Count };
+        return {this->data() + this->size() - Count, Count};
     }
 
+    // last() - extract the last count elements into a new span
     constexpr span<ValueType, dynamic_range> last(size_type count) const noexcept
     {
-        Expects(count <= this->size());
-        return { this->data() + this->size() - count, count };
+        Expects(count >= 0 && count <= this->size());
+        return {this->data() + this->size() - count, count};
     }
 
-    template<std::ptrdiff_t Offset, std::ptrdiff_t Count>
-    constexpr span<ValueType, Count> sub() const noexcept
+    // subspan() - create a subview of Count elements starting at Offset
+    template <std::ptrdiff_t Offset, std::ptrdiff_t Count>
+    constexpr span<ValueType, Count> subspan() const noexcept
     {
-        static_assert(bounds_type::static_size == dynamic_range || ((Offset == 0 || Offset <= bounds_type::static_size) && Offset + Count <= bounds_type::static_size), "Index is out of bound");
-        Expects(bounds_type::static_size != dynamic_range || ((Offset == 0 || Offset <= this->size()) && Offset + Count <= this->size()));
-        return { this->data() + Offset, Count };
+        static_assert(Count >= 0, "Count must be >= 0.");
+        static_assert(Offset >= 0, "Offset must be >= 0.");
+        static_assert(bounds_type::static_size == dynamic_range ||
+                          ((Offset <= bounds_type::static_size) &&
+                           Count <= bounds_type::static_size - Offset),
+                      "You must describe a sub-range within bounds of the span.");
+
+        Expects(bounds_type::static_size != dynamic_range ||
+                (Offset <= this->size() && Count <= this->size() - Offset));
+        return {this->data() + Offset, Count};
     }
 
-    constexpr span<ValueType, dynamic_range> sub(size_type offset, size_type count = dynamic_range) const noexcept
+    // subspan() - create a subview of count elements starting at offset
+    // supplying dynamic_range for count will consume all available elements from offset
+    constexpr span<ValueType, dynamic_range> subspan(size_type offset,
+                                                     size_type count = dynamic_range) const noexcept
     {
-        Expects((offset == 0 || offset <= this->size()) && (count == dynamic_range || (offset + count) <= this->size()));
-        return { this->data() + offset, count == dynamic_range ? this->length() - offset : count };
+        Expects((offset >= 0 && offset <= this->size()) &&
+                (count == dynamic_range || (count <= this->size() - offset)));
+        return {this->data() + offset, count == dynamic_range ? this->length() - offset : count};
     }
 
-    // size
-    constexpr size_type length() const noexcept
-    {
-        return this->size();
-    }
-
-    constexpr size_type used_length() const noexcept
-    {
-        return length();
-    }
-
-    constexpr size_type bytes() const noexcept
-    {
-        return sizeof(value_type) * this->size();
-    }
-
-    constexpr size_type used_bytes() const noexcept
-    {
-        return bytes();
-    }
-
-    // section
-    constexpr strided_span<ValueType, rank> section(index_type origin, index_type extents) const noexcept
+    // section - creates a non-contiguous, strided span from a contiguous one
+    constexpr strided_span<ValueType, Rank> section(index_type origin, index_type extents) const
+        noexcept
     {
         size_type size = this->bounds().total_size() - this->bounds().linearize(origin);
-        return{ &this->operator[](origin), size, strided_bounds<rank> {extents, details::make_stride(bounds())} };
-    }
-    
-    constexpr reference operator[](const index_type& idx) const noexcept
-    {
-        return m_pdata[m_bounds.linearize(idx)];
-    }
-    
-    template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
-    constexpr Ret operator[](size_type idx) const noexcept
-    {
-        Expects(idx < m_bounds.size()); // index is out of bounds of the array
-        const size_type ridx = idx * m_bounds.stride();
-
-        // index is out of bounds of the underlying data
-        Expects(ridx < m_bounds.total_size());
-        return Ret{ m_pdata + ridx, m_bounds.slice() };
+        return {&this->operator[](origin), size,
+                strided_bounds<Rank>{extents, details::make_stride(bounds())}};
     }
 
-    constexpr bounds_type bounds() const noexcept
-    {
-        return m_bounds;
-    }
+    // length of the span in elements
+    constexpr size_type size() const noexcept { return bounds_.size(); }
+
+    // length of the span in elements
+    constexpr size_type length() const noexcept { return this->size(); }
+
+    // length of the span in bytes
+    constexpr size_type size_bytes() const noexcept { return sizeof(value_type) * this->size(); }
+
+    // length of the span in bytes
+    constexpr size_type length_bytes() const noexcept { return this->size_bytes(); }
+
+    constexpr bool empty() const noexcept { return this->size() == 0; }
+
+    static constexpr std::size_t rank() { return Rank; }
 
     template <size_t Dim = 0>
     constexpr size_type extent() const noexcept
     {
-        static_assert(Dim < rank, "dimension should be less than rank (dimension count starts from 0)");
-        return m_bounds.template extent<Dim>();
+        static_assert(Dim < Rank,
+                      "Dimension should be less than rank (dimension count starts from 0).");
+        return bounds_.template extent<Dim>();
     }
 
-    constexpr size_type size() const noexcept
+    template <typename IntType>
+    constexpr size_type extent(IntType dim) const noexcept
     {
-        return m_bounds.size();
+        return bounds_.extent(dim);
     }
 
-    constexpr pointer data() const noexcept
+    constexpr bounds_type bounds() const noexcept { return bounds_; }
+
+    constexpr pointer data() const noexcept { return data_; }
+
+    template <typename FirstIndex>
+    constexpr reference operator()(FirstIndex index)
     {
-        return m_pdata;
+        return this->operator[](narrow_cast<std::ptrdiff_t>(index));
     }
 
-    constexpr explicit operator bool() const noexcept
+    template <typename FirstIndex, typename... OtherIndices>
+    constexpr reference operator()(FirstIndex index, OtherIndices... indices)
     {
-        return m_pdata != nullptr;
+        index_type idx = {narrow_cast<std::ptrdiff_t>(index),
+                          narrow_cast<std::ptrdiff_t>(indices...)};
+        return this->operator[](idx);
     }
 
-    constexpr iterator begin() const noexcept
+    constexpr reference operator[](const index_type& idx) const noexcept
     {
-        return iterator{ this, true };
+        return data_[bounds_.linearize(idx)];
     }
 
-    constexpr iterator end() const noexcept
+    template <bool Enabled = (Rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
+    constexpr Ret operator[](size_type idx) const noexcept
     {
-        return iterator{ this, false };
+        Expects(idx < bounds_.size()); // index is out of bounds of the array
+        const size_type ridx = idx * bounds_.stride();
+
+        // index is out of bounds of the underlying data
+        Expects(ridx < bounds_.total_size());
+        return Ret{data_ + ridx, bounds_.slice()};
     }
 
+    constexpr iterator begin() const noexcept { return iterator{this, true}; }
+
+    constexpr iterator end() const noexcept { return iterator{this, false}; }
+
     constexpr const_iterator cbegin() const noexcept
     {
-        return const_iterator{ reinterpret_cast<const const_span*>(this), true };
+        return const_iterator{reinterpret_cast<const const_span*>(this), true};
     }
 
     constexpr const_iterator cend() const noexcept
     {
-        return const_iterator{ reinterpret_cast<const const_span*>(this), false };
+        return const_iterator{reinterpret_cast<const const_span*>(this), false};
     }
 
-    constexpr reverse_iterator rbegin() const noexcept
-    {
-        return reverse_iterator{ end() };
-    }
+    constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
 
-    constexpr reverse_iterator rend() const noexcept
-    {
-        return reverse_iterator{ begin() };
-    }
+    constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
 
     constexpr const_reverse_iterator crbegin() const noexcept
     {
-        return const_reverse_iterator{ cend() };
+        return const_reverse_iterator{cend()};
     }
 
     constexpr const_reverse_iterator crend() const noexcept
     {
-        return const_reverse_iterator{ cbegin() };
+        return const_reverse_iterator{cbegin()};
     }
 
-    template <typename OtherValueType, std::ptrdiff_t... OtherDimensions, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
-    constexpr bool operator== (const span<OtherValueType, OtherDimensions...> & other) const noexcept
+    template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
+              typename Dummy = std::enable_if_t<std::is_same<
+                  std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
+    constexpr bool operator==(const span<OtherValueType, OtherDimensions...>& other) const noexcept
     {
-        return m_bounds.size() == other.m_bounds.size() &&
-            (m_pdata == other.m_pdata || std::equal(this->begin(), this->end(), other.begin()));
+        return bounds_.size() == other.bounds_.size() &&
+               (data_ == other.data_ || std::equal(this->begin(), this->end(), other.begin()));
     }
 
-    template <typename OtherValueType, std::ptrdiff_t... OtherDimensions, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
-    constexpr bool operator!= (const span<OtherValueType, OtherDimensions...> & other) const noexcept
+    template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
+              typename Dummy = std::enable_if_t<std::is_same<
+                  std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
+    constexpr bool operator!=(const span<OtherValueType, OtherDimensions...>& other) const noexcept
     {
         return !(*this == other);
     }
 
-    template <typename OtherValueType, std::ptrdiff_t... OtherDimensions, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
-    constexpr bool operator< (const span<OtherValueType, OtherDimensions...> & other) const noexcept
+    template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
+              typename Dummy = std::enable_if_t<std::is_same<
+                  std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
+    constexpr bool operator<(const span<OtherValueType, OtherDimensions...>& other) const noexcept
     {
         return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end());
     }
 
-    template <typename OtherValueType, std::ptrdiff_t... OtherDimensions, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
-    constexpr bool operator<= (const span<OtherValueType, OtherDimensions...> & other) const noexcept
+    template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
+              typename Dummy = std::enable_if_t<std::is_same<
+                  std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
+    constexpr bool operator<=(const span<OtherValueType, OtherDimensions...>& other) const noexcept
     {
         return !(other < *this);
     }
 
-    template <typename OtherValueType, std::ptrdiff_t... OtherDimensions, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
-    constexpr bool operator> (const span<OtherValueType, OtherDimensions...> & other) const noexcept
+    template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
+              typename Dummy = std::enable_if_t<std::is_same<
+                  std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
+    constexpr bool operator>(const span<OtherValueType, OtherDimensions...>& other) const noexcept
     {
         return (other < *this);
     }
 
-    template <typename OtherValueType, std::ptrdiff_t... OtherDimensions, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
-    constexpr bool operator>= (const span<OtherValueType, OtherDimensions...> & other) const noexcept
+    template <typename OtherValueType, std::ptrdiff_t... OtherDimensions,
+              typename Dummy = std::enable_if_t<std::is_same<
+                  std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
+    constexpr bool operator>=(const span<OtherValueType, OtherDimensions...>& other) const noexcept
     {
         return !(*this < other);
     }
 };
 
-template <typename T, std::ptrdiff_t... Dimensions>
-constexpr auto as_span(T* const& ptr, dim<Dimensions>... args) -> span<std::remove_all_extents_t<T>, Dimensions...>
+//
+// Free functions for manipulating spans
+//
+
+// reshape a span into a different dimensionality
+// DimCount and Enabled here are workarounds for a bug in MSVC 2015
+template <typename SpanType, typename... Dimensions2, size_t DimCount = sizeof...(Dimensions2),
+          bool Enabled = (DimCount > 0), typename = std::enable_if_t<Enabled>>
+constexpr span<typename SpanType::value_type, Dimensions2::value...> as_span(SpanType s,
+                                                                             Dimensions2... dims)
 {
-    return {reinterpret_cast<std::remove_all_extents_t<T>*>(ptr), details::static_as_span_helper<static_bounds<Dimensions...>>(args..., details::Sep{})};
+    static_assert(details::is_span<SpanType>::value,
+                  "Variadic as_span() is for reshaping existing spans.");
+    using BoundsType =
+        typename span<typename SpanType::value_type, (Dimensions2::value)...>::bounds_type;
+    auto tobounds = details::static_as_span_helper<BoundsType>(dims..., details::Sep{});
+    details::verifyBoundsReshape(s.bounds(), tobounds);
+    return {s.data(), tobounds};
+}
+
+// convert a span<T> to a span<const byte>
+template <typename U, std::ptrdiff_t... Dimensions>
+span<const byte, dynamic_range> as_bytes(span<U, Dimensions...> s) noexcept
+{
+    static_assert(std::is_trivial<std::decay_t<U>>::value,
+                  "The value_type of span must be a trivial type.");
+    return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
+}
+
+// convert a span<T> to a span<byte> (a writeable byte span)
+// this is not currently a portable function that can be relied upon to work
+// on all implementations. It should be considered an experimental extension
+// to the standard GSL interface.
+template <typename U, std::ptrdiff_t... Dimensions>
+span<byte> as_writeable_bytes(span<U, Dimensions...> s) noexcept
+{
+    static_assert(std::is_trivial<std::decay_t<U>>::value,
+                  "The value_type of span must be a trivial type.");
+    return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
+}
+
+// convert a span<const byte> to a span<const T>
+// this is not currently a portable function that can be relied upon to work
+// on all implementations. It should be considered an experimental extension
+// to the standard GSL interface.
+template <typename U, std::ptrdiff_t... Dimensions>
+constexpr auto as_span(span<const byte, Dimensions...> s) noexcept
+    -> span<const U, static_cast<std::ptrdiff_t>(
+                         span<const byte, Dimensions...>::bounds_type::static_size != dynamic_range
+                             ? (static_cast<size_t>(
+                                    span<const byte, Dimensions...>::bounds_type::static_size) /
+                                sizeof(U))
+                             : dynamic_range)>
+{
+    using ConstByteSpan = span<const byte, Dimensions...>;
+    static_assert(
+        std::is_trivial<std::decay_t<U>>::value &&
+            (ConstByteSpan::bounds_type::static_size == dynamic_range ||
+             ConstByteSpan::bounds_type::static_size % narrow_cast<std::ptrdiff_t>(sizeof(U)) == 0),
+        "Target type must be a trivial type and its size must match the byte array size");
+
+    Expects((s.size_bytes() % sizeof(U)) == 0 && (s.size_bytes() / sizeof(U)) < PTRDIFF_MAX);
+    return {reinterpret_cast<const U*>(s.data()),
+            s.size_bytes() / narrow_cast<std::ptrdiff_t>(sizeof(U))};
+}
+
+// convert a span<byte> to a span<T>
+// this is not currently a portable function that can be relied upon to work
+// on all implementations. It should be considered an experimental extension
+// to the standard GSL interface.
+template <typename U, std::ptrdiff_t... Dimensions>
+constexpr auto as_span(span<byte, Dimensions...> s) noexcept -> span<
+    U, narrow_cast<std::ptrdiff_t>(
+           span<byte, Dimensions...>::bounds_type::static_size != dynamic_range
+               ? static_cast<std::size_t>(span<byte, Dimensions...>::bounds_type::static_size) /
+                     sizeof(U)
+               : dynamic_range)>
+{
+    using ByteSpan = span<byte, Dimensions...>;
+    static_assert(
+        std::is_trivial<std::decay_t<U>>::value &&
+            (ByteSpan::bounds_type::static_size == dynamic_range ||
+             ByteSpan::bounds_type::static_size % static_cast<std::size_t>(sizeof(U)) == 0),
+        "Target type must be a trivial type and its size must match the byte array size");
+
+    Expects((s.bytes() % sizeof(U)) == 0);
+    return {reinterpret_cast<U*>(s.data()),
+            s.size_bytes() / narrow_cast<std::ptrdiff_t>(sizeof(U))};
+}
+
+template <typename T, std::ptrdiff_t... Dimensions>
+constexpr auto as_span(T* const& ptr, dim<Dimensions>... args)
+    -> span<std::remove_all_extents_t<T>, Dimensions...>
+{
+    return {reinterpret_cast<std::remove_all_extents_t<T>*>(ptr),
+            details::static_as_span_helper<static_bounds<Dimensions...>>(args..., details::Sep{})};
 }
 
 template <typename T>
-constexpr auto as_span (T* arr, std::ptrdiff_t len) -> typename details::SpanArrayTraits<T, dynamic_range>::type
+constexpr auto as_span(T* arr, std::ptrdiff_t len) ->
+    typename details::SpanArrayTraits<T, dynamic_range>::type
 {
     return {reinterpret_cast<std::remove_all_extents_t<T>*>(arr), len};
 }
 
 template <typename T, size_t N>
-constexpr auto as_span (T (&arr)[N]) -> typename details::SpanArrayTraits<T, N>::type
+constexpr auto as_span(T (&arr)[N]) -> typename details::SpanArrayTraits<T, N>::type
 {
     return {arr};
 }
 
 template <typename T, size_t N>
-constexpr span<const T, N> as_span(const std::array<T, N> &arr)
+constexpr span<const T, N> as_span(const std::array<T, N>& arr)
 {
     return {arr};
 }
 
 template <typename T, size_t N>
-constexpr span<const T, N> as_span(const std::array<T, N> &&) = delete;
+constexpr span<const T, N> as_span(const std::array<T, N>&&) = delete;
 
 template <typename T, size_t N>
-constexpr span<T, N> as_span(std::array<T, N> &arr)
+constexpr span<T, N> as_span(std::array<T, N>& arr)
 {
     return {arr};
 }
 
 template <typename T>
-constexpr span<T, dynamic_range> as_span(T *begin, T *end)
+constexpr span<T, dynamic_range> as_span(T* begin, T* end)
 {
     return {begin, end};
 }
 
 template <typename Cont>
-constexpr auto as_span(Cont &arr) -> std::enable_if_t<!details::is_span<std::decay_t<Cont>>::value,
+constexpr auto as_span(Cont& arr) -> std::enable_if_t<
+    !details::is_span<std::decay_t<Cont>>::value,
     span<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>>
 {
     Expects(arr.size() < PTRDIFF_MAX);
-    return {arr.data(), static_cast<std::ptrdiff_t>(arr.size())};
+    return {arr.data(), narrow_cast<std::ptrdiff_t>(arr.size())};
 }
 
 template <typename Cont>
-constexpr auto as_span(Cont &&arr) -> std::enable_if_t<!details::is_span<std::decay_t<Cont>>::value,
+constexpr auto as_span(Cont&& arr) -> std::enable_if_t<
+    !details::is_span<std::decay_t<Cont>>::value,
     span<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>> = delete;
 
 // from basic_string which doesn't have nonconst .data() member like other contiguous containers
 template <typename CharT, typename Traits, typename Allocator>
-constexpr auto as_span(std::basic_string<CharT, Traits, Allocator> &str) -> span<CharT, dynamic_range>
+constexpr auto as_span(std::basic_string<CharT, Traits, Allocator>& str)
+    -> span<CharT, dynamic_range>
 {
     Expects(str.size() < PTRDIFF_MAX);
-    return {&str[0], static_cast<std::ptrdiff_t>(str.size())};
+    return {&str[0], narrow_cast<std::ptrdiff_t>(str.size())};
 }
 
+// strided_span is an extension that is not strictly part of the GSL at this time.
+// It is kept here while the multidimensional interface is still being defined.
 template <typename ValueType, size_t Rank>
 class strided_span
 {
@@ -1601,11 +1757,12 @@
     using const_iterator = general_span_iterator<const_strided_span>;
     using reverse_iterator = std::reverse_iterator<iterator>;
     using const_reverse_iterator = std::reverse_iterator<const_iterator>;
-    using sliced_type = std::conditional_t<Rank == 1, value_type, strided_span<value_type, Rank-1>>;
+    using sliced_type =
+        std::conditional_t<Rank == 1, value_type, strided_span<value_type, Rank - 1>>;
 
 private:
-    pointer m_pdata;
-    bounds_type m_bounds;
+    pointer data_;
+    bounds_type bounds_;
 
     friend iterator;
     friend const_iterator;
@@ -1615,169 +1772,163 @@
 public:
     // from raw data
     constexpr strided_span(pointer ptr, size_type size, bounds_type bounds)
-        : m_pdata(ptr), m_bounds(std::move(bounds))
+        : data_(ptr), bounds_(std::move(bounds))
     {
-        Expects((m_bounds.size() > 0 && ptr != nullptr) || m_bounds.size() == 0);
+        Expects((bounds_.size() > 0 && ptr != nullptr) || bounds_.size() == 0);
         // Bounds cross data boundaries
         Expects(this->bounds().total_size() <= size);
-        (void)size;
+        (void) size;
     }
 
     // from static array of size N
-    template<size_type N>
-    constexpr strided_span(value_type(&values)[N], bounds_type bounds) : strided_span(values, N, std::move(bounds))
-    {}
+    template <size_type N>
+    constexpr strided_span(value_type (&values)[N], bounds_type bounds)
+        : strided_span(values, N, std::move(bounds))
+    {
+    }
 
     // from array view
     template <typename OtherValueType, std::ptrdiff_t... Dimensions,
-        bool Enabled1 = (sizeof...(Dimensions) == Rank),
-        bool Enabled2 = std::is_convertible<OtherValueType*, ValueType*>::value,
-        typename Dummy = std::enable_if_t<Enabled1 && Enabled2>
-    >
-    constexpr strided_span(span<OtherValueType, Dimensions...> av, bounds_type bounds) : strided_span(av.data(), av.bounds().total_size(), std::move(bounds))
-    {}
-    
+              bool Enabled1 = (sizeof...(Dimensions) == Rank),
+              bool Enabled2 = std::is_convertible<OtherValueType*, ValueType*>::value,
+              typename Dummy = std::enable_if_t<Enabled1 && Enabled2>>
+    constexpr strided_span(span<OtherValueType, Dimensions...> av, bounds_type bounds)
+        : strided_span(av.data(), av.bounds().total_size(), std::move(bounds))
+    {
+    }
+
     // convertible
-    template <typename OtherValueType,
-        typename Dummy = std::enable_if_t<std::is_convertible<OtherValueType(*)[], value_type(*)[]>::value>
-    >
+    template <typename OtherValueType, typename Dummy = std::enable_if_t<std::is_convertible<
+                                           OtherValueType (*)[], value_type (*)[]>::value>>
     constexpr strided_span(const strided_span<OtherValueType, Rank>& other)
-        : m_pdata(other.m_pdata), m_bounds(other.m_bounds)
-    {}
+        : data_(other.data_), bounds_(other.bounds_)
+    {
+    }
 
     // convert from bytes
     template <typename OtherValueType>
-    constexpr strided_span<typename std::enable_if<std::is_same<value_type, const byte>::value, OtherValueType>::type, Rank> as_strided_span() const
+    constexpr strided_span<
+        typename std::enable_if<std::is_same<value_type, const byte>::value, OtherValueType>::type,
+        Rank>
+    as_strided_span() const
     {
-        static_assert((sizeof(OtherValueType) >= sizeof(value_type)) && (sizeof(OtherValueType) % sizeof(value_type) == 0), "OtherValueType should have a size to contain a multiple of ValueTypes");
-        auto d = static_cast<size_type>(sizeof(OtherValueType) / sizeof(value_type));
+        static_assert((sizeof(OtherValueType) >= sizeof(value_type)) &&
+                          (sizeof(OtherValueType) % sizeof(value_type) == 0),
+                      "OtherValueType should have a size to contain a multiple of ValueTypes");
+        auto d = narrow_cast<size_type>(sizeof(OtherValueType) / sizeof(value_type));
 
         size_type size = this->bounds().total_size() / d;
-        return{ (OtherValueType*)this->data(), size, bounds_type{ resize_extent(this->bounds().index_bounds(), d), resize_stride(this->bounds().strides(), d)} };
+        return {(OtherValueType*) this->data(), size,
+                bounds_type{resize_extent(this->bounds().index_bounds(), d),
+                            resize_stride(this->bounds().strides(), d)}};
     }
 
     constexpr strided_span section(index_type origin, index_type extents) const
     {
         size_type size = this->bounds().total_size() - this->bounds().linearize(origin);
-        return { &this->operator[](origin), size, bounds_type {extents, details::make_stride(bounds())}};
+        return {&this->operator[](origin), size,
+                bounds_type{extents, details::make_stride(bounds())}};
     }
 
     constexpr reference operator[](const index_type& idx) const
     {
-        return m_pdata[m_bounds.linearize(idx)];
+        return data_[bounds_.linearize(idx)];
     }
 
     template <bool Enabled = (Rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
     constexpr Ret operator[](size_type idx) const
     {
-        Expects(idx < m_bounds.size()); // index is out of bounds of the array
-        const size_type ridx = idx * m_bounds.stride();
+        Expects(idx < bounds_.size()); // index is out of bounds of the array
+        const size_type ridx = idx * bounds_.stride();
 
         // index is out of bounds of the underlying data
-        Expects(ridx < m_bounds.total_size());
-        return{ m_pdata + ridx, m_bounds.slice().total_size(), m_bounds.slice() };
+        Expects(ridx < bounds_.total_size());
+        return {data_ + ridx, bounds_.slice().total_size(), bounds_.slice()};
     }
 
-    constexpr bounds_type bounds() const noexcept
-    {
-        return m_bounds;
-    }
+    constexpr bounds_type bounds() const noexcept { return bounds_; }
 
     template <size_t Dim = 0>
     constexpr size_type extent() const noexcept
     {
-        static_assert(Dim < Rank, "dimension should be less than Rank (dimension count starts from 0)");
-        return m_bounds.template extent<Dim>();
+        static_assert(Dim < Rank,
+                      "dimension should be less than Rank (dimension count starts from 0)");
+        return bounds_.template extent<Dim>();
     }
 
-    constexpr size_type size() const noexcept
-    {
-        return m_bounds.size();
-    }
+    constexpr size_type size() const noexcept { return bounds_.size(); }
 
-    constexpr pointer data() const noexcept
-    {
-        return m_pdata;
-    }
+    constexpr pointer data() const noexcept { return data_; }
 
-    constexpr explicit operator bool() const noexcept
-    {
-        return m_pdata != nullptr;
-    }
+    constexpr explicit operator bool() const noexcept { return data_ != nullptr; }
 
-    constexpr iterator begin() const
-    {
-        return iterator{ this, true };
-    }
+    constexpr iterator begin() const { return iterator{this, true}; }
 
-    constexpr iterator end() const
-    {
-        return iterator{ this, false };
-    }
+    constexpr iterator end() const { return iterator{this, false}; }
 
     constexpr const_iterator cbegin() const
     {
-        return const_iterator{ reinterpret_cast<const const_strided_span*>(this), true };
+        return const_iterator{reinterpret_cast<const const_strided_span*>(this), true};
     }
 
     constexpr const_iterator cend() const
     {
-        return const_iterator{ reinterpret_cast<const const_strided_span*>(this), false };
+        return const_iterator{reinterpret_cast<const const_strided_span*>(this), false};
     }
 
-    constexpr reverse_iterator rbegin() const
+    constexpr reverse_iterator rbegin() const { return reverse_iterator{end()}; }
+
+    constexpr reverse_iterator rend() const { return reverse_iterator{begin()}; }
+
+    constexpr const_reverse_iterator crbegin() const { return const_reverse_iterator{cend()}; }
+
+    constexpr const_reverse_iterator crend() const { return const_reverse_iterator{cbegin()}; }
+
+    template <typename OtherValueType, std::ptrdiff_t OtherRank,
+              typename Dummy = std::enable_if_t<std::is_same<
+                  std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
+    constexpr bool operator==(const strided_span<OtherValueType, OtherRank>& other) const noexcept
     {
-        return reverse_iterator{ end() };
+        return bounds_.size() == other.bounds_.size() &&
+               (data_ == other.data_ || std::equal(this->begin(), this->end(), other.begin()));
     }
 
-    constexpr reverse_iterator rend() const
-    {
-        return reverse_iterator{ begin() };
-    }
-
-    constexpr const_reverse_iterator crbegin() const
-    {
-        return const_reverse_iterator{ cend() };
-    }
-
-    constexpr const_reverse_iterator crend() const
-    {
-        return const_reverse_iterator{ cbegin() };
-    }
-
-    template <typename OtherValueType, std::ptrdiff_t OtherRank, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
-    constexpr bool operator== (const strided_span<OtherValueType, OtherRank>& other) const noexcept
-    {
-        return m_bounds.size() == other.m_bounds.size() &&
-            (m_pdata == other.m_pdata || std::equal(this->begin(), this->end(), other.begin()));
-    }
-
-    template <typename OtherValueType, std::ptrdiff_t OtherRank, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
-    constexpr bool operator!= (const strided_span<OtherValueType, OtherRank>& other) const noexcept
+    template <typename OtherValueType, std::ptrdiff_t OtherRank,
+              typename Dummy = std::enable_if_t<std::is_same<
+                  std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
+    constexpr bool operator!=(const strided_span<OtherValueType, OtherRank>& other) const noexcept
     {
         return !(*this == other);
     }
 
-    template <typename OtherValueType, std::ptrdiff_t OtherRank, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
-    constexpr bool operator< (const strided_span<OtherValueType, OtherRank>& other) const noexcept
+    template <typename OtherValueType, std::ptrdiff_t OtherRank,
+              typename Dummy = std::enable_if_t<std::is_same<
+                  std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
+    constexpr bool operator<(const strided_span<OtherValueType, OtherRank>& other) const noexcept
     {
         return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end());
     }
 
-    template <typename OtherValueType, std::ptrdiff_t OtherRank, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
-    constexpr bool operator<= (const strided_span<OtherValueType, OtherRank>& other) const noexcept
+    template <typename OtherValueType, std::ptrdiff_t OtherRank,
+              typename Dummy = std::enable_if_t<std::is_same<
+                  std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
+    constexpr bool operator<=(const strided_span<OtherValueType, OtherRank>& other) const noexcept
     {
         return !(other < *this);
     }
 
-    template <typename OtherValueType, std::ptrdiff_t OtherRank, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
-    constexpr bool operator> (const strided_span<OtherValueType, OtherRank>& other) const noexcept
+    template <typename OtherValueType, std::ptrdiff_t OtherRank,
+              typename Dummy = std::enable_if_t<std::is_same<
+                  std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
+    constexpr bool operator>(const strided_span<OtherValueType, OtherRank>& other) const noexcept
     {
         return (other < *this);
     }
 
-    template <typename OtherValueType, std::ptrdiff_t OtherRank, typename Dummy = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
-    constexpr bool operator>= (const strided_span<OtherValueType, OtherRank>& other) const noexcept
+    template <typename OtherValueType, std::ptrdiff_t OtherRank,
+              typename Dummy = std::enable_if_t<std::is_same<
+                  std::remove_cv_t<value_type>, std::remove_cv_t<OtherValueType>>::value>>
+    constexpr bool operator>=(const strided_span<OtherValueType, OtherRank>& other) const noexcept
     {
         return !(*this < other);
     }
@@ -1795,7 +1946,7 @@
     }
 
     template <bool Enabled = (Rank == 1), typename Dummy = std::enable_if_t<Enabled>>
-    static index_type resize_stride(const index_type& strides, std::ptrdiff_t , void * = 0)
+    static index_type resize_stride(const index_type& strides, std::ptrdiff_t, void* = 0)
     {
         // Only strided arrays with regular strides can be resized
         Expects(strides[Rank - 1] == 1);
@@ -1812,8 +1963,7 @@
         // memory that can contain a multiple of new type elements
         Expects(strides[Rank - 2] >= d && (strides[Rank - 2] % d == 0));
 
-        for (size_t i = Rank - 1; i > 0; --i)
-        {
+        for (size_t i = Rank - 1; i > 0; --i) {
             // Only strided arrays with regular strides can be resized
             Expects((strides[i - 1] >= strides[i]) && (strides[i - 1] % strides[i] == 0));
         }
@@ -1826,9 +1976,11 @@
 };
 
 template <class Span>
-class contiguous_span_iterator : public std::iterator<std::random_access_iterator_tag, typename Span::value_type>
+class contiguous_span_iterator
+    : public std::iterator<std::random_access_iterator_tag, typename Span::value_type>
 {
     using Base = std::iterator<std::random_access_iterator_tag, typename Span::value_type>;
+
 public:
     using typename Base::reference;
     using typename Base::pointer;
@@ -1838,33 +1990,36 @@
     template <typename ValueType, std::ptrdiff_t FirstDimension, std::ptrdiff_t... RestDimensions>
     friend class span;
 
-    pointer m_pdata;
+    pointer data_;
     const Span* m_validator;
     void validateThis() const
     {
         // iterator is out of range of the array
-        Expects(m_pdata >= m_validator->m_pdata &&
-            m_pdata < m_validator->m_pdata + m_validator->size());
+        Expects(data_ >= m_validator->data_ && data_ < m_validator->data_ + m_validator->size());
     }
-    contiguous_span_iterator (const Span* container, bool isbegin) :
-        m_pdata(isbegin ? container->m_pdata : container->m_pdata + container->size()), m_validator(container) {}
+    contiguous_span_iterator(const Span* container, bool isbegin)
+        : data_(isbegin ? container->data_ : container->data_ + container->size())
+        , m_validator(container)
+    {
+    }
+
 public:
     reference operator*() const noexcept
     {
         validateThis();
-        return *m_pdata;
+        return *data_;
     }
     pointer operator->() const noexcept
     {
         validateThis();
-        return m_pdata;
+        return data_;
     }
     contiguous_span_iterator& operator++() noexcept
     {
-        ++m_pdata;
+        ++data_;
         return *this;
     }
-    contiguous_span_iterator operator++(int)noexcept
+    contiguous_span_iterator operator++(int) noexcept
     {
         auto ret = *this;
         ++(*this);
@@ -1872,10 +2027,10 @@
     }
     contiguous_span_iterator& operator--() noexcept
     {
-        --m_pdata;
+        --data_;
         return *this;
     }
-    contiguous_span_iterator operator--(int)noexcept
+    contiguous_span_iterator operator--(int) noexcept
     {
         auto ret = *this;
         --(*this);
@@ -1883,104 +2038,87 @@
     }
     contiguous_span_iterator operator+(difference_type n) const noexcept
     {
-        contiguous_span_iterator ret{ *this };
+        contiguous_span_iterator ret{*this};
         return ret += n;
     }
     contiguous_span_iterator& operator+=(difference_type n) noexcept
     {
-        m_pdata += n;
+        data_ += n;
         return *this;
     }
     contiguous_span_iterator operator-(difference_type n) const noexcept
     {
-        contiguous_span_iterator ret{ *this };
+        contiguous_span_iterator ret{*this};
         return ret -= n;
     }
-    contiguous_span_iterator& operator-=(difference_type n) noexcept
-    {
-        return *this += -n;
-    }
+    contiguous_span_iterator& operator-=(difference_type n) noexcept { return * this += -n; }
     difference_type operator-(const contiguous_span_iterator& rhs) const noexcept
     {
         Expects(m_validator == rhs.m_validator);
-        return m_pdata - rhs.m_pdata;
+        return data_ - rhs.data_;
     }
-    reference operator[](difference_type n) const noexcept
-    {
-        return *(*this + n);
-    }
+    reference operator[](difference_type n) const noexcept { return *(*this + n); }
     bool operator==(const contiguous_span_iterator& rhs) const noexcept
     {
         Expects(m_validator == rhs.m_validator);
-        return m_pdata == rhs.m_pdata;
+        return data_ == rhs.data_;
     }
-    bool operator!=(const contiguous_span_iterator& rhs) const noexcept
-    {
-        return !(*this == rhs);
-    }
+    bool operator!=(const contiguous_span_iterator& rhs) const noexcept { return !(*this == rhs); }
     bool operator<(const contiguous_span_iterator& rhs) const noexcept
     {
         Expects(m_validator == rhs.m_validator);
-        return m_pdata < rhs.m_pdata;
+        return data_ < rhs.data_;
     }
-    bool operator<=(const contiguous_span_iterator& rhs) const noexcept
-    {
-        return !(rhs < *this);
-    }
-    bool operator>(const contiguous_span_iterator& rhs) const noexcept
-    {
-        return rhs < *this;
-    }
-    bool operator>=(const contiguous_span_iterator& rhs) const noexcept
-    {
-        return !(rhs > *this);
-    }
+    bool operator<=(const contiguous_span_iterator& rhs) const noexcept { return !(rhs < *this); }
+    bool operator>(const contiguous_span_iterator& rhs) const noexcept { return rhs < *this; }
+    bool operator>=(const contiguous_span_iterator& rhs) const noexcept { return !(rhs > *this); }
     void swap(contiguous_span_iterator& rhs) noexcept
     {
-        std::swap(m_pdata, rhs.m_pdata);
+        std::swap(data_, rhs.data_);
         std::swap(m_validator, rhs.m_validator);
     }
 };
 
 template <typename Span>
-contiguous_span_iterator<Span> operator+(typename contiguous_span_iterator<Span>::difference_type n, const contiguous_span_iterator<Span>& rhs) noexcept
+contiguous_span_iterator<Span> operator+(typename contiguous_span_iterator<Span>::difference_type n,
+                                         const contiguous_span_iterator<Span>& rhs) noexcept
 {
     return rhs + n;
 }
 
 template <typename Span>
-class general_span_iterator : public std::iterator<std::random_access_iterator_tag, typename Span::value_type>
+class general_span_iterator
+    : public std::iterator<std::random_access_iterator_tag, typename Span::value_type>
 {
     using Base = std::iterator<std::random_access_iterator_tag, typename Span::value_type>;
+
 public:
     using typename Base::reference;
     using typename Base::pointer;
     using typename Base::difference_type;
     using typename Base::value_type;
+
 private:
     template <typename ValueType, size_t Rank>
     friend class strided_span;
-    
+
     const Span* m_container;
     typename Span::bounds_type::iterator m_itr;
-    general_span_iterator(const Span* container, bool isbegin) :
-        m_container(container), m_itr(isbegin ? m_container->bounds().begin() : m_container->bounds().end())
-    {}
+    general_span_iterator(const Span* container, bool isbegin)
+        : m_container(container)
+        , m_itr(isbegin ? m_container->bounds().begin() : m_container->bounds().end())
+    {
+    }
+
 public:
-    reference operator*() noexcept
-    {
-        return (*m_container)[*m_itr];
-    }
-    pointer operator->() noexcept
-    {
-        return &(*m_container)[*m_itr];
-    }
+    reference operator*() noexcept { return (*m_container)[*m_itr]; }
+    pointer operator->() noexcept { return &(*m_container)[*m_itr]; }
     general_span_iterator& operator++() noexcept
     {
         ++m_itr;
         return *this;
     }
-    general_span_iterator operator++(int)noexcept
+    general_span_iterator operator++(int) noexcept
     {
         auto ret = *this;
         ++(*this);
@@ -1991,7 +2129,7 @@
         --m_itr;
         return *this;
     }
-    general_span_iterator operator--(int)noexcept
+    general_span_iterator operator--(int) noexcept
     {
         auto ret = *this;
         --(*this);
@@ -1999,7 +2137,7 @@
     }
     general_span_iterator operator+(difference_type n) const noexcept
     {
-        general_span_iterator ret{ *this };
+        general_span_iterator ret{*this};
         return ret += n;
     }
     general_span_iterator& operator+=(difference_type n) noexcept
@@ -2009,13 +2147,10 @@
     }
     general_span_iterator operator-(difference_type n) const noexcept
     {
-        general_span_iterator ret{ *this };
+        general_span_iterator ret{*this};
         return ret -= n;
     }
-    general_span_iterator& operator-=(difference_type n) noexcept
-    {
-        return *this += -n;
-    }
+    general_span_iterator& operator-=(difference_type n) noexcept { return * this += -n; }
     difference_type operator-(const general_span_iterator& rhs) const noexcept
     {
         Expects(m_container == rhs.m_container);
@@ -2023,34 +2158,23 @@
     }
     value_type operator[](difference_type n) const noexcept
     {
-        return (*m_container)[m_itr[n]];;
+        return (*m_container)[m_itr[n]];
+        ;
     }
     bool operator==(const general_span_iterator& rhs) const noexcept
     {
         Expects(m_container == rhs.m_container);
         return m_itr == rhs.m_itr;
     }
-    bool operator !=(const general_span_iterator& rhs) const noexcept
-    {
-        return !(*this == rhs);
-    }
+    bool operator!=(const general_span_iterator& rhs) const noexcept { return !(*this == rhs); }
     bool operator<(const general_span_iterator& rhs) const noexcept
     {
         Expects(m_container == rhs.m_container);
         return m_itr < rhs.m_itr;
     }
-    bool operator<=(const general_span_iterator& rhs) const noexcept
-    {
-        return !(rhs < *this);
-    }
-    bool operator>(const general_span_iterator& rhs) const noexcept
-    {
-        return rhs < *this;
-    }
-    bool operator>=(const general_span_iterator& rhs) const noexcept
-    {
-        return !(rhs > *this);
-    }
+    bool operator<=(const general_span_iterator& rhs) const noexcept { return !(rhs < *this); }
+    bool operator>(const general_span_iterator& rhs) const noexcept { return rhs < *this; }
+    bool operator>=(const general_span_iterator& rhs) const noexcept { return !(rhs > *this); }
     void swap(general_span_iterator& rhs) noexcept
     {
         std::swap(m_itr, rhs.m_itr);
@@ -2059,14 +2183,14 @@
 };
 
 template <typename Span>
-general_span_iterator<Span> operator+(typename general_span_iterator<Span>::difference_type n, const general_span_iterator<Span>& rhs) noexcept
+general_span_iterator<Span> operator+(typename general_span_iterator<Span>::difference_type n,
+                                      const general_span_iterator<Span>& rhs) noexcept
 {
     return rhs + n;
 }
 
 } // namespace gsl
 
-
 #ifdef _MSC_VER
 
 #undef constexpr
@@ -2080,13 +2204,13 @@
 #pragma pop_macro("noexcept")
 #endif // GSL_THROW_ON_CONTRACT_VIOLATION
 
-#undef GSL_MSVC_HAS_VARIADIC_CTOR_BUG 
+#undef GSL_MSVC_HAS_VARIADIC_CTOR_BUG
 
 #endif // _MSC_VER <= 1800
 
 #endif // _MSC_VER
 
-#if defined(GSL_THROW_ON_CONTRACT_VIOLATION) 
+#if defined(GSL_THROW_ON_CONTRACT_VIOLATION)
 
 #undef noexcept
 
@@ -2095,7 +2219,6 @@
 #pragma pop_macro("noexcept")
 #endif
 
-#endif // GSL_THROW_ON_CONTRACT_VIOLATION 
-
+#endif // GSL_THROW_ON_CONTRACT_VIOLATION
 
 #endif // GSL_SPAN_H