Merge pull request #8693 from Icinga/bugfix/stringbuilder-malloc

PackObject(): avoid one malloc()
This commit is contained in:
Julian Brost 2021-03-25 18:02:12 +01:00 committed by GitHub
commit 8813b74c9f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 20 additions and 94 deletions

View File

@ -70,7 +70,6 @@ set(base_SOURCES
stream.cpp stream.hpp stream.cpp stream.hpp
streamlogger.cpp streamlogger.hpp streamlogger-ti.hpp streamlogger.cpp streamlogger.hpp streamlogger-ti.hpp
string.cpp string.hpp string-script.cpp string.cpp string.hpp string-script.cpp
stringbuilder.cpp stringbuilder.hpp
sysloglogger.cpp sysloglogger.hpp sysloglogger-ti.hpp sysloglogger.cpp sysloglogger.hpp sysloglogger-ti.hpp
tcpsocket.cpp tcpsocket.hpp tcpsocket.cpp tcpsocket.hpp
threadpool.cpp threadpool.hpp threadpool.cpp threadpool.hpp

View File

@ -5,12 +5,11 @@
#include "base/dictionary.hpp" #include "base/dictionary.hpp"
#include "base/array.hpp" #include "base/array.hpp"
#include "base/objectlock.hpp" #include "base/objectlock.hpp"
#include "base/stringbuilder.hpp"
#include <algorithm> #include <algorithm>
#include <climits> #include <climits>
#include <cstdint> #include <cstdint>
#include <string>
#include <utility> #include <utility>
#include <vector>
using namespace icinga; using namespace icinga;
@ -30,7 +29,7 @@ static const EndiannessDetector l_EndiannessDetector;
// Assumption: The compiler will optimize (away) if/else statements using this. // Assumption: The compiler will optimize (away) if/else statements using this.
#define MACHINE_LITTLE_ENDIAN (l_EndiannessDetector.buf[0]) #define MACHINE_LITTLE_ENDIAN (l_EndiannessDetector.buf[0])
static void PackAny(const Value& value, StringBuilder& builder); static void PackAny(const Value& value, std::string& builder);
/** /**
* std::swap() seems not to work * std::swap() seems not to work
@ -73,7 +72,7 @@ static inline char UIntToByte(unsigned i)
/** /**
* Append the given int as big-endian 64-bit unsigned int * Append the given int as big-endian 64-bit unsigned int
*/ */
static inline void PackUInt64BE(uint_least64_t i, StringBuilder& builder) static inline void PackUInt64BE(uint_least64_t i, std::string& builder)
{ {
char buf[8] = { char buf[8] = {
UIntToByte(i >> 56u), UIntToByte(i >> 56u),
@ -86,7 +85,7 @@ static inline void PackUInt64BE(uint_least64_t i, StringBuilder& builder)
UIntToByte(i & 255u) UIntToByte(i & 255u)
}; };
builder.Append((char*)buf, (char*)buf + 8); builder.append((char*)buf, 8);
} }
union Double2BytesConverter union Double2BytesConverter
@ -110,7 +109,7 @@ union Double2BytesConverter
/** /**
* Append the given double as big-endian IEEE 754 binary64 * Append the given double as big-endian IEEE 754 binary64
*/ */
static inline void PackFloat64BE(double f, StringBuilder& builder) static inline void PackFloat64BE(double f, std::string& builder)
{ {
Double2BytesConverter converter; Double2BytesConverter converter;
@ -123,26 +122,26 @@ static inline void PackFloat64BE(double f, StringBuilder& builder)
SwapBytes(converter.buf[3], converter.buf[4]); SwapBytes(converter.buf[3], converter.buf[4]);
} }
builder.Append((char*)converter.buf, (char*)converter.buf + 8); builder.append((char*)converter.buf, 8);
} }
/** /**
* Append the given string's length (BE uint64) and the string itself * Append the given string's length (BE uint64) and the string itself
*/ */
static inline void PackString(const String& string, StringBuilder& builder) static inline void PackString(const String& string, std::string& builder)
{ {
PackUInt64BE(string.GetLength(), builder); PackUInt64BE(string.GetLength(), builder);
builder.Append(string); builder += string.GetData();
} }
/** /**
* Append the given array * Append the given array
*/ */
static inline void PackArray(const Array::Ptr& arr, StringBuilder& builder) static inline void PackArray(const Array::Ptr& arr, std::string& builder)
{ {
ObjectLock olock(arr); ObjectLock olock(arr);
builder.Append('\5'); builder += '\5';
PackUInt64BE(arr->GetLength(), builder); PackUInt64BE(arr->GetLength(), builder);
for (const Value& value : arr) { for (const Value& value : arr) {
@ -153,11 +152,11 @@ static inline void PackArray(const Array::Ptr& arr, StringBuilder& builder)
/** /**
* Append the given dictionary * Append the given dictionary
*/ */
static inline void PackDictionary(const Dictionary::Ptr& dict, StringBuilder& builder) static inline void PackDictionary(const Dictionary::Ptr& dict, std::string& builder)
{ {
ObjectLock olock(dict); ObjectLock olock(dict);
builder.Append('\6'); builder += '\6';
PackUInt64BE(dict->GetLength(), builder); PackUInt64BE(dict->GetLength(), builder);
for (const Dictionary::Pair& kv : dict) { for (const Dictionary::Pair& kv : dict) {
@ -169,25 +168,25 @@ static inline void PackDictionary(const Dictionary::Ptr& dict, StringBuilder& bu
/** /**
* Append any JSON-encodable value * Append any JSON-encodable value
*/ */
static void PackAny(const Value& value, StringBuilder& builder) static void PackAny(const Value& value, std::string& builder)
{ {
switch (value.GetType()) { switch (value.GetType()) {
case ValueString: case ValueString:
builder.Append('\4'); builder += '\4';
PackString(value.Get<String>(), builder); PackString(value.Get<String>(), builder);
break; break;
case ValueNumber: case ValueNumber:
builder.Append('\3'); builder += '\3';
PackFloat64BE(value.Get<double>(), builder); PackFloat64BE(value.Get<double>(), builder);
break; break;
case ValueBoolean: case ValueBoolean:
builder.Append(value.ToBool() ? '\2' : '\1'); builder += (value.ToBool() ? '\2' : '\1');
break; break;
case ValueEmpty: case ValueEmpty:
builder.Append('\0'); builder += '\0';
break; break;
case ValueObject: case ValueObject:
@ -207,7 +206,7 @@ static void PackAny(const Value& value, StringBuilder& builder)
} }
} }
builder.Append('\0'); builder += '\0';
break; break;
default: default:
@ -240,8 +239,8 @@ static void PackAny(const Value& value, StringBuilder& builder)
*/ */
String icinga::PackObject(const Value& value) String icinga::PackObject(const Value& value)
{ {
StringBuilder builder; std::string builder;
PackAny(value, builder); PackAny(value, builder);
return builder.ToString(); return std::move(builder);
} }

View File

@ -1,36 +0,0 @@
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
#include "base/stringbuilder.hpp"
#include <cstring>
using namespace icinga;
void StringBuilder::Append(const String& str)
{
m_Buffer.insert(m_Buffer.end(), str.Begin(), str.End());
}
void StringBuilder::Append(const std::string& str)
{
m_Buffer.insert(m_Buffer.end(), str.begin(), str.end());
}
void StringBuilder::Append(const char *begin, const char *end)
{
m_Buffer.insert(m_Buffer.end(), begin, end);
}
void StringBuilder::Append(const char *cstr)
{
m_Buffer.insert(m_Buffer.end(), cstr, cstr + std::strlen(cstr));
}
void StringBuilder::Append(char chr)
{
m_Buffer.emplace_back(chr);
}
String StringBuilder::ToString() const
{
return String(m_Buffer.data(), m_Buffer.data() + m_Buffer.size());
}

View File

@ -1,36 +0,0 @@
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
#ifndef STRINGBUILDER_H
#define STRINGBUILDER_H
#include "base/i2-base.hpp"
#include "base/string.hpp"
#include <string>
#include <vector>
namespace icinga
{
/**
* A string builder.
*
* @ingroup base
*/
class StringBuilder final
{
public:
void Append(const String&);
void Append(const std::string&);
void Append(const char *, const char *);
void Append(const char *);
void Append(char);
String ToString() const;
private:
std::vector<char> m_Buffer;
};
}
#endif /* STRINGBUILDER_H */