From 0e28a0826cfc32bad16d8b121b5bb52374faba86 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Fri, 21 Feb 2014 22:03:17 +0400 Subject: [PATCH] IntegerInfo --- .../uavcan/internal/marshalling/integer.hpp | 103 +++++++++++++++++ .../uavcan/internal/marshalling/types.hpp | 24 ++++ libuavcan/test/marshalling/integer.cpp | 109 ++++++++++++++++++ 3 files changed, 236 insertions(+) create mode 100644 libuavcan/include/uavcan/internal/marshalling/integer.hpp create mode 100644 libuavcan/include/uavcan/internal/marshalling/types.hpp create mode 100644 libuavcan/test/marshalling/integer.cpp diff --git a/libuavcan/include/uavcan/internal/marshalling/integer.hpp b/libuavcan/include/uavcan/internal/marshalling/integer.hpp new file mode 100644 index 0000000000..fe168ab2a8 --- /dev/null +++ b/libuavcan/include/uavcan/internal/marshalling/integer.hpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2014 Pavel Kirienko + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace uavcan +{ + +enum Signedness { SignednessUnsigned, SignednessSigned }; + +template +class IntegerInfo +{ + enum { IsSigned = Signedness == SignednessSigned }; + + struct ErrorNoSuchInteger; + +public: + enum { BitLen = BitLen_ }; + + 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; + +private: + typedef typename IntegerInfo::StorageType UnsignedStorageType; + + IntegerInfo() { } + + 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 + { + static StorageType max() + { + return IsSigned ? ((StorageType(1) << (BitLen - 1)) - 1) : ((StorageType(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) }; + + typedef typename StaticIf::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) + { + // cppcheck-suppress duplicateExpression + value &= Limits::mask(); + } + +public: + // cppcheck-suppress duplicateExpression + static StorageType max() { return Limits::max(); } + // cppcheck-suppress duplicateExpression + static StorageType min() { return Limits::min(); } + + static StorageType init() { return 0; } + + static int encode(StorageType value, ScalarCodec& codec, bool enable_tail_array_optimization = false) + { + (void)enable_tail_array_optimization; + // cppcheck-suppress duplicateExpression + if (CastMode == CastModeSaturate) + saturate(value); + else + truncate(value); + return codec.encode(value); + } + + static int decode(StorageType& out_value, ScalarCodec& codec, bool enable_tail_array_optimization = false) + { + (void)enable_tail_array_optimization; + return codec.decode(out_value); + } +}; + +template +class IntegerInfo<1, SignednessSigned, CastMode>; // Invalid instantiation + +} diff --git a/libuavcan/include/uavcan/internal/marshalling/types.hpp b/libuavcan/include/uavcan/internal/marshalling/types.hpp new file mode 100644 index 0000000000..0d172f8a14 --- /dev/null +++ b/libuavcan/include/uavcan/internal/marshalling/types.hpp @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2014 Pavel Kirienko + */ + +#pragma once + +#include +#include + +namespace uavcan +{ + +enum CastMode { CastModeSaturate, CastModeTruncate }; + +template +struct AddStorageTypeImpl { typedef T StorageType; }; + +template +struct AddStorageTypeImpl::Type> { }; + +template +struct AddStorageType : public T, public AddStorageTypeImpl { }; + +} diff --git a/libuavcan/test/marshalling/integer.cpp b/libuavcan/test/marshalling/integer.cpp new file mode 100644 index 0000000000..9cf9133a61 --- /dev/null +++ b/libuavcan/test/marshalling/integer.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2014 Pavel Kirienko + */ + +#include +#include + + +TEST(Integer, Limits) +{ + using uavcan::IntegerInfo; + using uavcan::SignednessSigned; + using uavcan::SignednessUnsigned; + using uavcan::CastModeSaturate; + using uavcan::CastModeTruncate; + + typedef IntegerInfo<8, SignednessUnsigned, CastModeSaturate> UInt8; + typedef IntegerInfo<4, SignednessSigned, CastModeTruncate> SInt4; + typedef IntegerInfo<32, SignednessUnsigned, CastModeTruncate> UInt32; + typedef IntegerInfo<40, SignednessUnsigned, CastModeSaturate> UInt40; + typedef IntegerInfo<64, SignednessUnsigned, CastModeTruncate> UInt64; + typedef IntegerInfo<64, SignednessSigned, CastModeSaturate> SInt64; + typedef IntegerInfo<63, SignednessUnsigned, CastModeSaturate> UInt63; + + ASSERT_EQ(255, UInt8::max()); + ASSERT_EQ(0, UInt8::min()); + + ASSERT_EQ(7, SInt4::max()); + ASSERT_EQ(-8, SInt4::min()); + + ASSERT_EQ(0xFFFFFFFF, UInt32::max()); + ASSERT_EQ(0, UInt32::min()); + + ASSERT_EQ(0xFFFFFFFFFF, UInt40::max()); + ASSERT_EQ(0, UInt40::min()); + + ASSERT_EQ(0xFFFFFFFFFFFFFFFF, UInt64::max()); + ASSERT_EQ(0, UInt64::min()); + + ASSERT_EQ(0x7FFFFFFFFFFFFFFF, SInt64::max()); + ASSERT_EQ(-0x8000000000000000, SInt64::min()); + + ASSERT_EQ(0x7FFFFFFFFFFFFFFF, UInt63::max()); + ASSERT_EQ(0, UInt63::min()); + + ASSERT_EQ(SInt64::max(), UInt63::max()); +} + + +TEST(Integer, Basic) +{ + using uavcan::IntegerInfo; + using uavcan::SignednessSigned; + using uavcan::SignednessUnsigned; + using uavcan::CastModeSaturate; + using uavcan::CastModeTruncate; + using uavcan::AddStorageType; + + uavcan::StaticTransferBuffer<100> buf; + uavcan::BitStream bs_wr(buf); + uavcan::ScalarCodec sc_wr(bs_wr); + + typedef AddStorageType > UInt8S; + typedef AddStorageType > SInt4T; + typedef AddStorageType > UInt32T; + typedef AddStorageType > UInt40S; + typedef AddStorageType > UInt64T; + typedef AddStorageType > SInt58S; + typedef AddStorageType > UInt63S; + typedef AddStorageType > SInt10S; + typedef AddStorageType > UInt1S; + + ASSERT_EQ(1, UInt8S::encode(UInt8S::StorageType(123), sc_wr)); + ASSERT_EQ(1, SInt4T::encode(SInt4T::StorageType(-0x44), sc_wr)); + ASSERT_EQ(1, UInt32T::encode(UInt32T::StorageType(0xFFFFFFFF), sc_wr)); + ASSERT_EQ(1, UInt40S::encode(UInt40S::StorageType(0xFFFFFFFFFFFFFFFF), sc_wr)); + ASSERT_EQ(1, UInt64T::encode(UInt64T::StorageType(0xFFFFFFFFFFFFFFFF), sc_wr)); + ASSERT_EQ(1, SInt58S::encode(SInt58S::StorageType(0xFFFFFFFFFFFFFFF), sc_wr)); + ASSERT_EQ(1, UInt63S::encode(UInt63S::StorageType(0xFFFFFFFFFFFFFFFF), sc_wr)); + ASSERT_EQ(1, SInt10S::encode(SInt10S::StorageType(-30000), sc_wr)); + ASSERT_EQ(1, UInt1S::encode(UInt1S::StorageType(42), sc_wr)); + + std::cout << bs_wr.toString() << std::endl; + + uavcan::BitStream bs_rd(buf); + uavcan::ScalarCodec sc_rd(bs_rd); + +#define CHECK(Type, expected_value) \ + do { \ + Type::StorageType var(Type::init()); \ + ASSERT_EQ(1, Type::decode(var, sc_rd)); \ + ASSERT_EQ(expected_value, var); \ + } while (0) + + CHECK(UInt8S, 123); + CHECK(SInt4T, -4); + CHECK(UInt32T, 0xFFFFFFFF); + CHECK(UInt40S, 0xFFFFFFFFFF); + CHECK(UInt64T, 0xFFFFFFFFFFFFFFFF); + CHECK(SInt58S, 0x1FFFFFFFFFFFFFF); + CHECK(UInt63S, 0x7FFFFFFFFFFFFFFF); + CHECK(SInt10S, -512); + CHECK(UInt1S, 1); + +#undef CHECK + + UInt1S::StorageType var; + ASSERT_EQ(0, UInt1S::decode(var, sc_rd)); +}