11namespace Stroika::Foundation::Memory {
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])
30 constexpr strong_ordering CompareBytes (
const uint8_t* lhs,
const uint8_t* rhs,
size_t count)
32 if (is_constant_evaluated ()) {
35 const uint8_t* li = lhs;
36 const uint8_t* ri = rhs;
37 for (; count--; ++li, ++ri) {
38 if (
int cmp =
static_cast<int> (*li) -
static_cast<int> (*ri)) {
42 return strong_ordering::equal;
45 if (count == 0) [[unlikely]] {
46 return strong_ordering::equal;
52 constexpr strong_ordering CompareBytes (
const T* lhs,
const T* rhs,
size_t count)
54 return CompareBytes (
reinterpret_cast<const uint8_t*
> (lhs),
reinterpret_cast<const uint8_t*
> (rhs), count *
sizeof (T));
56 template <
typename TL,
size_t EL,
typename TR,
size_t ER>
57 constexpr strong_ordering CompareBytes (span<TL, EL> lhs, span<TR, ER> rhs)
58 requires (same_as<remove_cvref_t<TL>, remove_cvref_t<TR>> and is_trivial_v<TL>)
60 Require (lhs.size () == rhs.size ());
61 return CompareBytes (lhs.data (), rhs.data (), lhs.size ());
70 inline span<const byte> AsBytes (
const T& elt)
71 requires (is_trivial_v<T>)
73 return as_bytes (span{&elt, 1});
81 template <
class T,
size_t EXTENT>
82 constexpr span<const T, EXTENT> ConstSpan (span<T, EXTENT> s)
92 template <
typename T1,
typename T2,
size_t E1,
size_t E2>
93 constexpr bool Intersects (span<T1, E1> lhs, span<T2, E2> rhs)
103 if (lhs.empty () or rhs.empty ()) {
106 const byte* lhsStart = addressof (*as_bytes (lhs).data ());
107 const byte* rhsStart = addressof (*as_bytes (rhs).data ());
108 const byte* lhsEnd = lhsStart + lhs.size_bytes ();
109 const byte* rhsEnd = rhsStart + rhs.size_bytes ();
112 if (rhsEnd <= lhsStart) {
116 if (rhsStart >= lhsEnd) {
129 template <ISpan TO_SPAN, ISpanBytesCastable<TO_SPAN> FROM_SPAN>
130 constexpr TO_SPAN SpanBytesCast (FROM_SPAN src)
132 using TO_T =
typename TO_SPAN::value_type;
133 Require ((src.size_bytes () / sizeof (TO_T)) *
sizeof (TO_T) == src.size_bytes ());
135 TO_SPAN result{(TO_T*)(src.data ()), src.size_bytes () /
sizeof (TO_T)};
136 Ensure (src.size_bytes () == result.size_bytes ());
145 template <Common::trivially_copyable FROM_T,
size_t FROM_E, Common::trivially_copyable TO_T,
size_t TO_E>
146 constexpr span<TO_T, TO_E> CopyBytes (span<FROM_T, FROM_E> src, span<TO_T, TO_E> target)
noexcept
147 requires (same_as<remove_cv_t<FROM_T>, TO_T>)
149 Require (src.size () <= target.size ());
150 Require (not Intersects (src, target));
151 copy (src.begin (), src.end (), target.data ());
152 return target.subspan (0, src.size ());
160 template <Common::trivially_copyable FROM_T,
size_t FROM_E, Common::trivially_copyable TO_T,
size_t TO_E>
161 constexpr span<TO_T, TO_E> CopyOverlappingBytes (span<FROM_T, FROM_E> src, span<TO_T, TO_E> target)
noexcept
162 requires (same_as<remove_cv_t<FROM_T>, TO_T>)
164 Require (src.size () <= target.size ());
165 if (src.size () == 0) {
166 Assert (target.size () == 0);
167 return target.subspan (0, 0);
172 if (Intersects (src, target)) {
173 span<byte> targetBytes = as_writable_bytes (target);
174 span<const byte> srcBytes = as_bytes (src);
176 if (addressof (*targetBytes.data ()) >= addressof (*srcBytes.data ())) {
178 copy_backward (srcBytes.data (), srcBytes.data () + srcBytes.size (), targetBytes.data () + srcBytes.size ());
181 copy (src.begin (), src.end (), target.data ());
183 return target.subspan (0, src.size ());
186 return CopyBytes (src, target);
195 template <
typename FROM_T,
size_t FROM_E,
typename TO_T,
size_t TO_E>
196 constexpr span<TO_T, TO_E> CopySpanData (span<FROM_T, FROM_E> src, span<TO_T, TO_E> target)
197 requires (not is_const_v<TO_T>)
199 Require (not Intersects (src, target));
200 Require (src.size () <= target.size ());
201 if constexpr (Common::trivially_copyable<TO_T> and Common::trivially_copyable<FROM_T> and
sizeof (FROM_T) ==
sizeof (TO_T)) {
203 return CopyBytes (SpanBytesCast<span<const TO_T, TO_E>> (src), target);
208 TO_T* tb = target.data ();
209 for (
const FROM_T& i : src) {
210 *tb++ =
static_cast<TO_T
> (i);
212 return target.subspan (0, src.size ());
221 template <
typename T,
size_t FROM_E,
size_t TO_E>
222 constexpr span<T, TO_E> CopyOverlappingSpanData (span<T, FROM_E> src, span<T, TO_E> target)
223 requires (not is_const_v<T>)
225 Require (src.size () == target.size ());
226 if (target.size () != 0) {
227 if (Intersects (src, target)) {
231 if (addressof (*target.data ()) >= addressof (*src.data ())) {
233 size_t nItems2Copy = src.size ();
234 copy_backward (src.data (), src.data () + nItems2Copy, target.data () + nItems2Copy);
237 copy (src.begin (), src.end (), target.data ());
241 return CopySpanData (src, target);
252 template <ISpan INTO_SPAN, ISpan FROM_SPAN>
253 requires (same_as<remove_const_t<typename INTO_SPAN::value_type>, remove_const_t<typename FROM_SPAN::value_type>>)
254 remove_cvref_t<INTO_SPAN> Insert (
const INTO_SPAN& intoLiveSpan,
const INTO_SPAN& intoReservedSpan,
size_t at,
const FROM_SPAN& copyFrom)
noexcept
256 using T = remove_cvref_t<typename INTO_SPAN::value_type>;
257 Require (intoLiveSpan.data () == intoReservedSpan.data () or (intoLiveSpan.size () == 0));
258 size_t n2Add = copyFrom.size ();
259 Require (intoLiveSpan.size () + copyFrom.size () <= intoReservedSpan.size ());
260 Require (at + copyFrom.size () <= intoReservedSpan.size ());
261 T* b = intoReservedSpan.data ();
274 size_t origSize = intoLiveSpan.size ();
275 size_t newSize = origSize + n2Add;
276 Assert (newSize > 0);
278 if constexpr (is_trivially_copyable_v<T>) {
281 CopyOverlappingBytes (span{b + at, origSize - at}, span{b + at + n2Add, origSize - at});
282#if qCompilerAndStdLib_stdlib_ranges_pretty_broken_Buggy
283 uninitialized_copy (copyFrom.begin (), copyFrom.end (), b + at);
285 ranges::uninitialized_copy (copyFrom, span{b + at, n2Add});
293#if qCompilerAndStdLib_stdlib_ranges_pretty_broken_Buggy
294 uninitialized_copy (copyFrom.begin (), copyFrom.end (), b + origSize);
296 ranges::uninitialized_copy (copyFrom, span{b + origSize, n2Add});
298 rotate (b + at, b + origSize, b + newSize);
300 return intoReservedSpan.subspan (0, newSize);
308 template <ISpan FROM_SPAN>
309 requires (not is_const_v<typename FROM_SPAN::value_type>)
310 remove_cvref_t<FROM_SPAN> Remove (FROM_SPAN&& spanToEdit, FROM_SPAN&& reservedSpan,
size_t from,
size_t to)
noexcept
313 using T = remove_cvref_t<typename FROM_SPAN::value_type>;
314 Require (spanToEdit.data () == reservedSpan.data () or (spanToEdit.data () ==
nullptr and spanToEdit.size () == 0));
315 Require (from <= to);
316 Require (to <= spanToEdit.size ());
317 T* b = reservedSpan.data ();
318 size_t amountRemoved = to - from;
321 if (to < spanToEdit.size ()) {
332 auto copySrcSpan = span{b + to, b + spanToEdit.size ()};
333 auto copyToSpan = span{b + from, copySrcSpan.size ()};
334 Memory::CopyOverlappingSpanData (copySrcSpan, copyToSpan);
337 auto destroySpan = span{b + spanToEdit.size () - amountRemoved, amountRemoved};
338#if qCompilerAndStdLib_stdlib_ranges_pretty_broken_Buggy
339 destroy (destroySpan.begin (), destroySpan.end ());
341 ranges::destroy (destroySpan);
343 return reservedSpan.subspan (0, spanToEdit.size () - amountRemoved);
352 namespace OffsetOfImpl_ {
353 namespace UsingRecursiveSideStruct_ {
356 template <
typename MEMBER,
size_t N_PAD_BYTES>
358 char pad[N_PAD_BYTES];
362 template <
typename MEMBER>
363 struct Pad<MEMBER, 0> {
367 DISABLE_COMPILER_MSC_WARNING_START (4324);
368 template <
typename BASE,
typename MEMBER,
size_t O>
374 constexpr U () noexcept
379 constexpr static U* u{
nullptr};
381 DISABLE_COMPILER_MSC_WARNING_END (4324);
383 template <
typename MEMBER,
typename BASE_CLASS,
typename ORIG_CLASS>
384 struct offset_of_impl {
385 template <size_t off, auto union_part = MakeUnion<BASE_CLASS, MEMBER, off>::u>
387 Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_UNDEFINED
static constexpr ptrdiff_t offset2 (MEMBER ORIG_CLASS::* member)
389 if constexpr (off >
sizeof (BASE_CLASS)) {
393 const auto diff1 = &((
static_cast<const ORIG_CLASS*
> (&union_part->base))->*member);
394 const auto diff2 = &union_part->pad.m;
396 constexpr auto MIN = (
sizeof (MEMBER) <
alignof (ORIG_CLASS)) ?
sizeof (MEMBER) :
alignof (ORIG_CLASS);
397 return offset2<off + MIN> (member);
406 template <
class MEMBER,
class BASE_CLASS>
407 tuple<MEMBER, BASE_CLASS> get_types (MEMBER BASE_CLASS::*);
409 template <
class TheBase =
void,
class TT>
410 inline constexpr size_t offset_of (TT member)
412 using T =
decltype (get_types (declval<TT> ()));
413 using Member = tuple_element_t<0, T>;
414 using Orig = tuple_element_t<1, T>;
415 using Base = conditional_t<is_void_v<TheBase>, Orig, TheBase>;
416 return static_cast<size_t> (offset_of_impl<Member, Base, Orig>::template offset2<0> (member));
420 namespace RequiringDefaultConstructibleObjectType_ {
422 template <
typename T1,
typename T2>
424 static constexpr size_t offset (T1 T2::* member)
427 array<char,
sizeof (T2)> bytes;
438 return size_t (&(objAsUnion.obj.*member)) - size_t (&objAsUnion.obj);
443 namespace UsingAlignedByteArrayBuf_ {
444 template <
typename FIELD_VALUE_TYPE,
typename OWNING_OBJECT>
445 inline size_t offset_of (FIELD_VALUE_TYPE OWNING_OBJECT::* member)
449 alignas (OWNING_OBJECT)
byte buf[
sizeof (OWNING_OBJECT)]{};
450 const OWNING_OBJECT& o = *
reinterpret_cast<const OWNING_OBJECT*
> (&buf);
451 auto result = size_t (
reinterpret_cast<const char*
> (&(o.*member)) -
reinterpret_cast<const char*
> (&o));
457 namespace UseExplicitDefaultConstructibleStaticInstance_ {
460 template <
typename T1,
typename T2>
462 static inline constexpr T2 sObj_{};
463 static constexpr size_t offset (T1 T2::* member)
470 return size_t (&(offset_of_<T1, T2>::sObj_.*member)) - size_t (&offset_of_<T1, T2>::sObj_);
475 namespace UsingSimpleUnionToConstructActualObj_ {
477 template <
typename OUTER_OBJECT,
typename DATA_MEMBER_TYPE>
478 inline constexpr size_t offset_of (DATA_MEMBER_TYPE (OUTER_OBJECT::* dataMember))
487 array<char,
sizeof (OUTER_OBJECT)> bytes;
501 return size_t (&(objAsUnion.obj.*dataMember)) - size_t (&objAsUnion.obj);
511 template <
typename OUTER_OBJECT,
typename DATA_MEMBER_TYPE>
512 inline constexpr size_t OffsetOf (DATA_MEMBER_TYPE (OUTER_OBJECT::* dataMember))
515 constexpr bool kTestAllWays_ =
true;
516 [[maybe_unused]]
size_t r1;
517 [[maybe_unused]]
size_t r2;
518 [[maybe_unused]]
size_t r3;
519 [[maybe_unused]]
size_t r4;
520 if constexpr (kTestAllWays_) {
530 r1 = Private_::OffsetOfImpl_::UsingRecursiveSideStruct_::offset_of<OUTER_OBJECT> (dataMember);
532 r2 = Private_::OffsetOfImpl_::RequiringDefaultConstructibleObjectType_::offset_of<DATA_MEMBER_TYPE, OUTER_OBJECT>::offset (dataMember);
533 r3 = Private_::OffsetOfImpl_::UsingAlignedByteArrayBuf_::offset_of<DATA_MEMBER_TYPE, OUTER_OBJECT> (dataMember);
534 if constexpr (is_trivially_default_constructible_v<OUTER_OBJECT>) {
535 r4 = Private_::OffsetOfImpl_::UseExplicitDefaultConstructibleStaticInstance_::offset_of_<DATA_MEMBER_TYPE, OUTER_OBJECT>::offset (dataMember);
538 size_t r5 = Private_::OffsetOfImpl_::UsingSimpleUnionToConstructActualObj_::offset_of<OUTER_OBJECT, DATA_MEMBER_TYPE> (dataMember);
540 if (not is_constant_evaluated () and kTestAllWays_) {
546 if constexpr (is_trivially_default_constructible_v<OUTER_OBJECT>) {
558 inline namespace Literals {
559 constexpr byte operator""_b (
unsigned long long b)
562 return static_cast<byte> (b);
567 template <
typename FIELD_VALUE_TYPE,
typename OWNING_OBJECT>
568 [[deprecated (
"Since Stroika v3.0d2 - just use OffsetOf")]]
inline size_t constexpr OffsetOf_Constexpr (FIELD_VALUE_TYPE OWNING_OBJECT::* member)
570 return OffsetOf (member);
572 template <
typename T>
573 [[deprecated (
"Since Stroika v3.0d12 - use CompareBytes")]]
constexpr strong_ordering MemCmp (
const T* lhs,
const T* rhs,
size_t count)
575 return CompareBytes (lhs, rhs, count);
577 template <
typename T>
578 [[deprecated (
"Since Stroika v3.0d12 - use CompareBytes")]]
constexpr strong_ordering MemCmp (span<const T> lhs, span<const T> rhs)
580 return CompareBytes (lhs, rhs);
582 template <
typename T>
583 [[deprecated (
"Since Stroika v3.0d12 - use CompareBytes")]]
constexpr strong_ordering MemCmp (span<T> lhs, span<T> rhs)
585 return CompareBytes (lhs, rhs);
587 template <
typename FROM_T,
size_t FROM_E,
typename TO_T,
size_t TO_E>
588 [[deprecated (
"Since Stroika v3.0d12 use CopyBytes")]]
constexpr span<TO_T, TO_E> CopySpanData_StaticCast (span<const FROM_T, FROM_E> src,
589 span<TO_T, TO_E> target)
591 return CopySpanData (src, target);
593 template <
typename FROM_T,
size_t FROM_E,
typename TO_T,
size_t TO_E>
594 [[deprecated (
"Since Stroika v3.0d12 use CopyBytes")]]
constexpr std::span<TO_T, TO_E> CopySpanData_StaticCast (span<FROM_T, FROM_E> src,
595 span<TO_T, TO_E> target)
597 return CopySpanData (ConstSpan (src), target);
bool Intersects(const set< T > &s1, const set< T > &s2)
constexpr strong_ordering CompareResultNormalizer(FROM_INT_TYPE f)