21#include "comms/details/tag.h"
25#if COMMS_IS_GCC_14 && defined(NDEBUG) && (COMMS_IS_CPP20 || COMMS_IS_CPP23)
27COMMS_GNU_WARNING_DISABLE(
"-Wfree-nonheap-object")
56using AccessSelectTypeItself =
typename std::decay<T>::type;
59using AccessSelectIntType =
61 std::is_signed<T>::value
62 >::template Type<int, unsigned>;
65using AccessOptimisedValueType =
66 typename comms::util::LazyShallowConditional<
67 sizeof(T) >=
sizeof(
int)
69 AccessSelectTypeItself,
74template <
typename TUn
signedByteType,
typename T>
75typename std::decay<T>::type signExtCommon(T value, std::size_t size)
77 using ValueType =
typename std::decay<T>::type;
78 static_assert(std::is_unsigned<ValueType>::value,
"Type T must be unsigned");
79 static_assert(std::is_unsigned<TUnsignedByteType>::value,
80 "Type TUnsignedByteType must be unsigned");
82 static const std::size_t BinDigits =
83 std::numeric_limits<TUnsignedByteType>::digits;
84 static_assert(BinDigits % 8 == 0,
"Byte size assumption is not valid");
87 static_cast<ValueType
>(
static_cast<ValueType
>(1) << ((size * BinDigits) - 1));
89 return static_cast<ValueType
>(value | (~((mask << 1) - 1)));
97 template <
typename... TParams>
98 using FullSize = comms::details::tag::Tag1<>;
100 template <
typename... TParams>
101 using PartialSize = comms::details::tag::Tag2<>;
104 template <std::
size_t TSize,
typename TByteType,
typename T>
105 static typename std::decay<T>::type value(T val)
107 using ValueType =
typename std::decay<T>::type;
109 typename comms::util::LazyShallowConditional<
110 sizeof(ValueType) == TSize
116 return valueInternal<TSize, TByteType>(val, Tag());
121 template <std::size_t TSize,
typename TByteType,
typename T,
typename... TParams>
122 static typename std::decay<T>::type valueInternal(T val, FullSize<TParams...>)
127 template <std::size_t TSize,
typename TByteType,
typename T,
typename... TParams>
128 static typename std::decay<T>::type valueInternal(T val, PartialSize<TParams...>)
130 using ValueType =
typename std::decay<T>::type;
131 using UnsignedValueType =
typename std::make_unsigned<ValueType>::type;
132 static_assert(std::is_integral<ValueType>::value,
"T must be integer type");
133 using UnsignedByteType =
typename std::make_unsigned<TByteType>::type;
135 auto castedValue =
static_cast<UnsignedValueType
>(val);
136 return static_cast<ValueType
>(
137 signExtCommon<UnsignedByteType>(castedValue, TSize));
141template <
typename TIter>
142using AccessIteratorByteType =
typename std::iterator_traits<typename std::decay<TIter>::type>::value_type;
144template <
typename TIter>
145struct AccessContainerByteTypeDetector
147 using Type = AccessIteratorByteType<TIter>;
150template <
typename TContainer>
151struct AccessContainerByteTypeDetector<
std::back_insert_iterator<TContainer> >
153 using Type =
typename TContainer::value_type;
156template <
typename TContainer>
157struct AccessContainerByteTypeDetector<
std::insert_iterator<TContainer> >
159 using Type =
typename TContainer::value_type;
162template <
typename TContainer>
163struct AccessContainerByteTypeDetector<
std::front_insert_iterator<TContainer> >
165 using Type =
typename TContainer::value_type;
168template <
typename TIter>
169using AccessContainerByteType =
170 typename AccessContainerByteTypeDetector<typename std::decay<TIter>::type>::Type;
172template <
typename TIter>
173using AccessByteType =
174 typename comms::util::LazyShallowConditional<
175 std::is_void<AccessIteratorByteType<TIter> >::value
177 AccessContainerByteType,
178 AccessIteratorByteType,
182template <
typename T,
typename TIter>
183void writeBigUnsigned(T value, std::size_t size, TIter& iter)
185 using ValueType =
typename std::decay<T>::type;
186 static_assert(std::is_unsigned<ValueType>::value,
"T type must be unsigned");
187 static_assert(std::is_integral<ValueType>::value,
"T must be integral type");
189 using ByteType = AccessByteType<TIter>;
190 static_assert(!std::is_void<ByteType>::value,
"Invalid byte type");
191 using UnsignedByteType =
typename std::make_unsigned<ByteType>::type;
192 static const std::size_t BinDigits =
193 std::numeric_limits<UnsignedByteType>::digits;
194 static_assert(BinDigits % 8 == 0,
"Byte size assumption is not valid");
196 std::size_t remainingSize = size;
197 while (remainingSize > 0) {
198 std::size_t remaingShift = ((remainingSize - 1) * BinDigits);
199 auto byte =
static_cast<ByteType
>(value >> remaingShift);
206template <
typename T,
typename TIter>
207void writeLittleUnsigned(T value, std::size_t size, TIter& iter)
209 using ValueType =
typename std::decay<T>::type;
210 static_assert(std::is_integral<ValueType>::value,
"T must be integral type");
211 static_assert(std::is_unsigned<ValueType>::value,
"T type must be unsigned");
213 using ByteType = AccessByteType<TIter>;
214 static_assert(!std::is_void<ByteType>::value,
"Invalid byte type");
215 using UnsignedByteType =
typename std::make_unsigned<ByteType>::type;
216 static const std::size_t BinDigits =
217 std::numeric_limits<UnsignedByteType>::digits;
218 static_assert(BinDigits % 8 == 0,
"Byte size assumption is not valid");
220 std::size_t remainingSize = size;
221 while (remainingSize > 0) {
222 std::size_t remaingShift = ((size - remainingSize) * BinDigits);
224 auto byte =
static_cast<ByteType
>(value >> remaingShift);
231template <
typename TEndian>
232struct WriteUnsignedFuncWrapper;
235struct WriteUnsignedFuncWrapper<traits::endian::Big>
237 template <
typename T,
typename TIter>
238 static void write(T value, std::size_t size, TIter& iter)
240 writeBigUnsigned(value, size, iter);
245struct WriteUnsignedFuncWrapper<traits::endian::Little>
247 template <
typename T,
typename TIter>
248 static void write(T value, std::size_t size, TIter& iter)
250 writeLittleUnsigned(value, size, iter);
254template <
typename TEndian,
typename T,
typename TIter>
255void write(T value, std::size_t size, TIter& iter)
257 using ValueType =
typename std::decay<T>::type;
258 static_assert(std::is_integral<ValueType>::value,
"T must be integral type");
259 using UnsignedType =
typename std::make_unsigned<ValueType>::type;
260 UnsignedType unsignedValue =
static_cast<UnsignedType
>(value);
261 WriteUnsignedFuncWrapper<TEndian>::write(unsignedValue, size, iter);
264template <
typename TEndian,
typename T,
typename TIter>
265void writeRandomAccess(T value, std::size_t size, TIter& iter)
267 using ValueType =
typename std::decay<T>::type;
269 static_assert(std::is_integral<ValueType>::value,
"T must be integral type");
272 typename std::iterator_traits<TIter>::iterator_category,
273 std::random_access_iterator_tag
275 "TIter must be random access iterator");
277 using ByteType = AccessByteType<TIter>;
278 static_assert(!std::is_void<ByteType>::value,
"Invalid byte type");
279 using UnsignedByteType =
typename std::make_unsigned<ByteType>::type;
280 static_assert(!std::is_const<UnsignedByteType>::value,
"Value must be updatable");
282 auto startPtr =
reinterpret_cast<UnsignedByteType*
>(&(*iter));
283 auto endPtr = startPtr;
284 write<TEndian>(value, size, endPtr);
285 iter += (endPtr - startPtr);
288template <
typename...>
291 template <
typename... TParams>
292 using RandomAccessTag = comms::details::tag::Tag1<>;
294 template <
typename... TParams>
295 using RegularTag = comms::details::tag::Tag2<>;
297 template <
typename TIter>
298 using RandomAccessOrPointerTag =
299 typename comms::util::LazyShallowConditional<
300 std::is_pointer<TIter>::value &&
301 std::is_unsigned<AccessByteType<TIter> >::value
307 template <
typename TIter>
309 typename comms::util::LazyShallowConditional<
311 typename std::iterator_traits<TIter>::iterator_category,
312 std::random_access_iterator_tag
315 RandomAccessOrPointerTag,
320 template <
typename TEndian,
typename T,
typename TIter,
typename... TParams>
321 static void writeInternal(T value, std::size_t size, TIter& iter, RandomAccessTag<TParams...>)
323 writeRandomAccess<TEndian>(value, size, iter);
326 template <
typename TEndian,
typename T,
typename TIter,
typename... TParams>
327 static void writeInternal(T value, std::size_t size, TIter& iter, RegularTag<TParams...>)
329 details::write<TEndian>(value, size, iter);
333 template <
typename TEndian,
typename T,
typename TIter>
334 static void write(T value, std::size_t size, TIter& iter)
336 using ValueType =
typename std::decay<T>::type;
337 using AccessOptimisedValueType = details::AccessOptimisedValueType<ValueType>;
339 return writeInternal<TEndian>(
static_cast<AccessOptimisedValueType
>(value), size, iter, Tag<TIter>());
343template <
typename T,
typename TIter>
344T readBigUnsigned(std::size_t size, TIter& iter)
346 using ValueType =
typename std::decay<T>::type;
347 static_assert(std::is_integral<ValueType>::value,
"T must be integral type");
348 static_assert(std::is_unsigned<ValueType>::value,
"T type must be unsigned");
350 using ByteType = AccessByteType<TIter>;
351 static_assert(!std::is_void<ByteType>::value,
"Invalid byte type");
352 using UnsignedByteType =
typename std::make_unsigned<ByteType>::type;
353 static const std::size_t BinDigits =
354 std::numeric_limits<UnsignedByteType>::digits;
355 static_assert(BinDigits % 8 == 0,
"Byte size assumption is not valid");
358 std::size_t remainingSize = size;
359 while (remainingSize > 0) {
361 value =
static_cast<ValueType
>(value << BinDigits);
362 value |=
static_cast<decltype(value)
>(
static_cast<UnsignedByteType
>(byte));
369template <
typename T,
typename TIter>
370T readLittleUnsigned(std::size_t size, TIter& iter)
372 using ValueType =
typename std::decay<T>::type;
373 static_assert(std::is_integral<ValueType>::value,
"T must be integral type");
374 static_assert(std::is_unsigned<ValueType>::value,
"T type must be unsigned");
376 using ByteType = AccessByteType<TIter>;
377 static_assert(!std::is_void<ByteType>::value,
"Invalid byte type");
378 using UnsignedByteType =
typename std::make_unsigned<ByteType>::type;
379 static const std::size_t BinDigits =
380 std::numeric_limits<UnsignedByteType>::digits;
381 static_assert(BinDigits % 8 == 0,
"Byte size assumption is not valid");
384 std::size_t remainingSize = size;
385 while (remainingSize > 0) {
387 value |=
static_cast<ValueType
>(
static_cast<UnsignedByteType
>(byte)) <<
388 ((size - remainingSize) * BinDigits);
393 return static_cast<T
>(value);
396template <
typename TEndian>
397struct ReadUnsignedFuncWrapper;
400struct ReadUnsignedFuncWrapper<traits::endian::Big>
402 template <
typename T,
typename TIter>
403 static T read(std::size_t size, TIter& iter)
405 return readBigUnsigned<T>(size, iter);
410struct ReadUnsignedFuncWrapper<traits::endian::Little>
412 template <
typename T,
typename TIter>
413 static T read(std::size_t size, TIter& iter)
415 return readLittleUnsigned<T>(size, iter);
419template <
typename TEndian,
typename T,
typename TIter>
420T read(std::size_t size, TIter& iter)
422 using ValueType =
typename std::decay<T>::type;
424 static_assert(std::is_integral<ValueType>::value,
"T must be integral type");
426 using UnsignedType =
typename std::make_unsigned<ValueType>::type;
427 auto value = ReadUnsignedFuncWrapper<TEndian>::template read<UnsignedType>(size, iter);
428 return static_cast<T
>(
static_cast<ValueType
>(value));
431template <
typename TEndian,
typename T,
typename TIter>
432T readFromPointerToSigned(std::size_t size, TIter& iter)
434 using ValueType =
typename std::decay<T>::type;
436 static_assert(std::is_integral<ValueType>::value,
"T must be integral type");
439 typename std::iterator_traits<TIter>::iterator_category,
440 std::random_access_iterator_tag
442 "TIter must be random access iterator");
444 using ByteType = AccessByteType<TIter>;
445 static_assert(!std::is_void<ByteType>::value,
"Invalid byte type");
446 using UnsignedByteType =
typename std::make_unsigned<ByteType>::type;
448 auto startPtr =
reinterpret_cast<const UnsignedByteType*
>(&(*iter));
449 auto endPtr = startPtr;
450 auto value = details::read<TEndian, ValueType>(size, endPtr);
451 iter += (endPtr - startPtr);
452 return static_cast<T
>(
static_cast<ValueType
>(value));
455template <
typename...>
458 template <
typename... TParams>
459 using PointerToSignedTag = comms::details::tag::Tag1<>;
461 template <
typename... TParams>
462 using OtherTag = comms::details::tag::Tag2<>;
464 template <
typename TIter>
465 using PointerCheckTag =
466 typename comms::util::LazyShallowConditional<
467 std::is_const<AccessByteType<TIter> >::value &&
468 std::is_unsigned<AccessByteType<TIter> >::value
474 template <
typename TIter>
476 typename comms::util::LazyShallowConditional<
477 std::is_pointer<TIter>::value
484 template <
typename TEndian,
typename T,
typename TIter,
typename... TParams>
485 static T readInternal(std::size_t size, TIter& iter, PointerToSignedTag<TParams...>)
487 return readFromPointerToSigned<TEndian, T>(size, iter);
490 template <
typename TEndian,
typename T,
typename TIter,
typename... TParams>
491 static T readInternal(std::size_t size, TIter& iter, OtherTag<TParams...>)
493 return details::read<TEndian, T>(size, iter);
497 template <
typename TEndian,
typename T,
typename TIter>
498 static T read(std::size_t size, TIter& iter)
500 using ValueType =
typename std::decay<T>::type;
501 using AccessOptimisedValueType = details::AccessOptimisedValueType<ValueType>;
503 static_cast<ValueType
>(
504 readInternal<TEndian, AccessOptimisedValueType>(size, iter, Tag<TIter>()));
507 template <
typename TEndian,
typename T, std::
size_t TSize,
typename TIter>
508 static T read(TIter& iter)
510 using ValueType =
typename std::decay<T>::type;
511 using ByteType = details::AccessByteType<TIter>;
512 static_assert(!std::is_void<ByteType>::value,
"Invalid byte type");
513 static_assert(TSize <=
sizeof(ValueType),
"Precondition failure");
514 auto retval = read<TEndian, ValueType>(TSize, iter);
515 if (std::is_signed<ValueType>::value) {
516 retval = details::SignExt<>::template value<TSize, ByteType>(retval);
518 return static_cast<T
>(retval);
533template <std::
size_t TSize,
typename T,
typename TIter>
536 details::WriteHelper<>::template write<traits::endian::Big>(value, TSize, iter);
548template <
typename T,
typename TIter>
549void writeBig(T value, std::size_t size, TIter& iter)
551 details::WriteHelper<>::template write<traits::endian::Big>(value, size, iter);
561template <
typename T,
typename TIter>
564 using ValueType =
typename std::decay<T>::type;
565 writeBig<sizeof(ValueType)>(
static_cast<ValueType
>(value), iter);
578template <
typename T, std::
size_t TSize,
typename TIter>
581 return details::ReadHelper<>::template read<traits::endian::Big, T, TSize>(iter);
592template <
typename T,
typename TIter>
595 using ValueType =
typename std::decay<T>::type;
596 return static_cast<T
>(readBig<ValueType, sizeof(ValueType)>(iter));
608template <
typename T,
typename TIter>
611 return details::ReadHelper<>::template read<traits::endian::Big, T>(size, iter);
623template <std::
size_t TSize,
typename T,
typename TIter>
626 details::WriteHelper<>::template write<traits::endian::Little>(value, TSize, iter);
638template <
typename T,
typename TIter>
641 details::WriteHelper<>::template write<traits::endian::Little>(value, size, iter);
651template <
typename T,
typename TIter>
654 using ValueType =
typename std::decay<T>::type;
655 writeLittle<sizeof(ValueType)>(
static_cast<ValueType
>(value), iter);
668template <
typename T, std::
size_t TSize,
typename TIter>
671 return details::ReadHelper<>::template read<traits::endian::Little, T, TSize>(iter);
682template <
typename T,
typename TIter>
685 using ValueType =
typename std::decay<T>::type;
686 return static_cast<T
>(readLittle<ValueType, sizeof(ValueType)>(iter));
698template <
typename T,
typename TIter>
701 return details::ReadHelper<>::template read<traits::endian::Little, T>(size, iter);
705template <
typename T,
typename TIter>
711 static_cast<void>(endian);
716template <std::
size_t TSize,
typename T,
typename TIter>
722 static_cast<void>(endian);
723 writeBig<TSize>(value, iter);
727template <
typename T,
typename TIter>
734 static_cast<void>(endian);
739template <
typename T,
typename TIter>
745 static_cast<void>(endian);
750template <std::
size_t TSize,
typename T,
typename TIter>
756 static_cast<void>(endian);
757 return writeLittle<TSize>(value, iter);
761template <
typename T,
typename TIter>
768 static_cast<void>(endian);
773template <
typename T,
typename TIter>
776 static_cast<void>(endian);
777 return readBig<T>(iter);
781template <
typename T,
typename TIter>
784 static_cast<void>(endian);
785 return readBig<T>(iter, size);
789template <
typename T, std::
size_t TSize,
typename TIter>
792 static_cast<void>(endian);
793 return readBig<T, TSize>(iter);
797template <
typename T,
typename TIter>
800 static_cast<void>(endian);
801 return readLittle<T>(iter);
805template <
typename T, std::
size_t TSize,
typename TIter>
808 static_cast<void>(endian);
809 return readLittle<T, TSize>(iter);
813template <
typename T,
typename TIter>
816 static_cast<void>(endian);
817 return readLittle<T>(iter, size);
Contains various compiler related definitions.
void writeLittle(T value, TIter &iter)
Write part of integral value into the output area using little endian notation.
Definition access.h:624
T readData(TIter &iter, const traits::endian::Big &endian)
Same as readBig<T, TIter>()
Definition access.h:774
void writeData(T value, TIter &iter, const traits::endian::Big &endian)
Same as writeBig<T, TIter>()
Definition access.h:706
T readBig(TIter &iter)
Read part of integral value from the input area using big endian notation.
Definition access.h:579
void writeBig(T value, TIter &iter)
Write part of integral value into the output area using big endian notation.
Definition access.h:534
T readLittle(TIter &iter)
Read part of integral value from the input area using little endian notation.
Definition access.h:669
Main namespace for all classes / functions of COMMS library.
Replacement to std::conditional.
Definition type_traits.h:28
Empty class used in traits to indicate Big Endian.
Definition access.h:43
Empty class used in traits to indicate Little Endian.
Definition access.h:46
Replacement to some types from standard type_traits.