Skip to content

Commit 26acc8d

Browse files
committed
Add sanity check asserts to span when -DDEBUG
1 parent 2676aea commit 26acc8d

File tree

1 file changed

+48
-10
lines changed

1 file changed

+48
-10
lines changed

src/span.h

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@
1010
#include <algorithm>
1111
#include <assert.h>
1212

13+
#ifdef DEBUG
14+
#define CONSTEXPR_IF_NOT_DEBUG
15+
#define ASSERT_IF_DEBUG(x) assert((x))
16+
#else
17+
#define CONSTEXPR_IF_NOT_DEBUG constexpr
18+
#define ASSERT_IF_DEBUG(x)
19+
#endif
20+
1321
/** A Span is an object that can refer to a contiguous sequence of objects.
1422
*
1523
* It implements a subset of C++20's std::span.
@@ -37,7 +45,10 @@ class Span
3745
* which is hard to implement without std::address_of.
3846
*/
3947
template <typename T, typename std::enable_if<std::is_convertible<T (*)[], C (*)[]>::value, int>::type = 0>
40-
constexpr Span(T* begin, T* end) noexcept : m_data(begin), m_size(end - begin) {}
48+
CONSTEXPR_IF_NOT_DEBUG Span(T* begin, T* end) noexcept : m_data(begin), m_size(end - begin)
49+
{
50+
ASSERT_IF_DEBUG(end >= begin);
51+
}
4152

4253
/** Implicit conversion of spans between compatible types.
4354
*
@@ -73,15 +84,42 @@ class Span
7384
constexpr C* data() const noexcept { return m_data; }
7485
constexpr C* begin() const noexcept { return m_data; }
7586
constexpr C* end() const noexcept { return m_data + m_size; }
76-
constexpr C& front() const noexcept { return m_data[0]; }
77-
constexpr C& back() const noexcept { return m_data[m_size - 1]; }
87+
CONSTEXPR_IF_NOT_DEBUG C& front() const noexcept
88+
{
89+
ASSERT_IF_DEBUG(size() > 0);
90+
return m_data[0];
91+
}
92+
CONSTEXPR_IF_NOT_DEBUG C& back() const noexcept
93+
{
94+
ASSERT_IF_DEBUG(size() > 0);
95+
return m_data[m_size - 1];
96+
}
7897
constexpr std::size_t size() const noexcept { return m_size; }
79-
constexpr C& operator[](std::size_t pos) const noexcept { return m_data[pos]; }
80-
81-
constexpr Span<C> subspan(std::size_t offset) const noexcept { return Span<C>(m_data + offset, m_size - offset); }
82-
constexpr Span<C> subspan(std::size_t offset, std::size_t count) const noexcept { return Span<C>(m_data + offset, count); }
83-
constexpr Span<C> first(std::size_t count) const noexcept { return Span<C>(m_data, count); }
84-
constexpr Span<C> last(std::size_t count) const noexcept { return Span<C>(m_data + m_size - count, count); }
98+
CONSTEXPR_IF_NOT_DEBUG C& operator[](std::size_t pos) const noexcept
99+
{
100+
ASSERT_IF_DEBUG(size() > pos);
101+
return m_data[pos];
102+
}
103+
CONSTEXPR_IF_NOT_DEBUG Span<C> subspan(std::size_t offset) const noexcept
104+
{
105+
ASSERT_IF_DEBUG(size() >= offset);
106+
return Span<C>(m_data + offset, m_size - offset);
107+
}
108+
CONSTEXPR_IF_NOT_DEBUG Span<C> subspan(std::size_t offset, std::size_t count) const noexcept
109+
{
110+
ASSERT_IF_DEBUG(size() >= offset + count);
111+
return Span<C>(m_data + offset, count);
112+
}
113+
CONSTEXPR_IF_NOT_DEBUG Span<C> first(std::size_t count) const noexcept
114+
{
115+
ASSERT_IF_DEBUG(size() >= count);
116+
return Span<C>(m_data, count);
117+
}
118+
CONSTEXPR_IF_NOT_DEBUG Span<C> last(std::size_t count) const noexcept
119+
{
120+
ASSERT_IF_DEBUG(size() >= count);
121+
return Span<C>(m_data + m_size - count, count);
122+
}
85123

86124
friend constexpr bool operator==(const Span& a, const Span& b) noexcept { return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin()); }
87125
friend constexpr bool operator!=(const Span& a, const Span& b) noexcept { return !(a == b); }
@@ -106,7 +144,7 @@ template <typename T>
106144
T& SpanPopBack(Span<T>& span)
107145
{
108146
size_t size = span.size();
109-
assert(size > 0);
147+
ASSERT_IF_DEBUG(size > 0);
110148
T& back = span[size - 1];
111149
span = Span<T>(span.data(), size - 1);
112150
return back;

0 commit comments

Comments
 (0)