Stroika Library 3.0d20
 
Loading...
Searching...
No Matches
Foundation/Memory/Common.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include <algorithm>
5#include <cstring>
6
10
11namespace Stroika::Foundation::Memory {
12
13 /*
14 ********************************************************************************
15 ********************************* Memory::NEltsOf ******************************
16 ********************************************************************************
17 */
18 template <typename ARRAY_TYPE, size_t SIZE_OF_ARRAY>
19 inline constexpr size_t NEltsOf ([[maybe_unused]] const ARRAY_TYPE (&arr)[SIZE_OF_ARRAY])
20 {
21 return SIZE_OF_ARRAY;
22 }
23
24 /*
25 ********************************************************************************
26 *************************** Memory::CompareBytes *******************************
27 ********************************************************************************
28 */
29 template <>
30 constexpr strong_ordering CompareBytes (const uint8_t* lhs, const uint8_t* rhs, size_t count)
31 {
32 DISABLE_COMPILER_MSC_WARNING_START (5063)
33 DISABLE_COMPILER_CLANG_WARNING_START ("clang diagnostic ignored \"-Wconstant-evaluated\"");
34 DISABLE_COMPILER_GCC_WARNING_START ("GCC diagnostic ignored \"-Wtautological-compare\"");
35 if constexpr (is_constant_evaluated ()) {
36 //Require (count == 0 or lhs != nullptr);
37 //Require (count == 0 or rhs != nullptr);
38 const uint8_t* li = lhs;
39 const uint8_t* ri = rhs;
40 for (; count--; ++li, ++ri) {
41 if (int cmp = static_cast<int> (*li) - static_cast<int> (*ri)) {
43 }
44 }
45 return strong_ordering::equal;
46 }
47 else {
48 if (count == 0) {
49 return strong_ordering::equal;
50 }
51 return Common::CompareResultNormalizer (::memcmp (lhs, rhs, count));
52 }
53 DISABLE_COMPILER_GCC_WARNING_END ("GCC diagnostic ignored \"-Wtautological-compare\"");
54 DISABLE_COMPILER_MSC_WARNING_END (5063)
55 DISABLE_COMPILER_CLANG_WARNING_END ("clang diagnostic ignored \"-Wconstant-evaluated\"");
56 }
57 template <typename T>
58 constexpr strong_ordering CompareBytes (const T* lhs, const T* rhs, size_t count)
59 {
60 return CompareBytes (reinterpret_cast<const uint8_t*> (lhs), reinterpret_cast<const uint8_t*> (rhs), count * sizeof (T));
61 }
62 template <typename TL, size_t EL, typename TR, size_t ER>
63 constexpr strong_ordering CompareBytes (span<TL, EL> lhs, span<TR, ER> rhs)
64 requires (same_as<remove_cvref_t<TL>, remove_cvref_t<TR>> and is_trivial_v<TL>)
65 {
66 Require (lhs.size () == rhs.size ());
67 return CompareBytes (lhs.data (), rhs.data (), lhs.size ());
68 }
69
70 /*
71 ********************************************************************************
72 ******************************** Memory::AsBytes *******************************
73 ********************************************************************************
74 */
75 template <typename T>
76 inline span<const byte> AsBytes (const T& elt)
77 requires (is_trivial_v<T>)
78 {
79 return as_bytes (span{&elt, 1}); //return span<const byte>{reinterpret_cast<const byte*> (&elt), sizeof (elt)};
80 }
81
82 /*
83 ********************************************************************************
84 ***************************** Memory::ConstSpan ********************************
85 ********************************************************************************
86 */
87 template <class T, size_t EXTENT>
88 constexpr span<const T, EXTENT> ConstSpan (span<T, EXTENT> s)
89 {
90 return s;
91 }
92
93 /*
94 ********************************************************************************
95 ***************************** Memory::Intersects *******************************
96 ********************************************************************************
97 */
98 template <typename T1, typename T2, size_t E1, size_t E2>
99 constexpr bool Intersects (span<T1, E1> lhs, span<T2, E2> rhs)
100 {
101 // See Range<T, TRAITS>::Intersects for explanation - avoid direct call here to avoid include file reference
102 /*
103 * Assume LHS is at given position. RHS could be A, B, C, D, E, F, G, or H
104 * | LHS |
105 * | A | | B | | C | | D | | E |
106 * | G | | H |
107 * | F |
108 */
109 if (lhs.empty () or rhs.empty ()) {
110 return false;
111 }
112 const byte* lhsStart = addressof (*as_bytes (lhs).data ());
113 const byte* rhsStart = addressof (*as_bytes (rhs).data ());
114 const byte* lhsEnd = lhsStart + lhs.size_bytes ();
115 const byte* rhsEnd = rhsStart + rhs.size_bytes ();
116 // NOTE - not sure how to test this safely in general. On segmented architectures, this test isn't legal, if they are not
117 // from the same segment, for example. C++ only guarantees test safe IF they overlap, in essence --LGP 2025-04-29
118 if (rhsEnd <= lhsStart) {
119 // cases A, G
120 return false; // combine two cases from Range<T, TRAITS>::Intersects cuz always closed
121 }
122 if (rhsStart >= lhsEnd) {
123 // cases E, H
124 return false; // ""
125 }
126 // cases B, C, D, F
127 return true;
128 }
129
130 /*
131 ********************************************************************************
132 ***************************** Memory::SpanBytesCast ****************************
133 ********************************************************************************
134 */
135 template <ISpan TO_SPAN, ISpanBytesCastable<TO_SPAN> FROM_SPAN>
136 constexpr TO_SPAN SpanBytesCast (FROM_SPAN src)
137 {
138 using TO_T = typename TO_SPAN::value_type;
139 Require ((src.size_bytes () / sizeof (TO_T)) * sizeof (TO_T) == src.size_bytes ()); // else cannot map evenly
140 // allow EITHER size or constness conversions - so NOT re-interpret cast
141 TO_SPAN result{(TO_T*)(src.data ()), src.size_bytes () / sizeof (TO_T)}; // no need to worry about overflow cuz then addressses would overflow
142 Ensure (src.size_bytes () == result.size_bytes ()); // size in elements can be <, ==, or >
143 return result;
144 }
145
146 /*
147 ********************************************************************************
148 ***************************** Memory::CopyBytes ********************************
149 ********************************************************************************
150 */
151 template <Common::trivially_copyable FROM_T, size_t FROM_E, Common::trivially_copyable TO_T, size_t TO_E>
152 constexpr span<TO_T, TO_E> CopyBytes (span<FROM_T, FROM_E> src, span<TO_T, TO_E> target) noexcept
153 requires (same_as<remove_cv_t<FROM_T>, TO_T>)
154 {
155 Require (src.size () <= target.size ());
156 Require (not Intersects (src, target));
157 DISABLE_COMPILER_GCC_WARNING_START ("GCC diagnostic ignored \"-Wstringop-overflow\""); // this suppress doesn't work for g++-11, so must use configure to add suppress to cmdline
158 copy (src.begin (), src.end (), target.data ());
159 DISABLE_COMPILER_GCC_WARNING_END ("GCC diagnostic ignored \"-Wstringop-overflow\"");
160 return target.subspan (0, src.size ());
161 }
162
163 /*
164 ********************************************************************************
165 ************************ Memory::CopyOverlappingBytes **************************
166 ********************************************************************************
167 */
168 template <Common::trivially_copyable FROM_T, size_t FROM_E, Common::trivially_copyable TO_T, size_t TO_E>
169 constexpr span<TO_T, TO_E> CopyOverlappingBytes (span<FROM_T, FROM_E> src, span<TO_T, TO_E> target) noexcept
170 requires (same_as<remove_cv_t<FROM_T>, TO_T>)
171 {
172 Require (src.size () <= target.size ());
173 if (src.size () == 0) {
174 Assert (target.size () == 0);
175 return target.subspan (0, 0);
176 }
177 // When copying overlapping ranges, std::copy is appropriate when copying to the left (beginning of the
178 // destination range is outside the source range) while std::copy_backward is appropriate when copying
179 // to the right (end of the destination range is outside the source range).
180 if (Intersects (src, target)) {
181 DISABLE_COMPILER_GCC_WARNING_START ("GCC diagnostic ignored \"-Wstringop-overflow\""); // this suppress doesn't work for g++-11, so must use configure to add suppress to cmdline
182 span<byte> targetBytes = as_writable_bytes (target);
183 span<const byte> srcBytes = as_bytes (src);
184 // we know they overlap, so just checking which is to the left and which to the right
185 if (addressof (*targetBytes.data ()) >= addressof (*srcBytes.data ())) {
186 // target inside src-range, so copy_backward
187 copy_backward (srcBytes.data (), srcBytes.data () + srcBytes.size (), targetBytes.data () + srcBytes.size ());
188 }
189 else {
190 copy (src.begin (), src.end (), target.data ());
191 }
192 DISABLE_COMPILER_GCC_WARNING_END ("GCC diagnostic ignored \"-Wstringop-overflow\"");
193 return target.subspan (0, src.size ());
194 }
195 else {
196 return CopyBytes (src, target);
197 }
198 }
199
200 /*
201 ********************************************************************************
202 ****************************** Memory::CopySpanData ****************************
203 ********************************************************************************
204 */
205 template <typename FROM_T, size_t FROM_E, typename TO_T, size_t TO_E>
206 constexpr span<TO_T, TO_E> CopySpanData (span<FROM_T, FROM_E> src, span<TO_T, TO_E> target)
207 requires (not is_const_v<TO_T>)
208 {
209 Require (not Intersects (src, target));
210 Require (src.size () <= target.size ()); // BUT size in BYTES need not match
211 if constexpr (Common::trivially_copyable<TO_T> and Common::trivially_copyable<FROM_T> and sizeof (FROM_T) == sizeof (TO_T)) {
212 // if elements trivially copyable, and STRIDE of elements same on both sides, can copy as bytes
213 return CopyBytes (SpanBytesCast<span<const TO_T, TO_E>> (src), target);
214 }
215 else {
216 // Do a for loop copying each element; this can be used to copy any data,
217 // like std::copy, except using spans not iterators, and no warning/error about target assignment (static_cast)
218 TO_T* tb = target.data ();
219 for (const FROM_T& i : src) {
220 *tb++ = static_cast<TO_T> (i);
221 }
222 return target.subspan (0, src.size ());
223 }
224 }
225
226 /*
227 ********************************************************************************
228 ********************* Memory::CopyOverlappingSpanData **************************
229 ********************************************************************************
230 */
231 template <typename T, size_t FROM_E, size_t TO_E>
232 constexpr span<T, TO_E> CopyOverlappingSpanData (span<T, FROM_E> src, span<T, TO_E> target)
233 requires (not is_const_v<T>)
234 {
235 Require (src.size () == target.size ());
236 if (target.size () != 0) {
237 if (Intersects (src, target)) {
238 // When copying overlapping ranges, std::copy is appropriate when copying to the left (beginning of the
239 // destination range is outside the source range) while std::copy_backward is appropriate when copying
240 // to the right (end of the destination range is outside the source range).
241 if (addressof (*target.data ()) >= addressof (*src.data ())) {
242 // target inside src-range, so copy_backward
243 size_t nItems2Copy = src.size ();
244 copy_backward (src.data (), src.data () + nItems2Copy, target.data () + nItems2Copy);
245 }
246 else {
247 copy (src.begin (), src.end (), target.data ());
248 }
249 }
250 else {
251 return CopySpanData (src, target);
252 }
253 }
254 return target;
255 }
256
257 /*
258 ********************************************************************************
259 ********************************* Memory::Insert *******************************
260 ********************************************************************************
261 */
262 template <ISpan INTO_SPAN, ISpan FROM_SPAN>
263 requires (same_as<remove_const_t<typename INTO_SPAN::value_type>, remove_const_t<typename FROM_SPAN::value_type>>)
264 remove_cvref_t<INTO_SPAN> Insert (const INTO_SPAN& intoLiveSpan, const INTO_SPAN& intoReservedSpan, size_t at, const FROM_SPAN& copyFrom) noexcept
265 {
266 using T = remove_cvref_t<typename INTO_SPAN::value_type>;
267 Require (intoLiveSpan.data () == intoReservedSpan.data () or (intoLiveSpan.size () == 0));
268 size_t n2Add = copyFrom.size ();
269 Require (intoLiveSpan.size () + copyFrom.size () <= intoReservedSpan.size ());
270 Require (at + copyFrom.size () <= intoReservedSpan.size ());
271 T* b = intoReservedSpan.data ();
272 //
273 // at origSize
274 // v v
275 // [.....orig data... ...more data...]
276 //
277 // becomes (; slide by newS; but last newS elts uninitialized_copy copy, and regular copy rest)
278 //
279 // at at+n2Add
280 // v v
281 // [.....orig data... {copyFrom} ...more data...]
282 //
283 //
284 size_t origSize = intoLiveSpan.size ();
285 size_t newSize = origSize + n2Add;
286 Assert (newSize > 0);
287
288 if constexpr (is_trivially_copyable_v<T>) {
289 // we don't need to pay attention to what is initialized and what is not so quicker and easier.
290 // So slosh bytes after at down, and copy in the new ones
291 CopyOverlappingBytes (span{b + at, origSize - at}, span{b + at + n2Add, origSize - at});
292#if qCompilerAndStdLib_stdlib_ranges_pretty_broken_Buggy
293 uninitialized_copy (copyFrom.begin (), copyFrom.end (), b + at);
294#else
295 ranges::uninitialized_copy (copyFrom, span{b + at, n2Add});
296#endif
297 }
298 else {
299 // Simple but not super algorithm, append the data (using uninitialized_copy)
300 // and then std::rotate () - idea lifted from MSVC std::vector::insert()
301 // reason for trixyness, is cuz we need uninitialized_copy for new stuff (into uninitialized memory)
302 // and copy with destruction of old stuff for rest (handled by rotate)
303#if qCompilerAndStdLib_stdlib_ranges_pretty_broken_Buggy
304 uninitialized_copy (copyFrom.begin (), copyFrom.end (), b + origSize);
305#else
306 ranges::uninitialized_copy (copyFrom, span{b + origSize, n2Add});
307#endif
308 rotate (b + at, b + origSize, b + newSize);
309 }
310 return intoReservedSpan.subspan (0, newSize);
311 }
312
313 /*
314 ********************************************************************************
315 ********************************* Memory::Remove *******************************
316 ********************************************************************************
317 */
318 template <ISpan FROM_SPAN>
319 requires (not is_const_v<typename FROM_SPAN::value_type>)
320 remove_cvref_t<FROM_SPAN> Remove (FROM_SPAN&& spanToEdit, FROM_SPAN&& reservedSpan, size_t from, size_t to) noexcept
321 {
322 // @todo FIX - this COPIES elements during destroy, but should MOVE THEM - slight performance optimization sometimes
323 using T = remove_cvref_t<typename FROM_SPAN::value_type>;
324 Require (spanToEdit.data () == reservedSpan.data () or (spanToEdit.data () == nullptr and spanToEdit.size () == 0));
325 Require (from <= to);
326 Require (to <= spanToEdit.size ());
327 T* b = reservedSpan.data ();
328 size_t amountRemoved = to - from;
329
330 // if removing from anything BUT the end of the (live) buffer, we must slide items down
331 if (to < spanToEdit.size ()) {
332 /*
333 * Slide items down. Note - this operates ENTIRELY on LIVE (constructed) objects.
334 * b b+from b+to
335 * v v v
336 * | .... RANGE2REMOVE|STUFF-AFTER|END-OF-BUFFER
337 * produces
338 * | .....STUFF-AFTER|END-OF-BUFFER
339 * /\
340 * b+spanToEdit.size()-amountRemoved
341 */
342 auto copySrcSpan = span{b + to, b + spanToEdit.size ()}; // STUFF-AFTER in first line
343 auto copyToSpan = span{b + from, copySrcSpan.size ()}; // RANGE2REMOVE in first line
344 Memory::CopyOverlappingSpanData (copySrcSpan, copyToSpan);
345 }
346 // but either way, we must destroy a few elements at the end, and return the updated span
347 auto destroySpan = span{b + spanToEdit.size () - amountRemoved, amountRemoved};
348#if qCompilerAndStdLib_stdlib_ranges_pretty_broken_Buggy
349 destroy (destroySpan.begin (), destroySpan.end ());
350#else
351 ranges::destroy (destroySpan);
352#endif
353 return reservedSpan.subspan (0, spanToEdit.size () - amountRemoved);
354 }
355
356 /*
357 ********************************************************************************
358 ******************************** Memory::OffsetOf ******************************
359 ********************************************************************************
360 */
361 namespace Private_ {
362 namespace OffsetOfImpl_ {
363 namespace UsingRecursiveSideStruct_ {
364 // OffsetOf_ BASED ON CODE FROM - https://gist.github.com/graphitemaster/494f21190bb2c63c5516
365#pragma pack(push, 1)
366 template <typename MEMBER, size_t N_PAD_BYTES>
367 struct Pad {
368 char pad[N_PAD_BYTES];
369 MEMBER m;
370 };
371#pragma pack(pop)
372 template <typename MEMBER>
373 struct Pad<MEMBER, 0> {
374 MEMBER m;
375 };
376
377 DISABLE_COMPILER_MSC_WARNING_START (4324);
378 template <typename BASE, typename MEMBER, size_t O>
379 struct MakeUnion {
380 union U {
381 char c;
382 BASE base;
383 Pad<MEMBER, O> pad;
384 constexpr U () noexcept
385 : c{} {};
386 ~U () = delete;
387 };
388 //constexpr static U* u{}; // old code did this, but doesn't work if MEMBER field has type which is not allowed to be constexpr --LGP 2023-08-20
389 constexpr static U* u{nullptr}; // don't actually allocate an object (maybe use declval instead?) - cuz else U not literal type sometimes if MEMBER obj type not literal
390 };
391 DISABLE_COMPILER_MSC_WARNING_END (4324);
392
393 template <typename MEMBER, typename BASE_CLASS, typename ORIG_CLASS>
394 struct offset_of_impl {
395 template <size_t off, auto union_part = MakeUnion<BASE_CLASS, MEMBER, off>::u>
396 // This gets called with nullptr as 'object' for computing diff below to avoid ever building the object (cuz just computing offsets)
397 Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_UNDEFINED static constexpr ptrdiff_t offset2 (MEMBER ORIG_CLASS::* member)
398 {
399 if constexpr (off > sizeof (BASE_CLASS)) {
400 throw 1;
401 }
402 else {
403 const auto diff1 = &((static_cast<const ORIG_CLASS*> (&union_part->base))->*member);
404 const auto diff2 = &union_part->pad.m;
405 if (diff1 > diff2) {
406 constexpr auto MIN = (sizeof (MEMBER) < alignof (ORIG_CLASS)) ? sizeof (MEMBER) : alignof (ORIG_CLASS);
407 return offset2<off + MIN> (member);
408 }
409 else {
410 return off;
411 }
412 }
413 }
414 };
415
416 template <class MEMBER, class BASE_CLASS>
417 tuple<MEMBER, BASE_CLASS> get_types (MEMBER BASE_CLASS::*); // never defined, never really called, just used to extract types with decltype()
418
419 template <class TheBase = void, class TT>
420 inline constexpr size_t offset_of (TT member)
421 {
422 using T = decltype (get_types (declval<TT> ()));
423 using Member = tuple_element_t<0, T>;
424 using Orig = tuple_element_t<1, T>;
425 using Base = conditional_t<is_void_v<TheBase>, Orig, TheBase>;
426 return static_cast<size_t> (offset_of_impl<Member, Base, Orig>::template offset2<0> (member));
427 }
428 }
429
430 namespace RequiringDefaultConstructibleObjectType_ {
431 // @see https://gist.github.com/graphitemaster/494f21190bb2c63c5516 for more info on maybe how to
432 template <typename T1, typename T2>
433 struct offset_of {
434 static constexpr size_t offset (T1 T2::* member)
435 {
436 union X {
437 array<char, sizeof (T2)> bytes;
438 T2 obj;
439 X () {};
440 ~X () {};
441 } objAsUnion;
442 /*
443 * &&& maybe not undefined anymore
444 * UNDEFINED BEHAVIOR: it is undefined, but for the following reason: expr.add-5.sentence-2
445 * "If the expressions P and Q point to, respectively, elements x[i] and x[j] of
446 * the same array object x, the expression P - Q has the value i - j; otherwise, the behavior is undefined."]
447 */
448 return size_t (&(objAsUnion.obj.*member)) - size_t (&objAsUnion.obj);
449 }
450 };
451 }
452
453 namespace UsingAlignedByteArrayBuf_ {
454 template <typename FIELD_VALUE_TYPE, typename OWNING_OBJECT>
455 inline size_t offset_of (FIELD_VALUE_TYPE OWNING_OBJECT::* member)
456 {
457 // Still not totally legal for non-std-layout classes, but seems to work, and I haven't found a better way
458 // --LGP 2021-05-27
459 alignas (OWNING_OBJECT) byte buf[sizeof (OWNING_OBJECT)]{};
460 const OWNING_OBJECT& o = *reinterpret_cast<const OWNING_OBJECT*> (&buf);
461 auto result = size_t (reinterpret_cast<const char*> (&(o.*member)) - reinterpret_cast<const char*> (&o));
462 // Avoid #include - Ensure (result <= sizeof (OWNING_OBJECT));
463 return result;
464 }
465 }
466
467 namespace UseExplicitDefaultConstructibleStaticInstance_ {
468 // @see https://gist.github.com/graphitemaster/494f21190bb2c63c5516 for more info on maybe how to
469 // get this working with constexpr and without static object
470 template <typename T1, typename T2>
471 struct offset_of_ {
472 static inline constexpr T2 sObj_{};
473 static constexpr size_t offset (T1 T2::* member)
474 {
475 /*
476 * UNDEFINED BEHAVIOR: it is undefined, but for the following reason: expr.add-5.sentence-2
477 * "If the expressions P and Q point to, respectively, elements x[i] and x[j] of
478 * the same array object x, the expression P - Q has the value i - j; otherwise, the behavior is undefined."]
479 */
480 return size_t (&(offset_of_<T1, T2>::sObj_.*member)) - size_t (&offset_of_<T1, T2>::sObj_);
481 }
482 };
483 }
484
485 namespace UsingSimpleUnionToConstructActualObj_ {
486
487 template <typename OUTER_OBJECT, typename DATA_MEMBER_TYPE>
488 inline constexpr size_t offset_of (DATA_MEMBER_TYPE (OUTER_OBJECT::* dataMember))
489 {
490 // NOT real assert - just tmphack to test
491 // auto a1 = Private_::OffsetOfImpl_::UsingRecursiveSideStruct_::offset_of<OUTER_OBJECT> (dataMember);
492 // auto a2 = PRIVATE_::OffsetOfImpl_::UsingAlignedByteArrayBuf_ (dataMember);
493 // auto a3 = PRIVATE_::OffsetOfImpl_::RequiringDefaultConstructibleObjectType_::offset_of<DATA_MEMBER_TYPE, OUTER_OBJECT>::offset (dataMember);
494 //WeakAssert (a1 == a2);
495
496 union X {
497 array<char, sizeof (OUTER_OBJECT)> bytes;
498 OUTER_OBJECT obj;
499 X () {};
500 ~X () {};
501 } objAsUnion;
502
503 // auto a4 = size_t (&(objAsUnion.obj.*dataMember)) - size_t (&objAsUnion.bytes);
504
505 /*
506 * &&& maybe not undefined anymore
507 * UNDEFINED BEHAVIOR: it is undefined, but for the following reason: expr.add-5.sentence-2
508 * "If the expressions P and Q point to, respectively, elements x[i] and x[j] of
509 * the same array object x, the expression P - Q has the value i - j; otherwise, the behavior is undefined."]
510 */
511 return size_t (&(objAsUnion.obj.*dataMember)) - size_t (&objAsUnion.obj);
512
513 //https://stackoverflow.com/questions/12141446/offset-from-member-pointer-without-temporary-instance
514 // return Private_::OffsetOf2_::offset_of<OUTER_OBJECT> (dataMember);
515 }
516
517 }
518 }
519 }
520
521 template <typename OUTER_OBJECT, typename DATA_MEMBER_TYPE>
522 inline constexpr size_t OffsetOf (DATA_MEMBER_TYPE (OUTER_OBJECT::* dataMember))
523 {
524 //constexpr bool kTestAllWays_ = false;
525 constexpr bool kTestAllWays_ = true;
526 [[maybe_unused]] size_t r1;
527 [[maybe_unused]] size_t r2;
528 [[maybe_unused]] size_t r3;
529 [[maybe_unused]] size_t r4;
530 if constexpr (kTestAllWays_) {
531 /*
532 * Setup to test/try each implementation. One with apparently best shot of working constexpr is UsingRecursiveSideStruct_
533 * HOWEVER, it requires (on unix) setting -ftemplate-depth=5000 flags, and even then, doesn't really work constexpr (complains about dereferencing nullptr).
534 *
535 * Don't give up, but no success so far. MAYBE works OK/portably without the constexpr stuff. Dunno. Probably NOT for the same deref-nullptr reason.
536 */
537#if defined(_MSC_VER)
538 // Don't bother compiling for gcc/clang cuz fails on some compilers without -fdepth= flag, and no point since wont really work right even
539 // if you provide that flag. REVISIT in the future maybe, but for now don't even bother calling
540 r1 = Private_::OffsetOfImpl_::UsingRecursiveSideStruct_::offset_of<OUTER_OBJECT> (dataMember);
541#endif
542 r2 = Private_::OffsetOfImpl_::RequiringDefaultConstructibleObjectType_::offset_of<DATA_MEMBER_TYPE, OUTER_OBJECT>::offset (dataMember);
543 r3 = Private_::OffsetOfImpl_::UsingAlignedByteArrayBuf_::offset_of<DATA_MEMBER_TYPE, OUTER_OBJECT> (dataMember);
544 if constexpr (is_trivially_default_constructible_v<OUTER_OBJECT>) {
545 r4 = Private_::OffsetOfImpl_::UseExplicitDefaultConstructibleStaticInstance_::offset_of_<DATA_MEMBER_TYPE, OUTER_OBJECT>::offset (dataMember);
546 }
547 }
548 size_t r5 = Private_::OffsetOfImpl_::UsingSimpleUnionToConstructActualObj_::offset_of<OUTER_OBJECT, DATA_MEMBER_TYPE> (dataMember);
549 size_t rr = r5;
550 if (not is_constant_evaluated () and kTestAllWays_) {
551#if defined(_MSC_VER)
552 Assert (r1 == rr);
553#endif
554 Assert (r2 == rr);
555 Assert (r3 == rr);
556 if constexpr (is_trivially_default_constructible_v<OUTER_OBJECT>) {
557 Assert (r4 == rr);
558 }
559 }
560 return rr;
561 }
562
563 /*
564 ********************************************************************************
565 ********************* Memory::Literals::operator""_b ***************************
566 ********************************************************************************
567 */
568 inline namespace Literals {
569 constexpr byte operator""_b (unsigned long long b)
570 {
571 Require (b <= 0xff);
572 return static_cast<byte> (b);
573 }
574 }
575
576 ////////////////////// DEPRECATED .//////////////////////////
577 template <typename FIELD_VALUE_TYPE, typename OWNING_OBJECT>
578 [[deprecated ("Since Stroika v3.0d2 - just use OffsetOf")]] inline size_t constexpr OffsetOf_Constexpr (FIELD_VALUE_TYPE OWNING_OBJECT::* member)
579 {
580 return OffsetOf (member);
581 }
582 template <typename T>
583 [[deprecated ("Since Stroika v3.0d12 - use CompareBytes")]] constexpr strong_ordering MemCmp (const T* lhs, const T* rhs, size_t count)
584 {
585 return CompareBytes (lhs, rhs, count);
586 }
587 template <typename T>
588 [[deprecated ("Since Stroika v3.0d12 - use CompareBytes")]] constexpr strong_ordering MemCmp (span<const T> lhs, span<const T> rhs)
589 {
590 return CompareBytes (lhs, rhs);
591 }
592 template <typename T>
593 [[deprecated ("Since Stroika v3.0d12 - use CompareBytes")]] constexpr strong_ordering MemCmp (span<T> lhs, span<T> rhs)
594 {
595 return CompareBytes (lhs, rhs);
596 }
597 template <typename FROM_T, size_t FROM_E, typename TO_T, size_t TO_E>
598 [[deprecated ("Since Stroika v3.0d12 use CopyBytes")]] constexpr span<TO_T, TO_E> CopySpanData_StaticCast (span<const FROM_T, FROM_E> src,
599 span<TO_T, TO_E> target)
600 {
601 return CopySpanData (src, target);
602 }
603 template <typename FROM_T, size_t FROM_E, typename TO_T, size_t TO_E>
604 [[deprecated ("Since Stroika v3.0d12 use CopyBytes")]] constexpr std::span<TO_T, TO_E> CopySpanData_StaticCast (span<FROM_T, FROM_E> src,
605 span<TO_T, TO_E> target)
606 {
607 return CopySpanData (ConstSpan (src), target);
608 }
609
610}
bool Intersects(const set< T > &s1, const set< T > &s2)
constexpr strong_ordering CompareResultNormalizer(FROM_INT_TYPE f)
Definition Compare.inl:226