/* * Copyright (C) 2014 Pavel Kirienko */ #pragma once #include #include #include #include #include #include namespace uavcan { enum Signedness { SignednessUnsigned, SignednessSigned }; template class IntegerSpec { struct ErrorNoSuchInteger; public: enum { IsSigned = Signedness == SignednessSigned }; enum { BitLen = BitLen_ }; enum { MinBitLen = BitLen }; enum { MaxBitLen = BitLen }; enum { IsPrimitive = 1 }; typedef typename StaticIf<(BitLen <= 8), typename StaticIf::Result, typename StaticIf<(BitLen <= 16), typename StaticIf::Result, typename StaticIf<(BitLen <= 32), typename StaticIf::Result, typename StaticIf<(BitLen <= 64), typename StaticIf::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(); 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); } }; struct LimitsImpl64 { static StorageType max() { return StorageType(IsSigned ? 0x7FFFFFFFFFFFFFFF : 0xFFFFFFFFFFFFFFFF); } static UnsignedStorageType mask() { return 0xFFFFFFFFFFFFFFFF; } }; typedef typename StaticIf<(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(); } static void truncate(StorageType& value) { value &= mask(); } static void validate() { StaticAssert<(BitLen <= (sizeof(StorageType) * 8))>::check(); assert(max() <= std::numeric_limits::max()); assert(min() >= std::numeric_limits::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 struct YamlStreamer > { typedef IntegerSpec RawType; typedef typename RawType::StorageType StorageType; template static void stream(Stream& s, const StorageType value, int) { // Get rid of character types - we want its integer representation, not ASCII code typedef typename StaticIf<(sizeof(StorageType) >= sizeof(int)), StorageType, typename StaticIf::Result >::Result TempType; s << TempType(value); } }; }