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 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 ()) {
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)) {
45 return strong_ordering::equal;
49 return strong_ordering::equal;
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\"");
58 constexpr strong_ordering CompareBytes (const T* lhs, const T* rhs,
size_t count)
60 return CompareBytes (
reinterpret_cast<const uint8_t*
> (lhs),
reinterpret_cast<const uint8_t*
> (rhs), count *
sizeof (T));
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>)
66 Require (lhs.size () == rhs.size ());
67 return CompareBytes (lhs.data (), rhs.data (), lhs.size ());
76 inline span<const byte> AsBytes (
const T& elt)
77 requires (is_trivial_v<T>)
79 return as_bytes (span{&elt, 1});
87 template <
class T,
size_t EXTENT>
88 constexpr span<const T, EXTENT> ConstSpan (span<T, EXTENT> s)
98 template <
typename T1,
typename T2,
size_t E1,
size_t E2>
99 constexpr bool Intersects (span<T1, E1> lhs, span<T2, E2> rhs)
102 if (lhs.empty () or rhs.empty ()) {
105 const byte* lhsStart = addressof (*as_bytes (lhs).data ());
106 const byte* rhsStart = addressof (*as_bytes (rhs).data ());
107 const byte* lhsEnd = lhsStart + lhs.size_bytes ();
108 const byte* rhsEnd = rhsStart + rhs.size_bytes ();
109 if (rhsEnd <= lhsStart) {
112 if (rhsStart >= lhsEnd) {
123 template <ISpan TO_SPAN, ISpanBytesCastable<TO_SPAN> FROM_SPAN>
124 constexpr TO_SPAN SpanBytesCast (FROM_SPAN src)
126 using TO_T =
typename TO_SPAN::value_type;
127 Require ((src.size_bytes () / sizeof (TO_T)) *
sizeof (TO_T) == src.size_bytes ());
129 TO_SPAN result{(TO_T*)(src.data ()), src.size_bytes () /
sizeof (TO_T)};
130 Ensure (src.size_bytes () == result.size_bytes ());
139 template <Common::trivially_copyable FROM_T,
size_t FROM_E, Common::trivially_copyable TO_T,
size_t TO_E>
140 constexpr span<TO_T, TO_E> CopyBytes (span<FROM_T, FROM_E> src, span<TO_T, TO_E> target)
noexcept
141 requires (same_as<remove_cv_t<FROM_T>, TO_T>)
143 Require (src.size () <= target.size ());
144 Require (not Intersects (src, target));
145 DISABLE_COMPILER_GCC_WARNING_START (
"GCC diagnostic ignored \"-Wstringop-overflow\"");
146 copy (src.begin (), src.end (), target.data ());
147 DISABLE_COMPILER_GCC_WARNING_END (
"GCC diagnostic ignored \"-Wstringop-overflow\"");
148 return target.subspan (0, src.size ());
156 template <Common::trivially_copyable FROM_T,
size_t FROM_E, Common::trivially_copyable TO_T,
size_t TO_E>
157 constexpr span<TO_T, TO_E> CopyOverlappingBytes (span<FROM_T, FROM_E> src, span<TO_T, TO_E> target)
noexcept
158 requires (same_as<remove_cv_t<FROM_T>, TO_T>)
160 Require (src.size () <= target.size ());
161 if (src.size () == 0) {
162 Assert (target.size () == 0);
163 return target.subspan (0, 0);
168 if (Intersects (src, target)) {
169 DISABLE_COMPILER_GCC_WARNING_START (
"GCC diagnostic ignored \"-Wstringop-overflow\"");
170 span<byte> targetBytes = as_writable_bytes (target);
171 span<const byte> srcBytes = as_bytes (src);
172 if (addressof (*targetBytes.data ()) >= addressof (*srcBytes.data ()) + srcBytes.size ()) {
174 copy_backward (srcBytes.data (), srcBytes.data () + srcBytes.size (), targetBytes.data () + srcBytes.size ());
177 copy (src.begin (), src.end (), target.data ());
179 DISABLE_COMPILER_GCC_WARNING_END (
"GCC diagnostic ignored \"-Wstringop-overflow\"");
180 return target.subspan (0, src.size ());
183 return CopyBytes (src, target);
192 template <
typename FROM_T,
size_t FROM_E,
typename TO_T,
size_t TO_E>
193 constexpr span<TO_T, TO_E> CopySpanData (span<FROM_T, FROM_E> src, span<TO_T, TO_E> target)
194 requires (not is_const_v<TO_T>)
196 Require (not Intersects (src, target));
197 Require (src.size () <= target.size ());
198 if constexpr (Common::trivially_copyable<TO_T> and Common::trivially_copyable<FROM_T> and
sizeof (FROM_T) ==
sizeof (TO_T)) {
200 return CopyBytes (SpanBytesCast<span<const TO_T, TO_E>> (src), target);
205 TO_T* tb = target.data ();
206 for (
const FROM_T& i : src) {
207 *tb++ =
static_cast<TO_T
> (i);
209 return target.subspan (0, src.size ());
218 template <
typename T,
size_t FROM_E,
size_t TO_E>
219 constexpr span<T, TO_E> CopyOverlappingSpanData (span<T, FROM_E> src, span<T, TO_E> target)
220 requires (not is_const_v<T>)
222 Require (src.size () == target.size ());
223 if (target.size () != 0) {
224 if (Intersects (src, target)) {
228 if (addressof (*target.data ()) >= addressof (*src.data ())) {
230 size_t nItems2Copy = src.size ();
231 copy_backward (src.data (), src.data () + nItems2Copy, target.data () + nItems2Copy);
234 copy (src.begin (), src.end (), target.data ());
238 return CopySpanData (src, target);
249 template <ISpan INTO_SPAN, ISpan FROM_SPAN>
250 requires (same_as<remove_const_t<typename INTO_SPAN::value_type>, remove_const_t<typename FROM_SPAN::value_type>>)
251 remove_cvref_t<INTO_SPAN> Insert (
const INTO_SPAN& intoLiveSpan,
const INTO_SPAN& intoReservedSpan,
size_t at,
const FROM_SPAN& copyFrom)
noexcept
253 using T = remove_cvref_t<typename INTO_SPAN::value_type>;
254 Require (intoLiveSpan.data () == intoReservedSpan.data () or (intoLiveSpan.size () == 0));
255 size_t n2Add = copyFrom.size ();
256 Require (intoLiveSpan.size () + copyFrom.size () <= intoReservedSpan.size ());
257 Require (at + copyFrom.size () <= intoReservedSpan.size ());
258 T* b = intoReservedSpan.data ();
271 size_t origSize = intoLiveSpan.size ();
272 size_t newSize = origSize + n2Add;
273 Assert (newSize > 0);
276 if constexpr (
true) {
278 if constexpr (not is_trivially_constructible_v<T>) {
279 if constexpr (
true) {
280 uninitialized_copy (copyFrom.begin (), copyFrom.end (), b + origSize);
283 for (
size_t i = 0; i < n2Add; ++i) {
284 new (b + origSize + i) T{copyFrom[i]};
292 if constexpr (
true) {
293 copy_backward (b + at, b + origSize, b + origSize + n2Add);
296 for (
size_t i = origSize; i > at; --i) {
297 b[i - 1 + n2Add] = b[i - 1];
302 if constexpr (
true) {
303 copy (copyFrom.begin (), copyFrom.end (), b + at);
306 for (
size_t i = 0; i < n2Add; ++i) {
307 b[at + i] = copyFrom[i];
311 else if constexpr (is_trivially_copyable_v<T>) {
314 CopyOverlappingBytes (span{b + at, origSize - at}, span{b + at + n2Add, origSize - at});
315#if qCompilerAndStdLib_stdlib_ranges_pretty_broken_Buggy
316 uninitialized_copy (copyFrom.begin (), copyFrom.end (), b + at);
318 ranges::uninitialized_copy (copyFrom, span{b + at, n2Add});
326#if qCompilerAndStdLib_stdlib_ranges_pretty_broken_Buggy
327 uninitialized_copy (copyFrom.begin (), copyFrom.end (), b + origSize);
329 ranges::uninitialized_copy (copyFrom, span{b + origSize, n2Add});
331 rotate (b + at, b + origSize, b + newSize);
333 return intoReservedSpan.subspan (0, newSize);
341 template <ISpan FROM_SPAN>
342 requires (not is_const_v<typename FROM_SPAN::value_type>)
343 remove_cvref_t<FROM_SPAN> Remove (FROM_SPAN&& spanToEdit, FROM_SPAN&& reservedSpan,
size_t from,
size_t to)
noexcept
346 using T = remove_cvref_t<typename FROM_SPAN::value_type>;
347 Require (spanToEdit.data () == reservedSpan.data () or (spanToEdit.data () ==
nullptr and spanToEdit.size () == 0));
348 Require (from <= to);
349 Require (to <= spanToEdit.size ());
350 T* b = reservedSpan.data ();
351 size_t amountRemoved = to - from;
354 if (to < spanToEdit.size ()) {
365 auto copySrcSpan = span{b + to, b + spanToEdit.size ()};
366 auto copyToSpan = span{b + from, copySrcSpan.size ()};
367 Memory::CopyOverlappingSpanData (copySrcSpan, copyToSpan);
370 auto destroySpan = span{b + spanToEdit.size () - amountRemoved, amountRemoved};
371#if qCompilerAndStdLib_stdlib_ranges_pretty_broken_Buggy
372 destroy (destroySpan.begin (), destroySpan.end ());
374 ranges::destroy (destroySpan);
376 return reservedSpan.subspan (0, spanToEdit.size () - amountRemoved);
385 namespace OffsetOfImpl_ {
386 namespace UsingRecursiveSideStruct_ {
389 template <
typename MEMBER,
size_t N_PAD_BYTES>
391 char pad[N_PAD_BYTES];
395 template <
typename MEMBER>
396 struct Pad<MEMBER, 0> {
400 DISABLE_COMPILER_MSC_WARNING_START (4324);
401 template <
typename BASE,
typename MEMBER,
size_t O>
407 constexpr U () noexcept
412 constexpr static U* u{
nullptr};
414 DISABLE_COMPILER_MSC_WARNING_END (4324);
416 template <
typename MEMBER,
typename BASE_CLASS,
typename ORIG_CLASS>
417 struct offset_of_impl {
418 template <size_t off, auto union_part = MakeUnion<BASE_CLASS, MEMBER, off>::u>
420 Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_UNDEFINED
static constexpr ptrdiff_t offset2 (MEMBER ORIG_CLASS::* member)
422 if constexpr (off >
sizeof (BASE_CLASS)) {
426 const auto diff1 = &((
static_cast<const ORIG_CLASS*
> (&union_part->base))->*member);
427 const auto diff2 = &union_part->pad.m;
429 constexpr auto MIN = (
sizeof (MEMBER) <
alignof (ORIG_CLASS)) ?
sizeof (MEMBER) :
alignof (ORIG_CLASS);
430 return offset2<off + MIN> (member);
439 template <
class MEMBER,
class BASE_CLASS>
440 tuple<MEMBER, BASE_CLASS> get_types (MEMBER BASE_CLASS::*);
442 template <
class TheBase =
void,
class TT>
443 inline constexpr size_t offset_of (TT member)
445 using T =
decltype (get_types (declval<TT> ()));
446 using Member = tuple_element_t<0, T>;
447 using Orig = tuple_element_t<1, T>;
448 using Base = conditional_t<is_void_v<TheBase>, Orig, TheBase>;
449 return static_cast<size_t> (offset_of_impl<Member, Base, Orig>::template offset2<0> (member));
453 namespace RequiringDefaultConstructibleObjectType_ {
455 template <
typename T1,
typename T2>
457 static constexpr size_t offset (T1 T2::* member)
460 array<char,
sizeof (T2)> bytes;
471 return size_t (&(objAsUnion.obj.*member)) - size_t (&objAsUnion.obj);
476 namespace UsingAlignedByteArrayBuf_ {
477 template <
typename FIELD_VALUE_TYPE,
typename OWNING_OBJECT>
478 inline size_t offset_of (FIELD_VALUE_TYPE OWNING_OBJECT::* member)
482 alignas (OWNING_OBJECT)
byte buf[
sizeof (OWNING_OBJECT)]{};
483 const OWNING_OBJECT& o = *
reinterpret_cast<const OWNING_OBJECT*
> (&buf);
484 auto result = size_t (
reinterpret_cast<const char*
> (&(o.*member)) -
reinterpret_cast<const char*
> (&o));
490 namespace UseExplicitDefaultConstructibleStaticInstance_ {
493 template <
typename T1,
typename T2>
495 static inline constexpr T2 sObj_{};
496 static constexpr size_t offset (T1 T2::* member)
503 return size_t (&(offset_of_<T1, T2>::sObj_.*member)) - size_t (&offset_of_<T1, T2>::sObj_);
508 namespace UsingSimpleUnionToConstructActualObj_ {
510 template <
typename OUTER_OBJECT,
typename DATA_MEMBER_TYPE>
511 inline constexpr size_t offset_of (DATA_MEMBER_TYPE (OUTER_OBJECT::* dataMember))
520 array<char,
sizeof (OUTER_OBJECT)> bytes;
534 return size_t (&(objAsUnion.obj.*dataMember)) - size_t (&objAsUnion.obj);
544 template <
typename OUTER_OBJECT,
typename DATA_MEMBER_TYPE>
545 inline constexpr size_t OffsetOf (DATA_MEMBER_TYPE (OUTER_OBJECT::* dataMember))
548 constexpr bool kTestAllWays_ =
true;
549 [[maybe_unused]]
size_t r1;
550 [[maybe_unused]]
size_t r2;
551 [[maybe_unused]]
size_t r3;
552 [[maybe_unused]]
size_t r4;
553 if constexpr (kTestAllWays_) {
563 r1 = Private_::OffsetOfImpl_::UsingRecursiveSideStruct_::offset_of<OUTER_OBJECT> (dataMember);
565 r2 = Private_::OffsetOfImpl_::RequiringDefaultConstructibleObjectType_::offset_of<DATA_MEMBER_TYPE, OUTER_OBJECT>::offset (dataMember);
566 r3 = Private_::OffsetOfImpl_::UsingAlignedByteArrayBuf_::offset_of<DATA_MEMBER_TYPE, OUTER_OBJECT> (dataMember);
567 if constexpr (is_trivially_default_constructible_v<OUTER_OBJECT>) {
568 r4 = Private_::OffsetOfImpl_::UseExplicitDefaultConstructibleStaticInstance_::offset_of_<DATA_MEMBER_TYPE, OUTER_OBJECT>::offset (dataMember);
571 size_t r5 = Private_::OffsetOfImpl_::UsingSimpleUnionToConstructActualObj_::offset_of<OUTER_OBJECT, DATA_MEMBER_TYPE> (dataMember);
573 if (not is_constant_evaluated () and kTestAllWays_) {
579 if constexpr (is_trivially_default_constructible_v<OUTER_OBJECT>) {
591 inline namespace Literals {
592 constexpr byte operator""_b (
unsigned long long b)
595 return static_cast<byte> (b);
600 template <
typename FIELD_VALUE_TYPE,
typename OWNING_OBJECT>
601 [[deprecated (
"Since Stroika v3.0d2 - just use OffsetOf")]]
inline size_t constexpr OffsetOf_Constexpr (FIELD_VALUE_TYPE OWNING_OBJECT::* member)
603 return OffsetOf (member);
605 template <
typename T>
606 [[deprecated (
"Since Stroika v3.0d12 - use CompareBytes")]]
constexpr strong_ordering MemCmp (
const T* lhs,
const T* rhs,
size_t count)
608 return CompareBytes (lhs, rhs, count);
610 template <
typename T>
611 [[deprecated (
"Since Stroika v3.0d12 - use CompareBytes")]]
constexpr strong_ordering MemCmp (span<const T> lhs, span<const T> rhs)
613 return CompareBytes (lhs, rhs);
615 template <
typename T>
616 [[deprecated (
"Since Stroika v3.0d12 - use CompareBytes")]]
constexpr strong_ordering MemCmp (span<T> lhs, span<T> rhs)
618 return CompareBytes (lhs, rhs);
620 template <
typename FROM_T,
size_t FROM_E,
typename TO_T,
size_t TO_E>
621 [[deprecated (
"Since Stroika v3.0d12 use CopyBytes")]]
constexpr span<TO_T, TO_E> CopySpanData_StaticCast (span<const FROM_T, FROM_E> src,
622 span<TO_T, TO_E> target)
624 return CopySpanData (src, target);
626 template <
typename FROM_T,
size_t FROM_E,
typename TO_T,
size_t TO_E>
627 [[deprecated (
"Since Stroika v3.0d12 use CopyBytes")]]
constexpr std::span<TO_T, TO_E> CopySpanData_StaticCast (span<FROM_T, FROM_E> src,
628 span<TO_T, TO_E> target)
630 return CopySpanData (ConstSpan (src), target);
bool Intersects(const set< T > &s1, const set< T > &s2)
constexpr strong_ordering CompareResultNormalizer(FROM_INT_TYPE f)