Skip to content

Commit 9da6546

Browse files
NickGerlemanfacebook-github-bot
authored andcommitted
Avoid ByteBuffer copies when reading nested MapBuffers (#44436)
Summary: Pull Request resolved: #44436 The backing buffer behind `ReadableMapBuffer` is effectively immutable, so we can make reads of nested MapBuffers work on an inline view of the same buffer. This book-keeping is kept within ReadableMapBuffer (we can not user `ByteBuffer.wrap()` because the fbjni produces ByteBuffer is not array backed). The main downside I can think of is that the whole buffer is kept in memory until all children buffers leave, but current use-cases don't involve long-term storage of MapBuffer children, so this is probably a better tradeoff. Changelog: [Internal] Reviewed By: javache Differential Revision: D57020759 fbshipit-source-id: d2f5a76561fa4a4219fe5022ba62cc96f56ce022
1 parent 29c3bc0 commit 9da6546

1 file changed

Lines changed: 14 additions & 11 deletions

File tree

  • packages/react-native/ReactAndroid/src/main/java/com/facebook/react/common/mapbuffer

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/common/mapbuffer/ReadableMapBuffer.kt

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ public class ReadableMapBuffer : MapBuffer {
3232

3333
// Byte data of the mapBuffer
3434
private val buffer: ByteBuffer
35+
// Offset to the start of the MapBuffer
36+
private val offsetToMapBuffer: Int
3537
// Amount of items serialized on the ByteBuffer
3638
override var count: Int = 0
3739
private set
@@ -40,12 +42,21 @@ public class ReadableMapBuffer : MapBuffer {
4042
private constructor(hybridData: HybridData) {
4143
mHybridData = hybridData
4244
buffer = importByteBuffer()
45+
offsetToMapBuffer = 0
4346
readHeader()
4447
}
4548

4649
private constructor(buffer: ByteBuffer) {
4750
mHybridData = null
4851
this.buffer = buffer
52+
offsetToMapBuffer = 0
53+
readHeader()
54+
}
55+
56+
private constructor(buffer: ByteBuffer, offset: Int) {
57+
mHybridData = null
58+
this.buffer = buffer.duplicate().apply { position(offset) }
59+
offsetToMapBuffer = offset
4960
readHeader()
5061
}
5162

@@ -135,12 +146,7 @@ public class ReadableMapBuffer : MapBuffer {
135146

136147
private fun readMapBufferValue(position: Int): ReadableMapBuffer {
137148
val offset = offsetForDynamicData + buffer.getInt(position)
138-
val sizeMapBuffer = buffer.getInt(offset)
139-
val newBuffer = ByteArray(sizeMapBuffer)
140-
val bufferOffset = offset + Int.SIZE_BYTES
141-
buffer.position(bufferOffset)
142-
buffer[newBuffer, 0, sizeMapBuffer]
143-
return ReadableMapBuffer(ByteBuffer.wrap(newBuffer))
149+
return ReadableMapBuffer(buffer, offset + Int.SIZE_BYTES)
144150
}
145151

146152
private fun readMapBufferListValue(position: Int): List<ReadableMapBuffer> {
@@ -151,18 +157,15 @@ public class ReadableMapBuffer : MapBuffer {
151157
var curLen = 0
152158
while (curLen < sizeMapBufferList) {
153159
val sizeMapBuffer = buffer.getInt(offset + curLen)
154-
val newMapBuffer = ByteArray(sizeMapBuffer)
155160
curLen = curLen + Int.SIZE_BYTES
156-
buffer.position(offset + curLen)
157-
buffer[newMapBuffer, 0, sizeMapBuffer]
158-
readMapBufferList.add(ReadableMapBuffer(ByteBuffer.wrap(newMapBuffer)))
161+
readMapBufferList.add(ReadableMapBuffer(buffer, offset + curLen))
159162
curLen = curLen + sizeMapBuffer
160163
}
161164
return readMapBufferList
162165
}
163166

164167
private fun getKeyOffsetForBucketIndex(bucketIndex: Int): Int {
165-
return HEADER_SIZE + BUCKET_SIZE * bucketIndex
168+
return offsetToMapBuffer + HEADER_SIZE + BUCKET_SIZE * bucketIndex
166169
}
167170

168171
override fun contains(key: Int): Boolean {

0 commit comments

Comments
 (0)