Platform.Data.Doublets C++
Loading...
Searching...
No Matches
UnitedMemoryLinksBase.h
Go to the documentation of this file.
2{
3
4 template <typename TSelf, typename TLinkOptions, typename TMemory, typename TSourceTreeMethods,
5 typename TTargetTreeMethods, typename TUnusedLinks, typename... TBase>
6 struct UnitedMemoryLinksBase : public Interfaces::Polymorph<TSelf, TBase...>
7 {
8 public:
9 using LinksOptionsType = TLinkOptions;
10 using LinkAddressType = typename LinksOptionsType::LinkAddressType;
11 using LinkType = typename LinksOptionsType::LinkType;
12 using WriteHandlerType = typename LinksOptionsType::WriteHandlerType;
13 using ReadHandlerType = typename LinksOptionsType::ReadHandlerType;
14 static constexpr LinksConstants<LinkAddressType> Constants = LinksOptionsType::Constants;
15
16 public:
17 static constexpr std::size_t LinkSizeInBytes = sizeof(RawLink<LinkAddressType>);
18
19 static constexpr std::size_t LinkHeaderSizeInBytes = sizeof(LinksHeader<LinkAddressType>);
20
21 static constexpr std::size_t DefaultLinksSizeStep = LinkSizeInBytes * 1024 * 1024;
22
23 public:
24 TMemory _memory;
25
26 private:
27 std::byte* _header;
28
29 private:
30 std::byte* _links;
31
32 const std::size_t _memoryReservationStep;
33
34 std::unique_ptr<TTargetTreeMethods> _TargetsTreeMethods;
35
36 std::unique_ptr<TSourceTreeMethods> _SourcesTreeMethods;
37
38 std::unique_ptr<TUnusedLinks> _UnusedLinksListMethods;
39
40 LinksHeader<LinkAddressType>& GetHeaderReference()
41 {
42 return *reinterpret_cast<LinksHeader<LinkAddressType>*>(_header);
43 }
44
45 const LinksHeader<LinkAddressType>& GetHeaderReference() const
46 {
47 return *reinterpret_cast<LinksHeader<LinkAddressType>*>(_header);
48 }
49
50 const RawLink<LinkAddressType>& GetLinkReference(LinkAddressType linkIndex) const
51 {
52 return reinterpret_cast<const RawLink<LinkAddressType>*>(_links)[linkIndex];
53 }
54
55 RawLink<LinkAddressType>& GetLinkReference(LinkAddressType linkIndex)
56 {
57 return reinterpret_cast<RawLink<LinkAddressType>*>(_links)[linkIndex];
58 }
59
60 LinkAddressType GetTotal() const
61 {
62 auto& header = this->GetHeaderReference();
63 return header.AllocatedLinks - header.FreeLinks;
64 }
65
66 public:
67 public:
69
70 UnitedMemoryLinksBase(TMemory&& memory, std::uint64_t memoryReservationStep)
71 : _memory(std::move(memory)), _memoryReservationStep(memoryReservationStep)
72 {
73 Init(_memory, memoryReservationStep);
74 }
75
76 void Init(TMemory& memory, std::size_t memoryReservationStep)
77 {
78
79 if (memory.ReservedCapacity() < memoryReservationStep)
80 {
81 memory.ReservedCapacity(memoryReservationStep);
82 }
83 SetPointers(memory);
84
85 auto& header = this->GetHeaderReference();
86 memory.UsedCapacity((header.AllocatedLinks * LinkSizeInBytes) + LinkHeaderSizeInBytes);
87 header.ReservedLinks = (memory.ReservedCapacity() - LinkHeaderSizeInBytes) / LinkSizeInBytes;
88 }
89
90 public:
91 LinkAddressType Count(const LinkType& restriction) const
92 {
93 // Restriction length determines which parts of a stored link are constrained.
94 // An empty restriction counts live records, excluding entries on the free list.
95 if (std::ranges::size(restriction) == 0)
96 {
97 return GetTotal();
98 }
99 auto any = Constants.Any;
100 auto index = restriction[Constants.IndexPart];
101 if (std::ranges::size(restriction) == 1)
102 {
103 if (index == any)
104 {
105 return GetTotal();
106 }
107 return Exists(index) ? LinkAddressType{1} : LinkAddressType{};
108 }
109 if (std::ranges::size(restriction) == 2)
110 {
111 // A two-part query matches the value in either the source or target index.
112 auto value = restriction[1];
113 if (index == any)
114 {
115 if (value == any)
116 {
117 return GetTotal(); // Any - как отсутствие ограничения
118 }
119 LinkAddressType count{};
120 if (value == Constants.Null)
121 {
122 Each(restriction, [&](const auto&) {
123 ++count;
124 return Constants.Continue;
125 });
126 return count;
127 }
128 count = _SourcesTreeMethods->CountUsages(value);
129 // Add target-only matches, retaining distinct records with equal endpoints.
130 _TargetsTreeMethods->EachUsage(value, [&](const auto& link) {
131 if (link[Constants.SourcePart] != value)
132 ++count;
133 return Constants.Continue;
134 });
135 return count;
136 }
137 else
138 {
139 if (!Exists(index))
140 {
141 return LinkAddressType{};
142 }
143 if (value == any)
144 {
145 return LinkAddressType{1};
146 }
147 auto& storedLinkValue = GetLinkReference(index);
148 if (storedLinkValue.Source == value || storedLinkValue.Target == value)
149 {
150 return LinkAddressType{1};
151 }
152 return LinkAddressType{};
153 }
154 }
155 if (std::ranges::size(restriction) == 3)
156 {
157 // Wildcards select the relevant usage index; two concrete values use a pair lookup.
158 auto source = restriction[Constants.SourcePart];
159 auto target = restriction[Constants.TargetPart];
160 if (index == any)
161 {
162 if (source == any && target == any)
163 {
164 return GetTotal();
165 }
166 else if (source == any)
167 {
168 return _TargetsTreeMethods->CountUsages(target);
169 }
170 else if (target == any)
171 {
172 return _SourcesTreeMethods->CountUsages(source);
173 }
174 else // if(source != Any && target != Any)
175 {
176 auto link = _SourcesTreeMethods->Search(source, target);
177 return link == Constants.Null ? LinkAddressType{} : LinkAddressType{1};
178 }
179 }
180 else
181 {
182 // A concrete address must exist before its stored values can be compared.
183 if (!Exists(index))
184 {
185 return LinkAddressType{};
186 }
187 if (source == any && target == any)
188 {
189 return LinkAddressType{1};
190 }
191 auto& storedLinkValue = GetLinkReference(index);
192 if (source != any && target != any)
193 {
194 if ((storedLinkValue.Source == source) && (storedLinkValue.Target == target))
195 {
196 return LinkAddressType{1};
197 }
198 return LinkAddressType{};
199 }
200 auto value = LinkAddressType();
201 if (source == any)
202 {
203 value = target;
204 }
205 if (target == any)
206 {
207 value = source;
208 }
209 if ((storedLinkValue.Source == value) || (storedLinkValue.Target == value))
210 {
211 return LinkAddressType{1};
212 }
213 return LinkAddressType{};
214 }
215 }
216 throw std::logic_error("Not supported exception.");
217 }
218
219 public:
220 LinkAddressType Each(const LinkType& restriction, const ReadHandlerType& handler) const
221 {
222 auto $continue{Constants.Continue};
223 auto $break = Constants.Break;
224 if (std::ranges::size(restriction) == 0)
225 {
226 for (auto link = LinkAddressType{1}; link <= this->GetHeaderReference().AllocatedLinks; ++link)
227 {
228 if (Exists(link) && (handler(GetLinkStruct(link)) == $break))
229 {
230 return $break;
231 }
232 }
233 return $continue;
234 }
235 auto _continue = Constants.Continue;
236 auto any = Constants.Any;
237 auto index = restriction[Constants.IndexPart];
238 if (std::ranges::size(restriction) == 1)
239 {
240 if (index == any)
241 {
242 return Data::Each(*this, handler);
243 }
244 if (!Exists(index))
245 {
246 return _continue;
247 }
248 return handler(GetLinkStruct(index));
249 }
250 if (std::ranges::size(restriction) == 2)
251 {
252 auto value = restriction[1];
253 if (index == any)
254 {
255 if (value == any)
256 {
257 return Data::Each(*this, handler);
258 }
259 if (value == Constants.Null)
260 {
261 // Null endpoints are absent from the usage indexes.
262 return Each(LinkType{}, [&](const auto& link) {
263 return link[Constants.SourcePart] == value || link[Constants.TargetPart] == value
264 ? handler(link)
265 : _continue;
266 });
267 }
268 if (Each(LinkType{index, value, any}, handler) == $break)
269 {
270 return $break;
271 }
272 return Each(LinkType{index, any, value}, [&](const auto& link) {
273 return link[Constants.SourcePart] == value ? _continue : handler(link);
274 });
275 }
276 else
277 {
278 if (!Exists(index))
279 {
280 return _continue;
281 }
282 if (value == any)
283 {
284 return handler(GetLinkStruct(index));
285 }
286 auto& storedLinkValue = GetLinkReference(index);
287 if ((storedLinkValue.Source == value) || (storedLinkValue.Target == value))
288 {
289 return handler(GetLinkStruct(index));
290 }
291 return _continue;
292 }
293 }
294 if (std::ranges::size(restriction) == 3)
295 {
296 auto source = restriction[Constants.SourcePart];
297 auto target = restriction[Constants.TargetPart];
298 if (index == any)
299 {
300 if (source == any && target == any)
301 {
302 return Data::Each(*this, handler);
303 }
304 else if (source == any)
305 {
306 return _TargetsTreeMethods->EachUsage(target, handler);
307 }
308 else if (target == any)
309 {
310 return _SourcesTreeMethods->EachUsage(source, handler);
311 }
312 else // if(source != Any && target != Any)
313 {
314 auto link = _SourcesTreeMethods->Search(source, target);
315 return (link == Constants.Null) ? _continue : handler(GetLinkStruct(link));
316 }
317 }
318 else
319 {
320 if (!Exists(index))
321 {
322 return _continue;
323 }
324 if (source == any && target == any)
325 {
326 return handler(GetLinkStruct(index));
327 }
328 // TODO: 'ref locals' are not converted by C# to C++ Converter:
329 // ORIGINAL LINE: ref var storedLinkValue = ref GetLinkReference(index);
330 auto& storedLinkValue = GetLinkReference(index);
331 if (source != any && target != any)
332 {
333 if (storedLinkValue.Source == source && storedLinkValue.Target == target)
334 {
335 return handler(GetLinkStruct(index));
336 }
337 return _continue;
338 }
339 auto value = LinkAddressType();
340 if (source == any)
341 {
342 value = target;
343 }
344 if (target == any)
345 {
346 value = source;
347 }
348 if (storedLinkValue.Source == value || storedLinkValue.Target == value)
349 {
350 return handler(GetLinkStruct(index));
351 }
352 return _continue;
353 }
354 }
355 throw std::logic_error("Not supported exception.");
356 }
357
358 // / <remarks>
359 // / TODO: Возможно можно перемещать значения, если указан индекс, но значение существует в другом месте (но не
360 // в менеджере памяти, а в логике Links) / </remarks> NOTE: The following .NET attribute has no direct
361 // equivalent in C++: ORIGINAL LINE: [MethodImpl(MethodImplOptions.AggressiveInlining)] public LinkAddressType
362 // Update(IList<LinkAddressType> restriction, IList<LinkAddressType> substitution)
363 public:
364 LinkAddressType Update(const LinkType& restriction, const LinkType& substitution,
365 const WriteHandlerType& handler)
366 {
367 auto null = Constants.Null;
368 auto linkIndex = restriction[Constants.IndexPart];
369 // TODO: 'ref locals' are not converted by C# to C++ Converter:
370 // ORIGINAL LINE: ref var link = ref GetLinkReference(linkIndex);
371 auto& link = GetLinkReference(linkIndex);
372 LinkType before{linkIndex, link.Source, link.Target};
373 // TODO: 'ref locals' are not converted by C# to C++ Converter:
374 // ORIGINAL LINE: ref var header = ref GetHeaderReference();
375 auto& header = this->GetHeaderReference();
376 // TODO: 'ref locals' are not converted by C# to C++ Converter:
377 // ORIGINAL LINE: ref var firstAsSource = ref header.RootAsSource;
378 auto& firstAsSource = header.RootAsSource;
379 // TODO: 'ref locals' are not converted by C# to C++ Converter:
380 // ORIGINAL LINE: ref var firstAsTarget = ref header.RootAsTarget;
381 auto& firstAsTarget = header.RootAsTarget;
382 // Будет корректно работать только в том случае, если пространство выделенной связи предварительно заполнено
383 // нулями
384 if (link.Source != null)
385 {
386 _SourcesTreeMethods->Detach(firstAsSource, linkIndex);
387 }
388 if (link.Target != null)
389 {
390 _TargetsTreeMethods->Detach(firstAsTarget, linkIndex);
391 }
392 link.Source = substitution[Constants.SourcePart];
393 link.Target = substitution[Constants.TargetPart];
394 if (link.Source != null)
395 {
396 _SourcesTreeMethods->Attach(firstAsSource, linkIndex);
397 }
398 if (link.Target != null)
399 {
400 _TargetsTreeMethods->Attach(firstAsTarget, linkIndex);
401 }
402 return handler(before, LinkType{linkIndex, link.Source, link.Target});
403 }
404
405 // TODO: Возможно нужно будет заполнение нулями, если внешнее API ими не заполняет пространство
406 public:
408 {
409 auto* header = &this->GetHeaderReference();
410 auto freeLink = header->FirstFreeLink;
411 if (freeLink != Constants.Null)
412 {
413 _UnusedLinksListMethods->Detach(freeLink);
414 }
415 else
416 {
417 auto maximumPossibleInnerReference = Constants.InternalReferencesRange.Maximum;
418 if (header->AllocatedLinks >= maximumPossibleInnerReference)
419 {
420 throw Platform::Exceptions::LinksLimitReachedException();
421 }
422 if (header->AllocatedLinks >= (header->ReservedLinks - 1))
423 {
424 _memory.ReservedCapacity(_memory.ReservedCapacity() + _memoryReservationStep);
426 header = &this->GetHeaderReference();
427 header->ReservedLinks = _memory.ReservedCapacity() / LinkSizeInBytes;
428 }
429 ++header->AllocatedLinks;
430 freeLink = header->AllocatedLinks;
431 _memory.UsedCapacity(_memory.UsedCapacity() + LinkSizeInBytes);
432 }
433 return handler(LinkType{0, 0, 0}, LinkType{freeLink, 0, 0});
434 }
435
436 public:
437 LinkAddressType Delete(const LinkType& restriction, const WriteHandlerType& handler)
438 {
439 auto& header = this->GetHeaderReference();
440 auto linkAddress = restriction[Constants.IndexPart];
441 auto before = GetLinkStruct(linkAddress);
442 if (linkAddress < header.AllocatedLinks)
443 {
444 _UnusedLinksListMethods->AttachAsFirst(linkAddress);
445 return handler ? handler(before, LinkType{}) : Constants.Continue;
446 }
447 else if (linkAddress == header.AllocatedLinks)
448 {
449 --header.AllocatedLinks;
450 _memory.UsedCapacity(_memory.UsedCapacity() - LinkSizeInBytes);
451 while ((header.AllocatedLinks > LinkAddressType{}) && IsUnusedLink(header.AllocatedLinks))
452 {
453 _UnusedLinksListMethods->Detach(header.AllocatedLinks);
454 --header.AllocatedLinks;
455 _memory.UsedCapacity(_memory.UsedCapacity() - LinkSizeInBytes);
456 }
457 return handler ? handler(before, LinkType{}) : Constants.Continue;
458 }
459 return Constants.Continue;
460 }
461
463 {
464 auto& link = this->GetLinkReference(linkIndex);
465 return LinkType{linkIndex, link.Source, link.Target};
466 }
467
468 // TODO: Возможно это должно быть событием, вызываемым из IMemory, в том случае, если адрес реально поменялся
469 //
470 // Указатель this.storage может быть в том же месте,
471 // так как 0-я связь не используется и имеет такой же размер как Header,
472 // поэтому header размещается в том же месте, что и 0-я связь
473 public:
474 void SetPointers(TMemory& memory)
475 {
476 _links = static_cast<std::byte*>(memory.Pointer());
477 _header = _links;
478 _SourcesTreeMethods = std::make_unique<TSourceTreeMethods>(_links, _header);
479 _TargetsTreeMethods = std::make_unique<TTargetTreeMethods>(_links, _header);
480 _UnusedLinksListMethods = std::make_unique<TUnusedLinks>(_links, _header);
481 }
482
483 bool Exists(LinkAddressType linkAddress) const
484 {
485 if (IsExternalReference<LinkAddressType, Constants>(linkAddress))
486 {
487 return false;
488 }
489 return (linkAddress >= Constants.InternalReferencesRange.Minimum) &&
490 (linkAddress <= this->GetHeaderReference().AllocatedLinks) && !IsUnusedLink(linkAddress);
491 }
492
493 bool IsUnusedLink(LinkAddressType linkIndex) const
494 {
495 if (GetHeaderReference().FirstFreeLink != linkIndex) // May be this check is not needed
496 {
497 auto& link = GetLinkReference(linkIndex);
498 return (link.SizeAsSource == LinkAddressType{}) && (link.Source != LinkAddressType{});
499 }
500 else
501 {
502 return true;
503 }
504 }
505 };
506} // namespace Platform::Data::Doublets::Memory::United::Generic
Definition LinksAvlBalancedTreeMethodsBase.h:2
Definition RawLinkDataPart.h:38
typename LinksOptionsType::LinkType LinkType
Definition UnitedMemoryLinksBase.h:11
void Init(TMemory &memory, std::size_t memoryReservationStep)
Definition UnitedMemoryLinksBase.h:76
static constexpr std::size_t LinkSizeInBytes
Definition UnitedMemoryLinksBase.h:17
void SetPointers(TMemory &memory)
Definition UnitedMemoryLinksBase.h:474
UnitedMemoryLinksBase(TMemory &&memory)
Definition UnitedMemoryLinksBase.h:68
LinkAddressType Each(const LinkType &restriction, const ReadHandlerType &handler) const
Definition UnitedMemoryLinksBase.h:220
typename LinksOptionsType::LinkAddressType LinkAddressType
Definition UnitedMemoryLinksBase.h:10
typename LinksOptionsType::ReadHandlerType ReadHandlerType
Definition UnitedMemoryLinksBase.h:13
LinkType GetLinkStruct(LinkAddressType linkIndex) const
Definition UnitedMemoryLinksBase.h:462
LinkAddressType Update(const LinkType &restriction, const LinkType &substitution, const WriteHandlerType &handler)
Definition UnitedMemoryLinksBase.h:364
bool IsUnusedLink(LinkAddressType linkIndex) const
Definition UnitedMemoryLinksBase.h:493
bool Exists(LinkAddressType linkAddress) const
Definition UnitedMemoryLinksBase.h:483
LinkAddressType Create(const LinkType &, const WriteHandlerType &handler)
Definition UnitedMemoryLinksBase.h:407
LinkAddressType Delete(const LinkType &restriction, const WriteHandlerType &handler)
Definition UnitedMemoryLinksBase.h:437
static constexpr std::size_t DefaultLinksSizeStep
Definition UnitedMemoryLinksBase.h:21
static constexpr std::size_t LinkHeaderSizeInBytes
Definition UnitedMemoryLinksBase.h:19
TLinkOptions LinksOptionsType
Definition UnitedMemoryLinksBase.h:9
UnitedMemoryLinksBase(TMemory &&memory, std::uint64_t memoryReservationStep)
Definition UnitedMemoryLinksBase.h:70
typename LinksOptionsType::WriteHandlerType WriteHandlerType
Definition UnitedMemoryLinksBase.h:12
LinkAddressType Count(const LinkType &restriction) const
Definition UnitedMemoryLinksBase.h:91
static constexpr LinksConstants< LinkAddressType > Constants
Definition UnitedMemoryLinksBase.h:14