10namespace Stroika::Foundation::Memory {
17 template <
typename ARRAY_TYPE,
size_t SIZE_OF_ARRAY>
18 inline constexpr size_t NEltsOf ([[maybe_unused]]
const ARRAY_TYPE (&arr)[SIZE_OF_ARRAY])
29 constexpr strong_ordering CompareBytes (
const uint8_t* lhs,
const uint8_t* rhs, std::size_t count)
31 DISABLE_COMPILER_MSC_WARNING_START (5063)
32 DISABLE_COMPILER_CLANG_WARNING_START ("clang diagnostic ignored \"-Wconstant-evaluated\"");
33 DISABLE_COMPILER_GCC_WARNING_START ("GCC diagnostic ignored \"-Wtautological-compare\"");
34 if constexpr (is_constant_evaluated ()) {
37 const uint8_t* li = lhs;
38 const uint8_t* ri = rhs;
39 for (; count--; ++li, ++ri) {
40 if (
int cmp =
static_cast<int> (*li) -
static_cast<int> (*ri)) {
44 return strong_ordering::equal;
48 return strong_ordering::equal;
52 DISABLE_COMPILER_GCC_WARNING_END (
"GCC diagnostic ignored \"-Wtautological-compare\"");
53 DISABLE_COMPILER_MSC_WARNING_END (5063)
54 DISABLE_COMPILER_CLANG_WARNING_END ("clang diagnostic ignored \"-Wconstant-evaluated\"");
57 constexpr strong_ordering CompareBytes (const T* lhs, const T* rhs,
size_t count)
59 return CompareBytes (
reinterpret_cast<const uint8_t*
> (lhs),
reinterpret_cast<const uint8_t*
> (rhs), count *
sizeof (T));
62 constexpr strong_ordering CompareBytes (span<const T> lhs, span<const T> rhs)
64 Require (lhs.size () == rhs.size ());
65 return CompareBytes (lhs.data (), rhs.data (), lhs.size ());
68 constexpr strong_ordering CompareBytes (span<T> lhs, span<T> rhs)
70 return CompareBytes (ConstSpan (lhs), ConstSpan (rhs));
79 inline span<const byte> AsBytes (
const T& elt)
80 requires (is_trivial_v<T>)
82 return as_bytes (span{&elt, 1});
90 template <
class T,
size_t EXTENT>
91 constexpr span<const T, EXTENT> ConstSpan (span<T, EXTENT> s)
101 template <
typename T1,
typename T2,
size_t E1,
size_t E2>
102 constexpr bool Intersects (span<T1, E1> lhs, span<T2, E2> rhs)
105 auto lhsStart = as_bytes (lhs).data ();
106 auto rhsStart = as_bytes (rhs).data ();
107 auto lhsEnd = lhsStart + lhs.size_bytes ();
108 auto rhsEnd = rhsStart + rhs.size_bytes ();
109 if (rhsEnd <= lhsStart) {
112 if (rhsStart >= lhsEnd) {
115 if (lhs.empty () or rhs.empty ()) {
126 template <ISpan TO_SPAN, ISpanBytesCastable<TO_SPAN> FROM_SPAN>
127 constexpr TO_SPAN SpanBytesCast (FROM_SPAN src)
129 using TO_T =
typename TO_SPAN::value_type;
130 Require ((src.size_bytes () / sizeof (TO_T)) *
sizeof (TO_T) == src.size_bytes ());
132 TO_SPAN result{(TO_T*)(src.data ()), src.size_bytes () /
sizeof (TO_T)};
133 Ensure (src.size_bytes () == result.size_bytes ());
142 template <Common::trivially_copyable FROM_T,
size_t FROM_E, Common::trivially_copyable TO_T,
size_t TO_E>
143 constexpr span<TO_T, TO_E> CopyBytes (span<FROM_T, FROM_E> src, span<TO_T, TO_E> target)
noexcept
144 requires (same_as<remove_cvref_t<FROM_T>, remove_cvref_t<TO_T>>)
146 Require (src.size () <= target.size ());
147 Require (not Intersects (src, target));
148 DISABLE_COMPILER_GCC_WARNING_START (
"GCC diagnostic ignored \"-Wstringop-overflow\"");
149 std::copy (src.begin (), src.end (), target.data ());
150 DISABLE_COMPILER_GCC_WARNING_END (
"GCC diagnostic ignored \"-Wstringop-overflow\"");
151 return target.subspan (0, src.size ());
159 template <
typename FROM_T,
size_t FROM_E,
typename TO_T,
size_t TO_E>
160 constexpr span<TO_T, TO_E> CopySpanData (span<FROM_T, FROM_E> src, span<TO_T, TO_E> target)
161 requires (not is_const_v<TO_T>)
163 Require (not Intersects (src, target));
164 Require (src.size () <= target.size ());
165 if constexpr (Common::trivially_copyable<TO_T> and Common::trivially_copyable<FROM_T> and
sizeof (FROM_T) ==
sizeof (TO_T)) {
167 return CopyBytes (SpanBytesCast<span<const TO_T, TO_E>> (src), target);
172 TO_T* tb = target.data ();
173 for (
const FROM_T& i : src) {
174 *tb++ =
static_cast<TO_T
> (i);
176 return target.subspan (0, src.size ());
185 template <Common::trivially_copyable FROM_T,
size_t FROM_E, Common::trivially_copyable TO_T,
size_t TO_E>
186 constexpr span<TO_T, TO_E> CopyOverlappingBytes (span<FROM_T, FROM_E> src, span<TO_T, TO_E> target)
noexcept
187 requires (same_as<remove_cvref_t<FROM_T>, remove_cvref_t<TO_T>>)
189 Require (src.size () <= target.size ());
190 DISABLE_COMPILER_GCC_WARNING_START (
"GCC diagnostic ignored \"-Wstringop-overflow\"");
191 std::copy_backward (src.begin (), src.end (), target.data ());
192 DISABLE_COMPILER_GCC_WARNING_END (
"GCC diagnostic ignored \"-Wstringop-overflow\"");
193 return target.subspan (0, src.size ());
202 namespace OffsetOfImpl_ {
203 namespace UsingRecursiveSideStruct_ {
206 template <
typename MEMBER,
size_t N_PAD_BYTES>
208 char pad[N_PAD_BYTES];
212 template <
typename MEMBER>
213 struct Pad<MEMBER, 0> {
217 DISABLE_COMPILER_MSC_WARNING_START (4324);
218 template <
typename BASE,
typename MEMBER,
size_t O>
224 constexpr U () noexcept
229 constexpr static U* u{
nullptr};
231 DISABLE_COMPILER_MSC_WARNING_END (4324);
233 template <
typename MEMBER,
typename BASE_CLASS,
typename ORIG_CLASS>
234 struct offset_of_impl {
235 template <size_t off, auto union_part = MakeUnion<BASE_CLASS, MEMBER, off>::u>
237 Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_UNDEFINED
static constexpr ptrdiff_t offset2 (MEMBER ORIG_CLASS::* member)
239 if constexpr (off >
sizeof (BASE_CLASS)) {
243 const auto diff1 = &((
static_cast<const ORIG_CLASS*
> (&union_part->base))->*member);
244 const auto diff2 = &union_part->pad.m;
246 constexpr auto MIN = (
sizeof (MEMBER) <
alignof (ORIG_CLASS)) ?
sizeof (MEMBER) :
alignof (ORIG_CLASS);
247 return offset2<off + MIN> (member);
256 template <
class MEMBER,
class BASE_CLASS>
257 tuple<MEMBER, BASE_CLASS> get_types (MEMBER BASE_CLASS::*);
259 template <
class TheBase =
void,
class TT>
260 inline constexpr size_t offset_of (TT member)
262 using T =
decltype (get_types (declval<TT> ()));
263 using Member = tuple_element_t<0, T>;
264 using Orig = tuple_element_t<1, T>;
265 using Base = conditional_t<is_void_v<TheBase>, Orig, TheBase>;
266 return static_cast<size_t> (offset_of_impl<Member, Base, Orig>::template offset2<0> (member));
270 namespace RequiringDefaultConstructibleObjectType_ {
272 template <
typename T1,
typename T2>
274 static constexpr size_t offset (T1 T2::* member)
277 array<char,
sizeof (T2)> bytes;
288 return size_t (&(objAsUnion.obj.*member)) - size_t (&objAsUnion.obj);
293 namespace UsingAlignedByteArrayBuf_ {
294 template <
typename FIELD_VALUE_TYPE,
typename OWNING_OBJECT>
295 inline size_t offset_of (FIELD_VALUE_TYPE OWNING_OBJECT::* member)
299 alignas (OWNING_OBJECT)
byte buf[
sizeof (OWNING_OBJECT)]{};
300 const OWNING_OBJECT& o = *
reinterpret_cast<const OWNING_OBJECT*
> (&buf);
301 auto result = size_t (
reinterpret_cast<const char*
> (&(o.*member)) -
reinterpret_cast<const char*
> (&o));
307 namespace UseExplicitDefaultConstructibleStaticInstance_ {
310 template <
typename T1,
typename T2>
312 static inline constexpr T2 sObj_{};
313 static constexpr size_t offset (T1 T2::* member)
320 return size_t (&(offset_of_<T1, T2>::sObj_.*member)) - size_t (&offset_of_<T1, T2>::sObj_);
325 namespace UsingSimpleUnionToConstructActualObj_ {
327 template <
typename OUTER_OBJECT,
typename DATA_MEMBER_TYPE>
328 inline constexpr size_t offset_of (DATA_MEMBER_TYPE (OUTER_OBJECT::* dataMember))
337 array<char,
sizeof (OUTER_OBJECT)> bytes;
351 return size_t (&(objAsUnion.obj.*dataMember)) - size_t (&objAsUnion.obj);
361 template <
typename OUTER_OBJECT,
typename DATA_MEMBER_TYPE>
362 inline constexpr size_t OffsetOf (DATA_MEMBER_TYPE (OUTER_OBJECT::* dataMember))
365 constexpr bool kTestAllWays_ =
true;
366 [[maybe_unused]]
size_t r1;
367 [[maybe_unused]]
size_t r2;
368 [[maybe_unused]]
size_t r3;
369 [[maybe_unused]]
size_t r4;
370 if constexpr (kTestAllWays_) {
380 r1 = Private_::OffsetOfImpl_::UsingRecursiveSideStruct_::offset_of<OUTER_OBJECT> (dataMember);
382 r2 = Private_::OffsetOfImpl_::RequiringDefaultConstructibleObjectType_::offset_of<DATA_MEMBER_TYPE, OUTER_OBJECT>::offset (dataMember);
383 r3 = Private_::OffsetOfImpl_::UsingAlignedByteArrayBuf_::offset_of<DATA_MEMBER_TYPE, OUTER_OBJECT> (dataMember);
384 if constexpr (is_trivially_default_constructible_v<OUTER_OBJECT>) {
385 r4 = Private_::OffsetOfImpl_::UseExplicitDefaultConstructibleStaticInstance_::offset_of_<DATA_MEMBER_TYPE, OUTER_OBJECT>::offset (dataMember);
388 size_t r5 = Private_::OffsetOfImpl_::UsingSimpleUnionToConstructActualObj_::offset_of<OUTER_OBJECT, DATA_MEMBER_TYPE> (dataMember);
390 if (not is_constant_evaluated () and kTestAllWays_) {
396 if constexpr (is_trivially_default_constructible_v<OUTER_OBJECT>) {
408 inline namespace Literals {
409 constexpr byte operator""_b (
unsigned long long b)
412 return static_cast<byte> (b);
417 template <
typename FIELD_VALUE_TYPE,
typename OWNING_OBJECT>
418 [[deprecated (
"Since Stroika v3.0d2 - just use OffsetOf")]]
inline size_t constexpr OffsetOf_Constexpr (FIELD_VALUE_TYPE OWNING_OBJECT::* member)
420 return OffsetOf (member);
422 template <
typename T>
423 [[deprecated (
"Since Stroika v3.0d12 - use CompareBytes")]]
constexpr strong_ordering MemCmp (
const T* lhs,
const T* rhs,
size_t count)
425 return CompareBytes (lhs, rhs, count);
427 template <
typename T>
428 [[deprecated (
"Since Stroika v3.0d12 - use CompareBytes")]]
constexpr strong_ordering MemCmp (span<const T> lhs, span<const T> rhs)
430 return CompareBytes (lhs, rhs);
432 template <
typename T>
433 [[deprecated (
"Since Stroika v3.0d12 - use CompareBytes")]]
constexpr strong_ordering MemCmp (span<T> lhs, span<T> rhs)
435 return CompareBytes (lhs, rhs);
437 template <
typename FROM_T,
size_t FROM_E,
typename TO_T,
size_t TO_E>
438 [[deprecated (
"Since Stroika v3.0d12 use CopyBytes")]]
constexpr span<TO_T, TO_E> CopySpanData_StaticCast (span<const FROM_T, FROM_E> src,
439 span<TO_T, TO_E> target)
441 return CopySpanData (src, target);
443 template <
typename FROM_T,
size_t FROM_E,
typename TO_T,
size_t TO_E>
444 [[deprecated (
"Since Stroika v3.0d12 use CopyBytes")]]
constexpr std::span<TO_T, TO_E> CopySpanData_StaticCast (span<FROM_T, FROM_E> src,
445 span<TO_T, TO_E> target)
447 return CopySpanData (ConstSpan (src), target);
bool Intersects(const set< T > &s1, const set< T > &s2)
constexpr strong_ordering CompareResultNormalizer(FROM_INT_TYPE f)