Merge branch 'master' into dev/neilmac/contracts
diff --git a/include/fail_fast.h b/include/fail_fast.h
deleted file mode 100644
index b9982eb..0000000
--- a/include/fail_fast.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/////////////////////////////////////////////////////////////////////////////// 
-// 
-// Copyright (c) 2015 Microsoft Corporation. All rights reserved. 
-// 
-// This code is licensed under the MIT License (MIT). 
-// 
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
-// THE SOFTWARE. 
-// 
-///////////////////////////////////////////////////////////////////////////////
-
-#pragma once
-
-#ifndef GSL_FAIL_FAST_H
-#define GSL_FAIL_FAST_H
-
-#include <exception>
-
-#if defined(GSL_THROWS_FOR_TESTING)
-#include <stdexcept>
-#endif
-
-namespace gsl
-{
-
-//
-// Having "fail fast" result in an exception makes unit testing
-// the GSL classes that rely upon it much simpler. 
-//
-#if defined(GSL_THROWS_FOR_TESTING)
-
-struct fail_fast : public std::runtime_error 
-{
-	fail_fast() : std::runtime_error("") {}
-	explicit fail_fast(char const* const message) : std::runtime_error(message) {}
-};
-
-inline void fail_fast_assert(bool cond) { if (!cond) throw fail_fast(); }
-inline void fail_fast_assert(bool cond, const char* const message) { if (!cond) throw fail_fast(message); }
-
-#else
-
-inline void fail_fast_assert(bool cond) { if (!cond) std::terminate(); }
-inline void fail_fast_assert(bool cond, const char* const) { if (!cond) std::terminate(); }
-
-#endif // GSL_THROWS_FOR_TESTING
-
-}
-
-#endif // GSL_FAIL_FAST_H
diff --git a/include/gsl.h b/include/gsl.h
index bcaf57a..0575d57 100644
--- a/include/gsl.h
+++ b/include/gsl.h
@@ -19,6 +19,7 @@
 #ifndef GSL_GSL_H
 #define GSL_GSL_H
 
+#include "gsl_assert.h"  // Ensures/Expects
 #include "span.h"           // span, strided_span...
 #include "string_span.h"    // zstring, string_span, zstring_builder...
 #include <memory>
@@ -27,15 +28,13 @@
 
 // No MSVC does constexpr fully yet
 #pragma push_macro("constexpr")
-#define constexpr /* nothing */
+#define constexpr 
 
 // MSVC 2013 workarounds
 #if _MSC_VER <= 1800
-
 // noexcept is not understood 
-#ifndef GSL_THROWS_FOR_TESTING
-#define noexcept /* nothing */ 
-#endif
+#pragma push_macro("noexcept")
+#define noexcept  
 
 // turn off some misguided warnings
 #pragma warning(push)
@@ -45,11 +44,6 @@
 
 #endif // _MSC_VER
 
-// In order to test the library, we need it to throw exceptions that we can catch
-#ifdef GSL_THROWS_FOR_TESTING
-#define noexcept /* nothing */ 
-#endif // GSL_THROWS_FOR_TESTING 
-
 
 namespace gsl
 {
@@ -64,12 +58,6 @@
 using owner = T;
 
 //
-// GSL.assert: assertions
-//
-#define Expects(x)  gsl::fail_fast_assert((x))
-#define Ensures(x)  gsl::fail_fast_assert((x))
-
-//
 // GSL.util: utilities
 //
 
@@ -110,14 +98,14 @@
 //
 // at() - Bounds-checked way of accessing static arrays, std::array, std::vector
 //
-template <class T, size_t N>
-T& at(T(&arr)[N], size_t index) { fail_fast_assert(index < N); return arr[index]; }
+template <class T, size_t N> 
+T& at(T(&arr)[N], size_t index) { Expects(index < N); return arr[index]; }
 
 template <class T, size_t N>
-T& at(std::array<T, N>& arr, size_t index) { fail_fast_assert(index < N); return arr[index]; }
+T& at(std::array<T, N>& arr, size_t index) { Expects(index < N); return arr[index]; }
 
 template <class Cont>
-typename Cont::value_type& at(Cont& cont, size_t index) { fail_fast_assert(index < cont.size()); return cont[index]; }
+typename Cont::value_type& at(Cont& cont, size_t index) { Expects(index < cont.size()); return cont[index]; }
 
 
 //
@@ -181,7 +169,7 @@
 
     // we assume that the compiler can hoist/prove away most of the checks inlined from this function
     // if not, we could make them optional via conditional compilation
-    void ensure_invariant() const { fail_fast_assert(ptr_ != nullptr); }
+    void ensure_invariant() const { Expects(ptr_ != nullptr); }
 
     // unwanted operators...pointers only point to single objects!
     // TODO ensure all arithmetic ops on this type are unavailable
@@ -216,18 +204,14 @@
 #pragma pop_macro("constexpr")
 
 #if _MSC_VER <= 1800
-#pragma warning(pop)
 
-#ifndef GSL_THROWS_FOR_TESTING
 #undef noexcept
-#endif // GSL_THROWS_FOR_TESTING
+#pragma pop_macro("noexcept")
+ 
+#pragma warning(pop)
 
 #endif // _MSC_VER <= 1800
 
 #endif // _MSC_VER
 
-#if defined(GSL_THROWS_FOR_TESTING) 
-#undef noexcept 
-#endif // GSL_THROWS_FOR_TESTING 
-
 #endif // GSL_GSL_H
diff --git a/include/gsl_assert.h b/include/gsl_assert.h
new file mode 100644
index 0000000..4a40552
--- /dev/null
+++ b/include/gsl_assert.h
@@ -0,0 +1,78 @@
+/////////////////////////////////////////////////////////////////////////////// 
+// 
+// Copyright (c) 2015 Microsoft Corporation. All rights reserved. 
+// 
+// This code is licensed under the MIT License (MIT). 
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
+// THE SOFTWARE. 
+// 
+///////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#ifndef GSL_CONTRACTS_H
+#define GSL_CONTRACTS_H
+
+#include <exception>
+
+//
+// There are three configuration options for this GSL implementation's behavior
+// when pre/post conditions on the GSL types are violated:
+//
+// 1. GSL_TERMINATE_ON_CONTRACT_VIOLATION: std::terminate will be called (default)
+// 2. GSL_THROW_ON_CONTRACT_VIOLATION: a gsl::fail_fast exception will be thrown
+// 3. GSL_UNENFORCED_ON_CONTRACT_VIOLATION: nothing happens  
+//
+#if !(defined(GSL_THROW_ON_CONTRACT_VIOLATION) ^ defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION) ^ defined(GSL_UNENFORCED_ON_CONTRACT_VIOLATION))
+#define GSL_TERMINATE_ON_CONTRACT_VIOLATION 
+#endif
+
+
+#define GSL_STRINGIFY_DETAIL(x) #x
+#define GSL_STRINGIFY(x) GSL_STRINGIFY_DETAIL(x)
+
+
+//
+// GSL.assert: assertions
+//
+
+#if defined(GSL_THROW_ON_CONTRACT_VIOLATION)
+
+#include <stdexcept>
+
+namespace gsl
+{
+struct fail_fast : public std::runtime_error 
+{
+	explicit fail_fast(char const* const message) : std::runtime_error(message) {}   
+};
+}
+
+#define Expects(cond)  if (!(cond)) \
+    throw gsl::fail_fast("GSL: Precondition failure at " __FILE__ GSL_STRINGIFY(__LINE__));
+#define Ensures(cond)  if (!(cond)) \
+    throw gsl::fail_fast("GSL: Postcondition failure at " __FILE__ GSL_STRINGIFY(__LINE__));
+
+
+#elif defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION)
+
+
+#define Expects(cond)           if (!(cond)) std::terminate(); 
+#define Ensures(cond)           if (!(cond)) std::terminate();
+
+
+#elif defined(GSL_UNENFORCED_ON_CONTRACT_VIOLATION)
+
+#define Expects(cond)           
+#define Ensures(cond)           
+
+#endif 
+
+
+#endif // GSL_CONTRACTS_H
diff --git a/include/span.h b/include/span.h
index 2bf9d20..0c67d22 100644
--- a/include/span.h
+++ b/include/span.h
@@ -31,13 +31,18 @@
 #include <stdexcept>
 #include <type_traits>
 #include <utility>
-#include "fail_fast.h"
+#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
+
 // No MSVC does constexpr fully yet
 #pragma push_macro("constexpr")
-#define constexpr /* nothing */
+#define constexpr
 
 // VS 2013 workarounds
 #if _MSC_VER <= 1800
@@ -46,7 +51,7 @@
 #define GSL_MSVC_HAS_VARIADIC_CTOR_BUG 
 
 // noexcept is not understood 
-#ifndef GSL_THROWS_FOR_TESTING
+#ifndef GSL_THROWS_ON_CONTRACT_VIOLATION
 #pragma push_macro("noexcept")
 #define noexcept /* nothing */ 
 #endif
@@ -60,8 +65,7 @@
 
 #endif // _MSC_VER
 
-// In order to test the library, we need it to throw exceptions that we can catch
-#ifdef GSL_THROWS_FOR_TESTING
+#ifdef GSL_THROW_ON_CONTRACT_VIOLATION
 
 #ifdef _MSC_VER
 #pragma push_macro("noexcept")
@@ -69,7 +73,7 @@
 
 #define noexcept /* nothing */ 
 
-#endif // GSL_THROWS_FOR_TESTING 
+#endif // GSL_THROW_ON_CONTRACT_VIOLATION 
 
 
 namespace gsl {
@@ -137,14 +141,14 @@
     // Preconditions: component_idx < rank
     constexpr reference operator[](size_t component_idx)
     {
-        fail_fast_assert(component_idx < Rank, "Component index must be less than rank");
+        Expects(component_idx < Rank); // Component index must be less than rank
         return elems[component_idx];
     }
 
     // Preconditions: component_idx < rank
     constexpr const_reference operator[](size_t component_idx) const noexcept
     {
-        fail_fast_assert(component_idx < Rank, "Component index must be less than rank");
+        Expects(component_idx < Rank); // Component index must be less than rank
         return elems[component_idx];
     }
 
@@ -344,7 +348,7 @@
         
             BoundsRanges(const std::ptrdiff_t* const arr) : Base(arr + 1), m_bound(*arr * this->Base::totalSize())
         {
-            fail_fast_assert(0 <= *arr);
+            Expects(0 <= *arr);
         }
 
         BoundsRanges() : m_bound(0) {}
@@ -365,7 +369,7 @@
         size_type linearize(const T& arr) const
         { 
             const size_type index = this->Base::totalSize() * arr[Dim];
-            fail_fast_assert(index < m_bound);
+            Expects(index < m_bound);
             return index + this->Base::template linearize<T, Dim + 1>(arr);
         }
         
@@ -419,8 +423,9 @@
 
         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)
-        {
-            fail_fast_assert((firstLevel && totalSize() <= other.totalSize()) || totalSize() == other.totalSize());
+        {            
+            Expects((firstLevel && totalSize() <= other.totalSize()) || totalSize() == other.totalSize());
+            (void)firstLevel;
         }
 
         template <typename T, size_t Dim = 0>
@@ -433,7 +438,7 @@
         template <typename T, size_t Dim = 0>
         size_type linearize(const T& arr) const
         {  
-            fail_fast_assert(arr[Dim] < CurrentRange, "Index is out of range");
+            Expects(arr[Dim] < CurrentRange); // Index is out of range
             return this->Base::totalSize() * arr[Dim] + this->Base::template linearize<T, Dim + 1>(arr);
         }
 
@@ -584,8 +589,10 @@
                                                        
     constexpr static_bounds(std::initializer_list<size_type> il) : m_ranges((const std::ptrdiff_t*)il.begin())
     {
-        fail_fast_assert((MyRanges::DynamicNum == 0 && il.size() == 1 && *il.begin() == static_size) || MyRanges::DynamicNum == il.size(), "Size of the initializer list must match the rank of the array");
-        fail_fast_assert(m_ranges.totalSize() <= PTRDIFF_MAX, "Size of the range is larger than the max element of the size type");
+        // 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()); 
+        // Size of the range must be less than the max element of the size type
+        Expects(m_ranges.totalSize() <= PTRDIFF_MAX); 
     }
     
     constexpr static_bounds() = default;
@@ -742,7 +749,7 @@
         size_type ret = 0;
         for (size_t i = 0; i < rank; i++)
         {
-            fail_fast_assert(idx[i] < m_extents[i], "index is out of bounds of the array");
+            Expects(idx[i] < m_extents[i]); // index is out of bounds of the array
             ret += idx[i] * m_strides[i];
         }
         return ret;
@@ -868,7 +875,7 @@
         }
         // If we're here the preconditions were violated
         // "pre: there exists s such that r == ++s"
-        fail_fast_assert(false);
+        Expects(false); 
         return *this;
     }
 
@@ -899,7 +906,8 @@
             curr[i] = linear_idx / stride[i];
             linear_idx = linear_idx % stride[i];
         }
-        fail_fast_assert(!less(curr, index_type{}) && !less(boundary, curr), "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;
     }
 
@@ -1038,7 +1046,7 @@
         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");
-        fail_fast_assert(src.size() == dest.size());
+        Expects(src.size() == dest.size());
     }
 
 
@@ -1099,13 +1107,13 @@
     template <typename BoundsType>
     BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::true_type) // dynamic size
     {
-        fail_fast_assert(totalSize <= PTRDIFF_MAX);
+        Expects(totalSize <= PTRDIFF_MAX);
         return BoundsType{totalSize};
     }
     template <typename BoundsType>
     BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::false_type) // static size
     {
-        fail_fast_assert(BoundsType::static_size == totalSize);
+        Expects(BoundsType::static_size == totalSize);
         return {};
     }
     template <typename BoundsType>
@@ -1192,7 +1200,7 @@
     constexpr span(pointer data, bounds_type bounds) noexcept
         : m_pdata(data), m_bounds(std::move(bounds))
     {
-        fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0);
+        Expects((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0);
     }
 
     constexpr span(pointer ptr, size_type size) noexcept
@@ -1206,7 +1214,7 @@
     constexpr span(std::nullptr_t, size_type size) noexcept
         : span(nullptr, bounds_type{})
     {
-        fail_fast_assert(size == 0);
+        Expects(size == 0);
     }
 
     // default
@@ -1236,7 +1244,7 @@
     >
     constexpr span(T(&arr)[N], size_type size) : span(arr, typename Helper::bounds_type{size})
     {
-        fail_fast_assert(size <= N);
+        Expects(size <= N);
     }
 
     // from std array
@@ -1313,7 +1321,7 @@
     {
         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");
-        fail_fast_assert((this->bytes() % sizeof(U)) == 0 && (this->bytes() / sizeof(U)) < PTRDIFF_MAX);
+        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)) };
     }
 
@@ -1322,7 +1330,7 @@
     {
         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");
-        fail_fast_assert((this->bytes() % sizeof(U)) == 0);
+        Expects((this->bytes() % sizeof(U)) == 0);
         return { reinterpret_cast<U*>(this->data()), this->bytes() / static_cast<size_type>(sizeof(U)) };
     }
 
@@ -1331,13 +1339,13 @@
     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");
-        fail_fast_assert(bounds_type::static_size != dynamic_range || Count <= this->size()); // ensures we only check condition when needed
+        Expects(bounds_type::static_size != dynamic_range || Count <= this->size()); 
         return { this->data(), Count };
     }
 
     constexpr span<ValueType, dynamic_range> first(size_type count) const noexcept
     {
-        fail_fast_assert(count <= this->size());
+        Expects(count <= this->size());
         return { this->data(), count };
     }
 
@@ -1345,13 +1353,13 @@
     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");
-        fail_fast_assert(bounds_type::static_size != dynamic_range || Count <= this->size());
+        Expects(bounds_type::static_size != dynamic_range || Count <= this->size());
         return { this->data() + this->size() - Count, Count };
     }
 
     constexpr span<ValueType, dynamic_range> last(size_type count) const noexcept
     {
-        fail_fast_assert(count <= this->size());
+        Expects(count <= this->size());
         return { this->data() + this->size() - count, count };
     }
 
@@ -1359,13 +1367,13 @@
     constexpr span<ValueType, Count> sub() 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");
-        fail_fast_assert(bounds_type::static_size != dynamic_range || ((Offset == 0 || Offset <= this->size()) && Offset + Count <= this->size()));
+        Expects(bounds_type::static_size != dynamic_range || ((Offset == 0 || Offset <= this->size()) && Offset + Count <= this->size()));
         return { this->data() + Offset, Count };
     }
 
     constexpr span<ValueType, dynamic_range> sub(size_type offset, size_type count = dynamic_range) const noexcept
     {
-        fail_fast_assert((offset == 0 || offset <= this->size()) && (count == dynamic_range || (offset + count) <= this->size()));
+        Expects((offset == 0 || offset <= this->size()) && (count == dynamic_range || (offset + count) <= this->size()));
         return { this->data() + offset, count == dynamic_range ? this->length() - offset : count };
     }
 
@@ -1405,10 +1413,11 @@
     template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
     constexpr Ret operator[](size_type idx) const noexcept
     {
-        fail_fast_assert(idx < m_bounds.size(), "index is out of bounds of the array");
+        Expects(idx < m_bounds.size()); // index is out of bounds of the array
         const size_type ridx = idx * m_bounds.stride();
 
-        fail_fast_assert(ridx < m_bounds.total_size(), "index is out of bounds of the underlying data");
+        // index is out of bounds of the underlying data
+        Expects(ridx < m_bounds.total_size());
         return Ret{ m_pdata + ridx, m_bounds.slice() };
     }
 
@@ -1560,7 +1569,7 @@
 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>>
 {
-    fail_fast_assert(arr.size() < PTRDIFF_MAX);
+    Expects(arr.size() < PTRDIFF_MAX);
     return {arr.data(), static_cast<std::ptrdiff_t>(arr.size())};
 }
 
@@ -1572,7 +1581,7 @@
 template <typename CharT, typename Traits, typename Allocator>
 constexpr auto as_span(std::basic_string<CharT, Traits, Allocator> &str) -> span<CharT, dynamic_range>
 {
-    fail_fast_assert(str.size() < PTRDIFF_MAX);
+    Expects(str.size() < PTRDIFF_MAX);
     return {&str[0], static_cast<std::ptrdiff_t>(str.size())};
 }
 
@@ -1608,8 +1617,10 @@
     constexpr strided_span(pointer ptr, size_type size, bounds_type bounds)
         : m_pdata(ptr), m_bounds(std::move(bounds))
     {
-        fail_fast_assert((m_bounds.size() > 0 && ptr != nullptr) || m_bounds.size() == 0);
-        fail_fast_assert(this->bounds().total_size() <= size, "Bounds cross data boundaries");
+        Expects((m_bounds.size() > 0 && ptr != nullptr) || m_bounds.size() == 0);
+        // Bounds cross data boundaries
+        Expects(this->bounds().total_size() <= size);
+        (void)size;
     }
 
     // from static array of size N
@@ -1659,10 +1670,11 @@
     template <bool Enabled = (Rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
     constexpr Ret operator[](size_type idx) const
     {
-        fail_fast_assert(idx < m_bounds.size(), "index is out of bounds of the array");
+        Expects(idx < m_bounds.size()); // index is out of bounds of the array
         const size_type ridx = idx * m_bounds.stride();
 
-        fail_fast_assert(ridx < m_bounds.total_size(), "index is out of bounds of the underlying data");
+        // 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() };
     }
 
@@ -1773,7 +1785,8 @@
 private:
     static index_type resize_extent(const index_type& extent, std::ptrdiff_t d)
     {
-        fail_fast_assert(extent[Rank - 1] >= d && (extent[Rank-1] % d == 0), "The last dimension of the array needs to contain a multiple of new type elements");
+        // The last dimension of the array needs to contain a multiple of new type elements
+        Expects(extent[Rank - 1] >= d && (extent[Rank - 1] % d == 0));
 
         index_type ret = extent;
         ret[Rank - 1] /= d;
@@ -1784,7 +1797,8 @@
     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)
     {
-        fail_fast_assert(strides[Rank - 1] == 1, "Only strided arrays with regular strides can be resized");
+        // Only strided arrays with regular strides can be resized
+        Expects(strides[Rank - 1] == 1);
 
         return strides;
     }
@@ -1792,12 +1806,16 @@
     template <bool Enabled = (Rank > 1), typename Dummy = std::enable_if_t<Enabled>>
     static index_type resize_stride(const index_type& strides, std::ptrdiff_t d)
     {
-        fail_fast_assert(strides[Rank - 1] == 1, "Only strided arrays with regular strides can be resized");
-        fail_fast_assert(strides[Rank - 2] >= d && (strides[Rank - 2] % d == 0), "The strides must have contiguous chunks of memory that can contain a multiple of new type elements");
+        // Only strided arrays with regular strides can be resized
+        Expects(strides[Rank - 1] == 1);
+        // The strides must have contiguous chunks of
+        // 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)
         {
-            fail_fast_assert((strides[i - 1] >= strides[i]) && (strides[i - 1] % strides[i] == 0), "Only strided arrays with regular strides can be resized");
+            // Only strided arrays with regular strides can be resized
+            Expects((strides[i - 1] >= strides[i]) && (strides[i - 1] % strides[i] == 0));
         }
 
         index_type ret = strides / d;
@@ -1824,7 +1842,9 @@
     const Span* m_validator;
     void validateThis() const
     {
-        fail_fast_assert(m_pdata >= m_validator->m_pdata && m_pdata < m_validator->m_pdata + m_validator->size(), "iterator is out of range of the array");
+        // iterator is out of range of the array
+        Expects(m_pdata >= m_validator->m_pdata &&
+            m_pdata < m_validator->m_pdata + 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) {}
@@ -1882,7 +1902,7 @@
     }
     difference_type operator-(const contiguous_span_iterator& rhs) const noexcept
     {
-        fail_fast_assert(m_validator == rhs.m_validator);
+        Expects(m_validator == rhs.m_validator);
         return m_pdata - rhs.m_pdata;
     }
     reference operator[](difference_type n) const noexcept
@@ -1891,7 +1911,7 @@
     }
     bool operator==(const contiguous_span_iterator& rhs) const noexcept
     {
-        fail_fast_assert(m_validator == rhs.m_validator);
+        Expects(m_validator == rhs.m_validator);
         return m_pdata == rhs.m_pdata;
     }
     bool operator!=(const contiguous_span_iterator& rhs) const noexcept
@@ -1900,7 +1920,7 @@
     }
     bool operator<(const contiguous_span_iterator& rhs) const noexcept
     {
-        fail_fast_assert(m_validator == rhs.m_validator);
+        Expects(m_validator == rhs.m_validator);
         return m_pdata < rhs.m_pdata;
     }
     bool operator<=(const contiguous_span_iterator& rhs) const noexcept
@@ -1998,7 +2018,7 @@
     }
     difference_type operator-(const general_span_iterator& rhs) const noexcept
     {
-        fail_fast_assert(m_container == rhs.m_container);
+        Expects(m_container == rhs.m_container);
         return m_itr - rhs.m_itr;
     }
     value_type operator[](difference_type n) const noexcept
@@ -2007,7 +2027,7 @@
     }
     bool operator==(const general_span_iterator& rhs) const noexcept
     {
-        fail_fast_assert(m_container == rhs.m_container);
+        Expects(m_container == rhs.m_container);
         return m_itr == rhs.m_itr;
     }
     bool operator !=(const general_span_iterator& rhs) const noexcept
@@ -2016,7 +2036,7 @@
     }
     bool operator<(const general_span_iterator& rhs) const noexcept
     {
-        fail_fast_assert(m_container == rhs.m_container);
+        Expects(m_container == rhs.m_container);
         return m_itr < rhs.m_itr;
     }
     bool operator<=(const general_span_iterator& rhs) const noexcept
@@ -2055,10 +2075,10 @@
 #if _MSC_VER <= 1800
 #pragma warning(pop)
 
-#ifndef GSL_THROWS_FOR_TESTING
+#ifndef GSL_THROW_ON_CONTRACT_VIOLATION
 #undef noexcept
 #pragma pop_macro("noexcept")
-#endif // GSL_THROWS_FOR_TESTING
+#endif // GSL_THROW_ON_CONTRACT_VIOLATION
 
 #undef GSL_MSVC_HAS_VARIADIC_CTOR_BUG 
 
@@ -2066,15 +2086,16 @@
 
 #endif // _MSC_VER
 
-#if defined(GSL_THROWS_FOR_TESTING) 
+#if defined(GSL_THROW_ON_CONTRACT_VIOLATION) 
 
 #undef noexcept
 
 #ifdef _MSC_VER
+#pragma warning(pop)
 #pragma pop_macro("noexcept")
 #endif
 
-#endif // GSL_THROWS_FOR_TESTING 
+#endif // GSL_THROW_ON_CONTRACT_VIOLATION 
 
 
 #endif // GSL_SPAN_H
diff --git a/include/string_span.h b/include/string_span.h
index b30ebf0..250c528 100644
--- a/include/string_span.h
+++ b/include/string_span.h
@@ -19,6 +19,7 @@
 #ifndef GSL_STRING_SPAN_H
 #define GSL_STRING_SPAN_H
 
+#include "gsl_assert.h"
 #include "span.h"
 #include <cstring>
 
@@ -89,7 +90,7 @@
 {
     auto cur = seq;
     while ((cur - seq) < max && *cur != Sentinel) ++cur;
-    fail_fast_assert(*cur == Sentinel);
+    Ensures(*cur == Sentinel);
     return{ seq, cur - seq };
 }
 
@@ -109,26 +110,26 @@
 inline basic_string_span<char, dynamic_range> ensure_z(char* const& sz, std::ptrdiff_t max)
 {
     auto len = strnlen(sz, max);
-    fail_fast_assert(sz[len] == 0);
+    Ensures(sz[len] == 0);
     return{ sz, static_cast<std::ptrdiff_t>(len) };
 }
 
 inline basic_string_span<const char, dynamic_range> ensure_z(const char* const& sz, std::ptrdiff_t max)
 {
     auto len = strnlen(sz, max);
-    fail_fast_assert(sz[len] == 0); return{ sz, static_cast<std::ptrdiff_t>(len) };
+    Ensures(sz[len] == 0); return{ sz, static_cast<std::ptrdiff_t>(len) };
 }
 
 inline basic_string_span<wchar_t, dynamic_range> ensure_z(wchar_t* const& sz, std::ptrdiff_t max)
 {
     auto len = wcsnlen(sz, max);
-    fail_fast_assert(sz[len] == 0); return{ sz, static_cast<std::ptrdiff_t>(len) };
+    Ensures(sz[len] == 0); return{ sz, static_cast<std::ptrdiff_t>(len) };
 }
 
 inline basic_string_span<const wchar_t, dynamic_range> ensure_z(const wchar_t* const& sz, std::ptrdiff_t max)
 {
     auto len = wcsnlen(sz, max);
-    fail_fast_assert(sz[len] == 0); return{ sz, static_cast<std::ptrdiff_t>(len) };
+    Ensures(sz[len] == 0); return{ sz, static_cast<std::ptrdiff_t>(len) };
 }
 
 template<class T, size_t N>
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 5529cda..fe7a831 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -9,7 +9,7 @@
     ./unittest-cpp
 )
 
-add_definitions(-DGSL_THROWS_FOR_TESTING)
+add_definitions(-DGSL_THROW_ON_CONTRACT_VIOLATION)
 
 if(MSVC14 OR MSVC12) # has the support we need
     # remove unnecessary warnings about unchecked iterators