Allow random stores and accesses to MapBuffer values

Summary:
Removes the need to store keys in incremental order by sorting them after before inserting into MapBuffer.
Updates MapBuffer to support random access on C++ side, actually retrieving values by keys and not bucket index.

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D33611758

fbshipit-source-id: c81e970613c8ecc688bfacb29ba038bf081a0c0f
This commit is contained in:
Andrei Shikov
2022-01-20 12:57:22 -08:00
committed by Facebook GitHub Bot
parent 1ec399781d
commit d287598d23
6 changed files with 98 additions and 71 deletions
@@ -12,6 +12,14 @@ using namespace facebook::react;
namespace facebook {
namespace react {
static inline int32_t bucketOffset(int32_t index) {
return HEADER_SIZE + BUCKET_SIZE * index;
}
static inline int32_t valueOffset(int32_t bucketIndex) {
return bucketOffset(bucketIndex) + offsetof(Bucket, data);
}
// TODO T83483191: Extend MapBuffer C++ implementation to support basic random
// access
MapBuffer::MapBuffer(std::vector<uint8_t> data) : bytes_(std::move(data)) {
@@ -25,13 +33,33 @@ MapBuffer::MapBuffer(std::vector<uint8_t> data) : bytes_(std::move(data)) {
}
}
uint32_t MapBuffer::getKeyBucket(Key key) const {
uint32_t lo = 0;
uint32_t hi = count_ - 1;
while (lo <= hi) {
uint32_t mid = (lo + hi) >> 1;
Key midVal =
*reinterpret_cast<Key const *>(bytes_.data() + bucketOffset(mid));
if (midVal < key) {
lo = mid + 1;
} else if (midVal > key) {
hi = mid - 1;
} else {
return mid;
}
}
return -1;
}
int32_t MapBuffer::getInt(Key key) const {
int32_t value = 0;
memcpy(
reinterpret_cast<uint8_t *>(&value),
bytes_.data() + getValueOffset(key),
INT_SIZE);
return value;
auto bucketIndex = getKeyBucket(key);
react_native_assert(bucketIndex != -1 && "Key not found in MapBuffer");
return *reinterpret_cast<int32_t const *>(
bytes_.data() + valueOffset(bucketIndex));
}
bool MapBuffer::getBool(Key key) const {
@@ -39,41 +67,31 @@ bool MapBuffer::getBool(Key key) const {
}
double MapBuffer::getDouble(Key key) const {
// TODO T83483191: extract this code into a "template method" and reuse it for
// other types
double value = 0;
memcpy(
reinterpret_cast<uint8_t *>(&value),
bytes_.data() + getValueOffset(key),
DOUBLE_SIZE);
return value;
auto bucketIndex = getKeyBucket(key);
react_native_assert(bucketIndex != -1 && "Key not found in MapBuffer");
return *reinterpret_cast<double const *>(
bytes_.data() + valueOffset(bucketIndex));
;
}
int32_t MapBuffer::getDynamicDataOffset() const {
// The begininig of dynamic data can be calculated as the offset of the next
// The start of dynamic data can be calculated as the offset of the next
// key in the map
return getKeyOffset(count_);
return bucketOffset(count_);
}
std::string MapBuffer::getString(Key key) const {
// TODO T83483191:Add checks to verify that offsets are under the boundaries
// of the map buffer
int32_t dynamicDataOffset = getDynamicDataOffset();
int32_t stringLength = 0;
int32_t offset = getInt(key);
memcpy(
reinterpret_cast<uint8_t *>(&stringLength),
bytes_.data() + dynamicDataOffset + offset,
INT_SIZE);
int32_t stringLength = *reinterpret_cast<int32_t const *>(
bytes_.data() + dynamicDataOffset + offset);
uint8_t const *stringPtr =
bytes_.data() + dynamicDataOffset + offset + INT_SIZE;
char *value = new char[stringLength];
memcpy(
reinterpret_cast<char *>(value),
bytes_.data() + dynamicDataOffset + offset + INT_SIZE,
stringLength);
return std::string(value, 0, stringLength);
return std::string(stringPtr, stringPtr + stringLength);
}
MapBuffer MapBuffer::getMapBuffer(Key key) const {
@@ -81,12 +99,9 @@ MapBuffer MapBuffer::getMapBuffer(Key key) const {
// of the map buffer
int32_t dynamicDataOffset = getDynamicDataOffset();
int32_t mapBufferLength = 0;
int32_t offset = getInt(key);
memcpy(
reinterpret_cast<uint8_t *>(&mapBufferLength),
bytes_.data() + dynamicDataOffset + offset,
INT_SIZE);
int32_t mapBufferLength = *reinterpret_cast<int32_t const *>(
bytes_.data() + dynamicDataOffset + offset);
std::vector<uint8_t> value(mapBufferLength);