IntBufferBatchMountItem - migrate to Kotlin (#50700)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/50700

## Changelog:
[Android] [Internal] - IntBufferBatchMountItem is now in Kotlin

Reviewed By: cortinico

Differential Revision: D72965060

fbshipit-source-id: d036030ddd3fbd0bc387e02236ee330bb310ca64
This commit is contained in:
Ruslan Shestopalyuk
2025-04-14 10:37:01 -07:00
committed by Facebook GitHub Bot
parent f622923374
commit 309ccb8b60
2 changed files with 335 additions and 346 deletions
@@ -1,346 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.fabric.mounting.mountitems;
import static com.facebook.react.fabric.FabricUIManager.IS_DEVELOPMENT_ENVIRONMENT;
import static com.facebook.react.fabric.mounting.mountitems.FabricNameComponentMapping.getFabricComponentName;
import com.facebook.common.logging.FLog;
import com.facebook.infer.annotation.Nullsafe;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.ReactMarker;
import com.facebook.react.bridge.ReactMarkerConstants;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.fabric.events.EventEmitterWrapper;
import com.facebook.react.fabric.mounting.MountingManager;
import com.facebook.react.fabric.mounting.SurfaceMountingManager;
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags;
import com.facebook.react.uimanager.StateWrapper;
import com.facebook.systrace.Systrace;
import java.util.Locale;
/**
* This class represents a batch of {@link MountItem}s, represented directly as int buffers to
* remove the need for actual MountItem instances.
*
* <p>An IntBufferBatchMountItem batch contains an array of ints, indicating the mount actions that
* should be taken, and a size; as well as an array of Objects, and a corresponding array size, for
* any data that cannot be passed as a raw int.
*
* <p>The purpose of encapsulating the array of MountItems this way, is to reduce the amount of
* allocations in C++ and JNI round-trips.
*/
@DoNotStrip
@Nullsafe(Nullsafe.Mode.LOCAL)
final class IntBufferBatchMountItem implements BatchMountItem {
static final String TAG = IntBufferBatchMountItem.class.getSimpleName();
static final int INSTRUCTION_FLAG_MULTIPLE = 1;
static final int INSTRUCTION_CREATE = 2;
static final int INSTRUCTION_DELETE = 4;
static final int INSTRUCTION_INSERT = 8;
static final int INSTRUCTION_REMOVE = 16;
static final int INSTRUCTION_UPDATE_PROPS = 32;
static final int INSTRUCTION_UPDATE_STATE = 64;
static final int INSTRUCTION_UPDATE_LAYOUT = 128;
static final int INSTRUCTION_UPDATE_EVENT_EMITTER = 256;
static final int INSTRUCTION_UPDATE_PADDING = 512;
static final int INSTRUCTION_UPDATE_OVERFLOW_INSET = 1024;
private final int mSurfaceId;
private final int mCommitNumber;
private final int[] mIntBuffer;
private final Object[] mObjBuffer;
private final int mIntBufferLen;
private final int mObjBufferLen;
IntBufferBatchMountItem(int surfaceId, int[] intBuf, Object[] objBuf, int commitNumber) {
mSurfaceId = surfaceId;
mCommitNumber = commitNumber;
mIntBuffer = intBuf;
mObjBuffer = objBuf;
mIntBufferLen = mIntBuffer.length;
mObjBufferLen = mObjBuffer.length;
}
private void beginMarkers(String reason) {
Systrace.beginSection(Systrace.TRACE_TAG_REACT, "IntBufferBatchMountItem::" + reason);
if (mCommitNumber > 0) {
ReactMarker.logFabricMarker(
ReactMarkerConstants.FABRIC_BATCH_EXECUTION_START, null, mCommitNumber);
}
}
private void endMarkers() {
if (mCommitNumber > 0) {
ReactMarker.logFabricMarker(
ReactMarkerConstants.FABRIC_BATCH_EXECUTION_END, null, mCommitNumber);
}
Systrace.endSection(Systrace.TRACE_TAG_REACT);
}
@Override
public void execute(MountingManager mountingManager) {
SurfaceMountingManager surfaceMountingManager = mountingManager.getSurfaceManager(mSurfaceId);
if (surfaceMountingManager == null) {
FLog.e(
TAG,
"Skipping batch of MountItems; no SurfaceMountingManager found for [%d].",
mSurfaceId);
return;
}
if (surfaceMountingManager.isStopped()) {
FLog.e(TAG, "Skipping batch of MountItems; was stopped [%d].", mSurfaceId);
return;
}
if (ReactNativeFeatureFlags.enableFabricLogs()) {
FLog.d(TAG, "Executing IntBufferBatchMountItem on surface [%d]", mSurfaceId);
}
beginMarkers("mountViews");
int i = 0, j = 0;
while (i < mIntBufferLen) {
int rawType = mIntBuffer[i++];
int type = rawType & ~INSTRUCTION_FLAG_MULTIPLE;
int numInstructions = ((rawType & INSTRUCTION_FLAG_MULTIPLE) != 0 ? mIntBuffer[i++] : 1);
String[] args = {"numInstructions", String.valueOf(numInstructions)};
Systrace.beginSection(
Systrace.TRACE_TAG_REACT,
"IntBufferBatchMountItem::mountInstructions::" + nameForInstructionString(type),
args,
args.length);
for (int k = 0; k < numInstructions; k++) {
if (type == INSTRUCTION_CREATE) {
String componentName = getFabricComponentName((String) mObjBuffer[j++]);
surfaceMountingManager.createView(
componentName,
mIntBuffer[i++],
(ReadableMap) mObjBuffer[j++],
(StateWrapper) mObjBuffer[j++],
(EventEmitterWrapper) mObjBuffer[j++],
mIntBuffer[i++] == 1);
} else if (type == INSTRUCTION_DELETE) {
surfaceMountingManager.deleteView(mIntBuffer[i++]);
} else if (type == INSTRUCTION_INSERT) {
int tag = mIntBuffer[i++];
int parentTag = mIntBuffer[i++];
surfaceMountingManager.addViewAt(parentTag, tag, mIntBuffer[i++]);
} else if (type == INSTRUCTION_REMOVE) {
surfaceMountingManager.removeViewAt(mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++]);
} else if (type == INSTRUCTION_UPDATE_PROPS) {
surfaceMountingManager.updateProps(mIntBuffer[i++], (ReadableMap) mObjBuffer[j++]);
} else if (type == INSTRUCTION_UPDATE_STATE) {
surfaceMountingManager.updateState(mIntBuffer[i++], (StateWrapper) mObjBuffer[j++]);
} else if (type == INSTRUCTION_UPDATE_LAYOUT) {
int reactTag = mIntBuffer[i++];
int parentTag = mIntBuffer[i++];
int x = mIntBuffer[i++];
int y = mIntBuffer[i++];
int width = mIntBuffer[i++];
int height = mIntBuffer[i++];
int displayType = mIntBuffer[i++];
int layoutDirection = mIntBuffer[i++];
surfaceMountingManager.updateLayout(
reactTag, parentTag, x, y, width, height, displayType, layoutDirection);
} else if (type == INSTRUCTION_UPDATE_PADDING) {
surfaceMountingManager.updatePadding(
mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++]);
} else if (type == INSTRUCTION_UPDATE_OVERFLOW_INSET) {
int reactTag = mIntBuffer[i++];
int overflowInsetLeft = mIntBuffer[i++];
int overflowInsetTop = mIntBuffer[i++];
int overflowInsetRight = mIntBuffer[i++];
int overflowInsetBottom = mIntBuffer[i++];
surfaceMountingManager.updateOverflowInset(
reactTag,
overflowInsetLeft,
overflowInsetTop,
overflowInsetRight,
overflowInsetBottom);
} else if (type == INSTRUCTION_UPDATE_EVENT_EMITTER) {
surfaceMountingManager.updateEventEmitter(
mIntBuffer[i++], (EventEmitterWrapper) mObjBuffer[j++]);
} else {
throw new IllegalArgumentException(
"Invalid type argument to IntBufferBatchMountItem: " + type + " at index: " + i);
}
}
Systrace.endSection(Systrace.TRACE_TAG_REACT);
}
endMarkers();
}
@Override
public int getSurfaceId() {
return mSurfaceId;
}
@Override
public boolean isBatchEmpty() {
return mIntBufferLen == 0;
}
@Override
public String toString() {
try {
StringBuilder s = new StringBuilder();
s.append(String.format(Locale.ROOT, "IntBufferBatchMountItem [surface:%d]:\n", mSurfaceId));
int i = 0, j = 0;
while (i < mIntBufferLen) {
int rawType = mIntBuffer[i++];
int type = rawType & ~INSTRUCTION_FLAG_MULTIPLE;
int numInstructions = ((rawType & INSTRUCTION_FLAG_MULTIPLE) != 0 ? mIntBuffer[i++] : 1);
for (int k = 0; k < numInstructions; k++) {
if (type == INSTRUCTION_CREATE) {
String componentName = getFabricComponentName((String) mObjBuffer[j++]);
j += 3;
s.append(
String.format(
Locale.ROOT,
"CREATE [%d] - layoutable:%d - %s\n",
mIntBuffer[i++],
mIntBuffer[i++],
componentName));
} else if (type == INSTRUCTION_DELETE) {
s.append(String.format(Locale.ROOT, "DELETE [%d]\n", mIntBuffer[i++]));
} else if (type == INSTRUCTION_INSERT) {
s.append(
String.format(
Locale.ROOT,
"INSERT [%d]->[%d] @%d\n",
mIntBuffer[i++],
mIntBuffer[i++],
mIntBuffer[i++]));
} else if (type == INSTRUCTION_REMOVE) {
s.append(
String.format(
Locale.ROOT,
"REMOVE [%d]->[%d] @%d\n",
mIntBuffer[i++],
mIntBuffer[i++],
mIntBuffer[i++]));
} else if (type == INSTRUCTION_UPDATE_PROPS) {
Object props = mObjBuffer[j++];
String propsString =
IS_DEVELOPMENT_ENVIRONMENT
? (props != null ? props.toString() : "<null>")
: "<hidden>";
s.append(
String.format(
Locale.ROOT, "UPDATE PROPS [%d]: %s\n", mIntBuffer[i++], propsString));
} else if (type == INSTRUCTION_UPDATE_STATE) {
StateWrapper state = (StateWrapper) mObjBuffer[j++];
String stateString =
IS_DEVELOPMENT_ENVIRONMENT
? (state != null ? state.toString() : "<null>")
: "<hidden>";
s.append(
String.format(
Locale.ROOT, "UPDATE STATE [%d]: %s\n", mIntBuffer[i++], stateString));
} else if (type == INSTRUCTION_UPDATE_LAYOUT) {
s.append(
String.format(
Locale.ROOT,
"UPDATE LAYOUT [%d]->[%d]: x:%d y:%d w:%d h:%d displayType:%d"
+ " layoutDirection:%d\n",
mIntBuffer[i++],
mIntBuffer[i++],
mIntBuffer[i++],
mIntBuffer[i++],
mIntBuffer[i++],
mIntBuffer[i++],
mIntBuffer[i++],
mIntBuffer[i++]));
} else if (type == INSTRUCTION_UPDATE_PADDING) {
s.append(
String.format(
Locale.ROOT,
"UPDATE PADDING [%d]: top:%d right:%d bottom:%d left:%d\n",
mIntBuffer[i++],
mIntBuffer[i++],
mIntBuffer[i++],
mIntBuffer[i++],
mIntBuffer[i++]));
} else if (type == INSTRUCTION_UPDATE_OVERFLOW_INSET) {
s.append(
String.format(
Locale.ROOT,
"UPDATE OVERFLOWINSET [%d]: left:%d top:%d right:%d bottom:%d\n",
mIntBuffer[i++],
mIntBuffer[i++],
mIntBuffer[i++],
mIntBuffer[i++],
mIntBuffer[i++]));
} else if (type == INSTRUCTION_UPDATE_EVENT_EMITTER) {
j += 1;
s.append(String.format(Locale.ROOT, "UPDATE EVENTEMITTER [%d]\n", mIntBuffer[i++]));
} else {
FLog.e(TAG, "String so far: " + s.toString());
throw new IllegalArgumentException(
"Invalid type argument to IntBufferBatchMountItem: " + type + " at index: " + i);
}
}
}
return s.toString();
} catch (Exception e) {
// Generally, this only happens during development when a malformed buffer is sent through.
// In these cases, we print the buffers to assist in debugging.
// This should never happen in production, but if it does... it'd still be helpful to know.
FLog.e(TAG, "Caught exception trying to print", e);
StringBuilder ss = new StringBuilder();
for (int ii = 0; ii < mIntBufferLen; ii++) {
ss.append(mIntBuffer[ii]);
ss.append(", ");
}
FLog.e(TAG, ss.toString());
for (int jj = 0; jj < mObjBufferLen; jj++) {
FLog.e(TAG, mObjBuffer[jj] != null ? mObjBuffer[jj].toString() : "null");
}
return "";
}
}
private static String nameForInstructionString(int type) {
if (type == INSTRUCTION_CREATE) {
return "CREATE";
} else if (type == INSTRUCTION_DELETE) {
return "DELETE";
} else if (type == INSTRUCTION_INSERT) {
return "INSERT";
} else if (type == INSTRUCTION_REMOVE) {
return "REMOVE";
} else if (type == INSTRUCTION_UPDATE_PROPS) {
return "UPDATE_PROPS";
} else if (type == INSTRUCTION_UPDATE_STATE) {
return "UPDATE_STATE";
} else if (type == INSTRUCTION_UPDATE_LAYOUT) {
return "UPDATE_LAYOUT";
} else if (type == INSTRUCTION_UPDATE_PADDING) {
return "UPDATE_PADDING";
} else if (type == INSTRUCTION_UPDATE_OVERFLOW_INSET) {
return "UPDATE_OVERFLOW_INSET";
} else if (type == INSTRUCTION_UPDATE_EVENT_EMITTER) {
return "UPDATE_EVENT_EMITTER";
} else {
return "UNKNOWN";
}
}
}
@@ -0,0 +1,335 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.fabric.mounting.mountitems
import com.facebook.common.logging.FLog
import com.facebook.proguard.annotations.DoNotStripAny
import com.facebook.react.bridge.ReactMarker
import com.facebook.react.bridge.ReactMarkerConstants
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.fabric.FabricUIManager
import com.facebook.react.fabric.events.EventEmitterWrapper
import com.facebook.react.fabric.mounting.MountingManager
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
import com.facebook.react.uimanager.StateWrapper
import com.facebook.systrace.Systrace
import java.util.Locale
/**
* This class represents a batch of [MountItem]s, represented directly as int buffers to remove the
* need for actual MountItem instances.
*
* An IntBufferBatchMountItem batch contains an array of ints, indicating the mount actions that
* should be taken, and a size; as well as an array of Objects, and a corresponding array size, for
* any data that cannot be passed as a raw int.
*
* The purpose of encapsulating the array of MountItems this way, is to reduce the amount of
* allocations in C++ and JNI round-trips.
*/
@DoNotStripAny
internal class IntBufferBatchMountItem(
private val surfaceId: Int,
private val intBuffer: IntArray,
private val objBuffer: Array<Any?>,
private val commitNumber: Int
) : BatchMountItem {
private val intBufferLen = intBuffer.size
private val objBufferLen = objBuffer.size
private fun beginMarkers(reason: String) {
Systrace.beginSection(Systrace.TRACE_TAG_REACT, "IntBufferBatchMountItem::$reason")
if (commitNumber > 0) {
ReactMarker.logFabricMarker(
ReactMarkerConstants.FABRIC_BATCH_EXECUTION_START, null, commitNumber)
}
}
private fun endMarkers() {
if (commitNumber > 0) {
ReactMarker.logFabricMarker(
ReactMarkerConstants.FABRIC_BATCH_EXECUTION_END, null, commitNumber)
}
Systrace.endSection(Systrace.TRACE_TAG_REACT)
}
override fun execute(mountingManager: MountingManager) {
val surfaceMountingManager = mountingManager.getSurfaceManager(surfaceId)
if (surfaceMountingManager == null) {
FLog.e(
TAG, "Skipping batch of MountItems; no SurfaceMountingManager found for [%d].", surfaceId)
return
}
if (surfaceMountingManager.isStopped()) {
FLog.e(TAG, "Skipping batch of MountItems; was stopped [%d].", surfaceId)
return
}
if (ReactNativeFeatureFlags.enableFabricLogs()) {
FLog.d(TAG, "Executing IntBufferBatchMountItem on surface [%d]", surfaceId)
}
beginMarkers("mountViews")
var i = 0
var j = 0
while (i < intBufferLen) {
val rawType = intBuffer[i++]
val type = rawType and INSTRUCTION_FLAG_MULTIPLE.inv()
val numInstructions =
(if ((rawType and INSTRUCTION_FLAG_MULTIPLE) != 0) intBuffer[i++] else 1)
val args = arrayOf("numInstructions", numInstructions.toString())
Systrace.beginSection(
Systrace.TRACE_TAG_REACT,
"IntBufferBatchMountItem::mountInstructions::" + nameForInstructionString(type),
args,
args.size)
for (k in 0 until numInstructions) {
when (type) {
INSTRUCTION_CREATE -> {
val componentName = (objBuffer[j++] as String?).orEmpty()
val fabricComponentName =
FabricNameComponentMapping.getFabricComponentName(componentName)
surfaceMountingManager.createView(
fabricComponentName,
intBuffer[i++],
objBuffer[j++] as ReadableMap?,
objBuffer[j++] as StateWrapper?,
objBuffer[j++] as EventEmitterWrapper?,
intBuffer[i++] == 1)
}
INSTRUCTION_DELETE -> surfaceMountingManager.deleteView(intBuffer[i++])
INSTRUCTION_INSERT -> {
val tag = intBuffer[i++]
val parentTag = intBuffer[i++]
surfaceMountingManager.addViewAt(parentTag, tag, intBuffer[i++])
}
INSTRUCTION_REMOVE ->
surfaceMountingManager.removeViewAt(intBuffer[i++], intBuffer[i++], intBuffer[i++])
INSTRUCTION_UPDATE_PROPS ->
surfaceMountingManager.updateProps(intBuffer[i++], objBuffer[j++] as ReadableMap?)
INSTRUCTION_UPDATE_STATE ->
surfaceMountingManager.updateState(intBuffer[i++], objBuffer[j++] as StateWrapper?)
INSTRUCTION_UPDATE_LAYOUT -> {
val reactTag = intBuffer[i++]
val parentTag = intBuffer[i++]
val x = intBuffer[i++]
val y = intBuffer[i++]
val width = intBuffer[i++]
val height = intBuffer[i++]
val displayType = intBuffer[i++]
val layoutDirection = intBuffer[i++]
surfaceMountingManager.updateLayout(
reactTag, parentTag, x, y, width, height, displayType, layoutDirection)
}
INSTRUCTION_UPDATE_PADDING ->
surfaceMountingManager.updatePadding(
intBuffer[i++], intBuffer[i++], intBuffer[i++], intBuffer[i++], intBuffer[i++])
INSTRUCTION_UPDATE_OVERFLOW_INSET -> {
val reactTag = intBuffer[i++]
val overflowInsetLeft = intBuffer[i++]
val overflowInsetTop = intBuffer[i++]
val overflowInsetRight = intBuffer[i++]
val overflowInsetBottom = intBuffer[i++]
surfaceMountingManager.updateOverflowInset(
reactTag,
overflowInsetLeft,
overflowInsetTop,
overflowInsetRight,
overflowInsetBottom)
}
INSTRUCTION_UPDATE_EVENT_EMITTER -> {
val eventEmitterWrapper = objBuffer[j++] as EventEmitterWrapper?
if (eventEmitterWrapper != null) {
surfaceMountingManager.updateEventEmitter(intBuffer[i++], eventEmitterWrapper)
}
}
else -> {
throw IllegalArgumentException(
"Invalid type argument to IntBufferBatchMountItem: $type at index: $i")
}
}
}
Systrace.endSection(Systrace.TRACE_TAG_REACT)
}
endMarkers()
}
override fun getSurfaceId(): Int = surfaceId
override fun isBatchEmpty(): Boolean = intBufferLen == 0
override fun toString(): String {
try {
val s = StringBuilder()
s.append(String.format(Locale.ROOT, "IntBufferBatchMountItem [surface:%d]:\n", surfaceId))
var i = 0
var j = 0
while (i < intBufferLen) {
val rawType = intBuffer[i++]
val type = rawType and INSTRUCTION_FLAG_MULTIPLE.inv()
val numInstructions =
(if ((rawType and INSTRUCTION_FLAG_MULTIPLE) != 0) intBuffer[i++] else 1)
for (k in 0 until numInstructions) {
when (type) {
INSTRUCTION_CREATE -> {
val componentName = (objBuffer[j++] as String?).orEmpty()
val fabricComponentName =
FabricNameComponentMapping.getFabricComponentName(componentName)
j += 3
s.append(
String.format(
Locale.ROOT,
"CREATE [%d] - layoutable:%d - %s\n",
intBuffer[i++],
intBuffer[i++],
fabricComponentName))
}
INSTRUCTION_DELETE ->
s.append(String.format(Locale.ROOT, "DELETE [%d]\n", intBuffer[i++]))
INSTRUCTION_INSERT ->
s.append(
String.format(
Locale.ROOT,
"INSERT [%d]->[%d] @%d\n",
intBuffer[i++],
intBuffer[i++],
intBuffer[i++]))
INSTRUCTION_REMOVE ->
s.append(
String.format(
Locale.ROOT,
"REMOVE [%d]->[%d] @%d\n",
intBuffer[i++],
intBuffer[i++],
intBuffer[i++]))
INSTRUCTION_UPDATE_PROPS -> {
val props = objBuffer[j++]
val propsString =
if (FabricUIManager.IS_DEVELOPMENT_ENVIRONMENT) (props?.toString() ?: "<null>")
else "<hidden>"
s.append(
String.format(
Locale.ROOT, "UPDATE PROPS [%d]: %s\n", intBuffer[i++], propsString))
}
INSTRUCTION_UPDATE_STATE -> {
val state: StateWrapper? = objBuffer[j++] as StateWrapper?
val stateString =
if (FabricUIManager.IS_DEVELOPMENT_ENVIRONMENT) (state?.toString() ?: "<null>")
else "<hidden>"
s.append(
String.format(
Locale.ROOT, "UPDATE STATE [%d]: %s\n", intBuffer[i++], stateString))
}
INSTRUCTION_UPDATE_LAYOUT ->
s.append(
String.format(
Locale.ROOT,
"UPDATE LAYOUT [%d]->[%d]: x:%d y:%d w:%d h:%d displayType:%d" +
" layoutDirection:%d\n",
intBuffer[i++],
intBuffer[i++],
intBuffer[i++],
intBuffer[i++],
intBuffer[i++],
intBuffer[i++],
intBuffer[i++],
intBuffer[i++]))
INSTRUCTION_UPDATE_PADDING ->
s.append(
String.format(
Locale.ROOT,
"UPDATE PADDING [%d]: top:%d right:%d bottom:%d left:%d\n",
intBuffer[i++],
intBuffer[i++],
intBuffer[i++],
intBuffer[i++],
intBuffer[i++]))
INSTRUCTION_UPDATE_OVERFLOW_INSET ->
s.append(
String.format(
Locale.ROOT,
"UPDATE OVERFLOWINSET [%d]: left:%d top:%d right:%d bottom:%d\n",
intBuffer[i++],
intBuffer[i++],
intBuffer[i++],
intBuffer[i++],
intBuffer[i++]))
INSTRUCTION_UPDATE_EVENT_EMITTER -> {
j += 1
s.append(String.format(Locale.ROOT, "UPDATE EVENTEMITTER [%d]\n", intBuffer[i++]))
}
else -> {
FLog.e(TAG, "String so far: $s")
throw IllegalArgumentException(
"Invalid type argument to IntBufferBatchMountItem: $type at index: $i")
}
}
}
}
return s.toString()
} catch (e: Exception) {
// Generally, this only happens during development when a malformed buffer is sent through.
// In these cases, we print the buffers to assist in debugging.
// This should never happen in production, but if it does... it'd still be helpful to know.
FLog.e(TAG, "Caught exception trying to print", e)
val ss = StringBuilder()
var ii = 0
while (ii < intBufferLen) {
ss.append(intBuffer[ii])
ss.append(", ")
ii++
}
FLog.e(TAG, ss.toString())
var jj = 0
while (jj < objBufferLen) {
FLog.e(TAG, if (objBuffer[jj] != null) objBuffer[jj].toString() else "null")
jj++
}
return ""
}
}
companion object {
val TAG: String = IntBufferBatchMountItem::class.java.simpleName
const val INSTRUCTION_FLAG_MULTIPLE: Int = 1
const val INSTRUCTION_CREATE: Int = 2
const val INSTRUCTION_DELETE: Int = 4
const val INSTRUCTION_INSERT: Int = 8
const val INSTRUCTION_REMOVE: Int = 16
const val INSTRUCTION_UPDATE_PROPS: Int = 32
const val INSTRUCTION_UPDATE_STATE: Int = 64
const val INSTRUCTION_UPDATE_LAYOUT: Int = 128
const val INSTRUCTION_UPDATE_EVENT_EMITTER: Int = 256
const val INSTRUCTION_UPDATE_PADDING: Int = 512
const val INSTRUCTION_UPDATE_OVERFLOW_INSET: Int = 1024
private fun nameForInstructionString(type: Int): String =
when (type) {
INSTRUCTION_CREATE -> "CREATE"
INSTRUCTION_DELETE -> "DELETE"
INSTRUCTION_INSERT -> "INSERT"
INSTRUCTION_REMOVE -> "REMOVE"
INSTRUCTION_UPDATE_PROPS -> "UPDATE_PROPS"
INSTRUCTION_UPDATE_STATE -> "UPDATE_STATE"
INSTRUCTION_UPDATE_LAYOUT -> "UPDATE_LAYOUT"
INSTRUCTION_UPDATE_PADDING -> "UPDATE_PADDING"
INSTRUCTION_UPDATE_OVERFLOW_INSET -> "UPDATE_OVERFLOW_INSET"
INSTRUCTION_UPDATE_EVENT_EMITTER -> "UPDATE_EVENT_EMITTER"
else -> "UNKNOWN"
}
}
}