From 2bf9f137a6ff12aa53424fd7d86510247216acb8 Mon Sep 17 00:00:00 2001 From: Ian Taylor Date: Mon, 5 Nov 2018 18:26:27 -0500 Subject: [PATCH 1/2] make BoundsRanges constexpr (#732) * make BoundsRanges constexpr * fix clang compilation error * fix windows compilation --- include/gsl/multi_span | 62 +++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/include/gsl/multi_span b/include/gsl/multi_span index c8f4aae..dbfff92 100644 --- a/include/gsl/multi_span +++ b/include/gsl/multi_span @@ -315,33 +315,33 @@ namespace details // TODO : following signature is for work around VS bug template - BoundsRanges(const OtherRange&, bool /* firstLevel */) + constexpr BoundsRanges(const OtherRange&, bool /* firstLevel */) {} - BoundsRanges(const std::ptrdiff_t* const) {} - BoundsRanges() noexcept = default; + constexpr BoundsRanges(const std::ptrdiff_t* const) {} + constexpr BoundsRanges() noexcept = default; template - void serialize(T&) const + constexpr void serialize(T&) const {} template - size_type linearize(const T&) const + constexpr size_type linearize(const T&) const { return 0; } template - size_type contains(const T&) const + constexpr size_type contains(const T&) const { return -1; } - size_type elementNum(std::size_t) const noexcept { return 0; } + constexpr size_type elementNum(std::size_t) const noexcept { return 0; } - size_type totalSize() const noexcept { return TotalSize; } + constexpr size_type totalSize() const noexcept { return TotalSize; } - bool operator==(const BoundsRanges&) const noexcept { return true; } + constexpr bool operator==(const BoundsRanges&) const noexcept { return true; } }; template @@ -360,23 +360,23 @@ namespace details public: GSL_SUPPRESS(f.23) // NO-FORMAT: attribute // this pointer type is cannot be assigned nullptr - issue in not_null GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - BoundsRanges(const std::ptrdiff_t* const arr) + constexpr BoundsRanges(const std::ptrdiff_t* const arr) : Base(arr + 1), m_bound(*arr * this->Base::totalSize()) { Expects(0 <= *arr); } - BoundsRanges() noexcept : m_bound(0) {} + constexpr BoundsRanges() noexcept : m_bound(0) {} template - BoundsRanges(const BoundsRanges& other, + constexpr BoundsRanges(const BoundsRanges& other, bool /* firstLevel */ = true) : Base(static_cast&>(other), false) , m_bound(other.totalSize()) {} template - void serialize(T& arr) const + constexpr void serialize(T& arr) const { arr[Dim] = elementNum(); this->Base::template serialize(arr); @@ -384,7 +384,7 @@ namespace details template GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute - size_type linearize(const T& arr) const + constexpr size_type linearize(const T& arr) const { const size_type index = this->Base::totalSize() * arr[Dim]; Expects(index < m_bound); @@ -392,7 +392,7 @@ namespace details } template - size_type contains(const T& arr) const + constexpr size_type contains(const T& arr) const { const ptrdiff_t last = this->Base::template contains(arr); if (last == -1) return -1; @@ -401,18 +401,18 @@ namespace details } GSL_SUPPRESS(c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used - size_type totalSize() const noexcept + constexpr size_type totalSize() const noexcept { return m_bound; } GSL_SUPPRESS(c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used - size_type elementNum() const noexcept + constexpr size_type elementNum() const noexcept { return totalSize() / this->Base::totalSize(); } - size_type elementNum(std::size_t dim) const noexcept + constexpr size_type elementNum(std::size_t dim) const noexcept { if (dim > 0) return this->Base::elementNum(dim - 1); @@ -420,7 +420,7 @@ namespace details return elementNum(); } - bool operator==(const BoundsRanges& rhs) const noexcept + constexpr bool operator==(const BoundsRanges& rhs) const noexcept { return m_bound == rhs.m_bound && static_cast(*this) == static_cast(rhs); @@ -438,11 +438,11 @@ namespace details static const size_type TotalSize = Base::TotalSize == dynamic_range ? dynamic_range : CurrentRange * Base::TotalSize; - BoundsRanges(const std::ptrdiff_t* const arr) : Base(arr) {} - BoundsRanges() = default; + constexpr BoundsRanges(const std::ptrdiff_t* const arr) : Base(arr) {} + constexpr BoundsRanges() = default; template - BoundsRanges(const BoundsRanges& other, + constexpr BoundsRanges(const BoundsRanges& other, bool firstLevel = true) : Base(static_cast&>(other), false) { @@ -451,25 +451,25 @@ namespace details } template - void serialize(T& arr) const + constexpr void serialize(T& arr) const { arr[Dim] = elementNum(); this->Base::template serialize(arr); } template - size_type linearize(const T& arr) const + constexpr size_type linearize(const T& arr) const { GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute Expects(arr[Dim] >= 0 && arr[Dim] < CurrentRange); // Index is out of range - GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute - return this->Base::totalSize() * arr[Dim] + + const ptrdiff_t d = arr[Dim]; + return this->Base::totalSize() * d + this->Base::template linearize(arr); } template - size_type contains(const T& arr) const + constexpr size_type contains(const T& arr) const { if (arr[Dim] >= CurrentRange) return -1; const size_type last = this->Base::template contains(arr); @@ -478,19 +478,19 @@ namespace details } GSL_SUPPRESS(c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used - size_type totalSize() const noexcept + constexpr size_type totalSize() const noexcept { return CurrentRange * this->Base::totalSize(); } GSL_SUPPRESS(c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used - size_type elementNum() const noexcept + constexpr size_type elementNum() const noexcept { return CurrentRange; } GSL_SUPPRESS(c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used - size_type elementNum(std::size_t dim) const noexcept + constexpr size_type elementNum(std::size_t dim) const noexcept { if (dim > 0) return this->Base::elementNum(dim - 1); @@ -498,7 +498,7 @@ namespace details return elementNum(); } - bool operator==(const BoundsRanges& rhs) const noexcept + constexpr bool operator==(const BoundsRanges& rhs) const noexcept { return static_cast(*this) == static_cast(rhs); } From c02ddae4bcff82b17826fe3127e835f5aa54b485 Mon Sep 17 00:00:00 2001 From: Dave Hill Date: Mon, 5 Nov 2018 15:39:41 -0800 Subject: [PATCH 2/2] Span can be constructed from empty std::array safely (#686) * Span std::array c'tor uses arr.data() instead of &arr[0] - Fixes runtime issues when constructing from an empty std::array * Construct span with std::data if C++17 detected * Specialize span c'tor for std::array of length 0, set storage to nullptr --- include/gsl/span | 28 +++++++++++++++++++--------- tests/span_tests.cpp | 8 +++++++- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index 8cb3dbe..b356ee9 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -394,17 +394,27 @@ public: : storage_(KnownNotNull{std::addressof(arr[0])}, details::extent_type()) {} - template > - // GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // TODO: parser bug - constexpr span(std::array& arr) noexcept - : storage_(arr.data(), details::extent_type()) - {} + template 0)>> + constexpr span(std::array, N>& arr) noexcept + : storage_(KnownNotNull{arr.data()}, details::extent_type()) + { + } - template - // GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // TODO: parser bug + constexpr span(std::array, 0>&) noexcept + : storage_(static_cast(nullptr), details::extent_type<0>()) + { + } + + template 0)>> constexpr span(const std::array, N>& arr) noexcept - : storage_(arr.data(), details::extent_type()) - {} + : storage_(KnownNotNull{arr.data()}, details::extent_type()) + { + } + + constexpr span(const std::array, 0>&) noexcept + : storage_(static_cast(nullptr), details::extent_type<0>()) + { + } // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the requirement // on Container to be a contiguous sequence container. diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index 07a59c8..b38b4eb 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -452,7 +452,13 @@ TEST_CASE("from_std_array_constructor") CHECK((cs.size() == narrow_cast(arr.size()) && cs.data() == arr.data())); } - std::array ao_arr{}; + { + std::array empty_arr{}; + span s{empty_arr}; + CHECK((s.size() == 0 && s.empty())); + } + + std::array ao_arr{}; { span fs{ao_arr};