• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
67     int32_t GetTotalCountOfOriginalDataset(const std::list<V2::Operation>& DataOperations);
68 
69     std::pair<std::string, RefPtr<UINode>> GetChildByIndex(int32_t index, bool needBuild, bool isCache = false);
70 
ExpandChildrenOnInitial()71     void ExpandChildrenOnInitial()
72     {
73         OnExpandChildrenOnInitialInNG();
74     }
75 
76     void OnDataReloaded();
77 
78     bool OnDataAdded(size_t index);
79 
80     bool OnDataBulkAdded(size_t index, size_t count);
81 
82     RefPtr<UINode> OnDataDeleted(size_t index);
83 
84     std::list<std::pair<std::string, RefPtr<UINode>>>& OnDataBulkDeleted(size_t index, size_t count);
85 
86     bool OnDataChanged(size_t index);
87 
88     std::list<std::pair<std::string, RefPtr<UINode>>>& OnDataBulkChanged(size_t index, size_t count);
89 
90     void OnDataMoveToNewPlace(size_t from, size_t to);
91 
92     bool OnDataMoved(size_t from, size_t to);
93 
94     std::pair<int32_t, std::list<RefPtr<UINode>>> OnDatasetChange(std::list<V2::Operation> DataOperations);
95 
96     void RepairDatasetItems(std::map<int32_t, LazyForEachChild>& cachedTemp,
97         std::map<int32_t, LazyForEachChild>& expiringTempItem_, std::map<int32_t, int32_t>& indexChangedMap);
98 
99     void RepairMoveOrExchange(std::map<int32_t, LazyForEachChild>& expiringTempItem_,
100         OperationInfo& info, LazyForEachChild& child, int32_t index, int32_t changedIndex);
101 
102     void CollectIndexChangedCount(std::map<int32_t, int32_t>& indexChangedMap);
103 
104     bool ClassifyOperation(V2::Operation& operation, int32_t& initialIndex,
105         std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp);
106 
107     bool ValidateIndex(int32_t index, const std::string& type);
108 
109     void OperateAdd(V2::Operation& operation, int32_t& initialIndex);
110 
111     void OperateDelete(V2::Operation& operation, int32_t& initialIndex);
112 
113     void OperateMove(V2::Operation& operation, int32_t& initialIndex,
114         std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp);
115 
116     void OperateChange(V2::Operation& operation, int32_t& initialIndex,
117         std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp);
118 
119     std::map<int32_t, LazyForEachChild>::iterator FindItem(int32_t index,
120         std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp);
121 
122     void OperateExchange(V2::Operation& operation, int32_t& initialIndex,
123         std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp);
124 
125     void OperateReload(std::map<int32_t, LazyForEachChild>& expiringTemp);
126 
127     void ThrowRepeatOperationError(int32_t index);
128 
129     void RecordOutOfBoundaryNodes(int32_t index);
130 
InvalidIndexOfChangedData(size_t index)131     void InvalidIndexOfChangedData(size_t index)
132     {
133         for (auto& [key, child] : expiringItem_) {
134             if (static_cast<size_t>(child.first) == index) {
135                 child.first = -1;
136                 break;
137             }
138         }
139     }
140 
GetChildByKey(const std::string & key)141     RefPtr<UINode> GetChildByKey(const std::string& key)
142     {
143         return nullptr;
144     }
145 
GetItems(std::list<std::pair<std::string,RefPtr<UINode>>> & childList)146     std::map<int32_t, LazyForEachChild>& GetItems(std::list<std::pair<std::string, RefPtr<UINode>>>& childList)
147     {
148         startIndex_ = -1;
149         endIndex_ = -1;
150         int32_t lastIndex = -1;
151         bool isCertained = false;
152 
153         decltype(cachedItems_) items(std::move(cachedItems_));
154 
155         for (auto& [index, node] : items) {
156             if (!node.second) {
157                 cachedItems_.try_emplace(index, std::move(node));
158                 continue;
159             }
160 
161             auto frameNode = AceType::DynamicCast<FrameNode>(node.second->GetFrameChildByIndex(0, true));
162             if (frameNode && !frameNode->IsActive()) {
163                 ACE_SYNTAX_SCOPED_TRACE("LazyForEach not active index[%d]", index);
164                 frameNode->SetJSViewActive(false, true);
165                 expiringItem_.try_emplace(node.first, LazyForEachCacheChild(index, std::move(node.second)));
166                 continue;
167             }
168             cachedItems_.try_emplace(index, std::move(node));
169             if (startIndex_ == -1) {
170                 startIndex_ = index;
171             }
172             if (isLoop_) {
173                 if (isCertained) {
174                     continue;
175                 }
176                 if (lastIndex > -1 && index - lastIndex > 1) {
177                     startIndex_ = index;
178                     endIndex_ = lastIndex;
179                     isCertained = true;
180                 } else {
181                     endIndex_ = std::max(endIndex_, index);
182                 }
183             } else {
184                 endIndex_ = std::max(endIndex_, index);
185             }
186             lastIndex = index;
187         }
188 
189         if (needTransition) {
190             for (auto& [key, node] : expiringItem_) {
191                 if (!node.second) {
192                     continue;
193                 }
194                 auto frameNode = AceType::DynamicCast<FrameNode>(node.second->GetFrameChildByIndex(0, true));
195                 if (frameNode && frameNode->IsOnMainTree()) {
196                     childList.emplace_back(key, node.second);
197                 }
198             }
199             needTransition = false;
200         }
201 
202         return cachedItems_;
203     }
204 
RemoveAllChild()205     void RemoveAllChild()
206     {
207         ACE_SYNTAX_SCOPED_TRACE("LazyForEach RemoveAllChild");
208         for (auto& [index, node] : cachedItems_) {
209             if (!node.second) {
210                 continue;
211             }
212             auto frameNode = AceType::DynamicCast<FrameNode>(node.second->GetFrameChildByIndex(0, true));
213             if (frameNode) {
214                 frameNode->SetActive(false);
215             }
216             auto pair = expiringItem_.try_emplace(node.first, LazyForEachCacheChild(index, std::move(node.second)));
217             if (!pair.second) {
218                 TAG_LOGW(AceLogTag::ACE_LAZY_FOREACH, "Use repeat key for index: %{public}d", index);
219             }
220         }
221     }
222 
SetActiveChildRange(int32_t start,int32_t end)223     bool SetActiveChildRange(int32_t start, int32_t end)
224     {
225         ACE_SYNTAX_SCOPED_TRACE("LazyForEach active range start[%d], end[%d]", start, end);
226         int32_t count = GetTotalCount();
227         bool needBuild = false;
228         for (auto& [index, node] : cachedItems_) {
229             if ((index < count) && ((start <= end && start <= index && end >= index) ||
230                 (start > end && (index <= end || index >= start)))) {
231                 if (node.second) {
232                     auto frameNode = AceType::DynamicCast<FrameNode>(node.second->GetFrameChildByIndex(0, true));
233                     if (frameNode) {
234                         frameNode->SetActive(true);
235                     }
236                     continue;
237                 }
238                 auto keyIter = expiringItem_.find(node.first);
239                 if (keyIter != expiringItem_.end() && keyIter->second.second) {
240                     node.second = keyIter->second.second;
241                     expiringItem_.erase(keyIter);
242                     auto frameNode = AceType::DynamicCast<FrameNode>(node.second->GetFrameChildByIndex(0, true));
243                     if (frameNode) {
244                         frameNode->SetActive(true);
245                     }
246                 }
247                 needBuild = true;
248                 continue;
249             }
250             if (!node.second) {
251                 continue;
252             }
253             auto frameNode = AceType::DynamicCast<FrameNode>(node.second->GetFrameChildByIndex(0, true));
254             if (frameNode) {
255                 frameNode->SetActive(false);
256             }
257             auto pair = expiringItem_.try_emplace(node.first, LazyForEachCacheChild(index, std::move(node.second)));
258             if (!pair.second) {
259                 TAG_LOGW(AceLogTag::ACE_LAZY_FOREACH, "Use repeat key for index: %{public}d", index);
260             }
261             needBuild = true;
262         }
263         return needBuild;
264     }
265 
GetChildIndex(const RefPtr<FrameNode> & targetNode)266     int32_t GetChildIndex(const RefPtr<FrameNode>& targetNode)
267     {
268         for (auto& [index, node] : cachedItems_) {
269             if (node.second) {
270                 auto frameNode = AceType::DynamicCast<FrameNode>(node.second->GetFrameChildByIndex(0, true));
271                 if (frameNode == targetNode) {
272                     return index;
273                 }
274             }
275         }
276         for (auto& [key, node] : expiringItem_) {
277             if (!node.second) {
278                 continue;
279             }
280             auto frameNode = AceType::DynamicCast<FrameNode>(node.second->GetFrameChildByIndex(0, true));
281             if (frameNode && frameNode == targetNode) {
282                 return node.first;
283             }
284         }
285         return -1;
286     }
287 
288     void UpdateMoveFromTo(int32_t from, int32_t to);
289     void ResetMoveFromTo();
290     int32_t ConvertFormToIndex(int32_t index);
291 
SetFlagForGeneratedItem(PropertyChangeFlag propertyChangeFlag)292     void SetFlagForGeneratedItem(PropertyChangeFlag propertyChangeFlag)
293     {
294         for (const auto& item : cachedItems_) {
295             if (!item.second.second) {
296                 continue;
297             }
298             item.second.second->ForceUpdateLayoutPropertyFlag(propertyChangeFlag);
299         }
300     }
301 
CacheItem(int32_t index,std::unordered_map<std::string,LazyForEachCacheChild> & cache,const std::optional<LayoutConstraintF> & itemConstraint,int64_t deadline,bool & isTimeout)302     RefPtr<UINode> CacheItem(int32_t index, std::unordered_map<std::string, LazyForEachCacheChild>& cache,
303         const std::optional<LayoutConstraintF>& itemConstraint, int64_t deadline, bool& isTimeout)
304     {
305         ACE_SCOPED_TRACE("Builder:BuildLazyItem [%d]", index);
306         auto itemInfo = OnGetChildByIndex(ConvertFormToIndex(index), expiringItem_);
307         CHECK_NULL_RETURN(itemInfo.second, nullptr);
308         cache.try_emplace(itemInfo.first, LazyForEachCacheChild(index, itemInfo.second));
309         auto context = itemInfo.second->GetContext();
310         CHECK_NULL_RETURN(context, itemInfo.second);
311         auto frameNode = AceType::DynamicCast<FrameNode>(itemInfo.second->GetFrameChildByIndex(0, false, true));
312         context->SetPredictNode(frameNode);
313         if (!itemInfo.second->RenderCustomChild(deadline)) {
314             isTimeout = true;
315             context->ResetPredictNode();
316             return itemInfo.second;
317         }
318         ProcessOffscreenNode(itemInfo.second, false);
319         itemInfo.second->Build(nullptr);
320         context->ResetPredictNode();
321         itemInfo.second->SetJSViewActive(false, true);
322         cachedItems_[index] = LazyForEachChild(itemInfo.first, nullptr);
323 
324         return itemInfo.second;
325     }
326 
CheckCacheIndex(std::set<int32_t> & idleIndexes,int32_t count)327     void CheckCacheIndex(std::set<int32_t>& idleIndexes, int32_t count)
328     {
329         for (int32_t i = 1; i <= cacheCount_; i++) {
330             if (isLoop_) {
331                 if ((startIndex_ <= endIndex_ && endIndex_ + i < count) ||
332                     startIndex_ > endIndex_ + i) {
333                     idleIndexes.emplace(endIndex_ + i);
334                 } else if ((endIndex_ + i) % count < startIndex_) {
335                     idleIndexes.emplace((endIndex_ + i) % count);
336                 }
337             } else {
338                 if (endIndex_ + i < count) {
339                     idleIndexes.emplace(endIndex_ + i);
340                 }
341             }
342         }
343         for (int32_t i = 1; i <= cacheCount_; i++) {
344             if (isLoop_) {
345                 if ((startIndex_ <= endIndex_ && startIndex_ >= i) ||
346                     startIndex_ > endIndex_ + i) {
347                     idleIndexes.emplace(startIndex_ - i);
348                 } else if ((startIndex_ - i + count) % count > endIndex_) {
349                     idleIndexes.emplace((startIndex_ - i + count) % count);
350                 }
351             } else {
352                 if (startIndex_ >= i) {
353                     idleIndexes.emplace(startIndex_ - i);
354                 }
355             }
356         }
357     }
358 
PreBuildByIndex(int32_t index,std::unordered_map<std::string,LazyForEachCacheChild> & cache,int64_t deadline,const std::optional<LayoutConstraintF> & itemConstraint,bool canRunLongPredictTask)359     bool PreBuildByIndex(int32_t index, std::unordered_map<std::string, LazyForEachCacheChild>& cache,
360         int64_t deadline, const std::optional<LayoutConstraintF>& itemConstraint, bool canRunLongPredictTask)
361     {
362         if (GetSysTimestamp() > deadline) {
363             if (!DeleteExpiringItemImmediately()) {
364                 cache.merge(expiringItem_);
365             }
366             return false;
367         }
368         bool isTimeout = false;
369         preBuildingIndex_ = -1;
370         auto uiNode = CacheItem(index, cache, itemConstraint, deadline, isTimeout);
371         if (isTimeout) {
372             preBuildingIndex_ = index;
373             return false;
374         }
375         if (!canRunLongPredictTask && itemConstraint) {
376             return false;
377         }
378         if (canRunLongPredictTask && uiNode && itemConstraint) {
379             RefPtr<FrameNode> frameNode = DynamicCast<FrameNode>(uiNode);
380             while (!frameNode) {
381                 auto tempNode = uiNode;
382                 uiNode = tempNode->GetFirstChild();
383                 if (!uiNode) {
384                     break;
385                 }
386                 frameNode = DynamicCast<FrameNode>(uiNode);
387             }
388             if (frameNode) {
389                 frameNode->GetGeometryNode()->SetParentLayoutConstraint(itemConstraint.value());
390                 FrameNode::ProcessOffscreenNode(frameNode);
391             }
392         }
393         return true;
394     }
395 
ProcessPreBuildingIndex(std::unordered_map<std::string,LazyForEachCacheChild> & cache,int64_t deadline,const std::optional<LayoutConstraintF> & itemConstraint,bool canRunLongPredictTask,std::set<int32_t> & idleIndexes)396     bool ProcessPreBuildingIndex(std::unordered_map<std::string, LazyForEachCacheChild>& cache, int64_t deadline,
397         const std::optional<LayoutConstraintF>& itemConstraint, bool canRunLongPredictTask,
398         std::set<int32_t>& idleIndexes)
399     {
400         if (idleIndexes.find(preBuildingIndex_) == idleIndexes.end()) {
401             preBuildingIndex_ = -1;
402             return true;
403         }
404         idleIndexes.erase(preBuildingIndex_);
405         return PreBuildByIndex(preBuildingIndex_, cache, deadline, itemConstraint, canRunLongPredictTask);
406     }
407 
408     bool PreBuild(int64_t deadline, const std::optional<LayoutConstraintF>& itemConstraint, bool canRunLongPredictTask);
409 
ProcessCachedIndex(std::unordered_map<std::string,LazyForEachCacheChild> & cache,std::set<int32_t> & idleIndexes)410     void ProcessCachedIndex(std::unordered_map<std::string, LazyForEachCacheChild>& cache,
411         std::set<int32_t>& idleIndexes)
412     {
413         auto expiringIter = expiringItem_.begin();
414         while (expiringIter != expiringItem_.end()) {
415             const auto& key = expiringIter->first;
416             const auto& node = expiringIter->second;
417             auto iter = idleIndexes.find(node.first);
418             if (iter != idleIndexes.end() && node.second) {
419                 LoadCacheByIndex(cache, idleIndexes, node, key, iter, expiringIter);
420             } else {
421                 LoadCacheByKey(cache, idleIndexes, node, key, expiringIter);
422             }
423         }
424     }
425 
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)426     void LoadCacheByIndex(std::unordered_map<std::string, LazyForEachCacheChild>& cache, std::set<int32_t>& idleIndexes,
427         const LazyForEachCacheChild& node, const std::string& key, const std::set<int32_t>::iterator& iter,
428         std::unordered_map<std::string, LazyForEachCacheChild>::iterator& expiringIter)
429     {
430         ProcessOffscreenNode(node.second, false);
431 
432         if (node.first == preBuildingIndex_) {
433             cache.try_emplace(key, node);
434         } else {
435             cache.try_emplace(key, std::move(node));
436             cachedItems_.try_emplace(node.first, LazyForEachChild(key, nullptr));
437             idleIndexes.erase(iter);
438         }
439 
440         expiringIter++;
441     }
442 
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)443     void LoadCacheByKey(std::unordered_map<std::string, LazyForEachCacheChild>& cache, std::set<int32_t>& idleIndexes,
444         const LazyForEachCacheChild& node, const std::string& key,
445         std::unordered_map<std::string, LazyForEachCacheChild>::iterator& expiringIter)
446     {
447         NotifyDataDeleted(node.second, static_cast<size_t>(node.first), true);
448         ProcessOffscreenNode(node.second, true);
449         NotifyItemDeleted(RawPtr(node.second), key);
450 
451         if (node.second) {
452             node.second->DetachFromMainTree();
453         }
454         if (DeleteExpiringItemImmediately()) {
455             expiringIter = expiringItem_.erase(expiringIter);
456         } else {
457             expiringIter++;
458         }
459     }
460 
ProcessOffscreenNode(RefPtr<UINode> uiNode,bool remove)461     void ProcessOffscreenNode(RefPtr<UINode> uiNode, bool remove)
462     {
463         if (uiNode) {
464             auto frameNode = DynamicCast<FrameNode>(uiNode);
465             while (!frameNode) {
466                 auto tempNode = uiNode;
467                 uiNode = tempNode->GetFirstChild();
468                 if (!uiNode) {
469                     break;
470                 }
471                 frameNode = DynamicCast<FrameNode>(uiNode);
472             }
473             if (frameNode) {
474                 if (!remove) {
475                     Inspector::AddOffscreenNode(frameNode);
476                 } else {
477                     Inspector::RemoveOffscreenNode(frameNode);
478                 }
479             }
480         }
481     }
482 
ClearAllOffscreenNode()483     void ClearAllOffscreenNode()
484     {
485         for (auto& [key, node] : expiringItem_) {
486             ProcessOffscreenNode(node.second, true);
487         }
488         for (auto& [key, node] : cachedItems_) {
489             ProcessOffscreenNode(node.second, true);
490         }
491     }
492 
493     virtual void ReleaseChildGroupById(const std::string& id) = 0;
494 
495     virtual void RegisterDataChangeListener(const RefPtr<V2::DataChangeListener>& listener) = 0;
496 
497     virtual void UnregisterDataChangeListener(V2::DataChangeListener* listener) = 0;
498 
SetCacheCount(int32_t cacheCount)499     void SetCacheCount(int32_t cacheCount)
500     {
501         cacheCount_ = cacheCount;
502     }
503 
SetIsLoop(bool isLoop)504     void SetIsLoop(bool isLoop)
505     {
506         isLoop_ = isLoop;
507     }
508 
clearDeletedNodes()509     void clearDeletedNodes()
510     {
511         nodeList_.clear();
512     }
513 
SetUseNewInterface(bool useNewInterface)514     void SetUseNewInterface(bool useNewInterface)
515     {
516         useNewInterface_ = useNewInterface;
517     }
518 
GetCachedUINodeMap()519     const std::unordered_map<std::string, LazyForEachCacheChild>& GetCachedUINodeMap()
520     {
521         return expiringItem_;
522     }
523 
GetAllChildren()524     const std::map<int32_t, LazyForEachChild>& GetAllChildren()
525     {
526         if (!cachedItems_.empty()) {
527             startIndex_ = cachedItems_.begin()->first;
528             endIndex_ = cachedItems_.rbegin()->first;
529         }
530         if (isLoop_ && !cachedItems_.empty()) {
531             int32_t lastIndex = -1;
532             for (auto& [index, node] : cachedItems_) {
533                 if (lastIndex > -1 && index - lastIndex > 1) {
534                     startIndex_ = index;
535                     endIndex_ = lastIndex;
536                     break;
537                 }
538             }
539         }
540         return cachedItems_;
541     }
542 
SetJSViewActive(bool active)543     void SetJSViewActive(bool active)
544     {
545         for (const auto& node : cachedItems_) {
546             if (node.second.second == nullptr) {
547                 continue;
548             }
549             node.second.second->SetJSViewActive(active, true);
550         }
551         for (const auto& node : expiringItem_) {
552             node.second.second->SetJSViewActive(active, true);
553         }
554     }
555 
PaintDebugBoundaryTreeAll(bool flag)556     void PaintDebugBoundaryTreeAll(bool flag)
557     {
558         for (const auto& node : cachedItems_) {
559             if (node.second.second == nullptr) {
560                 continue;
561             }
562             node.second.second->PaintDebugBoundaryTreeAll(flag);
563         }
564         for (const auto& node : expiringItem_) {
565             if (node.second.second == nullptr) {
566                 continue;
567             }
568             node.second.second->PaintDebugBoundaryTreeAll(flag);
569         }
570     }
571 
NotifyItemDeleted(UINode * node,const std::string & key)572     void NotifyItemDeleted(UINode* node, const std::string& key)
573     {
574         OnItemDeleted(node, key);
575     }
576 
577     void GetAllItems(std::vector<UINode*>& items);
578 protected:
579     virtual int32_t OnGetTotalCount() = 0;
580 
OnItemDeleted(UINode * node,const std::string & key)581     virtual void OnItemDeleted(UINode* node, const std::string& key) {};
582 
DeleteExpiringItemImmediately()583     virtual bool DeleteExpiringItemImmediately()
584     {
585         return false;
586     }
587 
588     virtual LazyForEachChild OnGetChildByIndex(
589         int32_t index, std::unordered_map<std::string, LazyForEachCacheChild>& expiringItems) = 0;
590 
591     virtual LazyForEachChild OnGetChildByIndexNew(int32_t index,
592         std::map<int32_t, LazyForEachChild>& cachedItems,
593         std::unordered_map<std::string, LazyForEachCacheChild>& expiringItems) = 0;
594 
595     virtual void OnExpandChildrenOnInitialInNG() = 0;
596 
597     virtual void NotifyDataChanged(size_t index, const RefPtr<UINode>& lazyForEachNode, bool isRebuild = true) = 0;
598 
599     virtual void NotifyDataDeleted(const RefPtr<UINode>& lazyForEachNode, size_t index, bool removeIds) = 0;
600 
601     virtual void NotifyDataAdded(size_t index) = 0;
602 
603     virtual void KeepRemovedItemInCache(NG::LazyForEachChild node,
604         std::unordered_map<std::string, NG::LazyForEachCacheChild>& cachedItems) = 0;
605 
606 private:
607     void RecycleItemsOutOfBoundary();
608     void RecycleChildByIndex(int32_t index);
609 
610     std::map<int32_t, LazyForEachChild> cachedItems_;
611     std::unordered_map<std::string, LazyForEachCacheChild> expiringItem_;
612     std::list<std::pair<std::string, RefPtr<UINode>>> nodeList_;
613     std::map<int32_t, OperationInfo> operationList_;
614     enum class OP { ADD, DEL, CHANGE, MOVE, EXCHANGE, RELOAD };
615     std::map<std::string, OP> operationTypeMap = {{"add", OP::ADD},
616         {"delete", OP::DEL},
617         {"change", OP::CHANGE},
618         {"move", OP::MOVE},
619         {"exchange", OP::EXCHANGE},
620         {"reload", OP::RELOAD}};
621     std::list<int32_t> outOfBoundaryNodes_;
622     std::optional<std::pair<int32_t, int32_t>> moveFromTo_;
623 
624     int32_t startIndex_ = -1;
625     int32_t endIndex_ = -1;
626     int32_t cacheCount_ = 0;
627     int32_t preBuildingIndex_ = -1;
628     int32_t totalCountOfOriginalDataset_ = 0;
629     bool needTransition = false;
630     bool isLoop_ = false;
631     bool useNewInterface_ = false;
632     ACE_DISALLOW_COPY_AND_MOVE(LazyForEachBuilder);
633 };
634 } // namespace OHOS::Ace::NG
635 
636 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_SYNTAX_FOREACH_LAZY_FOR_EACH_BUILDER_H
637