Refactor: Simplify BLI_serialize.hh for asset indexer
- Remove the unnecessary `ContainerValue` from the class hierarchy - Construct `StringValue` with a `std::string` by value to avoid copies - Remove some indirection by using type names directly instead of aliases - Use utility methods to lookup/append specific data types for arrays/dicts - Simplify conversion from unique_ptr to shared_ptr - Avoid use of `new` and `delete` - Avoid creating maps of all elements in vector for a single lookup
This commit is contained in:
@@ -90,9 +90,8 @@ class IDPropertySerializer {
|
||||
std::shared_ptr<DictionaryValue> create_dictionary(const IDProperty *id_property) const
|
||||
{
|
||||
std::shared_ptr<DictionaryValue> result = std::make_shared<DictionaryValue>();
|
||||
DictionaryValue::Items &attributes = result->elements();
|
||||
attributes.append_as(std::pair(IDP_KEY_NAME, new StringValue(id_property->name)));
|
||||
attributes.append_as(std::pair(IDP_KEY_TYPE, new StringValue(type_name())));
|
||||
result->append_str(IDP_KEY_NAME, id_property->name);
|
||||
result->append_str(IDP_KEY_TYPE, this->type_name());
|
||||
return result;
|
||||
}
|
||||
};
|
||||
@@ -101,7 +100,7 @@ class IDPropertySerializer {
|
||||
* \brief Helper class for parsing DictionaryValues.
|
||||
*/
|
||||
struct DictionaryEntryParser {
|
||||
const DictionaryValue::Lookup lookup;
|
||||
DictionaryValue::Lookup lookup;
|
||||
|
||||
public:
|
||||
explicit DictionaryEntryParser(const DictionaryValue &value) : lookup(value.create_lookup()) {}
|
||||
@@ -174,92 +173,74 @@ struct DictionaryEntryParser {
|
||||
private:
|
||||
std::optional<std::string> get_string(StringRef key) const
|
||||
{
|
||||
const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(key);
|
||||
if (value_ptr == nullptr) {
|
||||
const std::shared_ptr<Value> *value = lookup.lookup_ptr(key);
|
||||
if (value == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const DictionaryValue::LookupValue &value = *value_ptr;
|
||||
|
||||
if (value->type() != eValueType::String) {
|
||||
if (value->get()->type() != eValueType::String) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return value->as_string_value()->value();
|
||||
return value->get()->as_string_value()->value();
|
||||
}
|
||||
|
||||
const ArrayValue *get_array(StringRef key) const
|
||||
{
|
||||
const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(key);
|
||||
if (value_ptr == nullptr) {
|
||||
const std::shared_ptr<Value> *value = lookup.lookup_ptr(key);
|
||||
if (value == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
const DictionaryValue::LookupValue &value = *value_ptr;
|
||||
|
||||
if (value->type() != eValueType::Array) {
|
||||
if (value->get()->type() != eValueType::Array) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return value->as_array_value();
|
||||
return value->get()->as_array_value();
|
||||
}
|
||||
|
||||
std::optional<bool> get_bool(StringRef key) const
|
||||
{
|
||||
const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(key);
|
||||
if (value_ptr == nullptr) {
|
||||
const std::shared_ptr<Value> *value = lookup.lookup_ptr(key);
|
||||
if (value == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const DictionaryValue::LookupValue &value = *value_ptr;
|
||||
|
||||
if (value->type() != eValueType::Boolean) {
|
||||
if (value->get()->type() != eValueType::Boolean) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return value->as_boolean_value()->value();
|
||||
return value->get()->as_boolean_value()->value();
|
||||
}
|
||||
|
||||
std::optional<int32_t> get_int(StringRef key) const
|
||||
{
|
||||
const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(key);
|
||||
if (value_ptr == nullptr) {
|
||||
const std::shared_ptr<Value> *value = lookup.lookup_ptr(key);
|
||||
if (value == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const DictionaryValue::LookupValue &value = *value_ptr;
|
||||
|
||||
if (value->type() != eValueType::Int) {
|
||||
if (value->get()->type() != eValueType::Int) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return value->as_int_value()->value();
|
||||
return value->get()->as_int_value()->value();
|
||||
}
|
||||
|
||||
std::optional<int32_t> get_enum(StringRef key) const
|
||||
{
|
||||
const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(key);
|
||||
if (value_ptr == nullptr) {
|
||||
const std::shared_ptr<Value> *value = lookup.lookup_ptr(key);
|
||||
if (value == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const DictionaryValue::LookupValue &value = *value_ptr;
|
||||
|
||||
if (value->type() != eValueType::Int) {
|
||||
if (value->get()->type() != eValueType::Int) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return value->as_int_value()->value();
|
||||
return value->get()->as_int_value()->value();
|
||||
}
|
||||
|
||||
std::optional<double> get_double(StringRef key) const
|
||||
{
|
||||
const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(key);
|
||||
if (value_ptr == nullptr) {
|
||||
const std::shared_ptr<Value> *value = lookup.lookup_ptr(key);
|
||||
if (value == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const DictionaryValue::LookupValue &value = *value_ptr;
|
||||
|
||||
if (value->type() != eValueType::Double) {
|
||||
if (value->get()->type() != eValueType::Double) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return value->as_double_value()->value();
|
||||
return value->get()->as_double_value()->value();
|
||||
}
|
||||
|
||||
std::optional<float> get_float(StringRef key) const
|
||||
@@ -270,19 +251,16 @@ struct DictionaryEntryParser {
|
||||
template<typename PrimitiveType, typename ValueType>
|
||||
std::optional<Vector<PrimitiveType>> get_array_primitive(StringRef key) const
|
||||
{
|
||||
const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(key);
|
||||
if (value_ptr == nullptr) {
|
||||
const std::shared_ptr<Value> *value = lookup.lookup_ptr(key);
|
||||
if (value == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const DictionaryValue::LookupValue &value = *value_ptr;
|
||||
|
||||
if (value->type() != eValueType::Array) {
|
||||
if (value->get()->type() != eValueType::Array) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
Vector<PrimitiveType> result;
|
||||
const ArrayValue::Items &elements = value->as_array_value()->elements();
|
||||
for (const ArrayValue::Item &element : elements) {
|
||||
for (const std::shared_ptr<Value> &element : value->get()->as_array_value()->elements()) {
|
||||
const ValueType *value_type = static_cast<const ValueType *>(element.get());
|
||||
PrimitiveType primitive_value = value_type->value();
|
||||
result.append_as(primitive_value);
|
||||
@@ -321,8 +299,7 @@ class IDPStringSerializer : public IDPropertySerializer {
|
||||
const IDProperty *id_property) const override
|
||||
{
|
||||
std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
|
||||
DictionaryValue::Items &attributes = result->elements();
|
||||
attributes.append_as(std::pair(IDP_KEY_VALUE, new StringValue(IDP_String(id_property))));
|
||||
result->append_str(IDP_KEY_VALUE, IDP_String(id_property));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -361,8 +338,7 @@ class IDPBoolSerializer : public IDPropertySerializer {
|
||||
const IDProperty *id_property) const override
|
||||
{
|
||||
std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
|
||||
DictionaryValue::Items &attributes = result->elements();
|
||||
attributes.append_as(std::pair(IDP_KEY_VALUE, new BooleanValue(IDP_Bool(id_property) != 0)));
|
||||
result->append(IDP_KEY_VALUE, std::make_shared<BooleanValue>(IDP_Bool(id_property) != 0));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -401,8 +377,7 @@ class IDPIntSerializer : public IDPropertySerializer {
|
||||
const IDProperty *id_property) const override
|
||||
{
|
||||
std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
|
||||
DictionaryValue::Items &attributes = result->elements();
|
||||
attributes.append_as(std::pair(IDP_KEY_VALUE, new IntValue(IDP_Int(id_property))));
|
||||
result->append_int(IDP_KEY_VALUE, IDP_Int(id_property));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -441,8 +416,7 @@ class IDPFloatSerializer : public IDPropertySerializer {
|
||||
const IDProperty *id_property) const override
|
||||
{
|
||||
std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
|
||||
DictionaryValue::Items &attributes = result->elements();
|
||||
attributes.append_as(std::pair(IDP_KEY_VALUE, new DoubleValue(IDP_Float(id_property))));
|
||||
result->append_double(IDP_KEY_VALUE, IDP_Float(id_property));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -481,8 +455,7 @@ class IDPDoubleSerializer : public IDPropertySerializer {
|
||||
const IDProperty *id_property) const override
|
||||
{
|
||||
std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
|
||||
DictionaryValue::Items &attributes = result->elements();
|
||||
attributes.append_as(std::pair(IDP_KEY_VALUE, new DoubleValue(IDP_Double(id_property))));
|
||||
result->append_double(IDP_KEY_VALUE, IDP_Double(id_property));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -521,45 +494,38 @@ class IDPArraySerializer : public IDPropertySerializer {
|
||||
const IDProperty *id_property) const override
|
||||
{
|
||||
std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
|
||||
DictionaryValue::Items &attributes = result->elements();
|
||||
const IDPropertySerializer &subtype_serializer = serializer_for(
|
||||
static_cast<eIDPropertyType>(id_property->subtype));
|
||||
attributes.append_as(
|
||||
std::pair(IDP_KEY_SUBTYPE, new StringValue(subtype_serializer.type_name())));
|
||||
result->append_str(IDP_KEY_SUBTYPE, subtype_serializer.type_name());
|
||||
|
||||
std::shared_ptr<ArrayValue> array = std::make_shared<ArrayValue>();
|
||||
ArrayValue &array = *result->append_array(IDP_KEY_VALUE);
|
||||
switch (static_cast<eIDPropertyType>(id_property->subtype)) {
|
||||
case IDP_INT: {
|
||||
int32_t *values = static_cast<int32_t *>(IDP_Array(id_property));
|
||||
add_values<int32_t, IntValue>(array.get(), Span<int32_t>(values, id_property->len));
|
||||
add_values<int32_t, IntValue>(array, Span<int32_t>(values, id_property->len));
|
||||
break;
|
||||
}
|
||||
|
||||
case IDP_FLOAT: {
|
||||
float *values = static_cast<float *>(IDP_Array(id_property));
|
||||
add_values<float, DoubleValue>(array.get(), Span<float>(values, id_property->len));
|
||||
add_values<float, DoubleValue>(array, Span<float>(values, id_property->len));
|
||||
break;
|
||||
}
|
||||
|
||||
case IDP_DOUBLE: {
|
||||
double *values = static_cast<double *>(IDP_Array(id_property));
|
||||
add_values<double, DoubleValue>(array.get(), Span<double>(values, id_property->len));
|
||||
add_values<double, DoubleValue>(array, Span<double>(values, id_property->len));
|
||||
break;
|
||||
}
|
||||
|
||||
case IDP_GROUP: {
|
||||
IDProperty *values = static_cast<IDProperty *>(IDP_Array(id_property));
|
||||
add_values(array.get(), Span<IDProperty>(values, id_property->len));
|
||||
add_values(array, Span<IDProperty>(values, id_property->len));
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
/* IDP_ARRAY only supports IDP_INT, IDP_FLOAT, IDP_DOUBLE and IDP_GROUP. */
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
}
|
||||
attributes.append_as(std::pair(IDP_KEY_VALUE, std::move(array)));
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -576,17 +542,13 @@ class IDPArraySerializer : public IDPropertySerializer {
|
||||
switch (*property_subtype) {
|
||||
case IDP_INT:
|
||||
return idprop_array_int_from_value(entry_reader);
|
||||
|
||||
case IDP_FLOAT:
|
||||
return idprop_array_float_from_value(entry_reader);
|
||||
|
||||
case IDP_DOUBLE:
|
||||
return idprop_array_double_from_value(entry_reader);
|
||||
|
||||
default:
|
||||
break;
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -596,25 +558,22 @@ class IDPArraySerializer : public IDPropertySerializer {
|
||||
typename PrimitiveType,
|
||||
/* Type of value that can store the PrimitiveType in the Array. */
|
||||
typename ValueType>
|
||||
void add_values(ArrayValue *array, Span<PrimitiveType> values) const
|
||||
void add_values(ArrayValue &array, Span<PrimitiveType> values) const
|
||||
{
|
||||
ArrayValue::Items &items = array->elements();
|
||||
for (PrimitiveType value : values) {
|
||||
items.append_as(std::make_shared<ValueType>(value));
|
||||
array.append(std::make_shared<ValueType>(value));
|
||||
}
|
||||
}
|
||||
|
||||
void add_values(ArrayValue *array, Span<IDProperty> values) const
|
||||
void add_values(ArrayValue &array, Span<IDProperty> values) const
|
||||
{
|
||||
ArrayValue::Items &items = array->elements();
|
||||
for (const IDProperty &id_property : values) {
|
||||
const IDPropertySerializer &value_serializer = serializer_for(
|
||||
static_cast<eIDPropertyType>(id_property.type));
|
||||
if (!value_serializer.supports_serializing()) {
|
||||
continue;
|
||||
}
|
||||
std::shared_ptr<DictionaryValue> value = value_serializer.idprop_to_dictionary(&id_property);
|
||||
items.append_as(value);
|
||||
array.append(value_serializer.idprop_to_dictionary(&id_property));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -686,18 +645,15 @@ class IDPGroupSerializer : public IDPropertySerializer {
|
||||
const IDProperty *id_property) const override
|
||||
{
|
||||
std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
|
||||
DictionaryValue::Items &attributes = result->elements();
|
||||
|
||||
std::shared_ptr<ArrayValue> array = std::make_shared<ArrayValue>();
|
||||
ArrayValue::Items &elements = array->elements();
|
||||
|
||||
LISTBASE_FOREACH (IDProperty *, sub_property, &id_property->data.group) {
|
||||
|
||||
const IDPropertySerializer &sub_property_serializer = serializer_for(
|
||||
static_cast<eIDPropertyType>(sub_property->type));
|
||||
elements.append_as(sub_property_serializer.idprop_to_dictionary(sub_property));
|
||||
array->append(sub_property_serializer.idprop_to_dictionary(sub_property));
|
||||
}
|
||||
|
||||
attributes.append_as(std::pair(IDP_KEY_VALUE, array));
|
||||
result->append(IDP_KEY_VALUE, std::move(array));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -716,7 +672,7 @@ class IDPGroupSerializer : public IDPropertySerializer {
|
||||
}
|
||||
|
||||
std::unique_ptr<IDProperty, IDPropertyDeleter> result = create_group(name->c_str());
|
||||
for (const ArrayValue::Item &element : array->elements()) {
|
||||
for (const std::shared_ptr<Value> &element : array->elements()) {
|
||||
if (element->type() != eValueType::Dictionary) {
|
||||
continue;
|
||||
}
|
||||
@@ -840,13 +796,12 @@ std::unique_ptr<ArrayValue> convert_to_serialize_values(const IDProperty *proper
|
||||
{
|
||||
BLI_assert(properties != nullptr);
|
||||
std::unique_ptr<ArrayValue> result = std::make_unique<ArrayValue>();
|
||||
ArrayValue::Items &elements = result->elements();
|
||||
const IDProperty *current_property = properties;
|
||||
while (current_property != nullptr) {
|
||||
const IDPropertySerializer &serializer = serializer_for(
|
||||
static_cast<eIDPropertyType>(current_property->type));
|
||||
if (serializer.supports_serializing()) {
|
||||
elements.append_as(serializer.idprop_to_dictionary(current_property));
|
||||
result->append(serializer.idprop_to_dictionary(current_property));
|
||||
}
|
||||
current_property = current_property->next;
|
||||
}
|
||||
@@ -877,8 +832,7 @@ static IDProperty *idprop_from_value(const ArrayValue &value)
|
||||
IDProperty *result = nullptr;
|
||||
IDProperty *previous_added = nullptr;
|
||||
|
||||
const ArrayValue::Items &elements = value.elements();
|
||||
for (const ArrayValue::Item &element : elements) {
|
||||
for (const std::shared_ptr<Value> &element : value.elements()) {
|
||||
if (element->type() != eValueType::Dictionary) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -18,11 +18,11 @@ static void check_container_value(ArrayValue *value)
|
||||
{
|
||||
ASSERT_NE(value, nullptr);
|
||||
ASSERT_EQ(value->type(), eValueType::Array);
|
||||
const ArrayValue::Items elements = value->elements();
|
||||
const Span<std::shared_ptr<Value>> elements = value->elements();
|
||||
EXPECT_FALSE(elements.is_empty());
|
||||
EXPECT_EQ(elements.size(), 1);
|
||||
|
||||
const ArrayValue::Item &item = value->elements()[0];
|
||||
const std::shared_ptr<Value> &item = value->elements()[0];
|
||||
ASSERT_EQ(item->type(), eValueType::Dictionary);
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ static void test_string_to_value(const StringRefNull prop_name, const StringRefN
|
||||
|
||||
std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
|
||||
check_container_value(value.get());
|
||||
const ArrayValue::Item &item = value->elements()[0];
|
||||
const std::shared_ptr<Value> &item = value->elements()[0];
|
||||
const DictionaryValue *object = item->as_dictionary_value();
|
||||
const DictionaryValue::Lookup lookup = object->create_lookup();
|
||||
|
||||
@@ -93,7 +93,7 @@ static void test_int_to_value(const StringRefNull prop_name, int32_t prop_conten
|
||||
|
||||
std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
|
||||
check_container_value(value.get());
|
||||
const ArrayValue::Item &item = value->elements()[0];
|
||||
const std::shared_ptr<Value> &item = value->elements()[0];
|
||||
const DictionaryValue *object = item->as_dictionary_value();
|
||||
const DictionaryValue::Lookup lookup = object->create_lookup();
|
||||
|
||||
@@ -114,7 +114,7 @@ static void test_float_to_value(const StringRefNull prop_name, float prop_conten
|
||||
|
||||
std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
|
||||
check_container_value(value.get());
|
||||
const ArrayValue::Item &item = value->elements()[0];
|
||||
const std::shared_ptr<Value> &item = value->elements()[0];
|
||||
const DictionaryValue *object = item->as_dictionary_value();
|
||||
const DictionaryValue::Lookup lookup = object->create_lookup();
|
||||
|
||||
@@ -135,7 +135,7 @@ static void test_double_to_value(const StringRefNull prop_name, double prop_cont
|
||||
|
||||
std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
|
||||
check_container_value(value.get());
|
||||
const ArrayValue::Item &item = value->elements()[0];
|
||||
const std::shared_ptr<Value> &item = value->elements()[0];
|
||||
const DictionaryValue *object = item->as_dictionary_value();
|
||||
const DictionaryValue::Lookup lookup = object->create_lookup();
|
||||
|
||||
@@ -157,7 +157,7 @@ static void test_array_to_value(const StringRefNull prop_name, Vector<PrimitiveT
|
||||
std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
|
||||
|
||||
check_container_value(value.get());
|
||||
const ArrayValue::Item &item = value->elements()[0];
|
||||
const std::shared_ptr<Value> &item = value->elements()[0];
|
||||
const DictionaryValue *object = item->as_dictionary_value();
|
||||
const DictionaryValue::Lookup lookup = object->create_lookup();
|
||||
|
||||
@@ -168,7 +168,7 @@ static void test_array_to_value(const StringRefNull prop_name, Vector<PrimitiveT
|
||||
const std::shared_ptr<Value> &element = *lookup.lookup_ptr("value");
|
||||
const ArrayValue *subvalues = element->as_array_value();
|
||||
ASSERT_NE(subvalues, nullptr);
|
||||
const ArrayValue::Items &subitems = subvalues->elements();
|
||||
const Span<std::shared_ptr<Value>> subitems = subvalues->elements();
|
||||
ASSERT_EQ(subitems.size(), prop_content.size());
|
||||
|
||||
for (size_t i = 0; i < prop_content.size(); i++) {
|
||||
|
||||
@@ -198,7 +198,7 @@ class StringValue : public Value {
|
||||
std::string string_;
|
||||
|
||||
public:
|
||||
StringValue(const StringRef string) : Value(eValueType::String), string_(string) {}
|
||||
StringValue(std::string string) : Value(eValueType::String), string_(std::move(string)) {}
|
||||
|
||||
const std::string &value() const
|
||||
{
|
||||
@@ -206,44 +206,12 @@ class StringValue : public Value {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Template for arrays and objects.
|
||||
*
|
||||
* Both ArrayValue and DictionaryValue store their values in an array.
|
||||
*/
|
||||
template<
|
||||
/** The container type where the elements are stored in. */
|
||||
typename Container,
|
||||
|
||||
/** ValueType representing the value (object/array). */
|
||||
eValueType V,
|
||||
|
||||
/** Type of the data inside the container. */
|
||||
typename ContainerItem = typename Container::value_type>
|
||||
class ContainerValue : public Value {
|
||||
public:
|
||||
using Items = Container;
|
||||
using Item = ContainerItem;
|
||||
|
||||
private:
|
||||
Container inner_value_;
|
||||
class ArrayValue : public Value {
|
||||
Vector<std::shared_ptr<Value>> values_;
|
||||
|
||||
public:
|
||||
ContainerValue() : Value(V) {}
|
||||
ArrayValue() : Value(eValueType::Array) {}
|
||||
|
||||
const Container &elements() const
|
||||
{
|
||||
return inner_value_;
|
||||
}
|
||||
|
||||
Container &elements()
|
||||
{
|
||||
return inner_value_;
|
||||
}
|
||||
};
|
||||
|
||||
class ArrayValue : public ContainerValue<Vector<std::shared_ptr<Value>>, eValueType::Array> {
|
||||
public:
|
||||
void append(std::shared_ptr<Value> value);
|
||||
void append_bool(bool value);
|
||||
void append_int(int value);
|
||||
@@ -252,32 +220,38 @@ class ArrayValue : public ContainerValue<Vector<std::shared_ptr<Value>>, eValueT
|
||||
void append_null();
|
||||
std::shared_ptr<DictionaryValue> append_dict();
|
||||
std::shared_ptr<ArrayValue> append_array();
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal storage type for DictionaryValue.
|
||||
*
|
||||
* The elements are stored as an key value pair. The value is a shared pointer so it can be shared
|
||||
* when using `DictionaryValue::create_lookup`.
|
||||
*/
|
||||
using DictionaryElementType = std::pair<std::string, std::shared_ptr<Value>>;
|
||||
Span<std::shared_ptr<Value>> elements() const
|
||||
{
|
||||
return values_;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Object is a key-value container where the key must be a std::string.
|
||||
* Internally it is stored in a blender::Vector to ensure the order of keys.
|
||||
*/
|
||||
class DictionaryValue
|
||||
: public ContainerValue<Vector<DictionaryElementType>, eValueType::Dictionary> {
|
||||
class DictionaryValue : public Value {
|
||||
public:
|
||||
using LookupValue = std::shared_ptr<Value>;
|
||||
using Lookup = Map<std::string, LookupValue>;
|
||||
/**
|
||||
* Elements are stored as an key value pair. The value is a shared pointer so it can be
|
||||
* shared when using `DictionaryValue::create_lookup`.
|
||||
*/
|
||||
using Item = std::pair<std::string, std::shared_ptr<Value>>;
|
||||
using Lookup = Map<std::string, std::shared_ptr<Value>>;
|
||||
|
||||
private:
|
||||
Vector<Item> values_;
|
||||
|
||||
public:
|
||||
DictionaryValue() : Value(eValueType::Dictionary) {}
|
||||
|
||||
/**
|
||||
* Return a lookup map to quickly lookup by key.
|
||||
*
|
||||
* The lookup is owned by the caller.
|
||||
*/
|
||||
const Lookup create_lookup() const;
|
||||
Lookup create_lookup() const;
|
||||
|
||||
const std::shared_ptr<Value> *lookup(const StringRef key) const;
|
||||
std::optional<StringRefNull> lookup_str(const StringRef key) const;
|
||||
@@ -285,6 +259,10 @@ class DictionaryValue
|
||||
std::optional<double> lookup_double(const StringRef key) const;
|
||||
const DictionaryValue *lookup_dict(const StringRef key) const;
|
||||
const ArrayValue *lookup_array(const StringRef key) const;
|
||||
Span<Item> elements() const
|
||||
{
|
||||
return values_;
|
||||
}
|
||||
|
||||
void append(std::string key, std::shared_ptr<Value> value);
|
||||
void append_int(std::string key, int64_t value);
|
||||
|
||||
@@ -68,11 +68,10 @@ const DictionaryValue *Value::as_dictionary_value() const
|
||||
static void convert_to_json(nlohmann::ordered_json &j, const Value &value);
|
||||
static void convert_to_json(nlohmann::ordered_json &j, const ArrayValue &value)
|
||||
{
|
||||
const ArrayValue::Items &items = value.elements();
|
||||
/* Create a json array to store the elements. If this isn't done and items is empty it would
|
||||
* return use a null value, in stead of an empty array. */
|
||||
j = "[]"_json;
|
||||
for (const ArrayValue::Item &item_value : items) {
|
||||
for (const std::shared_ptr<Value> &item_value : value.elements()) {
|
||||
nlohmann::ordered_json json_item;
|
||||
convert_to_json(json_item, *item_value);
|
||||
j.push_back(json_item);
|
||||
@@ -81,11 +80,10 @@ static void convert_to_json(nlohmann::ordered_json &j, const ArrayValue &value)
|
||||
|
||||
static void convert_to_json(nlohmann::ordered_json &j, const DictionaryValue &value)
|
||||
{
|
||||
const DictionaryValue::Items &attributes = value.elements();
|
||||
/* Create a json object to store the attributes. If this isn't done and attributes is empty it
|
||||
* would return use a null value, in stead of an empty object. */
|
||||
j = "{}"_json;
|
||||
for (const DictionaryValue::Item &attribute : attributes) {
|
||||
for (const DictionaryValue::Item &attribute : value.elements()) {
|
||||
nlohmann::ordered_json json_item;
|
||||
convert_to_json(json_item, *attribute.second);
|
||||
j[attribute.first] = json_item;
|
||||
@@ -143,11 +141,8 @@ static std::unique_ptr<Value> convert_from_json(const nlohmann::ordered_json &j)
|
||||
static std::unique_ptr<ArrayValue> convert_from_json_to_array(const nlohmann::ordered_json &j)
|
||||
{
|
||||
std::unique_ptr<ArrayValue> array = std::make_unique<ArrayValue>();
|
||||
ArrayValue::Items &elements = array->elements();
|
||||
for (auto element : j.items()) {
|
||||
nlohmann::ordered_json element_json = element.value();
|
||||
std::unique_ptr<Value> value = convert_from_json(element_json);
|
||||
elements.append_as(value.release());
|
||||
array->append(convert_from_json(element.value()));
|
||||
}
|
||||
return array;
|
||||
}
|
||||
@@ -156,12 +151,8 @@ static std::unique_ptr<DictionaryValue> convert_from_json_to_object(
|
||||
const nlohmann::ordered_json &j)
|
||||
{
|
||||
std::unique_ptr<DictionaryValue> object = std::make_unique<DictionaryValue>();
|
||||
DictionaryValue::Items &elements = object->elements();
|
||||
for (auto element : j.items()) {
|
||||
std::string key = element.key();
|
||||
nlohmann::ordered_json element_json = element.value();
|
||||
std::unique_ptr<Value> value = convert_from_json(element_json);
|
||||
elements.append_as(std::pair(key, value.release()));
|
||||
object->append(element.key(), convert_from_json(element.value()));
|
||||
}
|
||||
return object;
|
||||
}
|
||||
@@ -216,7 +207,7 @@ static std::unique_ptr<Value> convert_from_json(const nlohmann::ordered_json &j)
|
||||
|
||||
void ArrayValue::append(std::shared_ptr<Value> value)
|
||||
{
|
||||
this->elements().append(std::move(value));
|
||||
values_.append(std::move(value));
|
||||
}
|
||||
|
||||
void ArrayValue::append_bool(const bool value)
|
||||
@@ -258,10 +249,10 @@ std::shared_ptr<ArrayValue> ArrayValue::append_array()
|
||||
return value;
|
||||
}
|
||||
|
||||
const DictionaryValue::Lookup DictionaryValue::create_lookup() const
|
||||
DictionaryValue::Lookup DictionaryValue::create_lookup() const
|
||||
{
|
||||
Lookup result;
|
||||
for (const Item &item : elements()) {
|
||||
for (const Item &item : values_) {
|
||||
result.add_as(item.first, item.second);
|
||||
}
|
||||
return result;
|
||||
@@ -269,7 +260,7 @@ const DictionaryValue::Lookup DictionaryValue::create_lookup() const
|
||||
|
||||
const std::shared_ptr<Value> *DictionaryValue::lookup(const StringRef key) const
|
||||
{
|
||||
for (const auto &item : this->elements()) {
|
||||
for (const auto &item : values_) {
|
||||
if (item.first == key) {
|
||||
return &item.second;
|
||||
}
|
||||
@@ -325,7 +316,7 @@ const ArrayValue *DictionaryValue::lookup_array(const StringRef key) const
|
||||
|
||||
void DictionaryValue::append(std::string key, std::shared_ptr<Value> value)
|
||||
{
|
||||
this->elements().append({std::move(key), std::move(value)});
|
||||
values_.append({std::move(key), std::move(value)});
|
||||
}
|
||||
|
||||
void DictionaryValue::append_int(std::string key, const int64_t value)
|
||||
@@ -338,9 +329,9 @@ void DictionaryValue::append_double(std::string key, const double value)
|
||||
this->append(std::move(key), std::make_shared<DoubleValue>(value));
|
||||
}
|
||||
|
||||
void DictionaryValue::append_str(std::string key, const std::string value)
|
||||
void DictionaryValue::append_str(std::string key, std::string value)
|
||||
{
|
||||
this->append(std::move(key), std::make_shared<StringValue>(value));
|
||||
this->append(std::move(key), std::make_shared<StringValue>(std::move(value)));
|
||||
}
|
||||
|
||||
std::shared_ptr<DictionaryValue> DictionaryValue::append_dict(std::string key)
|
||||
|
||||
@@ -140,30 +140,17 @@ class BlendFile : public AbstractFile {
|
||||
*
|
||||
* NOTE: id and name are encoded like #ID.name
|
||||
*/
|
||||
static void add_id_name(DictionaryValue::Items &result,
|
||||
const short idcode,
|
||||
const StringRefNull name)
|
||||
static void add_id_name(DictionaryValue &result, const short idcode, const StringRefNull name)
|
||||
{
|
||||
char idcode_prefix[2];
|
||||
/* Similar to `BKE_libblock_alloc`. */
|
||||
*((short *)idcode_prefix) = idcode;
|
||||
std::string name_with_idcode = std::string(idcode_prefix, sizeof(idcode_prefix)) + name;
|
||||
|
||||
result.append_as(std::pair(ATTRIBUTE_ENTRIES_NAME, new StringValue(name_with_idcode)));
|
||||
result.append_str(ATTRIBUTE_ENTRIES_NAME, name_with_idcode);
|
||||
}
|
||||
|
||||
static void add_tags(DictionaryValue::Items &result, const ListBase /* AssetTag */ *asset_tags)
|
||||
{
|
||||
ArrayValue *tags = new ArrayValue();
|
||||
result.append_as(std::pair(ATTRIBUTE_ENTRIES_TAGS, tags));
|
||||
ArrayValue::Items &tag_items = tags->elements();
|
||||
|
||||
LISTBASE_FOREACH (AssetTag *, tag, asset_tags) {
|
||||
tag_items.append_as(new StringValue(tag->name));
|
||||
}
|
||||
}
|
||||
|
||||
static void init_value_from_file_indexer_entry(DictionaryValue::Items &result,
|
||||
static void init_value_from_file_indexer_entry(DictionaryValue &result,
|
||||
const FileIndexerEntry *indexer_entry)
|
||||
{
|
||||
const BLODataBlockInfo &datablock_info = indexer_entry->datablock_info;
|
||||
@@ -171,31 +158,32 @@ static void init_value_from_file_indexer_entry(DictionaryValue::Items &result,
|
||||
add_id_name(result, indexer_entry->idcode, datablock_info.name);
|
||||
|
||||
const AssetMetaData &asset_data = *datablock_info.asset_data;
|
||||
result.append_as(std::pair(ATTRIBUTE_ENTRIES_CATALOG_ID,
|
||||
new StringValue(CatalogID(asset_data.catalog_id).str())));
|
||||
result.append_as(
|
||||
std::pair(ATTRIBUTE_ENTRIES_CATALOG_NAME, new StringValue(asset_data.catalog_simple_name)));
|
||||
result.append_str(ATTRIBUTE_ENTRIES_CATALOG_ID, CatalogID(asset_data.catalog_id).str());
|
||||
result.append_str(ATTRIBUTE_ENTRIES_CATALOG_NAME, asset_data.catalog_simple_name);
|
||||
|
||||
if (const char *description = asset_data.description) {
|
||||
result.append_as(std::pair(ATTRIBUTE_ENTRIES_DESCRIPTION, new StringValue(description)));
|
||||
result.append_str(ATTRIBUTE_ENTRIES_DESCRIPTION, description);
|
||||
}
|
||||
if (const char *author = asset_data.author) {
|
||||
result.append_as(std::pair(ATTRIBUTE_ENTRIES_AUTHOR, new StringValue(author)));
|
||||
result.append_str(ATTRIBUTE_ENTRIES_AUTHOR, author);
|
||||
}
|
||||
if (const char *copyright = asset_data.copyright) {
|
||||
result.append_as(std::pair(ATTRIBUTE_ENTRIES_COPYRIGHT, new StringValue(copyright)));
|
||||
result.append_str(ATTRIBUTE_ENTRIES_COPYRIGHT, copyright);
|
||||
}
|
||||
if (const char *license = asset_data.license) {
|
||||
result.append_as(std::pair(ATTRIBUTE_ENTRIES_LICENSE, new StringValue(license)));
|
||||
result.append_str(ATTRIBUTE_ENTRIES_LICENSE, license);
|
||||
}
|
||||
|
||||
if (!BLI_listbase_is_empty(&asset_data.tags)) {
|
||||
add_tags(result, &asset_data.tags);
|
||||
ArrayValue &tags = *result.append_array(ATTRIBUTE_ENTRIES_TAGS);
|
||||
LISTBASE_FOREACH (AssetTag *, tag, &asset_data.tags) {
|
||||
tags.append_str(tag->name);
|
||||
}
|
||||
}
|
||||
|
||||
if (const IDProperty *properties = asset_data.properties) {
|
||||
if (std::unique_ptr<Value> value = convert_to_serialize_values(properties)) {
|
||||
result.append_as(std::pair(ATTRIBUTE_ENTRIES_PROPERTIES, value.release()));
|
||||
result.append(ATTRIBUTE_ENTRIES_PROPERTIES, std::move(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -203,8 +191,7 @@ static void init_value_from_file_indexer_entry(DictionaryValue::Items &result,
|
||||
static void init_value_from_file_indexer_entries(DictionaryValue &result,
|
||||
const FileIndexerEntries &indexer_entries)
|
||||
{
|
||||
ArrayValue *entries = new ArrayValue();
|
||||
ArrayValue::Items &items = entries->elements();
|
||||
auto entries = std::make_shared<ArrayValue>();
|
||||
|
||||
for (LinkNode *ln = indexer_entries.entries; ln; ln = ln->next) {
|
||||
const FileIndexerEntry *indexer_entry = static_cast<const FileIndexerEntry *>(ln->link);
|
||||
@@ -213,26 +200,22 @@ static void init_value_from_file_indexer_entries(DictionaryValue &result,
|
||||
if (indexer_entry->datablock_info.asset_data == nullptr) {
|
||||
continue;
|
||||
}
|
||||
DictionaryValue *entry = new DictionaryValue();
|
||||
init_value_from_file_indexer_entry(entry->elements(), indexer_entry);
|
||||
items.append_as(entry);
|
||||
init_value_from_file_indexer_entry(*entries->append_dict(), indexer_entry);
|
||||
}
|
||||
|
||||
/* When no entries to index, we should not store the entries attribute as this would make the
|
||||
* size bigger than the #MIN_FILE_SIZE_WITH_ENTRIES. */
|
||||
if (items.is_empty()) {
|
||||
delete entries;
|
||||
if (entries->elements().is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DictionaryValue::Items &attributes = result.elements();
|
||||
attributes.append_as(std::pair(ATTRIBUTE_ENTRIES, entries));
|
||||
result.append(ATTRIBUTE_ENTRIES, entries);
|
||||
}
|
||||
|
||||
static void init_indexer_entry_from_value(FileIndexerEntry &indexer_entry,
|
||||
const DictionaryValue::Lookup &entry)
|
||||
const DictionaryValue &entry)
|
||||
{
|
||||
const StringRef idcode_name = entry.lookup(ATTRIBUTE_ENTRIES_NAME)->as_string_value()->value();
|
||||
const StringRef idcode_name = *entry.lookup_str(ATTRIBUTE_ENTRIES_NAME);
|
||||
|
||||
indexer_entry.idcode = GS(idcode_name.data());
|
||||
|
||||
@@ -242,39 +225,32 @@ static void init_indexer_entry_from_value(FileIndexerEntry &indexer_entry,
|
||||
indexer_entry.datablock_info.asset_data = asset_data;
|
||||
indexer_entry.datablock_info.free_asset_data = true;
|
||||
|
||||
if (const std::shared_ptr<Value> *value = entry.lookup_ptr(ATTRIBUTE_ENTRIES_DESCRIPTION)) {
|
||||
const StringRef description = value->get()->as_string_value()->value();
|
||||
asset_data->description = BLI_strdupn(description.data(), description.size());
|
||||
if (const std::optional<StringRef> value = entry.lookup_str(ATTRIBUTE_ENTRIES_DESCRIPTION)) {
|
||||
asset_data->description = BLI_strdupn(value->data(), value->size());
|
||||
}
|
||||
if (const std::shared_ptr<Value> *value = entry.lookup_ptr(ATTRIBUTE_ENTRIES_AUTHOR)) {
|
||||
const StringRef author = value->get()->as_string_value()->value();
|
||||
asset_data->author = BLI_strdupn(author.data(), author.size());
|
||||
if (const std::optional<StringRef> value = entry.lookup_str(ATTRIBUTE_ENTRIES_AUTHOR)) {
|
||||
asset_data->author = BLI_strdupn(value->data(), value->size());
|
||||
}
|
||||
if (const std::shared_ptr<Value> *value = entry.lookup_ptr(ATTRIBUTE_ENTRIES_COPYRIGHT)) {
|
||||
const StringRef copyright = value->get()->as_string_value()->value();
|
||||
asset_data->copyright = BLI_strdupn(copyright.data(), copyright.size());
|
||||
if (const std::optional<StringRef> value = entry.lookup_str(ATTRIBUTE_ENTRIES_COPYRIGHT)) {
|
||||
asset_data->copyright = BLI_strdupn(value->data(), value->size());
|
||||
}
|
||||
if (const std::shared_ptr<Value> *value = entry.lookup_ptr(ATTRIBUTE_ENTRIES_LICENSE)) {
|
||||
const StringRef license = value->get()->as_string_value()->value();
|
||||
asset_data->license = BLI_strdupn(license.data(), license.size());
|
||||
if (const std::optional<StringRef> value = entry.lookup_str(ATTRIBUTE_ENTRIES_LICENSE)) {
|
||||
asset_data->license = BLI_strdupn(value->data(), value->size());
|
||||
}
|
||||
|
||||
const StringRefNull catalog_name =
|
||||
entry.lookup(ATTRIBUTE_ENTRIES_CATALOG_NAME)->as_string_value()->value();
|
||||
const StringRefNull catalog_name = *entry.lookup_str(ATTRIBUTE_ENTRIES_CATALOG_NAME);
|
||||
STRNCPY_UTF8(asset_data->catalog_simple_name, catalog_name.c_str());
|
||||
|
||||
const StringRefNull catalog_id =
|
||||
entry.lookup(ATTRIBUTE_ENTRIES_CATALOG_ID)->as_string_value()->value();
|
||||
const StringRefNull catalog_id = *entry.lookup_str(ATTRIBUTE_ENTRIES_CATALOG_ID);
|
||||
asset_data->catalog_id = CatalogID(catalog_id);
|
||||
|
||||
if (const std::shared_ptr<Value> *value = entry.lookup_ptr(ATTRIBUTE_ENTRIES_TAGS)) {
|
||||
const ArrayValue *array_value = value->get()->as_array_value();
|
||||
for (const ArrayValue::Item &item : array_value->elements()) {
|
||||
if (const ArrayValue *array_value = entry.lookup_array(ATTRIBUTE_ENTRIES_TAGS)) {
|
||||
for (const std::shared_ptr<Value> &item : array_value->elements()) {
|
||||
BKE_asset_metadata_tag_add(asset_data, item->as_string_value()->value().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (const std::shared_ptr<Value> *value = entry.lookup_ptr(ATTRIBUTE_ENTRIES_PROPERTIES)) {
|
||||
if (const std::shared_ptr<Value> *value = entry.lookup(ATTRIBUTE_ENTRIES_PROPERTIES)) {
|
||||
asset_data->properties = convert_from_serialize_value(*value->get());
|
||||
}
|
||||
}
|
||||
@@ -282,20 +258,17 @@ static void init_indexer_entry_from_value(FileIndexerEntry &indexer_entry,
|
||||
static int init_indexer_entries_from_value(FileIndexerEntries &indexer_entries,
|
||||
const DictionaryValue &value)
|
||||
{
|
||||
const DictionaryValue::Lookup attributes = value.create_lookup();
|
||||
const DictionaryValue::LookupValue *entries_value = attributes.lookup_ptr(ATTRIBUTE_ENTRIES);
|
||||
BLI_assert(entries_value != nullptr);
|
||||
|
||||
if (entries_value == nullptr) {
|
||||
const ArrayValue *entries = value.lookup_array(ATTRIBUTE_ENTRIES);
|
||||
BLI_assert(entries != nullptr);
|
||||
if (entries == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int num_entries_read = 0;
|
||||
const ArrayValue::Items elements = (*entries_value)->as_array_value()->elements();
|
||||
for (ArrayValue::Item element : elements) {
|
||||
for (const std::shared_ptr<Value> &element : entries->elements()) {
|
||||
FileIndexerEntry *entry = static_cast<FileIndexerEntry *>(
|
||||
MEM_callocN(sizeof(FileIndexerEntry), __func__));
|
||||
init_indexer_entry_from_value(*entry, element->as_dictionary_value()->create_lookup());
|
||||
init_indexer_entry_from_value(*entry, *element->as_dictionary_value());
|
||||
|
||||
BLI_linklist_prepend(&indexer_entries.entries, entry);
|
||||
num_entries_read += 1;
|
||||
@@ -519,12 +492,8 @@ struct AssetIndex {
|
||||
if (root == nullptr) {
|
||||
return UNKNOWN_VERSION;
|
||||
}
|
||||
const DictionaryValue::Lookup attributes = root->create_lookup();
|
||||
const DictionaryValue::LookupValue *version_value = attributes.lookup_ptr(ATTRIBUTE_VERSION);
|
||||
if (version_value == nullptr) {
|
||||
return UNKNOWN_VERSION;
|
||||
}
|
||||
return (*version_value)->as_int_value()->value();
|
||||
const std::optional<int64_t> version_value = root->lookup_int(ATTRIBUTE_VERSION);
|
||||
return version_value.value_or(UNKNOWN_VERSION);
|
||||
}
|
||||
|
||||
bool is_latest_version() const
|
||||
|
||||
Reference in New Issue
Block a user