From fda8e1231008bdee8f5356a241ae9fd4ffc19872 Mon Sep 17 00:00:00 2001 From: Treb Connell Date: Mon, 5 Oct 2015 13:34:50 -0700 Subject: [PATCH 01/13] Fix #124 remove maybe_null --- include/gsl.h | 187 ----------------------- tests/CMakeLists.txt | 1 - tests/maybenull_tests.cpp | 304 -------------------------------------- 3 files changed, 492 deletions(-) delete mode 100644 tests/maybenull_tests.cpp diff --git a/include/gsl.h b/include/gsl.h index 824ca6a..519682b 100644 --- a/include/gsl.h +++ b/include/gsl.h @@ -195,193 +195,6 @@ private: not_null& operator-=(size_t) = delete; }; - -// -// maybe_null -// -// Describes an optional pointer - provides symmetry with not_null -// -template -class maybe_null_ret; - -template -class maybe_null_dbg -{ - template - friend class maybe_null_dbg; - - static_assert(std::is_assignable::value, "T cannot be assigned nullptr."); -public: - maybe_null_dbg() : ptr_(nullptr), tested_(false) {} - maybe_null_dbg(std::nullptr_t) : ptr_(nullptr), tested_(false) {} - - maybe_null_dbg(const T& p) : ptr_(p), tested_(false) {} - maybe_null_dbg& operator=(const T& p) - { - if (ptr_ != p) - { - ptr_ = p; - tested_ = false; - } - return *this; - } - - - maybe_null_dbg(const maybe_null_dbg& rhs) : ptr_(rhs.ptr_), tested_(false) {} - maybe_null_dbg& operator=(const maybe_null_dbg& rhs) - { - if (this != &rhs) - { - ptr_ = rhs.ptr_; - tested_ = false; - } - return *this; - } - - - template ::value>> - maybe_null_dbg(const not_null &other) : ptr_(other.get()), tested_(false) {} - - template ::value>> - maybe_null_dbg& operator=(const not_null &other) - { - ptr_ = other.get(); - tested_ = false; - return *this; - } - - - template ::value>> - maybe_null_dbg(const maybe_null_dbg &other) : ptr_(other.ptr_), tested_(false) {} - - template ::value>> - maybe_null_dbg& operator=(const maybe_null_dbg &other) - { - ptr_ = other.ptr_; - tested_ = false; - return *this; - } - - - template ::value>> - maybe_null_dbg(const maybe_null_ret &other) : ptr_(other.get()), tested_(false) {} - - template ::value>> - maybe_null_dbg& operator=(const maybe_null_ret &other) - { - ptr_ = other.get(); - tested_ = false; - return *this; - } - - - bool present() const { tested_ = true; return ptr_ != nullptr; } - - bool operator==(const T& rhs) const { tested_ = true; return ptr_ == rhs; } - bool operator!=(const T& rhs) const { return !(*this == rhs); } - template ::value>> - bool operator==(const maybe_null_dbg& rhs) const { tested_ = true; rhs.tested_ = true; return ptr_ == rhs.ptr_; } - template ::value>> - bool operator!=(const maybe_null_dbg& rhs) const { return !(*this == rhs); } - - T get() const { - fail_fast_assert(tested_); -#ifdef _MSC_VER - __assume(ptr_ != nullptr); -#endif - return ptr_; - } - - operator T() const { return get(); } - T operator->() const { return get(); } - -private: - // unwanted operators...pointers only point to single objects! - // TODO ensure all arithmetic ops on this type are unavailable - maybe_null_dbg& operator++() = delete; - maybe_null_dbg& operator--() = delete; - maybe_null_dbg operator++(int) = delete; - maybe_null_dbg operator--(int) = delete; - maybe_null_dbg& operator+(size_t) = delete; - maybe_null_dbg& operator+=(size_t) = delete; - maybe_null_dbg& operator-(size_t) = delete; - maybe_null_dbg& operator-=(size_t) = delete; - - T ptr_; - mutable bool tested_; -}; - -template -class maybe_null_ret -{ - static_assert(std::is_assignable::value, "T cannot be assigned nullptr."); -public: - maybe_null_ret() : ptr_(nullptr) {} - maybe_null_ret(std::nullptr_t) : ptr_(nullptr) {} - - maybe_null_ret(const T& p) : ptr_(p) {} - maybe_null_ret& operator=(const T& p) { ptr_ = p; return *this; } - - maybe_null_ret(const maybe_null_ret& rhs) = default; - maybe_null_ret& operator=(const maybe_null_ret& rhs) = default; - - template ::value>> - maybe_null_ret(const not_null &other) : ptr_(other.get()) {} - - template ::value>> - maybe_null_ret& operator=(const not_null &other) - { - ptr_ = other.get(); - return *this; - } - - - template ::value>> - maybe_null_ret(const maybe_null_ret &other) : ptr_(other.get()) {} - - template ::value>> - maybe_null_ret& operator=(const maybe_null_ret &other) - { - ptr_ = other.get(); - return *this; - } - - - template ::value>> - maybe_null_ret(const maybe_null_dbg &other) : ptr_(other.get()) {} - - template ::value>> - maybe_null_ret& operator=(const maybe_null_dbg &other) - { - ptr_ = other.get(); - return *this; - } - - - bool present() const { return ptr_ != nullptr; } - - T get() const { return ptr_; } - - operator T() const { return get(); } - T operator->() const { return get(); } - -private: - // unwanted operators...pointers only point to single objects! - // TODO ensure all arithmetic ops on this type are unavailable - maybe_null_ret& operator++() = delete; - maybe_null_ret& operator--() = delete; - maybe_null_ret operator++(int) = delete; - maybe_null_ret operator--(int) = delete; - maybe_null_ret& operator+(size_t) = delete; - maybe_null_ret& operator+=(size_t) = delete; - maybe_null_ret& operator-(size_t) = delete; - maybe_null_ret& operator-=(size_t) = delete; - - T ptr_; -}; - -template using maybe_null = maybe_null_ret; - } // namespace gsl #ifdef _MSC_VER diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 774413f..5e4c395 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -47,7 +47,6 @@ add_gsl_test(array_view_tests) add_gsl_test(string_view_tests) add_gsl_test(at_tests) add_gsl_test(bounds_tests) -add_gsl_test(maybenull_tests) add_gsl_test(notnull_tests) add_gsl_test(assertion_tests) add_gsl_test(utils_tests) diff --git a/tests/maybenull_tests.cpp b/tests/maybenull_tests.cpp deleted file mode 100644 index 74d449f..0000000 --- a/tests/maybenull_tests.cpp +++ /dev/null @@ -1,304 +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. -// -/////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include - -using namespace gsl; - -struct MyBase { bool foo() { return true; } }; -struct MyDerived : public MyBase {}; -struct Unrelated {}; - -SUITE(MaybeNullTests) -{ - TEST(TestMaybeNull1) - { -#ifdef CONFIRM_COMPILATION_ERRORS - // Forbid non-nullptr assignable types - maybe_null_ret> f_ret(std::vector{1}); - maybe_null_ret> f_ret(std::vector{1}); - maybe_null_ret z_ret(10); - maybe_null_dbg> y_dbg({1,2}); - maybe_null_dbg z_dbg(10); - maybe_null_dbg> y_dbg({1,2}); -#endif - int n = 5; - maybe_null_dbg opt_n(&n); - int result = 0; - bool threw = false; - - CHECK_THROW(result = *opt_n, fail_fast); - - maybe_null_ret> x_ret(std::make_shared(10)); // shared_ptr is nullptr assignable - maybe_null_dbg> x_dbg(std::make_shared(10)); // shared_ptr is nullptr assignable - } - - TEST(TestMaybeNull2) - { - int n = 5; - maybe_null opt_n(&n); - int result = 0; - if (opt_n.present()) - result = *opt_n; - } - - TEST(TestMaybeNull3) - { - int n = 5; - maybe_null opt_n(&n); - int result = 0; - if (opt_n != nullptr) - result = *opt_n; - } - - int test4_helper(maybe_null p) - { - if (p != nullptr) - return *p; - return -1; - } - - TEST(TestMaybeNull4) - { - int n = 5; - int result = 0; - result = test4_helper(&n); - } - - int test5_helper(maybe_null_dbg p) - { - return *p; - } - - TEST(TestMaybeNull5) - { - int n = 5; - int result = 0; - bool threw = false; - - CHECK_THROW(result = test5_helper(&n), fail_fast); - } - -#ifdef CONFIRM_COMPILATION_ERRORS - int TestMaybeNull6() - { - int n; - maybe_null o(n); - } -#endif - - int g_int; - void test7_helper(maybe_null *> outptr) - { - g_int = 5; - - if (outptr.present()) - *outptr = &g_int; - } - - void test7b_helper(maybe_null_dbg *> outptr) - { - g_int = 5; - - if (outptr.present()) - *outptr = &g_int; - } - - TEST(TestMaybeNull7a) - { - maybe_null outval; - test7_helper(&outval); - CHECK(outval.present() && *outval == 5); - } - - TEST(TestMaybeNull7b) - { - maybe_null_dbg outval; - test7b_helper(&outval); - CHECK_THROW((void)*outval, fail_fast); - } - - int test8_helper1(maybe_null_dbg opt) - { - return *opt; - } - - int test8_helper2a(maybe_null_dbg opt) - { - if (!opt.present()) - return 0; - return test8_helper1(opt); - } - - TEST(TestMaybeNull8a) - { - int n = 5; - maybe_null_dbg opt(&n); - CHECK_THROW(test8_helper2a(opt), fail_fast); - } - -#ifdef CONVERT_TO_PTR_TO_CONST - int test9_helper(maybe_null copt) - { - if (copt.present()) - return *copt; - return 0; - } - - void TestMaybeNull9() - { - int n = 5; - maybe_null opt(&n); - CHECK_THROW(test9_helper(opt), fail_fast); - } -#endif - - TEST(TestMaybeNullCasting) - { - MyDerived derived; - maybe_null p = &derived; - CHECK(p.present()); - - maybe_null q = p; - CHECK(q == p); - - maybe_null_dbg pdbg = &derived; - CHECK(pdbg.present()); - - maybe_null_dbg qdbg = pdbg; - CHECK(qdbg == pdbg); - -#ifdef CONFIRM_COMPILATION_ERRORS - maybe_null r = p; - maybe_null s = reinterpret_cast(p); -#endif - maybe_null_dbg t = reinterpret_cast(p.get()); - - CHECK_THROW((void)(void*)t.get(), fail_fast); - maybe_null_dbg u = reinterpret_cast(p.get()); - CHECK(u.present()); - CHECK((void*)p.get() == (void*)u.get()); - } - - TEST(TestMaybeNullArrow) - { - MyDerived derived; - maybe_null_dbg p = &derived; - - CHECK_THROW(p->foo(), fail_fast); - CHECK(p.present()); - CHECK(p->foo()); - - maybe_null q = p; - CHECK(q.present()); - CHECK(q->foo()); - } - - TEST(TestMaybeNullCompare) - { - int i1 = 1; - int i2 = 2; - - maybe_null_dbg p1 = &i1; - maybe_null_dbg p1_2 = &i1; - maybe_null_dbg p2 = &i2; - - CHECK_THROW(p1.get(), fail_fast); - CHECK_THROW(p1_2.get(), fail_fast); - CHECK_THROW(p2.get(), fail_fast); - - CHECK(p1 != p2); - CHECK(!(p1 == p2)); - CHECK(p1 == p1); - CHECK(p1 == p1_2); - - // Make sure we no longer throw here - CHECK(p1.get() != nullptr); - CHECK(p1_2.get() != nullptr); - CHECK(p2.get() != nullptr); - } - - TEST(TestMaybeNullCopy) - { - int i1 = 1; - int i2 = 2; - - maybe_null_dbg p1 = &i1; - maybe_null_dbg p1_2 = &i1; - maybe_null_dbg p2 = &i2; - - CHECK(p1 != p2); - CHECK(p1 == p1_2); - - // Make sure we no longer throw here - CHECK(p1.get() != nullptr); - CHECK(p2.get() != nullptr); - - p1 = p2; - - // Make sure we now throw - CHECK_THROW(p1.get(), fail_fast); - - CHECK(p1 == p2); - CHECK(p1 != p1_2); - - // Make sure we no longer throw here - CHECK(p1.get() != nullptr); - } - - TEST(TestMaybeNullAssignmentOps) - { - MyBase base; - MyDerived derived; - Unrelated unrelated; - - not_null nnBase(&base); - not_null nnDerived(&derived); - not_null nnUnrelated(&unrelated); - - maybe_null_ret mnBase_ret1(&base), mnBase_ret2; - mnBase_ret2 = mnBase_ret1; // maybe_null_ret = maybe_null_ret - mnBase_ret2 = nnBase; // maybe_null_ret = not_null - - maybe_null_ret mnDerived_ret(&derived); - mnBase_ret2 = mnDerived_ret; // maybe_null_ret = maybe_null_ret - mnBase_ret1 = &derived; // maybe_null_ret = U; - mnBase_ret1 = nnDerived; // maybe_null_ret = not_null - - maybe_null_ret mnUnrelated_ret; - mnUnrelated_ret = &unrelated; // maybe_null_ret = T - - maybe_null_dbg mnBase_dbg1(&base), mnBase_dbg2; - mnBase_dbg2 = mnBase_dbg1; // maybe_null_dbg = maybe_null_dbg - mnBase_dbg2 = nnBase; // maybe_null_dbg = not_null - - maybe_null_dbg mnDerived_dbg(&derived); - mnBase_dbg2 = mnDerived_dbg; // maybe_null_dbg = maybe_null_dbg - mnBase_dbg1 = &derived; // maybe_null_dbg = U; - mnBase_dbg1 = nnDerived; // maybe_null_dbg = not_null - - maybe_null_dbg mnUnrelated_dbg; - mnUnrelated_dbg = &unrelated; // maybe_null_dbg = T - } -} - -int main(int, const char *[]) -{ - return UnitTest::RunAllTests(); -} From db38497d05887e8c901504fa09d71042ed8bb3c0 Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Mon, 5 Oct 2015 12:34:23 -0700 Subject: [PATCH 02/13] Removed coordinate_facade class --- include/array_view.h | 499 ++++++++++++++++--------------------- tests/array_view_tests.cpp | 23 +- 2 files changed, 224 insertions(+), 298 deletions(-) diff --git a/include/array_view.h b/include/array_view.h index 046cbf8..aa1b4e5 100644 --- a/include/array_view.h +++ b/include/array_view.h @@ -73,180 +73,6 @@ namespace details static const size_t max_value = std::is_signed::value ? static_cast::type>(-1) / 2 : static_cast(-1); }; - - template - class coordinate_facade - { - static_assert(std::is_integral::value - && sizeof(ValueType) <= sizeof(size_t), "ValueType must be an integral type!"); - static_assert(Rank > 0, "Rank must be greater than 0!"); - - template - friend class coordinate_facade; - public: - using reference = ValueType&; - using const_reference = const ValueType&; - using value_type = ValueType; - static const size_t rank = Rank; - constexpr coordinate_facade() noexcept - { - static_assert(std::is_base_of::value, "ConcreteType must be derived from coordinate_facade."); - } - constexpr coordinate_facade(const value_type(&values)[rank]) noexcept - { - static_assert(std::is_base_of::value, "ConcreteType must be derived from coordinate_facade."); - for (size_t i = 0; i < rank; ++i) - elems[i] = values[i]; - } - constexpr coordinate_facade(value_type e0) noexcept - { - static_assert(std::is_base_of::value, "ConcreteType must be derived from coordinate_facade."); - static_assert(rank == 1, "This constructor can only be used with rank == 1."); - elems[0] = e0; - } - // Preconditions: il.size() == rank - constexpr coordinate_facade(std::initializer_list il) - { - static_assert(std::is_base_of::value, "ConcreteType must be derived from coordinate_facade."); - fail_fast_assert(il.size() == rank, "The size of the initializer list must match the rank of the array"); - for (size_t i = 0; i < rank; ++i) - { - elems[i] = begin(il)[i]; - } - } - - constexpr coordinate_facade(const coordinate_facade & other) = default; - - template - constexpr coordinate_facade(const coordinate_facade & other) - { - for (size_t i = 0; i < rank; ++i) - { - fail_fast_assert(static_cast(other.elems[i]) <= SizeTypeTraits::max_value); - elems[i] = static_cast(other.elems[i]); - } - } - protected: - coordinate_facade& operator=(const coordinate_facade& rhs) = default; - // Preconditions: component_idx < rank - constexpr reference operator[](size_t component_idx) - { - fail_fast_assert(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 - { - fail_fast_assert(component_idx < rank, "Component index must be less than rank"); - return elems[component_idx]; - } - constexpr bool operator==(const ConcreteType& rhs) const noexcept - { - return std::equal(elems, elems + rank, rhs.elems); - } - constexpr bool operator!=(const ConcreteType& rhs) const noexcept - { - return !(to_concrete() == rhs); - } - constexpr ConcreteType operator+() const noexcept - { - return to_concrete(); - } - constexpr ConcreteType operator-() const - { - ConcreteType ret = to_concrete(); - std::transform(ret, ret + rank, ret, std::negate{}); - return ret; - } - constexpr ConcreteType operator+(const ConcreteType& rhs) const - { - ConcreteType ret = to_concrete(); - ret += rhs; - return ret; - } - constexpr ConcreteType operator-(const ConcreteType& rhs) const - { - ConcreteType ret = to_concrete(); - ret -= rhs; - return ret; - } - constexpr ConcreteType& operator+=(const ConcreteType& rhs) - { - for (size_t i = 0; i < rank; ++i) - elems[i] += rhs.elems[i]; - return to_concrete(); - } - constexpr ConcreteType& operator-=(const ConcreteType& rhs) - { - for (size_t i = 0; i < rank; ++i) - elems[i] -= rhs.elems[i]; - return to_concrete(); - } - constexpr ConcreteType& operator++() - { - static_assert(rank == 1, "This operator can only be used with rank == 1."); - ++elems[0]; - return to_concrete(); - } - constexpr ConcreteType operator++(int) - { - static_assert(rank == 1, "This operator can only be used with rank == 1."); - ConcreteType ret = to_concrete(); - ++(*this); - return ret; - } - constexpr ConcreteType& operator--() - { - static_assert(rank == 1, "This operator can only be used with rank == 1."); - --elems[0]; - return to_concrete(); - } - constexpr ConcreteType operator--(int) - { - static_assert(rank == 1, "This operator can only be used with rank == 1."); - ConcreteType ret = to_concrete(); - --(*this); - return ret; - } - constexpr ConcreteType operator*(value_type v) const - { - ConcreteType ret = to_concrete(); - ret *= v; - return ret; - } - constexpr ConcreteType operator/(value_type v) const - { - ConcreteType ret = to_concrete(); - ret /= v; - return ret; - } - friend constexpr ConcreteType operator*(value_type v, const ConcreteType& rhs) - { - return rhs * v; - } - constexpr ConcreteType& operator*=(value_type v) - { - for (size_t i = 0; i < rank; ++i) - elems[i] *= v; - return to_concrete(); - } - constexpr ConcreteType& operator/=(value_type v) - { - for (size_t i = 0; i < rank; ++i) - elems[i] /= v; - return to_concrete(); - } - value_type elems[rank] = {}; - private: - constexpr const ConcreteType& to_concrete() const noexcept - { - return static_cast(*this); - } - constexpr ConcreteType& to_concrete() noexcept - { - return static_cast(*this); - } - }; template class arrow_proxy { @@ -268,47 +94,160 @@ namespace details } template -class index : private details::coordinate_facade, ValueType, Rank> +class index final { - using Base = details::coordinate_facade, ValueType, Rank>; - friend Base; + static_assert(std::is_integral::value, "ValueType must be an integral type!"); + static_assert(Rank > 0, "Rank must be greater than 0!"); + template friend class index; + public: - using Base::rank; - using reference = typename Base::reference; - using const_reference = typename Base::const_reference; - using size_type = typename Base::value_type; - using value_type = typename Base::value_type; - constexpr index() noexcept : Base(){} - constexpr index(const value_type (&values)[rank]) noexcept : Base(values) {} - constexpr index(std::initializer_list il) : Base(il) {} + static const size_t rank = Rank; + using value_type = std::remove_reference_t; + using reference = std::add_lvalue_reference_t; + using const_reference = std::add_lvalue_reference_t>; - constexpr index(const index &) = default; - - template - constexpr index(const index &other) : Base(other) + constexpr index(const value_type(&values)[Rank]) noexcept { - } - constexpr static index shift_left(const index& other) noexcept - { - value_type (&arr)[rank] = (value_type(&)[rank])(*(other.elems + 1)); - return index(arr); + std::copy(values, values + Rank, elems); } - using Base::operator[]; - using Base::operator==; - using Base::operator!=; - using Base::operator+; - using Base::operator-; - using Base::operator+=; - using Base::operator-=; - using Base::operator++; - using Base::operator--; - using Base::operator*; - using Base::operator/; - using Base::operator*=; - using Base::operator/=; + // Preconditions: il.size() == rank + constexpr index(std::initializer_list il) noexcept + { + fail_fast_assert(il.size() == Rank, "The size of the initializer list must match the rank of the array"); + std::copy(begin(il), end(il), elems); + } + + constexpr index(const index& other) noexcept = default; + + // copy from index over smaller domain + template + constexpr index(typename std::enable_if_t<(details::SizeTypeTraits::max_value <= details::SizeTypeTraits::max_value), const index>::type& other) noexcept + { + std::copy(other.elems, other.elems + Rank, elems); + } + + // copy from index over larger domain + template + constexpr index(typename std::enable_if_t<(details::SizeTypeTraits::max_value > details::SizeTypeTraits::max_value), const index>::type& other) noexcept + { + for (size_t i = 0; i < Rank; ++i) + { + fail_fast_assert(other.elems[i] <= static_cast(SizeTypeTraits::max_value)); + elems[i] = static_cast(other.elems[i]); + } + } + + constexpr static index shift_left(const index& other) noexcept + { + value_type(&arr)[Rank] = (value_type(&)[Rank])(*(other.elems + 1)); + return index(arr); + } + + constexpr static index zero() noexcept + { + value_type zero[Rank] = {}; + return index(zero); + } + + constexpr index& operator=(const index& rhs) noexcept = default; + + // Preconditions: component_idx < rank + constexpr reference operator[](size_t component_idx) + { + fail_fast_assert(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"); + return elems[component_idx]; + } + + constexpr bool operator==(const index& rhs) const noexcept + { + return std::equal(elems, elems + rank, rhs.elems); + } + + constexpr bool operator!=(const index& rhs) const noexcept + { + return !(this == rhs); + } + + constexpr index operator+() const noexcept + { + return *this; + } + + constexpr index operator-() const noexcept + { + index ret = *this; + std::transform(ret, ret + rank, ret, std::negate{}); + return ret; + } + + constexpr index operator+(const index& rhs) const noexcept + { + index ret = *this; + ret += rhs; + return ret; + } + + constexpr index operator-(const index& rhs) const noexcept + { + index ret = *this; + ret -= rhs; + return ret; + } + + constexpr index& operator+=(const index& rhs) noexcept + { + std::transform(elems, elems + rank, rhs.elems, elems, std::plus{}); + return *this; + } + + constexpr index& operator-=(const index& rhs) noexcept + { + std::transform(elems, elems + rank, rhs.elems, elems, std::minus{}); + return *this; + } + + constexpr index operator*(value_type v) const noexcept + { + index ret = *this; + ret *= v; + return ret; + } + + constexpr index operator/(value_type v) const noexcept + { + index ret = *this; + ret /= v; + return ret; + } + + friend static constexpr index operator*(value_type v, const index& rhs) noexcept + { + return rhs * v; + } + + constexpr index& operator*=(value_type v) noexcept + { + std::transform(elems, elems + rank, elems, [v](value_type x) { return std::multiplies{}(x, v); }); + return *this; + } + + constexpr index& operator/=(value_type v) noexcept + { + std::transform(elems, elems + rank, elems, [v](value_type x) { return std::divides{}(x, v); }); + return *this; + } +private: + value_type elems[Rank] = {}; }; template @@ -316,51 +255,60 @@ class index<1, ValueType> { template friend class index; + public: static const size_t rank = 1; - using reference = ValueType&; - using const_reference = const ValueType&; - using size_type = ValueType; - using value_type = ValueType; + using value_type = std::remove_reference_t; + using reference = std::add_lvalue_reference_t; + using const_reference = std::add_lvalue_reference_t>; - constexpr index() noexcept : value(0) - { - } constexpr index(value_type e0) noexcept : value(e0) - { - } + {} + constexpr index(const value_type(&values)[1]) noexcept : index(values[0]) - { - } + {} + // Preconditions: il.size() == rank - constexpr index(std::initializer_list il) + constexpr index(std::initializer_list il) noexcept { fail_fast_assert(il.size() == rank, "Size of the initializer list must match the rank of the array"); value = begin(il)[0]; } - constexpr index(const index &) = default; + constexpr index(const index &) noexcept = default; template - constexpr index(const index<1, OtherValueType> & other) + constexpr index(typename std::enable_if_t<(details::SizeTypeTraits::max_value <= details::SizeTypeTraits::max_value), const index<1, OtherValueType>>::type& other) noexcept { - fail_fast_assert(other.value <= details::SizeTypeTraits::max_value); value = static_cast(other.value); } - constexpr static index shift_left(const index& other) noexcept + template + constexpr index(typename std::enable_if_t<(details::SizeTypeTraits::max_value > details::SizeTypeTraits::max_value), const index<1, OtherValueType>>::type& other) noexcept + { + fail_fast_assert(other.value <= static_cast(SizeTypeTraits::max_value)); + value = static_cast(other.value); + } + + constexpr static index shift_left(const index<2, value_type>& other) noexcept { return other.elems[1]; } - // Preconditions: component_idx < rank - constexpr reference operator[](size_type component_idx) noexcept + + constexpr static index zero() noexcept + { + return 0; + } + + // Preconditions: component_idx < 1 + constexpr reference operator[](value_type component_idx) noexcept { fail_fast_assert(component_idx == 0, "Component index must be less than rank"); (void)(component_idx); return value; } - // Preconditions: component_idx < rank - constexpr const_reference operator[](size_type component_idx) const noexcept + // Preconditions: component_idx < 1 + constexpr const_reference operator[](value_type component_idx) const noexcept { fail_fast_assert(component_idx == 0, "Component index must be less than rank"); (void)(component_idx); @@ -440,9 +388,9 @@ public: value /= v; return *this; } - friend constexpr index operator*(value_type v, const index& rhs) noexcept + friend static constexpr index operator*(value_type v, const index& rhs) noexcept { - return index(rhs * v); + return{ rhs * v }; } private: value_type value; @@ -855,9 +803,9 @@ public: constexpr index_type index_bounds() const noexcept { - index_type extents; + size_type extents[rank]; m_ranges.serialize(extents); - return extents; + return{ extents }; } template @@ -874,32 +822,28 @@ public: constexpr const_iterator begin() const noexcept { - return const_iterator(*this); + return const_iterator(*this, index_type::zero()); } constexpr const_iterator end() const noexcept { - index_type boundary; - m_ranges.serialize(boundary); return const_iterator(*this, this->index_bounds()); } }; template -class strided_bounds : private details::coordinate_facade, SizeType, Rank> +class strided_bounds { - using Base = details::coordinate_facade, SizeType, Rank>; - friend Base; template friend class strided_bounds; public: - using Base::rank; - using reference = typename Base::reference; - using const_reference = typename Base::const_reference; - using size_type = typename Base::value_type; - using difference_type = typename Base::value_type; - using value_type = typename Base::value_type; + static const size_t rank = Rank; + using reference = typename SizeType&; + using const_reference = typename const SizeType&; + using size_type = typename SizeType; + using difference_type = typename SizeType; + using value_type = typename SizeType; using index_type = index; using iterator = bounds_iterator; using const_iterator = bounds_iterator; @@ -907,57 +851,52 @@ public: static const size_t static_size = dynamic_range; using sliced_type = std::conditional_t, void>; using mapping_type = generalized_mapping_tag; - constexpr strided_bounds(const strided_bounds &) = default; + constexpr strided_bounds(const strided_bounds &) noexcept = default; template - constexpr strided_bounds(const strided_bounds &other) - : Base(other), m_strides(other.strides) - { - } - - constexpr strided_bounds(const index_type &extents, const index_type &strides) - : m_strides(strides) - { - for (size_t i = 0; i < rank; i++) - Base::elems[i] = extents[i]; - } - constexpr strided_bounds(const value_type(&values)[rank], index_type strides) - : Base(values), m_strides(std::move(strides)) - { - } + constexpr strided_bounds(const strided_bounds &other) noexcept + : m_extents(other.extents), m_strides(other.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; + { + return m_strides; } constexpr size_type total_size() const noexcept { size_type ret = 0; for (size_t i = 0; i < rank; ++i) - ret += (Base::elems[i] - 1) * m_strides[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) - ret *= Base::elems[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] >= Base::elems[i]) + if (idx[i] < 0 || idx[i] >= m_extents[i]) return false; } return true; } - constexpr size_type linearize(const index_type & idx) const + constexpr size_type linearize(const index_type & idx) const noexcept { size_type ret = 0; for (size_t i = 0; i < rank; i++) { - fail_fast_assert(idx[i] < Base::elems[i], "index is out of bounds of the array"); + fail_fast_assert(idx[i] < m_extents[i], "index is out of bounds of the array"); ret += idx[i] * m_strides[i]; } return ret; @@ -969,27 +908,28 @@ public: template 1), typename Ret = std::enable_if_t> constexpr sliced_type slice() const { - return{ (value_type(&)[rank - 1])Base::elems[1], sliced_type::index_type::shift_left(m_strides) }; + return{ sliced_type::index_type::shift_left(m_extents), sliced_type::index_type::shift_left(m_strides) }; } template constexpr size_type extent() const noexcept { static_assert(Dim < Rank, "dimension should be less than rank (dimension count starts from 0)"); - return Base::elems[Dim]; + return m_extents[Dim]; } constexpr index_type index_bounds() const noexcept { - return index_type(Base::elems); + return m_extents; } const_iterator begin() const noexcept { - return const_iterator{ *this }; + return const_iterator{ *this, index_type::zero() }; } const_iterator end() const noexcept { return const_iterator{ *this, index_bounds() }; } private: + index_type m_extents; index_type m_strides; }; @@ -1017,9 +957,9 @@ public: using typename Base::difference_type; using typename Base::value_type; using index_type = value_type; - using index_size_type = typename IndexType::size_type; + using index_size_type = typename IndexType::value_type; template - explicit bounds_iterator(const Bounds & bnd, value_type curr = value_type{}) noexcept + explicit bounds_iterator(const Bounds& bnd, value_type curr) noexcept : boundary(bnd.index_bounds()) , curr( std::move(curr) ) { @@ -1210,7 +1150,7 @@ public: using typename Base::difference_type; using typename Base::value_type; using index_type = value_type; - using index_size_type = typename index_type::size_type; + using index_size_type = typename index_type::value_type; template explicit bounds_iterator(const Bounds &, value_type curr = value_type{}) noexcept @@ -1327,11 +1267,14 @@ namespace details constexpr std::enable_if_t::value, typename Bounds::index_type> make_stride(const Bounds& bnd) noexcept { auto extents = bnd.index_bounds(); - typename Bounds::index_type stride; - stride[Bounds::rank - 1] = 1; - for (size_t i = Bounds::rank - 1; Bounds::rank > 1 && i > 0; --i) - stride[i-1] = stride[i] * extents[i]; - return stride; + Bounds::size_type stride[Bounds::rank]; + + stride[Bounds::rank - 1] = 1; + for (size_t i = Bounds::rank - 1; Bounds::rank > 1 && i > 0; --i) + { + stride[i - 1] = stride[i] * extents[i]; + } + return{ stride }; } template diff --git a/tests/array_view_tests.cpp b/tests/array_view_tests.cpp index 918df9e..ec10bbd 100644 --- a/tests/array_view_tests.cpp +++ b/tests/array_view_tests.cpp @@ -552,26 +552,6 @@ SUITE(array_view_tests) CHECK_THROW(av.section(5, 5), fail_fast); } - { - // zero stride - strided_array_view sav{ av, {{4}, {}} }; - CHECK(sav[0] == 0); - CHECK(sav[3] == 0); - CHECK_THROW(sav[4], fail_fast); - } - - { - // zero extent - strided_array_view sav{ av,{ {},{1} } }; - CHECK_THROW(sav[0], fail_fast); - } - - { - // zero extent and stride - strided_array_view sav{ av,{ {},{} } }; - CHECK_THROW(sav[0], fail_fast); - } - { // strided array ctor with matching strided bounds strided_array_view sav{ arr,{ 4, 1 } }; @@ -627,6 +607,9 @@ SUITE(array_view_tests) #ifdef CONFIRM_COMPILATION_ERRORS { + strided_array_view sav{ av,{ { 4 },{} } }; + strided_array_view sav{ av,{ {},{ 1 } } }; + strided_array_view sav{ av,{ {},{} } }; strided_array_view sav0{ av.data(), { 3, 2 } }; strided_array_view sav1{ arr, { 1 } }; strided_array_view sav2{ arr, { 1,1,1 } }; From 546f8cc1306ec69cc3a8f292785658da8caf157a Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Mon, 5 Oct 2015 21:04:56 -0700 Subject: [PATCH 03/13] Added tests for index size_type conversions --- include/array_view.h | 106 +++++++++---------- tests/array_view_tests.cpp | 209 +++++++++++++++++++++++++++++++++---- 2 files changed, 243 insertions(+), 72 deletions(-) diff --git a/include/array_view.h b/include/array_view.h index aa1b4e5..98bbadf 100644 --- a/include/array_view.h +++ b/include/array_view.h @@ -70,7 +70,7 @@ namespace details template struct SizeTypeTraits { - static const size_t max_value = std::is_signed::value ? static_cast::type>(-1) / 2 : static_cast(-1); + static const SizeType max_value = std::is_signed::value ? static_cast::type>(-1) / 2 : static_cast(-1); }; template @@ -108,6 +108,9 @@ public: using reference = std::add_lvalue_reference_t; using const_reference = std::add_lvalue_reference_t>; + constexpr index() noexcept + {} + constexpr index(const value_type(&values)[Rank]) noexcept { std::copy(values, values + Rank, elems); @@ -120,36 +123,29 @@ public: std::copy(begin(il), end(il), elems); } - constexpr index(const index& other) noexcept = default; + constexpr index(const index& other) noexcept = default; // copy from index over smaller domain - template - constexpr index(typename std::enable_if_t<(details::SizeTypeTraits::max_value <= details::SizeTypeTraits::max_value), const index>::type& other) noexcept + template ::max_value <= details::SizeTypeTraits::max_value), + typename Other = std::enable_if_t>> + constexpr index(const index& other) noexcept { std::copy(other.elems, other.elems + Rank, elems); } // copy from index over larger domain - template - constexpr index(typename std::enable_if_t<(details::SizeTypeTraits::max_value > details::SizeTypeTraits::max_value), const index>::type& other) noexcept + template ::max_value > details::SizeTypeTraits::max_value), + typename Other = std::enable_if_t>> + constexpr index(const index& other, void* ptr = 0) noexcept { - for (size_t i = 0; i < Rank; ++i) - { - fail_fast_assert(other.elems[i] <= static_cast(SizeTypeTraits::max_value)); - elems[i] = static_cast(other.elems[i]); - } - } + bool ok = std::accumulate(other.elems, other.elems + Rank, true, + [&](bool b, OtherValueType val) { return b && (val <= static_cast(details::SizeTypeTraits::max_value)); } + ); - constexpr static index shift_left(const index& other) noexcept - { - value_type(&arr)[Rank] = (value_type(&)[Rank])(*(other.elems + 1)); - return index(arr); - } - - constexpr static index zero() noexcept - { - value_type zero[Rank] = {}; - return index(zero); + fail_fast_assert(ok, "other value must fit in the new domain"); + std::transform(other.elems, other.elems + rank, elems, [&](OtherValueType val) { return static_cast(val); }); } constexpr index& operator=(const index& rhs) noexcept = default; @@ -230,7 +226,7 @@ public: return ret; } - friend static constexpr index operator*(value_type v, const index& rhs) noexcept + friend constexpr index operator*(value_type v, const index& rhs) noexcept { return rhs * v; } @@ -246,6 +242,7 @@ public: std::transform(elems, elems + rank, elems, [v](value_type x) { return std::divides{}(x, v); }); return *this; } + private: value_type elems[Rank] = {}; }; @@ -262,44 +259,34 @@ public: using reference = std::add_lvalue_reference_t; using const_reference = std::add_lvalue_reference_t>; - constexpr index(value_type e0) noexcept : value(e0) + constexpr index() noexcept : value(0) {} - constexpr index(const value_type(&values)[1]) noexcept : index(values[0]) + constexpr index(value_type e) noexcept : value(e) {} - // Preconditions: il.size() == rank - constexpr index(std::initializer_list il) noexcept - { - fail_fast_assert(il.size() == rank, "Size of the initializer list must match the rank of the array"); - value = begin(il)[0]; - } + constexpr index(const value_type(&values)[1]) noexcept : index(values[0]) + {} constexpr index(const index &) noexcept = default; - template - constexpr index(typename std::enable_if_t<(details::SizeTypeTraits::max_value <= details::SizeTypeTraits::max_value), const index<1, OtherValueType>>::type& other) noexcept + template ::max_value <= details::SizeTypeTraits::max_value), + typename Other = std::enable_if_t>> + constexpr index(const index<1, OtherValueType>& other) noexcept { value = static_cast(other.value); } - template - constexpr index(typename std::enable_if_t<(details::SizeTypeTraits::max_value > details::SizeTypeTraits::max_value), const index<1, OtherValueType>>::type& other) noexcept + template ::max_value > details::SizeTypeTraits::max_value), + typename Other = std::enable_if_t>> + constexpr index(const index<1, OtherValueType>& other, void* ptr=0) noexcept { - fail_fast_assert(other.value <= static_cast(SizeTypeTraits::max_value)); + fail_fast_assert(other.value <= static_cast(details::SizeTypeTraits::max_value)); value = static_cast(other.value); } - constexpr static index shift_left(const index<2, value_type>& other) noexcept - { - return other.elems[1]; - } - - constexpr static index zero() noexcept - { - return 0; - } - // Preconditions: component_idx < 1 constexpr reference operator[](value_type component_idx) noexcept { @@ -388,7 +375,7 @@ public: value /= v; return *this; } - friend static constexpr index operator*(value_type v, const index& rhs) noexcept + friend constexpr index operator*(value_type v, const index& rhs) noexcept { return{ rhs * v }; } @@ -822,7 +809,7 @@ public: constexpr const_iterator begin() const noexcept { - return const_iterator(*this, index_type::zero()); + return const_iterator(*this); } constexpr const_iterator end() const noexcept @@ -908,7 +895,7 @@ public: template 1), typename Ret = std::enable_if_t> constexpr sliced_type slice() const { - return{ sliced_type::index_type::shift_left(m_extents), sliced_type::index_type::shift_left(m_strides) }; + return{ details::shift_left(m_extents), details::shift_left(m_strides) }; } template constexpr size_type extent() const noexcept @@ -922,7 +909,7 @@ public: } const_iterator begin() const noexcept { - return const_iterator{ *this, index_type::zero() }; + return const_iterator{ *this }; } const_iterator end() const noexcept { @@ -959,9 +946,9 @@ public: using index_type = value_type; using index_size_type = typename IndexType::value_type; template - explicit bounds_iterator(const Bounds& bnd, value_type curr) noexcept + explicit bounds_iterator(const Bounds& bnd, value_type curr = value_type{}) noexcept : boundary(bnd.index_bounds()) - , curr( std::move(curr) ) + , curr(std::move(curr)) { static_assert(is_bounds::value, "Bounds type must be provided"); } @@ -1270,13 +1257,24 @@ namespace details Bounds::size_type stride[Bounds::rank]; stride[Bounds::rank - 1] = 1; - for (size_t i = Bounds::rank - 1; Bounds::rank > 1 && i > 0; --i) + for (size_t i = 1; i < Bounds::rank; ++i) { - stride[i - 1] = stride[i] * extents[i]; + stride[Bounds::rank - i - 1] = stride[Bounds::rank - i] * extents[Bounds::rank - i]; } return{ stride }; } + template 1), typename Ret = std::enable_if_t>> + constexpr Ret shift_left(const index& other) noexcept + { + Ret ret; + for (size_t i = 0; i < Rank - 1; ++i) + { + ret[i] = other[i + 1]; + } + return ret; + } + template void verifyBoundsReshape(const BoundsSrc &src, const BoundsDest &dest) { diff --git a/tests/array_view_tests.cpp b/tests/array_view_tests.cpp index ec10bbd..a56d0f2 100644 --- a/tests/array_view_tests.cpp +++ b/tests/array_view_tests.cpp @@ -552,6 +552,26 @@ SUITE(array_view_tests) CHECK_THROW(av.section(5, 5), fail_fast); } + { + // zero stride + strided_array_view sav{ av,{ { 4 },{} } }; + CHECK(sav[0] == 0); + CHECK(sav[3] == 0); + CHECK_THROW(sav[4], fail_fast); + } + + { + // zero extent + strided_array_view sav{ av,{ {},{ 1 } } }; + CHECK_THROW(sav[0], fail_fast); + } + + { + // zero extent and stride + strided_array_view sav{ av,{ {},{} } }; + CHECK_THROW(sav[0], fail_fast); + } + { // strided array ctor with matching strided bounds strided_array_view sav{ arr,{ 4, 1 } }; @@ -607,9 +627,6 @@ SUITE(array_view_tests) #ifdef CONFIRM_COMPILATION_ERRORS { - strided_array_view sav{ av,{ { 4 },{} } }; - strided_array_view sav{ av,{ {},{ 1 } } }; - strided_array_view sav{ av,{ {},{} } }; strided_array_view sav0{ av.data(), { 3, 2 } }; strided_array_view sav1{ arr, { 1 } }; strided_array_view sav2{ arr, { 1,1,1 } }; @@ -618,27 +635,26 @@ SUITE(array_view_tests) strided_array_view sav5{ av.as_array_view(dim<2>(), dim<2>()), { 1 } }; strided_array_view sav6{ av.as_array_view(dim<2>(), dim<2>()), { 1,1,1 } }; strided_array_view sav7{ av.as_array_view(dim<2>(), dim<2>()), { { 1,1 },{ 1,1 },{ 1,1 } } }; + + index<1> index{ 0, 1 }; + strided_array_view sav8{ arr,{ 1,{ 1,1 } } }; +#ifdef _MSC_VER + strided_array_view sav9{ arr,{ { 1,1 },{ 1,1 } } }; +#endif + strided_array_view sav10{ av,{ 1,{ 1,1 } } }; +#ifdef _MSC_VER + strided_array_view sav11{ av,{ { 1,1 },{ 1,1 } } }; +#endif } #endif - + { - // stride initializer list size should match the rank of the array - CHECK_THROW((index<1>{ 0,1 }), fail_fast); - CHECK_THROW((strided_array_view{ arr, {1, {1,1}} }), fail_fast); -#ifdef _MSC_VER - CHECK_THROW((strided_array_view{ arr, {{1,1 }, {1,1}} }), fail_fast); -#endif - CHECK_THROW((strided_array_view{ av, {1, {1,1}} }), fail_fast); -#ifdef _MSC_VER - CHECK_THROW((strided_array_view{ av, {{1,1 }, {1,1}} }), fail_fast); -#endif CHECK_THROW((strided_array_view{ av.as_array_view(dim<2>(), dim<2>()), {{1}, {1}} }), fail_fast); CHECK_THROW((strided_array_view{ av.as_array_view(dim<2>(), dim<2>()), {{1}, {1,1,1}} }), fail_fast); #ifdef _MSC_VER CHECK_THROW((strided_array_view{ av.as_array_view(dim<2>(), dim<2>()), {{1,1,1}, {1}} }), fail_fast); #endif } - } TEST(strided_array_view_type_conversion) @@ -856,7 +872,18 @@ SUITE(array_view_tests) } { - index<2> k = index<2>::shift_left(i); + index<3> k = 3 * i; + + CHECK(i[0] == 0); + CHECK(i[1] == 1); + CHECK(i[2] == 2); + CHECK(k[0] == 0); + CHECK(k[1] == 3); + CHECK(k[2] == 6); + } + + { + index<2> k = details::shift_left(i); CHECK(i[0] == 0); CHECK(i[1] == 1); @@ -972,7 +999,7 @@ SUITE(array_view_tests) auto bounds = strided_bounds<1>({ length }, { 2 }); #else auto bounds = strided_bounds<1>(index<1>{ length }, index<1>{ 2 }); -#endif +#endif strided_array_view strided(&av.data()[1], av.size() - 1, bounds); CHECK(strided.size() == length); @@ -1033,7 +1060,7 @@ SUITE(array_view_tests) for (unsigned int k = 0; k < section.extent<2>(); ++k) { auto idx = index<3>{ i,j,k }; // avoid braces in the CHECK macro - CHECK(section[idx] == expected[2 * i + 2 * j + k]); + CHECK(section[idx] == expected[2 * i + 2 * j + k]); } } @@ -1151,6 +1178,152 @@ SUITE(array_view_tests) } + template + index Convert(index index) + { + return{ index }; + } + + TEST(DomainConverters) + { + // to smaller + { + index<2, int> int_index{ 0,1 }; + index<2, short> short_index{ int_index }; + + CHECK(short_index[0] == 0); + CHECK(short_index[1] == 1); + } + + // to smaller (failure) + { + index<2, int> big_int_index{ INT_MAX, 1 }; + CHECK_THROW((Convert<2,int, short int>(big_int_index)), fail_fast); + } + + // to same, sign mismatch + { + index<2, int> int_index{ 0,1 }; + index<2, unsigned int> uint_index{ int_index }; + + CHECK(uint_index[0] == 0); + CHECK(uint_index[1] == 1); + } + + // to same, sign mismatch, reversed + { + index<2, unsigned int> uint_index{ 0,1 }; + index<2, int> int_index{ uint_index }; + + CHECK(int_index[0] == 0); + CHECK(int_index[1] == 1); + } + + // to smaller, sign mismatch + { + index<2, int> int_index{ 0,1 }; + index<2, unsigned short> ushort_index{ int_index }; + + CHECK(ushort_index[0] == 0); + CHECK(ushort_index[1] == 1); + } + + // to bigger + { + index<2, int> int_index{ 0,1 }; + index<2, long long> longlong_index{ int_index }; + + CHECK(longlong_index[0] == 0); + CHECK(longlong_index[1] == 1); + } + + // to bigger with max index + { + index<2, int> big_int_index{ INT_MAX, 1 }; + index<2, long long> longlong_index{ big_int_index }; + + CHECK(longlong_index[0] == INT_MAX); + CHECK(longlong_index[1] == 1); + } + + // to bigger, sign mismatch + { + index<2, int> int_index{ 0,1 }; + index<2, unsigned long long> ulonglong_index{ int_index }; + + CHECK(ulonglong_index[0] == 0); + CHECK(ulonglong_index[1] == 1); + } + + } + + TEST(DomainConvertersRank1) + { + // to smaller + { + index<1, int> int_index{ 0 }; + index<1, short> short_index{ int_index }; + + CHECK(short_index[0] == 0); + } + + // to smaller (failure) + { + index<1, int> big_int_index{ INT_MAX }; + + CHECK_THROW((Convert<1, int, short int>(big_int_index)), fail_fast); + } + + // to same, sign mismatch + { + index<1, int> int_index{ 0 }; + index<1, unsigned int> uint_index{ int_index }; + + CHECK(uint_index[0] == 0); + } + + // to same, sign mismatch, reversed + { + index<1, unsigned int> uint_index{ 0 }; + index<1, int> int_index{ uint_index }; + + CHECK(int_index[0] == 0); + } + + // to smaller, sign mismatch + { + index<1, int> int_index{ 0 }; + index<1, unsigned short> ushort_index{ int_index }; + + CHECK(ushort_index[0] == 0); + } + + // to bigger + { + index<1, int> int_index{ 0 }; + index<1, long long> longlong_index{ int_index }; + + CHECK(longlong_index[0] == 0); + } + + // to bigger with max index + { + index<1, int> big_int_index{ INT_MAX }; + index<1, long long> longlong_index{ big_int_index }; + + CHECK(longlong_index[0] == INT_MAX); + } + + // to bigger, sign mismatch + { + index<1, int> int_index{ 0 }; + index<1, unsigned long long> ulonglong_index{ int_index }; + + CHECK(ulonglong_index[0] == 0); + } + + } + TEST(constructors) { array_view av(nullptr); From fdf864347150a108a33a467bc7ba3efd1ad78b2f Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Wed, 14 Oct 2015 10:46:22 -0700 Subject: [PATCH 04/13] Fixes for gcc --- include/array_view.h | 36 ++++++++++++++++++------------------ tests/array_view_tests.cpp | 13 +++++++------ 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/include/array_view.h b/include/array_view.h index 98bbadf..3502076 100644 --- a/include/array_view.h +++ b/include/array_view.h @@ -686,6 +686,17 @@ namespace details { return TypeListIndexer(obj); } + + template 1), typename Ret = std::enable_if_t>> + constexpr Ret shift_left(const index& other) noexcept + { + Ret ret; + for (size_t i = 0; i < Rank - 1; ++i) + { + ret[i] = other[i + 1]; + } + return ret; + } } template @@ -790,7 +801,7 @@ public: constexpr index_type index_bounds() const noexcept { - size_type extents[rank]; + size_type extents[rank] = {}; m_ranges.serialize(extents); return{ extents }; } @@ -826,11 +837,11 @@ class strided_bounds public: static const size_t rank = Rank; - using reference = typename SizeType&; - using const_reference = typename const SizeType&; - using size_type = typename SizeType; - using difference_type = typename SizeType; - using value_type = typename SizeType; + using reference = SizeType&; + using const_reference = const SizeType&; + using size_type = SizeType; + using difference_type = SizeType; + using value_type = SizeType; using index_type = index; using iterator = bounds_iterator; using const_iterator = bounds_iterator; @@ -1254,7 +1265,7 @@ namespace details constexpr std::enable_if_t::value, typename Bounds::index_type> make_stride(const Bounds& bnd) noexcept { auto extents = bnd.index_bounds(); - Bounds::size_type stride[Bounds::rank]; + typename Bounds::size_type stride[Bounds::rank] = {}; stride[Bounds::rank - 1] = 1; for (size_t i = 1; i < Bounds::rank; ++i) @@ -1264,17 +1275,6 @@ namespace details return{ stride }; } - template 1), typename Ret = std::enable_if_t>> - constexpr Ret shift_left(const index& other) noexcept - { - Ret ret; - for (size_t i = 0; i < Rank - 1; ++i) - { - ret[i] = other[i + 1]; - } - return ret; - } - template void verifyBoundsReshape(const BoundsSrc &src, const BoundsDest &dest) { diff --git a/tests/array_view_tests.cpp b/tests/array_view_tests.cpp index a56d0f2..f84e908 100644 --- a/tests/array_view_tests.cpp +++ b/tests/array_view_tests.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -1197,7 +1198,7 @@ SUITE(array_view_tests) // to smaller (failure) { - index<2, int> big_int_index{ INT_MAX, 1 }; + index<2, int> big_int_index{ std::numeric_limits::max(), 1 }; CHECK_THROW((Convert<2,int, short int>(big_int_index)), fail_fast); } @@ -1239,10 +1240,10 @@ SUITE(array_view_tests) // to bigger with max index { - index<2, int> big_int_index{ INT_MAX, 1 }; + index<2, int> big_int_index{ std::numeric_limits::max(), 1 }; index<2, long long> longlong_index{ big_int_index }; - CHECK(longlong_index[0] == INT_MAX); + CHECK(longlong_index[0] == std::numeric_limits::max()); CHECK(longlong_index[1] == 1); } @@ -1269,7 +1270,7 @@ SUITE(array_view_tests) // to smaller (failure) { - index<1, int> big_int_index{ INT_MAX }; + index<1, int> big_int_index{ std::numeric_limits::max() }; CHECK_THROW((Convert<1, int, short int>(big_int_index)), fail_fast); } @@ -1308,10 +1309,10 @@ SUITE(array_view_tests) // to bigger with max index { - index<1, int> big_int_index{ INT_MAX }; + index<1, int> big_int_index{ std::numeric_limits::max() }; index<1, long long> longlong_index{ big_int_index }; - CHECK(longlong_index[0] == INT_MAX); + CHECK(longlong_index[0] == std::numeric_limits::max()); } // to bigger, sign mismatch From f972b2d68c9a9d7ce151d93b3a3b3b2da9ecb6eb Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Thu, 15 Oct 2015 13:00:10 -0700 Subject: [PATCH 05/13] Adding g++-5 libraries to clang travis configuration to fix build break --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 524f1fb..3c64230 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ matrix: packages: - clang-3.6 - cmake + - g++-5 sources: &sources - ubuntu-toolchain-r-test - llvm-toolchain-precise-3.6 From 2cdedda7e4d85f356b8ef66f2d6f7e778538ba00 Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Thu, 15 Oct 2015 13:19:24 -0700 Subject: [PATCH 06/13] Adding missing include library to array_view.h --- include/array_view.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/array_view.h b/include/array_view.h index 3502076..c884c11 100644 --- a/include/array_view.h +++ b/include/array_view.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include From 01868f2516ee04e2129ceafe341fd5fe0d112e01 Mon Sep 17 00:00:00 2001 From: Neil MacIntosh Date: Thu, 15 Oct 2015 16:48:38 -0700 Subject: [PATCH 07/13] Fix missing header for std::divides. --- include/array_view.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/array_view.h b/include/array_view.h index c884c11..cc7ab23 100644 --- a/include/array_view.h +++ b/include/array_view.h @@ -30,6 +30,7 @@ #include #include #include +#include #include "fail_fast.h" #ifdef _MSC_VER From c973e82dff09144005e883a3daceded35044472f Mon Sep 17 00:00:00 2001 From: Neil MacIntosh Date: Thu, 15 Oct 2015 17:05:19 -0700 Subject: [PATCH 08/13] Added AppVeyor CI status badge. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7d96dec..c687673 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# GSL: Guidelines Support Library [![Build Status](https://travis-ci.org/Microsoft/GSL.svg?branch=master)](https://travis-ci.org/Microsoft/GSL) +# GSL: Guidelines Support Library [![Build Status](https://travis-ci.org/Microsoft/GSL.svg?branch=master)](https://travis-ci.org/Microsoft/GSL) [![Build status](https://ci.appveyor.com/api/projects/status/github/Microsoft/GSL?svg=true)](https://ci.appveyor.com/project/neilmacintosh/GSL) The Guidelines Support Library (GSL) contains functions and types that are suggested for use by the [C++ Core Guidelines](https://github.com/isocpp/CppCoreGuidelines) maintained by the [Standard C++ Foundation](https://isocpp.org). From a4654a46b535100f53143b6c616425cf293b6a3b Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Fri, 16 Oct 2015 12:15:22 -0700 Subject: [PATCH 09/13] Removed arrow_proxy class, fixes bugs in reverse bounds_iterator --- include/array_view.h | 269 +++++++++++++++++++------------------ tests/array_view_tests.cpp | 63 ++++++++- 2 files changed, 199 insertions(+), 133 deletions(-) diff --git a/include/array_view.h b/include/array_view.h index cc7ab23..a31efd8 100644 --- a/include/array_view.h +++ b/include/array_view.h @@ -74,25 +74,6 @@ namespace details { static const SizeType max_value = std::is_signed::value ? static_cast::type>(-1) / 2 : static_cast(-1); }; - - template - class arrow_proxy - { - public: - explicit arrow_proxy(T t) - : val(t) - {} - const T operator*() const noexcept - { - return val; - } - const T* operator->() const noexcept - { - return &val; - } - private: - T val; - }; } template @@ -730,8 +711,9 @@ public: using size_type = SizeType; using index_type = index; - using iterator = bounds_iterator; - using const_iterator = bounds_iterator; + using const_index_type = std::add_const_t; + using iterator = bounds_iterator; + using const_iterator = bounds_iterator; using difference_type = ptrdiff_t; using sliced_type = static_bounds; using mapping_type = contiguous_mapping_tag; @@ -822,7 +804,7 @@ public: constexpr const_iterator begin() const noexcept { - return const_iterator(*this); + return const_iterator(*this, index_type{}); } constexpr const_iterator end() const noexcept @@ -845,8 +827,9 @@ public: using difference_type = SizeType; using value_type = SizeType; using index_type = index; - using iterator = bounds_iterator; - using const_iterator = bounds_iterator; + using const_index_type = std::add_const_t; + using iterator = bounds_iterator; + using const_iterator = bounds_iterator; static const int dynamic_rank = rank; static const size_t static_size = dynamic_range; using sliced_type = std::conditional_t, void>; @@ -920,11 +903,11 @@ public: { return m_extents; } - const_iterator begin() const noexcept + constexpr const_iterator begin() const noexcept { - return const_iterator{ *this }; + return const_iterator{ *this, index_type{} }; } - const_iterator end() const noexcept + constexpr const_iterator end() const noexcept { return const_iterator{ *this, index_bounds() }; } @@ -941,15 +924,11 @@ template struct is_bounds> : std::integral_constant {}; template -class bounds_iterator - : public std::iterator, - const IndexType> +class bounds_iterator: public std::iterator { private: - using Base = std::iterator , const IndexType>; + using Base = std::iterator ; + public: static const size_t rank = IndexType::rank; using typename Base::reference; @@ -959,79 +938,88 @@ public: using index_type = value_type; using index_size_type = typename IndexType::value_type; template - explicit bounds_iterator(const Bounds& bnd, value_type curr = value_type{}) noexcept - : boundary(bnd.index_bounds()) - , curr(std::move(curr)) + explicit bounds_iterator(const Bounds& bnd, value_type curr) noexcept + : boundary(bnd.index_bounds()), curr(std::move(curr)) { static_assert(is_bounds::value, "Bounds type must be provided"); } - reference operator*() const noexcept + + constexpr reference operator*() const noexcept { return curr; } - pointer operator->() const noexcept + + constexpr pointer operator->() const noexcept { - return details::arrow_proxy{ curr }; + return &curr; } - bounds_iterator& operator++() noexcept + + constexpr bounds_iterator& operator++() noexcept { for (size_t i = rank; i-- > 0;) { - if (++curr[i] < boundary[i]) + if (curr[i] < boundary[i] - 1) { + curr[i]++; return *this; } - else - { - curr[i] = 0; - } + curr[i] = 0; } // If we're here we've wrapped over - set to past-the-end. - for (size_t i = 0; i < rank; ++i) - { - curr[i] = boundary[i]; - } + curr = boundary; return *this; } - bounds_iterator operator++(int) noexcept + + constexpr bounds_iterator operator++(int) noexcept { auto ret = *this; ++(*this); return ret; } - bounds_iterator& operator--() noexcept + + constexpr bounds_iterator& operator--() noexcept { - for (size_t i = rank; i-- > 0;) + if (!less(curr, boundary)) { - if (curr[i]-- > 0) - { - return *this; - } - else + // if at the past-the-end, set to last element + 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) + { + curr[i]--; + return *this; + } + curr[i] = boundary[i] - 1; } // If we're here the preconditions were violated // "pre: there exists s such that r == ++s" fail_fast_assert(false); return *this; } - bounds_iterator operator--(int) noexcept + + constexpr bounds_iterator operator--(int) noexcept { auto ret = *this; --(*this); return ret; } - bounds_iterator operator+(difference_type n) const noexcept + + constexpr bounds_iterator operator+(difference_type n) const noexcept { bounds_iterator ret{ *this }; return ret += n; } - bounds_iterator& operator+=(difference_type n) noexcept + + constexpr bounds_iterator& operator+=(difference_type n) noexcept { auto linear_idx = linearize(curr) + n; - value_type stride; + std::remove_const_t stride; stride[rank - 1] = 1; for (size_t i = rank - 1; i-- > 0;) { @@ -1042,76 +1030,84 @@ public: 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"); return *this; } - bounds_iterator operator-(difference_type n) const noexcept + + constexpr bounds_iterator operator-(difference_type n) const noexcept { bounds_iterator ret{ *this }; return ret -= n; } - bounds_iterator& operator-=(difference_type n) noexcept + + constexpr bounds_iterator& operator-=(difference_type n) noexcept { return *this += -n; } - difference_type operator-(const bounds_iterator& rhs) const noexcept + + constexpr difference_type operator-(const bounds_iterator& rhs) const noexcept { return linearize(curr) - linearize(rhs.curr); } - reference operator[](difference_type n) const noexcept + + constexpr reference operator[](difference_type n) const noexcept { return *(*this + n); } - bool operator==(const bounds_iterator& rhs) const noexcept + + constexpr bool operator==(const bounds_iterator& rhs) const noexcept { return curr == rhs.curr; } - bool operator!=(const bounds_iterator& rhs) const noexcept + + constexpr bool operator!=(const bounds_iterator& rhs) const noexcept { return !(*this == rhs); } - bool operator<(const bounds_iterator& rhs) const noexcept + + constexpr bool operator<(const bounds_iterator& rhs) const noexcept { - for (size_t i = 0; i < rank; ++i) - { - if (curr[i] < rhs.curr[i]) - return true; - } - return false; + return less(curr, rhs.curr); } - bool operator<=(const bounds_iterator& rhs) const noexcept + + constexpr bool operator<=(const bounds_iterator& rhs) const noexcept { return !(rhs < *this); } - bool operator>(const bounds_iterator& rhs) const noexcept + + constexpr bool operator>(const bounds_iterator& rhs) const noexcept { return rhs < *this; } - bool operator>=(const bounds_iterator& rhs) const noexcept + + 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: - index_size_type linearize(const value_type& idx) const noexcept + 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; + } + return false; + } + + constexpr index_size_type linearize(const value_type& idx) const noexcept { // TODO: Smarter impl. // Check if past-the-end - bool pte = true; - for (size_t i = 0; i < rank; ++i) - { - if (idx[i] != boundary[i]) - { - pte = false; - break; - } - } index_size_type multiplier = 1; index_size_type res = 0; - if (pte) + if (!less(idx, boundary)) { res = 1; for (size_t i = rank; i-- > 0;) @@ -1130,19 +1126,15 @@ private: } return res; } + value_type boundary; - value_type curr; + std::remove_const_t curr; }; template -class bounds_iterator> - : public std::iterator, - ptrdiff_t, - const details::arrow_proxy>, - const index<1, SizeType>> +class bounds_iterator> : public std::iterator> { - using Base = std::iterator, ptrdiff_t, const details::arrow_proxy>, const index<1, SizeType>>; + using Base = std::iterator>; public: using typename Base::reference; @@ -1153,96 +1145,116 @@ public: using index_size_type = typename index_type::value_type; template - explicit bounds_iterator(const Bounds &, value_type curr = value_type{}) noexcept - : curr( std::move(curr) ) + constexpr explicit bounds_iterator(const Bounds&, value_type curr) noexcept + : curr(std::move(curr)) {} - reference operator*() const noexcept + + constexpr reference operator*() const noexcept { return curr; } - pointer operator->() const noexcept + + constexpr pointer operator->() const noexcept { - return details::arrow_proxy{ curr }; + &curr; } - bounds_iterator& operator++() noexcept + + constexpr bounds_iterator& operator++() noexcept { ++curr; return *this; } - bounds_iterator operator++(int) noexcept + + constexpr bounds_iterator operator++(int) noexcept { auto ret = *this; ++(*this); return ret; } - bounds_iterator& operator--() noexcept + + constexpr bounds_iterator& operator--() noexcept { curr--; return *this; } - bounds_iterator operator--(int) noexcept + + constexpr bounds_iterator operator--(int) noexcept { auto ret = *this; --(*this); return ret; } - bounds_iterator operator+(difference_type n) const noexcept + + constexpr bounds_iterator operator+(difference_type n) const noexcept { bounds_iterator ret{ *this }; return ret += n; } - bounds_iterator& operator+=(difference_type n) noexcept + + constexpr bounds_iterator& operator+=(difference_type n) noexcept { curr += n; return *this; } - bounds_iterator operator-(difference_type n) const noexcept + + constexpr bounds_iterator operator-(difference_type n) const noexcept { bounds_iterator ret{ *this }; return ret -= n; } - bounds_iterator& operator-=(difference_type n) noexcept + + constexpr bounds_iterator& operator-=(difference_type n) noexcept { return *this += -n; } - difference_type operator-(const bounds_iterator& rhs) const noexcept + + constexpr difference_type operator-(const bounds_iterator& rhs) const noexcept { return curr[0] - rhs.curr[0]; } - reference operator[](difference_type n) const noexcept + + constexpr reference operator[](difference_type n) const noexcept { return curr + n; } - bool operator==(const bounds_iterator& rhs) const noexcept + + constexpr bool operator==(const bounds_iterator& rhs) const noexcept { return curr == rhs.curr; } - bool operator!=(const bounds_iterator& rhs) const noexcept + + constexpr bool operator!=(const bounds_iterator& rhs) const noexcept { return !(*this == rhs); } - bool operator<(const bounds_iterator& rhs) const noexcept + + constexpr bool operator<(const bounds_iterator& rhs) const noexcept { return curr[0] < rhs.curr[0]; } - bool operator<=(const bounds_iterator& rhs) const noexcept + + constexpr bool operator<=(const bounds_iterator& rhs) const noexcept { return !(rhs < *this); } - bool operator>(const bounds_iterator& rhs) const noexcept + + constexpr bool operator>(const bounds_iterator& rhs) const noexcept { return rhs < *this; } - bool operator>=(const bounds_iterator& rhs) const noexcept + + constexpr bool operator>=(const bounds_iterator& rhs) const noexcept { return !(rhs > *this); } - void swap(bounds_iterator& rhs) noexcept + + constexpr void swap(bounds_iterator& rhs) noexcept { std::swap(curr, rhs.curr); } + private: - value_type curr; + std::remove_const_t curr; }; template @@ -1304,10 +1316,11 @@ public: using size_type = typename bounds_type::size_type; using index_type = typename bounds_type::index_type; using value_type = ValueType; + using const_value_type = std::add_const_t; using pointer = ValueType*; using reference = ValueType&; using iterator = std::conditional_t::value, contiguous_array_view_iterator, general_array_view_iterator>; - using const_iterator = std::conditional_t::value, contiguous_array_view_iterator>, general_array_view_iterator>>; + using const_iterator = std::conditional_t::value, contiguous_array_view_iterator>, general_array_view_iterator>>; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; using sliced_type = std::conditional_t>; @@ -1360,7 +1373,7 @@ public: } constexpr iterator end() const { - return iterator {this}; + return iterator {this, false}; } constexpr const_iterator cbegin() const { @@ -1368,7 +1381,7 @@ public: } constexpr const_iterator cend() const { - return const_iterator {reinterpret_cast *>(this)}; + return const_iterator {reinterpret_cast *>(this), false}; } constexpr reverse_iterator rbegin() const @@ -1999,8 +2012,8 @@ private: { 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"); } - contiguous_array_view_iterator (const ArrayView *container, bool isbegin = false) : - m_pdata(isbegin ? container->m_pdata : container->m_pdata + container->size()), m_validator(container) { } + contiguous_array_view_iterator (const ArrayView *container, bool isbegin) : + m_pdata(isbegin ? container->m_pdata : container->m_pdata + container->size()), m_validator(container) {} public: reference operator*() const noexcept { @@ -2115,16 +2128,16 @@ private: friend class basic_array_view; const ArrayView * m_container; typename ArrayView::bounds_type::iterator m_itr; - general_array_view_iterator(const ArrayView *container, bool isbegin = false) : + general_array_view_iterator(const ArrayView *container, bool isbegin) : m_container(container), m_itr(isbegin ? m_container->bounds().begin() : m_container->bounds().end()) { } public: - reference operator*() const noexcept + reference operator*() noexcept { return (*m_container)[*m_itr]; } - pointer operator->() const noexcept + pointer operator->() noexcept { return &(*m_container)[*m_itr]; } diff --git a/tests/array_view_tests.cpp b/tests/array_view_tests.cpp index f84e908..cf83fd5 100644 --- a/tests/array_view_tests.cpp +++ b/tests/array_view_tests.cpp @@ -925,11 +925,35 @@ SUITE(array_view_tests) } } - size_t idx = 0; - for (auto num : section) + size_t check_sum = 0; + for (size_t i = 0; i < length; ++i) { - CHECK(num == av[idx][1]); - idx++; + check_sum += av[i][1]; + } + + { + size_t idx = 0; + size_t sum = 0; + for (auto num : section) + { + CHECK(num == av[idx][1]); + sum += num; + idx++; + } + + CHECK(sum == check_sum); + } + { + size_t idx = length - 1; + size_t sum = 0; + for (auto iter = section.rbegin(); iter != section.rend(); ++iter) + { + CHECK(*iter == av[idx][1]); + sum += *iter; + idx--; + } + + CHECK(sum == check_sum); } } @@ -1688,7 +1712,7 @@ SUITE(array_view_tests) CHECK_THROW(f(), fail_fast); } - TEST(AsWriteableBytes) + TEST(AsWriteableBytes) { int a[] = { 1, 2, 3, 4 }; @@ -1714,7 +1738,36 @@ SUITE(array_view_tests) CHECK(wav.data() == (byte*)&a[0]); CHECK(wav.length() == sizeof(a)); } + } + TEST(NonConstIterator) + { + int a[] = { 1, 2, 3, 4 }; + + { + array_view av = a; + auto wav = av.as_writeable_bytes(); + for (auto& b : wav) + { + b = byte(0); + } + for (size_t i = 0; i < 4; ++i) + { + CHECK(a[i] == 0); + } + } + + { + array_view av = a; + for (auto& n : av) + { + n = 1; + } + for (size_t i = 0; i < 4; ++i) + { + CHECK(a[i] == 1); + } + } } TEST(ArrayViewComparison) From a544ada8fe998bc7c47be942008430a7ec8366da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20Garc=C3=ADa=20Salas?= Date: Sat, 17 Oct 2015 08:53:58 +0200 Subject: [PATCH 10/13] std::hash support for gsl::not_null. --- include/gsl.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/gsl.h b/include/gsl.h index 519682b..ca37848 100644 --- a/include/gsl.h +++ b/include/gsl.h @@ -197,6 +197,19 @@ private: } // namespace gsl +namespace std +{ + template + struct hash> + { + size_t operator()(const gsl::not_null & value) const + { + return hash{}(value); + } + }; + +} // namespace std + #ifdef _MSC_VER #undef constexpr From 8e2acc9c901c658cfcce013ecaf594b9565b2fdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20Garc=C3=ADa=20Salas?= Date: Sat, 17 Oct 2015 09:28:05 +0200 Subject: [PATCH 11/13] std::hash support for gsl::not_null. --- include/gsl.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/gsl.h b/include/gsl.h index ca37848..ec75723 100644 --- a/include/gsl.h +++ b/include/gsl.h @@ -200,11 +200,11 @@ private: namespace std { template - struct hash> + struct hash> { - size_t operator()(const gsl::not_null & value) const + size_t operator()(const gsl::not_null & value) const { - return hash{}(value); + return hash{}(value); } }; From 5f26ddac70f05766070b5b62ecabb7086f0df7c2 Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Fri, 16 Oct 2015 17:30:48 -0700 Subject: [PATCH 12/13] Replaced index constructor from initializer list by a constructor from static list Conflicts: include/array_view.h --- include/array_view.h | 11 ++-- tests/array_view_tests.cpp | 110 +++++++++++++++++++++++++++++++------ 2 files changed, 96 insertions(+), 25 deletions(-) diff --git a/include/array_view.h b/include/array_view.h index a31efd8..a2ea49f 100644 --- a/include/array_view.h +++ b/include/array_view.h @@ -72,7 +72,7 @@ namespace details template struct SizeTypeTraits { - static const SizeType max_value = std::is_signed::value ? static_cast::type>(-1) / 2 : static_cast(-1); + static const SizeType max_value = std::numeric_limits::max(); }; } @@ -99,12 +99,9 @@ public: std::copy(values, values + Rank, elems); } - // Preconditions: il.size() == rank - constexpr index(std::initializer_list il) noexcept - { - fail_fast_assert(il.size() == Rank, "The size of the initializer list must match the rank of the array"); - std::copy(begin(il), end(il), elems); - } + template> + constexpr index(Ts... ds) noexcept : elems{ static_cast(ds)... } + {} constexpr index(const index& other) noexcept = default; diff --git a/tests/array_view_tests.cpp b/tests/array_view_tests.cpp index cf83fd5..3a8acc2 100644 --- a/tests/array_view_tests.cpp +++ b/tests/array_view_tests.cpp @@ -16,16 +16,11 @@ #include #include -#include -#include -#include + #include #include #include #include -#include -#include - using namespace std; using namespace gsl; @@ -639,23 +634,14 @@ SUITE(array_view_tests) index<1> index{ 0, 1 }; strided_array_view sav8{ arr,{ 1,{ 1,1 } } }; -#ifdef _MSC_VER strided_array_view sav9{ arr,{ { 1,1 },{ 1,1 } } }; -#endif strided_array_view sav10{ av,{ 1,{ 1,1 } } }; -#ifdef _MSC_VER strided_array_view sav11{ av,{ { 1,1 },{ 1,1 } } }; -#endif + strided_array_view sav12{ av.as_array_view(dim<2>(), dim<2>()),{ { 1 },{ 1 } } }; + strided_array_view sav13{ av.as_array_view(dim<2>(), dim<2>()),{ { 1 },{ 1,1,1 } } }; + strided_array_view sav14{ av.as_array_view(dim<2>(), dim<2>()),{ { 1,1,1 },{ 1 } } }; } #endif - - { - CHECK_THROW((strided_array_view{ av.as_array_view(dim<2>(), dim<2>()), {{1}, {1}} }), fail_fast); - CHECK_THROW((strided_array_view{ av.as_array_view(dim<2>(), dim<2>()), {{1}, {1,1,1}} }), fail_fast); -#ifdef _MSC_VER - CHECK_THROW((strided_array_view{ av.as_array_view(dim<2>(), dim<2>()), {{1,1,1}, {1}} }), fail_fast); -#endif - } } TEST(strided_array_view_type_conversion) @@ -839,6 +825,94 @@ SUITE(array_view_tests) delete[] arr; } + TEST(index_constructors) + { + { + // components of the same type + index<3> i1(0, 1, 2); + CHECK(i1[0] == 0); + + // components of different types + size_t c0 = 0; + size_t c1 = 1; + index<3> i2(c0, c1, 2); + CHECK(i2[0] == 0); + + // from array + index<3> i3 = { 0,1,2 }; + CHECK(i3[0] == 0); + + // from other index of the same size type + index<3> i4 = i3; + CHECK(i4[0] == 0); + + // from other index of bigger size type + index<3, short> i5 = i4; + CHECK(i5[0] == 0); + + // from other index of smaller size type + index<3, long long> i6 = i4; + CHECK(i6[0] == 0); + + // default + index<3, long long> i7; + CHECK(i7[0] == 0); + + // default + index<3, long long> i9 = {}; + CHECK(i9[0] == 0); + } + + { + // components of the same type + index<1> i1(0); + CHECK(i1[0] == 0); + + // components of different types + size_t c0 = 0; + index<1> i2(c0); + CHECK(i2[0] == 0); + + // from array + index<1> i3 = { 0 }; + CHECK(i3[0] == 0); + + // from int + index<1> i4 = 0; + CHECK(i4[0] == 0); + + // from other index of the same size type + index<1> i5 = i3; + CHECK(i5[0] == 0); + + // from other index of bigger size type + index<1, short> i6 = i5; + CHECK(i6[0] == 0); + + // from other index of smaller size type + index<1, long long> i7 = i6; + CHECK(i7[0] == 0); + + // default + index<1, long long> i8; + CHECK(i8[0] == 0); + + // default + index<1, long long> i9 = {}; + CHECK(i9[0] == 0); + } + +#ifdef CONFIRM_COMPILATION_ERRORS + { + index<3> i1(0, 1); + index<3> i2(0, 1, 2, 3); + index<3> i3 = { 0 }; + index<3> i4 = { 0, 1, 2, 3 }; + index<1> i5 = { 0,1 }; + } +#endif + } + TEST(index_operations) { size_t a[3] = { 0, 1, 2 }; From 1c208b33d0823dabed0832b91ce6e56fbcd046cd Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Fri, 16 Oct 2015 17:40:57 -0700 Subject: [PATCH 13/13] Removed specializations for Rank=1 --- include/array_view.h | 271 ++----------------------------------------- 1 file changed, 8 insertions(+), 263 deletions(-) diff --git a/include/array_view.h b/include/array_view.h index a2ea49f..0145799 100644 --- a/include/array_view.h +++ b/include/array_view.h @@ -74,6 +74,13 @@ namespace details { static const SizeType max_value = std::numeric_limits::max(); }; + + + template + class are_integral : public std::integral_constant {}; + + template + class are_integral : public std::integral_constant::value && are_integral::value> {}; } template @@ -99,7 +106,7 @@ public: std::copy(values, values + Rank, elems); } - template> + template::value, typename Dummy = std::enable_if_t> constexpr index(Ts... ds) noexcept : elems{ static_cast(ds)... } {} @@ -227,142 +234,6 @@ private: value_type elems[Rank] = {}; }; -template -class index<1, ValueType> -{ - template - friend class index; - -public: - static const size_t rank = 1; - using value_type = std::remove_reference_t; - using reference = std::add_lvalue_reference_t; - using const_reference = std::add_lvalue_reference_t>; - - constexpr index() noexcept : value(0) - {} - - constexpr index(value_type e) noexcept : value(e) - {} - - constexpr index(const value_type(&values)[1]) noexcept : index(values[0]) - {} - - constexpr index(const index &) noexcept = default; - - template ::max_value <= details::SizeTypeTraits::max_value), - typename Other = std::enable_if_t>> - constexpr index(const index<1, OtherValueType>& other) noexcept - { - value = static_cast(other.value); - } - - template ::max_value > details::SizeTypeTraits::max_value), - typename Other = std::enable_if_t>> - constexpr index(const index<1, OtherValueType>& other, void* ptr=0) noexcept - { - fail_fast_assert(other.value <= static_cast(details::SizeTypeTraits::max_value)); - value = static_cast(other.value); - } - - // Preconditions: component_idx < 1 - constexpr reference operator[](value_type component_idx) noexcept - { - fail_fast_assert(component_idx == 0, "Component index must be less than rank"); - (void)(component_idx); - return value; - } - // Preconditions: component_idx < 1 - constexpr const_reference operator[](value_type component_idx) const noexcept - { - fail_fast_assert(component_idx == 0, "Component index must be less than rank"); - (void)(component_idx); - return value; - } - constexpr bool operator==(const index& rhs) const noexcept - { - return value == rhs.value; - } - constexpr bool operator!=(const index& rhs) const noexcept - { - return !(*this == rhs); - } - constexpr index operator+() const noexcept - { - return *this; - } - constexpr index operator-() const noexcept - { - return index(-value); - } - constexpr index operator+(const index& rhs) const noexcept - { - return index(value + rhs.value); - } - constexpr index operator-(const index& rhs) const noexcept - { - return index(value - rhs.value); - } - constexpr index& operator+=(const index& rhs) noexcept - { - value += rhs.value; - return *this; - } - constexpr index& operator-=(const index& rhs) noexcept - { - value -= rhs.value; - return *this; - } - constexpr index& operator++() noexcept - { - ++value; - return *this; - } - constexpr index operator++(int) noexcept - { - index ret = *this; - ++(*this); - return ret; - } - constexpr index& operator--() noexcept - { - --value; - return *this; - } - constexpr index operator--(int) noexcept - { - index ret = *this; - --(*this); - return ret; - } - constexpr index operator*(value_type v) const noexcept - { - return index(value * v); - } - constexpr index operator/(value_type v) const noexcept - { - return index(value / v); - } - constexpr index& operator*=(value_type v) noexcept - { - value *= v; - return *this; - } - constexpr index& operator/=(value_type v) noexcept - { - value /= v; - return *this; - } - friend constexpr index operator*(value_type v, const index& rhs) noexcept - { - return{ rhs * v }; - } -private: - value_type value; -}; - #ifndef _MSC_VER struct static_bounds_dynamic_range_t @@ -1128,132 +999,6 @@ private: std::remove_const_t curr; }; -template -class bounds_iterator> : public std::iterator> -{ - using Base = std::iterator>; - -public: - using typename Base::reference; - using typename Base::pointer; - using typename Base::difference_type; - using typename Base::value_type; - using index_type = value_type; - using index_size_type = typename index_type::value_type; - - template - constexpr explicit bounds_iterator(const Bounds&, value_type curr) noexcept - : curr(std::move(curr)) - {} - - constexpr reference operator*() const noexcept - { - return curr; - } - - constexpr pointer operator->() const noexcept - { - &curr; - } - - constexpr bounds_iterator& operator++() noexcept - { - ++curr; - return *this; - } - - constexpr bounds_iterator operator++(int) noexcept - { - auto ret = *this; - ++(*this); - return ret; - } - - constexpr bounds_iterator& operator--() noexcept - { - curr--; - return *this; - } - - constexpr bounds_iterator operator--(int) noexcept - { - auto ret = *this; - --(*this); - return ret; - } - - constexpr bounds_iterator operator+(difference_type n) const noexcept - { - bounds_iterator ret{ *this }; - return ret += n; - } - - constexpr bounds_iterator& operator+=(difference_type n) noexcept - { - curr += n; - return *this; - } - - constexpr bounds_iterator operator-(difference_type n) const noexcept - { - bounds_iterator ret{ *this }; - return ret -= n; - } - - constexpr bounds_iterator& operator-=(difference_type n) noexcept - { - return *this += -n; - } - - constexpr difference_type operator-(const bounds_iterator& rhs) const noexcept - { - return curr[0] - rhs.curr[0]; - } - - constexpr reference operator[](difference_type n) const noexcept - { - return curr + 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 curr[0] < rhs.curr[0]; - } - - 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 void swap(bounds_iterator& rhs) noexcept - { - std::swap(curr, rhs.curr); - } - -private: - std::remove_const_t curr; -}; - template bounds_iterator operator+(typename bounds_iterator::difference_type n, const bounds_iterator& rhs) noexcept {