Add conveniently usable string builder
which allows fast string building without multiple heap allocations
This commit is contained in:
parent
f23c381da4
commit
a772cdf30b
|
@ -16,6 +16,7 @@ set(HEADER_FILES
|
|||
conversion/binaryconversionprivate.h
|
||||
conversion/conversionexception.h
|
||||
conversion/stringconversion.h
|
||||
conversion/stringbuilder.h
|
||||
conversion/types.h
|
||||
conversion/widen.h
|
||||
io/ansiescapecodes.h
|
||||
|
|
|
@ -11,6 +11,7 @@ The library utilizes:
|
|||
- split, join, find and replace
|
||||
- conversion from number to string and vice verca
|
||||
- encoding/decoding base-64
|
||||
- building string without multiple heap allocations (string builder)
|
||||
* IO
|
||||
- reading/writing primitive data types of various sizes (little-endian and big-endian)
|
||||
- reading/writing terminated strings and size-prefixed strings
|
||||
|
|
|
@ -0,0 +1,184 @@
|
|||
#ifndef CONVERSION_UTILITIES_STRINGBUILDER_H
|
||||
#define CONVERSION_UTILITIES_STRINGBUILDER_H
|
||||
|
||||
#include "../misc/traits.h"
|
||||
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace ConversionUtilities
|
||||
{
|
||||
|
||||
/// \cond
|
||||
namespace Helper {
|
||||
|
||||
template<class StringType, Traits::DisableIf<std::is_integral<StringType> > >
|
||||
std::size_t computeTupleElementSize(const StringType *str)
|
||||
{
|
||||
return str->size();
|
||||
}
|
||||
|
||||
template<class StringType>
|
||||
std::size_t computeTupleElementSize(const StringType &str)
|
||||
{
|
||||
return str.size();
|
||||
}
|
||||
|
||||
template<class CharType>
|
||||
std::size_t computeTupleElementSize(const CharType *str)
|
||||
{
|
||||
return std::char_traits<CharType>::length(str);
|
||||
}
|
||||
|
||||
template<class StringType>
|
||||
void append(StringType &target, const StringType *str)
|
||||
{
|
||||
target.append(*str);
|
||||
}
|
||||
|
||||
template<class StringType>
|
||||
void append(StringType &target, const StringType &str)
|
||||
{
|
||||
target.append(str);
|
||||
}
|
||||
|
||||
template<class StringType, class CharType>
|
||||
void append(StringType &target, const CharType *str)
|
||||
{
|
||||
target.append(str);
|
||||
}
|
||||
|
||||
template<class StringType, class Tuple, std::size_t N>
|
||||
struct TupleToString {
|
||||
static std::size_t precomputeSize(const Tuple &tuple)
|
||||
{
|
||||
return TupleToString<StringType, Tuple, N-1>::precomputeSize(tuple) + computeTupleElementSize(std::get<N-1>(tuple));
|
||||
}
|
||||
|
||||
static void append(const Tuple &tuple, StringType &str)
|
||||
{
|
||||
TupleToString<StringType, Tuple, N-1>::append(tuple, str);
|
||||
Helper::append(str, std::get<N-1>(tuple));
|
||||
}
|
||||
};
|
||||
|
||||
template<class StringType, class Tuple>
|
||||
struct TupleToString<StringType, Tuple, 1> {
|
||||
static std::size_t precomputeSize(const Tuple &tuple)
|
||||
{
|
||||
return computeTupleElementSize(std::get<0>(tuple));
|
||||
}
|
||||
|
||||
static void append(const Tuple &tuple, StringType &str)
|
||||
{
|
||||
Helper::append(str, std::get<0>(tuple));
|
||||
}
|
||||
};
|
||||
|
||||
template<class... Elements>
|
||||
class StringTuple : public std::tuple<Elements...>
|
||||
{
|
||||
public:
|
||||
StringTuple(Elements&&... elements) :
|
||||
std::tuple<Elements...>(elements...)
|
||||
{}
|
||||
|
||||
|
||||
};
|
||||
|
||||
template<class... Elements>
|
||||
constexpr auto makeStringTuple(Elements&&... elements) -> decltype(StringTuple<Elements...>(elements...))
|
||||
{
|
||||
return StringTuple<Elements...>(elements...);
|
||||
}
|
||||
|
||||
}
|
||||
/// \endcond
|
||||
|
||||
/*!
|
||||
* \brief Concatenates all strings hold by the specified \a tuple.
|
||||
*/
|
||||
template<class StringType = std::string, class... Args>
|
||||
StringType tupleToString(const std::tuple<Args...> &tuple)
|
||||
{
|
||||
StringType res;
|
||||
res.reserve(Helper::TupleToString<StringType, decltype(tuple), sizeof...(Args)>::precomputeSize(tuple));
|
||||
Helper::TupleToString<StringType, decltype(tuple), sizeof...(Args)>::append(tuple, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Allows construction of string-tuples via %-operator, eg. string1 % "string2" % string3.
|
||||
*/
|
||||
template<class Tuple>
|
||||
constexpr auto operator %(const Tuple &lhs, const std::string &rhs) -> decltype(std::tuple_cat(lhs, std::make_tuple(&rhs)))
|
||||
{
|
||||
return std::tuple_cat(lhs, std::make_tuple(&rhs));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Allows construction of string-tuples via %-operator, eg. string1 % "string2" % string3.
|
||||
*/
|
||||
template<class Tuple>
|
||||
constexpr auto operator %(const Tuple &lhs, const char *rhs) -> decltype(std::tuple_cat(lhs, std::make_tuple(rhs)))
|
||||
{
|
||||
return std::tuple_cat(lhs, std::make_tuple(rhs));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Allows construction of string-tuples via %-operator, eg. string1 % "string2" % string3.
|
||||
*/
|
||||
constexpr auto operator %(const std::string &lhs, const std::string &rhs) -> decltype(std::make_tuple(&lhs, &rhs))
|
||||
{
|
||||
return std::make_tuple(&lhs, &rhs);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Allows construction of string-tuples via %-operator, eg. string1 % "string2" % string3.
|
||||
*/
|
||||
constexpr auto operator %(const char *lhs, const std::string &rhs) -> decltype(std::make_tuple(lhs, &rhs))
|
||||
{
|
||||
return std::make_tuple(lhs, &rhs);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Allows construction of string-tuples via %-operator, eg. string1 % "string2" % string3.
|
||||
*/
|
||||
constexpr auto operator %(const std::string &lhs, const char *rhs) -> decltype(std::make_tuple(&lhs, rhs))
|
||||
{
|
||||
return std::make_tuple(&lhs, rhs);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Allows construction of final string from previously constructed string-tuple and trailing string via +-operator.
|
||||
*
|
||||
* This is meant to be used for fast string building without multiple heap allocation, eg.
|
||||
*
|
||||
* ```
|
||||
* printVelocity("velocity: " % numberToString(velocityExample) % " km/h (" % numberToString(velocityExample / 3.6) + " m/s)"));
|
||||
* ```
|
||||
*/
|
||||
template<class Tuple>
|
||||
inline std::string operator +(const Tuple &lhs, const std::string &rhs)
|
||||
{
|
||||
return tupleToString(std::tuple_cat(lhs, std::make_tuple(&rhs)));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Allows construction of final string from previously constructed string-tuple and trailing string via +-operator.
|
||||
*
|
||||
* This is meant to be used for fast string building without multiple heap allocation, eg.
|
||||
*
|
||||
* ```
|
||||
* printVelocity("velocity: " % numberToString(velocityExample) % " km/h (" % numberToString(velocityExample / 3.6) + " m/s)"));
|
||||
* ```
|
||||
*/
|
||||
template<class Tuple>
|
||||
inline std::string operator +(const Tuple &lhs, const char *rhs)
|
||||
{
|
||||
return tupleToString(std::tuple_cat(lhs, std::make_tuple(rhs)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // CONVERSION_UTILITIES_STRINGBUILDER_H
|
|
@ -1,5 +1,6 @@
|
|||
#include "../conversion/binaryconversion.h"
|
||||
#include "../conversion/stringconversion.h"
|
||||
#include "../conversion/stringbuilder.h"
|
||||
#include "../tests/testutils.h"
|
||||
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
|
@ -27,6 +28,7 @@ class ConversionTests : public TestFixture
|
|||
CPPUNIT_TEST(testSwapOrderFunctions);
|
||||
CPPUNIT_TEST(testStringEncodingConversions);
|
||||
CPPUNIT_TEST(testStringConversions);
|
||||
CPPUNIT_TEST(testStringBuilder);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
|
@ -40,6 +42,7 @@ public:
|
|||
void testSwapOrderFunctions();
|
||||
void testStringEncodingConversions();
|
||||
void testStringConversions();
|
||||
void testStringBuilder();
|
||||
|
||||
private:
|
||||
template<typename intType>
|
||||
|
@ -295,3 +298,18 @@ void ConversionTests::testStringConversions()
|
|||
CPPUNIT_ASSERT(decodedBase64Data.first[i] == originalBase64Data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
string functionTakingString(const string &str)
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
||||
void ConversionTests::testStringBuilder()
|
||||
{
|
||||
const tuple<const char *, string, const char *> tuple("string1", "string2", "string3");
|
||||
CPPUNIT_ASSERT_EQUAL(string("string1string2string3"), tupleToString(tuple));
|
||||
CPPUNIT_ASSERT_EQUAL(string("foobarfoo2bar2"), tupleToString(string("foo") % "bar" % string("foo2") % "bar2"));
|
||||
CPPUNIT_ASSERT_EQUAL(string("123456"), functionTakingString("12" % string("34") + "56"));
|
||||
constexpr double velocityExample = 27.0;
|
||||
CPPUNIT_ASSERT_EQUAL(string("velocity: 27 km/h (7.5 m/s)"), functionTakingString("velocity: " % numberToString(velocityExample) % " km/h (" % numberToString(velocityExample / 3.6) + " m/s)"));
|
||||
}
|
||||
|
|
|
@ -148,7 +148,8 @@ template <typename T> AsHexNumber<T> asHexNumber(const T &value)
|
|||
* \brief Asserts successful execution of application via TestApplication::execApp(). Output is stored in stdout and stderr.
|
||||
* \remarks Requires cppunit.
|
||||
*/
|
||||
# define TESTUTILS_ASSERT_EXEC(args) CPPUNIT_ASSERT_EQUAL(0, execApp(args, stdout, stderr))
|
||||
# define TESTUTILS_ASSERT_EXEC(args) \
|
||||
CPPUNIT_ASSERT_EQUAL(0, execApp(args, stdout, stderr))
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue