• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 *
15 * File: RecyclePoolV2 - Manages the recycling of cached JS objects for component reuse.
16 *
17 * Description: This class handles the caching and recycling of JS components in a pool,
18 * ensuring that components are reused efficiently when needed, and mapping old element IDs
19 * to new ones for recycling purposes.
20 */
21/**
22 * @class RecyclePoolV2
23 * @description Manages cached JS objects of components for recycling.
24 * This class provides methods for pushing, popping, and mapping recycled elements and their new IDs.
25 * It ensures that recycled components are reused when necessary and that element IDs are tracked for mapping
26 */
27class RecyclePoolV2 {
28    // key: recycle element name, value: recycled element JS object
29    private cachedRecycleComponents_: Map<string, Array<ViewV2>> = undefined;
30
31    private recycledIdRegistry_?: RecycledIdRegistry;
32
33    constructor() {
34      this.cachedRecycleComponents_ = new Map<string, Array<ViewV2>>();
35      this.recycledIdRegistry_ = new RecycledIdRegistry();
36    }
37
38    /**
39     * @function pushRecycleV2Component
40     * @description Adds a recycled component (ViewV2) to the pool based on its reuseId.
41     * If the pool does not contain a list for the specified reuseId, it creates one before
42     * adding the component.
43     *
44     * @param {string} reuseId - The id of the component being recycled.
45     * @param {ViewV2} reuseComp - The recycled component to be added to the pool.
46     */
47    public pushRecycleV2Component(reuseId: string, reuseComp: ViewV2): void {
48      if (!this.cachedRecycleComponents_.get(reuseId)) {
49        this.cachedRecycleComponents_.set(reuseId, new Array<ViewV2>());
50      }
51      this.cachedRecycleComponents_.get(reuseId)?.push(reuseComp);
52    }
53
54    /**
55     * @function popRecycleV2Component
56     * @description Retrieves and removes a recycled component (ViewV2) from the pool based on its reuseId.
57     * Returns undefined if no recycled component is found for the specified name.
58     *
59     * @param {string} reuseId - The id of the component being recycled.
60     * @returns {ViewV2 | undefined} - The recycled component, or undefined if not found.
61     */
62    public popRecycleV2Component(reuseId: string): ViewV2 | undefined {
63      return this.cachedRecycleComponents_.get(reuseId)?.pop();
64    }
65
66    /**
67     * @function updateRecycleIdMapping
68     * @description Updates the mapping of the recycledElementId element ID to a new element ID in
69     * the bi-directional map. This ensures that recycled elements are mapped correctly when
70     * their IDs change.
71     *
72     * @param {number} recycledElementId - The ID of the recycled element.
73     * @param {number} newElmtId - The new ID to map the recycled element to.
74     */
75    public updateRecycleIdMapping(recycledElementId: number, newElmtId: number): void {
76      this.recycledIdRegistry_.delete(recycledElementId);
77      this.recycledIdRegistry_.add([recycledElementId, newElmtId]);
78    }
79
80    /**
81     * @function getRecycleIdMapping
82     * @description Retrieves the mapped ID for a recycled element, if available.
83     * If no mapping exists, returns the original element ID.
84     *
85     * @param {number} recycledElementId - The ID of the recycled element.
86     * @returns {number} - The mapped ID or the original ID if no mapping exists.
87     */
88    public getRecycleIdMapping(recycledElementId : number): number {
89      const mappedId = this.recycledIdRegistry_.get(recycledElementId);
90      if (!mappedId) {
91        return recycledElementId;
92      }
93      return mappedId;
94    }
95
96    /**
97     * @function purgeAllCachedRecycleElements
98     * @description
99     * Clears all cached components from the recycle pool by clearing them
100     * from the cached components map. This function is invoked when a parent JS view
101     * is deleted to clean up all recycled components associated with it.
102     *
103     * It in turn calls the native `resetRecycleCustomNode` function to restore the
104     * custom node linked to the JSView object:
105     * - If the JSView object has been garbage collected, the CustomNode is deleted.
106     * - If the JSView object is managed by the RecyclePool, the CustomNode is reused.
107     */
108    public purgeAllCachedRecycleElmtIds(): void {
109      this.cachedRecycleComponents_.forEach((components_, _) => {
110        components_.forEach((node) => {
111          node.resetRecycleCustomNode();
112        });
113      });
114      this.cachedRecycleComponents_.clear();
115    }
116  }
117
118  /**
119   * @class RecycledIdRegistry
120   * @description A helper class that maintains a bi-directional map of recycle element ID with
121   * the new elementID that gets created on every initial render.
122   * This class supports adding, retrieving, and deleting mappings between old and new element IDs
123   *  for recycling purposes.
124   */
125  class RecycledIdRegistry {
126    private fwdMap_: Map<number, number>;
127    private revMap_: Map<number, number>;
128
129    constructor() {
130      this.fwdMap_ = new Map<number, number>();
131      this.revMap_ = new Map<number, number>();
132    }
133
134    /**
135     * @function delete
136     * @description Deletes the mapping for a given element ID from both the
137     * forward and reverse maps.
138     *
139     * @param {number} key - The element ID to be removed from the map.
140     */
141    delete(key: number): void {
142      if (!this.fwdMap_[key]) {
143        return;
144      }
145      const rev = this.fwdMap_[key];
146      this.fwdMap_.delete(key);
147      this.revMap_.delete(rev);
148    }
149
150    /**
151     * @function get
152     * @description Retrieves the mapped ID for a given element ID, either from the
153     * forward or reverse map.
154     *
155     * @param {number} key - The element ID for which the mapped ID is requested.
156     * @returns {number | undefined} - The mapped ID or undefined if no mapping exists.
157     */
158    get(key: number): number | undefined {
159      return this.fwdMap_[key] || this.revMap_[key];
160    }
161
162    /**
163     * @function add
164     * @description Adds a new mapping pair between an old and new element ID to both
165     * the forward and reverse maps.
166     *
167     * @param {Array<number>} pair - A pair of old and new element IDs to be added to the mapping.
168     */
169    add(pair: [number, number]): void {
170      this.fwdMap_[pair[0]] = pair[1];
171      this.revMap_[pair[1]] = pair[0];
172    }
173  }