String-like behavior for arrays

This commit is contained in:
Pavel Kirienko
2014-03-06 16:39:12 +04:00
parent a2d786fe5c
commit 76cecca84a
3 changed files with 160 additions and 2 deletions
@@ -8,6 +8,7 @@
#include <algorithm>
#include <stdexcept>
#include <typeinfo>
#include <cstring>
#include <uavcan/internal/impl_constants.hpp>
#include <uavcan/internal/util.hpp>
#include <uavcan/internal/marshal/type_util.hpp>
@@ -113,7 +114,12 @@ class ArrayImpl : public StaticIf<ArrayMode == ArrayModeDynamic,
DynamicArrayBase<MaxSize>,
StaticArrayBase<MaxSize> >::Result Base;
typename StorageType<T>::Type data_[MaxSize];
public:
enum { IsStringLike = IsIntegerSpec<T>::Result && (T::MaxBitLen == 8 || T::MaxBitLen == 7) };
private:
typedef typename StorageType<T>::Type BufferType[MaxSize + (IsStringLike ? 1 : 0)];
BufferType data_;
template <typename U>
typename EnableIf<sizeof(U(0) == U())>::Type initialize(int) { std::fill(data_, data_ + MaxSize, U()); }
@@ -128,6 +134,14 @@ public:
ArrayImpl() { initialize<ValueType>(0); }
const char* c_str() const
{
StaticAssert<IsStringLike>::check();
assert(size() < (MaxSize + 1));
const_cast<BufferType&>(data_)[size()] = 0; // Ad-hoc string termination
return reinterpret_cast<const char*>(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<IntegerSpec<1, SignednessUnsigned, CastMode>, ArrayMode, MaxSize
StaticArrayBase<MaxSize> >::Result ArrayBase;
public:
enum { IsStringLike = 0 };
typedef typename std::bitset<MaxSize>::reference Reference;
typedef typename ArrayBase::SizeType SizeType;
@@ -328,8 +344,12 @@ public:
}
}
/*
* Comparison operators
*/
template <typename R>
bool operator==(const R& rhs) const
typename EnableIf<sizeof(((const R*)(0U))->size()) && 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 <typename R> bool operator!=(const R& rhs) const { return !operator==(rhs); }
/*
* Assign/append operators
*/
SelfType& operator=(const char* ch)
{
StaticAssert<Base::IsStringLike>::check();
StaticAssert<IsDynamic>::check();
Base::clear();
while (*ch)
push_back(*ch++);
return *this;
}
SelfType& operator+=(const char* ch)
{
StaticAssert<Base::IsStringLike>::check();
StaticAssert<IsDynamic>::check();
while (*ch)
push_back(*ch++);
return *this;
}
typedef ValueType value_type;
typedef SizeType size_type;
};
template <typename R, typename T, ArrayMode ArrayMode, unsigned int MaxSize>
inline bool operator==(const R& rhs, const Array<T, ArrayMode, MaxSize>& lhs)
{
return lhs.operator==(rhs);
}
template <typename R, typename T, ArrayMode ArrayMode, unsigned int MaxSize>
inline bool operator!=(const R& rhs, const Array<T, ArrayMode, MaxSize>& lhs)
{
return lhs.operator!=(rhs);
}
}
@@ -109,4 +109,11 @@ class IntegerSpec<1, SignednessSigned, CastMode>; // Invalid instantiation
template <Signedness Signedness, CastMode CastMode>
class IntegerSpec<0, Signedness, CastMode>; // Invalid instantiation
template <typename T>
struct IsIntegerSpec { enum { Result = 0 }; };
template <unsigned int BitLen, Signedness Signedness, CastMode CastMode>
struct IsIntegerSpec<IntegerSpec<BitLen, Signedness, CastMode> > { enum { Result = 1 }; };
}
+89
View File
@@ -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<IntegerSpec<1, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 5> OneBitArray;
typedef Array<IntegerSpec<8, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 255> EightBitArray;
typedef Array<OneBitArray, ArrayModeDynamic, 255> A;
typedef Array<EightBitArray, ArrayModeDynamic, 255> 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<IntegerSpec<8, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 32> A8;
typedef Array<IntegerSpec<7, SignednessUnsigned, CastModeSaturate>, 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());
}