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