Skip to content

Commit 9a84a5b

Browse files
committed
Try Fix MapBuffer
1 parent f9ca545 commit 9a84a5b

File tree

3 files changed

+219
-0
lines changed

3 files changed

+219
-0
lines changed

.vscode/settings.json

+3
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,8 @@
4646
"typescript.tsdk": "node_modules\\typescript\\lib",
4747
"editor.codeActionsOnSave": {
4848
"source.fixAll.eslint": true
49+
},
50+
"files.associations": {
51+
"*.ipp": "cpp"
4952
}
5053
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#include "MapBuffer.h"
9+
10+
using namespace facebook::react;
11+
12+
namespace facebook {
13+
namespace react {
14+
15+
// TODO T83483191: Extend MapBuffer C++ implementation to support basic random
16+
// access
17+
MapBuffer::MapBuffer(std::vector<uint8_t> data) : bytes_(std::move(data)) {
18+
count_ = 0;
19+
memcpy(
20+
reinterpret_cast<uint8_t *>(&count_),
21+
bytes_.data() + HEADER_COUNT_OFFSET,
22+
UINT16_SIZE);
23+
24+
// TODO T83483191: extract memcpy calls into an inline function to simplify
25+
// the code
26+
uint32_t dataSize;
27+
memcpy(
28+
reinterpret_cast<uint8_t *>(&dataSize),
29+
reinterpret_cast<const uint8_t *>(bytes_.data() + HEADER_BUFFER_SIZE_OFFSET),
30+
INT_SIZE);
31+
32+
if (dataSize != bytes_.size()) {
33+
LOG(ERROR) << "Error: Data size does not match, expected " << dataSize
34+
<< " found: " << bytes_.size();
35+
abort();
36+
}
37+
}
38+
39+
int32_t MapBuffer::getInt(Key key) const {
40+
int32_t value = 0;
41+
memcpy(
42+
reinterpret_cast<uint8_t *>(&value),
43+
reinterpret_cast<const uint8_t *>(bytes_.data() + getValueOffset(key)),
44+
INT_SIZE);
45+
return value;
46+
}
47+
48+
bool MapBuffer::getBool(Key key) const {
49+
return getInt(key) != 0;
50+
}
51+
52+
double MapBuffer::getDouble(Key key) const {
53+
// TODO T83483191: extract this code into a "template method" and reuse it for
54+
// other types
55+
double value = 0;
56+
memcpy(
57+
reinterpret_cast<uint8_t *>(&value),
58+
reinterpret_cast<const uint8_t *>(bytes_.data() + getValueOffset(key)),
59+
DOUBLE_SIZE);
60+
return value;
61+
}
62+
63+
int32_t MapBuffer::getDynamicDataOffset() const {
64+
// The begininig of dynamic data can be calculated as the offset of the next
65+
// key in the map
66+
return getKeyOffset(count_);
67+
}
68+
69+
std::string MapBuffer::getString(Key key) const {
70+
// TODO T83483191:Add checks to verify that offsets are under the boundaries
71+
// of the map buffer
72+
int32_t dynamicDataOffset = getDynamicDataOffset();
73+
int32_t stringLength = 0;
74+
int32_t offset = getInt(key);
75+
memcpy(
76+
reinterpret_cast<uint8_t *>(&stringLength),
77+
reinterpret_cast<const uint8_t *>(bytes_.data() + dynamicDataOffset + offset),
78+
INT_SIZE);
79+
80+
char *value = new char[stringLength];
81+
82+
memcpy(
83+
reinterpret_cast<char *>(value),
84+
reinterpret_cast<const uint8_t *>(bytes_.data() + dynamicDataOffset + offset + INT_SIZE),
85+
stringLength);
86+
87+
return std::string(value, 0, stringLength);
88+
}
89+
90+
MapBuffer MapBuffer::getMapBuffer(Key key) const {
91+
// TODO T83483191: Add checks to verify that offsets are under the boundaries
92+
// of the map buffer
93+
int32_t dynamicDataOffset = getDynamicDataOffset();
94+
95+
int32_t mapBufferLength = 0;
96+
int32_t offset = getInt(key);
97+
memcpy(
98+
reinterpret_cast<uint8_t *>(&mapBufferLength),
99+
reinterpret_cast<const uint8_t *>(bytes_.data() + dynamicDataOffset + offset),
100+
INT_SIZE);
101+
102+
std::vector<uint8_t> value(mapBufferLength);
103+
104+
memcpy(
105+
value.data(),
106+
bytes_.data() + dynamicDataOffset + offset + INT_SIZE,
107+
mapBufferLength);
108+
109+
return MapBuffer(std::move(value));
110+
}
111+
112+
bool MapBuffer::isNull(Key key) const {
113+
return getInt(key) == NULL_VALUE;
114+
}
115+
116+
int32_t MapBuffer::getBufferSize() const {
117+
return bytes_.size();
118+
}
119+
120+
void MapBuffer::copy(uint8_t *output) const {
121+
memcpy(output, bytes_.data(), bytes_.size());
122+
}
123+
124+
uint16_t MapBuffer::getCount() const {
125+
uint16_t size = 0;
126+
127+
memcpy(
128+
reinterpret_cast<uint8_t *>(&size),
129+
bytes_.data() + HEADER_COUNT_OFFSET,
130+
UINT16_SIZE);
131+
132+
return size;
133+
}
134+
135+
136+
} // namespace react
137+
} // namespace facebook
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#pragma once
9+
10+
#include <react/debug/react_native_assert.h>
11+
#include <react/renderer/mapbuffer/primitives.h>
12+
13+
#include <limits>
14+
15+
namespace facebook {
16+
namespace react {
17+
18+
class ReadableMapBuffer;
19+
20+
/**
21+
* MapBuffer is an optimized map format for transferring data like props between
22+
* C++ and other platforms The implementation of this map is optimized to:
23+
* - be compact to optimize space when sparse (sparse is the common case).
24+
* - be accessible through JNI with zero/minimal copying via ByteBuffer.
25+
* - be Have excellent C++ single-write and many-read performance by maximizing
26+
* CPU cache performance through compactness, data locality, and fixed offsets
27+
* where possible.
28+
* - be optimized for iteration and intersection against other maps, but with
29+
* reasonably good random access as well.
30+
* - Work recursively for nested maps/arrays.
31+
* - Supports dynamic types that map to JSON.
32+
* - Don't require mutability - single-write on creation.
33+
* - have minimal APK size and build time impact.
34+
*/
35+
class MapBuffer {
36+
friend ReadableMapBuffer;
37+
38+
private:
39+
// Buffer and its size
40+
std::vector<uint8_t> const bytes_;
41+
42+
// amount of items in the MapBuffer
43+
uint16_t count_ = 0;
44+
45+
// returns the relative offset of the first byte of dynamic data
46+
int32_t getDynamicDataOffset() const;
47+
48+
public:
49+
explicit MapBuffer(std::vector<uint8_t> data);
50+
51+
MapBuffer(MapBuffer const &buffer) = delete;
52+
53+
MapBuffer &operator=(MapBuffer other) = delete;
54+
55+
MapBuffer(MapBuffer &&buffer) = default;
56+
57+
int32_t getInt(Key key) const;
58+
59+
bool getBool(Key key) const;
60+
61+
double getDouble(Key key) const;
62+
63+
std::string getString(Key key) const;
64+
65+
// TODO T83483191: review this declaration
66+
MapBuffer getMapBuffer(Key key) const;
67+
68+
int32_t getBufferSize() const;
69+
70+
// TODO T83483191: review parameters of copy method
71+
void copy(uint8_t *output) const;
72+
73+
bool isNull(Key key) const;
74+
75+
uint16_t getCount() const;
76+
};
77+
78+
} // namespace react
79+
} // namespace facebook

0 commit comments

Comments
 (0)