libuav original

Dependents:   UAVCAN UAVCAN_Subscriber

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers integer_spec.hpp Source File

integer_spec.hpp

00001 /*
00002  * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
00003  */
00004 
00005 #ifndef UAVCAN_MARSHAL_INTEGER_SPEC_HPP_INCLUDED
00006 #define UAVCAN_MARSHAL_INTEGER_SPEC_HPP_INCLUDED
00007 
00008 #include <uavcan/std.hpp>
00009 #include <uavcan/data_type.hpp>
00010 #include <uavcan/util/templates.hpp>
00011 #include <uavcan/marshal/scalar_codec.hpp>
00012 #include <uavcan/marshal/type_util.hpp>
00013 
00014 namespace uavcan
00015 {
00016 
00017 enum Signedness { SignednessUnsigned, SignednessSigned };
00018 
00019 /**
00020  * This template will be used for signed and unsigned integers more than 1 bit long.
00021  * There are explicit specializations for booleans below.
00022  */
00023 template <unsigned BitLen_, Signedness Signedness, CastMode CastMode>
00024 class UAVCAN_EXPORT IntegerSpec
00025 {
00026     struct ErrorNoSuchInteger;
00027 
00028 public:
00029     enum { IsSigned = Signedness == SignednessSigned };
00030     enum { BitLen = BitLen_ };
00031     enum { MinBitLen = BitLen };
00032     enum { MaxBitLen = BitLen };
00033     enum { IsPrimitive = 1 };
00034 
00035     typedef typename Select<(BitLen <= 8),  typename Select<IsSigned, int8_t,  uint8_t>::Result,
00036             typename Select<(BitLen <= 16), typename Select<IsSigned, int16_t, uint16_t>::Result,
00037             typename Select<(BitLen <= 32), typename Select<IsSigned, int32_t, uint32_t>::Result,
00038             typename Select<(BitLen <= 64), typename Select<IsSigned, int64_t, uint64_t>::Result,
00039                               ErrorNoSuchInteger>::Result>::Result>::Result>::Result StorageType;
00040 
00041     typedef typename IntegerSpec<BitLen, SignednessUnsigned, CastMode>::StorageType UnsignedStorageType;
00042 
00043 private:
00044     IntegerSpec();
00045 
00046     struct LimitsImplGeneric
00047     {
00048         static StorageType max()
00049         {
00050             StaticAssert<(sizeof(uintmax_t) >= 8)>::check();
00051             if (IsSigned == 0)
00052             {
00053                 return StorageType((uintmax_t(1) << static_cast<unsigned>(BitLen)) - 1U);
00054             }
00055             else
00056             {
00057                 return StorageType((uintmax_t(1) << (static_cast<unsigned>(BitLen) - 1U)) - 1);
00058             }
00059         }
00060         static UnsignedStorageType mask()
00061         {
00062             StaticAssert<(sizeof(uintmax_t) >= 8U)>::check();
00063             return UnsignedStorageType((uintmax_t(1) << static_cast<unsigned>(BitLen)) - 1U);
00064         }
00065     };
00066 
00067     struct LimitsImpl64
00068     {
00069         static StorageType max()
00070         {
00071             return StorageType((IsSigned == 0) ? 0xFFFFFFFFFFFFFFFFULL : 0x7FFFFFFFFFFFFFFFLL);
00072         }
00073         static UnsignedStorageType mask() { return 0xFFFFFFFFFFFFFFFFULL; }
00074     };
00075 
00076     typedef typename Select<(BitLen == 64), LimitsImpl64, LimitsImplGeneric>::Result Limits;
00077 
00078     static void saturate(StorageType& value)
00079     {
00080         if (value > max())
00081         {
00082             value = max();
00083         }
00084         else if (value <= min()) // 'Less or Equal' allows to suppress compiler warning on unsigned types
00085         {
00086             value = min();
00087         }
00088         else
00089         {
00090             ; // Valid range
00091         }
00092     }
00093 
00094     static void truncate(StorageType& value) { value = value & StorageType(mask()); }
00095 
00096     static void validate()
00097     {
00098         StaticAssert<(BitLen <= (sizeof(StorageType) * 8))>::check();
00099         // coverity[result_independent_of_operands : FALSE]
00100         UAVCAN_ASSERT(max() <= NumericTraits<StorageType>::max());
00101         // coverity[result_independent_of_operands : FALSE]
00102         UAVCAN_ASSERT(min() >= NumericTraits<StorageType>::min());
00103     }
00104 
00105 public:
00106     static StorageType max() { return Limits::max(); }
00107     static StorageType min() { return IsSigned ? StorageType(-max() - 1) : 0; }
00108     static UnsignedStorageType mask() { return Limits::mask(); }
00109 
00110     static int encode(StorageType value, ScalarCodec& codec, TailArrayOptimizationMode)
00111     {
00112         validate();
00113         // cppcheck-suppress duplicateExpression
00114         if (CastMode == CastModeSaturate)
00115         {
00116             saturate(value);
00117         }
00118         else
00119         {
00120             truncate(value);
00121         }
00122         return codec.encode<BitLen>(value);
00123     }
00124 
00125     static int decode(StorageType& out_value, ScalarCodec& codec, TailArrayOptimizationMode)
00126     {
00127         validate();
00128         return codec.decode<BitLen>(out_value);
00129     }
00130 
00131     static void extendDataTypeSignature(DataTypeSignature&) { }
00132 };
00133 
00134 /**
00135  * Boolean specialization
00136  */
00137 template <CastMode CastMode>
00138 class UAVCAN_EXPORT IntegerSpec<1, SignednessUnsigned, CastMode>
00139 {
00140 public:
00141     enum { IsSigned = 0 };
00142     enum { BitLen = 1 };
00143     enum { MinBitLen = 1 };
00144     enum { MaxBitLen = 1 };
00145     enum { IsPrimitive = 1 };
00146 
00147     typedef bool StorageType;
00148     typedef bool UnsignedStorageType;
00149 
00150 private:
00151     IntegerSpec();
00152 
00153 public:
00154     static StorageType max() { return true; }
00155     static StorageType min() { return false; }
00156     static UnsignedStorageType mask() { return true; }
00157 
00158     static int encode(StorageType value, ScalarCodec& codec, TailArrayOptimizationMode)
00159     {
00160         return codec.encode<BitLen>(value);
00161     }
00162 
00163     static int decode(StorageType& out_value, ScalarCodec& codec, TailArrayOptimizationMode)
00164     {
00165         return codec.decode<BitLen>(out_value);
00166     }
00167 
00168     static void extendDataTypeSignature(DataTypeSignature&) { }
00169 };
00170 
00171 template <CastMode CastMode>
00172 class IntegerSpec<1, SignednessSigned, CastMode>;   // Invalid instantiation
00173 
00174 template <Signedness Signedness, CastMode CastMode>
00175 class IntegerSpec<0, Signedness, CastMode>;         // Invalid instantiation
00176 
00177 
00178 template <typename T>
00179 struct IsIntegerSpec
00180 {
00181     enum { Result = 0 };
00182 };
00183 
00184 template <unsigned BitLen, Signedness Signedness, CastMode CastMode>
00185 struct IsIntegerSpec<IntegerSpec<BitLen, Signedness, CastMode> >
00186 {
00187     enum { Result = 1 };
00188 };
00189 
00190 
00191 template <unsigned BitLen, Signedness Signedness, CastMode CastMode>
00192 class UAVCAN_EXPORT YamlStreamer<IntegerSpec<BitLen, Signedness, CastMode> >
00193 {
00194     typedef IntegerSpec<BitLen, Signedness, CastMode> RawType;
00195     typedef typename RawType::StorageType StorageType;
00196 
00197 public:
00198     template <typename Stream>  // cppcheck-suppress passedByValue
00199     static void stream(Stream& s, const StorageType value, int)
00200     {
00201         // Get rid of character types - we want its integer representation, not ASCII code
00202         typedef typename Select<(sizeof(StorageType) >= sizeof(int)), StorageType,
00203                                 typename Select<RawType::IsSigned, int, unsigned>::Result >::Result TempType;
00204         s << TempType(value);
00205     }
00206 };
00207 
00208 }
00209 
00210 #endif // UAVCAN_MARSHAL_INTEGER_SPEC_HPP_INCLUDED