diff --git a/libuavcan/include/uavcan/internal/marshalling/integer_spec.hpp b/libuavcan/include/uavcan/internal/marshalling/integer_spec.hpp index 505394db0d..00376fe643 100644 --- a/libuavcan/include/uavcan/internal/marshalling/integer_spec.hpp +++ b/libuavcan/include/uavcan/internal/marshalling/integer_spec.hpp @@ -33,31 +33,32 @@ public: typename StaticIf<(BitLen <= 64), typename StaticIf::Result, ErrorNoSuchInteger>::Result>::Result>::Result>::Result StorageType; -private: typedef typename IntegerSpec::StorageType UnsignedStorageType; +private: IntegerSpec(); - struct ExactSizeLimits - { - static StorageType max() { return std::numeric_limits::max(); } - static StorageType min() { return std::numeric_limits::min(); } - static UnsignedStorageType mask() { return ~UnsignedStorageType(0); } - }; - - struct NonExactSizeLimits + struct LimitsImplGeneric { static StorageType max() { - return IsSigned ? ((StorageType(1) << (BitLen - 1)) - 1) : ((StorageType(1) << BitLen) - 1); + StaticAssert<(sizeof(uintmax_t) >= 8)>::check(); + return StorageType(IsSigned ? ((uintmax_t(1) << (BitLen - 1)) - 1) : ((uintmax_t(1) << BitLen) - 1)); + } + static UnsignedStorageType mask() + { + StaticAssert<(sizeof(uintmax_t) >= 8)>::check(); + return UnsignedStorageType((uintmax_t(1) << BitLen) - 1); } - static StorageType min() { return IsSigned ? -(StorageType(1) << (BitLen - 1)) : 0; } - static UnsignedStorageType mask() { return (UnsignedStorageType(1) << BitLen) - 1; } }; - enum { IsExactSize = (BitLen == 8) || (BitLen == 16) || (BitLen == 32) || (BitLen == 64) }; + struct LimitsImpl64 + { + static StorageType max() { return StorageType(IsSigned ? 0x7FFFFFFFFFFFFFFF : 0xFFFFFFFFFFFFFFFF); } + static UnsignedStorageType mask() { return 0xFFFFFFFFFFFFFFFF; } + }; - typedef typename StaticIf::Result Limits; + typedef typename StaticIf<(BitLen == 64), LimitsImpl64, LimitsImplGeneric>::Result Limits; static void saturate(StorageType& value) { @@ -67,20 +68,23 @@ private: value = min(); } - static void truncate(StorageType& value) + static void truncate(StorageType& value) { value &= mask(); } + + static void validate() { - // cppcheck-suppress duplicateExpression - value &= Limits::mask(); + StaticAssert<(BitLen <= (sizeof(StorageType) * 8))>::check(); + assert(max() <= std::numeric_limits::max()); + assert(min() >= std::numeric_limits::min()); } public: - // cppcheck-suppress duplicateExpression static StorageType max() { return Limits::max(); } - // cppcheck-suppress duplicateExpression - static StorageType min() { return Limits::min(); } + 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); @@ -91,6 +95,7 @@ public: static int decode(StorageType& out_value, ScalarCodec& codec, TailArrayOptimizationMode) { + validate(); return codec.decode(out_value); } }; @@ -98,4 +103,7 @@ public: template class IntegerSpec<1, SignednessSigned, CastMode>; // Invalid instantiation +template +class IntegerSpec<0, Signedness, CastMode>; // Invalid instantiation + }