4#include "Stroika/Foundation/Containers/Common.h"
7#include "Stroika/Foundation/Memory/Common.h"
11namespace Stroika::Foundation::Memory {
18 struct BLOB::BasicRep_ final :
public _IRep,
public Memory::UseBlockAllocationIfAppropriate<BasicRep_> {
23 InlineBuffer<byte, 64> fData;
25 BasicRep_ (span<const byte> s)
26 : fData{Memory::eUninitialized, s.
size ()}
28 CopyBytes (s, span{fData});
31 BasicRep_ (
const initializer_list<pair<const byte*, const byte*>>& startEndPairs);
32 BasicRep_ (
const initializer_list<BLOB>& list2Concatenate);
33 BasicRep_ (
const BasicRep_&) =
delete;
34 BasicRep_& operator= (
const BasicRep_&) =
delete;
36 virtual span<const byte> GetBounds ()
const override;
39 struct BLOB::ZeroRep_ final :
public _IRep,
public Memory::UseBlockAllocationIfAppropriate<ZeroRep_> {
40 virtual span<const byte> GetBounds ()
const override;
41 ZeroRep_ () =
default;
42 ZeroRep_ (
const ZeroRep_&) =
delete;
43 ZeroRep_& operator= (
const ZeroRep_&) =
delete;
46 struct BLOB::AdoptRep_ final :
public _IRep,
public Memory::UseBlockAllocationIfAppropriate<AdoptRep_> {
50 AdoptRep_ (
const AdoptRep_&) =
delete;
51 AdoptRep_ (
const byte* start,
const byte*
end);
52 ~AdoptRep_ () =
default;
53 AdoptRep_& operator= (
const AdoptRep_&) =
delete;
54 virtual span<const byte> GetBounds ()
const override;
57 struct BLOB::AdoptAndDeleteRep_ final :
public _IRep,
public Memory::UseBlockAllocationIfAppropriate<AdoptAndDeleteRep_> {
61 AdoptAndDeleteRep_ (
const AdoptAndDeleteRep_&) =
delete;
62 AdoptAndDeleteRep_ (
const byte* start,
const byte*
end);
63 ~AdoptAndDeleteRep_ ();
64 AdoptAndDeleteRep_& operator= (
const AdoptAndDeleteRep_&) =
delete;
65 virtual span<const byte> GetBounds ()
const override;
77 template <ranges::range CONTAINER_OF_BYTE>
78 inline BLOB::BLOB (
const CONTAINER_OF_BYTE& data)
79 requires (is_convertible_v<typename CONTAINER_OF_BYTE::value_type, byte> or is_convertible_v<typename CONTAINER_OF_BYTE::value_type, uint8_t>)
80 :
BLOB{as_bytes (span{data.data (), data.size ()})}
83 inline BLOB::BLOB (
const initializer_list<byte>& bytes)
87 inline BLOB::BLOB (
const initializer_list<uint8_t>& bytes)
88 : BLOB{as_bytes (span{bytes})}
92 : fRep_{s.empty () ? shared_ptr<_IRep>{MakeSharedPtr<ZeroRep_> ()} : shared_ptr<_IRep>{MakeSharedPtr<BasicRep_> (s)}}
94 Ensure (s.size () == size ());
96 inline BLOB::BLOB (span<const uint8_t> s)
99 Ensure (s.size () ==
size ());
101 inline BLOB::BLOB (
const byte* start,
const byte* end)
102 : BLOB{span{start, end}}
104 Ensure (
static_cast<size_t> (
end - start) ==
size ());
106 inline BLOB::BLOB (
const uint8_t* start,
const uint8_t* end)
107 : BLOB{as_bytes (span{start, end})}
109 Ensure (
static_cast<size_t> (
end - start) ==
size ());
111 inline BLOB::BLOB (
const initializer_list<pair<const byte*, const byte*>>& startEndPairs)
115 inline BLOB::BLOB (
const initializer_list<BLOB>& list2Concatenate)
130 return FromHex (span<const char>{b, ::strlen (b)});
134 return FromHex (span<const char>{s, e});
138 return FromHex (span<const char>{s});
143 return FromBase64 (span<const char>{b, ::strlen (b)});
149 template <Common::trivially_copyable T>
152 return BLOB{span{
reinterpret_cast<const byte*
> (s),
reinterpret_cast<const byte*
> (e)}};
154 template <Common::trivially_copyable T>
157 return BLOB{span{
reinterpret_cast<const byte*
> (s), sz}};
159 template <Common::trivially_copyable T>
161 requires (same_as<typename char_traits<T>::char_type, T>)
164 return FromRaw (s, s + char_traits<T>::length (s));
166 template <Common::trivially_copyable T>
168 requires (same_as<typename char_traits<T>::char_type, T>)
170 return FromRaw (s.c_str (), s.c_str () + s.length ());
172 template <Common::trivially_copyable T>
177 template <
typename BYTEISH,
size_t EXTENT>
178 inline BLOB BLOB::Attach (span<BYTEISH, EXTENT> s)
179 requires (convertible_to<BYTEISH, const byte> or convertible_to<BYTEISH, const uint8_t>)
181 const byte* b =
reinterpret_cast<const byte*
> (s.data ());
182 return BLOB{MakeSharedPtr<AdoptRep_> (b, b + s.size ())};
184 template <
typename BYTEISH,
size_t EXTENT>
185 inline BLOB BLOB::Attach (BYTEISH (&data)[EXTENT])
186 requires (convertible_to<BYTEISH, const byte> or convertible_to<BYTEISH, const uint8_t>)
188 return Attach (span<const BYTEISH>{data, EXTENT});
190 inline BLOB BLOB::AttachAndDelete (
const byte* b,
size_t arrayLen)
192 return BLOB{MakeSharedPtr<AdoptAndDeleteRep_> (b, b + arrayLen)};
195 Streams::InputStream::Ptr<byte>
BLOB::As ()
const;
196 template <
typename T>
198#if !qCompilerAndStdLib_template_requires_doesnt_work_with_specialization_Buggy
201 Common::IAnyOf<T,span<const byte>,span<const uint8_t>, pair<const byte*, const byte*>, pair<const uint8_t*, const uint8_t*>, vector<byte> ,vector<uint8_t>, Streams::InputStream::Ptr<byte>,
string>
202 or is_trivially_copyable_v<T>
208 if constexpr (same_as<T, span<const byte>>) {
209 return fRep_->GetBounds ();
211 else if constexpr (same_as<T, span<const uint8_t>>) {
212 return T{
reinterpret_cast<const uint8_t*
> (this->data ()), this->size ()};
214 else if constexpr (same_as<T, pair<const byte*, const byte*>>) {
215 return make_pair (this->data (), this->data () + this->size ());
217 else if constexpr (same_as<T, pair<const uint8_t*, const uint8_t*>>) {
218 auto s = this->As<span<const uint8_t>> ();
219 return make_pair (s.data (), s.data () + s.size ());
221 else if constexpr (same_as<T, vector<byte>>) {
222 return T{this->begin (), this->end ()};
224 else if constexpr (same_as<T, vector<uint8_t>>) {
225 auto s = this->As<span<const uint8_t>> ();
226 return T{s.begin (), s.end ()};
228 else if constexpr (same_as<T, Streams::InputStream::Ptr<byte>>) {
231 else if constexpr (same_as<T, string>) {
232 span<const byte> tmp = fRep_->GetBounds ();
233 return string{
reinterpret_cast<const char*
> (tmp.data ()),
reinterpret_cast<const char*
> (tmp.data () + tmp.size ())};
235 else if constexpr (is_trivially_copyable_v<T>) {
236 Require (size () >=
sizeof (T));
237 return *(
reinterpret_cast<const T*
> (begin ()));
242 return As<Streams::InputStream::Ptr<byte>> ();
247 span<const byte> tmp = fRep_->GetBounds ();
248 Assert (i < tmp.size ());
254 span<const byte> tmp = fRep_->GetBounds ();
255 Assert (tmp.begin () <= tmp.end ());
261 return fRep_->GetBounds ().data ();
266 auto b = fRep_->GetBounds ();
267 return b.data () + b.size ();
272 span<const byte> tmp = fRep_->GetBounds ();
273 Assert (tmp.begin () <= tmp.end ());
291 inline strong_ordering BLOB::operator<=> (
const BLOB& rhs)
const
293 return TWC_ (*
this, rhs);
295 inline bool BLOB::operator== (
const BLOB& rhs)
const
299 if (fRep_ == rhs.fRep_) {
302 span<const byte> l = fRep_->GetBounds ();
303 span<const byte> r = rhs.fRep_->GetBounds ();
304 size_t lSize = l.size ();
305 size_t rSize = r.size ();
306 if (lSize != rSize) {
309 return CompareBytes (l, r) == 0;
314 return BLOB ({*
this, rhs});
316 inline strong_ordering BLOB::TWC_ (
const BLOB& lhs,
const BLOB& rhs)
320 span<const byte> l = lhs.fRep_->GetBounds ();
321 span<const byte> r = rhs.fRep_->GetBounds ();
322 size_t lSize = l.size ();
323 size_t rSize = r.size ();
324 size_t nCommonBytes = min (lSize, rSize);
325 if (nCommonBytes != 0) {
327 if (strong_ordering tmp = CompareBytes (l.subspan (0, nCommonBytes), r.subspan (0, nCommonBytes)); tmp != strong_ordering::equal) {
332 if (lSize == rSize) {
333 return strong_ordering::equal;
335 return (lSize < rSize) ? strong_ordering::less : strong_ordering::greater;
338 inline namespace Literals {
339 inline BLOB operator""_blob (
const char* str,
size_t len)
341 return BLOB::Attach (span<const byte>{
reinterpret_cast<const byte*
> (str), len});
#define RequireNotNull(p)
#define AssertNotReached()
auto MakeSharedPtr(ARGS_TYPE &&... args) -> shared_ptr< T >
same as make_shared, but if type T has block allocation, then use block allocation for the 'shared pa...
shared_lock< const AssertExternallySynchronizedMutex > ReadContext
Instantiate AssertExternallySynchronizedMutex::ReadContext to designate an area of code where protect...
nonvirtual size_t length() const
nonvirtual const byte * end() const
nonvirtual STRING_TYPE AsBase64() const
static BLOB FromHex(const char *b)
Convert string of hex bytes to BLOB.
nonvirtual byte operator[](const size_t i) const
nonvirtual BLOB operator+(const BLOB &rhs) const
nonvirtual bool empty() const
nonvirtual const byte * begin() const
nonvirtual size_t GetSize() const
static BLOB FromBase64(const char *b)
Convert string of base64 bytes to BLOB.
static BLOB FromRaw(const T *s, const T *e)
Convert pointed to/referenced data to BLOB (treating the argument as raw bytes).
nonvirtual size_t size() const
nonvirtual const byte * data() const
Ptr Attach(PlatformNativeHandle sd)