1 /* 2 * Copyright (c) 2022 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 16 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_SYNTAX_FOREACH_LAZY_FOR_EACH_BUILDER_H 17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_SYNTAX_FOREACH_LAZY_FOR_EACH_BUILDER_H 18 19 #include <cstdint> 20 #include <list> 21 #include <map> 22 #include <optional> 23 #include <string> 24 #include <unordered_map> 25 #include <unordered_set> 26 #include <utility> 27 28 #include "base/log/ace_trace.h" 29 #include "base/utils/noncopyable.h" 30 #include "base/utils/time_util.h" 31 #include "base/utils/utils.h" 32 #include "core/components_ng/base/frame_node.h" 33 #include "core/components_ng/base/inspector.h" 34 #include "core/components_ng/base/ui_node.h" 35 #include "core/components_v2/foreach/lazy_foreach_component.h" 36 #include "core/pipeline_ng/pipeline_context.h" 37 38 namespace OHOS::Ace::NG { 39 40 typedef struct OperationInfo { OperationInfoOperationInfo41 OperationInfo():node(nullptr) {} 42 int32_t changeCount = 0; 43 int32_t fromDiffTo = 0; 44 std::string key; 45 RefPtr<UINode> node; 46 bool isDeleting = false; 47 bool isChanged = false; 48 bool moveIn = false; 49 bool isExchange = false; 50 std::vector<std::string> extraKey; 51 } OperationInfo; 52 53 using LazyForEachChild = std::pair<std::string, RefPtr<UINode>>; 54 using LazyForEachCacheChild = std::pair<int32_t, RefPtr<UINode>>; 55 56 class ACE_EXPORT LazyForEachBuilder : public virtual AceType { 57 DECLARE_ACE_TYPE(NG::LazyForEachBuilder, AceType); 58 public: 59 LazyForEachBuilder() = default; 60 ~LazyForEachBuilder() override = default; 61 GetTotalCount()62 int32_t GetTotalCount() 63 { 64 return OnGetTotalCount(); 65 } 66 UpdateHistoricalTotalCount(int32_t count)67 void UpdateHistoricalTotalCount(int32_t count) 68 { 69 historicalTotalCount_ = count; 70 } 71 72 int32_t GetTotalCountOfOriginalDataset(); 73 74 std::pair<std::string, RefPtr<UINode>> GetChildByIndex(int32_t index, bool needBuild, bool isCache = false); 75 ExpandChildrenOnInitial()76 void ExpandChildrenOnInitial() 77 { 78 OnExpandChildrenOnInitialInNG(); 79 } 80 81 void OnDataReloaded(); 82 83 bool OnDataAdded(size_t index); 84 85 bool OnDataBulkAdded(size_t index, size_t count); 86 87 RefPtr<UINode> OnDataDeleted(size_t index); 88 89 std::list<std::pair<std::string, RefPtr<UINode>>>& OnDataBulkDeleted(size_t index, size_t count); 90 91 bool OnDataChanged(size_t index); 92 93 std::list<std::pair<std::string, RefPtr<UINode>>>& OnDataBulkChanged(size_t index, size_t count); 94 95 void OnDataMoveToNewPlace(size_t from, size_t to); 96 97 bool OnDataMoved(size_t from, size_t to); 98 99 std::pair<int32_t, std::list<std::pair<std::string, RefPtr<UINode>>>> OnDatasetChange( 100 std::list<V2::Operation> DataOperations); 101 102 void RepairDatasetItems(std::map<int32_t, LazyForEachChild>& cachedTemp, 103 std::map<int32_t, LazyForEachChild>& expiringTempItem_, std::map<int32_t, int32_t>& indexChangedMap); 104 105 void RepairMoveOrExchange(std::map<int32_t, LazyForEachChild>& expiringTempItem_, 106 OperationInfo& info, LazyForEachChild& child, int32_t index, int32_t changedIndex); 107 108 void CollectIndexChangedCount(std::map<int32_t, int32_t>& indexChangedMap); 109 110 bool ClassifyOperation(V2::Operation& operation, int32_t& initialIndex, 111 std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp); 112 113 bool ValidateIndex(int32_t index, const std::string& type); 114 115 void OperateAdd(V2::Operation& operation, int32_t& initialIndex); 116 117 void OperateDelete(V2::Operation& operation, int32_t& initialIndex); 118 119 void OperateMove(V2::Operation& operation, int32_t& initialIndex, 120 std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp); 121 122 void OperateChange(V2::Operation& operation, int32_t& initialIndex, 123 std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp); 124 125 std::map<int32_t, LazyForEachChild>::iterator FindItem(int32_t index, 126 std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp); 127 128 void OperateExchange(V2::Operation& operation, int32_t& initialIndex, 129 std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp); 130 131 void OperateReload(std::map<int32_t, LazyForEachChild>& expiringTemp); 132 133 void ThrowRepeatOperationError(int32_t index); 134 135 void RecordOutOfBoundaryNodes(int32_t index); 136 InvalidIndexOfChangedData(size_t index)137 void InvalidIndexOfChangedData(size_t index) 138 { 139 for (auto& [key, child] : expiringItem_) { 140 if (static_cast<size_t>(child.first) == index) { 141 child.first = -1; 142 break; 143 } 144 } 145 } 146 GetChildByKey(const std::string & key)147 RefPtr<UINode> GetChildByKey(const std::string& key) 148 { 149 return nullptr; 150 } 151 152 void Transit(std::list<std::pair<std::string, RefPtr<UINode>>>& childList); 153 154 std::map<int32_t, LazyForEachChild>& GetItems(std::list<std::pair<std::string, RefPtr<UINode>>>& childList); 155 156 void RemoveAllChild(); 157 158 bool SetActiveChildRange(int32_t start, int32_t end); 159 160 int32_t GetChildIndex(const RefPtr<FrameNode>& targetNode); 161 162 void UpdateMoveFromTo(int32_t from, int32_t to); 163 void ResetMoveFromTo(); 164 int32_t ConvertFromToIndex(int32_t index); 165 SetFlagForGeneratedItem(PropertyChangeFlag propertyChangeFlag)166 void SetFlagForGeneratedItem(PropertyChangeFlag propertyChangeFlag) 167 { 168 for (const auto& item : cachedItems_) { 169 if (!item.second.second) { 170 continue; 171 } 172 item.second.second->ForceUpdateLayoutPropertyFlag(propertyChangeFlag); 173 } 174 } 175 176 RefPtr<UINode> CacheItem(int32_t index, std::unordered_map<std::string, LazyForEachCacheChild>& cache, 177 const std::optional<LayoutConstraintF>& itemConstraint, int64_t deadline, bool& isTimeout); 178 179 void CheckCacheIndex(std::set<int32_t>& idleIndexes, int32_t count); 180 181 bool PreBuildByIndex(int32_t index, std::unordered_map<std::string, LazyForEachCacheChild>& cache, 182 int64_t deadline, const std::optional<LayoutConstraintF>& itemConstraint, bool canRunLongPredictTask); 183 ProcessPreBuildingIndex(std::unordered_map<std::string,LazyForEachCacheChild> & cache,int64_t deadline,const std::optional<LayoutConstraintF> & itemConstraint,bool canRunLongPredictTask,std::set<int32_t> & idleIndexes)184 bool ProcessPreBuildingIndex(std::unordered_map<std::string, LazyForEachCacheChild>& cache, int64_t deadline, 185 const std::optional<LayoutConstraintF>& itemConstraint, bool canRunLongPredictTask, 186 std::set<int32_t>& idleIndexes) 187 { 188 if (idleIndexes.find(preBuildingIndex_) == idleIndexes.end()) { 189 preBuildingIndex_ = -1; 190 return true; 191 } 192 idleIndexes.erase(preBuildingIndex_); 193 return PreBuildByIndex(preBuildingIndex_, cache, deadline, itemConstraint, canRunLongPredictTask); 194 } 195 196 bool PreBuild(int64_t deadline, const std::optional<LayoutConstraintF>& itemConstraint, bool canRunLongPredictTask); 197 198 void ProcessCachedIndex(std::unordered_map<std::string, LazyForEachCacheChild>& cache, 199 std::set<int32_t>& idleIndexes); 200 LoadCacheByIndex(std::unordered_map<std::string,LazyForEachCacheChild> & cache,std::set<int32_t> & idleIndexes,const LazyForEachCacheChild & node,const std::string & key,const std::set<int32_t>::iterator & iter,std::unordered_map<std::string,LazyForEachCacheChild>::iterator & expiringIter)201 void LoadCacheByIndex(std::unordered_map<std::string, LazyForEachCacheChild>& cache, std::set<int32_t>& idleIndexes, 202 const LazyForEachCacheChild& node, const std::string& key, const std::set<int32_t>::iterator& iter, 203 std::unordered_map<std::string, LazyForEachCacheChild>::iterator& expiringIter) 204 { 205 ProcessOffscreenNode(node.second, false); 206 207 if (node.first == preBuildingIndex_) { 208 cache.try_emplace(key, node); 209 } else { 210 cache.try_emplace(key, std::move(node)); 211 cachedItems_.try_emplace(node.first, LazyForEachChild(key, nullptr)); 212 idleIndexes.erase(iter); 213 } 214 215 expiringIter++; 216 } 217 LoadCacheByKey(std::unordered_map<std::string,LazyForEachCacheChild> & cache,std::set<int32_t> & idleIndexes,const LazyForEachCacheChild & node,const std::string & key,std::unordered_map<std::string,LazyForEachCacheChild>::iterator & expiringIter)218 void LoadCacheByKey(std::unordered_map<std::string, LazyForEachCacheChild>& cache, std::set<int32_t>& idleIndexes, 219 const LazyForEachCacheChild& node, const std::string& key, 220 std::unordered_map<std::string, LazyForEachCacheChild>::iterator& expiringIter) 221 { 222 NotifyDataDeleted(node.second, static_cast<size_t>(node.first), true); 223 ProcessOffscreenNode(node.second, true); 224 NotifyItemDeleted(RawPtr(node.second), key); 225 226 if (node.second) { 227 node.second->DetachFromMainTree(); 228 } 229 if (DeleteExpiringItemImmediately()) { 230 expiringIter = expiringItem_.erase(expiringIter); 231 } else { 232 expiringIter++; 233 } 234 } 235 236 void ProcessOffscreenNode(RefPtr<UINode> uiNode, bool remove); 237 ClearAllOffscreenNode()238 void ClearAllOffscreenNode() 239 { 240 for (auto& [key, node] : expiringItem_) { 241 ProcessOffscreenNode(node.second, true); 242 } 243 for (auto& [key, node] : cachedItems_) { 244 ProcessOffscreenNode(node.second, true); 245 } 246 } 247 248 virtual void ReleaseChildGroupById(const std::string& id) = 0; 249 250 virtual void RegisterDataChangeListener(const RefPtr<V2::DataChangeListener>& listener) = 0; 251 252 virtual void UnregisterDataChangeListener(V2::DataChangeListener* listener) = 0; 253 SetCacheCount(int32_t cacheCount)254 void SetCacheCount(int32_t cacheCount) 255 { 256 cacheCount_ = cacheCount; 257 } 258 SetIsLoop(bool isLoop)259 void SetIsLoop(bool isLoop) 260 { 261 isLoop_ = isLoop; 262 } 263 clearDeletedNodes()264 void clearDeletedNodes() 265 { 266 nodeList_.clear(); 267 } 268 SetUseNewInterface(bool useNewInterface)269 void SetUseNewInterface(bool useNewInterface) 270 { 271 useNewInterface_ = useNewInterface; 272 } 273 GetCachedUINodeMap()274 const std::unordered_map<std::string, LazyForEachCacheChild>& GetCachedUINodeMap() 275 { 276 return expiringItem_; 277 } 278 279 const std::map<int32_t, LazyForEachChild>& GetAllChildren(); 280 281 void SetJSViewActive(bool active); 282 283 void PaintDebugBoundaryTreeAll(bool flag); 284 NotifyItemDeleted(UINode * node,const std::string & key)285 void NotifyItemDeleted(UINode* node, const std::string& key) 286 { 287 OnItemDeleted(node, key); 288 } 289 290 void GetAllItems(std::vector<UINode*>& items); 291 SetShowCached(int32_t start,int32_t end)292 void SetShowCached(int32_t start, int32_t end) 293 { 294 startShowCached_ = start; 295 endShowCached_ = end; 296 } 297 GetHistoryTotalCount()298 int32_t GetHistoryTotalCount() const 299 { 300 return historicalTotalCount_; 301 } 302 303 void SetDestroying(bool isDestroying, bool cleanStatus); 304 void NotifyColorModeChange(uint32_t colorMode, bool rerenderable); 305 EnablePreBuild(bool enable)306 void EnablePreBuild(bool enable) 307 { 308 enablePreBuild_ = enable; 309 } 310 311 protected: 312 virtual int32_t OnGetTotalCount() = 0; 313 OnItemDeleted(UINode * node,const std::string & key)314 virtual void OnItemDeleted(UINode* node, const std::string& key) {}; 315 DeleteExpiringItemImmediately()316 virtual bool DeleteExpiringItemImmediately() 317 { 318 return false; 319 } 320 321 virtual LazyForEachChild OnGetChildByIndex( 322 int32_t index, std::unordered_map<std::string, LazyForEachCacheChild>& cachedItems) = 0; 323 324 virtual LazyForEachChild OnGetChildByIndexNew(int32_t index, 325 std::map<int32_t, LazyForEachChild>& cachedItems, 326 std::unordered_map<std::string, LazyForEachCacheChild>& expiringItems) = 0; 327 328 virtual void OnExpandChildrenOnInitialInNG() = 0; 329 330 virtual void NotifyDataChanged(size_t index, const RefPtr<UINode>& lazyForEachNode, bool isRebuild = true) = 0; 331 332 virtual void NotifyDataDeleted(const RefPtr<UINode>& lazyForEachNode, size_t index, bool removeIds) = 0; 333 334 virtual void NotifyDataAdded(size_t index) = 0; 335 336 virtual void KeepRemovedItemInCache(NG::LazyForEachChild node, 337 std::unordered_map<std::string, NG::LazyForEachCacheChild>& cachedItems) = 0; 338 339 private: 340 void RecycleItemsOutOfBoundary(); 341 void RecycleChildByIndex(int32_t index); 342 343 std::map<int32_t, LazyForEachChild> cachedItems_; 344 std::unordered_map<std::string, LazyForEachCacheChild> expiringItem_; 345 std::list<std::pair<std::string, RefPtr<UINode>>> nodeList_; 346 std::map<int32_t, OperationInfo> operationList_; 347 enum class OP { ADD, DEL, CHANGE, MOVE, EXCHANGE, RELOAD }; 348 std::map<std::string, OP> operationTypeMap = {{"add", OP::ADD}, 349 {"delete", OP::DEL}, 350 {"change", OP::CHANGE}, 351 {"move", OP::MOVE}, 352 {"exchange", OP::EXCHANGE}, 353 {"reload", OP::RELOAD}}; 354 std::list<int32_t> outOfBoundaryNodes_; 355 std::optional<std::pair<int32_t, int32_t>> moveFromTo_; 356 357 int32_t startIndex_ = -1; 358 int32_t endIndex_ = -1; 359 int32_t cacheCount_ = 0; 360 int32_t startShowCached_ = 0; 361 int32_t endShowCached_ = 0; 362 int32_t preBuildingIndex_ = -1; 363 int32_t totalCountOfOriginalDataset_ = 0; 364 int32_t historicalTotalCount_ = 0; 365 bool needTransition = false; 366 bool isLoop_ = false; 367 bool useNewInterface_ = false; 368 bool enablePreBuild_ = true; 369 ACE_DISALLOW_COPY_AND_MOVE(LazyForEachBuilder); 370 }; 371 } // namespace OHOS::Ace::NG 372 373 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_SYNTAX_FOREACH_LAZY_FOR_EACH_BUILDER_H 374