Page MenuHomePhabricator

D9121.diff
No OneTemporary

D9121.diff

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

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)

Event Timeline