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_.emplace(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()308 int32_t LazyForEachBuilder::GetTotalCountOfOriginalDataset() 309 { 310 int32_t totalCount = GetTotalCount(); 311 int32_t totalCountOfOriginalDataset = historicalTotalCount_; 312 UpdateHistoricalTotalCount(totalCount); 313 return totalCountOfOriginalDataset; 314 } 315 OnDatasetChange(std::list<V2::Operation> DataOperations)316 std::pair<int32_t, std::list<std::pair<std::string, RefPtr<UINode>>>> LazyForEachBuilder::OnDatasetChange( 317 std::list<V2::Operation> DataOperations) 318 { 319 totalCountOfOriginalDataset_ = GetTotalCountOfOriginalDataset(); 320 int32_t initialIndex = totalCountOfOriginalDataset_; 321 std::map<int32_t, LazyForEachChild> expiringTempItem_; 322 std::list<std::string> expiringKeys; 323 for (auto& [key, cacheChild] : expiringItem_) { 324 if (cacheChild.first > -1) { 325 expiringTempItem_.try_emplace(cacheChild.first, LazyForEachChild(key, cacheChild.second)); 326 expiringKeys.emplace_back(key); 327 } 328 } 329 for (auto& key : expiringKeys) { 330 expiringItem_.erase(key); 331 } 332 decltype(expiringTempItem_) expiringTemp(std::move(expiringTempItem_)); 333 for (auto operation : DataOperations) { 334 bool isReload = ClassifyOperation(operation, initialIndex, cachedItems_, expiringTemp); 335 if (isReload) { 336 initialIndex = 0; 337 return std::pair(initialIndex, nodeList_); 338 } 339 } 340 decltype(cachedItems_) cachedTemp(std::move(cachedItems_)); 341 std::map<int32_t, int32_t> indexChangedMap; 342 CollectIndexChangedCount(indexChangedMap); 343 RepairDatasetItems(cachedTemp, cachedItems_, indexChangedMap); 344 RepairDatasetItems(expiringTemp, expiringTempItem_, indexChangedMap); 345 for (auto& [index, node] : expiringTempItem_) { 346 expiringItem_.emplace(node.first, LazyForEachCacheChild(index, node.second)); 347 } 348 operationList_.clear(); 349 return std::pair(initialIndex, nodeList_); 350 } 351 RepairDatasetItems(std::map<int32_t,LazyForEachChild> & cachedTemp,std::map<int32_t,LazyForEachChild> & expiringTempItem_,std::map<int32_t,int32_t> & indexChangedMap)352 void LazyForEachBuilder::RepairDatasetItems(std::map<int32_t, LazyForEachChild>& cachedTemp, 353 std::map<int32_t, LazyForEachChild>& expiringTempItem_, std::map<int32_t, int32_t>& indexChangedMap) 354 { 355 int32_t changedIndex = 0; 356 for (auto& [index, child] : cachedTemp) { 357 auto iter = indexChangedMap.find(index); 358 if (iter == indexChangedMap.end()) { 359 if (!indexChangedMap.empty()) { 360 iter--; 361 if (iter->first < index) { 362 changedIndex = iter->second; 363 } 364 } 365 } else { 366 changedIndex = iter->second; 367 } 368 if (operationList_.find(index) == operationList_.end()) { 369 expiringTempItem_.try_emplace(index + changedIndex, child); 370 continue; 371 } 372 if (!indexChangedMap.empty()) { 373 changedIndex = iter->second; 374 } 375 auto info = operationList_.find(index)->second; 376 if (info.isDeleting) { 377 nodeList_.emplace_back(child.first, child.second); 378 } else if (info.isChanged) { 379 expiringTempItem_.try_emplace(index + changedIndex, LazyForEachChild(info.key, nullptr)); 380 } else if (!info.extraKey.empty()) { 381 expiringTempItem_.try_emplace(index + changedIndex, child); 382 int32_t preChangedIndex = 0; 383 auto preIter = indexChangedMap.find(index - 1); 384 if (preIter != indexChangedMap.end()) { 385 preChangedIndex = preIter->second; 386 } 387 for (int32_t i = 0; i < static_cast<int32_t>(info.extraKey.size()); i++) { 388 expiringTempItem_.try_emplace( 389 index + preChangedIndex + i, LazyForEachChild(info.extraKey[i], nullptr)); 390 } 391 } else { 392 RepairMoveOrExchange(expiringTempItem_, info, child, index, changedIndex); 393 } 394 } 395 } 396 RepairMoveOrExchange(std::map<int32_t,LazyForEachChild> & expiringTempItem_,OperationInfo & info,LazyForEachChild & child,int32_t index,int32_t changedIndex)397 void LazyForEachBuilder::RepairMoveOrExchange(std::map<int32_t, LazyForEachChild>& expiringTempItem_, 398 OperationInfo& info, LazyForEachChild& child, int32_t index, int32_t changedIndex) 399 { 400 if (info.isExchange) { 401 // if the child will be exchanged with a null node, this child should be deleted 402 if (info.node == nullptr && child.second != nullptr) { 403 nodeList_.emplace_back(child.first, child.second); 404 } 405 // null node should not be put in expiringTempItem_ then expiringTempItem_ 406 if (info.node != nullptr) { 407 expiringTempItem_.try_emplace(index + changedIndex, LazyForEachChild(info.key, info.node)); 408 } 409 return; 410 } 411 if (info.moveIn) { 412 int32_t fromIndex = index + changedIndex - 1; 413 int32_t toIndex = index + changedIndex; 414 if (info.fromDiffTo > 0) { 415 fromIndex = index + changedIndex; 416 toIndex = index + changedIndex - 1; 417 } 418 expiringTempItem_.try_emplace(toIndex, LazyForEachChild(info.key, info.node)); 419 expiringTempItem_.try_emplace(fromIndex, child); 420 } 421 } 422 CollectIndexChangedCount(std::map<int32_t,int32_t> & indexChangedMap)423 void LazyForEachBuilder::CollectIndexChangedCount(std::map<int32_t, int32_t>& indexChangedMap) 424 { 425 int32_t changedIndex = 0; 426 for (auto& [index, operationInfo] : operationList_) { 427 if (indexChangedMap.size() >= static_cast<size_t>(1)) { 428 for (int32_t i = indexChangedMap.rbegin()->first + 1; i < index; i++) { 429 indexChangedMap.try_emplace(i, changedIndex); 430 } 431 } 432 operationInfo.changeCount += changedIndex; 433 changedIndex = operationInfo.changeCount; 434 indexChangedMap.try_emplace(index, changedIndex); 435 } 436 } 437 ClassifyOperation(V2::Operation & operation,int32_t & initialIndex,std::map<int32_t,LazyForEachChild> & cachedTemp,std::map<int32_t,LazyForEachChild> & expiringTemp)438 bool LazyForEachBuilder::ClassifyOperation(V2::Operation& operation, int32_t& initialIndex, 439 std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp) 440 { 441 switch (operationTypeMap[operation.type]) { 442 case OP::ADD: 443 OperateAdd(operation, initialIndex); 444 break; 445 case OP::DEL: 446 OperateDelete(operation, initialIndex); 447 break; 448 case OP::CHANGE: 449 OperateChange(operation, initialIndex, cachedTemp, expiringTemp); 450 break; 451 case OP::MOVE: 452 OperateMove(operation, initialIndex, cachedTemp, expiringTemp); 453 break; 454 case OP::EXCHANGE: 455 OperateExchange(operation, initialIndex, cachedTemp, expiringTemp); 456 break; 457 case OP::RELOAD: 458 OperateReload(expiringTemp); 459 return true; 460 } 461 return false; 462 } 463 ValidateIndex(int32_t index,const std::string & type)464 bool LazyForEachBuilder::ValidateIndex(int32_t index, const std::string& type) 465 { 466 bool isValid = true; 467 if (operationTypeMap[type] == OP::ADD) { 468 // for add operation, the index can equal totalCountOfOriginalDataset_ 469 isValid = index >= 0 && index <= totalCountOfOriginalDataset_; 470 } else { 471 isValid = index >= 0 && index < totalCountOfOriginalDataset_; 472 } 473 if (!isValid) { 474 TAG_LOGE( 475 AceLogTag::ACE_LAZY_FOREACH, "%{public}s(%{public}d) Operation is out of range", type.c_str(), index); 476 } 477 return isValid; 478 } 479 OperateAdd(V2::Operation & operation,int32_t & initialIndex)480 void LazyForEachBuilder::OperateAdd(V2::Operation& operation, int32_t& initialIndex) 481 { 482 OperationInfo itemInfo; 483 if (!ValidateIndex(operation.index, operation.type)) { 484 return; 485 } 486 auto indexExist = operationList_.find(operation.index); 487 if (indexExist == operationList_.end()) { 488 itemInfo.changeCount = operation.count; 489 if (!operation.key.empty()) { 490 itemInfo.extraKey.push_back(operation.key); 491 } else if (operation.keyList.size() >= static_cast<size_t>(1)) { 492 for (std::string key : operation.keyList) { 493 itemInfo.extraKey.push_back(key); 494 } 495 } 496 initialIndex = std::min(initialIndex, operation.index); 497 operationList_.try_emplace(operation.index, itemInfo); 498 } else { 499 ThrowRepeatOperationError(operation.index); 500 } 501 } 502 OperateDelete(V2::Operation & operation,int32_t & initialIndex)503 void LazyForEachBuilder::OperateDelete(V2::Operation& operation, int32_t& initialIndex) 504 { 505 OperationInfo itemInfo; 506 if (!ValidateIndex(operation.index, operation.type)) { 507 return; 508 } 509 auto indexExist = operationList_.find(operation.index); 510 if (indexExist == operationList_.end()) { 511 itemInfo.changeCount = -operation.count; 512 itemInfo.isDeleting = true; 513 initialIndex = std::min(initialIndex, operation.index); 514 operationList_.try_emplace(operation.index, itemInfo); 515 for (int32_t i = operation.index + 1; i < operation.index + operation.count; i++) { 516 OperationInfo extraInfo; 517 if (operationList_.find(i) == operationList_.end()) { 518 extraInfo.isDeleting = true; 519 operationList_.try_emplace(i, extraInfo); 520 } else { 521 ThrowRepeatOperationError(i); 522 } 523 } 524 } else { 525 ThrowRepeatOperationError(operation.index); 526 } 527 } 528 OperateChange(V2::Operation & operation,int32_t & initialIndex,std::map<int32_t,LazyForEachChild> & cachedTemp,std::map<int32_t,LazyForEachChild> & expiringTemp)529 void LazyForEachBuilder::OperateChange(V2::Operation& operation, int32_t& initialIndex, 530 std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp) 531 { 532 OperationInfo itemInfo; 533 if (!ValidateIndex(operation.index, operation.type)) { 534 return; 535 } 536 auto indexExist = operationList_.find(operation.index); 537 if (indexExist == operationList_.end()) { 538 itemInfo.isChanged = true; 539 auto iter = cachedTemp.find(operation.index); 540 if (iter == cachedTemp.end()) { 541 iter = expiringTemp.find(operation.index); 542 } 543 if (iter == expiringTemp.end()) { 544 return; 545 } 546 if (!operation.key.empty()) { 547 itemInfo.key = operation.key; 548 } else { 549 itemInfo.key = iter->second.first; 550 } 551 initialIndex = std::min(initialIndex, operation.index); 552 operationList_.try_emplace(operation.index, itemInfo); 553 } else { 554 ThrowRepeatOperationError(operation.index); 555 } 556 } 557 OperateMove(V2::Operation & operation,int32_t & initialIndex,std::map<int32_t,LazyForEachChild> & cachedTemp,std::map<int32_t,LazyForEachChild> & expiringTemp)558 void LazyForEachBuilder::OperateMove(V2::Operation& operation, int32_t& initialIndex, 559 std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp) 560 { 561 OperationInfo fromInfo; 562 OperationInfo toInfo; 563 if (!ValidateIndex(operation.coupleIndex.first, operation.type) || 564 !ValidateIndex(operation.coupleIndex.second, operation.type)) { 565 return; 566 } 567 auto fromIndexExist = operationList_.find(operation.coupleIndex.first); 568 auto toIndexExist = operationList_.find(operation.coupleIndex.second); 569 if (fromIndexExist == operationList_.end()) { 570 fromInfo.changeCount = -1; 571 fromInfo.isDeleting = true; 572 initialIndex = std::min(initialIndex, operation.coupleIndex.first); 573 operationList_.try_emplace(operation.coupleIndex.first, fromInfo); 574 } else { 575 ThrowRepeatOperationError(operation.coupleIndex.first); 576 } 577 if (toIndexExist == operationList_.end()) { 578 toInfo.changeCount = 1; 579 auto iter = cachedTemp.find(operation.coupleIndex.first); 580 if (iter == cachedTemp.end()) { 581 iter = expiringTemp.find(operation.coupleIndex.first); 582 } 583 if (iter == expiringTemp.end()) { 584 return; 585 } 586 toInfo.node = iter->second.second; 587 toInfo.moveIn = true; 588 toInfo.fromDiffTo = operation.coupleIndex.first - operation.coupleIndex.second; 589 if (!operation.key.empty()) { 590 toInfo.key = operation.key; 591 } else { 592 toInfo.key = iter->second.first; 593 } 594 initialIndex = std::min(initialIndex, operation.coupleIndex.second); 595 operationList_.try_emplace(operation.coupleIndex.second, toInfo); 596 } else { 597 ThrowRepeatOperationError(operation.coupleIndex.second); 598 } 599 } 600 OperateExchange(V2::Operation & operation,int32_t & initialIndex,std::map<int32_t,LazyForEachChild> & cachedTemp,std::map<int32_t,LazyForEachChild> & expiringTemp)601 void LazyForEachBuilder::OperateExchange(V2::Operation& operation, int32_t& initialIndex, 602 std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp) 603 { 604 OperationInfo startInfo; 605 OperationInfo endInfo; 606 if (!ValidateIndex(operation.coupleIndex.first, operation.type) || 607 !ValidateIndex(operation.coupleIndex.second, operation.type)) { 608 return; 609 } 610 auto startIndexExist = operationList_.find(operation.coupleIndex.first); 611 auto endIndexExist = operationList_.find(operation.coupleIndex.second); 612 if (startIndexExist == operationList_.end()) { 613 auto iter = FindItem(operation.coupleIndex.first, cachedTemp, expiringTemp); 614 // if item can't be find in cachedItems_ nor expiringItem_, set UI node to null 615 if (iter == expiringTemp.end()) { 616 startInfo.node = nullptr; 617 } else { 618 startInfo.node = iter->second.second; 619 if (!operation.coupleKey.first.empty()) { 620 startInfo.key = operation.coupleKey.first; 621 } else { 622 startInfo.key = iter->second.first; 623 } 624 } 625 startInfo.isExchange = true; 626 initialIndex = std::min(initialIndex, operation.coupleIndex.second); 627 operationList_.try_emplace(operation.coupleIndex.second, startInfo); 628 } else { 629 ThrowRepeatOperationError(operation.coupleIndex.first); 630 } 631 if (endIndexExist == operationList_.end()) { 632 auto iter = FindItem(operation.coupleIndex.second, cachedTemp, expiringTemp); 633 // if item can't be find in cachedItems_ nor expiringItem_, set UI node to null 634 if (iter == expiringTemp.end()) { 635 endInfo.node = nullptr; 636 } else { 637 endInfo.node = iter->second.second; 638 if (!operation.coupleKey.second.empty()) { 639 endInfo.key = operation.coupleKey.second; 640 } else { 641 endInfo.key = iter->second.first; 642 } 643 } 644 endInfo.isExchange = true; 645 initialIndex = std::min(initialIndex, operation.coupleIndex.first); 646 operationList_.try_emplace(operation.coupleIndex.first, endInfo); 647 } else { 648 ThrowRepeatOperationError(operation.coupleIndex.second); 649 } 650 } 651 FindItem(int32_t index,std::map<int32_t,LazyForEachChild> & cachedTemp,std::map<int32_t,LazyForEachChild> & expiringTemp)652 std::map<int32_t, LazyForEachChild>::iterator LazyForEachBuilder::FindItem(int32_t index, 653 std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp) 654 { 655 auto iterOfCached = cachedTemp.find(index); 656 auto iterOfExpiring = expiringTemp.find(index); 657 // if UI node can't be find in cachedTemp, find it in expiringTemp 658 if (iterOfCached == cachedTemp.end() || iterOfCached->second.second == nullptr) { 659 return iterOfExpiring; 660 } else { 661 return iterOfCached; 662 } 663 } 664 OperateReload(std::map<int32_t,LazyForEachChild> & expiringTemp)665 void LazyForEachBuilder::OperateReload(std::map<int32_t, LazyForEachChild>& expiringTemp) 666 { 667 for (auto& [index, node] : expiringTemp) { 668 expiringItem_.emplace(node.first, LazyForEachCacheChild(index, node.second)); 669 } 670 operationList_.clear(); 671 OnDataReloaded(); 672 } 673 ThrowRepeatOperationError(int32_t index)674 void LazyForEachBuilder::ThrowRepeatOperationError(int32_t index) 675 { 676 TAG_LOGE(AceLogTag::ACE_LAZY_FOREACH, "Repeat Operation for index: %{public}d", index); 677 } 678 RecycleChildByIndex(int32_t index)679 void LazyForEachBuilder::RecycleChildByIndex(int32_t index) 680 { 681 auto iter = cachedItems_.find(index); 682 if (iter != cachedItems_.end()) { 683 if (!iter->second.second) { 684 return; 685 } 686 auto dummyNode = AceType::DynamicCast<RecycleDummyNode>(iter->second.second); 687 if (!dummyNode) { 688 return; 689 } 690 auto keyIter = expiringItem_.find(iter->second.first); 691 if (keyIter != expiringItem_.end() && keyIter->second.second) { 692 expiringItem_.erase(keyIter); 693 } 694 cachedItems_.erase(index); 695 } 696 } 697 PreBuild(int64_t deadline,const std::optional<LayoutConstraintF> & itemConstraint,bool canRunLongPredictTask)698 bool LazyForEachBuilder::PreBuild(int64_t deadline, const std::optional<LayoutConstraintF>& itemConstraint, 699 bool canRunLongPredictTask) 700 { 701 ACE_SYNTAX_SCOPED_TRACE("expiringItem_ count:[%zu]", expiringItem_.size()); 702 outOfBoundaryNodes_.clear(); 703 if (itemConstraint && !canRunLongPredictTask) { 704 return false; 705 } 706 auto count = OnGetTotalCount(); 707 std::unordered_map<std::string, LazyForEachCacheChild> cache; 708 std::set<int32_t> idleIndexes; 709 if (startIndex_ != -1 && endIndex_ != -1) { 710 CheckCacheIndex(idleIndexes, count); 711 } 712 713 ProcessCachedIndex(cache, idleIndexes); 714 715 bool result = true; 716 result = ProcessPreBuildingIndex(cache, deadline, itemConstraint, canRunLongPredictTask, idleIndexes); 717 if (!result) { 718 expiringItem_.swap(cache); 719 return result; 720 } 721 722 for (auto index : idleIndexes) { 723 result = PreBuildByIndex(index, cache, deadline, itemConstraint, canRunLongPredictTask); 724 if (!result) { 725 break; 726 } 727 } 728 expiringItem_.swap(cache); 729 return result; 730 } 731 RecordOutOfBoundaryNodes(int32_t index)732 void LazyForEachBuilder::RecordOutOfBoundaryNodes(int32_t index) 733 { 734 outOfBoundaryNodes_.emplace_back(index); 735 } 736 RecycleItemsOutOfBoundary()737 void LazyForEachBuilder::RecycleItemsOutOfBoundary() 738 { 739 for (const auto& i: outOfBoundaryNodes_) { 740 RecycleChildByIndex(i); 741 } 742 outOfBoundaryNodes_.clear(); 743 } 744 UpdateMoveFromTo(int32_t from,int32_t to)745 void LazyForEachBuilder::UpdateMoveFromTo(int32_t from, int32_t to) 746 { 747 if (moveFromTo_) { 748 moveFromTo_.value().second = to; 749 } else { 750 moveFromTo_ = { from, to }; 751 } 752 } 753 ResetMoveFromTo()754 void LazyForEachBuilder::ResetMoveFromTo() 755 { 756 moveFromTo_.reset(); 757 } 758 ConvertFormToIndex(int32_t index)759 int32_t LazyForEachBuilder::ConvertFormToIndex(int32_t index) 760 { 761 if (!moveFromTo_) { 762 return index; 763 } 764 if (moveFromTo_.value().second == index) { 765 return moveFromTo_.value().first; 766 } 767 if (moveFromTo_.value().first <= index && index < moveFromTo_.value().second) { 768 return index + 1; 769 } 770 if (moveFromTo_.value().second < index && index <= moveFromTo_.value().first) { 771 return index - 1; 772 } 773 return index; 774 } 775 } 776