16#include "comms/details/tag.h"
26#if COMMS_IS_GCC_14 && defined(NDEBUG) && (COMMS_IS_CPP20 || COMMS_IS_CPP23)
28COMMS_GNU_WARNING_DISABLE(
"-Wfree-nonheap-object")
57using AccessSelectTypeItself =
typename std::decay<T>::type;
60using AccessSelectIntType =
62 std::is_signed<T>::value
63 >::template Type<int, unsigned>;
66using AccessOptimisedValueType =
67 typename comms::util::LazyShallowConditional<
68 sizeof(T) >=
sizeof(
int)
70 AccessSelectTypeItself,
75template <
typename TUn
signedByteType,
typename T>
76typename std::decay<T>::type signExtCommon(T value, std::size_t size)
78 using ValueType =
typename std::decay<T>::type;
79 static_assert(std::is_unsigned<ValueType>::value,
"Type T must be unsigned");
80 static_assert(std::is_unsigned<TUnsignedByteType>::value,
81 "Type TUnsignedByteType must be unsigned");
83 static const std::size_t BinDigits =
84 std::numeric_limits<TUnsignedByteType>::digits;
85 static_assert(BinDigits % 8 == 0,
"Byte size assumption is not valid");
88 static_cast<ValueType
>(
static_cast<ValueType
>(1) << ((size * BinDigits) - 1));
90 return static_cast<ValueType
>(value | (~((mask << 1) - 1)));
98 template <
typename... TParams>
99 using FullSize = comms::details::tag::Tag1<>;
101 template <
typename... TParams>
102 using PartialSize = comms::details::tag::Tag2<>;
105 template <std::
size_t TSize,
typename TByteType,
typename T>
106 static typename std::decay<T>::type value(T val)
108 using ValueType =
typename std::decay<T>::type;
110 typename comms::util::LazyShallowConditional<
111 sizeof(ValueType) == TSize
117 return valueInternal<TSize, TByteType>(val, Tag());
122 template <std::size_t TSize,
typename TByteType,
typename T,
typename... TParams>
123 static typename std::decay<T>::type valueInternal(T val, FullSize<TParams...>)
128 template <std::size_t TSize,
typename TByteType,
typename T,
typename... TParams>
129 static typename std::decay<T>::type valueInternal(T val, PartialSize<TParams...>)
131 using ValueType =
typename std::decay<T>::type;
132 using UnsignedValueType =
typename std::make_unsigned<ValueType>::type;
133 static_assert(std::is_integral<ValueType>::value,
"T must be integer type");
134 using UnsignedByteType =
typename std::make_unsigned<TByteType>::type;
136 auto castedValue =
static_cast<UnsignedValueType
>(val);
137 return static_cast<ValueType
>(
138 signExtCommon<UnsignedByteType>(castedValue, TSize));
142template <
typename TIter>
143using AccessIteratorByteType =
typename std::iterator_traits<typename std::decay<TIter>::type>::value_type;
145template <
typename TIter>
146struct AccessContainerByteTypeDetector
148 using Type = AccessIteratorByteType<TIter>;
151template <
typename TContainer>
152struct AccessContainerByteTypeDetector<
std::back_insert_iterator<TContainer> >
154 using Type =
typename TContainer::value_type;
157template <
typename TContainer>
158struct AccessContainerByteTypeDetector<
std::insert_iterator<TContainer> >
160 using Type =
typename TContainer::value_type;
163template <
typename TContainer>
164struct AccessContainerByteTypeDetector<
std::front_insert_iterator<TContainer> >
166 using Type =
typename TContainer::value_type;
169template <
typename TIter>
170using AccessContainerByteType =
171 typename AccessContainerByteTypeDetector<typename std::decay<TIter>::type>::Type;
173template <
typename TIter>
174using AccessByteType =
175 typename comms::util::LazyShallowConditional<
176 std::is_void<AccessIteratorByteType<TIter> >::value
178 AccessContainerByteType,
179 AccessIteratorByteType,
183template <
typename T,
typename TIter>
184void writeBigUnsigned(T value, std::size_t size, TIter& iter)
186 using ValueType =
typename std::decay<T>::type;
187 static_assert(std::is_unsigned<ValueType>::value,
"T type must be unsigned");
188 static_assert(std::is_integral<ValueType>::value,
"T must be integral type");
190 using ByteType = AccessByteType<TIter>;
191 static_assert(!std::is_void<ByteType>::value,
"Invalid byte type");
192 using UnsignedByteType =
typename std::make_unsigned<ByteType>::type;
193 static const std::size_t BinDigits =
194 std::numeric_limits<UnsignedByteType>::digits;
195 static_assert(BinDigits % 8 == 0,
"Byte size assumption is not valid");
197 std::size_t remainingSize = size;
198 while (remainingSize > 0) {
199 std::size_t remaingShift = ((remainingSize - 1) * BinDigits);
200 auto byte =
static_cast<ByteType
>(value >> remaingShift);
207template <
typename T,
typename TIter>
208void writeLittleUnsigned(T value, std::size_t size, TIter& iter)
210 using ValueType =
typename std::decay<T>::type;
211 static_assert(std::is_integral<ValueType>::value,
"T must be integral type");
212 static_assert(std::is_unsigned<ValueType>::value,
"T type must be unsigned");
214 using ByteType = AccessByteType<TIter>;
215 static_assert(!std::is_void<ByteType>::value,
"Invalid byte type");
216 using UnsignedByteType =
typename std::make_unsigned<ByteType>::type;
217 static const std::size_t BinDigits =
218 std::numeric_limits<UnsignedByteType>::digits;
219 static_assert(BinDigits % 8 == 0,
"Byte size assumption is not valid");
221 std::size_t remainingSize = size;
222 while (remainingSize > 0) {
223 std::size_t remaingShift = ((size - remainingSize) * BinDigits);
225 auto byte =
static_cast<ByteType
>(value >> remaingShift);
232template <
typename TEndian>
233struct WriteUnsignedFuncWrapper;
236struct WriteUnsignedFuncWrapper<traits::endian::Big>
238 template <
typename T,
typename TIter>
239 static void write(T value, std::size_t size, TIter& iter)
241 writeBigUnsigned(value, size, iter);
246struct WriteUnsignedFuncWrapper<traits::endian::Little>
248 template <
typename T,
typename TIter>
249 static void write(T value, std::size_t size, TIter& iter)
251 writeLittleUnsigned(value, size, iter);
255template <
typename TEndian,
typename T,
typename TIter>
256void write(T value, std::size_t size, TIter& iter)
258 using ValueType =
typename std::decay<T>::type;
259 static_assert(std::is_integral<ValueType>::value,
"T must be integral type");
260 using UnsignedType =
typename std::make_unsigned<ValueType>::type;
261 UnsignedType unsignedValue =
static_cast<UnsignedType
>(value);
262 WriteUnsignedFuncWrapper<TEndian>::write(unsignedValue, size, iter);
265template <
typename TEndian,
typename T,
typename TIter>
266void writeRandomAccess(T value, std::size_t size, TIter& iter)
268 using ValueType =
typename std::decay<T>::type;
270 static_assert(std::is_integral<ValueType>::value,
"T must be integral type");
273 typename std::iterator_traits<TIter>::iterator_category,
274 std::random_access_iterator_tag
276 "TIter must be random access iterator");
278 using ByteType = AccessByteType<TIter>;
279 static_assert(!std::is_void<ByteType>::value,
"Invalid byte type");
280 using UnsignedByteType =
typename std::make_unsigned<ByteType>::type;
281 static_assert(!std::is_const<UnsignedByteType>::value,
"Value must be updatable");
283 auto startPtr =
reinterpret_cast<UnsignedByteType*
>(&(*iter));
284 auto endPtr = startPtr;
285 write<TEndian>(value, size, endPtr);
286 iter += (endPtr - startPtr);
289template <
typename...>
292 template <
typename... TParams>
293 using RandomAccessTag = comms::details::tag::Tag1<>;
295 template <
typename... TParams>
296 using RegularTag = comms::details::tag::Tag2<>;
298 template <
typename TIter>
299 using RandomAccessOrPointerTag =
300 typename comms::util::LazyShallowConditional<
301 std::is_pointer<TIter>::value &&
302 std::is_unsigned<AccessByteType<TIter> >::value
308 template <
typename TIter>
310 typename comms::util::LazyShallowConditional<
312 typename std::iterator_traits<TIter>::iterator_category,
313 std::random_access_iterator_tag
316 RandomAccessOrPointerTag,
321 template <
typename TEndian,
typename T,
typename TIter,
typename... TParams>
322 static void writeInternal(T value, std::size_t size, TIter& iter, RandomAccessTag<TParams...>)
324 writeRandomAccess<TEndian>(value, size, iter);
327 template <
typename TEndian,
typename T,
typename TIter,
typename... TParams>
328 static void writeInternal(T value, std::size_t size, TIter& iter, RegularTag<TParams...>)
330 details::write<TEndian>(value, size, iter);
334 template <
typename TEndian,
typename T,
typename TIter>
335 static void write(T value, std::size_t size, TIter& iter)
337 using ValueType =
typename std::decay<T>::type;
338 using AccessOptimisedValueType = details::AccessOptimisedValueType<ValueType>;
340 return writeInternal<TEndian>(
static_cast<AccessOptimisedValueType
>(value), size, iter, Tag<TIter>());
344template <
typename T,
typename TIter>
345T readBigUnsigned(std::size_t size, TIter& iter)
347 using ValueType =
typename std::decay<T>::type;
348 static_assert(std::is_integral<ValueType>::value,
"T must be integral type");
349 static_assert(std::is_unsigned<ValueType>::value,
"T type must be unsigned");
351 using ByteType = AccessByteType<TIter>;
352 static_assert(!std::is_void<ByteType>::value,
"Invalid byte type");
353 using UnsignedByteType =
typename std::make_unsigned<ByteType>::type;
354 static const std::size_t BinDigits =
355 std::numeric_limits<UnsignedByteType>::digits;
356 static_assert(BinDigits % 8 == 0,
"Byte size assumption is not valid");
359 std::size_t remainingSize = size;
360 while (remainingSize > 0) {
362 value =
static_cast<ValueType
>(value << BinDigits);
363 value |=
static_cast<decltype(value)
>(
static_cast<UnsignedByteType
>(byte));
370template <
typename T,
typename TIter>
371T readLittleUnsigned(std::size_t size, TIter& iter)
373 using ValueType =
typename std::decay<T>::type;
374 static_assert(std::is_integral<ValueType>::value,
"T must be integral type");
375 static_assert(std::is_unsigned<ValueType>::value,
"T type must be unsigned");
377 using ByteType = AccessByteType<TIter>;
378 static_assert(!std::is_void<ByteType>::value,
"Invalid byte type");
379 using UnsignedByteType =
typename std::make_unsigned<ByteType>::type;
380 static const std::size_t BinDigits =
381 std::numeric_limits<UnsignedByteType>::digits;
382 static_assert(BinDigits % 8 == 0,
"Byte size assumption is not valid");
385 std::size_t remainingSize = size;
386 while (remainingSize > 0) {
388 value |=
static_cast<ValueType
>(
static_cast<UnsignedByteType
>(byte)) <<
389 ((size - remainingSize) * BinDigits);
394 return static_cast<T
>(value);
397template <
typename TEndian>
398struct ReadUnsignedFuncWrapper;
401struct ReadUnsignedFuncWrapper<traits::endian::Big>
403 template <
typename T,
typename TIter>
404 static T read(std::size_t size, TIter& iter)
406 return readBigUnsigned<T>(size, iter);
411struct ReadUnsignedFuncWrapper<traits::endian::Little>
413 template <
typename T,
typename TIter>
414 static T read(std::size_t size, TIter& iter)
416 return readLittleUnsigned<T>(size, iter);
420template <
typename TEndian,
typename T,
typename TIter>
421T read(std::size_t size, TIter& iter)
423 using ValueType =
typename std::decay<T>::type;
425 static_assert(std::is_integral<ValueType>::value,
"T must be integral type");
427 using UnsignedType =
typename std::make_unsigned<ValueType>::type;
428 auto value = ReadUnsignedFuncWrapper<TEndian>::template read<UnsignedType>(size, iter);
429 return static_cast<T
>(
static_cast<ValueType
>(value));
432template <
typename TEndian,
typename T,
typename TIter>
433T readFromPointerToSigned(std::size_t size, TIter& iter)
435 using ValueType =
typename std::decay<T>::type;
437 static_assert(std::is_integral<ValueType>::value,
"T must be integral type");
440 typename std::iterator_traits<TIter>::iterator_category,
441 std::random_access_iterator_tag
443 "TIter must be random access iterator");
445 using ByteType = AccessByteType<TIter>;
446 static_assert(!std::is_void<ByteType>::value,
"Invalid byte type");
447 using UnsignedByteType =
typename std::make_unsigned<ByteType>::type;
449 auto startPtr =
reinterpret_cast<const UnsignedByteType*
>(&(*iter));
450 auto endPtr = startPtr;
451 auto value = details::read<TEndian, ValueType>(size, endPtr);
452 iter += (endPtr - startPtr);
453 return static_cast<T
>(
static_cast<ValueType
>(value));
456template <
typename...>
459 template <
typename... TParams>
460 using PointerToSignedTag = comms::details::tag::Tag1<>;
462 template <
typename... TParams>
463 using OtherTag = comms::details::tag::Tag2<>;
465 template <
typename TIter>
466 using PointerCheckTag =
467 typename comms::util::LazyShallowConditional<
468 std::is_const<AccessByteType<TIter> >::value &&
469 std::is_unsigned<AccessByteType<TIter> >::value
475 template <
typename TIter>
477 typename comms::util::LazyShallowConditional<
478 std::is_pointer<TIter>::value
485 template <
typename TEndian,
typename T,
typename TIter,
typename... TParams>
486 static T readInternal(std::size_t size, TIter& iter, PointerToSignedTag<TParams...>)
488 return readFromPointerToSigned<TEndian, T>(size, iter);
491 template <
typename TEndian,
typename T,
typename TIter,
typename... TParams>
492 static T readInternal(std::size_t size, TIter& iter, OtherTag<TParams...>)
494 return details::read<TEndian, T>(size, iter);
498 template <
typename TEndian,
typename T,
typename TIter>
499 static T read(std::size_t size, TIter& iter)
501 using ValueType =
typename std::decay<T>::type;
502 using AccessOptimisedValueType = details::AccessOptimisedValueType<ValueType>;
504 static_cast<ValueType
>(
505 readInternal<TEndian, AccessOptimisedValueType>(size, iter, Tag<TIter>()));
508 template <
typename TEndian,
typename T, std::
size_t TSize,
typename TIter>
509 static T read(TIter& iter)
511 using ValueType =
typename std::decay<T>::type;
512 using ByteType = details::AccessByteType<TIter>;
513 static_assert(!std::is_void<ByteType>::value,
"Invalid byte type");
514 static_assert(TSize <=
sizeof(ValueType),
"Precondition failure");
515 auto retval = read<TEndian, ValueType>(TSize, iter);
516 if (std::is_signed<ValueType>::value) {
517 retval = details::SignExt<>::template value<TSize, ByteType>(retval);
519 return static_cast<T
>(retval);
534template <std::
size_t TSize,
typename T,
typename TIter>
537 details::WriteHelper<>::template write<traits::endian::Big>(value, TSize, iter);
549template <
typename T,
typename TIter>
550void writeBig(T value, std::size_t size, TIter& iter)
552 details::WriteHelper<>::template write<traits::endian::Big>(value, size, iter);
562template <
typename T,
typename TIter>
565 using ValueType =
typename std::decay<T>::type;
566 writeBig<sizeof(ValueType)>(
static_cast<ValueType
>(value), iter);
579template <
typename T, std::
size_t TSize,
typename TIter>
582 return details::ReadHelper<>::template read<traits::endian::Big, T, TSize>(iter);
593template <
typename T,
typename TIter>
596 using ValueType =
typename std::decay<T>::type;
597 return static_cast<T
>(readBig<ValueType, sizeof(ValueType)>(iter));
609template <
typename T,
typename TIter>
612 return details::ReadHelper<>::template read<traits::endian::Big, T>(size, iter);
624template <std::
size_t TSize,
typename T,
typename TIter>
627 details::WriteHelper<>::template write<traits::endian::Little>(value, TSize, iter);
639template <
typename T,
typename TIter>
642 details::WriteHelper<>::template write<traits::endian::Little>(value, size, iter);
652template <
typename T,
typename TIter>
655 using ValueType =
typename std::decay<T>::type;
656 writeLittle<sizeof(ValueType)>(
static_cast<ValueType
>(value), iter);
669template <
typename T, std::
size_t TSize,
typename TIter>
672 return details::ReadHelper<>::template read<traits::endian::Little, T, TSize>(iter);
683template <
typename T,
typename TIter>
686 using ValueType =
typename std::decay<T>::type;
687 return static_cast<T
>(readLittle<ValueType, sizeof(ValueType)>(iter));
699template <
typename T,
typename TIter>
702 return details::ReadHelper<>::template read<traits::endian::Little, T>(size, iter);
706template <
typename T,
typename TIter>
712 static_cast<void>(endian);
717template <std::
size_t TSize,
typename T,
typename TIter>
723 static_cast<void>(endian);
724 writeBig<TSize>(value, iter);
728template <
typename T,
typename TIter>
735 static_cast<void>(endian);
740template <
typename T,
typename TIter>
746 static_cast<void>(endian);
751template <std::
size_t TSize,
typename T,
typename TIter>
757 static_cast<void>(endian);
758 return writeLittle<TSize>(value, iter);
762template <
typename T,
typename TIter>
769 static_cast<void>(endian);
774template <
typename T,
typename TIter>
777 static_cast<void>(endian);
778 return readBig<T>(iter);
782template <
typename T,
typename TIter>
785 static_cast<void>(endian);
786 return readBig<T>(iter, size);
790template <
typename T, std::
size_t TSize,
typename TIter>
793 static_cast<void>(endian);
794 return readBig<T, TSize>(iter);
798template <
typename T,
typename TIter>
801 static_cast<void>(endian);
802 return readLittle<T>(iter);
806template <
typename T, std::
size_t TSize,
typename TIter>
809 static_cast<void>(endian);
810 return readLittle<T, TSize>(iter);
814template <
typename T,
typename TIter>
817 static_cast<void>(endian);
818 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:625
T readData(TIter &iter, const traits::endian::Big &endian)
Same as readBig<T, TIter>()
Definition access.h:775
void writeData(T value, TIter &iter, const traits::endian::Big &endian)
Same as writeBig<T, TIter>()
Definition access.h:707
T readBig(TIter &iter)
Read part of integral value from the input area using big endian notation.
Definition access.h:580
void writeBig(T value, TIter &iter)
Write part of integral value into the output area using big endian notation.
Definition access.h:535
T readLittle(TIter &iter)
Read part of integral value from the input area using little endian notation.
Definition access.h:670
Main namespace for all classes / functions of COMMS library.
Replacement to std::conditional.
Definition type_traits.h:32
Empty class used in traits to indicate Big Endian.
Definition access.h:44
Empty class used in traits to indicate Little Endian.
Definition access.h:47
Replacement to some types from standard type_traits.