Platform.Data.Doublets C++
Loading...
Searching...
No Matches
ILinksExtensions.h
Go to the documentation of this file.
2{
3 template <typename TStorage>
4 static void RunRandomCreations(TStorage& storage, typename TStorage::LinkAddressType amountOfCreations)
5 {
6 using namespace Platform::Data;
7 using namespace Platform::Random;
8 using namespace Platform::Ranges;
9 auto& randomGenerator64 = Random::RandomHelpers::Default;
10 for (typename TStorage::LinkAddressType i{0}; i < amountOfCreations; ++i)
11 {
12 Range<typename TStorage::LinkAddressType> linksAddressRange{0, Count(storage)};
13 auto source = Random::NextUInt64(randomGenerator64, linksAddressRange);
14 auto target = Random::NextUInt64(randomGenerator64, linksAddressRange);
15 GetOrCreate(storage, source, target);
16 }
17 }
18
19 template <typename TStorage>
20 static void RunRandomSearches(const TStorage& storage, typename TStorage::LinkAddressType amountOfSearches)
21 {
22 using namespace Platform::Data;
23 using namespace Platform::Random;
24 using namespace Platform::Ranges;
25 auto randomGenerator64 = Random::RandomHelpers::Default;
26 for (typename TStorage::LinkAddressType i{0}; i < amountOfSearches; ++i)
27 {
28 auto linksAddressRange = Range<typename TStorage::LinkAddressType>(0, Count(storage));
29 auto source = Random::NextUInt64(randomGenerator64, linksAddressRange);
30 auto target = Random::NextUInt64(randomGenerator64, linksAddressRange);
31 SearchOrDefault(storage, source, target);
32 }
33 }
34
35 template <typename TStorage>
36 static void RunRandomDeletions(TStorage& storage, typename TStorage::LinkAddressType amountOfDeletions)
37 {
38 using namespace Platform::Data;
39 using namespace Platform::Random;
40 using namespace Platform::Ranges;
41 auto& randomGenerator64 = RandomHelpers::Default;
42 auto linksCount = Count(storage);
43 typename TStorage::LinkAddressType min = amountOfDeletions > linksCount ? 0 : linksCount - amountOfDeletions;
44 for (typename TStorage::LinkAddressType i{0}; i < amountOfDeletions; ++i)
45 {
46 linksCount = Count(storage);
47 if (linksCount <= min)
48 {
49 break;
50 }
51 auto linksAddressRange = Range<typename TStorage::LinkAddressType>(min, linksCount);
52 auto linkAddress = Random::NextUInt64(randomGenerator64, linksAddressRange);
53 Delete(storage, linkAddress);
54 }
55 }
56
57 template <typename TStorage>
58 void TestRandomCreationsAndDeletions(TStorage& storage,
59 typename TStorage::LinkAddressType maximumOperationsPerCycle)
60 {
61 using namespace Platform::Random;
62 using namespace Platform::Ranges;
63 using namespace Platform::Interfaces;
64 for (auto N = 1; N < maximumOperationsPerCycle; N++)
65 {
66 auto& randomGen64 = RandomHelpers::Default;
67 typename TStorage::LinkAddressType created = 0;
68 typename TStorage::LinkAddressType deleted = 0;
69 for (auto i = 0; i < N; i++)
70 {
71 auto linksCount = Count(storage);
72 auto createPoint = Random::NextBoolean(randomGen64);
73 if (linksCount >= 2 && createPoint)
74 {
75 Ranges::Range linksAddressRange{1, linksCount};
76 auto source = Random::NextUInt64(randomGen64, linksAddressRange);
77 auto target = Random::NextUInt64(randomGen64, linksAddressRange); //-V3086
78 auto resultLink = GetOrCreate(storage, source, target);
79 if (resultLink > linksCount)
80 {
81 ++created;
82 }
83 }
84 else
85 {
86 Create(storage);
87 ++created;
88 }
89 }
90 auto count = Count(storage);
91 for (auto i = 0; i < count; i++)
92 {
93 auto link = i + 1;
94 {
95 DIRECT_METHOD_CALL(TStorage, storage, Update, link, 0, 0);
96 Delete(storage, link);
97 ++deleted;
98 }
99 }
100 }
101 }
102
103 template <typename TStorage>
104 static typename TStorage::LinkAddressType Delete(TStorage& storage, typename TStorage::LinkAddressType linkToDelete,
105 const typename TStorage::WriteHandlerType& handler)
106 {
107 if (Exists(storage, linkToDelete))
108 {
109 EnforceResetValues(storage, linkToDelete, handler);
110 }
111 return Delete(storage, linkToDelete, handler);
112 }
113
114 template <typename TStorage>
115 static typename TStorage::LinkAddressType First(const TStorage& storage)
116 {
117 constexpr auto constants = std::remove_cvref_t<decltype(storage)>::Constants;
118 auto $break{constants.Break};
119 typename TStorage::LinkAddressType firstLink = 0;
120 Expects(constants.Null != firstLink);
121 DIRECT_METHOD_CALL(
122 TStorage, storage, Each,
123 typename TStorage::LinkType{storage.Constants.Any, storage.Constants.Any, storage.Constants.Any},
124 [&firstLink, $break](const typename TStorage::LinkType& link) {
125 firstLink = link[0];
126 return $break;
127 });
128 Ensures(constants.Null != firstLink);
129 return firstLink;
130 }
131
132 template <typename TStorage>
133 static typename TStorage::HandlerParameterType SingleOrDefault(const TStorage& storage,
134 const typename TStorage::LinkType& query)
135 {
136 typename TStorage::LinkType result{};
137 auto count = 0;
138 constexpr auto constants = std::remove_cvref_t<decltype(storage)>::Constants;
139 auto linkHandler{[&result, &count, &constants](const typename TStorage::LinkType& link) {
140 if (count == 0)
141 {
142 result = link;
143 ++count;
144 return constants.Continue;
145 }
146 else
147 {
148 result = {};
149 return constants.Break;
150 }
151 }};
152 DIRECT_METHOD_CALL(TStorage, storage, Each, query, linkHandler);
153 return result;
154 }
155
156 template <typename TStorage>
157 static bool CheckPathExistence(const TStorage& storage,
158 std::convertible_to<typename TStorage::LinkAddressType> auto... pathPack)
159 {
160 typename TStorage::HandlerParameterType path{static_cast<typename TStorage::LinkdAddressType>(pathPack)...};
161 auto current = path[0];
162 if (!Exists(storage, current))
163 {
164 return false;
165 }
166 constexpr auto constants = std::remove_cvref_t<decltype(storage)>::Constants;
167 for (typename TStorage::LinkAddressType i{1}; i < std::ranges::size(path); ++i)
168 {
169 auto next = path[i];
170 auto values = GetLink(storage, current);
171 auto source = GetSource(storage, values);
172 auto target = GetTarget(storage, values);
173 if (target == source && next == source)
174 {
175 return false;
176 }
177 if ((source != next) && (target != next))
178 {
179 return false;
180 }
181 current = next;
182 }
183 return true;
184 }
185
186 template <typename TStorage>
187 static typename TStorage::LinkAddressType GetByKeys(
188 TStorage& storage, typename TStorage::LinkAddressType root,
189 std::convertible_to<typename TStorage::LinkAddressType> auto... pathPack)
190 {
191 typename TStorage::HandlerParameterType path{static_cast<typename TStorage::LinkdAddressType>(pathPack)...};
192 storage.EnsureLinkExists(root, "root");
193 auto currentLink = root;
194 for (typename TStorage::LinkAddressType i{0}; i < std::ranges::size(path); ++i)
195 {
196 currentLink = GetLink(storage, currentLink)[path[i]];
197 }
198 return currentLink;
199 }
200
201 template <typename TStorage>
202 static auto GetIndex(const TStorage& storage, const typename TStorage::LinkType& link)
203 {
204 return link[storage.Constants.IndexPart];
205 }
206
207 template <typename TStorage>
208 static typename TStorage::LinkAddressType GetSource(const TStorage& storage,
209 typename TStorage::LinkAddressType linkAddress)
210 {
211 return GetLink(storage, linkAddress)[storage.Constants.SourcePart];
212 }
213
214 template <typename TStorage>
215 static typename TStorage::LinkAddressType GetSource(const TStorage& storage,
216 const typename TStorage::LinkType& link)
217 {
218 return link[storage.Constants.SourcePart];
219 }
220
221 template <typename TStorage>
222 static typename TStorage::LinkAddressType GetTarget(const TStorage& storage,
223 typename TStorage::LinkAddressType linkAddress)
224 {
225 return GetLink(storage, linkAddress)[storage.Constants.TargetPart];
226 }
227
228 template <typename TStorage>
229 static typename TStorage::LinkAddressType GetTarget(const TStorage& storage,
230 const typename TStorage::LinkType& link)
231 {
232 return link[storage.Constants.TargetPart];
233 }
234
235 template <typename TStorage>
236 static std::vector<typename TStorage::LinkType> All(const TStorage& storage,
237 const typename TStorage::LinkType& restriction)
238 {
239 using namespace Platform::Collections;
240 auto $continue{storage.Constants.Continue};
241 std::vector<typename TStorage::LinkType> allLinks{};
242 DIRECT_METHOD_CALL(TStorage, storage, Each, restriction,
243 [&allLinks, $continue](const typename TStorage::LinkType& link) {
244 allLinks.push_back(link);
245 return $continue;
246 });
247 return allLinks;
248 }
249
250 template <typename TStorage>
251 static auto All(const TStorage& storage)
252 {
253 return All(storage, typename TStorage::LinkType{});
254 }
255
256 template <typename TStorage, typename... TRestrictions>
257 requires(sizeof...(TRestrictions) > 0 &&
258 (std::convertible_to<TRestrictions, typename TStorage::LinkAddressType> && ...))
259 static auto All(const TStorage& storage, TRestrictions... restrictionPack)
260 {
261 typename TStorage::LinkType restriction{static_cast<typename TStorage::LinkAddressType>(restrictionPack)...};
262 return All(storage, restriction);
263 }
264
265 template <typename TStorage>
266 static typename TStorage::LinkAddressType AllIndices(TStorage& storage,
267 const typename TStorage::LinkType& restriction)
268 {
269 std::vector<typename TStorage::LinkType> allIndices{};
270 auto usages = std::vector<typename TStorage::LinkType>();
271 auto $continue = storage.Constants.Continue;
272 DIRECT_METHOD_CALL(TStorage, storage, Each, restriction,
273 [&allIndices, $continue](const typename TStorage::LinkType& link) {
274 allIndices.push_back(link);
275 return $continue;
276 });
277 return allIndices;
278 }
279
280 template <typename TStorage>
281 static void EnsureLinkExists(TStorage& storage, const typename TStorage::LinkType& restriction)
282 {
283 for (auto i{0}; i < restriction.Count(); ++i)
284 {
285 if (!storage.Exists(restriction[i]))
286 {
287 throw ArgumentLinkDoesNotExistsException<typename TStorage::LinkAddressType>(
288 restriction[i],
289 std::string("sequence[").append(Platform::Converters::To<std::string>(i)).append(1, ']'));
290 }
291 }
292 }
293
294 template <typename TStorage>
295 static bool Exists(TStorage& storage, typename TStorage::LinkAddressType source,
296 typename TStorage::LinkAddressType target)
297 {
298 return DIRECT_METHOD_CALL(TStorage, storage, Count,
299 typename TStorage::LinkType{storage.Constants.Any, source, target}) > 0;
300 }
301
302 template <typename TStorage>
303 static void EnsureInnerReferenceExists(TStorage& storage, typename TStorage::LinkAddressType reference,
304 std::string argumentName)
305 {
306 using namespace Platform::Exceptions;
307 if (storage.Constants.IsInternalReference(reference) && !storage.Exists(reference))
308 {
309 throw ArgumentLinkDoesNotExistsException<typename TStorage::LinkAddressType>(reference, argumentName);
310 }
311 }
312
313 template <typename TStorage>
314 static void EnsureInnerReferenceExists(TStorage& storage, const typename TStorage::LinkType& restriction,
315 std::string argumentName)
316 {
317 using namespace Platform::Exceptions;
318 for (std::int32_t i = 0; i < restriction.Count(); ++i)
319 {
320 storage.EnsureInnerReferenceExists(restriction[i], argumentName);
321 }
322 }
323
324 template <typename TStorage>
325 static void EnsureLinkIsAnyOrExists(TStorage& storage, const typename TStorage::LinkType& restriction)
326 {
327 using namespace Platform::Exceptions;
328 auto any = storage.Constants.Any;
329 for (auto i{0}; i < restriction.Count(); ++i)
330 {
331 if ((any != restriction[i]) && !storage.Exists(restriction[i]))
332 {
333 throw ArgumentLinkDoesNotExistsException<typename TStorage::LinkAddressType>(
334 restriction[i],
335 std::string("sequence[").append(Platform::Converters::To<std::string>(i)).append(1, ']'));
336 }
337 }
338 }
339
340 template <typename TStorage>
341 static void EnsureLinkIsAnyOrExists(TStorage& storage, typename TStorage::LinkAddressType linkAddress,
342 std::string argumentName)
343 {
344 using namespace Platform::Exceptions;
345 if ((storage.Constants.Any != linkAddress) && !storage.Exists(linkAddress))
346 {
347 throw ArgumentLinkDoesNotExistsException<typename TStorage::LinkAddressType>(linkAddress, argumentName);
348 }
349 }
350
351 template <typename TStorage>
352 static void EnsureLinkIsItselfOrExists(TStorage& storage, typename TStorage::LinkAddressType linkAddress,
353 std::string argumentName)
354 {
355 using namespace Platform::Exceptions;
356 if ((storage.Constants.Itself != linkAddress) && !storage.Exists(linkAddress))
357 {
358 throw ArgumentLinkDoesNotExistsException<typename TStorage::LinkAddressType>(linkAddress, argumentName);
359 }
360 }
361
362 template <typename TStorage>
363 static void EnsureDoesNotExists(TStorage& storage, typename TStorage::LinkAddressType source,
364 typename TStorage::LinkAddressType target)
365 {
366 using namespace Platform::Exceptions;
367 if (storage.Exists(source, target))
368 {
369 throw Platform::Exceptions::LinkWithSameValueAlreadyExistsException();
370 }
371 }
372
373 template <typename TStorage>
374 static void EnsureNoUsages(TStorage& storage, typename TStorage::LinkAddressType linkAddress)
375 {
376 using namespace Platform::Exceptions;
377 if (storage.HasUsages(linkAddress))
378 {
379 throw ArgumentLinkHasDependenciesException<typename TStorage::LinkAddressType>(linkAddress);
380 }
381 }
382
383 template <typename TStorage>
384 static void EnsureCreated(TStorage& storage, std::function<typename TStorage::LinkAddressType()> creator,
385 const typename TStorage::LinkType& addresses)
386 {
387 using Address = typename TStorage::LinkAddressType;
388 std::unordered_set<Address> remaining;
389 for (auto address : addresses)
390 {
391 if (address != storage.Constants.Null && address <= storage.Constants.InternalReferencesRange.Maximum &&
392 !Platform::Data::Exists(storage, address))
393 {
394 remaining.insert(address);
395 }
396 }
397 const auto requested = remaining;
398 std::unordered_set<Address> created;
399 // Retain intermediate allocations until every requested address exists:
400 // freeing one early could make the allocator return it repeatedly.
401 while (!remaining.empty())
402 {
403 auto address = creator();
404 if (address == storage.Constants.Null || !created.insert(address).second)
405 {
406 throw std::runtime_error("The creator did not allocate a new link");
407 }
408 remaining.erase(address);
409 }
410 for (auto address : created)
411 {
412 if (!requested.contains(address))
413 {
414 Platform::Data::Update(
415 storage, typename TStorage::LinkType{address},
416 typename TStorage::LinkType{address, storage.Constants.Null, storage.Constants.Null});
417 Platform::Data::Delete(storage, address);
418 }
419 }
420 }
421
422 template <typename TStorage>
423 static void EnsureCreated(TStorage& storage, const typename TStorage::LinkType& addresses)
424 {
425 EnsureCreated(storage, std::function<typename TStorage::LinkAddressType()>{[&storage] {
426 return Platform::Data::Create(storage);
427 }},
428 addresses);
429 }
430
431 template <typename TStorage>
432 static void EnsurePointsCreated(TStorage& storage, const typename TStorage::LinkType& addresses)
433 {
434 EnsureCreated(storage, std::function<typename TStorage::LinkAddressType()>{[&storage] {
435 auto point = Platform::Data::Create(storage);
436 return Platform::Data::Update(storage, typename TStorage::LinkType{point},
437 typename TStorage::LinkType{point, point, point});
438 }},
439 addresses);
440 }
441
442 template <typename TStorage>
443 static typename TStorage::LinkAddressType CountUsages(TStorage& storage,
444 typename TStorage::LinkAddressType linkAddress)
445 {
446 constexpr auto constants = std::remove_cvref_t<decltype(storage)>::Constants;
447 auto values = GetLink(storage, linkAddress);
448 auto usagesAsSource = DIRECT_METHOD_CALL(
449 TStorage, storage, Count, typename TStorage::LinkType{constants.Any, storage, linkAddress, constants.Any});
450 if (linkAddress == GetSource(storage, values))
451 {
452 --usagesAsSource;
453 }
454 auto usagesAsTarget = DIRECT_METHOD_CALL(
455 TStorage, storage, Count, typename TStorage::LinkType{constants.Any, storage, constants.Any, linkAddress});
456 if (linkAddress == GetTarget(storage, values))
457 {
458 --usagesAsTarget;
459 }
460 return usagesAsSource + usagesAsTarget;
461 }
462
463 template <typename TStorage>
464 static bool HasUsages(TStorage& storage, typename TStorage::LinkAddressType linkAddress)
465 {
466 return CountUsages(storage, linkAddress) > 0;
467 }
468
469 template <typename TStorage>
470 typename TStorage::LinkAddressType SearchOrDefault(TStorage& storage, typename TStorage::LinkAddressType source,
471 typename TStorage::LinkAddressType target)
472 {
473 constexpr auto constants = std::remove_cvref_t<decltype(storage)>::Constants;
474 auto _break = constants.Break;
475 typename TStorage::LinkAddressType searchedLinkAddress{};
476 DIRECT_METHOD_CALL(TStorage, storage, Each, typename TStorage::LinkType{storage.Constants.Any, source, target},
477 [&searchedLinkAddress, _break](const typename TStorage::LinkType& link) {
478 searchedLinkAddress = link[0];
479 return _break;
480 });
481 return searchedLinkAddress;
482 }
483 template <typename TStorage>
484 auto CreatePoint(TStorage& storage)
485 {
486 auto point = Platform::Data::Create(storage);
487 return Update(storage, point, point, point);
488 }
489
490 template <typename TStorage>
491 static typename TStorage::LinkAddressType CreatePoint(TStorage& storage,
492 const typename TStorage::WriteHandlerType& handler)
493 {
494 constexpr auto constants = std::remove_cvref_t<decltype(storage)>::Constants;
495 WriteHandlerState<TStorage> handlerState{constants.Continue, constants.Break, handler};
496 typename TStorage::LinkAddressType linkAddress;
497 typename TStorage::LinkAddressType HandlerWrapper = [&linkAddress,
498 &handlerState](const typename TStorage::LinkType& before,
499 const typename TStorage::LinkType& after) {
500 linkAddress = after[0];
501 return handlerState.Handle(before, after);
502 };
503 handlerState.Apply(
504 DIRECT_METHOD_CALL(TStorage, storage, Create, typename TStorage::LinkType{}, HandlerWrapper));
505 return handlerState.Apply(
506 DIRECT_METHOD_CALL(TStorage, storage, Update, linkAddress, linkAddress, linkAddress, HandlerWrapper));
507 }
508
509 template <typename TStorage>
510 typename TStorage::LinkAddressType CreateAndUpdate(TStorage& storage, typename TStorage::LinkAddressType source,
511 typename TStorage::LinkAddressType target)
512 {
513 auto $continue{storage.Constants.Continue};
514 typename TStorage::LinkAddressType linkAddress;
515 return CreateAndUpdate(
516 storage, source, target,
517 [&linkAddress, $continue](const typename TStorage::LinkType&, const typename TStorage::LinkType& after) {
518 linkAddress = after[0];
519 return $continue;
520 });
521 }
522
523 template <typename TStorage>
524 static typename TStorage::LinkAddressType CreateAndUpdate(TStorage& storage,
525 typename TStorage::LinkAddressType source,
526 typename TStorage::LinkAddressType target,
527 const typename TStorage::WriteHandlerType& handler)
528 {
529 constexpr auto constants = std::remove_cvref_t<decltype(storage)>::Constants;
530 typename TStorage::LinkAddressType createdLinkAddress;
531 WriteHandlerState<TStorage> handlerState{constants.Continue, constants.Break, handler};
532 handlerState.Apply(
533 DIRECT_METHOD_CALL(TStorage, storage, Create, typename TStorage::LinkType{},
534 [&createdLinkAddress, &handlerState](const typename TStorage::LinkType& before,
535 const typename TStorage::LinkType& after) {
536 createdLinkAddress = after[0];
537 return handlerState.Handle(before, after);
538 }));
539 return handlerState.Apply(Update(storage, createdLinkAddress, source, target, handlerState.Handler));
540 }
541
542 template <typename TStorage>
543 typename TStorage::LinkAddressType Update(TStorage& storage,
544 CArray<typename TStorage::LinkAddressType> auto&& restriction,
545 CArray<typename TStorage::LinkAddressType> auto&& substitution)
546 {
547 auto $continue{storage.Constants.Continue};
548 typename TStorage::LinkAddressType updatedLinkAddress;
549 DIRECT_METHOD_CALL(TStorage, storage, Update, restriction, substitution,
550 [&updatedLinkAddress, $continue](const typename TStorage::LinkType&,
551 const typename TStorage::LinkType& after) {
552 updatedLinkAddress = after[0];
553 return $continue;
554 });
555 return updatedLinkAddress;
556 }
557
558 template <typename TStorage>
559 static typename TStorage::LinkAddressType Update(TStorage& storage, const typename TStorage::LinkType& restriction,
560 const typename TStorage::WriteHandlerType& handler)
561 {
562 const auto length{std::ranges::size(restriction)};
563 if (length == 2)
564 {
565 return MergeAndDelete(storage, restriction[0], restriction[1], handler);
566 }
567 else if (length == 4)
568 {
569 return UpdateOrCreateOrGet(storage, restriction[0], restriction[1], restriction[2], restriction[3],
570 handler);
571 }
572 else
573 {
574 return Update(storage, restriction[0], restriction[1], restriction[2], handler);
575 }
576 }
577
578 template <typename TStorage>
579 static typename TStorage::LinkAddressType Update(TStorage& storage, typename TStorage::LinkAddressType linkAddress,
580 typename TStorage::LinkAddressType newSource,
581 typename TStorage::LinkAddressType newTarget,
582 const typename TStorage::WriteHandlerType& handler)
583 {
584 return DIRECT_METHOD_CALL(TStorage, storage, Update, typename TStorage::LinkType{linkAddress},
585 typename TStorage::LinkType{linkAddress, newSource, newTarget}, handler);
586 // return std::is_abstract<TStorage>::value ? DIRECT_METHOD_CALL(TStorage, storage, Update,typename
587 // TStorage::LinkType{linkAddress}, typename TStorage::LinkType{linkAddress, newSource, newTarget},
588 // handler) : storage.TStorage::Update(typename TStorage::LinkType{linkAddress}, typename
589 // TStorage::LinkType{linkAddress, newSource, newTarget}, handler); if constexpr
590 // (std::is_abstract<TStorage>::value) {
591 // return DIRECT_METHOD_CALL(TStorage, storage, Update,typename TStorage::LinkType{linkAddress},
592 // typename TStorage::LinkType{linkAddress, newSource, newTarget}, handler);
593 // } else {
594 // return storage.TStorage::Update(typename TStorage::LinkType{linkAddress}, typename
595 // TStorage::LinkType{linkAddress, newSource, newTarget}, handler);
596 // }
597 }
598
599 template <typename TStorage>
600 static typename TStorage::LinkAddressType Update(TStorage& storage, typename TStorage::LinkAddressType linkAddress,
601 typename TStorage::LinkAddressType newSource,
602 typename TStorage::LinkAddressType newTarget)
603 {
604 auto $continue{storage.Constants.Continue};
605 typename TStorage::LinkAddressType updatedLinkAddress;
606 Update(storage, linkAddress, newSource, newTarget,
607 [&updatedLinkAddress, $continue](const typename TStorage::LinkType&,
608 const typename TStorage::LinkType& after) {
609 updatedLinkAddress = after[0];
610 return $continue;
611 });
612 return updatedLinkAddress;
613 }
614
615 template <typename TStorage>
616 static typename TStorage::LinkAddressType Update(TStorage& storage, const typename TStorage::LinkType& restriction)
617 {
618 auto $continue{storage.Constants.Continue};
619 typename TStorage::LinkAddressType updatedLinkAddress;
620 return Update(storage, restriction,
621 [&updatedLinkAddress, $continue](const typename TStorage::LinkType&,
622 const typename TStorage::LinkType& after) {
623 updatedLinkAddress = after;
624 return $continue;
625 });
626 }
627
628 template <typename TStorage>
629 static typename TStorage::LinkAddressType Update(
630 TStorage& storage, const typename TStorage::WriteHandlerType& handler,
631 std::convertible_to<typename TStorage::LinkAddressType> auto... restrictionPack)
632 {
633 typename TStorage::HandlerParameterType restriction{
634 static_cast<typename TStorage::HandlerParameterType>(restrictionPack)...};
635 return Update(storage, restriction, handler);
636 }
637 //
638 template <typename TStorage>
639 static typename TStorage::LinkType ResolveConstantAsSelfReference(const TStorage& storage,
640 typename TStorage::LinkAddressType constant,
641 const typename TStorage::LinkType& restriction,
642 const typename TStorage::LinkType& substitution)
643 {
644 constexpr auto constants = std::remove_cvref_t<decltype(storage)>::Constants;
645 auto restrictionIndex = GetIndex(storage, restriction);
646 auto substitutionIndex = GetIndex(storage, substitution);
647 if (constants.Null == substitutionIndex)
648 {
649 substitutionIndex = restrictionIndex;
650 }
651 auto source = GetSource(storage, substitution);
652 auto target = GetTarget(storage, substitution);
653 source = constant == source ? substitutionIndex : source;
654 target = constant == target ? substitutionIndex : target;
655 return typename TStorage::LinkType{substitutionIndex, source, target};
656 }
657
658 template <typename TStorage>
659 typename TStorage::LinkAddressType GetOrCreate(TStorage& storage, typename TStorage::LinkAddressType source,
660 typename TStorage::LinkAddressType target)
661 {
662 constexpr auto constants = std::remove_cvref_t<decltype(storage)>::Constants;
663 auto link = SearchOrDefault(storage, source, target);
664 if (link == constants.Null)
665 {
666 link = CreateAndUpdate(storage, source, target);
667 }
668 return link;
669 }
670
671 template <typename TStorage>
672 static typename TStorage::LinkAddressType UpdateOrCreateOrGet(TStorage& storage,
673 typename TStorage::LinkAddressType source,
674 typename TStorage::LinkAddressType target,
675 typename TStorage::LinkAddressType newSource,
676 typename TStorage::LinkAddressType newTarget,
677 const typename TStorage::WriteHandlerType& handler)
678 {
679 auto link = SearchOrDefault(storage, source, target);
680 if (storage.Constants.Null == link)
681 {
682 return CreateAndUpdate(storage, newSource, newTarget, handler);
683 }
684 if ((source == newSource) && (target == newTarget))
685 {
686 return link;
687 }
688 return Update(storage, link, newSource, newTarget, handler);
689 }
690
691 template <typename TStorage>
692 static typename TStorage::LinkAddressType UpdateOrCreateOrGet(TStorage& storage,
693 typename TStorage::LinkAddressType source,
694 typename TStorage::LinkAddressType target,
695 typename TStorage::LinkAddressType newSource,
696 typename TStorage::LinkAddressType newTarget)
697 {
698 auto $continue = storage.Constants.Continue;
699 typename TStorage::LinkAddressType resultLink;
700 UpdateOrCreateOrGet(
701 storage, source, target, newSource, newTarget,
702 [&resultLink, $continue](const typename TStorage::LinkType&, const typename TStorage::LinkType& after) {
703 resultLink = after[0];
704 return $continue;
705 });
706 return resultLink;
707 }
708
709 template <typename TStorage>
710 typename TStorage::LinkAddressType DeleteIfExists(TStorage& storage, typename TStorage::LinkAddressType source,
711 typename TStorage::LinkAddressType target)
712 {
713 constexpr auto constants = std::remove_cvref_t<decltype(storage)>::Constants;
714 auto linkAddress = storage.SearchOrDefault(source, target);
715 if (linkAddress != constants.Null)
716 {
717 return Delete(storage, linkAddress);
718 }
719 return constants.Null;
720 }
721
722 template <typename TStorage>
723 static void DeleteMany(TStorage& storage, const typename TStorage::LinkType& linkAddressesToDelete)
724 {
725 for (auto linkAddress : linkAddressesToDelete)
726 {
727 Delete(storage, linkAddress);
728 }
729 }
730
731 template <typename TStorage>
732 static typename TStorage::LinkAddressType DeleteAllUsages(TStorage& storage,
733 typename TStorage::LinkAddressType linkIndex,
734 const typename TStorage::WriteHandlerType& handler)
735 {
736 constexpr auto constants = std::remove_cvref_t<decltype(storage)>::Constants;
737 auto any = constants.Any;
738 auto $continue = storage.Constants.Continue;
739 auto $break = storage.Constants.Break;
740 auto usagesAsSourceQuery = typename TStorage::LinkType{any, linkIndex, any};
741 auto usagesAsTargetQuery = typename TStorage::LinkType{any, any, linkIndex};
742 auto usages = std::vector<typename TStorage::LinkType>();
743 DIRECT_METHOD_CALL(TStorage, storage, Each, usagesAsSourceQuery,
744 [&usages, $continue](const typename TStorage::LinkType& link) {
745 usages.push_back(link);
746 return $continue;
747 });
748 DIRECT_METHOD_CALL(TStorage, storage, Each, usagesAsTargetQuery, [&usages, $continue](auto&& link) {
749 usages.push_back(link);
750 return $continue;
751 });
752 WriteHandlerState<TStorage> handlerState{$continue, $break, handler};
753 for (auto usage : usages)
754 {
755 auto usageAddress{GetIndex(storage, usage)};
756 if (linkIndex == usageAddress || Exists(storage, usageAddress))
757 {
758 continue;
759 }
760 auto result = DIRECT_METHOD_CALL(TStorage, storage, Delete, usage, handlerState.Handler);
761 handlerState.Apply(result);
762 }
763 return handlerState.Result;
764 }
765
766 template <typename TStorage>
767 static void DeleteAllUsages(TStorage& storage, typename TStorage::LinkAddressType linkIndex)
768 {
769 DeleteAllUsages(storage, linkIndex, nullptr);
770 }
771
772 template <typename TStorage>
773 auto DeleteAll(TStorage& storage)
774 {
775 auto handler = [](typename TStorage::LinkType, typename TStorage::LinkType) {
776 return typename TStorage::LinkAddressType{};
777 };
778 auto any = storage.Constants.Any;
779 for (auto count = Count(storage); count != storage.Constants.Null; count = Count(storage))
780 {
781 DIRECT_METHOD_CALL(TStorage, storage, Delete, {count, any, any}, handler);
782 }
783 }
784
785 template <typename TStorage>
786 static bool AreValuesReset(const TStorage& storage, typename TStorage::LinkAddressType linkIndex)
787 {
788 auto nullConstant = storage.Constants.Null;
789 auto link = GetLink(storage, linkIndex);
790 for (std::size_t i = 1; i < std::ranges::size(link); ++i)
791 {
792 if (nullConstant != link[i])
793 {
794 return false;
795 }
796 }
797 return true;
798 }
799
800 template <typename TStorage>
801 typename TStorage::LinkAddressType ResetValues(TStorage& storage, typename TStorage::LinkAddressType linkAddress,
802 const typename TStorage::WriteHandlerType& handler)
803 {
804 return Update(storage, linkAddress, 0, 0, handler);
805 }
806
807 template <typename TStorage>
808 void ResetValues(TStorage& storage, typename TStorage::LinkAddressType linkAddress)
809 {
810 auto $break = storage.Constants.Break;
811 ResetValues(storage, linkAddress, nullptr);
812 }
813
814 template <typename TStorage>
815 static typename TStorage::LinkAddressType EnforceResetValues(TStorage& storage,
816 typename TStorage::LinkAddressType linkIndex,
817 const typename TStorage::WriteHandlerType& handler)
818 {
819 if (!AreValuesReset(storage, linkIndex))
820 {
821 return ResetValues(storage, linkIndex, handler);
822 }
823 return storage.Constants.Continue;
824 }
825
826 template <typename TStorage>
827 static typename TStorage::LinkAddressType EnforceResetValues(TStorage& storage,
828 typename TStorage::LinkAddressType linkIndex)
829 {
830 return EnforceResetValues(storage, linkIndex, nullptr);
831 }
832
833 template <typename TStorage>
834 static typename TStorage::LinkAddressType MergeUsages(TStorage& storage,
835 typename TStorage::LinkAddressType oldLinkIndex,
836 typename TStorage::LinkAddressType newLinkIndex,
837 const typename TStorage::WriteHandlerType& handler)
838 {
839 if (newLinkIndex == oldLinkIndex)
840 {
841 return newLinkIndex;
842 }
843 constexpr auto constants = std::remove_cvref_t<decltype(storage)>::Constants;
844 auto usagesAsSource = All(storage, typename TStorage::LinkType(constants.Any, oldLinkIndex, constants.Any));
845 WriteHandlerState<TStorage> handlerState{constants.Continue, constants.Break, handler};
846 for (auto i{0}; i < std::ranges::size(usagesAsSource); ++i)
847 {
848 auto usageAsSource = usagesAsSource[i];
849 if (oldLinkIndex == GetIndex(storage, usageAsSource))
850 {
851 continue;
852 }
853 typename TStorage::LinkType restriction{GetIndex(storage, usageAsSource)};
854 typename TStorage::LinkType substitution = (newLinkIndex, GetTarget(storage, usageAsSource));
855 handlerState.Apply(
856 DIRECT_METHOD_CALL(TStorage, storage, Update, restriction, substitution, handlerState.Handler));
857 }
858 auto usagesAsTarget = All(storage, typename TStorage::LinkType(constants.Any, constants.Any, oldLinkIndex));
859 for (auto i{0}; i < std::ranges::size(usagesAsTarget); ++i)
860 {
861 auto usageAsTarget = usagesAsTarget[i];
862 if (oldLinkIndex == GetIndex(storage, usageAsTarget))
863 {
864 continue;
865 }
866 auto substitution = typename TStorage::LinkType(GetTarget(storage, usageAsTarget), newLinkIndex);
867 handlerState.Apply(
868 DIRECT_METHOD_CALL(TStorage, storage, Update, usageAsTarget, substitution, handlerState.Handler));
869 }
870 return handlerState.Result;
871 }
872
873 template <typename TStorage>
874 static void MergeUsages(TStorage& storage, typename TStorage::LinkAddressType oldLinkIndex,
875 typename TStorage::LinkAddressType newLinkIndex)
876 {
877 MergeUsages(storage, oldLinkIndex, newLinkIndex, nullptr);
878 }
879
880 template <typename TStorage>
881 static typename TStorage::LinkAddressType MergeAndDelete(TStorage& storage,
882 typename TStorage::LinkAddressType oldLinkIndex,
883 typename TStorage::LinkAddressType newLinkIndex)
884 {
885 if (newLinkIndex != oldLinkIndex)
886 {
887 MergeUsages(storage, oldLinkIndex, newLinkIndex);
888 Delete(storage, oldLinkIndex);
889 }
890 return newLinkIndex;
891 }
892
893 template <typename TStorage>
894 static typename TStorage::LinkAddressType MergeAndDelete(TStorage& storage,
895 typename TStorage::LinkAddressType oldLinkIndex,
896 typename TStorage::LinkAddressType newLinkIndex,
897 const typename TStorage::WriteHandlerType& handler)
898 {
899 constexpr auto constants = std::remove_cvref_t<decltype(storage)>::Constants;
900 WriteHandlerState<TStorage> handlerState{constants.Continue, constants.Break, handler};
901 if (newLinkIndex != oldLinkIndex)
902 {
903 handlerState.Apply(MergeUsages(storage, oldLinkIndex, newLinkIndex, handlerState.Handler));
904 handlerState.Apply(Delete(storage, oldLinkIndex, handlerState.Handler));
905 }
906 return handlerState.Result;
907 }
908
909 template <typename TStorage>
910 static std::string Format(TStorage& storage, const typename TStorage::LinkType& link)
911 {
912 constexpr auto constants = std::remove_cvref_t<decltype(storage)>::Constants;
913 return std::string{}
914 .append("(")
915 .append(std::to_string(GetIndex(storage, link)))
916 .append("): ")
917 .append("(")
918 .append(std::to_string(GetSource(storage, link)))
919 .append(")")
920 .append(" -> ")
921 .append("(")
922 .append(std::to_string(GetTarget(storage, link)))
923 .append(")");
924 }
925
926 template <typename TStorage>
927 std::string Format(TStorage& storage, typename TStorage::LinkAddressType linkAddress)
928 {
929 return Format(GetLink(storage, linkAddress));
930 }
931
932 template <typename TStorage>
933 typename TStorage::LinkAddressType HasUsages(TStorage& storage, typename TStorage::LinkAddressType linkAddress)
934 {
935 return storage.CountUsages(linkAddress) != 0;
936 }
937
938 template <typename TStorage>
939 static void DeleteByQuery(TStorage& storage, typename TStorage::LinkType query)
940 {
941 typename TStorage::LinkType queryResult;
942 DIRECT_METHOD_CALL(TStorage, storage, Each, query,
943 [&](typename TStorage::LinkType vec) -> typename TStorage::LinkAddressType {
944 queryResult.push_back(vec[storage.Constants.IndexPart]);
945 return storage.Constants.Continue;
946 });
947
948 for (auto link : queryResult)
949 {
950 Delete(storage, link);
951 }
952 }
953
954} // namespace Platform::Data::Doublets
Definition TargetMatcher.h:2
TStorage::LinkAddressType SearchOrDefault(TStorage &storage, typename TStorage::LinkAddressType source, typename TStorage::LinkAddressType target)
Definition ILinksExtensions.h:470
TStorage::LinkAddressType DeleteIfExists(TStorage &storage, typename TStorage::LinkAddressType source, typename TStorage::LinkAddressType target)
Definition ILinksExtensions.h:710
auto CreatePoint(TStorage &storage)
Definition ILinksExtensions.h:484
TStorage::LinkAddressType ResetValues(TStorage &storage, typename TStorage::LinkAddressType linkAddress, const typename TStorage::WriteHandlerType &handler)
Definition ILinksExtensions.h:801
TStorage::LinkAddressType GetOrCreate(TStorage &storage, typename TStorage::LinkAddressType source, typename TStorage::LinkAddressType target)
Definition ILinksExtensions.h:659
TStorage::LinkAddressType CreateAndUpdate(TStorage &storage, typename TStorage::LinkAddressType source, typename TStorage::LinkAddressType target)
Definition ILinksExtensions.h:510
auto DeleteAll(TStorage &storage)
Definition ILinksExtensions.h:773
void TestRandomCreationsAndDeletions(TStorage &storage, typename TStorage::LinkAddressType maximumOperationsPerCycle)
Definition ILinksExtensions.h:58
TStorage::LinkAddressType Update(TStorage &storage, CArray< typename TStorage::LinkAddressType > auto &&restriction, CArray< typename TStorage::LinkAddressType > auto &&substitution)
Definition ILinksExtensions.h:543
Definition TargetMatcher.h:2