simplified constructors and removed GSL_NOEXCEPT in span (#639)

- simplified storage constructors to reduce branching
- eliminated null check for constructor from array
- removed GSL_NOEXCEPT in span
This commit is contained in:
Anna Gringauze 2018-03-15 12:14:29 -07:00 committed by GitHub
parent c9e423d7cf
commit c6bf25a5f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 60 additions and 50 deletions

View File

@ -58,8 +58,6 @@
#endif // _MSC_VER #endif // _MSC_VER
#define GSL_NOEXCEPT noexcept
namespace gsl namespace gsl
{ {
@ -136,13 +134,13 @@ namespace details
span_iterator() = default; span_iterator() = default;
constexpr span_iterator(const Span* span, typename Span::index_type idx) GSL_NOEXCEPT constexpr span_iterator(const Span* span, typename Span::index_type idx) noexcept
: span_(span), index_(idx) : span_(span), index_(idx)
{} {}
friend span_iterator<Span, true>; friend span_iterator<Span, true>;
template<bool B, std::enable_if_t<!B && IsConst>* = nullptr> template<bool B, std::enable_if_t<!B && IsConst>* = nullptr>
constexpr span_iterator(const span_iterator<Span, B>& other) GSL_NOEXCEPT constexpr span_iterator(const span_iterator<Span, B>& other) noexcept
: span_iterator(other.span_, other.index_) : span_iterator(other.span_, other.index_)
{ {
} }
@ -220,37 +218,37 @@ namespace details
} }
constexpr friend bool operator==(span_iterator lhs, constexpr friend bool operator==(span_iterator lhs,
span_iterator rhs) GSL_NOEXCEPT span_iterator rhs) noexcept
{ {
return lhs.span_ == rhs.span_ && lhs.index_ == rhs.index_; return lhs.span_ == rhs.span_ && lhs.index_ == rhs.index_;
} }
constexpr friend bool operator!=(span_iterator lhs, constexpr friend bool operator!=(span_iterator lhs,
span_iterator rhs) GSL_NOEXCEPT span_iterator rhs) noexcept
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
constexpr friend bool operator<(span_iterator lhs, constexpr friend bool operator<(span_iterator lhs,
span_iterator rhs) GSL_NOEXCEPT span_iterator rhs) noexcept
{ {
return lhs.index_ < rhs.index_; return lhs.index_ < rhs.index_;
} }
constexpr friend bool operator<=(span_iterator lhs, constexpr friend bool operator<=(span_iterator lhs,
span_iterator rhs) GSL_NOEXCEPT span_iterator rhs) noexcept
{ {
return !(rhs < lhs); return !(rhs < lhs);
} }
constexpr friend bool operator>(span_iterator lhs, constexpr friend bool operator>(span_iterator lhs,
span_iterator rhs) GSL_NOEXCEPT span_iterator rhs) noexcept
{ {
return rhs < lhs; return rhs < lhs;
} }
constexpr friend bool operator>=(span_iterator lhs, constexpr friend bool operator>=(span_iterator lhs,
span_iterator rhs) GSL_NOEXCEPT span_iterator rhs) noexcept
{ {
return !(rhs > lhs); return !(rhs > lhs);
} }
@ -284,7 +282,7 @@ namespace details
static_assert(Ext >= 0, "A fixed-size span must be >= 0 in size."); static_assert(Ext >= 0, "A fixed-size span must be >= 0 in size.");
constexpr extent_type() GSL_NOEXCEPT {} constexpr extent_type() noexcept {}
template <index_type Other> template <index_type Other>
constexpr extent_type(extent_type<Other> ext) constexpr extent_type(extent_type<Other> ext)
@ -296,7 +294,7 @@ namespace details
constexpr extent_type(index_type size) { Expects(size == Ext); } constexpr extent_type(index_type size) { Expects(size == Ext); }
constexpr index_type size() const GSL_NOEXCEPT { return Ext; } constexpr index_type size() const noexcept { return Ext; }
}; };
template <> template <>
@ -312,7 +310,7 @@ namespace details
explicit constexpr extent_type(index_type size) : size_(size) { Expects(size >= 0); } explicit constexpr extent_type(index_type size) : size_(size) { Expects(size >= 0); }
constexpr index_type size() const GSL_NOEXCEPT { return size_; } constexpr index_type size() const noexcept { return size_; }
private: private:
index_type size_; index_type size_;
@ -355,7 +353,7 @@ public:
// "Dependent" is needed to make "std::enable_if_t<Dependent || Extent <= 0>" SFINAE, // "Dependent" is needed to make "std::enable_if_t<Dependent || Extent <= 0>" SFINAE,
// since "std::enable_if_t<Extent <= 0>" is ill-formed when Extent is greater than 0. // since "std::enable_if_t<Extent <= 0>" is ill-formed when Extent is greater than 0.
class = std::enable_if_t<(Dependent || Extent <= 0)>> class = std::enable_if_t<(Dependent || Extent <= 0)>>
constexpr span() GSL_NOEXCEPT : storage_(nullptr, details::extent_type<0>()) constexpr span() noexcept : storage_(nullptr, details::extent_type<0>())
{ {
} }
@ -367,19 +365,19 @@ public:
} }
template <std::size_t N> template <std::size_t N>
constexpr span(element_type (&arr)[N]) GSL_NOEXCEPT constexpr span(element_type (&arr)[N]) noexcept
: storage_(&arr[0], details::extent_type<N>()) : storage_(KnownNotNull{&arr[0]}, details::extent_type<N>())
{ {
} }
template <std::size_t N, class ArrayElementType = std::remove_const_t<element_type>> template <std::size_t N, class ArrayElementType = std::remove_const_t<element_type>>
constexpr span(std::array<ArrayElementType, N>& arr) GSL_NOEXCEPT constexpr span(std::array<ArrayElementType, N>& arr) noexcept
: storage_(&arr[0], details::extent_type<N>()) : storage_(&arr[0], details::extent_type<N>())
{ {
} }
template <std::size_t N> template <std::size_t N>
constexpr span(const std::array<std::remove_const_t<element_type>, N>& arr) GSL_NOEXCEPT constexpr span(const std::array<std::remove_const_t<element_type>, N>& arr) noexcept
: storage_(&arr[0], details::extent_type<N>()) : storage_(&arr[0], details::extent_type<N>())
{ {
} }
@ -406,7 +404,7 @@ public:
{ {
} }
constexpr span(const span& other) GSL_NOEXCEPT = default; constexpr span(const span& other) noexcept = default;
template < template <
class OtherElementType, std::ptrdiff_t OtherExtent, class OtherElementType, std::ptrdiff_t OtherExtent,
@ -418,8 +416,8 @@ public:
{ {
} }
~span() GSL_NOEXCEPT = default; ~span() noexcept = default;
constexpr span& operator=(const span& other) GSL_NOEXCEPT = default; constexpr span& operator=(const span& other) noexcept = default;
// [span.sub], span subviews // [span.sub], span subviews
template <std::ptrdiff_t Count> template <std::ptrdiff_t Count>
@ -464,12 +462,12 @@ public:
// [span.obs], span observers // [span.obs], span observers
constexpr index_type size() const GSL_NOEXCEPT { return storage_.size(); } constexpr index_type size() const noexcept { return storage_.size(); }
constexpr index_type size_bytes() const GSL_NOEXCEPT constexpr index_type size_bytes() const noexcept
{ {
return size() * narrow_cast<index_type>(sizeof(element_type)); return size() * narrow_cast<index_type>(sizeof(element_type));
} }
constexpr bool empty() const GSL_NOEXCEPT { return size() == 0; } constexpr bool empty() const noexcept { return size() == 0; }
// [span.elem], span element access // [span.elem], span element access
constexpr reference operator[](index_type idx) const constexpr reference operator[](index_type idx) const
@ -480,22 +478,29 @@ public:
constexpr reference at(index_type idx) const { return this->operator[](idx); } constexpr reference at(index_type idx) const { return this->operator[](idx); }
constexpr reference operator()(index_type idx) const { return this->operator[](idx); } constexpr reference operator()(index_type idx) const { return this->operator[](idx); }
constexpr pointer data() const GSL_NOEXCEPT { return storage_.data(); } constexpr pointer data() const noexcept { return storage_.data(); }
// [span.iter], span iterator support // [span.iter], span iterator support
constexpr iterator begin() const GSL_NOEXCEPT { return {this, 0}; } constexpr iterator begin() const noexcept { return {this, 0}; }
constexpr iterator end() const GSL_NOEXCEPT { return {this, size()}; } constexpr iterator end() const noexcept { return {this, size()}; }
constexpr const_iterator cbegin() const GSL_NOEXCEPT { return {this, 0}; } constexpr const_iterator cbegin() const noexcept { return {this, 0}; }
constexpr const_iterator cend() const GSL_NOEXCEPT { return {this, size()}; } constexpr const_iterator cend() const noexcept { return {this, size()}; }
constexpr reverse_iterator rbegin() const GSL_NOEXCEPT { return reverse_iterator{end()}; } constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
constexpr reverse_iterator rend() const GSL_NOEXCEPT { return reverse_iterator{begin()}; } constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
constexpr const_reverse_iterator crbegin() const GSL_NOEXCEPT { return const_reverse_iterator{cend()}; } constexpr const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator{cend()}; }
constexpr const_reverse_iterator crend() const GSL_NOEXCEPT { return const_reverse_iterator{cbegin()}; } constexpr const_reverse_iterator crend() const noexcept { return const_reverse_iterator{cbegin()}; }
private: private:
// Needed to remove unnecessary null check in subspans
struct KnownNotNull
{
pointer p;
};
// this implementation detail class lets us take advantage of the // this implementation detail class lets us take advantage of the
// empty base class optimization to pay for only storage of a single // empty base class optimization to pay for only storage of a single
// pointer in the case of fixed-size spans // pointer in the case of fixed-size spans
@ -503,16 +508,23 @@ private:
class storage_type : public ExtentType class storage_type : public ExtentType
{ {
public: public:
// KnownNotNull parameter is needed to remove unnecessary null check
// checked parameter is needed to remove unnecessary null check in subspans // in subspans and constructors from arrays
template <class OtherExtentType> template <class OtherExtentType>
constexpr storage_type(pointer data, OtherExtentType ext, bool checked = false) : ExtentType(ext), data_(data) constexpr storage_type(KnownNotNull data, OtherExtentType ext) : ExtentType(ext), data_(data.p)
{ {
Expects(((checked || !data) && ExtentType::size() == 0) || Expects(ExtentType::size() >= 0);
((checked || data) && ExtentType::size() >= 0));
} }
constexpr pointer data() const GSL_NOEXCEPT { return data_; }
template <class OtherExtentType>
constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data)
{
Expects(ExtentType::size() >= 0);
Expects(data || ExtentType::size() == 0);
}
constexpr pointer data() const noexcept { return data_; }
private: private:
pointer data_; pointer data_;
@ -520,8 +532,9 @@ private:
storage_type<details::extent_type<Extent>> storage_; storage_type<details::extent_type<Extent>> storage_;
// The rest is needed to remove unnecessary null check in subspans // The rest is needed to remove unnecessary null check
constexpr span(pointer ptr, index_type count, bool checked) : storage_(ptr, count, checked) {} // in subspans and constructors from arrays
constexpr span(KnownNotNull ptr, index_type count) : storage_(ptr, count) {}
template <std::ptrdiff_t CallerExtent> template <std::ptrdiff_t CallerExtent>
class subspan_selector {}; class subspan_selector {};
@ -542,11 +555,11 @@ private:
Expects(offset >= 0 && size() - offset >= 0); Expects(offset >= 0 && size() - offset >= 0);
if (count == dynamic_extent) if (count == dynamic_extent)
{ {
return { data() + offset, size() - offset, true }; return { KnownNotNull{ data() + offset }, size() - offset };
} }
Expects(count >= 0 && size() - offset >= count); Expects(count >= 0 && size() - offset >= count);
return { data() + offset, count, true }; return { KnownNotNull{ data() + offset }, count };
} }
}; };
@ -625,7 +638,7 @@ namespace details
// [span.objectrep], views of object representation // [span.objectrep], views of object representation
template <class ElementType, std::ptrdiff_t Extent> template <class ElementType, std::ptrdiff_t Extent>
span<const byte, details::calculate_byte_size<ElementType, Extent>::value> span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
as_bytes(span<ElementType, Extent> s) GSL_NOEXCEPT as_bytes(span<ElementType, Extent> s) noexcept
{ {
return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()}; return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
} }
@ -633,7 +646,7 @@ as_bytes(span<ElementType, Extent> s) GSL_NOEXCEPT
template <class ElementType, std::ptrdiff_t Extent, template <class ElementType, std::ptrdiff_t Extent,
class = std::enable_if_t<!std::is_const<ElementType>::value>> class = std::enable_if_t<!std::is_const<ElementType>::value>>
span<byte, details::calculate_byte_size<ElementType, Extent>::value> span<byte, details::calculate_byte_size<ElementType, Extent>::value>
as_writeable_bytes(span<ElementType, Extent> s) GSL_NOEXCEPT as_writeable_bytes(span<ElementType, Extent> s) noexcept
{ {
return {reinterpret_cast<byte*>(s.data()), s.size_bytes()}; return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
} }
@ -654,7 +667,7 @@ constexpr span<ElementType> make_span(ElementType* firstElem, ElementType* lastE
} }
template <class ElementType, std::size_t N> template <class ElementType, std::size_t N>
constexpr span<ElementType, N> make_span(ElementType (&arr)[N]) GSL_NOEXCEPT constexpr span<ElementType, N> make_span(ElementType (&arr)[N]) noexcept
{ {
return span<ElementType, N>(arr); return span<ElementType, N>(arr);
} }
@ -693,8 +706,6 @@ constexpr ElementType& at(span<ElementType, Extent> s, index i)
} // namespace gsl } // namespace gsl
#undef GSL_NOEXCEPT
#ifdef _MSC_VER #ifdef _MSC_VER
#if _MSC_VER < 1910 #if _MSC_VER < 1910
#undef constexpr #undef constexpr

View File

@ -417,9 +417,8 @@ public:
constexpr string_span_type as_string_span() const GSL_NOEXCEPT constexpr string_span_type as_string_span() const GSL_NOEXCEPT
{ {
auto sz = span_.size(); auto sz = span_.size();
return span_.first(sz <= 0 ? 0 : sz - 1); return { span_.data(), sz > 1 ? sz - 1 : 0 };
} }
constexpr string_span_type ensure_z() const GSL_NOEXCEPT { return gsl::ensure_z(span_); } constexpr string_span_type ensure_z() const GSL_NOEXCEPT { return gsl::ensure_z(span_); }
constexpr const_zstring_type assume_z() const GSL_NOEXCEPT { return span_.data(); } constexpr const_zstring_type assume_z() const GSL_NOEXCEPT { return span_.data(); }