• 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 
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 ConvertFormToIndex(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 
305 protected:
306     virtual int32_t OnGetTotalCount() = 0;
307 
OnItemDeleted(UINode * node,const std::string & key)308     virtual void OnItemDeleted(UINode* node, const std::string& key) {};
309 
DeleteExpiringItemImmediately()310     virtual bool DeleteExpiringItemImmediately()
311     {
312         return false;
313     }
314 
315     virtual LazyForEachChild OnGetChildByIndex(
316         int32_t index, std::unordered_map<std::string, LazyForEachCacheChild>& cachedItems) = 0;
317 
318     virtual LazyForEachChild OnGetChildByIndexNew(int32_t index,
319         std::map<int32_t, LazyForEachChild>& cachedItems,
320         std::unordered_map<std::string, LazyForEachCacheChild>& expiringItems) = 0;
321 
322     virtual void OnExpandChildrenOnInitialInNG() = 0;
323 
324     virtual void NotifyDataChanged(size_t index, const RefPtr<UINode>& lazyForEachNode, bool isRebuild = true) = 0;
325 
326     virtual void NotifyDataDeleted(const RefPtr<UINode>& lazyForEachNode, size_t index, bool removeIds) = 0;
327 
328     virtual void NotifyDataAdded(size_t index) = 0;
329 
330     virtual void KeepRemovedItemInCache(NG::LazyForEachChild node,
331         std::unordered_map<std::string, NG::LazyForEachCacheChild>& cachedItems) = 0;
332 
333 private:
334     void RecycleItemsOutOfBoundary();
335     void RecycleChildByIndex(int32_t index);
336 
337     std::map<int32_t, LazyForEachChild> cachedItems_;
338     std::unordered_map<std::string, LazyForEachCacheChild> expiringItem_;
339     std::list<std::pair<std::string, RefPtr<UINode>>> nodeList_;
340     std::map<int32_t, OperationInfo> operationList_;
341     enum class OP { ADD, DEL, CHANGE, MOVE, EXCHANGE, RELOAD };
342     std::map<std::string, OP> operationTypeMap = {{"add", OP::ADD},
343         {"delete", OP::DEL},
344         {"change", OP::CHANGE},
345         {"move", OP::MOVE},
346         {"exchange", OP::EXCHANGE},
347         {"reload", OP::RELOAD}};
348     std::list<int32_t> outOfBoundaryNodes_;
349     std::optional<std::pair<int32_t, int32_t>> moveFromTo_;
350 
351     int32_t startIndex_ = -1;
352     int32_t endIndex_ = -1;
353     int32_t cacheCount_ = 0;
354     int32_t startShowCached_ = 0;
355     int32_t endShowCached_ = 0;
356     int32_t preBuildingIndex_ = -1;
357     int32_t totalCountOfOriginalDataset_ = 0;
358     int32_t historicalTotalCount_ = 0;
359     bool needTransition = false;
360     bool isLoop_ = false;
361     bool useNewInterface_ = false;
362     ACE_DISALLOW_COPY_AND_MOVE(LazyForEachBuilder);
363 };
364 } // namespace OHOS::Ace::NG
365 
366 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_SYNTAX_FOREACH_LAZY_FOR_EACH_BUILDER_H
367