Embedded Template Library 1.0
Loading...
Searching...
No Matches
mem_cast.h
Go to the documentation of this file.
1
2
3/******************************************************************************
4The MIT License(MIT)
5
6Embedded Template Library.
7https://github.com/ETLCPP/etl
8https://www.etlcpp.com
9
10Copyright(c) 2021 John Wellbelove
11
12Permission is hereby granted, free of charge, to any person obtaining a copy
13of this software and associated documentation files(the "Software"), to deal
14in the Software without restriction, including without limitation the rights
15to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16copies of the Software, and to permit persons to whom the Software is
17furnished to do so, subject to the following conditions :
18
19The above copyright notice and this permission notice shall be included in all
20copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28SOFTWARE.
29******************************************************************************/
30
31#ifndef ETL_MEM_CAST_INCLUDED
32#define ETL_MEM_CAST_INCLUDED
33
34#include "platform.h"
35#include "binary.h"
36#include "error_handler.h"
37#include "exception.h"
38#include "file_error_numbers.h"
39#include "largest.h"
40#include "memory.h"
41#include "placement_new.h"
42#include "static_assert.h"
43#include "utility.h"
44
45#include <stdint.h>
46#include <string.h>
47
48namespace etl
49{
50 //***************************************************************************
52 //***************************************************************************
53 class mem_cast_exception : public etl::exception
54 {
55 public:
56
57 mem_cast_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
58 : exception(reason_, file_name_, line_number_)
59 {
60 }
61 };
62
63 //***************************************************************************
65 //***************************************************************************
66 class mem_cast_size_exception : public etl::mem_cast_exception
67 {
68 public:
69
70 mem_cast_size_exception(string_type file_name_, numeric_type line_number_)
71 : mem_cast_exception(ETL_ERROR_TEXT("mem_cast:size", ETL_MEM_CAST_FILE_ID"A"), file_name_, line_number_)
72 {
73 }
74 };
75
76 //***************************************************************************
78 //***************************************************************************
79 class mem_cast_nullptr_exception : public etl::mem_cast_exception
80 {
81 public:
82
83 mem_cast_nullptr_exception(string_type file_name_, numeric_type line_number_)
84 : mem_cast_exception(ETL_ERROR_TEXT("mem_cast:null pointer", ETL_MEM_CAST_FILE_ID"B"), file_name_, line_number_)
85 {
86 }
87 };
88
89 //*****************************************************************************
91 //*****************************************************************************
92 template <size_t Size_, size_t Alignment_>
94 {
95 public:
96
97 static ETL_CONSTANT size_t Size = Size_;
98 static ETL_CONSTANT size_t Alignment = Alignment_;
99
100 ETL_STATIC_ASSERT((Alignment == 1) || etl::is_power_of_2<Alignment>::value, "Alignment must be a power of 2");
101
102 //***********************************
104 //***********************************
106 : buffer()
107 {
108 }
109
110 //***********************************
112 //***********************************
113 template <size_t Other_Size, size_t Other_Alignment>
115 {
116 ETL_STATIC_ASSERT(Size >= Other_Size, "Other size is too large");
117
118 memcpy(buffer, other.buffer, Size_);
119 }
120
121 //***********************************
123 //***********************************
124 template <size_t Other_Size, size_t Other_Alignment>
126 {
127 ETL_STATIC_ASSERT(Size >= Other_Size, "RHS size is too large");
128
129 memcpy(buffer, rhs.buffer, Size_);
130
131 return *this;
132 }
133
134 //***********************************
136 //***********************************
137 template <typename T>
138 void assign(const T& value)
139 {
140 ETL_STATIC_ASSERT(Size >= sizeof(T), "Type size is too large");
141
142 ::new (static_cast<void*>(buffer.raw)) T(value);
143 }
144
145 //***********************************
147 //***********************************
148 template <typename T>
149 void assign_at_offset(size_t offset, const T& value)
150 {
151 char* p = static_cast<char*>(buffer.raw) + offset;
152 ETL_ASSERT(sizeof(T) <= (Size - offset), ETL_ERROR(etl::mem_cast_size_exception));
153
154 ::new (p) T(value);
155 }
156
157 //***********************************
159 //***********************************
160 template <typename T, size_t Offset>
161 void assign_at_offset(const T& value)
162 {
163 char* p = static_cast<char*>(buffer.raw) + Offset;
164 ETL_STATIC_ASSERT(sizeof(T) <= (Size - Offset), "Type size is too large");
165
166 ::new (p) T(value);
167 }
168
169#if ETL_USING_CPP11
170 //***********************************
172 //***********************************
173 template <typename T, typename... TArgs>
174 T& emplace(TArgs... args)
175 {
176 ETL_STATIC_ASSERT(Size >= sizeof(T), "Type size is too large");
177
178 ::new (static_cast<void*>(buffer.raw)) T(etl::forward<TArgs>(args)...);
179
180 return ref<T>();
181 }
182
183 //***********************************
185 //***********************************
186 template <typename T, typename... TArgs>
187 T& emplace_at_offset(size_t offset, TArgs... args)
188 {
189 char* p = static_cast<char*>(buffer.raw) + offset;
190 ETL_ASSERT(sizeof(T) <= (Size - offset), ETL_ERROR(etl::mem_cast_size_exception));
191
192 ::new (p) T(etl::forward<TArgs>(args)...);
193
194 return ref_at_offset<T>(offset);
195 }
196
197 //***********************************
199 //***********************************
200 template <typename T, size_t Offset, typename... TArgs>
201 T& emplace_at_offset(TArgs... args)
202 {
203 char* p = static_cast<char*>(buffer.raw) + Offset;
204 ETL_STATIC_ASSERT(sizeof(T) <= (Size - Offset), "Type size is too large");
205
206 ::new (p) T(etl::forward<TArgs>(args)...);
207
209 }
210#endif
211
212 //***********************************
214 //***********************************
215 template <typename T>
216 ETL_NODISCARD
217 T& ref()
218 {
219 ETL_STATIC_ASSERT(sizeof(T) <= Size, "Size of type too large for storage");
220
221 return *reinterpret_cast<T*>(buffer.raw);
222 }
223
224 //***********************************
226 //***********************************
227 template <typename T>
228 ETL_NODISCARD
229 const T& ref() const
230 {
231 ETL_STATIC_ASSERT(sizeof(T) <= Size, "Size of type too large for storage");
232
233 return *reinterpret_cast<const T*>(buffer.raw);
234 }
235
236 //***********************************
238 //***********************************
239 template <typename T>
240 ETL_NODISCARD
241 T& ref_at_offset(size_t offset)
242 {
243 ETL_ASSERT(sizeof(T) <= (Size - offset), ETL_ERROR(etl::mem_cast_size_exception));
244
245 return *reinterpret_cast<T*>(buffer.raw + offset);
246 }
247
248 //***********************************
250 //***********************************
251 template <typename T>
252 ETL_NODISCARD
253 const T& ref_at_offset(size_t offset) const
254 {
255 ETL_ASSERT(sizeof(T) <= (Size - offset), ETL_ERROR(etl::mem_cast_size_exception));
256
257 return *reinterpret_cast<const T*>(buffer.raw + offset);
258 }
259
260 //***********************************
262 //***********************************
263 template <typename T, size_t Offset>
264 ETL_NODISCARD
266 {
267 ETL_STATIC_ASSERT(sizeof(T) <= (Size - Offset), "Size of type too large for storage");
268
269 return *reinterpret_cast<T*>(buffer.raw + Offset);
270 }
271
272 //***********************************
274 //***********************************
275 template <typename T, size_t Offset>
276 ETL_NODISCARD
277 const T& ref_at_offset() const
278 {
279 ETL_STATIC_ASSERT(sizeof(T) <= (Size - Offset), "Size of type too large for storage");
280
281 return *reinterpret_cast<const T*>(buffer.raw + Offset);
282 }
283
284 //***********************************
286 //***********************************
287 ETL_NODISCARD
288 static ETL_CONSTEXPR size_t size()
289 {
290 return Size;
291 }
292
293 //***********************************
295 //***********************************
296 ETL_NODISCARD
297 static ETL_CONSTEXPR size_t alignment()
298 {
299 return Alignment;
300 }
301
302 //***********************************
304 //***********************************
305 ETL_NODISCARD
306 char* data()
307 {
308 return buffer;
309 }
310
311 //***********************************
313 //***********************************
314 ETL_NODISCARD
315 const char* data() const
316 {
317 return buffer;
318 }
319
320 private:
321
324 };
325
326 template <size_t Size_, size_t Alignment_>
327 ETL_CONSTANT size_t mem_cast<Size_, Alignment_>::Size;
328
329 template <size_t Size_, size_t Alignment_>
330 ETL_CONSTANT size_t mem_cast<Size_, Alignment_>::Alignment;
331
332 //*****************************************************************************
334 //*****************************************************************************
336 {
337 public:
338
339 static ETL_CONSTANT size_t Undefined_Size = etl::integral_limits<size_t>::max;
340
341 //***********************************
343 //***********************************
345 : pbuffer(ETL_NULLPTR)
346 , buffer_size(Undefined_Size)
347 {
348 }
349
350 //***********************************
352 //***********************************
353 mem_cast_ptr(char* pbuffer_, size_t buffer_size_ = Undefined_Size)
354 : pbuffer(pbuffer_)
355 , buffer_size(buffer_size_)
356 {
357 }
358
359 //***********************************
361 //***********************************
363 : pbuffer(other.pbuffer)
364 , buffer_size(other.buffer_size)
365 {
366 }
367
368 //***********************************
370 //***********************************
372 {
373 pbuffer = rhs.pbuffer;
374 buffer_size = rhs.buffer_size;
375
376 return *this;
377 }
378
379 //***********************************
381 //***********************************
382 template <typename T>
383 void assign(const T& value)
384 {
385 ETL_ASSERT((pbuffer != ETL_NULLPTR), ETL_ERROR(etl::mem_cast_nullptr_exception));
386 ETL_ASSERT(sizeof(T) <= buffer_size, ETL_ERROR(etl::mem_cast_size_exception));
387
388 ::new (pbuffer) T(value);
389 }
390
391 //***********************************
393 //***********************************
394 template <typename T>
395 void assign_at_offset(size_t offset, const T& value)
396 {
397 ETL_ASSERT((pbuffer != ETL_NULLPTR), ETL_ERROR(etl::mem_cast_nullptr_exception));
398 char* p = pbuffer + offset;
399 ETL_ASSERT(sizeof(T) <= (buffer_size - offset), ETL_ERROR(etl::mem_cast_size_exception));
400
401 ::new (p) T(value);
402 }
403
404 //***********************************
406 //***********************************
407 template <typename T, size_t Offset>
408 void assign_at_offset(const T& value)
409 {
410 ETL_ASSERT((pbuffer != ETL_NULLPTR), ETL_ERROR(etl::mem_cast_nullptr_exception));
411 char* p = pbuffer + Offset;
412 ETL_ASSERT(sizeof(T) <= (buffer_size - Offset), ETL_ERROR(etl::mem_cast_size_exception));
413
414 ::new (p) T(value);
415 }
416
417#if ETL_USING_CPP11
418 //***********************************
420 //***********************************
421 template <typename T, typename... TArgs>
422 T& emplace(TArgs... args)
423 {
424 ETL_ASSERT((pbuffer != ETL_NULLPTR), ETL_ERROR(etl::mem_cast_nullptr_exception));
425 ETL_ASSERT(sizeof(T) <= buffer_size, ETL_ERROR(etl::mem_cast_size_exception));
426
427 ::new (pbuffer) T(etl::forward<TArgs>(args)...);
428
429 return ref<T>();
430 }
431
432 //***********************************
434 //***********************************
435 template <typename T, typename... TArgs>
436 T& emplace_at_offset(size_t offset, TArgs... args)
437 {
438 ETL_ASSERT((pbuffer != ETL_NULLPTR), ETL_ERROR(etl::mem_cast_nullptr_exception));
439 char* p = pbuffer + offset;
440 ETL_ASSERT(sizeof(T) <= (buffer_size - offset), ETL_ERROR(etl::mem_cast_size_exception));
441
442 ::new (p) T(etl::forward<TArgs>(args)...);
443
444 return ref_at_offset<T>(offset);
445 }
446
447 //***********************************
449 //***********************************
450 template <typename T, size_t Offset, typename... TArgs>
451 T& emplace_at_offset(TArgs... args)
452 {
453 ETL_ASSERT((pbuffer != ETL_NULLPTR), ETL_ERROR(etl::mem_cast_nullptr_exception));
454 char* p = pbuffer + Offset;
455 ETL_ASSERT(sizeof(T) <= (buffer_size - Offset), ETL_ERROR(etl::mem_cast_size_exception));
456
457 ::new (p) T(etl::forward<TArgs>(args)...);
458
459 return ref_at_offset<T, Offset>();
460 }
461#endif
462
463 //***********************************
465 //***********************************
466 template <typename T>
467 ETL_NODISCARD
468 T& ref()
469 {
470 ETL_ASSERT((pbuffer != ETL_NULLPTR), ETL_ERROR(etl::mem_cast_nullptr_exception));
471 ETL_ASSERT(sizeof(T) <= buffer_size, ETL_ERROR(etl::mem_cast_size_exception));
472
473 T* p = reinterpret_cast<T*>(pbuffer);
474
475 return *p;
476 }
477
478 //***********************************
480 //***********************************
481 template <typename T>
482 ETL_NODISCARD
483 const T& ref() const
484 {
485 ETL_ASSERT((pbuffer != ETL_NULLPTR), ETL_ERROR(etl::mem_cast_nullptr_exception));
486 ETL_ASSERT(sizeof(T) <= buffer_size, ETL_ERROR(etl::mem_cast_size_exception));
487
488 const T* p = reinterpret_cast<const T*>(pbuffer);
489
490 return *p;
491 }
492
493 //***********************************
495 //***********************************
496 template <typename T>
497 ETL_NODISCARD
498 T& ref_at_offset(size_t offset)
499 {
500 ETL_ASSERT((pbuffer != ETL_NULLPTR), ETL_ERROR(etl::mem_cast_nullptr_exception));
501 ETL_ASSERT(sizeof(T) <= (buffer_size - offset), ETL_ERROR(etl::mem_cast_size_exception));
502
503 T* p = reinterpret_cast<T*>(pbuffer + offset);
504
505 return *p;
506 }
507
508 //***********************************
510 //***********************************
511 template <typename T>
512 ETL_NODISCARD
513 const T& ref_at_offset(size_t offset) const
514 {
515 ETL_ASSERT((pbuffer != ETL_NULLPTR), ETL_ERROR(etl::mem_cast_nullptr_exception));
516 ETL_ASSERT(sizeof(T) <= (buffer_size - offset), ETL_ERROR(etl::mem_cast_size_exception));
517
518 const T* p = reinterpret_cast<const T*>(pbuffer + offset);
519
520 return *p;
521 }
522
523 //***********************************
525 //***********************************
526 template <typename T, size_t Offset>
527 ETL_NODISCARD
529 {
530 ETL_ASSERT((pbuffer != ETL_NULLPTR), ETL_ERROR(etl::mem_cast_nullptr_exception));
531 ETL_ASSERT(sizeof(T) <= (buffer_size - Offset), ETL_ERROR(etl::mem_cast_size_exception));
532
533 T* p = reinterpret_cast<T*>(pbuffer + Offset);
534
535 return *p;
536 }
537
538 //***********************************
540 //***********************************
541 template <typename T, size_t Offset>
542 ETL_NODISCARD
543 const T& ref_at_offset() const
544 {
545 ETL_ASSERT((pbuffer != ETL_NULLPTR), ETL_ERROR(etl::mem_cast_nullptr_exception));
546 ETL_ASSERT(sizeof(T) <= (buffer_size - Offset), ETL_ERROR(etl::mem_cast_size_exception));
547
548 const T* p = reinterpret_cast<const T*>(pbuffer + Offset);
549
550 return *p;
551 }
552
553 //***********************************
555 //***********************************
556 ETL_NODISCARD
557 size_t size() const
558 {
559 return buffer_size;
560 }
561
562 //***********************************
564 //***********************************
565 ETL_NODISCARD
566 size_t alignment() const
567 {
568 typedef typename etl::smallest_uint_for_bits<sizeof(uintptr_t) * CHAR_BIT>::type type;
569
570 const type p = reinterpret_cast<type>(pbuffer);
571
572 return size_t(1U) << etl::count_trailing_zeros(p);
573 }
574
575 //***********************************
577 //***********************************
578 void data(char* pbuffer_, size_t buffer_size_ = Undefined_Size)
579 {
580 pbuffer = pbuffer_;
581 buffer_size = buffer_size_;
582 }
583
584 //***********************************
586 //***********************************
587 ETL_NODISCARD
588 char* data()
589 {
590 return pbuffer;
591 }
592
593 //***********************************
595 //***********************************
596 ETL_NODISCARD
597 const char* data() const
598 {
599 return pbuffer;
600 }
601
602 private:
603
605 char* pbuffer;
606 size_t buffer_size;
607 };
608
609 //*****************************************************************************
612 //*****************************************************************************
613#if ETL_USING_CPP11 && !defined(ETL_MEM_CAST_FORCE_CPP03_IMPLEMENTATION)
614 template <typename... TTypes>
615 using mem_cast_types = etl::mem_cast<etl::largest<TTypes...>::size, etl::largest<TTypes...>::alignment>;
616#else
617 template <typename T1, typename T2 = char, typename T3 = char, typename T4 = char, typename T5 = char, typename T6 = char, typename T7 = char,
618 typename T8 = char, typename T9 = char, typename T10 = char, typename T11 = char, typename T12 = char, typename T13 = char,
619 typename T14 = char, typename T15 = char, typename T16 = char>
621 : public etl::mem_cast< etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::size,
622 etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::alignment>
623 {
624 };
625#endif
626} // namespace etl
627
628#endif
The base class for mem_cast exceptions.
Definition mem_cast.h:54
The exception thrown when the pointer is null.
Definition mem_cast.h:80
ETL_NODISCARD T & ref_at_offset()
Get a reference to T at offset (static).
Definition mem_cast.h:528
ETL_NODISCARD size_t size() const
Get the size of the buffer.
Definition mem_cast.h:557
ETL_NODISCARD char * data()
Get a pointer to the external buffer.
Definition mem_cast.h:588
ETL_NODISCARD const char * data() const
Get const a pointer to the external buffer.
Definition mem_cast.h:597
void assign_at_offset(size_t offset, const T &value)
Assign from value at offset.
Definition mem_cast.h:395
ETL_NODISCARD const T & ref_at_offset(size_t offset) const
Get a const reference to T at offset (dynamic).
Definition mem_cast.h:513
ETL_NODISCARD const T & ref_at_offset() const
Get a const reference to T at offset (static).
Definition mem_cast.h:543
ETL_NODISCARD T & ref_at_offset(size_t offset)
Get a reference to T at offset (dynamic).
Definition mem_cast.h:498
ETL_NODISCARD const T & ref() const
Get a const reference to T.
Definition mem_cast.h:483
mem_cast_ptr & operator=(const mem_cast_ptr &rhs)
Assignment operator.
Definition mem_cast.h:371
ETL_NODISCARD T & ref()
Get a reference to T.
Definition mem_cast.h:468
mem_cast_ptr(const mem_cast_ptr &other)
Copy construct.
Definition mem_cast.h:362
mem_cast_ptr(char *pbuffer_, size_t buffer_size_=Undefined_Size)
Construct with pointer to buffer and optional size.
Definition mem_cast.h:353
void assign(const T &value)
Assign from value.
Definition mem_cast.h:383
ETL_NODISCARD size_t alignment() const
Get the alignment of the buffer.
Definition mem_cast.h:566
void data(char *pbuffer_, size_t buffer_size_=Undefined_Size)
Set the pointer to the external buffer.
Definition mem_cast.h:578
void assign_at_offset(const T &value)
Assign from value at offset.
Definition mem_cast.h:408
mem_cast_ptr()
Default constructor.
Definition mem_cast.h:344
The exception thrown when the type size is too large.
Definition mem_cast.h:67
mem_cast
Definition mem_cast.h:94
void assign_at_offset(size_t offset, const T &value)
Assign from value at offset.
Definition mem_cast.h:149
mem_cast(const mem_cast< Other_Size, Other_Alignment > &other)
Copy constructor.
Definition mem_cast.h:114
void assign_at_offset(const T &value)
Assign from value at offset.
Definition mem_cast.h:161
mem_cast()
Default constructor.
Definition mem_cast.h:105
ETL_NODISCARD const T & ref_at_offset(size_t offset) const
Get a const reference to T at offset (dynamic).
Definition mem_cast.h:253
void assign(const T &value)
Assign from value.
Definition mem_cast.h:138
ETL_NODISCARD char * data()
Get a pointer to the internal buffer.
Definition mem_cast.h:306
ETL_NODISCARD T & ref_at_offset(size_t offset)
Get a reference to T at offset (dynamic).
Definition mem_cast.h:241
ETL_NODISCARD T & ref()
Get a reference to T.
Definition mem_cast.h:217
static ETL_NODISCARD ETL_CONSTEXPR size_t alignment()
Get the alignment of the buffer.
Definition mem_cast.h:297
ETL_NODISCARD T & ref_at_offset()
Get a reference to T at offset (static).
Definition mem_cast.h:265
ETL_NODISCARD const T & ref_at_offset() const
Get a const reference to T at offset (static).
Definition mem_cast.h:277
ETL_NODISCARD const char * data() const
Get a const pointer to the internal buffer.
Definition mem_cast.h:315
static ETL_NODISCARD ETL_CONSTEXPR size_t size()
Get the size of the buffer.
Definition mem_cast.h:288
mem_cast & operator=(const mem_cast< Other_Size, Other_Alignment > &rhs)
Assignment operator.
Definition mem_cast.h:125
ETL_NODISCARD const T & ref() const
Get a const reference to T.
Definition mem_cast.h:229
Definition memory.h:2662
ETL_CONSTEXPR14 etl::enable_if< etl::is_integral< T >::value &&etl::is_unsigned< T >::value &&(etl::integral_limits< T >::bits==16U), uint_least8_t >::type count_trailing_zeros(T value)
Definition binary.h:1133
#define ETL_ASSERT(b, e)
Definition error_handler.h:511
ETL_EXCEPTION_CONSTEXPR exception(string_type reason_, string_type, numeric_type)
Constructor.
Definition exception.h:81
Definition exception.h:59
Definition integral_limits.h:518
Definition largest.h:45
Definition smallest.h:205
bitset_ext
Definition absolute.h:40
Definition mem_cast.h:623