Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F13115474
D9121.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
12 KB
Subscribers
None
D9121.diff
View Options
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -169,7 +169,7 @@
}
std::string AddChecksum(const std::string &str) {
- return str + "#" + DescriptorChecksum(MakeSpan(str));
+ return str + "#" + DescriptorChecksum(str);
}
////////////////////////////////////////////////////////////////////////////
@@ -1277,7 +1277,7 @@
std::unique_ptr<Descriptor> Parse(const std::string &descriptor,
FlatSigningProvider &out, std::string &error,
bool require_checksum) {
- Span<const char> sp(descriptor.data(), descriptor.size());
+ Span<const char> sp{descriptor};
if (!CheckChecksum(sp, require_checksum, error)) {
return nullptr;
}
@@ -1291,7 +1291,7 @@
std::string GetDescriptorChecksum(const std::string &descriptor) {
std::string ret;
std::string error;
- Span<const char> sp(descriptor.data(), descriptor.size());
+ Span<const char> sp{descriptor};
if (!CheckChecksum(sp, false, error, &ret)) {
return "";
}
diff --git a/src/span.h b/src/span.h
--- a/src/span.h
+++ b/src/span.h
@@ -10,22 +10,54 @@
#include <cstddef>
#include <type_traits>
-/** A Span is an object that can refer to a contiguous sequence of objects.
+#ifdef DEBUG
+#define CONSTEXPR_IF_NOT_DEBUG
+#define ASSERT_IF_DEBUG(x) assert((x))
+#else
+#define CONSTEXPR_IF_NOT_DEBUG constexpr
+#define ASSERT_IF_DEBUG(x)
+#endif
+
+/**
+ * A Span is an object that can refer to a contiguous sequence of objects.
*
* It implements a subset of C++20's std::span.
*/
template <typename C> class Span {
C *m_data;
- std::ptrdiff_t m_size;
+ std::size_t m_size;
public:
constexpr Span() noexcept : m_data(nullptr), m_size(0) {}
- constexpr Span(C *data, std::ptrdiff_t size) noexcept
- : m_data(data), m_size(size) {}
- constexpr Span(C *data, C *end) noexcept
- : m_data(data), m_size(end - data) {}
- /** Implicit conversion of spans between compatible types.
+ /**
+ * Construct a span from a begin pointer and a size.
+ *
+ * This implements a subset of the iterator-based std::span constructor in
+ * C++20, which is hard to implement without std::address_of.
+ */
+ template <typename T,
+ typename std::enable_if<
+ std::is_convertible<T (*)[], C (*)[]>::value, int>::type = 0>
+ constexpr Span(T *begin, std::size_t size) noexcept
+ : m_data(begin), m_size(size) {}
+
+ /**
+ * Construct a span from a begin and end pointer.
+ *
+ * This implements a subset of the iterator-based std::span constructor in
+ * C++20, which is hard to implement without std::address_of.
+ */
+ template <typename T,
+ typename std::enable_if<
+ std::is_convertible<T (*)[], C (*)[]>::value, int>::type = 0>
+ CONSTEXPR_IF_NOT_DEBUG Span(T *begin, T *end) noexcept
+ : m_data(begin), m_size(end - begin) {
+ ASSERT_IF_DEBUG(end >= begin);
+ }
+
+ /**
+ * Implicit conversion of spans between compatible types.
*
* Specifically, if a pointer to an array of type O can be implicitly
* converted to a pointer to an array of type C, then permit implicit
@@ -47,27 +79,66 @@
/** Default assignment operator. */
Span &operator=(const Span &other) noexcept = default;
+ /** Construct a Span from an array. This matches the corresponding C++20
+ * std::span constructor. */
+ template <int N>
+ constexpr Span(C (&a)[N]) noexcept : m_data(a), m_size(N) {}
+
+ /**
+ * Construct a Span for objects with .data() and .size() (std::string,
+ * std::array, std::vector, ...).
+ *
+ * This implements a subset of the functionality provided by the C++20
+ * std::span range-based constructor.
+ *
+ * To prevent surprises, only Spans for constant value types are supported
+ * when passing in temporaries. Note that this restriction does not exist
+ * when converting arrays or other Spans (see above).
+ */
+ template <
+ typename V,
+ typename std::enable_if<
+ (std::is_const<C>::value || std::is_lvalue_reference<V>::value) &&
+ std::is_convertible<
+ typename std::remove_pointer<
+ decltype(std::declval<V &>().data())>::type (*)[],
+ C (*)[]>::value &&
+ std::is_convertible<decltype(std::declval<V &>().size()),
+ std::size_t>::value,
+ int>::type = 0>
+ constexpr Span(V &&v) noexcept : m_data(v.data()), m_size(v.size()) {}
+
constexpr C *data() const noexcept { return m_data; }
constexpr C *begin() const noexcept { return m_data; }
constexpr C *end() const noexcept { return m_data + m_size; }
- constexpr C &front() const noexcept { return m_data[0]; }
- constexpr C &back() const noexcept { return m_data[m_size - 1]; }
- constexpr std::ptrdiff_t size() const noexcept { return m_size; }
- constexpr C &operator[](std::ptrdiff_t pos) const noexcept {
+ CONSTEXPR_IF_NOT_DEBUG C &front() const noexcept {
+ ASSERT_IF_DEBUG(size() > 0);
+ return m_data[0];
+ }
+ CONSTEXPR_IF_NOT_DEBUG C &back() const noexcept {
+ ASSERT_IF_DEBUG(size() > 0);
+ return m_data[m_size - 1];
+ }
+ constexpr std::size_t size() const noexcept { return m_size; }
+ CONSTEXPR_IF_NOT_DEBUG C &operator[](std::size_t pos) const noexcept {
+ ASSERT_IF_DEBUG(size() > pos);
return m_data[pos];
}
-
- constexpr Span<C> subspan(std::ptrdiff_t offset) const noexcept {
+ CONSTEXPR_IF_NOT_DEBUG Span<C> subspan(std::size_t offset) const noexcept {
+ ASSERT_IF_DEBUG(size() >= offset);
return Span<C>(m_data + offset, m_size - offset);
}
- constexpr Span<C> subspan(std::ptrdiff_t offset, std::ptrdiff_t count) const
- noexcept {
+ CONSTEXPR_IF_NOT_DEBUG Span<C> subspan(std::size_t offset,
+ std::size_t count) const noexcept {
+ ASSERT_IF_DEBUG(size() >= offset + count);
return Span<C>(m_data + offset, count);
}
- constexpr Span<C> first(std::ptrdiff_t count) const noexcept {
+ CONSTEXPR_IF_NOT_DEBUG Span<C> first(std::size_t count) const noexcept {
+ ASSERT_IF_DEBUG(size() >= count);
return Span<C>(m_data, count);
}
- constexpr Span<C> last(std::ptrdiff_t count) const noexcept {
+ CONSTEXPR_IF_NOT_DEBUG Span<C> last(std::size_t count) const noexcept {
+ ASSERT_IF_DEBUG(size() >= count);
return Span<C>(m_data + m_size - count, count);
}
@@ -95,33 +166,30 @@
template <typename O> friend class Span;
};
-/** Create a span to a container exposing data() and size().
- *
- * This correctly deals with constness: the returned Span's element type will be
- * whatever data() returns a pointer to. If either the passed container is
- * const, or its element type is const, the resulting span will have a const
- * element type.
- *
- * std::span will have a constructor that implements this functionality
- * directly.
- */
-template <typename A, int N> constexpr Span<A> MakeSpan(A (&a)[N]) {
+// MakeSpan helps constructing a Span of the right type automatically.
+/** MakeSpan for arrays: */
+template <typename A, int N> Span<A> constexpr MakeSpan(A (&a)[N]) {
return Span<A>(a, N);
}
-
+/** MakeSpan for temporaries / rvalue references, only supporting const output.
+ */
+template <typename V>
+constexpr auto MakeSpan(V &&v) -> typename std::enable_if<
+ !std::is_lvalue_reference<V>::value,
+ Span<const typename std::remove_pointer<decltype(v.data())>::type>>::type {
+ return std::forward<V>(v);
+}
+/** MakeSpan for (lvalue) references, supporting mutable output. */
template <typename V>
-constexpr Span<
- typename std::remove_pointer<decltype(std::declval<V>().data())>::type>
-MakeSpan(V &v) {
- return Span<
- typename std::remove_pointer<decltype(std::declval<V>().data())>::type>(
- v.data(), v.size());
+constexpr auto MakeSpan(V &v)
+ -> Span<typename std::remove_pointer<decltype(v.data())>::type> {
+ return v;
}
/** Pop the last element off a span, and return a reference to that element. */
template <typename T> T &SpanPopBack(Span<T> &span) {
size_t size = span.size();
- assert(size > 0);
+ ASSERT_IF_DEBUG(size > 0);
T &back = span[size - 1];
span = Span<T>(span.data(), size - 1);
return back;
diff --git a/src/test/fuzz/span.cpp b/src/test/fuzz/span.cpp
--- a/src/test/fuzz/span.cpp
+++ b/src/test/fuzz/span.cpp
@@ -18,7 +18,7 @@
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
std::string str = fuzzed_data_provider.ConsumeBytesAsString(32);
- const Span<const char> span = MakeSpan(str);
+ const Span<const char> span{str};
(void)span.data();
(void)span.begin();
(void)span.end();
@@ -34,7 +34,7 @@
}
std::string another_str = fuzzed_data_provider.ConsumeBytesAsString(32);
- const Span<const char> another_span = MakeSpan(another_str);
+ const Span<const char> another_span{another_str};
assert((span <= another_span) != (span > another_span));
assert((span == another_span) != (span != another_span));
assert((span >= another_span) != (span < another_span));
diff --git a/src/test/fuzz/spanparsing.cpp b/src/test/fuzz/spanparsing.cpp
--- a/src/test/fuzz/spanparsing.cpp
+++ b/src/test/fuzz/spanparsing.cpp
@@ -13,7 +13,7 @@
std::min<size_t>(query_size, 1024 * 1024));
const std::string span_str =
fuzzed_data_provider.ConsumeRemainingBytesAsString();
- const Span<const char> const_span = MakeSpan(span_str);
+ const Span<const char> const_span{span_str};
Span<const char> mut_span = const_span;
(void)spanparsing::Const(query, mut_span);
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -2197,7 +2197,7 @@
// Const(...): parse a constant, update span to skip it if successful
input = "MilkToastHoney";
- sp = MakeSpan(input);
+ sp = input;
success = Const("", sp); // empty
BOOST_CHECK(success);
BOOST_CHECK_EQUAL(SpanToStr(sp), "MilkToastHoney");
@@ -2222,7 +2222,7 @@
// Func(...): parse a function call, update span to argument if successful
input = "Foo(Bar(xy,z()))";
- sp = MakeSpan(input);
+ sp = input;
success = Func("FooBar", sp);
BOOST_CHECK(!success);
@@ -2246,31 +2246,31 @@
Span<const char> result;
input = "(n*(n-1))/2";
- sp = MakeSpan(input);
+ sp = input;
result = Expr(sp);
BOOST_CHECK_EQUAL(SpanToStr(result), "(n*(n-1))/2");
BOOST_CHECK_EQUAL(SpanToStr(sp), "");
input = "foo,bar";
- sp = MakeSpan(input);
+ sp = input;
result = Expr(sp);
BOOST_CHECK_EQUAL(SpanToStr(result), "foo");
BOOST_CHECK_EQUAL(SpanToStr(sp), ",bar");
input = "(aaaaa,bbbbb()),c";
- sp = MakeSpan(input);
+ sp = input;
result = Expr(sp);
BOOST_CHECK_EQUAL(SpanToStr(result), "(aaaaa,bbbbb())");
BOOST_CHECK_EQUAL(SpanToStr(sp), ",c");
input = "xyz)foo";
- sp = MakeSpan(input);
+ sp = input;
result = Expr(sp);
BOOST_CHECK_EQUAL(SpanToStr(result), "xyz");
BOOST_CHECK_EQUAL(SpanToStr(sp), ")foo");
input = "((a),(b),(c)),xxx";
- sp = MakeSpan(input);
+ sp = input;
result = Expr(sp);
BOOST_CHECK_EQUAL(SpanToStr(result), "((a),(b),(c))");
BOOST_CHECK_EQUAL(SpanToStr(sp), ",xxx");
@@ -2279,7 +2279,7 @@
std::vector<Span<const char>> results;
input = "xxx";
- results = Split(MakeSpan(input), 'x');
+ results = Split(input, 'x');
BOOST_CHECK_EQUAL(results.size(), 4);
BOOST_CHECK_EQUAL(SpanToStr(results[0]), "");
BOOST_CHECK_EQUAL(SpanToStr(results[1]), "");
@@ -2287,19 +2287,19 @@
BOOST_CHECK_EQUAL(SpanToStr(results[3]), "");
input = "one#two#three";
- results = Split(MakeSpan(input), '-');
+ results = Split(input, '-');
BOOST_CHECK_EQUAL(results.size(), 1);
BOOST_CHECK_EQUAL(SpanToStr(results[0]), "one#two#three");
input = "one#two#three";
- results = Split(MakeSpan(input), '#');
+ results = Split(input, '#');
BOOST_CHECK_EQUAL(results.size(), 3);
BOOST_CHECK_EQUAL(SpanToStr(results[0]), "one");
BOOST_CHECK_EQUAL(SpanToStr(results[1]), "two");
BOOST_CHECK_EQUAL(SpanToStr(results[2]), "three");
input = "*foo*bar*";
- results = Split(MakeSpan(input), '*');
+ results = Split(input, '*');
BOOST_CHECK_EQUAL(results.size(), 4);
BOOST_CHECK_EQUAL(SpanToStr(results[0]), "");
BOOST_CHECK_EQUAL(SpanToStr(results[1]), "foo");
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Mar 1, 11:10 (19 h, 31 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5187525
Default Alt Text
D9121.diff (12 KB)
Attached To
D9121: Span improvements
Event Timeline
Log In to Comment