Add ability to store and retrieve a list of MapBuffer
Summary: Add ability to store and retrieve a list of MapBuffer as an entry of MapBuffer. ``` Example: MapBuffer1 { key1: "test string", key2: MapBuffer2, key3: [MapBuffer3, MapBuffer4] } ``` Changelog: [General][Added] Add ability to store and retrieve a list of MapBuffer Reviewed By: JoshuaGross Differential Revision: D38460204 fbshipit-source-id: 3e721418be2dca6d5f15f665753844d6f531e31c
This commit is contained in:
Родитель
7e580b97bf
Коммит
fc065151ce
|
@ -126,6 +126,16 @@ interface MapBuffer : Iterable<MapBuffer.Entry> {
|
|||
*/
|
||||
fun getMapBuffer(key: Int): MapBuffer
|
||||
|
||||
/**
|
||||
* Provides parsed [List<MapBuffer>] value if the entry for given key exists with [DataType.MAP]
|
||||
* type
|
||||
* @param key key to lookup [List<MapBuffer>] value for
|
||||
* @return value associated with the requested key
|
||||
* @throws IllegalArgumentException if the key doesn't exist
|
||||
* @throws IllegalStateException if the data type doesn't match
|
||||
*/
|
||||
fun getMapBufferList(key: Int): List<MapBuffer>
|
||||
|
||||
/** Iterable entry representing parsed MapBuffer values */
|
||||
interface Entry {
|
||||
/**
|
||||
|
|
|
@ -137,6 +137,24 @@ class ReadableMapBuffer : MapBuffer {
|
|||
return ReadableMapBuffer(ByteBuffer.wrap(newBuffer))
|
||||
}
|
||||
|
||||
private fun readMapBufferListValue(position: Int): List<ReadableMapBuffer> {
|
||||
val readMapBufferList = arrayListOf<ReadableMapBuffer>()
|
||||
var offset = offsetForDynamicData + buffer.getInt(position)
|
||||
val sizeMapBufferList = buffer.getInt(offset)
|
||||
offset += Int.SIZE_BYTES
|
||||
var curLen = 0
|
||||
while (curLen < sizeMapBufferList) {
|
||||
val sizeMapBuffer = buffer.getInt(offset + curLen)
|
||||
val newMapBuffer = ByteArray(sizeMapBuffer)
|
||||
curLen = curLen + Int.SIZE_BYTES
|
||||
buffer.position(offset + curLen)
|
||||
buffer[newMapBuffer, 0, sizeMapBuffer]
|
||||
readMapBufferList.add(ReadableMapBuffer(ByteBuffer.wrap(newMapBuffer)))
|
||||
curLen = curLen + sizeMapBuffer
|
||||
}
|
||||
return readMapBufferList
|
||||
}
|
||||
|
||||
private fun getKeyOffsetForBucketIndex(bucketIndex: Int): Int {
|
||||
return HEADER_SIZE + BUCKET_SIZE * bucketIndex
|
||||
}
|
||||
|
@ -172,6 +190,9 @@ class ReadableMapBuffer : MapBuffer {
|
|||
override fun getMapBuffer(key: Int): ReadableMapBuffer =
|
||||
readMapBufferValue(getTypedValueOffsetForKey(key, MapBuffer.DataType.MAP))
|
||||
|
||||
override fun getMapBufferList(key: Int): List<ReadableMapBuffer> =
|
||||
readMapBufferListValue(getTypedValueOffsetForKey(key, MapBuffer.DataType.MAP))
|
||||
|
||||
override fun hashCode(): Int {
|
||||
buffer.rewind()
|
||||
return buffer.hashCode()
|
||||
|
|
|
@ -106,6 +106,8 @@ class WritableMapBuffer : MapBuffer {
|
|||
|
||||
override fun getMapBuffer(key: Int): MapBuffer = verifyValue(key, values.get(key))
|
||||
|
||||
override fun getMapBufferList(key: Int): List<MapBuffer> = verifyValue(key, values.get(key))
|
||||
|
||||
/** Generalizes verification of the value types based on the requested type. */
|
||||
private inline fun <reified T> verifyValue(key: Int, value: Any?): T {
|
||||
require(value != null) { "Key not found: $key" }
|
||||
|
|
|
@ -112,6 +112,31 @@ MapBuffer MapBuffer::getMapBuffer(Key key) const {
|
|||
return MapBuffer(std::move(value));
|
||||
}
|
||||
|
||||
std::vector<MapBuffer> MapBuffer::getMapBufferList(MapBuffer::Key key) const {
|
||||
std::vector<MapBuffer> mapBufferList;
|
||||
|
||||
int32_t dynamicDataOffset = getDynamicDataOffset();
|
||||
int32_t offset = getInt(key);
|
||||
int32_t mapBufferListLength = *reinterpret_cast<int32_t const *>(
|
||||
bytes_.data() + dynamicDataOffset + offset);
|
||||
offset = offset + sizeof(uint32_t);
|
||||
|
||||
int32_t curLen = 0;
|
||||
while (curLen < mapBufferListLength) {
|
||||
int32_t mapBufferLength = *reinterpret_cast<int32_t const *>(
|
||||
bytes_.data() + dynamicDataOffset + offset + curLen);
|
||||
curLen = curLen + sizeof(uint32_t);
|
||||
std::vector<uint8_t> value(mapBufferLength);
|
||||
memcpy(
|
||||
value.data(),
|
||||
bytes_.data() + dynamicDataOffset + offset + curLen,
|
||||
mapBufferLength);
|
||||
mapBufferList.emplace_back(std::move(value));
|
||||
curLen = curLen + mapBufferLength;
|
||||
}
|
||||
return mapBufferList;
|
||||
}
|
||||
|
||||
size_t MapBuffer::size() const {
|
||||
return bytes_.size();
|
||||
}
|
||||
|
|
|
@ -126,6 +126,8 @@ class MapBuffer {
|
|||
// TODO T83483191: review this declaration
|
||||
MapBuffer getMapBuffer(MapBuffer::Key key) const;
|
||||
|
||||
std::vector<MapBuffer> getMapBufferList(MapBuffer::Key key) const;
|
||||
|
||||
size_t size() const;
|
||||
|
||||
uint8_t const *data() const;
|
||||
|
|
|
@ -114,6 +114,39 @@ void MapBufferBuilder::putMapBuffer(MapBuffer::Key key, MapBuffer const &map) {
|
|||
INT_SIZE);
|
||||
}
|
||||
|
||||
void MapBufferBuilder::putMapBufferList(
|
||||
MapBuffer::Key key,
|
||||
const std::vector<MapBuffer> &mapBufferList) {
|
||||
int32_t offset = dynamicData_.size();
|
||||
int32_t dataSize = 0;
|
||||
for (const MapBuffer &mapBuffer : mapBufferList) {
|
||||
dataSize = dataSize + INT_SIZE + mapBuffer.size();
|
||||
}
|
||||
|
||||
dynamicData_.resize(offset + INT_SIZE, 0);
|
||||
memcpy(dynamicData_.data() + offset, &dataSize, INT_SIZE);
|
||||
|
||||
for (const MapBuffer &mapBuffer : mapBufferList) {
|
||||
int32_t mapBufferSize = mapBuffer.size();
|
||||
int32_t dynamicDataSize = dynamicData_.size();
|
||||
dynamicData_.resize(dynamicDataSize + INT_SIZE + mapBufferSize, 0);
|
||||
// format [length of buffer (int)] + [bytes of MapBuffer]
|
||||
memcpy(dynamicData_.data() + dynamicDataSize, &mapBufferSize, INT_SIZE);
|
||||
// Copy the content of the map into dynamicData_
|
||||
memcpy(
|
||||
dynamicData_.data() + dynamicDataSize + INT_SIZE,
|
||||
mapBuffer.data(),
|
||||
mapBufferSize);
|
||||
}
|
||||
|
||||
// Store Key and pointer to the string
|
||||
storeKeyValue(
|
||||
key,
|
||||
MapBuffer::DataType::Map,
|
||||
reinterpret_cast<uint8_t const *>(&offset),
|
||||
INT_SIZE);
|
||||
}
|
||||
|
||||
static inline bool compareBuckets(
|
||||
MapBuffer::Bucket const &a,
|
||||
MapBuffer::Bucket const &b) {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <react/debug/react_native_assert.h>
|
||||
#include <react/renderer/mapbuffer/MapBuffer.h>
|
||||
#include <vector>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
@ -35,6 +36,10 @@ class MapBufferBuilder {
|
|||
|
||||
void putMapBuffer(MapBuffer::Key key, MapBuffer const &map);
|
||||
|
||||
void putMapBufferList(
|
||||
MapBuffer::Key key,
|
||||
const std::vector<MapBuffer> &mapBufferList);
|
||||
|
||||
MapBuffer build();
|
||||
|
||||
private:
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <react/renderer/mapbuffer/MapBuffer.h>
|
||||
|
@ -150,6 +151,30 @@ TEST(MapBufferTest, testMapEntries) {
|
|||
EXPECT_EQ(readMap2.getInt(1), 1234);
|
||||
}
|
||||
|
||||
TEST(MapBufferTest, testMapListEntries) {
|
||||
std::vector<MapBuffer> mapBufferList;
|
||||
auto builder = MapBufferBuilder();
|
||||
builder.putString(0, "This is a test");
|
||||
builder.putInt(1, 1234);
|
||||
mapBufferList.push_back(builder.build());
|
||||
|
||||
auto builder2 = MapBufferBuilder();
|
||||
builder2.putInt(2, 4321);
|
||||
builder2.putDouble(3, 908.1);
|
||||
mapBufferList.push_back(builder2.build());
|
||||
|
||||
auto builder3 = MapBufferBuilder();
|
||||
builder3.putMapBufferList(5, std::move(mapBufferList));
|
||||
auto map = builder3.build();
|
||||
|
||||
std::vector<MapBuffer> mapBufferList2 = map.getMapBufferList(5);
|
||||
|
||||
EXPECT_EQ(mapBufferList2.size(), 2);
|
||||
EXPECT_EQ(mapBufferList2[0].getString(0), "This is a test");
|
||||
EXPECT_EQ(mapBufferList2[0].getInt(1), 1234);
|
||||
EXPECT_EQ(mapBufferList2[1].getDouble(3), 908.1);
|
||||
}
|
||||
|
||||
TEST(MapBufferTest, testMapRandomAccess) {
|
||||
auto builder = MapBufferBuilder();
|
||||
builder.putInt(1234, 4321);
|
||||
|
|
Загрузка…
Ссылка в новой задаче