From 76cecca84a72739565580a8bae4fa62d7c436c7d Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Thu, 6 Mar 2014 16:39:12 +0400 Subject: [PATCH] String-like behavior for arrays --- .../include/uavcan/internal/marshal/array.hpp | 66 +++++++++++++- .../uavcan/internal/marshal/integer_spec.hpp | 7 ++ libuavcan/test/marshal/array.cpp | 89 +++++++++++++++++++ 3 files changed, 160 insertions(+), 2 deletions(-) diff --git a/libuavcan/include/uavcan/internal/marshal/array.hpp b/libuavcan/include/uavcan/internal/marshal/array.hpp index 57c6981d18..5fdfd6bb53 100644 --- a/libuavcan/include/uavcan/internal/marshal/array.hpp +++ b/libuavcan/include/uavcan/internal/marshal/array.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -113,7 +114,12 @@ class ArrayImpl : public StaticIf, StaticArrayBase >::Result Base; - typename StorageType::Type data_[MaxSize]; +public: + enum { IsStringLike = IsIntegerSpec::Result && (T::MaxBitLen == 8 || T::MaxBitLen == 7) }; + +private: + typedef typename StorageType::Type BufferType[MaxSize + (IsStringLike ? 1 : 0)]; + BufferType data_; template typename EnableIf::Type initialize(int) { std::fill(data_, data_ + MaxSize, U()); } @@ -128,6 +134,14 @@ public: ArrayImpl() { initialize(0); } + const char* c_str() const + { + StaticAssert::check(); + assert(size() < (MaxSize + 1)); + const_cast(data_)[size()] = 0; // Ad-hoc string termination + return reinterpret_cast(data_); + } + ValueType& at(SizeType pos) { return data_[validateRange(pos)]; } const ValueType& at(SizeType pos) const { return data_[Base::validateRange(pos)]; } @@ -167,6 +181,8 @@ class ArrayImpl, ArrayMode, MaxSize StaticArrayBase >::Result ArrayBase; public: + enum { IsStringLike = 0 }; + typedef typename std::bitset::reference Reference; typedef typename ArrayBase::SizeType SizeType; @@ -328,8 +344,12 @@ public: } } + /* + * Comparison operators + */ template - bool operator==(const R& rhs) const + typename EnableIfsize()) && sizeof((*((const R*)(0U)))[0]), bool>::Type + operator==(const R& rhs) const { if (size() != rhs.size()) return false; @@ -338,10 +358,52 @@ public: return false; return true; } + + bool operator==(const char* ch) const + { + if (ch == NULL) + return false; + return std::strcmp(Base::c_str(), ch) == 0; + } + template bool operator!=(const R& rhs) const { return !operator==(rhs); } + /* + * Assign/append operators + */ + SelfType& operator=(const char* ch) + { + StaticAssert::check(); + StaticAssert::check(); + Base::clear(); + while (*ch) + push_back(*ch++); + return *this; + } + + SelfType& operator+=(const char* ch) + { + StaticAssert::check(); + StaticAssert::check(); + while (*ch) + push_back(*ch++); + return *this; + } + typedef ValueType value_type; typedef SizeType size_type; }; +template +inline bool operator==(const R& rhs, const Array& lhs) +{ + return lhs.operator==(rhs); +} + +template +inline bool operator!=(const R& rhs, const Array& lhs) +{ + return lhs.operator!=(rhs); +} + } diff --git a/libuavcan/include/uavcan/internal/marshal/integer_spec.hpp b/libuavcan/include/uavcan/internal/marshal/integer_spec.hpp index 817ca3b840..b79f94735e 100644 --- a/libuavcan/include/uavcan/internal/marshal/integer_spec.hpp +++ b/libuavcan/include/uavcan/internal/marshal/integer_spec.hpp @@ -109,4 +109,11 @@ 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 }; }; + } diff --git a/libuavcan/test/marshal/array.cpp b/libuavcan/test/marshal/array.cpp index 799372f6ac..ab8a4d9ae4 100644 --- a/libuavcan/test/marshal/array.cpp +++ b/libuavcan/test/marshal/array.cpp @@ -208,6 +208,8 @@ TEST(Array, Basic) ASSERT_TRUE(a1 == v1); ASSERT_FALSE(a1 != v1); + ASSERT_TRUE(v1 == a1); + ASSERT_FALSE(v1 != a1); ASSERT_FALSE(a1 < v1); v1[0] = 9000; @@ -621,3 +623,90 @@ TEST(Array, StaticEncodeDecodeErrors) ASSERT_EQ(0, A::decode(a, sc_rd, uavcan::TailArrayOptEnabled)); } } + + +TEST(Array, Copyability) +{ + typedef Array, ArrayModeDynamic, 5> OneBitArray; + typedef Array, ArrayModeDynamic, 255> EightBitArray; + typedef Array A; + typedef Array B; + typedef EightBitArray C; + + A a; + B b; + C c; + + A a2 = a; + B b2 = b; + C c2 = c; + + ASSERT_TRUE(a == a2); + ASSERT_TRUE(b == b2); + ASSERT_TRUE(c == c2); + + a.push_back(OneBitArray()); + b.push_back(EightBitArray()); + c.push_back(42); + + ASSERT_TRUE(a != a2); + ASSERT_TRUE(b != b2); + ASSERT_TRUE(c != c2); + + a2 = a; + b2 = b; + c2 = c; + + ASSERT_TRUE(a2 == a); + ASSERT_TRUE(b2 == b); + ASSERT_TRUE(c2 == c); +} + + +TEST(Array, Strings) +{ + typedef Array, ArrayModeDynamic, 32> A8; + typedef Array, ArrayModeDynamic, 32> A7; + + A8 a8; + A8 a8_2; + A7 a7; + + ASSERT_TRUE(a8 == a7); + // cppcheck-suppress duplicateExpression + ASSERT_TRUE(a8 == a8); + // cppcheck-suppress duplicateExpression + ASSERT_TRUE(a7 == a7); + ASSERT_TRUE(a8 == ""); + ASSERT_TRUE(a7 == ""); + + a8 = "Hello world!"; + a7 = "123"; + ASSERT_TRUE(a8 == "Hello world!"); + ASSERT_TRUE(a7 == "123"); + + a8 = "Our sun is dying."; + a7 = "456"; + ASSERT_TRUE("Our sun is dying." == a8); + ASSERT_TRUE("456" == a7); + + a8 += " 123456"; + a8 += "-789"; + ASSERT_TRUE("Our sun is dying. 123456-789" == a8); + + ASSERT_TRUE(a8_2 == ""); + ASSERT_TRUE(a8_2.empty()); + ASSERT_TRUE(a8_2 != a8); + a8_2 = a8; + ASSERT_TRUE(a8_2 == "Our sun is dying. 123456-789"); + ASSERT_TRUE(a8_2 == a8); + + /* + * c_str() + */ + ASSERT_STREQ("", A8().c_str()); + ASSERT_STREQ("", A7().c_str()); + ASSERT_STREQ("Our sun is dying. 123456-789", a8_2.c_str()); + ASSERT_STREQ("Our sun is dying. 123456-789", a8.c_str()); + ASSERT_STREQ("456", a7.c_str()); +}