Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
BLOB.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include "Stroika/Foundation/Containers/Common.h"
7#include "Stroika/Foundation/Memory/Common.h"
10
11namespace Stroika::Foundation::Memory {
12
13 template <>
14 Characters::String Stroika::Foundation::Memory::BLOB::AsBase64 () const;
15 template <>
16 Characters::String Stroika::Foundation::Memory::BLOB::AsBase64 (const Cryptography::Encoding::Algorithm::Base64::Options& o) const;
17
18 struct BLOB::BasicRep_ final : public _IRep, public Memory::UseBlockAllocationIfAppropriate<BasicRep_> {
19 // really not sure what size to use???
20 // May not be any universal, good answer...
21 // Remember - users can subclass BLOB, and provider their own
22 // 'rep' type tuned to their application.
23 InlineBuffer<byte, 64> fData;
24
25 BasicRep_ (span<const byte> s)
26 : fData{Memory::eUninitialized, s.size ()}
27 {
28 CopyBytes (s, span{fData});
29 }
30
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;
35
36 virtual span<const byte> GetBounds () const override;
37 };
38
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;
44 };
45
46 struct BLOB::AdoptRep_ final : public _IRep, public Memory::UseBlockAllocationIfAppropriate<AdoptRep_> {
47 const byte* fStart;
48 const byte* fEnd;
49
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;
55 };
56
57 struct BLOB::AdoptAndDeleteRep_ final : public _IRep, public Memory::UseBlockAllocationIfAppropriate<AdoptAndDeleteRep_> {
58 const byte* fStart;
59 const byte* fEnd;
60
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;
66 };
67
68 /*
69 ********************************************************************************
70 ************************************** BLOB ************************************
71 ********************************************************************************
72 */
73 inline BLOB::BLOB ()
74 : fRep_{MakeSharedPtr<ZeroRep_> ()}
75 {
76 }
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 ()})}
81 {
82 }
83 inline BLOB::BLOB (const initializer_list<byte>& bytes)
84 : BLOB{span{bytes}}
85 {
86 }
87 inline BLOB::BLOB (const initializer_list<uint8_t>& bytes)
88 : BLOB{as_bytes (span{bytes})}
89 {
90 }
91 inline BLOB::BLOB (span<const byte> s)
92 : fRep_{s.empty () ? shared_ptr<_IRep>{MakeSharedPtr<ZeroRep_> ()} : shared_ptr<_IRep>{MakeSharedPtr<BasicRep_> (s)}}
93 {
94 Ensure (s.size () == size ());
95 }
96 inline BLOB::BLOB (const byte* start, const byte* end)
97 : BLOB{span{start, end}}
98 {
99 Ensure (static_cast<size_t> (end - start) == size ());
100 }
101 inline BLOB::BLOB (const uint8_t* start, const uint8_t* end)
102 : BLOB{as_bytes (span{start, end})}
103 {
104 Ensure (static_cast<size_t> (end - start) == size ());
105 }
106 inline BLOB::BLOB (const initializer_list<pair<const byte*, const byte*>>& startEndPairs)
107 : fRep_{MakeSharedPtr<BasicRep_> (startEndPairs)}
108 {
109 }
110 inline BLOB::BLOB (const initializer_list<BLOB>& list2Concatenate)
111 : fRep_{MakeSharedPtr<BasicRep_> (list2Concatenate)}
112 {
113 }
114 inline BLOB::BLOB (const shared_ptr<_IRep>& rep)
115 : fRep_{rep}
116 {
117 }
118 inline BLOB::BLOB (shared_ptr<_IRep>&& rep)
119 : fRep_{move (rep)}
120 {
121 }
122 inline BLOB BLOB::FromHex (const char* b)
123 {
124 RequireNotNull (b);
125 return FromHex (span<const char>{b, ::strlen (b)});
126 }
127 inline BLOB BLOB::FromHex (const char* s, const char* e)
128 {
129 return FromHex (span<const char>{s, e});
130 }
131 inline BLOB BLOB::FromHex (string_view s)
132 {
133 return FromHex (span<const char>{s});
134 }
135 inline BLOB BLOB::FromBase64 (const char* b)
136 {
137 RequireNotNull (b);
138 return FromBase64 (span<const char>{b, ::strlen (b)});
139 }
140 inline BLOB BLOB::FromBase64 (string_view s)
141 {
142 return FromBase64 (span<const char>{s});
143 }
144 template <Common::trivially_copyable T>
145 inline BLOB BLOB::FromRaw (const T* s, const T* e)
146 {
147 return BLOB{span{reinterpret_cast<const byte*> (s), reinterpret_cast<const byte*> (e)}};
148 }
149 template <Common::trivially_copyable T>
150 inline BLOB BLOB::FromRaw (const T* s, size_t sz)
151 {
152 return BLOB{span{reinterpret_cast<const byte*> (s), sz}};
153 }
154 template <Common::trivially_copyable T>
155 inline BLOB BLOB::FromRaw (const T* s)
156 requires (same_as<typename char_traits<T>::char_type, T>)
157 {
158 RequireNotNull (s);
159 return FromRaw (s, s + char_traits<T>::length (s));
160 }
161 template <Common::trivially_copyable T>
162 inline BLOB BLOB::FromRaw (const basic_string<T>& s)
163 requires (same_as<typename char_traits<T>::char_type, T>)
164 {
165 return FromRaw (s.c_str (), s.c_str () + s.length ());
166 }
167 template <Common::trivially_copyable T>
168 inline BLOB BLOB::FromRaw (const T& s)
169 {
170 return FromRaw (&s, &s + 1);
171 }
172 template <typename BYTEISH, size_t EXTENT>
173 inline BLOB BLOB::Attach (span<BYTEISH, EXTENT> s)
174 requires (convertible_to<BYTEISH, const byte> or convertible_to<BYTEISH, const uint8_t>)
175 {
176 const byte* b = reinterpret_cast<const byte*> (s.data ());
177 return BLOB{MakeSharedPtr<AdoptRep_> (b, b + s.size ())};
178 }
179 template <typename BYTEISH, size_t EXTENT>
180 inline BLOB BLOB::Attach (BYTEISH (&data)[EXTENT])
181 requires (convertible_to<BYTEISH, const byte> or convertible_to<BYTEISH, const uint8_t>)
182 {
183 return Attach (span<const BYTEISH>{data, EXTENT});
184 }
185 inline BLOB BLOB::AttachAndDelete (const byte* b, size_t arrayLen)
186 {
187 return BLOB{MakeSharedPtr<AdoptAndDeleteRep_> (b, b + arrayLen)};
188 }
189 template <>
190 Streams::InputStream::Ptr<byte> BLOB::As () const;
191 template <typename T>
192 inline T BLOB::As () const
193#if !qCompilerAndStdLib_template_requires_doesnt_work_with_specialization_Buggy
194 // clang-format off
195 requires (
196 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>
197 or is_trivially_copyable_v<T>
198 )
199 // clang-format on
200#endif
201 {
202 Debug::AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
203 if constexpr (same_as<T, span<const byte>>) {
204 return fRep_->GetBounds ();
205 }
206 else if constexpr (same_as<T, span<const uint8_t>>) {
207 return T{reinterpret_cast<const uint8_t*> (this->data ()), this->size ()};
208 }
209 else if constexpr (same_as<T, pair<const byte*, const byte*>>) {
210 return make_pair (this->data (), this->data () + this->size ());
211 }
212 else if constexpr (same_as<T, pair<const uint8_t*, const uint8_t*>>) {
213 auto s = this->As<span<const uint8_t>> ();
214 return make_pair (s.data (), s.data () + s.size ());
215 }
216 else if constexpr (same_as<T, vector<byte>>) {
217 return T{this->begin (), this->end ()};
218 }
219 else if constexpr (same_as<T, vector<uint8_t>>) {
220 auto s = this->As<span<const uint8_t>> ();
221 return T{s.begin (), s.end ()};
222 }
223 else if constexpr (same_as<T, Streams::InputStream::Ptr<byte>>) {
224 AssertNotReached (); //template specialized - handled in C++ file
225 }
226 else if constexpr (same_as<T, string>) {
227 span<const byte> tmp = fRep_->GetBounds ();
228 return string{reinterpret_cast<const char*> (tmp.data ()), reinterpret_cast<const char*> (tmp.data () + tmp.size ())};
229 }
230 else if constexpr (is_trivially_copyable_v<T>) {
231 Require (size () >= sizeof (T)); // allow object slicing, but not reading garbage data
232 return *(reinterpret_cast<const T*> (begin ()));
233 }
234 }
235 inline BLOB::operator Streams::InputStream::Ptr<byte> () const
236 {
237 return As<Streams::InputStream::Ptr<byte>> ();
238 }
239 inline byte BLOB::operator[] (const size_t i) const
240 {
241 Debug::AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
242 span<const byte> tmp = fRep_->GetBounds ();
243 Assert (i < tmp.size ());
244 return tmp[i];
245 }
246 inline bool BLOB::empty () const
247 {
248 Debug::AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
249 span<const byte> tmp = fRep_->GetBounds ();
250 Assert (tmp.begin () <= tmp.end ());
251 return tmp.empty ();
252 }
253 inline const byte* BLOB::begin () const
254 {
255 Debug::AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
256 return fRep_->GetBounds ().data ();
257 }
258 inline const byte* BLOB::end () const
259 {
260 Debug::AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
261 auto b = fRep_->GetBounds ();
262 return b.data () + b.size ();
263 }
264 inline size_t BLOB::GetSize () const
265 {
266 Debug::AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
267 span<const byte> tmp = fRep_->GetBounds ();
268 Assert (tmp.begin () <= tmp.end ());
269 return tmp.size ();
270 }
271 inline size_t BLOB::length () const
272 {
273 Debug::AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
274 return GetSize ();
275 }
276 inline const byte* BLOB::data () const
277 {
278 Debug::AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
279 return begin ();
280 }
281 inline size_t BLOB::size () const
282 {
283 Debug::AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
284 return GetSize ();
285 }
286 inline strong_ordering BLOB::operator<=> (const BLOB& rhs) const
287 {
288 return TWC_ (*this, rhs);
289 }
290 inline bool BLOB::operator== (const BLOB& rhs) const
291 {
292 Debug::AssertExternallySynchronizedMutex::ReadContext readLockL{fThisAssertExternallySynchronized_}; // this pattern of double locking might risk a deadlock for real locks, but these locks are fake to assure externally locked
293 Debug::AssertExternallySynchronizedMutex::ReadContext readLockR{rhs.fThisAssertExternallySynchronized_};
294 if (fRep_ == rhs.fRep_) {
295 return true; // cheap optimization for not super uncommon case
296 }
297 span<const byte> l = fRep_->GetBounds ();
298 span<const byte> r = rhs.fRep_->GetBounds ();
299 size_t lSize = l.size ();
300 size_t rSize = r.size ();
301 if (lSize != rSize) {
302 return false;
303 }
304 return CompareBytes (l, r) == 0;
305 }
306 inline BLOB BLOB::operator+ (const BLOB& rhs) const
307 {
308 Debug::AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
309 return BLOB ({*this, rhs});
310 }
311 inline strong_ordering BLOB::TWC_ (const BLOB& lhs, const BLOB& rhs)
312 {
313 Debug::AssertExternallySynchronizedMutex::ReadContext readLockL{lhs.fThisAssertExternallySynchronized_}; // this pattern of double locking might risk a deadlock for real locks, but these locks are fake to assure externally locked
314 Debug::AssertExternallySynchronizedMutex::ReadContext readLockR{rhs.fThisAssertExternallySynchronized_};
315 span<const byte> l = lhs.fRep_->GetBounds ();
316 span<const byte> r = rhs.fRep_->GetBounds ();
317 size_t lSize = l.size ();
318 size_t rSize = r.size ();
319 size_t nCommonBytes = min (lSize, rSize);
320 if (nCommonBytes != 0) {
321 // see http://stackoverflow.com/questions/16362925/can-i-pass-a-null-pointer-to-memcmp -- illegal to pass nullptr to memcmp() even if size 0
322 if (strong_ordering tmp = CompareBytes (l.subspan (0, nCommonBytes), r.subspan (0, nCommonBytes)); tmp != strong_ordering::equal) {
323 return tmp;
324 }
325 }
326 // if tmp is zero, and same size - its really zero. But if lhs shorter than right, say lhs < right
327 if (lSize == rSize) {
328 return strong_ordering::equal;
329 }
330 return (lSize < rSize) ? strong_ordering::less : strong_ordering::greater;
331 }
332
333 inline namespace Literals {
334 inline BLOB operator"" _blob (const char* str, size_t len)
335 {
336 return BLOB::Attach (span<const byte>{reinterpret_cast<const byte*> (str), len});
337 }
338
339 }
340
341}
#define RequireNotNull(p)
Definition Assertions.h:347
#define AssertNotReached()
Definition Assertions.h:355
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
Definition BLOB.inl:271
nonvirtual const byte * end() const
Definition BLOB.inl:258
nonvirtual STRING_TYPE AsBase64() const
static BLOB FromHex(const char *b)
Convert string of hex bytes to BLOB.
Definition BLOB.inl:122
nonvirtual byte operator[](const size_t i) const
Definition BLOB.inl:239
nonvirtual BLOB operator+(const BLOB &rhs) const
Definition BLOB.inl:306
nonvirtual bool empty() const
Definition BLOB.inl:246
nonvirtual const byte * begin() const
Definition BLOB.inl:253
nonvirtual size_t GetSize() const
Definition BLOB.inl:264
static BLOB FromBase64(const char *b)
Convert string of base64 bytes to BLOB.
Definition BLOB.inl:135
static BLOB FromRaw(const T *s, const T *e)
Convert pointed to/referenced data to BLOB (treating the argument as raw bytes).
Definition BLOB.inl:145
nonvirtual size_t size() const
Definition BLOB.inl:281
nonvirtual const byte * data() const
Definition BLOB.inl:276
InputStream<>::Ptr is Smart pointer (with abstract Rep) class defining the interface to reading from ...