Platform.Data.Doublets C++
Loading...
Searching...
No Matches
SplitMemoryLinksBase.h
Go to the documentation of this file.
2{
3 template <typename TSelf, typename TLinksOptions, typename TMemory, typename TInternalSourcesTreeMethods,
4 typename TInternalLinksSourcesLinkedListMethods, typename TInternalTargetsTreeMethods,
5 typename TExternalSourcesTreeMethods, typename TExternalTargetsTreeMethods,
6 typename TUnusedLinksListMethods, typename... TBase>
7 struct SplitMemoryLinksBase : public Interfaces::Polymorph<TSelf, TBase...>
8 {
9 public:
10 using LinksOptionsType = TLinksOptions;
11 using LinkAddressType = typename LinksOptionsType::LinkAddressType;
12 using LinkType = typename LinksOptionsType::LinkType;
13 using WriteHandlerType = typename LinksOptionsType::WriteHandlerType;
14 using ReadHandlerType = typename LinksOptionsType::ReadHandlerType;
15 static constexpr LinksConstants<LinkAddressType> Constants = LinksOptionsType::Constants;
16 static constexpr bool UseLinkedList = false;
17
18 public:
19 TMemory _dataMemory;
20 TMemory _indexMemory;
23 std::unique_ptr<TInternalSourcesTreeMethods> InternalSourcesTreeMethods;
24 std::unique_ptr<TInternalLinksSourcesLinkedListMethods> InternalSourcesListMethods;
25 std::unique_ptr<TInternalTargetsTreeMethods> InternalTargetsTreeMethods;
26 std::unique_ptr<TExternalSourcesTreeMethods> ExternalSourcesTreeMethods;
27 std::unique_ptr<TExternalTargetsTreeMethods> ExternalTargetsTreeMethods;
28 std::unique_ptr<TUnusedLinksListMethods> UnusedLinksListMethods;
29 std::byte* _header;
30 std::byte* _linksDataParts;
31 std::byte* _linksIndexParts;
32
33 public:
39
45
51
57
58 public:
60 {
61 return *reinterpret_cast<LinksHeader<LinkAddressType>*>(_header);
62 }
63
68
70 {
71 return this->GetHeaderReference().AllocatedLinks - this->GetHeaderReference().FreeLinks;
72 }
73
74 public:
75 static constexpr std::size_t LinkDataPartSizeInBytes = sizeof(RawLinkDataPart<LinkAddressType>);
76
77 static constexpr std::size_t LinkIndexPartSizeInBytes = sizeof(RawLinkIndexPart<LinkAddressType>);
78
79 static constexpr std::size_t LinkHeaderSizeInBytes = sizeof(LinksHeader<LinkAddressType>);
80
81 static constexpr std::size_t DefaultLinksSizeStep = 1 * 1024 * 1024;
82
83 SplitMemoryLinksBase(TMemory&& dataMemory, TMemory&& indexMemory)
84 : SplitMemoryLinksBase(std::move(dataMemory), std::move(indexMemory), DefaultLinksSizeStep)
85 {
86 }
87
88 SplitMemoryLinksBase(TMemory&& dataMemory, TMemory&& indexMemory, std::uint64_t memoryReservationStep)
89 : _dataMemory{std::move(dataMemory)}, _indexMemory{std::move(indexMemory)},
92 {
93
95 }
96
97 void Init(TMemory& dataMemory, TMemory& indexMemory)
98 {
99 if (indexMemory.ReservedCapacity() < LinkHeaderSizeInBytes)
100 {
101 indexMemory.ReservedCapacity(LinkHeaderSizeInBytes);
102 }
103 SetPointers(dataMemory, indexMemory);
104 auto allocatedLinks{this->GetHeaderReference().AllocatedLinks};
105 auto minimumDataReservedCapacity = (allocatedLinks + 1) * LinkDataPartSizeInBytes;
106 if (minimumDataReservedCapacity < dataMemory.UsedCapacity())
107 {
108 minimumDataReservedCapacity = dataMemory.UsedCapacity();
109 }
110 if (minimumDataReservedCapacity < _dataMemoryReservationStepInBytes)
111 {
112 minimumDataReservedCapacity = _dataMemoryReservationStepInBytes;
113 }
114 auto minimumIndexReservedCapacity = allocatedLinks * LinkIndexPartSizeInBytes + LinkHeaderSizeInBytes;
115 if (minimumIndexReservedCapacity < indexMemory.UsedCapacity())
116 {
117 minimumIndexReservedCapacity = indexMemory.UsedCapacity();
118 }
119 if (minimumIndexReservedCapacity < _indexMemoryReservationStepInBytes)
120 {
121 minimumIndexReservedCapacity = _indexMemoryReservationStepInBytes;
122 }
123 // Check for alignment
124 if (minimumDataReservedCapacity % _dataMemoryReservationStepInBytes > 0)
125 {
126 minimumDataReservedCapacity = ((minimumDataReservedCapacity / _dataMemoryReservationStepInBytes) *
129 }
130 if (minimumIndexReservedCapacity % _indexMemoryReservationStepInBytes > 0)
131 {
132 minimumIndexReservedCapacity = ((minimumIndexReservedCapacity / _indexMemoryReservationStepInBytes) *
135 }
136 if (dataMemory.ReservedCapacity() < minimumDataReservedCapacity)
137 {
138 dataMemory.ReservedCapacity(minimumDataReservedCapacity);
139 }
140 if (indexMemory.ReservedCapacity() < minimumIndexReservedCapacity)
141 {
142 indexMemory.ReservedCapacity(minimumIndexReservedCapacity);
143 }
144 SetPointers(dataMemory, indexMemory);
145 // Ensure correctness _memory.UsedCapacity over _header->AllocatedLinks
146 dataMemory.UsedCapacity((this->GetHeaderReference().AllocatedLinks * LinkDataPartSizeInBytes) +
147 LinkDataPartSizeInBytes); // First link is read only zero link.
148 indexMemory.UsedCapacity((this->GetHeaderReference().AllocatedLinks * LinkIndexPartSizeInBytes) +
150 // Ensure correctness _memory.ReservedLinks over _header->ReservedCapacity
151 this->GetHeaderReference().ReservedLinks =
152 std::min((dataMemory.ReservedCapacity() - LinkDataPartSizeInBytes) / LinkDataPartSizeInBytes,
153 (indexMemory.ReservedCapacity() - LinkHeaderSizeInBytes) / LinkIndexPartSizeInBytes);
154 }
155
156 LinkAddressType Count(const LinkType& restriction) const
157 {
158 // Query length selects the constrained parts: total, address, one value, or a pair.
159 // The total excludes reusable records recorded in the free-list header.
160 if (std::ranges::size(restriction) == 0)
161 {
162 return this->Total();
163 }
164 auto index = GetIndex(*this, restriction);
165 auto any = Constants.Any;
166 if (std::ranges::size(restriction) == 1)
167 {
168 if (index == any)
169 {
170 return this->Total();
171 }
172 return this->Exists(index) ? LinkAddressType{1} : LinkAddressType{0};
173 }
174 if (std::ranges::size(restriction) == 2)
175 {
176 // A value-only query can use either the internal or external usage indexes.
177 auto value = restriction[1];
178 if (index == any)
179 {
180 if (value == any)
181 {
182 return this->Total(); // Any - как отсутствие ограничения
183 }
184 auto externalReferencesRange = Constants.ExternalReferencesRange;
185 if (Constants.IsExternalReferencesRangeEnabled && externalReferencesRange.Contains(value))
186 {
187 return ExternalSourcesTreeMethods->CountUsages(value) +
188 ExternalTargetsTreeMethods->CountUsages(value);
189 }
190 else
191 {
192 if (UseLinkedList)
193 {
194 return InternalSourcesListMethods->CountUsages(value) +
195 InternalTargetsTreeMethods->CountUsages(value);
196 }
197 else
198 {
199 return InternalSourcesTreeMethods->CountUsages(value) +
200 InternalTargetsTreeMethods->CountUsages(value);
201 }
202 }
203 }
204 else
205 {
206 if (!this->Exists(index))
207 {
208 return LinkAddressType{0};
209 }
210 if (value == any)
211 {
212 return LinkAddressType{1};
213 }
214 auto& storedLinkValue = this->GetLinkDataPartReference(index);
215 if ((storedLinkValue.Source == value) || (storedLinkValue.Target == value))
216 {
217 return LinkAddressType{1};
218 }
219 return LinkAddressType{0};
220 }
221 }
222 if (std::ranges::size(restriction) == 3)
223 {
224 // Source and target wildcards determine which usage tree can answer the query.
225 // Concrete source/target values require an exact pair search.
226 auto externalReferencesRange = Constants.ExternalReferencesRange;
227 auto source = GetSource(*this, restriction);
228 auto target = GetTarget(*this, restriction);
229 if (index == any)
230 {
231 if ((source == any) && (target == any))
232 {
233 return this->Total();
234 }
235 else if (source == any)
236 {
237 if (Constants.IsExternalReferencesRangeEnabled && externalReferencesRange.Contains(target))
238 {
239 return ExternalTargetsTreeMethods->CountUsages(target);
240 }
241 else
242 {
243 return InternalTargetsTreeMethods->CountUsages(target);
244 }
245 }
246 else if (target == any)
247 {
248 if (Constants.IsExternalReferencesRangeEnabled && externalReferencesRange.Contains(source))
249 {
250 return ExternalSourcesTreeMethods->CountUsages(source);
251 }
252 else
253 {
254 if (UseLinkedList)
255 {
256 return InternalSourcesTreeMethods->CountUsages(source);
257 }
258 else
259 {
260 return InternalSourcesTreeMethods->CountUsages(source);
261 }
262 }
263 }
264 else // if(source != Any && target != Any)
265 {
266 // Эквивалент Exists(source, target) => Count(Any, source, target) > 0
267 LinkAddressType linkAddress;
268 if (Constants.IsExternalReferencesRangeEnabled)
269 {
270 if (externalReferencesRange.Contains(source) && externalReferencesRange.Contains(target))
271 {
272 linkAddress = ExternalSourcesTreeMethods->Search(source, target);
273 }
274 else if (externalReferencesRange.Contains(source))
275 {
276 linkAddress = InternalTargetsTreeMethods->Search(source, target);
277 }
278 else if (externalReferencesRange.Contains(target))
279 {
280 if (UseLinkedList)
281 {
282 linkAddress = ExternalSourcesTreeMethods->Search(source, target);
283 }
284 else
285 {
286 linkAddress = InternalSourcesTreeMethods->Search(source, target);
287 }
288 }
289 else
290 {
291 if (UseLinkedList || InternalSourcesTreeMethods->CountUsages(source) >
292 InternalTargetsTreeMethods->CountUsages(target))
293 {
294 linkAddress = InternalTargetsTreeMethods->Search(source, target);
295 }
296 else
297 {
298 linkAddress = InternalSourcesTreeMethods->Search(source, target);
299 }
300 }
301 }
302 else
303 {
304 if (UseLinkedList || InternalSourcesTreeMethods->CountUsages(source) >
305 InternalTargetsTreeMethods->CountUsages(target))
306 {
307 linkAddress = InternalTargetsTreeMethods->Search(source, target);
308 }
309 else
310 {
311 linkAddress = InternalSourcesTreeMethods->Search(source, target);
312 }
313 }
314 return (linkAddress == Constants.Null) ? LinkAddressType{0} : LinkAddressType{1};
315 }
316 }
317 else
318 {
319 if (!this->Exists(index))
320 {
321 return LinkAddressType{0};
322 }
323 if ((source == any) && (target == any))
324 {
325 return LinkAddressType{1};
326 }
327 auto& storedLinkValue = GetLinkDataPartReference(index);
328 if ((source != any) && (target != any))
329 {
330 if ((storedLinkValue.Source == source) && (storedLinkValue.Target == target))
331 {
332 return LinkAddressType{1};
333 }
334 return LinkAddressType{0};
335 }
336 auto value = LinkAddressType{};
337 if (source == any)
338 {
339 value = target;
340 }
341 if (target == any)
342 {
343 value = source;
344 }
345 if ((storedLinkValue.Source == value) || (storedLinkValue.Target == value))
346 {
347 return LinkAddressType{1};
348 }
349 return LinkAddressType{0};
350 }
351 }
352 throw Platform::Exceptions::NotSupportedException();
353 }
354 //
355 void SetPointers(TMemory& dataMemory, TMemory& indexMemory)
356 {
357 _linksDataParts = static_cast<std::byte*>(dataMemory.Pointer());
358 _linksIndexParts = static_cast<std::byte*>(indexMemory.Pointer());
360 if (UseLinkedList)
361 {
363 std::make_unique<TInternalLinksSourcesLinkedListMethods>(_linksDataParts, _linksIndexParts);
364 }
365 else
366 {
368 std::make_unique<TInternalSourcesTreeMethods>(_linksDataParts, _linksIndexParts, _header);
369 }
371 std::make_unique<TInternalTargetsTreeMethods>(_linksDataParts, _linksIndexParts, _header);
373 std::make_unique<TExternalSourcesTreeMethods>(_linksDataParts, _linksIndexParts, _header);
375 std::make_unique<TExternalTargetsTreeMethods>(_linksDataParts, _linksIndexParts, _header);
376 UnusedLinksListMethods = std::make_unique<TUnusedLinksListMethods>(_linksDataParts, _header);
377 }
378
379 LinkAddressType Count(const LinkType& restriction)
380 {
381 using namespace Platform::Exceptions;
382 auto length = std::ranges::size(restriction);
383 // Если нет ограничений, тогда возвращаем общее число связей находящихся в хранилище.
384 if (length == 0)
385 {
386 return Total();
387 }
388 auto constants = Constants;
389 auto any = constants.Any;
390 auto index = GetIndex(*this, restriction);
391 if (length == 1)
392 {
393 if (index == any)
394 {
395 return Total();
396 }
397 return Exists(index) ? LinkAddressType{1} : LinkAddressType{0};
398 }
399 if (length == 2)
400 {
401 auto value = restriction[1];
402 if (index == any)
403 {
404 if (value == any)
405 {
406 return Total(); // Any - как отсутствие ограничения
407 }
408 LinkAddressType count{};
409 if (value == constants.Null)
410 {
411 Each(restriction, [&](const auto&) {
412 ++count;
413 return constants.Continue;
414 });
415 return count;
416 }
417 count = Count(LinkType{index, value, any});
418 // The target pass adds only records absent from the source pass.
419 Each(LinkType{index, any, value}, [&](const auto& link) {
420 if (link[constants.SourcePart] != value)
421 ++count;
422 return constants.Continue;
423 });
424 return count;
425 }
426 else
427 {
428 if (!Exists(index))
429 {
430 return LinkAddressType{0};
431 }
432 if (value == any)
433 {
434 return LinkAddressType{1};
435 }
436 auto& storedLinkValue = GetLinkDataPartReference(index);
437 if ((storedLinkValue.Source == value) || (storedLinkValue.Target == value))
438 {
439 return LinkAddressType{1};
440 }
441 return LinkAddressType{0};
442 }
443 }
444 if (length == 3)
445 {
446 auto externalReferencesRange = constants.ExternalReferencesRange;
447 auto source = GetSource(*this, restriction);
448 auto target = GetTarget(*this, restriction);
449 if (index == any)
450 {
451 if ((source == any) && (target == any))
452 {
453 return Total();
454 }
455 else if (source == any)
456 {
457 if (Constants.IsExternalReferencesRangeEnabled && externalReferencesRange.Contains(target))
458 {
459 return ExternalTargetsTreeMethods->CountUsages(target);
460 }
461 else
462 {
463 return InternalTargetsTreeMethods->CountUsages(target);
464 }
465 }
466 else if (target == any)
467 {
468 if (Constants.IsExternalReferencesRangeEnabled && externalReferencesRange.Contains(source))
469 {
470 return ExternalSourcesTreeMethods->CountUsages(source);
471 }
472 else
473 {
474 if (UseLinkedList)
475 {
476 return InternalSourcesListMethods->CountUsages(source);
477 }
478 else
479 {
480 return InternalSourcesTreeMethods->CountUsages(source);
481 }
482 }
483 }
484 else // if(source != Any && target != Any)
485 {
486 // Эквивалент Exists(source, target) => Count(Any, source, target) > 0
487 LinkAddressType linkAddress;
488 if (Constants.IsExternalReferencesRangeEnabled)
489 {
490 if (externalReferencesRange.Contains(source) && externalReferencesRange.Contains(target))
491 {
492 linkAddress = ExternalSourcesTreeMethods->Search(source, target);
493 }
494 else if (externalReferencesRange.Contains(source))
495 {
496 linkAddress = InternalTargetsTreeMethods->Search(source, target);
497 }
498 else if (externalReferencesRange.Contains(target))
499 {
500 if (UseLinkedList)
501 {
502 linkAddress = ExternalSourcesTreeMethods->Search(source, target);
503 }
504 else
505 {
506 linkAddress = InternalSourcesTreeMethods->Search(source, target);
507 }
508 }
509 else
510 {
511 if (UseLinkedList || (InternalSourcesTreeMethods->CountUsages(source) >
512 InternalTargetsTreeMethods->CountUsages(target)))
513 {
514 linkAddress = InternalTargetsTreeMethods->Search(source, target);
515 }
516 else
517 {
518 linkAddress = InternalSourcesTreeMethods->Search(source, target);
519 }
520 }
521 }
522 else
523 {
524 if (UseLinkedList || (InternalSourcesTreeMethods->CountUsages(source) >
525 InternalTargetsTreeMethods->CountUsages(target)))
526 {
527 linkAddress = InternalTargetsTreeMethods->Search(source, target);
528 }
529 else
530 {
531 linkAddress = InternalSourcesTreeMethods->Search(source, target);
532 }
533 }
534 return (linkAddress == constants.Null) ? LinkAddressType{0} : LinkAddressType{1};
535 }
536 }
537 else
538 {
539 if (!Exists(index))
540 {
541 return LinkAddressType{0};
542 }
543 if ((source == any) && (target == any))
544 {
545 return LinkAddressType{1};
546 }
547 auto& storedLinkValue = GetLinkDataPartReference(index);
548 if ((source != any) && (target != any))
549 {
550 if ((storedLinkValue.Source == source) && (storedLinkValue.Target == target))
551 {
552 return LinkAddressType{1};
553 }
554 return LinkAddressType{0};
555 }
556 auto value = LinkAddressType{0};
557 if (source == any)
558 {
559 value = target;
560 }
561 if (target == any)
562 {
563 value = source;
564 }
565 if ((storedLinkValue.Source == value) || (storedLinkValue.Target == value))
566 {
567 return LinkAddressType{1};
568 }
569 return LinkAddressType{0};
570 }
571 }
572 throw Platform::Exceptions::NotSupportedException();
573 }
574
575 LinkAddressType Each(const LinkType& restriction, const ReadHandlerType& handler) const
576 {
577 // Enumerate only live records and propagate the callback's request to stop.
578 // Query shape determines whether to scan addresses or traverse a usage index.
579 using namespace Platform::Exceptions;
580 auto constants = Constants;
581 auto $break = constants.Break;
582 auto length = std::ranges::size(restriction);
583 if (length == 0)
584 {
585 // An unrestricted scan skips the zero record and entries on the free list.
586 for (auto linkAddress = LinkAddressType{1}; (linkAddress <= this->GetHeaderReference().AllocatedLinks);
587 ++linkAddress)
588 {
589 if (Exists(linkAddress) && (handler(GetLinkStruct(linkAddress)) == $break))
590 {
591 return $break;
592 }
593 }
594 return constants.Continue;
595 }
596 auto $continue = constants.Continue;
597 auto any = constants.Any;
598 auto index = GetIndex(*this, restriction);
599 if (length == 1)
600 {
601 if (index == any)
602 {
603 return Each(LinkType{}, handler);
604 }
605 if (!Exists(index))
606 {
607 return $continue;
608 }
609 return handler(GetLinkStruct(index));
610 }
611 if (length == 2)
612 {
613 // The value may be internal or external, which selects the matching index family.
614 auto value = restriction[1];
615 if (index == any)
616 {
617 if (value == any)
618 {
619 return Each(LinkType{}, handler);
620 }
621 if (value == constants.Null)
622 {
623 // Null endpoints are absent from the usage indexes.
624 return Each(LinkType{}, [&](const auto& link) {
625 return link[constants.SourcePart] == value || link[constants.TargetPart] == value
626 ? handler(link)
627 : $continue;
628 });
629 }
630 if (Each(LinkType{index, value, any}, handler) == $break)
631 {
632 return $break;
633 }
634 return Each(LinkType{index, any, value}, [&](const auto& link) {
635 return link[constants.SourcePart] == value ? $continue : handler(link);
636 });
637 }
638 else
639 {
640 if (!Exists(index))
641 {
642 return $continue;
643 }
644 if (value == any)
645 {
646 return handler(GetLinkStruct(index));
647 }
648 auto& storedLinkValue = GetLinkDataPartReference(index);
649 if ((storedLinkValue.Source == value) || (storedLinkValue.Target == value))
650 {
651 return handler(GetLinkStruct(index));
652 }
653 return $continue;
654 }
655 }
656 if (length == 3)
657 {
658 // Wildcards choose source/target traversal; concrete values use the pair lookup.
659 // A specified address is checked directly instead of enumerating unrelated links.
660 auto externalReferencesRange = constants.ExternalReferencesRange;
661 auto source = GetSource(*this, restriction);
662 auto target = GetTarget(*this, restriction);
663 if (index == any)
664 {
665 if ((source == any) && (target == any))
666 {
667 return Each(LinkType{}, handler);
668 }
669 else if (source == any)
670 {
671 if (Constants.IsExternalReferencesRangeEnabled && externalReferencesRange.Contains(target))
672 {
673 return ExternalTargetsTreeMethods->EachUsage(target, handler);
674 }
675 else
676 {
677 return InternalTargetsTreeMethods->EachUsage(target, handler);
678 }
679 }
680 else if (target == any)
681 {
682 if (Constants.IsExternalReferencesRangeEnabled && externalReferencesRange.Contains(source))
683 {
684 return ExternalSourcesTreeMethods->EachUsage(source, handler);
685 }
686 else
687 {
688 if (UseLinkedList)
689 {
690 return InternalSourcesListMethods->EachUsage(source, handler);
691 }
692 else
693 {
694 return InternalSourcesTreeMethods->EachUsage(source, handler);
695 }
696 }
697 }
698 else // if(source != Any && target != Any)
699 {
700 LinkAddressType linkAddress;
701 if (Constants.IsExternalReferencesRangeEnabled)
702 {
703 if (externalReferencesRange.Contains(source) && externalReferencesRange.Contains(target))
704 {
705 linkAddress = ExternalSourcesTreeMethods->Search(source, target);
706 }
707 else if (externalReferencesRange.Contains(source))
708 {
709 linkAddress = InternalTargetsTreeMethods->Search(source, target);
710 }
711 else if (externalReferencesRange.Contains(target))
712 {
713 if (UseLinkedList)
714 {
715 linkAddress = ExternalSourcesTreeMethods->Search(source, target);
716 }
717 else
718 {
719 linkAddress = InternalSourcesTreeMethods->Search(source, target);
720 }
721 }
722 else
723 {
724 if (UseLinkedList || (InternalSourcesTreeMethods->CountUsages(source) ==
725 InternalTargetsTreeMethods->CountUsages(target)))
726 {
727 linkAddress = InternalTargetsTreeMethods->Search(source, target);
728 }
729 else
730 {
731 linkAddress = InternalSourcesTreeMethods->Search(source, target);
732 }
733 }
734 }
735 else
736 {
737 if (UseLinkedList || (InternalSourcesTreeMethods->CountUsages(source) >
738 InternalTargetsTreeMethods->CountUsages(target)))
739 {
740 linkAddress = InternalTargetsTreeMethods->Search(source, target);
741 }
742 else
743 {
744 linkAddress = InternalSourcesTreeMethods->Search(source, target);
745 }
746 }
747 return (linkAddress == constants.Null) ? $continue : handler(GetLinkStruct(linkAddress));
748 }
749 }
750 else
751 {
752 if (!Exists(index))
753 {
754 return $continue;
755 }
756 if ((source == any) && (target == any))
757 {
758 return handler(GetLinkStruct(index));
759 }
760 auto& storedLinkValue = GetLinkDataPartReference(index);
761 if ((source != any) && (target != any))
762 {
763 if ((storedLinkValue.Source == source) && (storedLinkValue.Target == target))
764 {
765 return handler(GetLinkStruct(index));
766 }
767 return $continue;
768 }
769 auto value = LinkAddressType{0};
770 if (source == any)
771 {
772 value = target;
773 }
774 if (target == any)
775 {
776 value = source;
777 }
778 if ((storedLinkValue.Source == value) || (storedLinkValue.Target == value))
779 {
780 return handler(GetLinkStruct(index));
781 }
782 return $continue;
783 }
784 }
785 throw Platform::Exceptions::NotSupportedException();
786 }
787
788 LinkAddressType Update(const LinkType& restriction, const LinkType& substitution,
789 const WriteHandlerType& handler)
790 {
791 auto constants = Constants;
792 auto $null = constants.Null;
793 auto externalReferencesRange = constants.ExternalReferencesRange;
794 auto linkIndex = GetIndex(*this, restriction);
795 auto before = this->GetLinkStruct(linkIndex);
796 auto& link = this->GetLinkDataPartReference(linkIndex);
797 auto source = link.Source;
798 auto target = link.Target;
799 auto& rootAsSource = this->GetHeaderReference().RootAsSource;
800 auto& rootAsTarget = this->GetHeaderReference().RootAsTarget;
801 // Будет корректно работать только в том случае, если пространство выделенной связи предварительно заполнено
802 // нулями
803 if (source != $null)
804 {
805 if (Constants.IsExternalReferencesRangeEnabled && externalReferencesRange.Contains(source))
806 {
807 ExternalSourcesTreeMethods->Detach(&rootAsSource, linkIndex);
808 }
809 else
810 {
811 if (UseLinkedList)
812 {
813 InternalSourcesListMethods->Detach(source, linkIndex);
814 }
815 else
816 {
817 InternalSourcesTreeMethods->Detach(&(GetLinkIndexPartReference(source).RootAsSource),
818 linkIndex);
819 }
820 }
821 }
822 if (target != $null)
823 {
824 if (Constants.IsExternalReferencesRangeEnabled && externalReferencesRange.Contains(target))
825 {
826 ExternalTargetsTreeMethods->Detach(&rootAsTarget, linkIndex);
827 }
828 else
829 {
830 InternalTargetsTreeMethods->Detach(&(GetLinkIndexPartReference(target).RootAsTarget), linkIndex);
831 }
832 }
833 source = link.Source = GetSource(*this, substitution);
834 target = link.Target = GetTarget(*this, substitution);
835 if (source != $null)
836 {
837 if (Constants.IsExternalReferencesRangeEnabled && externalReferencesRange.Contains(source))
838 {
839 ExternalSourcesTreeMethods->Attach(&rootAsSource, linkIndex);
840 }
841 else
842 {
843 if (UseLinkedList)
844 {
845 InternalSourcesListMethods->AttachAsLast(source, linkIndex);
846 }
847 else
848 {
849 InternalSourcesTreeMethods->Attach(&(GetLinkIndexPartReference(source).RootAsSource),
850 linkIndex);
851 }
852 }
853 }
854 if (target != $null)
855 {
856 if (Constants.IsExternalReferencesRangeEnabled && externalReferencesRange.Contains(target))
857 {
858 ExternalTargetsTreeMethods->Attach(&rootAsTarget, linkIndex);
859 }
860 else
861 {
862 InternalTargetsTreeMethods->Attach(&(GetLinkIndexPartReference(target).RootAsTarget), linkIndex);
863 }
864 }
865 return handler ? handler(before, LinkType{linkIndex, source, target}) : Constants.Continue;
866 }
867
869 {
870 using namespace Platform::Exceptions;
871 auto freeLink = this->GetHeaderReference().FirstFreeLink;
872 if (freeLink != Constants.Null)
873 {
874 UnusedLinksListMethods->Detach(freeLink);
875 }
876 else
877 {
878 auto maximumPossibleInnerReference = Constants.InternalReferencesRange.Maximum;
879 if (this->GetHeaderReference().AllocatedLinks >= maximumPossibleInnerReference)
880 {
881 throw Platform::Exceptions::LinksLimitReachedException();
882 }
883 if (this->GetHeaderReference().AllocatedLinks >= this->GetHeaderReference().ReservedLinks)
884 {
885 _dataMemory.ReservedCapacity(_dataMemory.ReservedCapacity() + _dataMemoryReservationStepInBytes);
886 _indexMemory.ReservedCapacity(_indexMemory.ReservedCapacity() + _indexMemoryReservationStepInBytes);
888 this->GetHeaderReference().ReservedLinks =
889 std::min((_dataMemory.ReservedCapacity() - LinkDataPartSizeInBytes) / LinkDataPartSizeInBytes,
891 }
892 freeLink = ++this->GetHeaderReference().AllocatedLinks;
893 _dataMemory.UsedCapacity(_dataMemory.UsedCapacity() + LinkDataPartSizeInBytes);
894 _indexMemory.UsedCapacity(_indexMemory.UsedCapacity() + LinkIndexPartSizeInBytes);
895 }
896 return handler ? handler(LinkType{}, GetLinkStruct(freeLink)) : Constants.Continue;
897 }
898
899 LinkAddressType Delete(const LinkType& restriction, const WriteHandlerType& handler)
900 {
901 auto linkAddress = GetIndex(*this, restriction);
902 auto before = GetLinkStruct(linkAddress);
903 if (linkAddress < this->GetHeaderReference().AllocatedLinks)
904 {
905 UnusedLinksListMethods->AttachAsFirst(linkAddress);
906 return handler ? handler(before, LinkType{}) : Constants.Continue;
907 }
908 else if (linkAddress == this->GetHeaderReference().AllocatedLinks)
909 {
910 --this->GetHeaderReference().AllocatedLinks;
911 _dataMemory.UsedCapacity(_dataMemory.UsedCapacity() - LinkDataPartSizeInBytes);
912 _indexMemory.UsedCapacity(_indexMemory.UsedCapacity() - LinkIndexPartSizeInBytes);
913 // Убираем все связи, находящиеся в списке свободных в конце файла, до тех пор, пока не дойдём до первой
914 // существующей связи Позволяет оптимизировать количество выделенных связей (AllocatedLinks)
915 while ((this->GetHeaderReference().AllocatedLinks > LinkAddressType{0}) &&
916 this->IsUnusedLink(this->GetHeaderReference().AllocatedLinks))
917 {
918 UnusedLinksListMethods->Detach(this->GetHeaderReference().AllocatedLinks);
919 --this->GetHeaderReference().AllocatedLinks;
920 _dataMemory.UsedCapacity(_dataMemory.UsedCapacity() - LinkDataPartSizeInBytes);
921 _indexMemory.UsedCapacity(_indexMemory.UsedCapacity() - LinkIndexPartSizeInBytes);
922 }
923 return handler ? handler(before, LinkType{}) : Constants.Continue;
924 }
925 return Constants.Continue;
926 }
927
928 public:
929 bool IsUnusedLink(LinkAddressType linkIndex) const
930 {
931 if (GetHeaderReference().FirstFreeLink != linkIndex) // May be this check is not needed
932 {
933 // TODO: Reduce access to memory in different location (should be enough to use just linkIndexPart)
934 const auto& linkDataPart = this->GetLinkDataPartReference(linkIndex);
935 const auto& linkIndexPart = this->GetLinkIndexPartReference(linkIndex);
936 return (linkIndexPart.SizeAsTarget == LinkAddressType{0}) &&
937 (linkDataPart.Source != LinkAddressType{0});
938 }
939 else
940 {
941 return true;
942 }
943 }
944
945 bool Exists(LinkAddressType linkAddress) const
946 {
947 return (linkAddress >= Constants.InternalReferencesRange.Minimum) &&
948 (linkAddress <= this->GetHeaderReference().AllocatedLinks) && !IsUnusedLink(linkAddress);
949 }
950
951 public:
953 {
954 const auto& link = this->GetLinkDataPartReference(linkIndex);
955 return LinkType{linkIndex, link.Source, link.Target};
956 }
957 };
958} // namespace Platform::Data::Doublets::Memory::Split::Generic
Definition ExternalLinksRecursionlessSizeBalancedTreeMethodsBase.h:2
Definition RawLinkDataPart.h:38
LinkAddressType Create(const LinkType &, const WriteHandlerType &handler)
Definition SplitMemoryLinksBase.h:868
bool IsUnusedLink(LinkAddressType linkIndex) const
Definition SplitMemoryLinksBase.h:929
void Init(TMemory &dataMemory, TMemory &indexMemory)
Definition SplitMemoryLinksBase.h:97
std::byte * _linksDataParts
Definition SplitMemoryLinksBase.h:30
std::unique_ptr< TUnusedLinksListMethods > UnusedLinksListMethods
Definition SplitMemoryLinksBase.h:28
typename LinksOptionsType::WriteHandlerType WriteHandlerType
Definition SplitMemoryLinksBase.h:13
LinkAddressType Count(const LinkType &restriction)
Definition SplitMemoryLinksBase.h:379
LinkAddressType Total() const
Definition SplitMemoryLinksBase.h:69
static constexpr bool UseLinkedList
Definition SplitMemoryLinksBase.h:16
std::uint64_t _indexMemoryReservationStepInBytes
Definition SplitMemoryLinksBase.h:22
std::byte * _linksIndexParts
Definition SplitMemoryLinksBase.h:31
static constexpr std::size_t LinkHeaderSizeInBytes
Definition SplitMemoryLinksBase.h:79
const LinksHeader< LinkAddressType > & GetHeaderReference() const
Definition SplitMemoryLinksBase.h:59
RawLinkDataPart< LinkAddressType > & GetLinkDataPartReference(LinkAddressType linkIndex)
Definition SplitMemoryLinksBase.h:40
static constexpr std::size_t LinkDataPartSizeInBytes
Definition SplitMemoryLinksBase.h:75
const RawLinkDataPart< LinkAddressType > & GetLinkDataPartReference(LinkAddressType linkIndex) const
Definition SplitMemoryLinksBase.h:34
std::uint64_t _dataMemoryReservationStepInBytes
Definition SplitMemoryLinksBase.h:21
const RawLinkIndexPart< LinkAddressType > & GetLinkIndexPartReference(LinkAddressType linkIndex) const
Definition SplitMemoryLinksBase.h:46
static constexpr LinksConstants< LinkAddressType > Constants
Definition SplitMemoryLinksBase.h:15
void SetPointers(TMemory &dataMemory, TMemory &indexMemory)
Definition SplitMemoryLinksBase.h:355
std::unique_ptr< TExternalSourcesTreeMethods > ExternalSourcesTreeMethods
Definition SplitMemoryLinksBase.h:26
std::unique_ptr< TInternalLinksSourcesLinkedListMethods > InternalSourcesListMethods
Definition SplitMemoryLinksBase.h:24
std::unique_ptr< TExternalTargetsTreeMethods > ExternalTargetsTreeMethods
Definition SplitMemoryLinksBase.h:27
LinkAddressType Count(const LinkType &restriction) const
Definition SplitMemoryLinksBase.h:156
LinkAddressType Each(const LinkType &restriction, const ReadHandlerType &handler) const
Definition SplitMemoryLinksBase.h:575
LinksHeader< LinkAddressType > & GetHeaderReference()
Definition SplitMemoryLinksBase.h:64
LinkAddressType Update(const LinkType &restriction, const LinkType &substitution, const WriteHandlerType &handler)
Definition SplitMemoryLinksBase.h:788
typename LinksOptionsType::LinkType LinkType
Definition SplitMemoryLinksBase.h:12
static constexpr std::size_t DefaultLinksSizeStep
Definition SplitMemoryLinksBase.h:81
std::unique_ptr< TInternalSourcesTreeMethods > InternalSourcesTreeMethods
Definition SplitMemoryLinksBase.h:23
std::byte * _header
Definition SplitMemoryLinksBase.h:29
LinkAddressType Delete(const LinkType &restriction, const WriteHandlerType &handler)
Definition SplitMemoryLinksBase.h:899
static constexpr std::size_t LinkIndexPartSizeInBytes
Definition SplitMemoryLinksBase.h:77
bool Exists(LinkAddressType linkAddress) const
Definition SplitMemoryLinksBase.h:945
TLinksOptions LinksOptionsType
Definition SplitMemoryLinksBase.h:10
typename LinksOptionsType::LinkAddressType LinkAddressType
Definition SplitMemoryLinksBase.h:11
SplitMemoryLinksBase(TMemory &&dataMemory, TMemory &&indexMemory, std::uint64_t memoryReservationStep)
Definition SplitMemoryLinksBase.h:88
std::unique_ptr< TInternalTargetsTreeMethods > InternalTargetsTreeMethods
Definition SplitMemoryLinksBase.h:25
SplitMemoryLinksBase(TMemory &&dataMemory, TMemory &&indexMemory)
Definition SplitMemoryLinksBase.h:83
TMemory _indexMemory
Definition SplitMemoryLinksBase.h:20
RawLinkIndexPart< LinkAddressType > & GetLinkIndexPartReference(LinkAddressType linkIndex)
Definition SplitMemoryLinksBase.h:52
typename LinksOptionsType::ReadHandlerType ReadHandlerType
Definition SplitMemoryLinksBase.h:14
LinkType GetLinkStruct(LinkAddressType linkIndex) const
Definition SplitMemoryLinksBase.h:952