• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 #include "core/components_ng/syntax/lazy_for_each_builder.h"
17 #include "core/components_ng/pattern/recycle_view/recycle_dummy_node.h"
18 
19 namespace OHOS::Ace::NG {
GetChildByIndex(int32_t index,bool needBuild,bool isCache)20     std::pair<std::string, RefPtr<UINode>> LazyForEachBuilder::GetChildByIndex(
21         int32_t index, bool needBuild, bool isCache)
22     {
23         auto iter = cachedItems_.find(index);
24         if (iter != cachedItems_.end()) {
25             if (iter->second.second) {
26                 return iter->second;
27             }
28             auto keyIter = expiringItem_.find(iter->second.first);
29             if (keyIter != expiringItem_.end() && keyIter->second.second) {
30                 if (!isCache) {
31                     iter->second.second = keyIter->second.second;
32                     expiringItem_.erase(keyIter);
33                     return iter->second;
34                 } else {
35                     return { keyIter->first, keyIter->second.second };
36                 }
37             }
38         }
39 
40         if (needBuild) {
41             ACE_SCOPED_TRACE("Builder:BuildLazyItem [%d]", index);
42             std::pair<std::string, RefPtr<UINode>> itemInfo;
43             if (useNewInterface_) {
44                 itemInfo = OnGetChildByIndexNew(ConvertFormToIndex(index), cachedItems_, expiringItem_);
45             } else {
46                 itemInfo = OnGetChildByIndex(ConvertFormToIndex(index), expiringItem_);
47             }
48             CHECK_NULL_RETURN(itemInfo.second, itemInfo);
49             if (isCache) {
50                 expiringItem_[itemInfo.first] = LazyForEachCacheChild(index, itemInfo.second);
51                 cachedItems_[index] = LazyForEachChild(itemInfo.first, nullptr);
52             } else {
53                 cachedItems_[index] = itemInfo;
54             }
55             return itemInfo;
56         }
57         return {};
58     }
59 
OnDataReloaded()60     void LazyForEachBuilder::OnDataReloaded()
61     {
62         for (auto& [key, node] : expiringItem_) {
63             node.first = -1;
64         }
65         for (auto& [index, node] : cachedItems_) {
66             if (node.second) {
67                 expiringItem_.try_emplace(node.first, LazyForEachCacheChild(-1, std::move(node.second)));
68             }
69         }
70         cachedItems_.clear();
71         needTransition = true;
72     }
73 
OnDataAdded(size_t index)74     bool LazyForEachBuilder::OnDataAdded(size_t index)
75     {
76         NotifyDataAdded(index);
77         if (!cachedItems_.empty() && index <= static_cast<size_t>(cachedItems_.rbegin()->first)) {
78             decltype(cachedItems_) temp(std::move(cachedItems_));
79 
80             for (auto& [oldindex, id] : temp) {
81                 cachedItems_.try_emplace(
82                     index > static_cast<size_t>(oldindex) ? oldindex : oldindex + 1, std::move(id));
83             }
84         }
85         for (auto& [key, node] : expiringItem_) {
86             if (static_cast<size_t>(node.first) >= index && node.first != -1) {
87                 node.first++;
88             }
89         }
90 
91         return true;
92     }
93 
OnDataBulkAdded(size_t index,size_t count)94     bool LazyForEachBuilder::OnDataBulkAdded(size_t index, size_t count)
95     {
96         if (!cachedItems_.empty() && index <= static_cast<size_t>(cachedItems_.rbegin()->first)) {
97             decltype(cachedItems_) temp(std::move(cachedItems_));
98 
99             for (auto& [oldindex, id] : temp) {
100                 cachedItems_.try_emplace(
101                     index > static_cast<size_t>(oldindex) ? oldindex : oldindex + count, std::move(id));
102             }
103         }
104         for (auto& [key, node] : expiringItem_) {
105             if (static_cast<size_t>(node.first) >= index && node.first != -1) {
106                 node.first = node.first + static_cast<int32_t>(count);
107             }
108         }
109 
110         return true;
111     }
112 
OnDataDeleted(size_t index)113     RefPtr<UINode> LazyForEachBuilder::OnDataDeleted(size_t index)
114     {
115         RefPtr<UINode> node;
116         if (cachedItems_.empty()) {
117             return node;
118         }
119         if (index <= static_cast<size_t>(cachedItems_.rbegin()->first)) {
120             decltype(cachedItems_) temp(std::move(cachedItems_));
121 
122             for (auto& [oldindex, child] : temp) {
123                 if (static_cast<size_t>(oldindex) == index) {
124                     node = child.second;
125                     KeepRemovedItemInCache(child, expiringItem_);
126                 } else {
127                     cachedItems_.try_emplace(
128                         index > static_cast<size_t>(oldindex) ? oldindex : oldindex - 1, std::move(child));
129                 }
130             }
131         }
132         NotifyDataDeleted(node, index, false);
133         for (auto& [key, child] : expiringItem_) {
134             if (static_cast<size_t>(child.first) > index) {
135                 child.first--;
136                 continue;
137             }
138             if (static_cast<size_t>(child.first) == index) {
139                 child.first = -1;
140                 node = child.second;
141             }
142         }
143 
144         return node;
145     }
146 
OnDataBulkDeleted(size_t index,size_t count)147     std::list<std::pair<std::string, RefPtr<UINode>>>& LazyForEachBuilder::OnDataBulkDeleted(size_t index, size_t count)
148     {
149         if (cachedItems_.empty()) {
150             return nodeList_;
151         }
152         if (index <= static_cast<size_t>(cachedItems_.rbegin()->first)) {
153             decltype(cachedItems_) temp(std::move(cachedItems_));
154 
155             for (auto& [oldindex, child] : temp) {
156                 if (static_cast<size_t>(oldindex) >= index && static_cast<size_t>(oldindex) < index + count) {
157                     nodeList_.emplace_back(child.first, child.second);
158                 } else {
159                     cachedItems_.try_emplace(
160                         index > static_cast<size_t>(oldindex) ? oldindex : oldindex - count, std::move(child));
161                 }
162             }
163         }
164 
165         if (DeleteExpiringItemImmediately()) {
166             decltype(expiringItem_) expiringTemp(std::move(expiringItem_));
167             for (auto& [key, child] : expiringTemp) {
168                 if (child.first < 0) {
169                     nodeList_.emplace_back(key, child.second);
170                     continue;
171                 }
172                 if (static_cast<size_t>(child.first) >= index + count) {
173                     child.first -= static_cast<int32_t>(count);
174                     expiringItem_.try_emplace(key, child);
175                     continue;
176                 }
177                 if (static_cast<size_t>(child.first) >= index && static_cast<size_t>(child.first) < index + count) {
178                     nodeList_.emplace_back(key, child.second);
179                 } else {
180                     expiringItem_.try_emplace(key, child);
181                 }
182             }
183         } else {
184             for (auto& [key, child] : expiringItem_) {
185                 if (static_cast<size_t>(child.first) >= index + count) {
186                     child.first -= static_cast<int32_t>(count);
187                     continue;
188                 }
189                 if (static_cast<size_t>(child.first) >= index && static_cast<size_t>(child.first) < index + count) {
190                     child.first = -1;
191                 }
192             }
193         }
194 
195         return nodeList_;
196     }
197 
OnDataChanged(size_t index)198     bool LazyForEachBuilder::OnDataChanged(size_t index)
199     {
200         auto keyIter = cachedItems_.find(index);
201         if (keyIter != cachedItems_.end()) {
202             if (keyIter->second.second) {
203                 NotifyDataChanged(index, keyIter->second.second, false);
204                 expiringItem_.try_emplace(
205                     keyIter->second.first, LazyForEachCacheChild(-1, std::move(keyIter->second.second)));
206             } else {
207                 InvalidIndexOfChangedData(index);
208             }
209             cachedItems_.erase(keyIter);
210             return true;
211         }
212         return false;
213     }
214 
OnDataBulkChanged(size_t index,size_t count)215     std::list<std::pair<std::string, RefPtr<UINode>>>& LazyForEachBuilder::OnDataBulkChanged(size_t index, size_t count)
216     {
217         if (cachedItems_.empty()) {
218             return nodeList_;
219         }
220         if (static_cast<size_t>(cachedItems_.rbegin()->first) < index) {
221             return nodeList_;
222         }
223         auto iter = cachedItems_.begin();
224         while (iter != cachedItems_.end()) {
225             auto itemIndex = iter->first;
226             const auto& child = iter->second;
227             if (static_cast<size_t>(itemIndex) >= index && static_cast<size_t>(itemIndex) < index + count) {
228                 NotifyDataChanged(index, child.second, false);
229                 nodeList_.emplace_back(child.first, child.second);
230                 iter = cachedItems_.erase(iter);
231             } else {
232                 iter++;
233             }
234         }
235         for (auto& [key, node] : expiringItem_) {
236             if (static_cast<size_t>(node.first) >= index && static_cast<size_t>(node.first) < index + count) {
237                 node.first = -1;
238             }
239         }
240         return nodeList_;
241     }
242 
OnDataMoveToNewPlace(size_t from,size_t to)243     void LazyForEachBuilder::OnDataMoveToNewPlace(size_t from, size_t to)
244     {
245         if (from == to) {
246             return;
247         }
248         decltype(cachedItems_) temp(std::move(cachedItems_));
249         if (from < to) {
250             for (const auto& [itemIndex, child] : temp) {
251                 auto position = static_cast<size_t>(itemIndex);
252                 if (position > from && position <= to && position >= 1) {
253                     cachedItems_.emplace(position - 1, child);
254                 } else if (position == from) {
255                     cachedItems_.emplace(to, child);
256                 } else {
257                     cachedItems_.emplace(itemIndex, child);
258                 }
259             }
260         } else {
261             for (const auto& [itemIndex, child] : temp) {
262                 auto position = static_cast<size_t>(itemIndex);
263                 if (position >= to && position < from) {
264                     cachedItems_.emplace(position + 1, child);
265                 } else if (position == from) {
266                     cachedItems_.emplace(to, child);
267                 } else {
268                     cachedItems_.emplace(itemIndex, child);
269                 }
270             }
271         }
272     }
273 
OnDataMoved(size_t from,size_t to)274     bool LazyForEachBuilder::OnDataMoved(size_t from, size_t to)
275     {
276         if (from == to) {
277             return false;
278         }
279         auto fromIter = cachedItems_.find(from);
280         auto toIter = cachedItems_.find(to);
281         if (fromIter != cachedItems_.end() && toIter != cachedItems_.end()) {
282             std::swap(fromIter->second, toIter->second);
283         } else if (fromIter != cachedItems_.end()) {
284             expiringItem_.try_emplace(
285                 fromIter->second.first, LazyForEachCacheChild(to, std::move(fromIter->second.second)));
286             cachedItems_.erase(fromIter);
287         } else if (toIter != cachedItems_.end()) {
288             expiringItem_.try_emplace(
289                 toIter->second.first, LazyForEachCacheChild(from, std::move(toIter->second.second)));
290             cachedItems_.erase(toIter);
291         }
292         return true;
293     }
294 
GetAllItems(std::vector<UINode * > & items)295     void LazyForEachBuilder::GetAllItems(std::vector<UINode*>& items)
296     {
297         for (const auto& item : cachedItems_) {
298             items.emplace_back(RawPtr(item.second.second));
299         }
300         for (const auto& item : expiringItem_) {
301             items.emplace_back(RawPtr(item.second.second));
302         }
303         for (const auto& item : nodeList_) {
304             items.emplace_back(RawPtr(item.second));
305         }
306     }
307 
GetTotalCountOfOriginalDataset(const std::list<V2::Operation> & DataOperations)308     int32_t LazyForEachBuilder::GetTotalCountOfOriginalDataset(const std::list<V2::Operation>& DataOperations)
309     {
310         int32_t totalCountOfCurrentDataset_ = GetTotalCount();
311         int32_t deltaCount = 0;
312         for (auto& operation : DataOperations) {
313             switch (operationTypeMap[operation.type]) {
314                 case OP::ADD:
315                     deltaCount = deltaCount - operation.count;
316                     break;
317                 case OP::DEL:
318                     deltaCount = deltaCount + operation.count;
319                     break;
320                 default:
321                     break;
322             }
323         }
324         return totalCountOfCurrentDataset_ + deltaCount;
325     }
326 
OnDatasetChange(std::list<V2::Operation> DataOperations)327     std::pair<int32_t, std::list<RefPtr<UINode>>> LazyForEachBuilder::OnDatasetChange(
328         std::list<V2::Operation> DataOperations)
329     {
330         totalCountOfOriginalDataset_ = GetTotalCountOfOriginalDataset(DataOperations);
331         int32_t initialIndex = totalCountOfOriginalDataset_;
332         std::map<int32_t, LazyForEachChild> expiringTempItem_;
333         std::list<std::string> expiringKeys;
334         for (auto& [key, cacheChild] : expiringItem_) {
335             if (cacheChild.first > -1) {
336                 expiringTempItem_.try_emplace(cacheChild.first, LazyForEachChild(key, cacheChild.second));
337                 expiringKeys.emplace_back(key);
338             }
339         }
340         for (auto& key : expiringKeys) {
341             expiringItem_.erase(key);
342         }
343         decltype(expiringTempItem_) expiringTemp(std::move(expiringTempItem_));
344         std::list<RefPtr<UINode>> nodeList;
345         for (const auto& item : nodeList_) {
346             nodeList.emplace_back(item.second);
347         }
348 
349         for (auto operation : DataOperations) {
350             bool isReload = ClassifyOperation(operation, initialIndex, cachedItems_, expiringTemp);
351             if (isReload) {
352                 initialIndex = 0;
353                 return std::pair(initialIndex, std::move(nodeList));
354             }
355         }
356         decltype(cachedItems_) cachedTemp(std::move(cachedItems_));
357         std::map<int32_t, int32_t> indexChangedMap;
358         CollectIndexChangedCount(indexChangedMap);
359         RepairDatasetItems(cachedTemp, cachedItems_, indexChangedMap);
360         RepairDatasetItems(expiringTemp, expiringTempItem_, indexChangedMap);
361         for (auto& [index, node] : expiringTempItem_) {
362             expiringItem_.emplace(node.first, LazyForEachCacheChild(index, node.second));
363         }
364         operationList_.clear();
365         return std::pair(initialIndex, std::move(nodeList));
366     }
367 
RepairDatasetItems(std::map<int32_t,LazyForEachChild> & cachedTemp,std::map<int32_t,LazyForEachChild> & expiringTempItem_,std::map<int32_t,int32_t> & indexChangedMap)368     void LazyForEachBuilder::RepairDatasetItems(std::map<int32_t, LazyForEachChild>& cachedTemp,
369         std::map<int32_t, LazyForEachChild>& expiringTempItem_, std::map<int32_t, int32_t>& indexChangedMap)
370     {
371         int32_t changedIndex = 0;
372         for (auto& [index, child] : cachedTemp) {
373             auto iter = indexChangedMap.find(index);
374             if (iter == indexChangedMap.end()) {
375                 if (!indexChangedMap.empty()) {
376                     iter--;
377                     if (iter->first < index) {
378                         changedIndex = iter->second;
379                     }
380                 }
381             } else {
382                 changedIndex = iter->second;
383             }
384             if (operationList_.find(index) == operationList_.end()) {
385                 expiringTempItem_.try_emplace(index + changedIndex, child);
386                 continue;
387             }
388             if (!indexChangedMap.empty()) {
389                 changedIndex = iter->second;
390             }
391             auto info = operationList_.find(index)->second;
392             if (info.isDeleting) {
393                 nodeList_.emplace_back(child.first, child.second);
394             } else if (info.isChanged) {
395                 expiringTempItem_.try_emplace(index, LazyForEachChild(info.key, nullptr));
396             } else if (!info.extraKey.empty()) {
397                 expiringTempItem_.try_emplace(index + changedIndex, child);
398                 for (int32_t i = 0; i < static_cast<int32_t>(info.extraKey.size()); i++) {
399                     expiringTempItem_.try_emplace(index + i, LazyForEachChild(info.extraKey[i], nullptr));
400                 }
401             } else if (info.node != nullptr) {
402                 RepairMoveOrExchange(expiringTempItem_, info, child, index, changedIndex);
403             } else {
404                 expiringTempItem_.try_emplace(index + changedIndex, child);
405             }
406         }
407     }
408 
RepairMoveOrExchange(std::map<int32_t,LazyForEachChild> & expiringTempItem_,OperationInfo & info,LazyForEachChild & child,int32_t index,int32_t changedIndex)409     void LazyForEachBuilder::RepairMoveOrExchange(std::map<int32_t, LazyForEachChild>& expiringTempItem_,
410         OperationInfo& info, LazyForEachChild& child, int32_t index, int32_t changedIndex)
411     {
412         if (info.isExchange) {
413             expiringTempItem_.try_emplace(index + changedIndex, LazyForEachChild(info.key, info.node));
414             return;
415         }
416         if (info.moveIn) {
417             int32_t fromIndex = index + changedIndex - 1;
418             int32_t toIndex = index + changedIndex;
419             if (info.fromDiffTo > 0) {
420                 fromIndex = index + changedIndex;
421                 toIndex = index + changedIndex - 1;
422             }
423             expiringTempItem_.try_emplace(toIndex, LazyForEachChild(info.key, info.node));
424             expiringTempItem_.try_emplace(fromIndex, child);
425         }
426     }
427 
CollectIndexChangedCount(std::map<int32_t,int32_t> & indexChangedMap)428     void LazyForEachBuilder::CollectIndexChangedCount(std::map<int32_t, int32_t>& indexChangedMap)
429     {
430         int32_t changedIndex = 0;
431         for (auto& [index, operationInfo] : operationList_) {
432             if (indexChangedMap.size() >= static_cast<size_t>(1)) {
433                 for (int32_t i = indexChangedMap.rbegin()->first + 1; i < index; i++) {
434                     indexChangedMap.try_emplace(i, changedIndex);
435                 }
436             }
437             operationInfo.changeCount += changedIndex;
438             changedIndex = operationInfo.changeCount;
439             indexChangedMap.try_emplace(index, changedIndex);
440         }
441     }
442 
ClassifyOperation(V2::Operation & operation,int32_t & initialIndex,std::map<int32_t,LazyForEachChild> & cachedTemp,std::map<int32_t,LazyForEachChild> & expiringTemp)443     bool LazyForEachBuilder::ClassifyOperation(V2::Operation& operation, int32_t& initialIndex,
444         std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp)
445     {
446         switch (operationTypeMap[operation.type]) {
447             case OP::ADD:
448                 OperateAdd(operation, initialIndex);
449                 break;
450             case OP::DEL:
451                 OperateDelete(operation, initialIndex);
452                 break;
453             case OP::CHANGE:
454                 OperateChange(operation, initialIndex, cachedTemp, expiringTemp);
455                 break;
456             case OP::MOVE:
457                 OperateMove(operation, initialIndex, cachedTemp, expiringTemp);
458                 break;
459             case OP::EXCHANGE:
460                 OperateExchange(operation, initialIndex, cachedTemp, expiringTemp);
461                 break;
462             case OP::RELOAD:
463                 OperateReload(expiringTemp);
464                 return true;
465         }
466         return false;
467     }
468 
ValidateIndex(int32_t index,const std::string & type)469     bool LazyForEachBuilder::ValidateIndex(int32_t index, const std::string& type)
470     {
471         bool isValid = true;
472         if (operationTypeMap[type] == OP::ADD) {
473             // for add operation, the index can equal totalCountOfOriginalDataset_
474             isValid = index >= 0 && index <= totalCountOfOriginalDataset_;
475         } else {
476             isValid = index >= 0 && index < totalCountOfOriginalDataset_;
477         }
478         if (!isValid) {
479             TAG_LOGE(
480                 AceLogTag::ACE_LAZY_FOREACH, "%{public}s(%{public}d) Operation is out of range", type.c_str(), index);
481         }
482         return isValid;
483     }
484 
OperateAdd(V2::Operation & operation,int32_t & initialIndex)485     void LazyForEachBuilder::OperateAdd(V2::Operation& operation, int32_t& initialIndex)
486     {
487         OperationInfo itemInfo;
488         if (!ValidateIndex(operation.index, operation.type)) {
489             return;
490         }
491         auto indexExist = operationList_.find(operation.index);
492         if (indexExist == operationList_.end()) {
493             itemInfo.changeCount = operation.count;
494             if (!operation.key.empty()) {
495                 itemInfo.extraKey.push_back(operation.key);
496             } else if (operation.keyList.size() >= static_cast<size_t>(1)) {
497                 for (std::string key : operation.keyList) {
498                     itemInfo.extraKey.push_back(key);
499                 }
500             }
501             initialIndex = std::min(initialIndex, operation.index);
502             operationList_.try_emplace(operation.index, itemInfo);
503         } else {
504             ThrowRepeatOperationError(operation.index);
505         }
506     }
507 
OperateDelete(V2::Operation & operation,int32_t & initialIndex)508     void LazyForEachBuilder::OperateDelete(V2::Operation& operation, int32_t& initialIndex)
509     {
510         OperationInfo itemInfo;
511         if (!ValidateIndex(operation.index, operation.type)) {
512             return;
513         }
514         auto indexExist = operationList_.find(operation.index);
515         if (indexExist == operationList_.end()) {
516             itemInfo.changeCount = -operation.count;
517             itemInfo.isDeleting = true;
518             initialIndex = std::min(initialIndex, operation.index);
519             operationList_.try_emplace(operation.index, itemInfo);
520             for (int32_t i = operation.index + 1; i < operation.index + operation.count; i++) {
521                 OperationInfo extraInfo;
522                 if (operationList_.find(i) == operationList_.end()) {
523                     extraInfo.isDeleting = true;
524                     operationList_.try_emplace(i, extraInfo);
525                 } else {
526                     ThrowRepeatOperationError(i);
527                 }
528             }
529         } else {
530             ThrowRepeatOperationError(operation.index);
531         }
532     }
533 
OperateChange(V2::Operation & operation,int32_t & initialIndex,std::map<int32_t,LazyForEachChild> & cachedTemp,std::map<int32_t,LazyForEachChild> & expiringTemp)534     void LazyForEachBuilder::OperateChange(V2::Operation& operation, int32_t& initialIndex,
535         std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp)
536     {
537         OperationInfo itemInfo;
538         if (!ValidateIndex(operation.index, operation.type)) {
539             return;
540         }
541         auto indexExist = operationList_.find(operation.index);
542         if (indexExist == operationList_.end()) {
543             itemInfo.isChanged = true;
544             auto iter = cachedTemp.find(operation.index);
545             if (iter == cachedTemp.end()) {
546                 iter = expiringTemp.find(operation.index);
547             }
548             if (iter == expiringTemp.end()) {
549                 return;
550             }
551             if (!operation.key.empty()) {
552                 itemInfo.key = operation.key;
553             } else {
554                 itemInfo.key = iter->second.first;
555             }
556             initialIndex = std::min(initialIndex, operation.index);
557             operationList_.try_emplace(operation.index, itemInfo);
558         } else {
559             ThrowRepeatOperationError(operation.index);
560         }
561     }
562 
OperateMove(V2::Operation & operation,int32_t & initialIndex,std::map<int32_t,LazyForEachChild> & cachedTemp,std::map<int32_t,LazyForEachChild> & expiringTemp)563     void LazyForEachBuilder::OperateMove(V2::Operation& operation, int32_t& initialIndex,
564         std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp)
565     {
566         OperationInfo fromInfo;
567         OperationInfo toInfo;
568         if (!ValidateIndex(operation.coupleIndex.first, operation.type) ||
569             !ValidateIndex(operation.coupleIndex.second, operation.type)) {
570             return;
571         }
572         auto fromIndexExist = operationList_.find(operation.coupleIndex.first);
573         auto toIndexExist = operationList_.find(operation.coupleIndex.second);
574         if (fromIndexExist == operationList_.end()) {
575             fromInfo.changeCount = -1;
576             fromInfo.isDeleting = true;
577             initialIndex = std::min(initialIndex, operation.coupleIndex.first);
578             operationList_.try_emplace(operation.coupleIndex.first, fromInfo);
579         } else {
580             ThrowRepeatOperationError(operation.coupleIndex.first);
581         }
582         if (toIndexExist == operationList_.end()) {
583             toInfo.changeCount = 1;
584             auto iter = cachedTemp.find(operation.coupleIndex.first);
585             if (iter == cachedTemp.end()) {
586                 iter = expiringTemp.find(operation.coupleIndex.first);
587             }
588             if (iter == expiringTemp.end()) {
589                 return;
590             }
591             toInfo.node = iter->second.second;
592             toInfo.moveIn = true;
593             toInfo.fromDiffTo = operation.coupleIndex.first - operation.coupleIndex.second;
594             if (!operation.key.empty()) {
595                 toInfo.key = operation.key;
596             } else {
597                 toInfo.key = iter->second.first;
598             }
599             initialIndex = std::min(initialIndex, operation.coupleIndex.second);
600             operationList_.try_emplace(operation.coupleIndex.second, toInfo);
601         } else {
602             ThrowRepeatOperationError(operation.coupleIndex.second);
603         }
604     }
605 
OperateExchange(V2::Operation & operation,int32_t & initialIndex,std::map<int32_t,LazyForEachChild> & cachedTemp,std::map<int32_t,LazyForEachChild> & expiringTemp)606     void LazyForEachBuilder::OperateExchange(V2::Operation& operation, int32_t& initialIndex,
607         std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp)
608     {
609         OperationInfo startInfo;
610         OperationInfo endInfo;
611         if (!ValidateIndex(operation.coupleIndex.first, operation.type) ||
612             !ValidateIndex(operation.coupleIndex.second, operation.type)) {
613             return;
614         }
615         auto startIndexExist = operationList_.find(operation.coupleIndex.first);
616         auto endIndexExist = operationList_.find(operation.coupleIndex.second);
617         if (startIndexExist == operationList_.end()) {
618             auto iter = FindItem(operation.coupleIndex.first, cachedTemp, expiringTemp);
619             if (iter == expiringTemp.end()) {
620                 return;
621             }
622             startInfo.node = iter->second.second;
623             if (!operation.coupleKey.first.empty()) {
624                 startInfo.key = operation.coupleKey.first;
625             } else {
626                 startInfo.key = iter->second.first;
627             }
628             startInfo.isExchange = true;
629             initialIndex = std::min(initialIndex, operation.coupleIndex.second);
630             operationList_.try_emplace(operation.coupleIndex.second, startInfo);
631         } else {
632             ThrowRepeatOperationError(operation.coupleIndex.first);
633         }
634         if (endIndexExist == operationList_.end()) {
635             auto iter = FindItem(operation.coupleIndex.second, cachedTemp, expiringTemp);
636             if (iter == expiringTemp.end()) {
637                 return;
638             }
639             endInfo.node = iter->second.second;
640             if (!operation.coupleKey.second.empty()) {
641                 endInfo.key = operation.coupleKey.second;
642             } else {
643                 endInfo.key = iter->second.first;
644             }
645             endInfo.isExchange = true;
646             initialIndex = std::min(initialIndex, operation.coupleIndex.first);
647             operationList_.try_emplace(operation.coupleIndex.first, endInfo);
648         } else {
649             ThrowRepeatOperationError(operation.coupleIndex.second);
650         }
651     }
652 
FindItem(int32_t index,std::map<int32_t,LazyForEachChild> & cachedTemp,std::map<int32_t,LazyForEachChild> & expiringTemp)653     std::map<int32_t, LazyForEachChild>::iterator LazyForEachBuilder::FindItem(int32_t index,
654         std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp)
655     {
656         auto iter = cachedTemp.find(index);
657         if (iter == cachedTemp.end()) {
658             iter = expiringTemp.find(index);
659         }
660         return iter;
661     }
662 
OperateReload(std::map<int32_t,LazyForEachChild> & expiringTemp)663     void LazyForEachBuilder::OperateReload(std::map<int32_t, LazyForEachChild>& expiringTemp)
664     {
665         for (auto& [index, node] : expiringTemp) {
666             expiringItem_.emplace(node.first, LazyForEachCacheChild(index, node.second));
667         }
668         operationList_.clear();
669         OnDataReloaded();
670     }
671 
ThrowRepeatOperationError(int32_t index)672     void LazyForEachBuilder::ThrowRepeatOperationError(int32_t index)
673     {
674         TAG_LOGE(AceLogTag::ACE_LAZY_FOREACH, "Repeat Operation for index: %{public}d", index);
675     }
676 
RecycleChildByIndex(int32_t index)677     void LazyForEachBuilder::RecycleChildByIndex(int32_t index)
678     {
679         auto iter = cachedItems_.find(index);
680         if (iter != cachedItems_.end()) {
681             if (!iter->second.second) {
682                 return;
683             }
684             auto dummyNode = AceType::DynamicCast<RecycleDummyNode>(iter->second.second);
685             if (!dummyNode) {
686                 return;
687             }
688             auto keyIter = expiringItem_.find(iter->second.first);
689             if (keyIter != expiringItem_.end() && keyIter->second.second) {
690                 expiringItem_.erase(keyIter);
691             }
692             cachedItems_.erase(index);
693         }
694     }
695 
PreBuild(int64_t deadline,const std::optional<LayoutConstraintF> & itemConstraint,bool canRunLongPredictTask)696     bool LazyForEachBuilder::PreBuild(int64_t deadline, const std::optional<LayoutConstraintF>& itemConstraint,
697         bool canRunLongPredictTask)
698     {
699         ACE_SYNTAX_SCOPED_TRACE("expiringItem_ count:[%zu]", expiringItem_.size());
700         outOfBoundaryNodes_.clear();
701         if (itemConstraint && !canRunLongPredictTask) {
702             return false;
703         }
704         auto count = OnGetTotalCount();
705         std::unordered_map<std::string, LazyForEachCacheChild> cache;
706         std::set<int32_t> idleIndexes;
707         if (startIndex_ != -1 && endIndex_ != -1) {
708             CheckCacheIndex(idleIndexes, count);
709         }
710 
711         ProcessCachedIndex(cache, idleIndexes);
712 
713         bool result = true;
714         result = ProcessPreBuildingIndex(cache, deadline, itemConstraint, canRunLongPredictTask, idleIndexes);
715         if (!result) {
716             expiringItem_.swap(cache);
717             return result;
718         }
719 
720         for (auto index : idleIndexes) {
721             result = PreBuildByIndex(index, cache, deadline, itemConstraint, canRunLongPredictTask);
722             if (!result) {
723                 break;
724             }
725         }
726         expiringItem_.swap(cache);
727         return result;
728     }
729 
RecordOutOfBoundaryNodes(int32_t index)730     void LazyForEachBuilder::RecordOutOfBoundaryNodes(int32_t index)
731     {
732         outOfBoundaryNodes_.emplace_back(index);
733     }
734 
RecycleItemsOutOfBoundary()735     void LazyForEachBuilder::RecycleItemsOutOfBoundary()
736     {
737         for (const auto& i: outOfBoundaryNodes_) {
738             RecycleChildByIndex(i);
739         }
740         outOfBoundaryNodes_.clear();
741     }
742 
UpdateMoveFromTo(int32_t from,int32_t to)743     void LazyForEachBuilder::UpdateMoveFromTo(int32_t from, int32_t to)
744     {
745         if (moveFromTo_) {
746             moveFromTo_.value().second = to;
747         } else {
748             moveFromTo_ = { from, to };
749         }
750     }
751 
ResetMoveFromTo()752     void LazyForEachBuilder::ResetMoveFromTo()
753     {
754         moveFromTo_.reset();
755     }
756 
ConvertFormToIndex(int32_t index)757     int32_t LazyForEachBuilder::ConvertFormToIndex(int32_t index)
758     {
759         if (!moveFromTo_) {
760             return index;
761         }
762         if (moveFromTo_.value().second == index) {
763             return moveFromTo_.value().first;
764         }
765         if (moveFromTo_.value().first <= index && index < moveFromTo_.value().second) {
766             return index + 1;
767         }
768         if (moveFromTo_.value().second < index && index <= moveFromTo_.value().first) {
769             return index - 1;
770         }
771         return index;
772     }
773 }
774