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:
Hans Goudey
2024-03-13 14:44:01 -04:00
parent ae12c1bd92
commit b5082f6640
5 changed files with 139 additions and 247 deletions
@@ -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++) {
+27 -49
View File
@@ -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);
+11 -20
View File
@@ -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