Skip to content

Commit

Permalink
Add ability to store and retrieve a list of MapBuffer
Browse files Browse the repository at this point in the history
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
  • Loading branch information
luluwu2032 authored and facebook-github-bot committed Aug 11, 2022
1 parent 7e580b9 commit fc06515
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
25 changes: 25 additions & 0 deletions ReactCommon/react/renderer/mapbuffer/MapBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
2 changes: 2 additions & 0 deletions ReactCommon/react/renderer/mapbuffer/MapBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
33 changes: 33 additions & 0 deletions ReactCommon/react/renderer/mapbuffer/MapBufferBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
5 changes: 5 additions & 0 deletions ReactCommon/react/renderer/mapbuffer/MapBufferBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <react/debug/react_native_assert.h>
#include <react/renderer/mapbuffer/MapBuffer.h>
#include <vector>

namespace facebook {
namespace react {
Expand All @@ -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:
Expand Down
25 changes: 25 additions & 0 deletions ReactCommon/react/renderer/mapbuffer/tests/MapBufferTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

#include <memory>
#include <vector>

#include <gtest/gtest.h>
#include <react/renderer/mapbuffer/MapBuffer.h>
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit fc06515

Please sign in to comment.