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)
109 if (lhs.empty () or rhs.empty ()) {
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 ();
118 if (rhsEnd <= lhsStart) {
122 if (rhsStart >= lhsEnd) {
135 template <ISpan TO_SPAN, ISpanBytesCastable<TO_SPAN> FROM_SPAN>
136 constexpr TO_SPAN SpanBytesCast (FROM_SPAN src)
138 using TO_T =
typename TO_SPAN::value_type;
139 Require ((src.size_bytes () / sizeof (TO_T)) *
sizeof (TO_T) == src.size_bytes ());
141 TO_SPAN result{(TO_T*)(src.data ()), src.size_bytes () /
sizeof (TO_T)};
142 Ensure (src.size_bytes () == result.size_bytes ());
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>)
155 Require (src.size () <= target.size ());
156 Require (not Intersects (src, target));
157 DISABLE_COMPILER_GCC_WARNING_START (
"GCC diagnostic ignored \"-Wstringop-overflow\"");
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 ());
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>)
172 Require (src.size () <= target.size ());
173 if (src.size () == 0) {
174 Assert (target.size () == 0);
175 return target.subspan (0, 0);
180 if (Intersects (src, target)) {
181 DISABLE_COMPILER_GCC_WARNING_START (
"GCC diagnostic ignored \"-Wstringop-overflow\"");
182 span<byte> targetBytes = as_writable_bytes (target);
183 span<const byte> srcBytes = as_bytes (src);
185 if (addressof (*targetBytes.data ()) >= addressof (*srcBytes.data ())) {
187 copy_backward (srcBytes.data (), srcBytes.data () + srcBytes.size (), targetBytes.data () + srcBytes.size ());
190 copy (src.begin (), src.end (), target.data ());
192 DISABLE_COMPILER_GCC_WARNING_END (
"GCC diagnostic ignored \"-Wstringop-overflow\"");
193 return target.subspan (0, src.size ());
196 return CopyBytes (src, target);
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>)
209 Require (not Intersects (src, target));
210 Require (src.size () <= target.size ());
211 if constexpr (Common::trivially_copyable<TO_T> and Common::trivially_copyable<FROM_T> and
sizeof (FROM_T) ==
sizeof (TO_T)) {
213 return CopyBytes (SpanBytesCast<span<const TO_T, TO_E>> (src), target);
218 TO_T* tb = target.data ();
219 for (
const FROM_T& i : src) {
220 *tb++ =
static_cast<TO_T
> (i);
222 return target.subspan (0, src.size ());
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>)
235 Require (src.size () == target.size ());
236 if (target.size () != 0) {
237 if (Intersects (src, target)) {
241 if (addressof (*target.data ()) >= addressof (*src.data ())) {
243 size_t nItems2Copy = src.size ();
244 copy_backward (src.data (), src.data () + nItems2Copy, target.data () + nItems2Copy);
247 copy (src.begin (), src.end (), target.data ());
251 return CopySpanData (src, target);
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
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 ();
284 size_t origSize = intoLiveSpan.size ();
285 size_t newSize = origSize + n2Add;
286 Assert (newSize > 0);
288 if constexpr (is_trivially_copyable_v<T>) {
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);
295 ranges::uninitialized_copy (copyFrom, span{b + at, n2Add});
303#if qCompilerAndStdLib_stdlib_ranges_pretty_broken_Buggy
304 uninitialized_copy (copyFrom.begin (), copyFrom.end (), b + origSize);
306 ranges::uninitialized_copy (copyFrom, span{b + origSize, n2Add});
308 rotate (b + at, b + origSize, b + newSize);
310 return intoReservedSpan.subspan (0, newSize);
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
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;
331 if (to < spanToEdit.size ()) {
342 auto copySrcSpan = span{b + to, b + spanToEdit.size ()};
343 auto copyToSpan = span{b + from, copySrcSpan.size ()};
344 Memory::CopyOverlappingSpanData (copySrcSpan, copyToSpan);
347 auto destroySpan = span{b + spanToEdit.size () - amountRemoved, amountRemoved};
348#if qCompilerAndStdLib_stdlib_ranges_pretty_broken_Buggy
349 destroy (destroySpan.begin (), destroySpan.end ());
351 ranges::destroy (destroySpan);
353 return reservedSpan.subspan (0, spanToEdit.size () - amountRemoved);
362 namespace OffsetOfImpl_ {
363 namespace UsingRecursiveSideStruct_ {
366 template <
typename MEMBER,
size_t N_PAD_BYTES>
368 char pad[N_PAD_BYTES];
372 template <
typename MEMBER>
373 struct Pad<MEMBER, 0> {
377 DISABLE_COMPILER_MSC_WARNING_START (4324);
378 template <
typename BASE,
typename MEMBER,
size_t O>
384 constexpr U () noexcept
389 constexpr static U* u{
nullptr};
391 DISABLE_COMPILER_MSC_WARNING_END (4324);
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>
397 Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_UNDEFINED
static constexpr ptrdiff_t offset2 (MEMBER ORIG_CLASS::* member)
399 if constexpr (off >
sizeof (BASE_CLASS)) {
403 const auto diff1 = &((
static_cast<const ORIG_CLASS*
> (&union_part->base))->*member);
404 const auto diff2 = &union_part->pad.m;
406 constexpr auto MIN = (
sizeof (MEMBER) <
alignof (ORIG_CLASS)) ?
sizeof (MEMBER) :
alignof (ORIG_CLASS);
407 return offset2<off + MIN> (member);
416 template <
class MEMBER,
class BASE_CLASS>
417 tuple<MEMBER, BASE_CLASS> get_types (MEMBER BASE_CLASS::*);
419 template <
class TheBase =
void,
class TT>
420 inline constexpr size_t offset_of (TT member)
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));
430 namespace RequiringDefaultConstructibleObjectType_ {
432 template <
typename T1,
typename T2>
434 static constexpr size_t offset (T1 T2::* member)
437 array<char,
sizeof (T2)> bytes;
448 return size_t (&(objAsUnion.obj.*member)) - size_t (&objAsUnion.obj);
453 namespace UsingAlignedByteArrayBuf_ {
454 template <
typename FIELD_VALUE_TYPE,
typename OWNING_OBJECT>
455 inline size_t offset_of (FIELD_VALUE_TYPE OWNING_OBJECT::* member)
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));
467 namespace UseExplicitDefaultConstructibleStaticInstance_ {
470 template <
typename T1,
typename T2>
472 static inline constexpr T2 sObj_{};
473 static constexpr size_t offset (T1 T2::* member)
480 return size_t (&(offset_of_<T1, T2>::sObj_.*member)) - size_t (&offset_of_<T1, T2>::sObj_);
485 namespace UsingSimpleUnionToConstructActualObj_ {
487 template <
typename OUTER_OBJECT,
typename DATA_MEMBER_TYPE>
488 inline constexpr size_t offset_of (DATA_MEMBER_TYPE (OUTER_OBJECT::* dataMember))
497 array<char,
sizeof (OUTER_OBJECT)> bytes;
511 return size_t (&(objAsUnion.obj.*dataMember)) - size_t (&objAsUnion.obj);
521 template <
typename OUTER_OBJECT,
typename DATA_MEMBER_TYPE>
522 inline constexpr size_t OffsetOf (DATA_MEMBER_TYPE (OUTER_OBJECT::* dataMember))
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_) {
540 r1 = Private_::OffsetOfImpl_::UsingRecursiveSideStruct_::offset_of<OUTER_OBJECT> (dataMember);
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);
548 size_t r5 = Private_::OffsetOfImpl_::UsingSimpleUnionToConstructActualObj_::offset_of<OUTER_OBJECT, DATA_MEMBER_TYPE> (dataMember);
550 if (not is_constant_evaluated () and kTestAllWays_) {
556 if constexpr (is_trivially_default_constructible_v<OUTER_OBJECT>) {
568 inline namespace Literals {
569 constexpr byte operator""_b (
unsigned long long b)
572 return static_cast<byte> (b);
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)
580 return OffsetOf (member);
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)
585 return CompareBytes (lhs, rhs, count);
587 template <
typename T>
588 [[deprecated (
"Since Stroika v3.0d12 - use CompareBytes")]]
constexpr strong_ordering MemCmp (span<const T> lhs, span<const T> rhs)
590 return CompareBytes (lhs, rhs);
592 template <
typename T>
593 [[deprecated (
"Since Stroika v3.0d12 - use CompareBytes")]]
constexpr strong_ordering MemCmp (span<T> lhs, span<T> rhs)
595 return CompareBytes (lhs, rhs);
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)
601 return CopySpanData (src, target);
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)
607 return CopySpanData (ConstSpan (src), target);
bool Intersects(const set< T > &s1, const set< T > &s2)
constexpr strong_ordering CompareResultNormalizer(FROM_INT_TYPE f)