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 }