SerializeInternal(): allow to optionally not malloc() anything

This effectively just checks for circular refs.
This commit is contained in:
Alexander A. Klimov 2022-11-22 16:52:28 +01:00
parent f59f361f09
commit e53ec2a50f
3 changed files with 76 additions and 24 deletions

View File

@ -48,6 +48,18 @@ void Namespace::Set(const String& field, const Value& value, bool overrideFrozen
return SetFieldByName(field, value, overrideFrozen, DebugInfo()); return SetFieldByName(field, value, overrideFrozen, DebugInfo());
} }
/**
* Returns the number of elements in the namespace.
*
* @returns Number of elements.
*/
size_t Namespace::GetLength() const
{
ObjectLock olock(this);
return m_Data.size();
}
bool Namespace::Contains(const String& field) const bool Namespace::Contains(const String& field) const
{ {
ObjectLock olock(this); ObjectLock olock(this);

View File

@ -88,6 +88,8 @@ public:
Iterator Begin(); Iterator Begin();
Iterator End(); Iterator End();
size_t GetLength() const;
Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const override; Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const override;
void SetFieldByName(const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) override; void SetFieldByName(const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) override;
bool HasOwnField(const String& field) const override; bool HasOwnField(const String& field) const override;

View File

@ -9,6 +9,7 @@
#include "base/namespace.hpp" #include "base/namespace.hpp"
#include <boost/algorithm/string/join.hpp> #include <boost/algorithm/string/join.hpp>
#include <deque> #include <deque>
#include <utility>
using namespace icinga; using namespace icinga;
@ -64,13 +65,15 @@ struct SerializeStack
} }
}; };
static Value SerializeInternal(const Value& value, int attributeTypes, SerializeStack& stack); static Value SerializeInternal(const Value& value, int attributeTypes, SerializeStack& stack, bool dryRun);
static Array::Ptr SerializeArray(const Array::Ptr& input, int attributeTypes, SerializeStack& stack) static Array::Ptr SerializeArray(const Array::Ptr& input, int attributeTypes, SerializeStack& stack, bool dryRun)
{ {
ArrayData result; ArrayData result;
result.reserve(input->GetLength()); if (!dryRun) {
result.reserve(input->GetLength());
}
ObjectLock olock(input); ObjectLock olock(input);
@ -78,48 +81,72 @@ static Array::Ptr SerializeArray(const Array::Ptr& input, int attributeTypes, Se
for (const Value& value : input) { for (const Value& value : input) {
stack.Push(Convert::ToString(index), value); stack.Push(Convert::ToString(index), value);
result.emplace_back(SerializeInternal(value, attributeTypes, stack));
auto serialized (SerializeInternal(value, attributeTypes, stack, dryRun));
if (!dryRun) {
result.emplace_back(std::move(serialized));
}
stack.Pop(); stack.Pop();
index++; index++;
} }
return new Array(std::move(result)); return dryRun ? nullptr : new Array(std::move(result));
} }
static Dictionary::Ptr SerializeDictionary(const Dictionary::Ptr& input, int attributeTypes, SerializeStack& stack) static Dictionary::Ptr SerializeDictionary(const Dictionary::Ptr& input, int attributeTypes, SerializeStack& stack, bool dryRun)
{ {
DictionaryData result; DictionaryData result;
result.reserve(input->GetLength()); if (!dryRun) {
result.reserve(input->GetLength());
}
ObjectLock olock(input); ObjectLock olock(input);
for (const Dictionary::Pair& kv : input) { for (const Dictionary::Pair& kv : input) {
stack.Push(kv.first, kv.second); stack.Push(kv.first, kv.second);
result.emplace_back(kv.first, SerializeInternal(kv.second, attributeTypes, stack));
auto serialized (SerializeInternal(kv.second, attributeTypes, stack, dryRun));
if (!dryRun) {
result.emplace_back(kv.first, std::move(serialized));
}
stack.Pop(); stack.Pop();
} }
return new Dictionary(std::move(result)); return dryRun ? nullptr : new Dictionary(std::move(result));
} }
static Dictionary::Ptr SerializeNamespace(const Namespace::Ptr& input, int attributeTypes, SerializeStack& stack) static Dictionary::Ptr SerializeNamespace(const Namespace::Ptr& input, int attributeTypes, SerializeStack& stack, bool dryRun)
{ {
DictionaryData result; DictionaryData result;
if (!dryRun) {
result.reserve(input->GetLength());
}
ObjectLock olock(input); ObjectLock olock(input);
for (const Namespace::Pair& kv : input) { for (const Namespace::Pair& kv : input) {
Value val = kv.second->Get(); Value val = kv.second->Get();
stack.Push(kv.first, val); stack.Push(kv.first, val);
result.emplace_back(kv.first, Serialize(val, attributeTypes));
auto serialized (SerializeInternal(val, attributeTypes, stack, dryRun));
if (!dryRun) {
result.emplace_back(kv.first, std::move(serialized));
}
stack.Pop(); stack.Pop();
} }
return new Dictionary(std::move(result)); return dryRun ? nullptr : new Dictionary(std::move(result));
} }
static Object::Ptr SerializeObject(const Object::Ptr& input, int attributeTypes, SerializeStack& stack) static Object::Ptr SerializeObject(const Object::Ptr& input, int attributeTypes, SerializeStack& stack, bool dryRun)
{ {
Type::Ptr type = input->GetReflectionType(); Type::Ptr type = input->GetReflectionType();
@ -127,7 +154,10 @@ static Object::Ptr SerializeObject(const Object::Ptr& input, int attributeTypes,
return nullptr; return nullptr;
DictionaryData fields; DictionaryData fields;
fields.reserve(type->GetFieldCount() + 1);
if (!dryRun) {
fields.reserve(type->GetFieldCount() + 1);
}
ObjectLock olock(input); ObjectLock olock(input);
@ -142,13 +172,21 @@ static Object::Ptr SerializeObject(const Object::Ptr& input, int attributeTypes,
Value value = input->GetField(i); Value value = input->GetField(i);
stack.Push(field.Name, value); stack.Push(field.Name, value);
fields.emplace_back(field.Name, SerializeInternal(value, attributeTypes, stack));
auto serialized (SerializeInternal(value, attributeTypes, stack, dryRun));
if (!dryRun) {
fields.emplace_back(field.Name, std::move(serialized));
}
stack.Pop(); stack.Pop();
} }
fields.emplace_back("type", type->GetName()); if (!dryRun) {
fields.emplace_back("type", type->GetName());
}
return new Dictionary(std::move(fields)); return dryRun ? nullptr : new Dictionary(std::move(fields));
} }
static Array::Ptr DeserializeArray(const Array::Ptr& input, bool safe_mode, int attributeTypes) static Array::Ptr DeserializeArray(const Array::Ptr& input, bool safe_mode, int attributeTypes)
@ -228,35 +266,35 @@ static Object::Ptr DeserializeObject(const Object::Ptr& object, const Dictionary
return instance; return instance;
} }
static Value SerializeInternal(const Value& value, int attributeTypes, SerializeStack& stack) static Value SerializeInternal(const Value& value, int attributeTypes, SerializeStack& stack, bool dryRun)
{ {
if (!value.IsObject()) if (!value.IsObject())
return value; return dryRun ? Empty : value;
Object::Ptr input = value; Object::Ptr input = value;
Array::Ptr array = dynamic_pointer_cast<Array>(input); Array::Ptr array = dynamic_pointer_cast<Array>(input);
if (array) if (array)
return SerializeArray(array, attributeTypes, stack); return SerializeArray(array, attributeTypes, stack, dryRun);
Dictionary::Ptr dict = dynamic_pointer_cast<Dictionary>(input); Dictionary::Ptr dict = dynamic_pointer_cast<Dictionary>(input);
if (dict) if (dict)
return SerializeDictionary(dict, attributeTypes, stack); return SerializeDictionary(dict, attributeTypes, stack, dryRun);
Namespace::Ptr ns = dynamic_pointer_cast<Namespace>(input); Namespace::Ptr ns = dynamic_pointer_cast<Namespace>(input);
if (ns) if (ns)
return SerializeNamespace(ns, attributeTypes, stack); return SerializeNamespace(ns, attributeTypes, stack, dryRun);
return SerializeObject(input, attributeTypes, stack); return SerializeObject(input, attributeTypes, stack, dryRun);
} }
Value icinga::Serialize(const Value& value, int attributeTypes) Value icinga::Serialize(const Value& value, int attributeTypes)
{ {
SerializeStack stack; SerializeStack stack;
return SerializeInternal(value, attributeTypes, stack); return SerializeInternal(value, attributeTypes, stack, false);
} }
Value icinga::Deserialize(const Value& value, bool safe_mode, int attributeTypes) Value icinga::Deserialize(const Value& value, bool safe_mode, int attributeTypes)