/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.litho;
import java.util.ArrayDeque;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Resources;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.util.SparseArrayCompat;
import android.util.SparseArray;
import com.facebook.litho.config.ComponentsConfiguration;
import com.facebook.litho.displaylist.DisplayList;
import com.facebook.infer.annotation.ThreadSafe;
import com.facebook.litho.internal.ArraySet;
import com.facebook.yoga.YogaConfig;
import com.facebook.yoga.YogaDirection;
import com.facebook.yoga.YogaExperimentalFeature;
import com.facebook.yoga.YogaNode;
import static android.support.v4.view.ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
/**
* Pools of recycled resources.
*
* FUTURE: Consider customizing the pool implementation such that we can match buffer sizes. Without
* this we will tend to expand all buffers to the largest size needed.
*/
public class ComponentsPools {
private static final int SCRAP_ARRAY_INITIAL_SIZE = 4;
private static YogaConfig sYogaConfig;
private ComponentsPools() {
}
// FUTURE: tune pool max sizes
private static final Object mountContentLock = new Object();
static final RecyclePool<LayoutState> sLayoutStatePool =
new RecyclePool<>("LayoutState", 64, true);
static final RecyclePool<InternalNode> sInternalNodePool =
new RecyclePool<>("InternalNode", 256, true);
static final RecyclePool<NodeInfo> sNodeInfoPool =
new RecyclePool<>("NodeInfo", 256, true);
static final RecyclePool<ViewNodeInfo> sViewNodeInfoPool =
new RecyclePool<>("ViewNodeInfo", 64, true);
static final RecyclePool<YogaNode> sYogaNodePool =
new RecyclePool<>("YogaNode", 256, true);
static final RecyclePool<MountItem> sMountItemPool =
new RecyclePool<>("MountItem", 256, true);
static final Map<Context, SparseArray<RecyclePool>> sMountContentPoolsByContext =
new ConcurrentHashMap<>(4);
static final RecyclePool<LayoutOutput> sLayoutOutputPool =
new RecyclePool<>("LayoutOutput", 256, true);
static final RecyclePool<VisibilityOutput> sVisibilityOutputPool =
new RecyclePool<>("VisibilityOutput", 64, true);
// These are lazily initialized as they are only needed when we're in a test environment.
static RecyclePool<TestOutput> sTestOutputPool = null;
static RecyclePool<TestItem> sTestItemPool = null;
static final RecyclePool<VisibilityItem> sVisibilityItemPool =
new RecyclePool<>("VisibilityItem", 64, true);
static final RecyclePool<Output<?>> sOutputPool =
new RecyclePool<>("Output", 20, true);
static final RecyclePool<DiffNode> sDiffNodePool =
new RecyclePool<>("DiffNode", 256, true);
static final RecyclePool<Diff<?>> sDiffPool =
new RecyclePool<>("Diff", 20, true);
static final RecyclePool<ComponentTree.Builder> sComponentTreeBuilderPool =
new RecyclePool<>("ComponentTree.Builder", 2, true);
static final RecyclePool<StateHandler> sStateHandlerPool =
new RecyclePool<>("StateHandler", 10, true);
static final RecyclePool<SparseArrayCompat<MountItem>> sMountItemScrapArrayPool =
new RecyclePool<>("MountItemScrapArray", 8, false);
static final RecyclePool<SparseArrayCompat<Touchable>> sTouchableScrapArrayPool =
new RecyclePool<>("TouchableScrapArray", 4, false);
static final RecyclePool<RectF> sRectFPool =
new RecyclePool<>("RectF", 4, true);
static final RecyclePool<Rect> sRectPool =
new RecyclePool<>("Rect", 30, true);
static final RecyclePool<Edges> sEdgesPool =
new RecyclePool<>("Edges", 30, true);
static final RecyclePool<TransitionContext> sTransitionContextPool =
new RecyclePool<>("TransitionContext", 2, true);
static final RecyclePool<DisplayListDrawable> sDisplayListDrawablePool =
new RecyclePool<>("DisplayListDrawable", 10, false);
static final RecyclePool<TreeProps> sTreePropsMapPool =
new RecyclePool<>("TreeProps", 10, true);
static final RecyclePool<ArraySet> sArraySetPool =
new RecyclePool<>("ArraySet", 10, true);
static final RecyclePool<ArrayDeque> sArrayDequePool =
new RecyclePool<>("ArrayDeque", 10, true);
static final RecyclePool<LogEvent> sLogEventPool =
new RecyclePool<>("LogEvent", 10, true);
// Lazily initialized when acquired first time, as this is not a common use case.
static RecyclePool<BorderColorDrawable> sBorderColorDrawablePool = null;
private static PoolsActivityCallback sActivityCallbacks;
/**
* To support Gingerbread (where the registerActivityLifecycleCallbacks API
* doesn't exist), we allow apps to explicitly invoke activity callbacks. If
* this is enabled we'll throw if we are passed a context for which we have
* no record.
*/
static boolean sIsManualCallbacks;
static LayoutState acquireLayoutState(ComponentContext context) {
LayoutState state = ComponentsConfiguration.usePooling ? sLayoutStatePool.acquire() : null;
if (state == null) {
state = new LayoutState();
}
state.init(context);
return state;
}
static synchronized YogaNode acquireYogaNode(ComponentContext c) {
if (sYogaConfig == null) {
sYogaConfig = new YogaConfig();
sYogaConfig.setUseWebDefaults(true);
sYogaConfig.setUseLegacyStretchBehaviour(true);
}
if (sYogaConfig.getLogger() != ComponentsConfiguration.YOGA_LOGGER) {
sYogaConfig.setLogger(ComponentsConfiguration.YOGA_LOGGER);
}
YogaNode node = ComponentsConfiguration.usePooling ? sYogaNodePool.acquire() : null;
if (node == null) {
node = new YogaNode(sYogaConfig);
}
return node;
}
static synchronized InternalNode acquireInternalNode(
ComponentContext componentContext,
Resources resources) {
InternalNode node = ComponentsConfiguration.usePooling ? sInternalNodePool.acquire() : null;
if (node == null) {
node = new InternalNode();
}
node.init(acquireYogaNode(componentContext), componentContext, resources);
return node;
}
static synchronized NodeInfo acquireNodeInfo() {
NodeInfo nodeInfo = ComponentsConfiguration.usePooling ? sNodeInfoPool.acquire() : null;
if (nodeInfo == null) {
nodeInfo = new NodeInfo();
}
return nodeInfo;
}
static synchronized ViewNodeInfo acquireViewNodeInfo() {
ViewNodeInfo viewNodeInfo =
ComponentsConfiguration.usePooling ? sViewNodeInfoPool.acquire() : null;
if (viewNodeInfo == null) {
viewNodeInfo = new ViewNodeInfo();
}
return viewNodeInfo;
}
static MountItem acquireRootHostMountItem(
Component<?> component,
ComponentHost host,
Object content) {
MountItem item = ComponentsConfiguration.usePooling ? sMountItemPool.acquire() : null;
if (item == null) {
item = new MountItem();
}
final ViewNodeInfo viewNodeInfo = ViewNodeInfo.acquire();
viewNodeInfo.setLayoutDirection(YogaDirection.INHERIT);
item.init(
component,
host,
content,
null,
viewNodeInfo,
null,
0,
IMPORTANT_FOR_ACCESSIBILITY_AUTO);
return item;
}
static MountItem acquireMountItem(
Component<?> component,
ComponentHost host,
Object content,
LayoutOutput layoutOutput) {
MountItem item = ComponentsConfiguration.usePooling ? sMountItemPool.acquire() : null;
if (item == null) {
item = new MountItem();
}
item.init(component, host, content, layoutOutput, null);
return item;
}
static Object acquireMountContent(Context context, int componentId) {
if (context instanceof ComponentContext) {
context = ((ComponentContext) context).getBaseContext();
if (context instanceof ComponentContext) {
throw new IllegalStateException("Double wrapped ComponentContext.");
}
}
final RecyclePool<Object> pool;
synchronized (mountContentLock) {
if (sActivityCallbacks == null && !sIsManualCallbacks) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
throw new RuntimeException(
"Activity callbacks must be invoked manually below ICS (API level 14)");
}
sActivityCallbacks = new PoolsActivityCallback();
((Application) context.getApplicationContext())
.registerActivityLifecycleCallbacks(sActivityCallbacks);
}
SparseArray<RecyclePool> poolsArray =
sMountContentPoolsByContext.get(context);
if (poolsArray == null) {
// The context is created here because we are sure the Activity is alive at this point in
// contrast of the release call where the Activity might by gone.
sMountContentPoolsByContext.put(context, new SparseArray<RecyclePool>());
return null;
}
pool = poolsArray.get(componentId);
if (pool == null) {
return null;
}
}
return pool.acquire();
}
static LayoutOutput acquireLayoutOutput() {
LayoutOutput output = ComponentsConfiguration.usePooling ? sLayoutOutputPool.acquire() : null;
if (output == null) {
output = new LayoutOutput();
}
return output;
}
static VisibilityOutput acquireVisibilityOutput() {
VisibilityOutput output =
ComponentsConfiguration.usePooling ? sVisibilityOutputPool.acquire() : null;
if (output == null) {
output = new VisibilityOutput();
}
return output;
}
static VisibilityItem acquireVisibilityItem(
EventHandler<InvisibleEvent> invisibleHandler,
EventHandler<UnfocusedVisibleEvent> unfocusedHandler) {
VisibilityItem item = ComponentsConfiguration.usePooling ? sVisibilityItemPool.acquire() : null;
if (item == null) {
item = new VisibilityItem();
}
item.setInvisibleHandler(invisibleHandler);
item.setUnfocusedHandler(unfocusedHandler);
return item;
}
static TestOutput acquireTestOutput() {
if (sTestOutputPool == null) {
sTestOutputPool = new RecyclePool<>("TestOutput", 64, true);
}
TestOutput output = ComponentsConfiguration.usePooling ? sTestOutputPool.acquire() : null;
if (output == null) {
output = new TestOutput();
}
return output;
}
static TestItem acquireTestItem() {
if (sTestItemPool == null) {
sTestItemPool = new RecyclePool<>("TestItem", 64, true);
}
TestItem item = ComponentsConfiguration.usePooling ? sTestItemPool.acquire() : null;
if (item == null) {
item = new TestItem();
}
return item;
}
static Output acquireOutput() {
Output output = ComponentsConfiguration.usePooling ? sOutputPool.acquire() : null;
if (output == null) {
output = new Output();
}
return output;
}
static DiffNode acquireDiffNode() {
DiffNode node = ComponentsConfiguration.usePooling ? sDiffNodePool.acquire() : null;
if (node == null) {
node = new DiffNode();
}
return node;
}
public static <T> Diff acquireDiff(T previous, T next) {
Diff diff = ComponentsConfiguration.usePooling ? sDiffPool.acquire() : null;
if (diff == null) {
diff = new Diff();
}
diff.init(previous, next);
return diff;
}
static ComponentTree.Builder acquireComponentTreeBuilder(ComponentContext c, Component<?> root) {
ComponentTree.Builder componentTreeBuilder =
ComponentsConfiguration.usePooling ? sComponentTreeBuilderPool.acquire() : null;
if (componentTreeBuilder == null) {
componentTreeBuilder = new ComponentTree.Builder();
}
componentTreeBuilder.init(c, root);
return componentTreeBuilder;
}
static StateHandler acquireStateHandler(StateHandler fromStateHandler) {
StateHandler stateHandler =
ComponentsConfiguration.usePooling ? sStateHandlerPool.acquire() : null;
if (stateHandler == null) {
stateHandler = new StateHandler();
}
stateHandler.init(fromStateHandler);
return stateHandler;
}
static StateHandler acquireStateHandler() {
return acquireStateHandler(null);
}
static TransitionContext acquireTransitionContext() {
TransitionContext transitionContext =
ComponentsConfiguration.usePooling ? sTransitionContextPool.acquire() : null;
if (transitionContext == null) {
transitionContext = new TransitionContext();
}
return transitionContext;
}
public static TreeProps acquireTreeProps() {
TreeProps treeProps = ComponentsConfiguration.usePooling ? sTreePropsMapPool.acquire() : null;
if (treeProps == null) {
treeProps = new TreeProps();
}
return treeProps;
}
public static LogEvent acquireLogEvent(int eventId) {
LogEvent event = ComponentsConfiguration.usePooling ? sLogEventPool.acquire() : null;
if (event == null) {
event = new LogEvent();
}
event.setEventId(eventId);
return event;
}
//TODO t16407516 shb: change all "enableChecks = false" here to @TakesOwnership
@ThreadSafe(enableChecks = false)
public static void release(TreeProps treeProps) {
if (!ComponentsConfiguration.usePooling) {
return;
}
treeProps.reset();
sTreePropsMapPool.release(treeProps);
}
@ThreadSafe(enableChecks = false)
static void release(TransitionContext transitionContext) {
if (!ComponentsConfiguration.usePooling) {
return;
}
transitionContext.reset();
sTransitionContextPool.release(transitionContext);
}
@ThreadSafe(enableChecks = false)
static void release(ComponentTree.Builder componentTreeBuilder) {
if (!ComponentsConfiguration.usePooling) {
return;
}
componentTreeBuilder.release();
sComponentTreeBuilderPool.release(componentTreeBuilder);
}
@ThreadSafe(enableChecks = false)
static void release(StateHandler stateHandler) {
if (!ComponentsConfiguration.usePooling) {
return;
}
stateHandler.release();
sStateHandlerPool.release(stateHandler);
}
@ThreadSafe(enableChecks = false)
static void release(LayoutState state) {
if (!ComponentsConfiguration.usePooling) {
return;
}
sLayoutStatePool.release(state);
}
@ThreadSafe(enableChecks = false)
static void release(YogaNode node) {
if (!ComponentsConfiguration.usePooling) {
return;
}
node.reset();
sYogaNodePool.release(node);
}
@ThreadSafe(enableChecks = false)
static void release(InternalNode node) {
if (!ComponentsConfiguration.usePooling) {
return;
}
node.release();
sInternalNodePool.release(node);
}
@ThreadSafe(enableChecks = false)
static void release(NodeInfo nodeInfo) {
if (!ComponentsConfiguration.usePooling) {
return;
}
sNodeInfoPool.release(nodeInfo);
}
@ThreadSafe(enableChecks = false)
static void release(ViewNodeInfo viewNodeInfo) {
if (!ComponentsConfiguration.usePooling) {
return;
}
sViewNodeInfoPool.release(viewNodeInfo);
}
@ThreadSafe(enableChecks = false)
static void release(Context context, MountItem item) {
if (!ComponentsConfiguration.usePooling) {
return;
}
item.release(context);
sMountItemPool.release(item);
}
@ThreadSafe(enableChecks = false)
static void release(LayoutOutput output) {
if (!ComponentsConfiguration.usePooling) {
return;
}
output.release();
sLayoutOutputPool.release(output);
}
@ThreadSafe(enableChecks = false)
static void release(VisibilityOutput output) {
if (!ComponentsConfiguration.usePooling) {
return;
}
output.release();
sVisibilityOutputPool.release(output);
}
@ThreadSafe(enableChecks = false)
static void release(VisibilityItem item) {
if (!ComponentsConfiguration.usePooling) {
return;
}
item.release();
sVisibilityItemPool.release(item);
}
@ThreadSafe(enableChecks = false)
static void release(TestOutput testOutput) {
if (!ComponentsConfiguration.usePooling) {
return;
}
testOutput.release();
sTestOutputPool.release(testOutput);
}
@ThreadSafe(enableChecks = false)
static void release(TestItem testItem) {
if (!ComponentsConfiguration.usePooling) {
return;
}
testItem.release();
sTestItemPool.release(testItem);
}
@ThreadSafe(enableChecks = false)
static void release(DiffNode node) {
if (!ComponentsConfiguration.usePooling) {
return;
}
node.release();
sDiffNodePool.release(node);
}
@ThreadSafe(enableChecks = false)
static void release(Output output) {
if (!ComponentsConfiguration.usePooling) {
return;
}
output.release();
sOutputPool.release(output);
}
@ThreadSafe(enableChecks = false)
public static void release(Diff diff) {
if (!ComponentsConfiguration.usePooling) {
return;
}
diff.release();
sDiffPool.release(diff);
}
@ThreadSafe(enableChecks = false)
static void release(Context context, ComponentLifecycle lifecycle, Object mountContent) {
if (context instanceof ComponentContext) {
context = ((ComponentContext) context).getBaseContext();
if (context instanceof ComponentContext) {
throw new IllegalStateException("Double wrapped ComponentContext.");
}
}
RecyclePool pool = null;
synchronized (mountContentLock) {
SparseArray<RecyclePool> poolsArray =
sMountContentPoolsByContext.get(context);
if (poolsArray != null) {
pool = poolsArray.get(lifecycle.getId());
if (pool == null) {
pool = new RecyclePool(
"MountContent - " + lifecycle.getClass().getSimpleName(),
lifecycle.poolSize(),
true);
poolsArray.put(lifecycle.getId(), pool);
}
}
if (pool != null) {
pool.release(mountContent);
}
}
}
static boolean canAddMountContentToPool(Context context, ComponentLifecycle lifecycle) {
if (lifecycle.poolSize() == 0) {
return false;
}
final SparseArray<RecyclePool> poolsArray =
sMountContentPoolsByContext.get(context);
if (poolsArray == null) {
return true;
}
final RecyclePool pool = poolsArray.get(lifecycle.getId());
return pool == null || !pool.isFull();
}
static SparseArrayCompat<MountItem> acquireScrapMountItemsArray() {
SparseArrayCompat<MountItem> sparseArray =
ComponentsConfiguration.usePooling ? sMountItemScrapArrayPool.acquire() : null;
if (sparseArray == null) {
sparseArray = new SparseArrayCompat<>(SCRAP_ARRAY_INITIAL_SIZE);
}
return sparseArray;
}
@ThreadSafe(enableChecks = false)
static void releaseScrapMountItemsArray(SparseArrayCompat<MountItem> sparseArray) {
if (!ComponentsConfiguration.usePooling) {
return;
}
sMountItemScrapArrayPool.release(sparseArray);
}
static SparseArrayCompat<Touchable> acquireScrapTouchablesArray() {
SparseArrayCompat<Touchable> sparseArray =
ComponentsConfiguration.usePooling ? sTouchableScrapArrayPool.acquire() : null;
if (sparseArray == null) {
sparseArray = new SparseArrayCompat<>(SCRAP_ARRAY_INITIAL_SIZE);
}
return sparseArray;
}
@ThreadSafe(enableChecks = false)
static void releaseScrapTouchablesArray(SparseArrayCompat<Touchable> sparseArray) {
if (!ComponentsConfiguration.usePooling) {
return;
}
sTouchableScrapArrayPool.release(sparseArray);
}
static RectF acquireRectF() {
RectF rect = ComponentsConfiguration.usePooling ? sRectFPool.acquire() : null;
if (rect == null) {
rect = new RectF();
}
return rect;
}
@ThreadSafe(enableChecks = false)
static void releaseRectF(RectF rect) {
if (!ComponentsConfiguration.usePooling) {
return;
}
rect.setEmpty();
sRectFPool.release(rect);
}
static Rect acquireRect() {
Rect rect = ComponentsConfiguration.usePooling ? sRectPool.acquire() : null;
if (rect == null) {
rect = new Rect();
}
return rect;
}
@ThreadSafe(enableChecks = false)
static void release(Rect rect) {
if (!ComponentsConfiguration.usePooling) {
return;
}
rect.setEmpty();
sRectPool.release(rect);
}
static Edges acquireEdges() {
Edges spacing = ComponentsConfiguration.usePooling ? sEdgesPool.acquire() : null;
if (spacing == null) {
spacing = new Edges();
}
return spacing;
}
@ThreadSafe(enableChecks = false)
static void release(Edges edges) {
if (!ComponentsConfiguration.usePooling) {
return;
}
edges.reset();
sEdgesPool.release(edges);
}
/**
* Empty implementation of the {@link Application.ActivityLifecycleCallbacks} interface
*/
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
private static class PoolsActivityCallback
implements Application.ActivityLifecycleCallbacks {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
ComponentsPools.onContextCreated(activity);
}
@Override
public void onActivityStarted(Activity activity) {
// Do nothing.
}
@Override
public void onActivityResumed(Activity activity) {
// Do nothing.
}
@Override
public void onActivityPaused(Activity activity) {
// Do nothing.
}
@Override
public void onActivityStopped(Activity activity) {
// Do nothing.
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
// Do nothing.
}
@Override
public void onActivityDestroyed(Activity activity) {
ComponentsPools.onContextDestroyed(activity);
}
}
static void onContextCreated(Context context) {
if (sMountContentPoolsByContext.containsKey(context)) {
throw new IllegalStateException("The MountContentPools has a reference to an activity" +
"that has just been created");
}
}
static void onContextDestroyed(Context context) {
sMountContentPoolsByContext.remove(context);
// Clear any context wrappers holding a reference to this activity.
final Iterator<Map.Entry<Context, SparseArray<RecyclePool>>> it =
sMountContentPoolsByContext.entrySet().iterator();
while (it.hasNext()) {
final Context contextKey = it.next().getKey();
if (isContextWrapper(contextKey, context)) {
it.remove();
}
}
}
/**
* Call from tests to clear external references.
*/
public static void clearAll() {
sMountContentPoolsByContext.clear();
}
/**
* Check whether contextWrapper is a wrapper of baseContext
*/
private static boolean isContextWrapper(Context contextWrapper, Context baseContext) {
Context currentContext = contextWrapper;
while (currentContext instanceof ContextWrapper) {
currentContext = ((ContextWrapper) currentContext).getBaseContext();
if (currentContext == baseContext) {
return true;
}
}
return false;
}
public static DisplayListDrawable acquireDisplayListDrawable(
Drawable content,
DisplayList displayList) {
// When we are wrapping drawable with DisplayListDrawable we need to make sure that
// wrapped DisplayListDrawable has the same view callback as original one had for correct
// view invalidations.
final Drawable.Callback callback = content.getCallback();
DisplayListDrawable displayListDrawable =
ComponentsConfiguration.usePooling ? sDisplayListDrawablePool.acquire() : null;
if (displayListDrawable == null) {
displayListDrawable = new DisplayListDrawable(content, displayList);
} else {
displayListDrawable.setWrappedDrawable(content, displayList);
}
displayListDrawable.setCallback(callback);
return displayListDrawable;
}
@ThreadSafe(enableChecks = false)
public static void release(DisplayListDrawable displayListDrawable) {
if (!ComponentsConfiguration.usePooling) {
return;
}
displayListDrawable.release();
sDisplayListDrawablePool.release(displayListDrawable);
}
public static BorderColorDrawable acquireBorderColorDrawable() {
if (sBorderColorDrawablePool == null) {
sBorderColorDrawablePool = new RecyclePool<>("BorderColorDrawable", 10, true);
}
BorderColorDrawable drawable =
ComponentsConfiguration.usePooling ? sBorderColorDrawablePool.acquire() : null;
if (drawable == null) {
drawable = new BorderColorDrawable();
}
return drawable;
}
@ThreadSafe(enableChecks = false)
public static void release(BorderColorDrawable borderColorDrawable) {
if (!ComponentsConfiguration.usePooling) {
return;
}
sBorderColorDrawablePool.release(borderColorDrawable);
}
public static <E> ArraySet<E> acquireArraySet() {
ArraySet<E> set = ComponentsConfiguration.usePooling ? sArraySetPool.acquire() : null;
if (set == null) {
set = new ArraySet<>();
}
return set;
}
@ThreadSafe(enableChecks = false)
public static void release(ArraySet set) {
if (!ComponentsConfiguration.usePooling) {
return;
}
set.clear();
sArraySetPool.release(set);
}
public static <E> ArrayDeque<E> acquireArrayDeque() {
ArrayDeque<E> deque = ComponentsConfiguration.usePooling ? sArrayDequePool.acquire() : null;
if (deque == null) {
deque = new ArrayDeque<>();
}
return deque;
}
@ThreadSafe(enableChecks = false)
public static void release(ArrayDeque deque) {
if (!ComponentsConfiguration.usePooling) {
return;
}
deque.clear();
sArrayDequePool.release(deque);
}
@ThreadSafe(enableChecks = false)
public static void release(LogEvent event) {
if (!ComponentsConfiguration.usePooling) {
return;
}
event.reset();
sLogEventPool.release(event);
}
}