Skip to content

Commit

Permalink
MapBuffer long support (#43030)
Browse files Browse the repository at this point in the history
Summary:
This adds support for 64 bit integer (long) values to MapBuffer. Per the wide gamut color [RFC](react-native-community/discussions-and-proposals#738) Android encodes wide gamut colors as long values so we need to update MapBuffer to support 64 bit integers as well.

## Changelog:

[ANDROID] [ADDED] - Add 64 bit integer (long) value support to MapBuffer

Pull Request resolved: #43030

Test Plan: I've added a test to the MapBuffer test suite. This new API is otherwise currently unused but will be used in subsequent PRs as part of wide gamut color support changes.

Reviewed By: mdvacca

Differential Revision: D53881809

Pulled By: NickGerleman

fbshipit-source-id: 39c20b93493a2609db9f66426640ef5e97d6e1a8
  • Loading branch information
ryanlntn authored and facebook-github-bot committed Feb 28, 2024
1 parent 8317325 commit 57ed0fb
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 2 deletions.
6 changes: 6 additions & 0 deletions packages/react-native/ReactAndroid/api/ReactAndroid.api
Original file line number Diff line number Diff line change
Expand Up @@ -1793,6 +1793,7 @@ public abstract interface class com/facebook/react/common/mapbuffer/MapBuffer :
public abstract fun getDouble (I)D
public abstract fun getInt (I)I
public abstract fun getKeyOffset (I)I
public abstract fun getLong (I)J
public abstract fun getMapBuffer (I)Lcom/facebook/react/common/mapbuffer/MapBuffer;
public abstract fun getMapBufferList (I)Ljava/util/List;
public abstract fun getString (I)Ljava/lang/String;
Expand All @@ -1806,6 +1807,7 @@ public final class com/facebook/react/common/mapbuffer/MapBuffer$DataType : java
public static final field BOOL Lcom/facebook/react/common/mapbuffer/MapBuffer$DataType;
public static final field DOUBLE Lcom/facebook/react/common/mapbuffer/MapBuffer$DataType;
public static final field INT Lcom/facebook/react/common/mapbuffer/MapBuffer$DataType;
public static final field LONG Lcom/facebook/react/common/mapbuffer/MapBuffer$DataType;
public static final field MAP Lcom/facebook/react/common/mapbuffer/MapBuffer$DataType;
public static final field STRING Lcom/facebook/react/common/mapbuffer/MapBuffer$DataType;
public static fun valueOf (Ljava/lang/String;)Lcom/facebook/react/common/mapbuffer/MapBuffer$DataType;
Expand All @@ -1817,6 +1819,7 @@ public abstract interface class com/facebook/react/common/mapbuffer/MapBuffer$En
public abstract fun getDoubleValue ()D
public abstract fun getIntValue ()I
public abstract fun getKey ()I
public abstract fun getLongValue ()J
public abstract fun getMapBufferValue ()Lcom/facebook/react/common/mapbuffer/MapBuffer;
public abstract fun getStringValue ()Ljava/lang/String;
public abstract fun getType ()Lcom/facebook/react/common/mapbuffer/MapBuffer$DataType;
Expand All @@ -1837,6 +1840,7 @@ public final class com/facebook/react/common/mapbuffer/ReadableMapBuffer : com/f
public fun getDouble (I)D
public fun getInt (I)I
public fun getKeyOffset (I)I
public fun getLong (I)J
public synthetic fun getMapBuffer (I)Lcom/facebook/react/common/mapbuffer/MapBuffer;
public fun getMapBuffer (I)Lcom/facebook/react/common/mapbuffer/ReadableMapBuffer;
public fun getMapBufferList (I)Ljava/util/List;
Expand All @@ -1859,13 +1863,15 @@ public final class com/facebook/react/common/mapbuffer/WritableMapBuffer : com/f
public fun getDouble (I)D
public fun getInt (I)I
public fun getKeyOffset (I)I
public fun getLong (I)J
public fun getMapBuffer (I)Lcom/facebook/react/common/mapbuffer/MapBuffer;
public fun getMapBufferList (I)Ljava/util/List;
public fun getString (I)Ljava/lang/String;
public fun getType (I)Lcom/facebook/react/common/mapbuffer/MapBuffer$DataType;
public fun iterator ()Ljava/util/Iterator;
public final fun put (ID)Lcom/facebook/react/common/mapbuffer/WritableMapBuffer;
public final fun put (II)Lcom/facebook/react/common/mapbuffer/WritableMapBuffer;
public final fun put (IJ)Lcom/facebook/react/common/mapbuffer/WritableMapBuffer;
public final fun put (ILcom/facebook/react/common/mapbuffer/MapBuffer;)Lcom/facebook/react/common/mapbuffer/WritableMapBuffer;
public final fun put (ILjava/lang/String;)Lcom/facebook/react/common/mapbuffer/WritableMapBuffer;
public final fun put (IZ)Lcom/facebook/react/common/mapbuffer/WritableMapBuffer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ public interface MapBuffer : Iterable<MapBuffer.Entry> {
INT,
DOUBLE,
STRING,
MAP
MAP,
LONG
}

/**
Expand Down Expand Up @@ -109,6 +110,16 @@ public interface MapBuffer : Iterable<MapBuffer.Entry> {
*/
public fun getInt(key: Int): Int

/**
* Provides parsed [Long] value if the entry for given key exists with [DataType.LONG] type
*
* @param key key to lookup [Long] 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
*/
public fun getLong(key: Int): Long

/**
* Provides parsed [Double] value if the entry for given key exists with [DataType.DOUBLE] type
*
Expand Down Expand Up @@ -175,6 +186,13 @@ public interface MapBuffer : Iterable<MapBuffer.Entry> {
*/
public val intValue: Int

/**
* Entry value represented as [Long]
*
* @throws IllegalStateException if the data type doesn't match [DataType.LONG]
*/
public val longValue: Long

/**
* Entry value represented as [Double]
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ public class ReadableMapBuffer : MapBuffer {
return buffer.getInt(bufferPosition)
}

private fun readLongValue(bufferPosition: Int): Long {
return buffer.getLong(bufferPosition)
}

private fun readBooleanValue(bufferPosition: Int): Boolean {
return readIntValue(bufferPosition) == 1
}
Expand Down Expand Up @@ -180,6 +184,9 @@ public class ReadableMapBuffer : MapBuffer {
override fun getInt(key: Int): Int =
readIntValue(getTypedValueOffsetForKey(key, MapBuffer.DataType.INT))

override fun getLong(key: Int): Long =
readLongValue(getTypedValueOffsetForKey(key, MapBuffer.DataType.LONG))

override fun getDouble(key: Int): Double =
readDoubleValue(getTypedValueOffsetForKey(key, MapBuffer.DataType.DOUBLE))

Expand Down Expand Up @@ -223,6 +230,7 @@ public class ReadableMapBuffer : MapBuffer {
when (entry.type) {
MapBuffer.DataType.BOOL -> builder.append(entry.booleanValue)
MapBuffer.DataType.INT -> builder.append(entry.intValue)
MapBuffer.DataType.LONG -> builder.append(entry.longValue)
MapBuffer.DataType.DOUBLE -> builder.append(entry.doubleValue)
MapBuffer.DataType.STRING -> builder.append(entry.stringValue)
MapBuffer.DataType.MAP -> builder.append(entry.mapBufferValue.toString())
Expand Down Expand Up @@ -280,6 +288,12 @@ public class ReadableMapBuffer : MapBuffer {
return readIntValue(bucketOffset + VALUE_OFFSET)
}

override val longValue: Long
get() {
assertType(MapBuffer.DataType.LONG)
return readLongValue(bucketOffset + VALUE_OFFSET)
}

override val booleanValue: Boolean
get() {
assertType(MapBuffer.DataType.BOOL)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ public class WritableMapBuffer : MapBuffer {
*/
public fun put(key: Int, value: Int): WritableMapBuffer = putInternal(key, value)

/**
* Adds a long value for given key to the MapBuffer.
*
* @param key entry key
* @param value entry value
* @throws IllegalArgumentException if key is out of [UShort] range
*/
public fun put(key: Int, value: Long): WritableMapBuffer = putInternal(key, value)

/**
* Adds a double value for given key to the MapBuffer.
*
Expand Down Expand Up @@ -107,6 +116,8 @@ public class WritableMapBuffer : MapBuffer {

override fun getInt(key: Int): Int = verifyValue(key, values.get(key))

override fun getLong(key: Int): Long = verifyValue(key, values.get(key))

override fun getDouble(key: Int): Double = verifyValue(key, values.get(key))

override fun getString(key: Int): String = verifyValue(key, values.get(key))
Expand All @@ -128,6 +139,7 @@ public class WritableMapBuffer : MapBuffer {
return when (val value = this) {
is Boolean -> DataType.BOOL
is Int -> DataType.INT
is Long -> DataType.LONG
is Double -> DataType.DOUBLE
is String -> DataType.STRING
is MapBuffer -> DataType.MAP
Expand All @@ -153,6 +165,9 @@ public class WritableMapBuffer : MapBuffer {
override val intValue: Int
get() = verifyValue(key, values.valueAt(index))

override val longValue: Long
get() = verifyValue(key, values.valueAt(index))

override val doubleValue: Double
get() = verifyValue(key, values.valueAt(index))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ int32_t MapBuffer::getInt(Key key) const {
bytes_.data() + valueOffset(bucketIndex));
}

int64_t MapBuffer::getLong(Key key) const {
auto bucketIndex = getKeyBucket(key);
react_native_assert(bucketIndex != -1 && "Key not found in MapBuffer");

return *reinterpret_cast<const int64_t*>(
bytes_.data() + valueOffset(bucketIndex));
}

bool MapBuffer::getBool(Key key) const {
return getInt(key) != 0;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ class MapBuffer {
Double = 2,
String = 3,
Map = 4,
Long = 5,
};

explicit MapBuffer(std::vector<uint8_t> data);
Expand All @@ -118,6 +119,8 @@ class MapBuffer {

int32_t getInt(MapBuffer::Key key) const;

int64_t getLong(MapBuffer::Key key) const;

bool getBool(MapBuffer::Key key) const;

double getDouble(MapBuffer::Key key) const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ using namespace facebook::react;
namespace facebook::react {

constexpr uint32_t INT_SIZE = sizeof(uint32_t);
constexpr uint32_t LONG_SIZE = sizeof(uint64_t);
constexpr uint32_t DOUBLE_SIZE = sizeof(double);
constexpr uint32_t MAX_BUCKET_VALUE_SIZE = sizeof(uint64_t);

Expand Down Expand Up @@ -76,6 +77,14 @@ void MapBufferBuilder::putInt(MapBuffer::Key key, int32_t value) {
INT_SIZE);
}

void MapBufferBuilder::putLong(MapBuffer::Key key, int64_t value) {
storeKeyValue(
key,
MapBuffer::DataType::Long,
reinterpret_cast<const uint8_t*>(&value),
LONG_SIZE);
}

void MapBufferBuilder::putString(MapBuffer::Key key, const std::string& value) {
auto strSize = value.size();
const char* strData = value.data();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class MapBufferBuilder {

void putInt(MapBuffer::Key key, int32_t value);

// TODO: Support 64 bit integers
void putLong(MapBuffer::Key key, int64_t value);

void putBool(MapBuffer::Key key, bool value);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/

#include <limits>
#include <memory>
#include <vector>

Expand All @@ -27,6 +28,26 @@ TEST(MapBufferTest, testSimpleIntMap) {
EXPECT_EQ(map.getInt(1), 4321);
}

TEST(MapBufferTest, testSimpleLongMap) {
auto builder = MapBufferBuilder();

int64_t minInt64 = std::numeric_limits<int64_t>::min();
int64_t maxInt64 = std::numeric_limits<int64_t>::max();

builder.putLong(0, minInt64);
builder.putLong(1, maxInt64);
builder.putLong(2, 1125899906842623LL);
builder.putLong(3, -1125899906842623LL);

auto map = builder.build();

EXPECT_EQ(map.count(), 4);
EXPECT_EQ(map.getLong(0), minInt64);
EXPECT_EQ(map.getLong(1), maxInt64);
EXPECT_EQ(map.getLong(2), 1125899906842623LL);
EXPECT_EQ(map.getLong(3), -1125899906842623LL);
}

TEST(MapBufferTest, testMapBufferExtension) {
// 26 = 2 buckets: 2*10 + 6 sizeof(header)
int initialSize = 26;
Expand Down

0 comments on commit 57ed0fb

Please sign in to comment.