Switch std::span<const uint8_t> to TrivialSpan

This commit is contained in:
2024-10-30 11:45:56 -07:00
parent 2c1c26bc88
commit 3b858551f3
3 changed files with 121 additions and 108 deletions

View File

@@ -17,26 +17,26 @@ constexpr int kPrefixLen = 0;
constexpr int kMvccWindow = 100000; constexpr int kMvccWindow = 100000;
std::span<const uint8_t> makeKey(Arena &arena, int index) { TrivialSpan makeKey(Arena &arena, int index) {
auto result = uint8_t *buf = new (arena) uint8_t[4 + kPrefixLen];
std::span<uint8_t>{new (arena) uint8_t[4 + kPrefixLen], 4 + kPrefixLen}; auto result = TrivialSpan{buf, 4 + kPrefixLen};
index = __builtin_bswap32(index); index = __builtin_bswap32(index);
memset(result.data(), 0, kPrefixLen); memset(buf, 0, kPrefixLen);
memcpy(result.data() + kPrefixLen, &index, 4); memcpy(buf, &index, 4);
return result; return result;
} }
ConflictSet::ReadRange singleton(Arena &arena, std::span<const uint8_t> key) { ConflictSet::ReadRange singleton(Arena &arena, TrivialSpan key) {
auto r = uint8_t *buf = new (arena) uint8_t[key.size() + 1];
std::span<uint8_t>(new (arena) uint8_t[key.size() + 1], key.size() + 1); auto r = TrivialSpan(buf, key.size() + 1);
memcpy(r.data(), key.data(), key.size()); memcpy(buf, key.data(), key.size());
r[key.size()] = 0; buf[key.size()] = 0;
return {{key.data(), int(key.size())}, {r.data(), int(r.size())}, 0}; return {{key.data(), int(key.size())}, {r.data(), int(r.size())}, 0};
} }
ConflictSet::ReadRange prefixRange(Arena &arena, std::span<const uint8_t> key) { ConflictSet::ReadRange prefixRange(Arena &arena, TrivialSpan key) {
int index; int index;
for (index = key.size() - 1; index >= 0; index--) for (index = key.size() - 1; index >= 0; index--)
if ((key[index]) != 255) if ((key[index]) != 255)
@@ -48,9 +48,10 @@ ConflictSet::ReadRange prefixRange(Arena &arena, std::span<const uint8_t> key) {
assert(false); assert(false);
} }
auto r = std::span<uint8_t>(new (arena) uint8_t[index + 1], index + 1); uint8_t *buf = new (arena) uint8_t[index + 1];
memcpy(r.data(), key.data(), index + 1); auto r = TrivialSpan(buf, index + 1);
r[r.size() - 1]++; memcpy(buf, key.data(), index + 1);
buf[r.size() - 1]++;
return {{key.data(), int(key.size())}, {r.data(), int(r.size())}, 0}; return {{key.data(), int(key.size())}, {r.data(), int(r.size())}, 0};
} }
@@ -81,14 +82,7 @@ void benchConflictSet() {
++version; ++version;
} }
// I don't know why std::less didn't work /shrug auto points = set<TrivialSpan, std::less<>>(arena);
struct Less {
bool operator()(const std::span<const uint8_t> &lhs,
const std::span<const uint8_t> &rhs) const {
return lhs < rhs;
}
};
auto points = set<std::span<const uint8_t>, Less>(arena);
while (points.size() < kOpsPerTx * 2 + 1) { while (points.size() < kOpsPerTx * 2 + 1) {
// TODO don't use rand? // TODO don't use rand?

View File

@@ -1213,14 +1213,13 @@ TaggedNodePointer getChild(Node *self, uint8_t index) {
} }
} }
TaggedNodePointer *getChildUpdatingMaxVersion(Node0 *, TaggedNodePointer *getChildUpdatingMaxVersion(Node0 *, TrivialSpan &,
std::span<const uint8_t> &,
InternalVersionT) { InternalVersionT) {
return nullptr; return nullptr;
} }
TaggedNodePointer * TaggedNodePointer *getChildUpdatingMaxVersion(Node3 *self,
getChildUpdatingMaxVersion(Node3 *self, std::span<const uint8_t> &remaining, TrivialSpan &remaining,
InternalVersionT maxVersion) { InternalVersionT maxVersion) {
assert(remaining.size() > 0); assert(remaining.size() > 0);
int index = remaining.front(); int index = remaining.front();
auto key = remaining.subspan(1, remaining.size() - 1); auto key = remaining.subspan(1, remaining.size() - 1);
@@ -1241,9 +1240,9 @@ getChildUpdatingMaxVersion(Node3 *self, std::span<const uint8_t> &remaining,
self->childMaxVersion[i] = maxVersion; self->childMaxVersion[i] = maxVersion;
return &self->children[i]; return &self->children[i];
} }
TaggedNodePointer * TaggedNodePointer *getChildUpdatingMaxVersion(Node16 *self,
getChildUpdatingMaxVersion(Node16 *self, std::span<const uint8_t> &remaining, TrivialSpan &remaining,
InternalVersionT maxVersion) { InternalVersionT maxVersion) {
assert(remaining.size() > 0); assert(remaining.size() > 0);
int index = remaining.front(); int index = remaining.front();
auto key = remaining.subspan(1, remaining.size() - 1); auto key = remaining.subspan(1, remaining.size() - 1);
@@ -1264,9 +1263,9 @@ getChildUpdatingMaxVersion(Node16 *self, std::span<const uint8_t> &remaining,
self->childMaxVersion[i] = maxVersion; self->childMaxVersion[i] = maxVersion;
return &self->children[i]; return &self->children[i];
} }
TaggedNodePointer * TaggedNodePointer *getChildUpdatingMaxVersion(Node48 *self,
getChildUpdatingMaxVersion(Node48 *self, std::span<const uint8_t> &remaining, TrivialSpan &remaining,
InternalVersionT maxVersion) { InternalVersionT maxVersion) {
assert(remaining.size() > 0); assert(remaining.size() > 0);
int index = remaining.front(); int index = remaining.front();
auto key = remaining.subspan(1, remaining.size() - 1); auto key = remaining.subspan(1, remaining.size() - 1);
@@ -1289,9 +1288,9 @@ getChildUpdatingMaxVersion(Node48 *self, std::span<const uint8_t> &remaining,
std::max(self->maxOfMax[i >> Node48::kMaxOfMaxShift], maxVersion); std::max(self->maxOfMax[i >> Node48::kMaxOfMaxShift], maxVersion);
return &self->children[i]; return &self->children[i];
} }
TaggedNodePointer * TaggedNodePointer *getChildUpdatingMaxVersion(Node256 *self,
getChildUpdatingMaxVersion(Node256 *self, std::span<const uint8_t> &remaining, TrivialSpan &remaining,
InternalVersionT maxVersion) { InternalVersionT maxVersion) {
assert(remaining.size() > 0); assert(remaining.size() > 0);
int index = remaining.front(); int index = remaining.front();
auto key = remaining.subspan(1, remaining.size() - 1); auto key = remaining.subspan(1, remaining.size() - 1);
@@ -1319,9 +1318,9 @@ getChildUpdatingMaxVersion(Node256 *self, std::span<const uint8_t> &remaining,
// If a child of self lies along the search path of remaining, return a pointer // If a child of self lies along the search path of remaining, return a pointer
// to that child, update max version, and consume the matching prefix bytes from // to that child, update max version, and consume the matching prefix bytes from
// remaining. Otherwise return nullptr without changing the tree at all. // remaining. Otherwise return nullptr without changing the tree at all.
TaggedNodePointer * TaggedNodePointer *getChildUpdatingMaxVersion(Node *self,
getChildUpdatingMaxVersion(Node *self, std::span<const uint8_t> &remaining, TrivialSpan &remaining,
InternalVersionT maxVersion) { InternalVersionT maxVersion) {
switch (self->getType()) { switch (self->getType()) {
case Type_Node0: case Type_Node0:
return getChildUpdatingMaxVersion(static_cast<Node0 *>(self), remaining, return getChildUpdatingMaxVersion(static_cast<Node0 *>(self), remaining,
@@ -1560,8 +1559,7 @@ TaggedNodePointer getFirstChildExists(Node *self) {
// GCOVR_EXCL_STOP // GCOVR_EXCL_STOP
} }
void consumePartialKeyFull(TaggedNodePointer &self, void consumePartialKeyFull(TaggedNodePointer &self, TrivialSpan &key,
std::span<const uint8_t> &key,
InternalVersionT writeVersion, InternalVersionT writeVersion,
WriteContext *writeContext) { WriteContext *writeContext) {
// Handle an existing partial key // Handle an existing partial key
@@ -1607,7 +1605,7 @@ void consumePartialKeyFull(TaggedNodePointer &self,
// Consume any partial key of `self`, and update `self` and // Consume any partial key of `self`, and update `self` and
// `key` such that `self` is along the search path of `key` // `key` such that `self` is along the search path of `key`
inline __attribute__((always_inline)) void inline __attribute__((always_inline)) void
consumePartialKey(TaggedNodePointer &self, std::span<const uint8_t> &key, consumePartialKey(TaggedNodePointer &self, TrivialSpan &key,
InternalVersionT writeVersion, WriteContext *writeContext) { InternalVersionT writeVersion, WriteContext *writeContext) {
if (self->partialKeyLen > 0) { if (self->partialKeyLen > 0) {
consumePartialKeyFull(self, key, writeVersion, writeContext); consumePartialKeyFull(self, key, writeVersion, writeContext);
@@ -1618,8 +1616,7 @@ consumePartialKey(TaggedNodePointer &self, std::span<const uint8_t> &key,
// such that the search path of the result + key is the same as the search path // such that the search path of the result + key is the same as the search path
// of self + key before the call. Creates a node if necessary. Updates // of self + key before the call. Creates a node if necessary. Updates
// `maxVersion` for result. // `maxVersion` for result.
TaggedNodePointer &getOrCreateChild(TaggedNodePointer &self, TaggedNodePointer &getOrCreateChild(TaggedNodePointer &self, TrivialSpan &key,
std::span<const uint8_t> &key,
InternalVersionT newMaxVersion, InternalVersionT newMaxVersion,
WriteContext *writeContext) { WriteContext *writeContext) {
@@ -2805,7 +2802,7 @@ bool checkMaxBetweenExclusive(Node *n, int begin, int end,
} }
} }
Vector<uint8_t> getSearchPath(Arena &arena, Node *n) { TrivialSpan getSearchPath(Arena &arena, Node *n) {
assert(n != nullptr); assert(n != nullptr);
auto result = vector<uint8_t>(arena); auto result = vector<uint8_t>(arena);
for (;;) { for (;;) {
@@ -2819,7 +2816,7 @@ Vector<uint8_t> getSearchPath(Arena &arena, Node *n) {
n = n->parent; n = n->parent;
} }
std::reverse(result.begin(), result.end()); std::reverse(result.begin(), result.end());
return result; return {result.begin(), result.size()};
} }
// Return true if the max version among all keys that start with key + [child], // Return true if the max version among all keys that start with key + [child],
@@ -2828,8 +2825,8 @@ Vector<uint8_t> getSearchPath(Arena &arena, Node *n) {
// Precondition: transitively, no child of n has a search path that's a longer // Precondition: transitively, no child of n has a search path that's a longer
// prefix of key than n // prefix of key than n
template <class NodeT> template <class NodeT>
bool checkRangeStartsWith(NodeT *nTyped, std::span<const uint8_t> key, bool checkRangeStartsWith(NodeT *nTyped, TrivialSpan key, int begin, int end,
int begin, int end, InternalVersionT readVersion, InternalVersionT readVersion,
ReadContext *readContext) { ReadContext *readContext) {
Node *n; Node *n;
#if DEBUG_VERBOSE && !defined(NDEBUG) #if DEBUG_VERBOSE && !defined(NDEBUG)
@@ -2921,7 +2918,7 @@ checkMaxBetweenExclusiveImpl<true>(Node256 *n, int begin, int end,
// postcondition. Nodes along the search path may be invalidated. Callers must // postcondition. Nodes along the search path may be invalidated. Callers must
// ensure that the max version of the self argument is updated. // ensure that the max version of the self argument is updated.
[[nodiscard]] TaggedNodePointer *insert(TaggedNodePointer *self, [[nodiscard]] TaggedNodePointer *insert(TaggedNodePointer *self,
std::span<const uint8_t> key, TrivialSpan key,
InternalVersionT writeVersion, InternalVersionT writeVersion,
WriteContext *writeContext) { WriteContext *writeContext) {
@@ -2983,7 +2980,7 @@ void eraseTree(Node *root, WriteContext *writeContext) {
} }
} }
void addPointWrite(TaggedNodePointer &root, std::span<const uint8_t> key, void addPointWrite(TaggedNodePointer &root, TrivialSpan key,
InternalVersionT writeVersion, WriteContext *writeContext) { InternalVersionT writeVersion, WriteContext *writeContext) {
++writeContext->accum.point_writes; ++writeContext->accum.point_writes;
auto n = *insert(&root, key, writeVersion, writeContext); auto n = *insert(&root, key, writeVersion, writeContext);
@@ -3113,9 +3110,8 @@ struct AddedWriteRange {
Node *endNode; Node *endNode;
}; };
AddedWriteRange addWriteRange(Node *beginRoot, std::span<const uint8_t> begin, AddedWriteRange addWriteRange(Node *beginRoot, TrivialSpan begin, Node *endRoot,
Node *endRoot, std::span<const uint8_t> end, TrivialSpan end, InternalVersionT writeVersion,
InternalVersionT writeVersion,
WriteContext *writeContext, WriteContext *writeContext,
ConflictSet::Impl *impl) { ConflictSet::Impl *impl) {
@@ -3176,9 +3172,9 @@ void eraseInRange(Node *beginNode, Node *endNode, WriteContext *writeContext,
fixupMaxVersion(iter, writeContext); fixupMaxVersion(iter, writeContext);
} }
void addWriteRange(TaggedNodePointer &root, std::span<const uint8_t> begin, void addWriteRange(TaggedNodePointer &root, TrivialSpan begin, TrivialSpan end,
std::span<const uint8_t> end, InternalVersionT writeVersion, InternalVersionT writeVersion, WriteContext *writeContext,
WriteContext *writeContext, ConflictSet::Impl *impl) { ConflictSet::Impl *impl) {
int lcp = longestCommonPrefix(begin.data(), end.data(), int lcp = longestCommonPrefix(begin.data(), end.data(),
std::min(begin.size(), end.size())); std::min(begin.size(), end.size()));
if (lcp == int(begin.size()) && end.size() == begin.size() + 1 && if (lcp == int(begin.size()) && end.size() == begin.size() + 1 &&
@@ -3195,7 +3191,7 @@ void addWriteRange(TaggedNodePointer &root, std::span<const uint8_t> begin,
eraseInRange(beginNode, endNode, writeContext, impl); eraseInRange(beginNode, endNode, writeContext, impl);
} }
Node *firstGeqPhysical(Node *n, const std::span<const uint8_t> key) { Node *firstGeqPhysical(Node *n, const TrivialSpan key) {
auto remaining = key; auto remaining = key;
for (;;) { for (;;) {
if (remaining.size() == 0) { if (remaining.size() == 0) {
@@ -3278,13 +3274,13 @@ struct Job {
Node *root, int64_t oldestVersionFullPrecision); Node *root, int64_t oldestVersionFullPrecision);
Node *n; Node *n;
std::span<const uint8_t> begin; TrivialSpan begin;
InternalVersionT maxV; InternalVersionT maxV;
std::span<const uint8_t> end; // range read only TrivialSpan end; // range read only
std::span<const uint8_t> remaining; // range read only TrivialSpan remaining; // range read only
Node *child; // range read only Node *child; // range read only
int lcp; // range read only int lcp; // range read only
Node *commonPrefixNode; // range read only Node *commonPrefixNode; // range read only
InternalVersionT readVersion; InternalVersionT readVersion;
ConflictSet::Result *result; ConflictSet::Result *result;
Continuation continuation; Continuation continuation;
@@ -4068,8 +4064,8 @@ PRESERVE_NONE void right_side_iter(Job *job, Context *context) {
void Job::init(const ConflictSet::ReadRange *read, ConflictSet::Result *result, void Job::init(const ConflictSet::ReadRange *read, ConflictSet::Result *result,
Node *root, int64_t oldestVersionFullPrecision) { Node *root, int64_t oldestVersionFullPrecision) {
auto begin = std::span<const uint8_t>(read->begin.p, read->begin.len); auto begin = TrivialSpan(read->begin.p, read->begin.len);
auto end = std::span<const uint8_t>(read->end.p, read->end.len); auto end = TrivialSpan(read->end.p, read->end.len);
if (read->readVersion < oldestVersionFullPrecision) [[unlikely]] { if (read->readVersion < oldestVersionFullPrecision) [[unlikely]] {
*result = ConflictSet::TooOld; *result = ConflictSet::TooOld;
continuation = complete; continuation = complete;
@@ -4096,13 +4092,13 @@ typedef PRESERVE_NONE void (*Continuation)(struct Job *, struct Context *);
// State relevant to an individual insertion // State relevant to an individual insertion
struct Job { struct Job {
std::span<const uint8_t> remaining; TrivialSpan remaining;
Node *n; Node *n;
int index; int index;
std::span<const uint8_t> begin; // Range write only TrivialSpan begin; // Range write only
std::span<const uint8_t> end; // Range write only TrivialSpan end; // Range write only
Node *endNode; // Range write only Node *endNode; // Range write only
int commonPrefixLen; // Range write only int commonPrefixLen; // Range write only
// State for context switching machinery - not application specific // State for context switching machinery - not application specific
Continuation continuation; Continuation continuation;
@@ -4116,10 +4112,10 @@ struct Job {
// path of the original key // path of the original key
struct Result { struct Result {
Node *insertionPoint; Node *insertionPoint;
std::span<const uint8_t> remaining; TrivialSpan remaining;
Node *endInsertionPoint; // Range write only Node *endInsertionPoint; // Range write only
std::span<const uint8_t> endRemaining; // Range write only TrivialSpan endRemaining; // Range write only
}; };
// State relevant to every insertion // State relevant to every insertion
@@ -4285,10 +4281,10 @@ void Job::init(Context *context, int index) {
goto pointWrite; goto pointWrite;
} }
begin = std::span<const uint8_t>(context->writes[index].begin.p, begin = TrivialSpan(context->writes[index].begin.p,
context->writes[index].begin.len); context->writes[index].begin.len);
end = std::span<const uint8_t>(context->writes[index].end.p, end =
context->writes[index].end.len); TrivialSpan(context->writes[index].end.p, context->writes[index].end.len);
commonPrefixLen = longestCommonPrefix(begin.data(), end.data(), commonPrefixLen = longestCommonPrefix(begin.data(), end.data(),
std::min(begin.size(), end.size())); std::min(begin.size(), end.size()));
@@ -4297,8 +4293,7 @@ void Job::init(Context *context, int index) {
goto pointWrite; goto pointWrite;
} }
remaining = remaining = TrivialSpan(context->writes[index].begin.p, commonPrefixLen);
std::span<const uint8_t>(context->writes[index].begin.p, commonPrefixLen);
if (commonPrefixLen > 0) { if (commonPrefixLen > 0) {
// common prefix iter will set endNode // common prefix iter will set endNode
@@ -4313,8 +4308,8 @@ void Job::init(Context *context, int index) {
return; return;
pointWrite: pointWrite:
remaining = std::span<const uint8_t>(context->writes[index].begin.p, remaining = TrivialSpan(context->writes[index].begin.p,
context->writes[index].begin.len); context->writes[index].begin.len);
if (remaining.size() == 0) [[unlikely]] { if (remaining.size() == 0) [[unlikely]] {
context->results[index] = {n, remaining, nullptr, {}}; context->results[index] = {n, remaining, nullptr, {}};
continuation = complete; continuation = complete;
@@ -4330,7 +4325,7 @@ namespace {
// Logically this is the same as performing firstGeq and then checking against // Logically this is the same as performing firstGeq and then checking against
// point or range version according to cmp, but this version short circuits as // point or range version according to cmp, but this version short circuits as
// soon as it can prove that there's no conflict. // soon as it can prove that there's no conflict.
bool checkPointRead(Node *n, const std::span<const uint8_t> key, bool checkPointRead(Node *n, const TrivialSpan key,
InternalVersionT readVersion, ReadContext *readContext) { InternalVersionT readVersion, ReadContext *readContext) {
++readContext->point_read_accum; ++readContext->point_read_accum;
#if DEBUG_VERBOSE && !defined(NDEBUG) #if DEBUG_VERBOSE && !defined(NDEBUG)
@@ -4404,7 +4399,7 @@ downLeftSpine:
// Logically this is the same as performing firstGeq and then checking against // Logically this is the same as performing firstGeq and then checking against
// max version or range version if this prefix doesn't exist, but this version // max version or range version if this prefix doesn't exist, but this version
// short circuits as soon as it can prove that there's no conflict. // short circuits as soon as it can prove that there's no conflict.
bool checkPrefixRead(Node *n, const std::span<const uint8_t> key, bool checkPrefixRead(Node *n, const TrivialSpan key,
InternalVersionT readVersion, ReadContext *readContext) { InternalVersionT readVersion, ReadContext *readContext) {
++readContext->prefix_read_accum; ++readContext->prefix_read_accum;
#if DEBUG_VERBOSE && !defined(NDEBUG) #if DEBUG_VERBOSE && !defined(NDEBUG)
@@ -4478,7 +4473,7 @@ downLeftSpine:
// Return true if the max version among all keys that start with key[:prefixLen] // Return true if the max version among all keys that start with key[:prefixLen]
// that are >= key is <= readVersion // that are >= key is <= readVersion
bool checkRangeLeftSide(Node *n, std::span<const uint8_t> key, int prefixLen, bool checkRangeLeftSide(Node *n, TrivialSpan key, int prefixLen,
InternalVersionT readVersion, InternalVersionT readVersion,
ReadContext *readContext) { ReadContext *readContext) {
auto remaining = key; auto remaining = key;
@@ -4565,7 +4560,7 @@ downLeftSpine:
// Return true if the max version among all keys that start with key[:prefixLen] // Return true if the max version among all keys that start with key[:prefixLen]
// that are < key is <= readVersion // that are < key is <= readVersion
bool checkRangeRightSide(Node *n, std::span<const uint8_t> key, int prefixLen, bool checkRangeRightSide(Node *n, TrivialSpan key, int prefixLen,
InternalVersionT readVersion, InternalVersionT readVersion,
ReadContext *readContext) { ReadContext *readContext) {
auto remaining = key; auto remaining = key;
@@ -4658,9 +4653,8 @@ downLeftSpine:
} }
return n->entry.rangeVersion <= readVersion; return n->entry.rangeVersion <= readVersion;
} }
bool checkRangeRead(Node *n, std::span<const uint8_t> begin, bool checkRangeRead(Node *n, TrivialSpan begin, TrivialSpan end,
std::span<const uint8_t> end, InternalVersionT readVersion, InternalVersionT readVersion, ReadContext *readContext) {
ReadContext *readContext) {
int lcp = longestCommonPrefix(begin.data(), end.data(), int lcp = longestCommonPrefix(begin.data(), end.data(),
std::min(begin.size(), end.size())); std::min(begin.size(), end.size()));
if (lcp == int(begin.size()) && end.size() == begin.size() + 1 && if (lcp == int(begin.size()) && end.size() == begin.size() + 1 &&
@@ -4746,14 +4740,12 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
bool ok; bool ok;
if (reads[i].end.len == 0) { if (reads[i].end.len == 0) {
ok = checkPointRead( ok = checkPointRead(
root, root, TrivialSpan(reads[i].begin.p, reads[i].begin.len),
std::span<const uint8_t>(reads[i].begin.p, reads[i].begin.len),
InternalVersionT(reads[i].readVersion), &context.readContext); InternalVersionT(reads[i].readVersion), &context.readContext);
} else { } else {
ok = checkRangeRead( ok = checkRangeRead(
root, root, TrivialSpan(reads[i].begin.p, reads[i].begin.len),
std::span<const uint8_t>(reads[i].begin.p, reads[i].begin.len), TrivialSpan(reads[i].end.p, reads[i].end.len),
std::span<const uint8_t>(reads[i].end.p, reads[i].end.len),
InternalVersionT(reads[i].readVersion), &context.readContext); InternalVersionT(reads[i].readVersion), &context.readContext);
} }
result[i] = ok ? Commit : Conflict; result[i] = ok ? Commit : Conflict;
@@ -4977,8 +4969,8 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
} else { } else {
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
const auto &w = writes[i]; const auto &w = writes[i];
auto begin = std::span<const uint8_t>(w.begin.p, w.begin.len); auto begin = TrivialSpan(w.begin.p, w.begin.len);
auto end = std::span<const uint8_t>(w.end.p, w.end.len); auto end = TrivialSpan(w.end.p, w.end.len);
if (w.end.len > 0) { if (w.end.len > 0) {
addWriteRange(root, begin, end, InternalVersionT(writeVersion), addWriteRange(root, begin, end, InternalVersionT(writeVersion),
&writeContext, this); &writeContext, this);
@@ -5216,7 +5208,7 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
WriteContext writeContext; WriteContext writeContext;
Arena removalKeyArena; Arena removalKeyArena;
std::span<const uint8_t> removalKey; TrivialSpan removalKey;
int64_t keyUpdates; int64_t keyUpdates;
TaggedNodePointer root; TaggedNodePointer root;
@@ -5363,7 +5355,7 @@ double internal_getMetricValue(const ConflictSet::MetricsV1 *metric) {
// GCOVR_EXCL_START // GCOVR_EXCL_START
Node *firstGeqLogical(Node *n, const std::span<const uint8_t> key) { Node *firstGeqLogical(Node *n, const TrivialSpan key) {
auto remaining = key; auto remaining = key;
for (;;) { for (;;) {
if (remaining.size() == 0) { if (remaining.size() == 0) {
@@ -5624,8 +5616,8 @@ void checkParentPointers(Node *node, bool &success) {
} }
Node *firstGeq(Node *n, std::string_view key) { Node *firstGeq(Node *n, std::string_view key) {
return firstGeqLogical( return firstGeqLogical(n,
n, std::span<const uint8_t>((const uint8_t *)key.data(), key.size())); TrivialSpan((const uint8_t *)key.data(), key.size()));
} }
#if USE_64_BIT #if USE_64_BIT

View File

@@ -26,9 +26,38 @@ using namespace weaselab;
#define DEBUG_VERBOSE 0 #define DEBUG_VERBOSE 0
#define SHOW_MEMORY 0 #define SHOW_MEMORY 0
[[nodiscard]] inline auto // std::span is not trivially constructible. We want a span that leaves its
operator<=>(const std::span<const uint8_t> &lhs, // members uninitialized for performance reasons.
const std::span<const uint8_t> &rhs) noexcept { struct TrivialSpan {
TrivialSpan() = default;
TrivialSpan(const uint8_t *begin, int len) : begin(begin), len(len) {}
uint8_t back() const {
assert(len > 0);
return begin[len - 1];
}
uint8_t front() const {
assert(len > 0);
return begin[0];
}
uint8_t operator[](int i) const {
assert(0 <= i);
assert(i < len);
return begin[i];
}
int size() const { return len; }
TrivialSpan subspan(int offset, int len) { return {begin + offset, len}; }
const uint8_t *data() const { return begin; }
private:
const uint8_t *begin;
int len;
};
static_assert(std::is_trivial_v<TrivialSpan>);
[[nodiscard]] inline auto operator<=>(const TrivialSpan &lhs,
const TrivialSpan &rhs) noexcept {
int cl = std::min<int>(lhs.size(), rhs.size()); int cl = std::min<int>(lhs.size(), rhs.size());
if (cl > 0) { if (cl > 0) {
if (auto c = memcmp(lhs.data(), rhs.data(), cl) <=> 0; c != 0) { if (auto c = memcmp(lhs.data(), rhs.data(), cl) <=> 0; c != 0) {
@@ -38,7 +67,7 @@ operator<=>(const std::span<const uint8_t> &lhs,
return lhs.size() <=> rhs.size(); return lhs.size() <=> rhs.size();
} }
[[nodiscard]] inline auto operator<=>(const std::span<const uint8_t> &lhs, [[nodiscard]] inline auto operator<=>(const TrivialSpan &lhs,
const ConflictSet::Key &rhs) noexcept { const ConflictSet::Key &rhs) noexcept {
int cl = std::min<int>(lhs.size(), rhs.len); int cl = std::min<int>(lhs.size(), rhs.len);
if (cl > 0) { if (cl > 0) {
@@ -46,7 +75,7 @@ operator<=>(const std::span<const uint8_t> &lhs,
return c; return c;
} }
} }
return lhs.size() <=> size_t(rhs.len); return lhs.size() <=> rhs.len;
} }
[[nodiscard]] inline auto operator<=>(const ConflictSet::Key &lhs, [[nodiscard]] inline auto operator<=>(const ConflictSet::Key &lhs,
@@ -688,10 +717,8 @@ struct TestDriver {
arbitrary->randomBytes(begin + prefixLen, keyLen - prefixLen); arbitrary->randomBytes(begin + prefixLen, keyLen - prefixLen);
writes[i].end.len = keyLen; writes[i].end.len = keyLen;
writes[i].end.p = begin; writes[i].end.p = begin;
auto c = auto c = TrivialSpan(writes[i].begin.p, writes[i].begin.len) <=>
std::span<const uint8_t>(writes[i].begin.p, TrivialSpan(writes[i].end.p, writes[i].end.len);
writes[i].begin.len) <=>
std::span<const uint8_t>(writes[i].end.p, writes[i].end.len);
if (c > 0) { if (c > 0) {
using std::swap; using std::swap;
swap(writes[i].begin, writes[i].end); swap(writes[i].begin, writes[i].end);