Blender  V3.3
asset_catalog_path.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
8 
9 #include "BLI_path_util.h"
10 
11 namespace blender::bke {
12 
13 const char AssetCatalogPath::SEPARATOR = '/';
14 
15 AssetCatalogPath::AssetCatalogPath(const std::string &path) : path_(path)
16 {
17 }
18 
20 {
21 }
22 
23 AssetCatalogPath::AssetCatalogPath(const char *path) : path_(path)
24 {
25 }
26 
28  : path_(std::move(other_path.path_))
29 {
30 }
31 
33 {
34  std::hash<std::string> hasher{};
35  return hasher(this->path_);
36 }
37 
39 {
40  return this->path_.length();
41 }
42 
43 const char *AssetCatalogPath::c_str() const
44 {
45  return this->path_.c_str();
46 }
47 
48 const std::string &AssetCatalogPath::str() const
49 {
50  return this->path_;
51 }
52 
54 {
55  const size_t last_sep_index = this->path_.rfind(SEPARATOR);
56  if (last_sep_index == std::string::npos) {
57  return StringRefNull(this->path_);
58  }
59 
60  return StringRefNull(this->path_.c_str() + last_sep_index + 1);
61 }
62 
63 bool AssetCatalogPath::operator==(const AssetCatalogPath &other_path) const
64 {
65  return this->path_ == other_path.path_;
66 }
67 
68 bool AssetCatalogPath::operator!=(const AssetCatalogPath &other_path) const
69 {
70  return !(*this == other_path);
71 }
72 
73 bool AssetCatalogPath::operator<(const AssetCatalogPath &other_path) const
74 {
75  return this->path_ < other_path.path_;
76 }
77 
79 {
80  /* `"" / "path"` or `"path" / ""` should just result in `"path"` */
81  if (!*this) {
82  return path_to_append;
83  }
84  if (!path_to_append) {
85  return *this;
86  }
87 
88  std::stringstream new_path;
89  new_path << this->path_ << SEPARATOR << path_to_append.path_;
90  return AssetCatalogPath(new_path.str());
91 }
92 
93 AssetCatalogPath::operator bool() const
94 {
95  return !this->path_.empty();
96 }
97 
98 std::ostream &operator<<(std::ostream &stream, const AssetCatalogPath &path_to_append)
99 {
100  stream << path_to_append.path_;
101  return stream;
102 }
103 
105 {
106  std::stringstream clean_components;
107  bool first_component_seen = false;
108 
109  this->iterate_components([&clean_components, &first_component_seen](StringRef component_name,
110  bool /*is_last_component*/) {
111  const std::string clean_component = cleanup_component(component_name);
112 
113  if (clean_component.empty()) {
114  /* These are caused by leading, trailing, or double slashes. */
115  return;
116  }
117 
118  /* If a previous path component has been streamed already, we need a path separator. This
119  * cannot use the `is_last_component` boolean, because the last component might be skipped due
120  * to the condition above. */
121  if (first_component_seen) {
122  clean_components << SEPARATOR;
123  }
124  first_component_seen = true;
125 
126  clean_components << clean_component;
127  });
128 
129  return AssetCatalogPath(clean_components.str());
130 }
131 
133 {
134  std::string cleaned = component.trim();
135  /* Replace colons with something else, as those are used in the CDF file as delimiter. */
136  std::replace(cleaned.begin(), cleaned.end(), ':', '-');
137  return cleaned;
138 }
139 
141 {
142  if (!other_path) {
143  /* The empty path contains all other paths. */
144  return true;
145  }
146 
147  if (this->path_ == other_path.path_) {
148  /* Weak is-in relation: equal paths contain each other. */
149  return true;
150  }
151 
152  /* To be a child path of 'other_path', our path must be at least a separator and another
153  * character longer. */
154  if (this->length() < other_path.length() + 2) {
155  return false;
156  }
157 
158  /* Create StringRef to be able to use .startswith(). */
159  const StringRef this_path(this->path_);
160  const bool prefix_ok = this_path.startswith(other_path.path_);
161  const char next_char = this_path[other_path.length()];
162  return prefix_ok && next_char == SEPARATOR;
163 }
164 
166 {
167  if (!*this) {
168  return AssetCatalogPath("");
169  }
170  std::string::size_type last_sep_index = this->path_.rfind(SEPARATOR);
171  if (last_sep_index == std::string::npos) {
172  return AssetCatalogPath("");
173  }
174  return AssetCatalogPath(this->path_.substr(0, last_sep_index));
175 }
176 
178 {
179  const char *next_slash_ptr;
180 
181  for (const char *path_component = this->path_.data(); path_component && path_component[0];
182  /* Jump to one after the next slash if there is any. */
183  path_component = next_slash_ptr ? next_slash_ptr + 1 : nullptr) {
184  /* Note that this also treats backslashes as component separators, which
185  * helps in cleaning up backslash-separated paths. */
186  next_slash_ptr = BLI_path_slash_find(path_component);
187 
188  const bool is_last_component = next_slash_ptr == nullptr;
189  /* Note that this won't be null terminated. */
190  const StringRef component_name = is_last_component ?
191  path_component :
192  StringRef(path_component,
193  next_slash_ptr - path_component);
194 
195  callback(component_name, is_last_component);
196  }
197 }
198 
200  const AssetCatalogPath &to_path) const
201 {
202  if (!from_path) {
203  if (!to_path) {
204  return AssetCatalogPath("");
205  }
206  return to_path / *this;
207  }
208 
209  if (!this->is_contained_in(from_path)) {
210  return AssetCatalogPath("");
211  }
212 
213  if (*this == from_path) {
214  /* Early return, because otherwise the length+1 below is going to cause problems. */
215  return to_path;
216  }
217 
218  /* When from_path = "test", we need to skip "test/" to get the rest of the path, hence the +1. */
219  const StringRef suffix = StringRef(this->path_).substr(from_path.length() + 1);
220  const AssetCatalogPath path_suffix(suffix);
221  return to_path / path_suffix;
222 }
223 
224 } // namespace blender::bke
const char * BLI_path_slash_find(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1750
static uint8 component(Color32 c, uint i)
Definition: ColorBlock.cpp:108
int size_type
constexpr StringRef substr(int64_t start, int64_t size) const
constexpr bool startswith(StringRef prefix) const
const std::string & str() const
AssetCatalogPath operator/(const AssetCatalogPath &path_to_append) const
AssetCatalogPath cleanup() const
bool operator<(const AssetCatalogPath &other_path) const
bool is_contained_in(const AssetCatalogPath &other_path) const
bool operator==(const AssetCatalogPath &other_path) const
static std::string cleanup_component(StringRef component_name)
void iterate_components(ComponentIteratorFn callback) const
bool operator!=(const AssetCatalogPath &other_path) const
AssetCatalogPath rebase(const AssetCatalogPath &from_path, const AssetCatalogPath &to_path) const
AssetCatalogPath parent() const
DEGForeachIDComponentCallback callback
std::ostream & operator<<(std::ostream &stream, const AssetCatalogPath &path_to_append)
unsigned __int64 uint64_t
Definition: stdint.h:90