mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-10-14 01:23:34 +08:00
CharArrayFormatter<> implementation and tests
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <uavcan/impl_constants.hpp>
|
||||
#include <uavcan/marshal/array.hpp>
|
||||
|
||||
#if !defined(UAVCAN_CPP_VERSION) || !defined(UAVCAN_CPP11)
|
||||
# error UAVCAN_CPP_VERSION
|
||||
#endif
|
||||
|
||||
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
|
||||
# include <type_traits>
|
||||
#endif
|
||||
|
||||
namespace uavcan
|
||||
{
|
||||
|
||||
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
|
||||
|
||||
template <typename ArrayType_>
|
||||
class CharArrayFormatter
|
||||
{
|
||||
ArrayType_& array_;
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_floating_point<T>::value>::type
|
||||
writeValue(T value)
|
||||
{
|
||||
array_.template appendFormatted<double>("%f", double(value));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_integral<T>::value>::type
|
||||
writeValue(T value)
|
||||
{
|
||||
if (std::is_same<T, char>())
|
||||
{
|
||||
array_.template appendFormatted("%c", value); // TODO: speedup
|
||||
}
|
||||
else if (std::is_signed<T>())
|
||||
{
|
||||
array_.template appendFormatted<long long>("%lli", static_cast<long long>(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
array_.template appendFormatted<unsigned long long>("%llu", static_cast<unsigned long long>(value));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_pointer<T>::value && !std::is_same<T, const char*>::value>::type
|
||||
writeValue(T value)
|
||||
{
|
||||
array_.template appendFormatted<const void*>("%p", static_cast<const void*>(value));
|
||||
}
|
||||
|
||||
void writeValue(const char* value)
|
||||
{
|
||||
array_.template appendFormatted<const char*>("%s", value);
|
||||
}
|
||||
|
||||
public:
|
||||
typedef ArrayType_ ArrayType;
|
||||
|
||||
CharArrayFormatter(ArrayType& array)
|
||||
: array_(array)
|
||||
{ }
|
||||
|
||||
ArrayType& getArray() { return array_; }
|
||||
const ArrayType& getArray() const { return array_; }
|
||||
|
||||
void write(const char* text)
|
||||
{
|
||||
writeValue(text);
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
void write(const char* s, T value, Args... args)
|
||||
{
|
||||
while (s && *s)
|
||||
{
|
||||
if (*s == '%' && *++s != '%')
|
||||
{
|
||||
writeValue(value);
|
||||
write(++s, args...);
|
||||
break;
|
||||
}
|
||||
writeValue(*s++);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
template <typename ArrayType_>
|
||||
class CharArrayFormatter
|
||||
{
|
||||
ArrayType_& array_;
|
||||
|
||||
public:
|
||||
typedef ArrayType_ ArrayType;
|
||||
|
||||
CharArrayFormatter(ArrayType& array)
|
||||
: array_(array)
|
||||
{ }
|
||||
|
||||
ArrayType& getArray() { return array_; }
|
||||
const ArrayType& getArray() const { return array_; }
|
||||
|
||||
void write(const char* const text)
|
||||
{
|
||||
array_.template appendFormatted<const char*>("%s", text);
|
||||
}
|
||||
|
||||
/**
|
||||
* This version does not support more than one formatted argument, though it can be improved.
|
||||
* And it is unsafe.
|
||||
* There is typesafe version for C++11 above.
|
||||
* TODO: make this version typesafe and add support for multiple args.
|
||||
*/
|
||||
template <typename A>
|
||||
void write(const char* const format, const A value)
|
||||
{
|
||||
array_.template appendFormatted<A>(format, value);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <uavcan/marshal/char_array_formatter.hpp>
|
||||
|
||||
using uavcan::Array;
|
||||
using uavcan::ArrayModeDynamic;
|
||||
using uavcan::ArrayModeStatic;
|
||||
using uavcan::IntegerSpec;
|
||||
using uavcan::SignednessSigned;
|
||||
using uavcan::SignednessUnsigned;
|
||||
using uavcan::CastModeSaturate;
|
||||
using uavcan::CastModeTruncate;
|
||||
using uavcan::CharArrayFormatter;
|
||||
|
||||
TEST(CharArrayFormatter, Basic)
|
||||
{
|
||||
typedef Array<IntegerSpec<8, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 45> A8;
|
||||
A8 a;
|
||||
|
||||
CharArrayFormatter<A8> f(a);
|
||||
ASSERT_STREQ("", f.getArray().c_str());
|
||||
|
||||
f.write("Don't %s.", "Panic");
|
||||
ASSERT_STREQ("Don't Panic.", f.getArray().c_str());
|
||||
|
||||
f.write(" abc%idef ", 123);
|
||||
ASSERT_STREQ("Don't Panic. abc123def ", f.getArray().c_str());
|
||||
|
||||
f.write("%f", 0.0);
|
||||
ASSERT_STREQ("Don't Panic. abc123def 0.000000", f.getArray().c_str());
|
||||
|
||||
a.clear();
|
||||
ASSERT_STREQ("", f.getArray().c_str());
|
||||
|
||||
f.write("123456789");
|
||||
ASSERT_STREQ("123456789", f.getArray().c_str());
|
||||
}
|
||||
|
||||
#if !defined(UAVCAN_CPP_VERSION) || !defined(UAVCAN_CPP11)
|
||||
# error UAVCAN_CPP_VERSION
|
||||
#endif
|
||||
|
||||
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
|
||||
|
||||
TEST(CharArrayFormatter, Hardcore)
|
||||
{
|
||||
typedef Array<IntegerSpec<8, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 150> A8;
|
||||
A8 a;
|
||||
|
||||
CharArrayFormatter<A8> f(a);
|
||||
|
||||
f.write("%% char='%*' double='%*' long='%*' unsigned long='%*' int='%s' long double='%*' bool='%*' const char='%*' %%",
|
||||
'%', -12.3456, -123456789123456789L, 987654321, -123456789, 0.000001L, true, "Don't Panic.");
|
||||
|
||||
static const std::string Reference =
|
||||
"% char='%' double='-12.345600' long='-123456789123456789' unsigned long='987654321' int='-123456789' "
|
||||
"long double='0.000001' bool='1' const char='Don't"; // 8 chars truncated!
|
||||
|
||||
ASSERT_STREQ(Reference.c_str(), f.getArray().c_str());
|
||||
|
||||
a.clear();
|
||||
|
||||
f.write("");
|
||||
ASSERT_STREQ("", f.getArray().c_str());
|
||||
|
||||
f.write("%%"); // Nothing to format --> "%%" is not expanded
|
||||
ASSERT_STREQ("%%", f.getArray().c_str());
|
||||
|
||||
f.write("%*", "Test", 123, true); // Extra args ignored
|
||||
ASSERT_STREQ("%%Test", f.getArray().c_str());
|
||||
|
||||
f.write("%% %* %* %% %*", true); // Insufficient args are OK; second "%%" is not expanded
|
||||
ASSERT_STREQ("%%Test% 1 %* %% %*", f.getArray().c_str());
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user