/* * Copyright (C) 2014 Pavel Kirienko */ #ifndef UAVCAN_MARSHAL_INTEGER_SPEC_HPP_INCLUDED #define UAVCAN_MARSHAL_INTEGER_SPEC_HPP_INCLUDED #include #include #include #include #include namespace uavcan { enum Signedness { SignednessUnsigned, SignednessSigned }; template class UAVCAN_EXPORT IntegerSpec { struct ErrorNoSuchInteger; public: enum { IsSigned = Signedness == SignednessSigned }; enum { BitLen = BitLen_ }; enum { MinBitLen = BitLen }; enum { MaxBitLen = BitLen }; enum { IsPrimitive = 1 }; typedef typename Select<(BitLen <= 8), typename Select::Result, typename Select<(BitLen <= 16), typename Select::Result, typename Select<(BitLen <= 32), typename Select::Result, typename Select<(BitLen <= 64), typename Select::Result, ErrorNoSuchInteger>::Result>::Result>::Result>::Result StorageType; typedef typename IntegerSpec::StorageType UnsignedStorageType; private: IntegerSpec(); struct LimitsImplGeneric { static StorageType max() { StaticAssert<(sizeof(uintmax_t) >= 8)>::check(); if (IsSigned == 0) { return StorageType((uintmax_t(1) << static_cast(BitLen)) - 1U); } else { return StorageType((uintmax_t(1) << (static_cast(BitLen) - 1U)) - 1); } } static UnsignedStorageType mask() { StaticAssert<(sizeof(uintmax_t) >= 8U)>::check(); return UnsignedStorageType((uintmax_t(1) << static_cast(BitLen)) - 1U); } }; struct LimitsImpl64 { static StorageType max() { return StorageType((IsSigned == 0) ? 0xFFFFFFFFFFFFFFFFULL : 0x7FFFFFFFFFFFFFFFLL); } static UnsignedStorageType mask() { return 0xFFFFFFFFFFFFFFFFULL; } }; typedef typename Select<(BitLen == 64), LimitsImpl64, LimitsImplGeneric>::Result Limits; static void saturate(StorageType& value) { if (value > max()) { value = max(); } else if (value <= min()) // 'Less or Equal' allows to suppress compiler warning on unsigned types { value = min(); } else { ; // Valid range } } static void truncate(StorageType& value) { value = value & StorageType(mask()); } static void validate() { StaticAssert<(BitLen <= (sizeof(StorageType) * 8))>::check(); // coverity[result_independent_of_operands : FALSE] UAVCAN_ASSERT(max() <= NumericTraits::max()); // coverity[result_independent_of_operands : FALSE] UAVCAN_ASSERT(min() >= NumericTraits::min()); } public: static StorageType max() { return Limits::max(); } static StorageType min() { return IsSigned ? StorageType(-max() - 1) : 0; } static UnsignedStorageType mask() { return Limits::mask(); } static int encode(StorageType value, ScalarCodec& codec, TailArrayOptimizationMode) { validate(); // cppcheck-suppress duplicateExpression if (CastMode == CastModeSaturate) { saturate(value); } else { truncate(value); } return codec.encode(value); } static int decode(StorageType& out_value, ScalarCodec& codec, TailArrayOptimizationMode) { validate(); return codec.decode(out_value); } static void extendDataTypeSignature(DataTypeSignature&) { } }; template class IntegerSpec<1, SignednessSigned, CastMode>; // Invalid instantiation template class IntegerSpec<0, Signedness, CastMode>; // Invalid instantiation template struct IsIntegerSpec { enum { Result = 0 }; }; template struct IsIntegerSpec > { enum { Result = 1 }; }; template class UAVCAN_EXPORT YamlStreamer > { typedef IntegerSpec RawType; typedef typename RawType::StorageType StorageType; public: template // cppcheck-suppress passedByValue static void stream(Stream& s, const StorageType value, int) { // Get rid of character types - we want its integer representation, not ASCII code typedef typename Select<(sizeof(StorageType) >= sizeof(int)), StorageType, typename Select::Result >::Result TempType; s << TempType(value); } }; } #endif // UAVCAN_MARSHAL_INTEGER_SPEC_HPP_INCLUDED