Refactor: Geometry Nodes: add BundleKey type

Previously, a raw `UString` was used as bundle key. However, that did not
capture all the constraints put on the key (some characters are forbidden). This
patch adds a smaller `BundleKey` wrapper around `UString` that ensures these
constraints during construction so that code using the type does not have to
check it again.

This might also become useful when we want `Bundle` to become a thinner wrapper
around `Map` instead of duplicating large parts of its interface.

Pull Request: https://projects.blender.org/blender/blender/pulls/159023
This commit is contained in:
Jacques Lucke 2026-05-25 01:01:43 +02:00
parent 578ebff417
commit 761c881737
25 changed files with 285 additions and 189 deletions

View file

@ -1494,8 +1494,8 @@ template<typename T>
if (!io_item) {
return false;
}
const std::optional<std::string> key = io_item->lookup_str("key");
if (!key) {
const std::optional<std::string> key_str = io_item->lookup_str("key");
if (key_str) {
return false;
}
const std::optional<StringRefNull> socket_idname = io_item->lookup_str("socket_idname");
@ -1512,7 +1512,11 @@ template<typename T>
if (!stype) {
return false;
}
r_bundle.add(UString(*key), nodes::BundleItemSocketValue{stype, std::move(*value)});
std::optional<nodes::BundleKey> key = nodes::BundleKey::from_str(*key_str);
if (!key) {
return false;
}
r_bundle.add(*key, nodes::BundleItemSocketValue{stype, std::move(*value)});
}
return true;
}
@ -1525,7 +1529,7 @@ static void serialize_bundle_items(const nodes::Bundle &bundle,
for (const auto &item : bundle.items()) {
if (const auto *socket_value = std::get_if<nodes::BundleItemSocketValue>(&item.value.value)) {
DictionaryValue &io_bundle_item = *r_io_items.append_dict();
io_bundle_item.append_str("key", item.key.string());
io_bundle_item.append_str("key", item.key.ustr().string());
io_bundle_item.append_str("socket_idname", socket_value->type->idname.string());
io::serialize::DictionaryValue &io_bundle_item_value = *io_bundle_item.append_dict("value");
serialize_socket_value_variant(

View file

@ -370,7 +370,7 @@ class RuntimeToBakeValue {
void runtime_to_bake__Bundle(nodes::Bundle &bundle)
{
Vector<UString> values_to_remove;
Vector<nodes::BundleKey> values_to_remove;
for (const auto &item : bundle.items()) {
if (auto *socket_value = std::get_if<nodes::BundleItemSocketValue>(&item.value.value)) {
if (!this->runtime_to_bake__SocketValueVariant(socket_value->value)) {
@ -378,7 +378,7 @@ class RuntimeToBakeValue {
}
}
}
for (const UString &value_to_remove : values_to_remove) {
for (const nodes::BundleKey &value_to_remove : values_to_remove) {
bundle.remove(value_to_remove);
}
}
@ -580,7 +580,7 @@ class BakeToRuntimeValue {
{
for (auto &&item : bundle.items()) {
if (auto *socket_value = std::get_if<nodes::BundleItemSocketValue>(&item.value.value)) {
this->bake_to_runtime__SocketValueVariant(socket_value->value, item.key.ref());
this->bake_to_runtime__SocketValueVariant(socket_value->value, item.key.ustr().ref());
}
}
}

View file

@ -44,7 +44,7 @@ TEST_F(SocketValueVisitorTest, edit_in_nested_mesh)
geometry_set_list.append(std::move(instance_geometry));
nodes::GListPtr list_ptr = nodes::GList::from_container(std::move(geometry_set_list));
nodes::BundlePtr bundle_ptr = nodes::Bundle::create();
bundle_ptr.ensure_mutable_inplace().add("test"_ustr,
bundle_ptr.ensure_mutable_inplace().add(*nodes::BundleKey::from_str("test"),
SocketValueVariant::From(std::move(list_ptr)));
SocketValueVariant value = SocketValueVariant::From(std::move(bundle_ptr));

View file

@ -1100,7 +1100,7 @@ static bool socket_needs_volume_grid_search(const bNode &node, const bNodeSocket
static bool socket_needs_bundle_type_search(const bNode &node, const bNodeSocket &socket)
{
if (node.type_legacy == NODE_COMBINE_BUNDLE) {
return socket.name == nodes::Bundle::type_item_name;
return socket.name == nodes::Bundle::type_item_name.ustr();
}
if (node.is_type("NodeGetNestedBundlePaths"_ustr)) {
return socket.name == StringRef("Bundle Type");

View file

@ -115,7 +115,7 @@ static void bundle_type_string_search_exec(bContext *C, void *data_v, void * /*i
if (item.socket_type != SOCK_STRING) {
return;
}
if (item.name != nodes::Bundle::type_item_name) {
if (item.name != nodes::Bundle::type_item_name.ustr()) {
return;
}
nodes::sync_node(*C, *node, nullptr);

View file

@ -910,8 +910,8 @@ void BundleDataSource::collect_flat_items(const nodes::Bundle &bundle, const Str
{
for (const auto &item : bundle.items()) {
const std::string path = parent_path.is_empty() ?
item.key.string() :
nodes::Bundle::combine_path({parent_path, item.key.ref()});
item.key.ustr().string() :
nodes::Bundle::combine_path({parent_path, item.key.ustr().ref()});
flat_item_keys_.append(path);
flat_items_.append(&item.value);
if (const auto *value = std::get_if<nodes::BundleItemSocketValue>(&item.value.value)) {
@ -1094,9 +1094,16 @@ static bke::SocketValueVariant lookup_bundle_path(const nodes::BundlePtr &bundle
if (path.bundle_path_num == 0) {
return bke::SocketValueVariant::From(bundle);
}
Vector<UString> keys;
Vector<nodes::BundleKey> keys;
for (const int i : IndexRange(path.bundle_path_num)) {
keys.append(UString(path.bundle_path[i].identifier));
if (const std::optional<nodes::BundleKey> key = nodes::BundleKey::from_str(
path.bundle_path[i].identifier))
{
keys.append(*key);
}
else {
return {};
}
}
return bundle->lookup_path<bke::SocketValueVariant>(keys).value_or(bke::SocketValueVariant{});
}

View file

@ -55,7 +55,7 @@ struct GeometryDomainDataId {
};
struct GeometryBundleItemId {
Vector<UString> keys;
Vector<nodes::BundleKey> keys;
SpreadsheetClosureInputOutput closure_in_out = SPREADSHEET_CLOSURE_NONE;
};
@ -69,7 +69,8 @@ struct GeometryDataIdentifier {
{
}
GeometryDataIdentifier(Vector<UString> bundle_keys, SpreadsheetClosureInputOutput closure_in_out)
GeometryDataIdentifier(Vector<nodes::BundleKey> bundle_keys,
SpreadsheetClosureInputOutput closure_in_out)
: id(GeometryBundleItemId{std::move(bundle_keys), closure_in_out})
{
}
@ -568,18 +569,18 @@ class GeometryBundleViewItem : public DataSetViewItem {
std::optional<GeometryDataIdentifier> get_geometry_data_id() const override
{
return GeometryDataIdentifier(Vector<UString>(), SPREADSHEET_CLOSURE_NONE);
return GeometryDataIdentifier(Vector<nodes::BundleKey>(), SPREADSHEET_CLOSURE_NONE);
}
};
class GeometryBundleItemViewItem : public DataSetViewItem {
private:
UString key_;
nodes::BundleKey key_;
public:
GeometryBundleItemViewItem(const UString key) : key_(key)
GeometryBundleItemViewItem(const nodes::BundleKey key) : key_(key)
{
label_ = key_.string();
label_ = key_.ustr().ref();
}
void build_row(ui::Layout &row) override
@ -589,7 +590,7 @@ class GeometryBundleItemViewItem : public DataSetViewItem {
std::optional<GeometryDataIdentifier> get_geometry_data_id() const override
{
Vector<UString> keys;
Vector<nodes::BundleKey> keys;
keys.append(key_);
this->foreach_parent([&](const AbstractTreeViewItem &parent) {
if (const auto *bundle_item = dynamic_cast<const GeometryBundleItemViewItem *>(&parent)) {
@ -896,7 +897,7 @@ void DataSetViewItem::on_activate(bContext &C)
}
else if (const auto *bundle_item_id = std::get_if<GeometryBundleItemId>(&data_id->id)) {
sspreadsheet.geometry_id.geometry_item_type = SPREADSHEET_GEOMETRY_ITEM_TYPE_BUNDLE;
Vector<UString> keys = bundle_item_id->keys.as_span();
Vector<nodes::BundleKey> keys = bundle_item_id->keys.as_span();
spreadsheet_bundle_path_init_from(
keys, bundle_item_id->closure_in_out, sspreadsheet.geometry_id.geometry_bundle_path);
RNA_property_update(&C, &ptr, RNA_struct_find_property(&ptr, "geometry_component_type"));
@ -949,7 +950,7 @@ std::optional<bool> DataSetViewItem::should_be_active() const
}
for (const int i : IndexRange(bundle_item_id->keys.size())) {
if (sspreadsheet.geometry_id.geometry_bundle_path.bundle_path[i].identifier !=
bundle_item_id->keys[i])
bundle_item_id->keys[i].ustr())
{
return false;
}
@ -1218,7 +1219,7 @@ class ViewerDataTreeItem : public ui::AbstractTreeViewItem {
struct ViewerDataPath {
int viewer_item;
Vector<UString> bundles;
Vector<nodes::BundleKey> bundles;
SpreadsheetClosureInputOutput closure_input_output = SPREADSHEET_CLOSURE_NONE;
friend bool operator==(const ViewerDataPath &a, const ViewerDataPath &b) = default;
@ -1230,7 +1231,11 @@ struct ViewerDataPath {
for (const auto &elem : Span(table_id.viewer_item_bundle_path.bundle_path,
table_id.viewer_item_bundle_path.bundle_path_num))
{
this->bundles.append(UString(elem.identifier));
const std::optional<nodes::BundleKey> key = nodes::BundleKey::from_str(elem.identifier);
if (!key) {
continue;
}
this->bundles.append(*key);
}
this->closure_input_output = SpreadsheetClosureInputOutput(
table_id.viewer_item_bundle_path.closure_input_output);
@ -1268,9 +1273,9 @@ class BundleViewerTreeItem : public ViewerDataTreeItem {
friend ViewerDataPath;
public:
BundleViewerTreeItem(const UString key)
BundleViewerTreeItem(const nodes::BundleKey key)
{
label_ = key.string();
label_ = key.ustr().ref();
}
void build_row(ui::Layout &row) override
@ -1304,7 +1309,11 @@ ViewerDataPath::ViewerDataPath(const Span<const ViewerDataTreeItem *> tree_items
this->viewer_item = viewer_node_item->item_.identifier;
}
else if (const auto *bundle_item = dynamic_cast<const BundleViewerTreeItem *>(item)) {
this->bundles.append(UString(bundle_item->label_));
if (const std::optional<nodes::BundleKey> key = nodes::BundleKey::from_str(
bundle_item->label_))
{
this->bundles.append(*key);
}
}
else if (const auto *bundle_item = dynamic_cast<const ClosureInOutViewerTreeItem *>(item)) {
this->closure_input_output = bundle_item->in_out_;

View file

@ -12,6 +12,7 @@
#include "BLO_read_write.hh"
#include "NOD_geometry_nodes_bundle.hh"
#include "spreadsheet_column.hh"
#include "spreadsheet_table.hh"
@ -72,7 +73,7 @@ void spreadsheet_bundle_path_clear(SpreadsheetBundleTreeViewPath &bundle_path)
}
void spreadsheet_bundle_path_init_from(
const Span<UString> keys,
const Span<nodes::BundleKey> keys,
const std::optional<SpreadsheetClosureInputOutput> closure_input_output,
SpreadsheetBundleTreeViewPath &r_bundle_path)
{
@ -80,7 +81,7 @@ void spreadsheet_bundle_path_init_from(
r_bundle_path.bundle_path = MEM_new_array<SpreadsheetBundlePathElem>(keys.size(), __func__);
r_bundle_path.bundle_path_num = keys.size();
for (const int i : keys.index_range()) {
const StringRef key = keys[i].ref();
const StringRef key = keys[i].ustr().ref();
r_bundle_path.bundle_path[i].identifier = BLI_strdupn(key.data(), key.size());
}
r_bundle_path.closure_input_output = closure_input_output.value_or(SPREADSHEET_CLOSURE_NONE);

View file

@ -10,6 +10,8 @@
#include "DNA_space_types.h"
#include "NOD_geometry_nodes_bundle.hh"
namespace blender::ed::spreadsheet {
SpreadsheetTableIDGeometry *spreadsheet_table_id_new_geometry();
@ -28,7 +30,7 @@ void spreadsheet_table_id_foreach_id(SpreadsheetTableID &table_id, LibraryForeac
void spreadsheet_bundle_path_clear(SpreadsheetBundleTreeViewPath &bundle_path);
void spreadsheet_bundle_path_init_from(
Span<UString> keys,
Span<nodes::BundleKey> keys,
std::optional<SpreadsheetClosureInputOutput> closure_input_output,
SpreadsheetBundleTreeViewPath &r_bundle_path);

View file

@ -80,7 +80,7 @@ void RNA_api_text(StructRNA *srna)
parm = RNA_def_string(func, "text", "Text", 0, "", "New text for this data-block");
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
func = RNA_def_function(srna, "from_string", "rna_Text_from_string");
func = RNA_def_function(srna, "from_str", "rna_Text_from_string");
RNA_def_function_ui_description(func, "Replace text with this string.");
parm = RNA_def_string(func, "text", "Text", 0, "", "");
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);

View file

@ -56,6 +56,28 @@ struct BundleItemValue {
template<typename T> const T *as_pointer() const;
};
class BundleKey {
private:
UString key_;
BundleKey(UString key);
public:
static std::optional<BundleKey> from_ustr(UString key);
static std::optional<BundleKey> from_str(StringRef key);
uint64_t hash() const;
bool operator==(const BundleKey &other) const = default;
UString ustr() const;
/* Disallow certain characters so that we can use them to e.g. build a bundle path or
* expressions referencing multiple bundle items. We might not need all of them in the future,
* but better reserve them now while we still can. */
static constexpr StringRefNull forbidden_key_chars = "/*&|\"^~!,{}()+$#@[];:?<>.-%\\=";
static bool is_valid_key(StringRef key);
};
/**
* A bundle is a map containing keys and their corresponding values.
*
@ -63,33 +85,33 @@ struct BundleItemValue {
*/
class Bundle : public ImplicitSharingMixin {
public:
using BundleItemMap = Map<UString, BundleItemValue>;
using BundleItemMap = Map<BundleKey, BundleItemValue>;
private:
BundleItemMap items_;
public:
static inline UString type_item_name = "Type"_ustr;
static inline BundleKey type_item_name = *BundleKey::from_str("Type");
static BundlePtr create();
bool add(UString key, const BundleItemValue &value);
bool add(UString key, BundleItemValue &&value);
void add_new(UString key, const BundleItemValue &value);
void add_new(UString key, BundleItemValue &&value);
void add_override(UString key, const BundleItemValue &value);
bool add(BundleKey key, const BundleItemValue &value);
bool add(BundleKey key, BundleItemValue &&value);
void add_new(BundleKey key, const BundleItemValue &value);
void add_new(BundleKey key, BundleItemValue &&value);
void add_override(BundleKey key, const BundleItemValue &value);
bool add_path(StringRef path, const BundleItemValue &value);
void add_path_new(StringRef path, const BundleItemValue &value);
void add_path_override(StringRef path, const BundleItemValue &value);
template<typename T>
requires(!std::is_same_v<std::decay_t<T>, BundleItemValue>)
void add(UString key, T &&value);
void add(BundleKey key, T &&value);
template<typename T>
requires(!std::is_same_v<std::decay_t<T>, BundleItemValue>)
void add_new(UString key, T &&value);
void add_new(BundleKey key, T &&value);
template<typename T>
requires(!std::is_same_v<std::decay_t<T>, BundleItemValue>)
void add_override(UString key, T &&value);
void add_override(BundleKey key, T &&value);
template<typename T>
requires(!std::is_same_v<std::decay_t<T>, BundleItemValue>)
void add_path(StringRef path, T &&value);
@ -97,28 +119,28 @@ class Bundle : public ImplicitSharingMixin {
requires(!std::is_same_v<std::decay_t<T>, BundleItemValue>)
void add_path_override(StringRef path, T &&value);
bool remove(UString key);
bool remove(BundleKey key);
bool remove_path(StringRef path);
bool remove_path(Span<UString> path);
bool contains(UString key) const;
bool remove_path(Span<BundleKey> path);
bool contains(BundleKey key) const;
bool contains_path(StringRef path) const;
bool contains_path(Span<UString> path) const;
bool contains_path(Span<BundleKey> path) const;
const BundleItemValue *lookup(UString key) const;
BundleItemValue *lookup(UString key);
const BundleItemValue *lookup_path(Span<UString> path) const;
const BundleItemValue *lookup(BundleKey key) const;
BundleItemValue *lookup(BundleKey key);
const BundleItemValue *lookup_path(Span<BundleKey> path) const;
const BundleItemValue *lookup_path(StringRef path) const;
BundleItemValue *lookup_path_for_write(Span<UString> path);
BundleItemValue *lookup_path_for_write(Span<BundleKey> path);
BundleItemValue *lookup_path_for_write(StringRef path);
template<typename T> std::optional<T> lookup(UString key) const;
template<typename T> std::optional<T> lookup_path(Span<UString> path) const;
template<typename T> std::optional<T> lookup(BundleKey key) const;
template<typename T> std::optional<T> lookup_path(Span<BundleKey> path) const;
template<typename T> std::optional<T> lookup_path(StringRef path) const;
template<typename T> T *lookup_ptr(UString key);
template<typename T> const T *lookup_ptr(UString key) const;
template<typename T> T *lookup_ptr(BundleKey key);
template<typename T> const T *lookup_ptr(BundleKey key) const;
template<typename T> const T *lookup_path_ptr(StringRef path) const;
template<typename T> const T *lookup_path_ptr(Span<UString> path) const;
template<typename T> const T *lookup_path_ptr(Span<BundleKey> path) const;
template<typename T> T *lookup_path_for_write_ptr(StringRef path);
template<typename T> T *lookup_path_for_write_ptr(Span<UString> path);
template<typename T> T *lookup_path_for_write_ptr(Span<BundleKey> path);
Bundle &ensure_nested_bundle(StringRef path);
@ -149,15 +171,10 @@ class Bundle : public ImplicitSharingMixin {
/** Create the combined path by inserting '/' between each element. */
static std::string combine_path(Span<StringRef> path);
static std::string combine_path(Span<UString> path);
static std::string combine_path(Span<BundleKey> path);
/* Disallow certain characters so that we can use them to e.g. build a bundle path or
* expressions referencing multiple bundle items. We might not need all of them in the future,
* but better reserve them now while we still can. */
static constexpr StringRefNull forbidden_key_chars = "/*&|\"^~!,{}()+$#@[];:?<>.-%\\=";
static bool is_valid_key(StringRef key);
static bool is_valid_path(StringRef path);
static std::optional<Vector<UString>> split_path(StringRef path);
static std::optional<Vector<BundleKey>> split_path(StringRef path);
};
enum class BundlePathsGatherFilterResult {
@ -172,7 +189,8 @@ Vector<std::string> gather_bundle_paths_by_data_type(const Bundle &bundle,
eNodeSocketDatatype data_type);
void foreach_nested_bundle_item(
const Bundle &bundle, FunctionRef<void(Span<UString> path, const BundleItemValue &value)> fn);
const Bundle &bundle,
FunctionRef<void(Span<BundleKey> path, const BundleItemValue &value)> fn);
template<typename T>
inline std::optional<T> BundleItemValue::as_socket_value(
@ -277,7 +295,7 @@ template<typename T> inline std::optional<T> BundleItemValue::as() const
return std::nullopt;
}
template<typename T> inline std::optional<T> Bundle::lookup(const UString key) const
template<typename T> inline std::optional<T> Bundle::lookup(const BundleKey key) const
{
const BundleItemValue *item = this->lookup(key);
if (!item) {
@ -286,7 +304,7 @@ template<typename T> inline std::optional<T> Bundle::lookup(const UString key) c
return item->as<T>();
}
template<typename T> inline T *Bundle::lookup_ptr(const UString key)
template<typename T> inline T *Bundle::lookup_ptr(const BundleKey key)
{
BundleItemValue *item = this->lookup(key);
return item ? item->as_pointer<T>() : nullptr;
@ -298,19 +316,19 @@ template<typename T> inline const T *Bundle::lookup_path_ptr(const StringRef pat
return item ? item->as_pointer<T>() : nullptr;
}
template<typename T> inline const T *Bundle::lookup_path_ptr(const Span<UString> path) const
template<typename T> inline const T *Bundle::lookup_path_ptr(const Span<BundleKey> path) const
{
const BundleItemValue *item = this->lookup_path(path);
return item ? item->as_pointer<T>() : nullptr;
}
template<typename T> inline const T *Bundle::lookup_ptr(const UString key) const
template<typename T> inline const T *Bundle::lookup_ptr(const BundleKey key) const
{
const BundleItemValue *item = this->lookup(key);
return item ? item->as_pointer<T>() : nullptr;
}
template<typename T> inline T *Bundle::lookup_path_for_write_ptr(const Span<UString> path)
template<typename T> inline T *Bundle::lookup_path_for_write_ptr(const Span<BundleKey> path)
{
BundleItemValue *item = this->lookup_path_for_write(path);
return item ? item->as_pointer<T>() : nullptr;
@ -322,7 +340,7 @@ template<typename T> inline T *Bundle::lookup_path_for_write_ptr(const StringRef
return item ? item->as_pointer<T>() : nullptr;
}
template<typename T> inline std::optional<T> Bundle::lookup_path(const Span<UString> path) const
template<typename T> inline std::optional<T> Bundle::lookup_path(const Span<BundleKey> path) const
{
const BundleItemValue *item = this->lookup_path(path);
if (!item) {
@ -376,7 +394,7 @@ template<typename T, typename Fn> inline void to_stored_type(T &&value, Fn &&fn)
template<typename T>
requires(!std::is_same_v<std::decay_t<T>, BundleItemValue>)
inline void Bundle::add(const UString key, T &&value)
inline void Bundle::add(const BundleKey key, T &&value)
{
to_stored_type(std::forward<T>(value),
[&]<typename U>(U &&item_value) { this->add(key, std::forward<U>(item_value)); });
@ -384,7 +402,7 @@ inline void Bundle::add(const UString key, T &&value)
template<typename T>
requires(!std::is_same_v<std::decay_t<T>, BundleItemValue>)
inline void Bundle::add_new(const UString key, T &&value)
inline void Bundle::add_new(const BundleKey key, T &&value)
{
to_stored_type(std::forward<T>(value), [&]<typename U>(U &&item_value) {
this->add_new(key, std::forward<U>(item_value));
@ -402,7 +420,7 @@ inline void Bundle::add_path(const StringRef path, T &&value)
template<typename T>
requires(!std::is_same_v<std::decay_t<T>, BundleItemValue>)
inline void Bundle::add_override(const UString key, T &&value)
inline void Bundle::add_override(const BundleKey key, T &&value)
{
to_stored_type(std::forward<T>(value), [&]<typename U>(U &&item_value) {
this->add_override(key, std::forward<U>(item_value));
@ -438,4 +456,38 @@ inline int64_t Bundle::size() const
return items_.size();
}
inline BundleKey::BundleKey(const UString key) : key_(key) {}
inline uint64_t BundleKey::hash() const
{
return get_default_hash(key_);
}
std::optional<BundleKey> inline BundleKey::from_ustr(const UString key)
{
if (is_valid_key(key.ref())) {
return BundleKey(key);
}
return std::nullopt;
}
std::optional<BundleKey> inline BundleKey::from_str(const StringRef key)
{
/* Check validity before converting to UString. */
if (is_valid_key(key)) {
return BundleKey(UString(key));
}
return std::nullopt;
}
inline UString BundleKey::ustr() const
{
return key_;
}
inline std::string_view format_as(const BundleKey key)
{
return key.ustr().ref();
}
} // namespace blender::nodes

View file

@ -58,9 +58,9 @@ class StringPattern {
* Create a new pattern. If the pattern is invalid, nullopt is returned and the error message is
* set.
*/
static std::optional<StringPattern> from_string(StringPatternMode mode,
StringRef pattern,
std::string &r_error);
static std::optional<StringPattern> from_str(StringPatternMode mode,
StringRef pattern,
std::string &r_error);
/** Returns true if the string matches the pattern. */
bool match(StringRef query) const;

View file

@ -65,7 +65,7 @@ static void node_declare(NodeDeclarationBuilder &b)
}
}
if (i == 0 && socket_type == SOCK_STRING && name == Bundle::type_item_name) {
if (i == 0 && socket_type == SOCK_STRING && name == Bundle::type_item_name.ustr()) {
decl.optional_label();
b.add_separator();
}
@ -156,12 +156,13 @@ static void node_geo_exec(GeoNodeExecParams params)
continue;
}
const StringRef name = item.name;
if (!Bundle::is_valid_key(name)) {
const std::optional<BundleKey> key = BundleKey::from_str(name);
if (!key) {
continue;
}
bke::SocketValueVariant value = params.extract_input<bke::SocketValueVariant>(
node.input_socket(i).identifier_ustr());
bundle.add(UString(name), BundleItemSocketValue{stype, std::move(value)});
bundle.add(*key, BundleItemSocketValue{stype, std::move(value)});
}
params.set_output("Bundle"_ustr, std::move(bundle_ptr));
@ -252,7 +253,7 @@ std::string CombineBundleItemsAccessor::validate_name(const StringRef name)
if (name.is_empty()) {
return result;
}
const Span<char> forbidden_chars = Bundle::forbidden_key_chars;
const Span<char> forbidden_chars = BundleKey::forbidden_key_chars;
for (const char c : name) {
if (forbidden_chars.contains(c)) {
result += '_';
@ -272,7 +273,7 @@ std::string CombineBundleItemsAccessor::validate_name(const StringRef name)
result[last_index] = '_';
}
}
BLI_assert(Bundle::is_valid_key(result));
BLI_assert(BundleKey::is_valid_key(result));
return result;
}
@ -285,7 +286,7 @@ std::optional<StringRefNull> combine_bundle_node_type(const bNodeTree & /*tree*/
if (socket.type != SOCK_STRING) {
continue;
}
if (socket.name != Bundle::type_item_name) {
if (socket.name != Bundle::type_item_name.ustr()) {
continue;
}
return socket.default_value_typed<bNodeSocketValueString>()->value;

View file

@ -71,10 +71,10 @@ static void node_geo_exec(GeoNodeExecParams params)
Vector<std::string> paths;
switch (mode) {
case Mode::All: {
foreach_nested_bundle_item(bundle,
[&](const Span<UString> path, const BundleItemValue & /*value*/) {
paths.append(Bundle::combine_path(path));
});
foreach_nested_bundle_item(
bundle, [&](const Span<BundleKey> path, const BundleItemValue & /*value*/) {
paths.append(Bundle::combine_path(path));
});
break;
}
case Mode::BundleType: {
@ -82,7 +82,7 @@ static void node_geo_exec(GeoNodeExecParams params)
const StringPatternMode pattern_mode = params.extract_input<StringPatternMode>(
"Pattern Mode"_ustr);
std::string pattern_error;
std::optional<StringPattern> pattern_fn = StringPattern::from_string(
std::optional<StringPattern> pattern_fn = StringPattern::from_str(
pattern_mode, type_pattern, pattern_error);
if (!pattern_fn) {
params.error_message_add(NodeWarningType::Error, pattern_error);

View file

@ -50,7 +50,7 @@ static void node_geo_exec(GeoNodeExecParams params)
}
Bundle &mutable_output_bundle = output_bundle.ensure_mutable_inplace();
VectorSet<UString> overridden_keys;
VectorSet<BundleKey> overridden_keys;
for (; bundle_i < bundles.values.size(); bundle_i++) {
BundlePtr &bundle = bundles.values[bundle_i];
if (!bundle) {

View file

@ -103,7 +103,7 @@ static void node_geo_exec(GeoNodeExecParams params)
}
std::string pattern_error;
std::optional<StringPattern> pattern_fn = StringPattern::from_string(
std::optional<StringPattern> pattern_fn = StringPattern::from_str(
params.get_input<StringPatternMode>("Pattern Mode"_ustr), pattern, pattern_error);
if (!pattern_fn) {
params.error_message_add(NodeWarningType::Error, pattern_error);

View file

@ -139,14 +139,15 @@ static void node_geo_exec(GeoNodeExecParams params)
for (const int i : IndexRange(storage.items_num)) {
const NodeSeparateBundleItem &item = storage.items[i];
const StringRef name = item.name;
if (!Bundle::is_valid_key(name)) {
std::optional<BundleKey> key = BundleKey::from_str(name);
if (!key) {
continue;
}
const bke::bNodeSocketType *stype = bke::node_socket_type_find_static(item.socket_type);
if (!stype || !stype->geometry_nodes_default_value) {
continue;
}
const BundleItemValue *value = bundle->lookup(UString(name));
const BundleItemValue *value = bundle->lookup(*key);
if (!value) {
params.error_message_add(
NodeWarningType::Error,

View file

@ -403,7 +403,7 @@ static void node_geo_exec(GeoNodeExecParams params)
if (attribute_patterns_list->cpp_type().is<std::string>()) {
attribute_patterns_list.typed<std::string>()->foreach([&](const std::string &pattern) {
std::string error;
if (std::optional<StringPattern> pattern_fn = StringPattern::from_string(
if (std::optional<StringPattern> pattern_fn = StringPattern::from_str(
pattern_mode, pattern, error))
{
patterns.append(std::move(*pattern_fn));

View file

@ -673,7 +673,7 @@ class XpbdSolverStep {
void gather_nested_bundle_paths()
{
foreach_nested_bundle_item(world_,
[&](const Span<UString> path, const BundleItemValue &value) {
[&](const Span<BundleKey> path, const BundleItemValue &value) {
const BundlePtr *bundle_ptr = value.as_pointer<BundlePtr>();
if (!bundle_ptr || !*bundle_ptr) {
return;
@ -830,17 +830,23 @@ class XpbdSolverStep {
}
const Bundle &bundle = **bundle_ptr;
const Bundle *previous_bundle = this->get_previous_bundle(bundle);
const bke::GeometrySet *geometry = bundle.lookup_ptr<bke::GeometrySet>("geometry"_ustr);
const float margin = bundle.lookup<float>("margin"_ustr).value_or(0.0f);
const float friction = bundle.lookup<float>("friction"_ustr).value_or(0.0f);
const float compliance = bundle.lookup<float>("compliance"_ustr).value_or(0.0f);
const bool deforming = bundle.lookup<bool>("deforming"_ustr).value_or(false);
const bool use_edge_contacts = bundle.lookup<bool>("use_edge_contacts"_ustr).value_or(false);
const bool is_boundary = bundle.lookup<bool>("is_boundary"_ustr).value_or(false);
const float error_threshold = bundle.lookup<float>("error_threshold"_ustr).value_or(1e-3f);
const bke::GeometrySet *geometry = bundle.lookup_ptr<bke::GeometrySet>(
*BundleKey::from_str("geometry"));
const float margin = bundle.lookup<float>(*BundleKey::from_str("margin")).value_or(0.0f);
const float friction = bundle.lookup<float>(*BundleKey::from_str("friction")).value_or(0.0f);
const float compliance =
bundle.lookup<float>(*BundleKey::from_str("compliance")).value_or(0.0f);
const bool deforming =
bundle.lookup<bool>(*BundleKey::from_str("deforming")).value_or(false);
const bool use_edge_contacts =
bundle.lookup<bool>(*BundleKey::from_str("use_edge_contacts")).value_or(false);
const bool is_boundary =
bundle.lookup<bool>(*BundleKey::from_str("is_boundary")).value_or(false);
const float error_threshold =
bundle.lookup<float>(*BundleKey::from_str("error_threshold")).value_or(1e-3f);
const bke::GeometrySet *prev_geometry = previous_bundle ?
previous_bundle->lookup_ptr<bke::GeometrySet>(
"geometry"_ustr) :
*BundleKey::from_str("geometry")) :
nullptr;
if (!geometry) {
continue;
@ -1603,11 +1609,16 @@ class XpbdSolverStep {
const Bundle &bundle = **world_.lookup_path_ptr<BundlePtr>(path);
RodStretchShearConstraint constraint;
constraint.path = path;
constraint.error_threshold = bundle.lookup<float>("error_threshold"_ustr).value_or(1e-3f);
constraint.lambda_pos_attr =
bundle.lookup<std::string>("lambda_position_attribute"_ustr).value_or("");
constraint.lambda_rot_attr =
bundle.lookup<std::string>("lambda_rotation_attribute"_ustr).value_or("");
constraint.error_threshold =
bundle.lookup<float>(*BundleKey::from_str("error_threshold")).value_or(1e-3f);
constraint.lambda_pos_attr = bundle
.lookup<std::string>(
*BundleKey::from_str("lambda_position_attribute"))
.value_or("");
constraint.lambda_rot_attr = bundle
.lookup<std::string>(
*BundleKey::from_str("lambda_rotation_attribute"))
.value_or("");
const int constraint_i = constraints_.rod_stretch_shear_constraints.append_and_get_index(
std::move(constraint));
@ -1729,7 +1740,8 @@ class XpbdSolverStep {
RodBendTwistConstraint constraint;
constraint.path = path;
constraint.error_threshold = bundle.lookup<float>("error_threshold"_ustr).value_or(1e-2f);
constraint.error_threshold =
bundle.lookup<float>(*BundleKey::from_str("error_threshold")).value_or(1e-2f);
const int constraint_i = constraints_.rod_bend_twist_constraints.append_and_get_index(
std::move(constraint));
@ -1805,7 +1817,8 @@ class XpbdSolverStep {
for (const StringRef path : paths) {
const Bundle &bundle = **world_.lookup_path_ptr<BundlePtr>(path);
const float error_threshold = bundle.lookup<float>("error_threshold"_ustr).value_or(1e-3f);
const float error_threshold =
bundle.lookup<float>(*BundleKey::from_str("error_threshold")).value_or(1e-3f);
const int constraint_i = constraints_.edge_length_constraints.append_and_get_index(
{path, error_threshold});
@ -1868,7 +1881,8 @@ class XpbdSolverStep {
CrossEdgeLengthConstraintBundle::name);
for (const StringRef path : paths) {
const Bundle &bundle = **world_.lookup_path_ptr<BundlePtr>(path);
const float error_threshold = bundle.lookup<float>("error_threshold"_ustr).value_or(1e-3f);
const float error_threshold =
bundle.lookup<float>(*BundleKey::from_str("error_threshold")).value_or(1e-3f);
const int constraint_i = constraints_.cross_edge_length_constraints.append_and_get_index(
{path, error_threshold});
for (const int data_key_i : geometries_.data.index_range()) {
@ -2092,8 +2106,10 @@ class XpbdSolverStep {
const Bundle &bundle = **world_.lookup_path_ptr<BundlePtr>(path);
PinPositionConstraint constraint;
constraint.path = path;
constraint.error_threshold = bundle.lookup<float>("error_threshold"_ustr).value_or(1e-3f);
constraint.lambda_attr = bundle.lookup<std::string>("lambda_attribute"_ustr).value_or("");
constraint.error_threshold =
bundle.lookup<float>(*BundleKey::from_str("error_threshold")).value_or(1e-3f);
constraint.lambda_attr =
bundle.lookup<std::string>(*BundleKey::from_str("lambda_attribute")).value_or("");
const int constraint_i = constraints_.pin_position_constraints.append_and_get_index(
std::move(constraint));
@ -2248,7 +2264,8 @@ class XpbdSolverStep {
PinRotationConstraint constraint;
constraint.path = path;
constraint.error_threshold = bundle.lookup<float>("error_threshold"_ustr).value_or(1e-2f);
constraint.error_threshold =
bundle.lookup<float>(*BundleKey::from_str("error_threshold")).value_or(1e-2f);
const int constraint_i = constraints_.pin_rotation_constraints.append_and_get_index(
std::move(constraint));
@ -2929,7 +2946,8 @@ class XpbdSolverStep {
const Bundle *get_previous_bundle(const Bundle &bundle) const
{
const BundlePtr *previous_bundle_ptr = bundle.lookup_ptr<BundlePtr>("previous"_ustr);
const BundlePtr *previous_bundle_ptr = bundle.lookup_ptr<BundlePtr>(
*BundleKey::from_str("previous"));
if (!previous_bundle_ptr || !*previous_bundle_ptr) {
return nullptr;
}
@ -2944,7 +2962,8 @@ class XpbdSolverStep {
const GeometrySetData &geo_set_data = geometries_.geometry_sets[data_key.geo_bundle_i];
const StringRef geo_bundle_path = geo_set_data.path;
const bool filter_local = effector.lookup<bool>("filter_local"_ustr).value_or(false);
const bool filter_local =
effector.lookup<bool>(*BundleKey::from_str("filter_local")).value_or(false);
if (filter_local) {
const int pos = effector_path.rfind('/');
if (pos == StringRef::not_found) {
@ -2957,7 +2976,8 @@ class XpbdSolverStep {
}
return false;
}
const std::string filter = effector.lookup<std::string>("filter"_ustr).value_or("");
const std::string filter =
effector.lookup<std::string>(*BundleKey::from_str("filter")).value_or("");
const bool match = tag_filter_matches(filter, geo_set_data.tags);
return match;
}
@ -3322,7 +3342,7 @@ static void node_geo_exec(GeoNodeExecParams params)
if (!solver_path.empty()) {
BundlePtr solver_data_ptr = Bundle::create();
Bundle &solver_data = solver_data_ptr.ensure_mutable_inplace();
solver_data.add_path(Bundle::type_item_name.string(), std::string(XPBDSolverDataBundle::name));
solver_data.add(Bundle::type_item_name, std::string(XPBDSolverDataBundle::name));
solver_data.add_path("residual_error", step.result().total_residual_error);
world.add_path_override(solver_path, std::move(solver_data_ptr));
}

View file

@ -34,7 +34,7 @@ FlatBundleTypePtr FlatBundleTypeBuilder::build()
BundleSignature FlatBundleType::to_bundle_signature() const
{
BundleSignature signature;
signature.add(Bundle::type_item_name.string(), SOCK_STRING);
signature.add(Bundle::type_item_name.ustr().string(), SOCK_STRING);
for (const Item &item : items_) {
signature.add(item.name().ref(), item.decl->socket_type);
}

View file

@ -370,12 +370,12 @@ void NodeTreeLogger::log_value(const bNode &node, const bNodeSocket &socket, con
if (const BundleItemSocketValue *socket_value = std::get_if<BundleItemSocketValue>(
&item.value.value))
{
items.append({item.key, {socket_value->type}});
items.append({item.key.ustr(), {socket_value->type}});
}
if (const BundleItemInternalValue *internal_value = std::get_if<BundleItemInternalValue>(
&item.value.value))
{
items.append({item.key, {internal_value->value->type_name()}});
items.append({item.key.ustr(), {internal_value->value->type_name()}});
}
}
}

View file

@ -32,17 +32,18 @@ void BundleSignature::set_auto_structure_types()
}
}
bool Bundle::is_valid_key(const StringRef key)
bool BundleKey::is_valid_key(const StringRef key)
{
if (key.is_empty()) {
return false;
}
if (key != key.trim()) {
/* Keys must not have leading or trailing white-space. This simplifies potentially using these
/* Keys must not have leading or trailing white-space. This simplifies potentially using
these
* keys in expressions later on (or even just have a comma separated list of keys). */
return false;
}
return key.find_first_of(Bundle::forbidden_key_chars) == StringRef::not_found;
return key.find_first_of(BundleKey::forbidden_key_chars) == StringRef::not_found;
}
bool Bundle::is_valid_path(const StringRef path)
@ -50,29 +51,30 @@ bool Bundle::is_valid_path(const StringRef path)
return split_path(path).has_value();
}
std::optional<Vector<UString>> Bundle::split_path(const StringRef path)
std::optional<Vector<BundleKey>> Bundle::split_path(const StringRef path)
{
if (path.is_empty()) {
return std::nullopt;
}
Vector<UString> path_elems;
Vector<BundleKey> path_elems;
StringRef remaining = path;
while (!remaining.is_empty()) {
const int sep = remaining.find_first_of('/');
if (sep == StringRef::not_found) {
const StringRef key = remaining;
if (!is_valid_key(key)) {
return std::nullopt;
const StringRef key_str = remaining;
if (const std::optional<BundleKey> key = BundleKey::from_str(key_str)) {
path_elems.append(*key);
}
path_elems.append(UString(key));
break;
}
const StringRef key = remaining.substr(0, sep);
if (!is_valid_key(key)) {
const StringRef key_str = remaining.substr(0, sep);
if (const std::optional<BundleKey> key = BundleKey::from_str(key_str)) {
path_elems.append(*key);
remaining = remaining.substr(sep + 1);
}
else {
return std::nullopt;
}
path_elems.append(UString(key));
remaining = remaining.substr(sep + 1);
}
return path_elems;
}
@ -82,25 +84,23 @@ BundlePtr Bundle::create()
return BundlePtr(MEM_new<Bundle>(__func__));
}
void Bundle::add_new(const UString key, const BundleItemValue &value)
void Bundle::add_new(const BundleKey key, const BundleItemValue &value)
{
BLI_assert(is_valid_key(key.ref()));
items_.add_new_as(key, value);
}
void Bundle::add_new(UString key, BundleItemValue &&value)
void Bundle::add_new(BundleKey key, BundleItemValue &&value)
{
BLI_assert(is_valid_key(key.ref()));
items_.add_new_as(key, std::move(value));
}
void Bundle::add_override(const UString key, const BundleItemValue &value)
void Bundle::add_override(const BundleKey key, const BundleItemValue &value)
{
this->remove(key);
this->add_new(key, value);
}
bool Bundle::add(const UString key, const BundleItemValue &value)
bool Bundle::add(const BundleKey key, const BundleItemValue &value)
{
if (this->contains(key)) {
return false;
@ -109,7 +109,7 @@ bool Bundle::add(const UString key, const BundleItemValue &value)
return true;
}
bool Bundle::add(const UString key, BundleItemValue &&value)
bool Bundle::add(const BundleKey key, BundleItemValue &&value)
{
if (this->contains(key)) {
return false;
@ -129,9 +129,9 @@ static BundleItemValue create_nested_bundle_item()
void Bundle::add_path_override(const StringRef path, const BundleItemValue &value)
{
BLI_assert(is_valid_path(path));
const Vector<UString> path_elems = *split_path(path);
const Vector<BundleKey> path_elems = *split_path(path);
Bundle *current = this;
for (const UString path_elem : path_elems.as_span().drop_back(1)) {
for (const BundleKey path_elem : path_elems.as_span().drop_back(1)) {
BundleItemValue &item = current->items_.lookup_or_add_cb_as(
path_elem, [&]() { return create_nested_bundle_item(); });
BundlePtr *child_bundle_ptr = item.as_pointer<BundlePtr>();
@ -172,22 +172,20 @@ Bundle &Bundle::ensure_nested_bundle(const StringRef path)
return new_bundle_ref;
}
const BundleItemValue *Bundle::lookup(const UString key) const
const BundleItemValue *Bundle::lookup(const BundleKey key) const
{
BLI_assert(is_valid_key(key.ref()));
return items_.lookup_ptr_as(key);
}
BundleItemValue *Bundle::lookup(const UString key)
BundleItemValue *Bundle::lookup(const BundleKey key)
{
BLI_assert(is_valid_key(key.ref()));
return items_.lookup_ptr_as(key);
}
const BundleItemValue *Bundle::lookup_path(const Span<UString> path) const
const BundleItemValue *Bundle::lookup_path(const Span<BundleKey> path) const
{
BLI_assert(!path.is_empty());
const UString first_elem = path[0];
const BundleKey first_elem = path[0];
const BundleItemValue *item = this->lookup(first_elem);
if (!item) {
return nullptr;
@ -205,14 +203,14 @@ const BundleItemValue *Bundle::lookup_path(const Span<UString> path) const
const BundleItemValue *Bundle::lookup_path(const StringRef path) const
{
BLI_assert(is_valid_path(path));
const Vector<UString> path_elems = *split_path(path);
const Vector<BundleKey> path_elems = *split_path(path);
return this->lookup_path(path_elems);
}
BundleItemValue *Bundle::lookup_path_for_write(Span<UString> path)
BundleItemValue *Bundle::lookup_path_for_write(Span<BundleKey> path)
{
BLI_assert(!path.is_empty());
const UString first_elem = path[0];
const BundleKey first_elem = path[0];
BundleItemValue *item = this->lookup(first_elem);
if (!item) {
return nullptr;
@ -234,7 +232,7 @@ BundleItemValue *Bundle::lookup_path_for_write(Span<UString> path)
BundleItemValue *Bundle::lookup_path_for_write(StringRef path)
{
BLI_assert(is_valid_path(path));
const Vector<UString> path_elems = *split_path(path);
const Vector<BundleKey> path_elems = *split_path(path);
return this->lookup_path_for_write(path_elems);
}
@ -281,20 +279,19 @@ BundlePtr Bundle::copy() const
return copy_ptr;
}
bool Bundle::remove(const UString key)
bool Bundle::remove(const BundleKey key)
{
BLI_assert(is_valid_key(key.ref()));
return items_.remove_as(key);
}
bool Bundle::remove_path(const StringRef path)
{
BLI_assert(is_valid_path(path));
const Vector<UString> path_elems = *split_path(path);
const Vector<BundleKey> path_elems = *split_path(path);
return this->remove_path(path_elems);
}
bool Bundle::remove_path(const Span<UString> path)
bool Bundle::remove_path(const Span<BundleKey> path)
{
BLI_assert(this->is_mutable());
BLI_assert(!path.is_empty());
@ -302,7 +299,7 @@ bool Bundle::remove_path(const Span<UString> path)
return false;
}
Bundle *current = this;
for (const UString path_elem : path.drop_back(1)) {
for (const BundleKey path_elem : path.drop_back(1)) {
BundleItemValue &item = current->items_.lookup_as(path_elem);
BundlePtr *child_bundle_ptr = item.as_pointer<BundlePtr>();
current = &child_bundle_ptr->ensure_mutable_inplace();
@ -311,9 +308,8 @@ bool Bundle::remove_path(const Span<UString> path)
return true;
}
bool Bundle::contains(const UString key) const
bool Bundle::contains(const BundleKey key) const
{
BLI_assert(is_valid_key(key.ref()));
return items_.contains_as(key);
}
@ -322,7 +318,7 @@ bool Bundle::contains_path(const StringRef path) const
return this->lookup_path(path) != nullptr;
}
bool Bundle::contains_path(const Span<UString> path) const
bool Bundle::contains_path(const Span<BundleKey> path) const
{
return this->lookup_path(path) != nullptr;
}
@ -332,7 +328,7 @@ std::string Bundle::combine_path(const Span<StringRef> path)
return fmt::format("{}", fmt::join(path, "/"));
}
std::string Bundle::combine_path(const Span<UString> path)
std::string Bundle::combine_path(const Span<BundleKey> path)
{
return fmt::format("{}", fmt::join(path, "/"));
}
@ -453,8 +449,8 @@ std::optional<BundleSignature> LinkedBundleSignatures::get_merged_signature() co
static void foreach_nested_bundle_item_recursive(
const Bundle &bundle,
const FunctionRef<void(Span<UString>, const BundleItemValue &value)> fn,
Vector<UString> &r_path)
const FunctionRef<void(Span<BundleKey>, const BundleItemValue &value)> fn,
Vector<BundleKey> &r_path)
{
for (const auto &child_item : bundle.items()) {
r_path.append(child_item.key);
@ -474,9 +470,10 @@ static void foreach_nested_bundle_item_recursive(
}
void foreach_nested_bundle_item(
const Bundle &bundle, const FunctionRef<void(Span<UString>, const BundleItemValue &value)> fn)
const Bundle &bundle,
const FunctionRef<void(Span<BundleKey>, const BundleItemValue &value)> fn)
{
Vector<UString> path;
Vector<BundleKey> path;
foreach_nested_bundle_item_recursive(bundle, fn, path);
}
@ -484,17 +481,18 @@ Vector<std::string> gather_bundle_paths_by_bundle_type(
const Bundle &bundle, const FunctionRef<bool(StringRef type)> type_filter_fn)
{
Vector<std::string> paths;
foreach_nested_bundle_item(bundle, [&](const Span<UString> path, const BundleItemValue &value) {
if (const BundlePtr *child_bundle_ptr = value.as_pointer<BundlePtr>()) {
if (*child_bundle_ptr) {
if (const std::optional<StringRef> type = (*child_bundle_ptr)->type()) {
if (type_filter_fn(*type)) {
paths.append(Bundle::combine_path(path));
foreach_nested_bundle_item(
bundle, [&](const Span<BundleKey> path, const BundleItemValue &value) {
if (const BundlePtr *child_bundle_ptr = value.as_pointer<BundlePtr>()) {
if (*child_bundle_ptr) {
if (const std::optional<StringRef> type = (*child_bundle_ptr)->type()) {
if (type_filter_fn(*type)) {
paths.append(Bundle::combine_path(path));
}
}
}
}
}
}
});
});
return paths;
}
@ -502,13 +500,14 @@ Vector<std::string> gather_bundle_paths_by_data_type(const Bundle &bundle,
const eNodeSocketDatatype data_type)
{
Vector<std::string> paths;
foreach_nested_bundle_item(bundle, [&](const Span<UString> path, const BundleItemValue &value) {
if (const auto *socket_value = std::get_if<BundleItemSocketValue>(&value.value)) {
if (socket_value->type->type == data_type) {
paths.append(Bundle::combine_path(path));
}
}
});
foreach_nested_bundle_item(
bundle, [&](const Span<BundleKey> path, const BundleItemValue &value) {
if (const auto *socket_value = std::get_if<BundleItemSocketValue>(&value.value)) {
if (socket_value->type->type == data_type) {
paths.append(Bundle::combine_path(path));
}
}
});
return paths;
}

View file

@ -22,10 +22,10 @@ TEST_F(BundleTest, AddItems)
{
BundlePtr bundle_ptr = Bundle::create();
Bundle &bundle = const_cast<Bundle &>(*bundle_ptr);
bundle.add("a"_ustr, 3);
bundle.add(*BundleKey::from_str("a"), 3);
EXPECT_EQ(bundle.size(), 1);
EXPECT_TRUE(bundle.contains("a"_ustr));
EXPECT_EQ(bundle.lookup<int>("a"_ustr), 3);
EXPECT_TRUE(bundle.contains(*BundleKey::from_str("a")));
EXPECT_EQ(bundle.lookup<int>(*BundleKey::from_str("a")), 3);
}
TEST_F(BundleTest, AddLookupPath)
@ -91,7 +91,7 @@ TEST_F(BundleTest, EnsureNestedBundle)
BundlePtr bundle_ptr = Bundle::create();
Bundle &bundle = bundle_ptr.ensure_mutable_inplace();
Bundle &nested_bundle = bundle.ensure_nested_bundle("a/b/c");
nested_bundle.add("test"_ustr, 4);
nested_bundle.add(*BundleKey::from_str("test"), 4);
const std::optional<int> value = bundle.lookup_path<int>("a/b/c/test");
EXPECT_EQ(value, 4);
}

View file

@ -23,9 +23,9 @@ const EnumPropertyItem string_pattern_mode_items[] = {
{0, nullptr, 0, nullptr, nullptr},
};
std::optional<StringPattern> StringPattern::from_string(StringPatternMode mode,
StringRef pattern,
std::string &r_error)
std::optional<StringPattern> StringPattern::from_str(StringPatternMode mode,
StringRef pattern,
std::string &r_error)
{
switch (mode) {
case StringPatternMode::Exact: {

View file

@ -113,7 +113,7 @@ def api_dump(use_properties=True, use_functions=True):
sys.stderr.write("\n\nEOF\n")
else:
text = bpy.data.texts.new(name="api.py")
text.from_string(data)
text.from_str(data)
print("END")