This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/blenkernel/intern/asset_catalog_path.cc
Campbell Barton ffc4c126f5 Cleanup: move public doc-strings into headers for 'blenkernel'
- Added space below non doc-string comments to make it clear
  these aren't comments for the symbols directly below them.
- Use doxy sections for some headers.
- Minor improvements to doc-strings.

Ref T92709
2021-12-07 17:38:48 +11:00

239 lines
6.8 KiB
C++

/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup bke
*/
#include "BKE_asset_catalog_path.hh"
#include "BLI_path_util.h"
namespace blender::bke {
const char AssetCatalogPath::SEPARATOR = '/';
AssetCatalogPath::AssetCatalogPath(const std::string &path) : path_(path)
{
}
AssetCatalogPath::AssetCatalogPath(StringRef path) : path_(path)
{
}
AssetCatalogPath::AssetCatalogPath(const char *path) : path_(path)
{
}
AssetCatalogPath::AssetCatalogPath(AssetCatalogPath &&other_path) noexcept
: path_(std::move(other_path.path_))
{
}
uint64_t AssetCatalogPath::hash() const
{
std::hash<std::string> hasher{};
return hasher(this->path_);
}
uint64_t AssetCatalogPath::length() const
{
return this->path_.length();
}
const char *AssetCatalogPath::c_str() const
{
return this->path_.c_str();
}
const std::string &AssetCatalogPath::str() const
{
return this->path_;
}
StringRefNull AssetCatalogPath::name() const
{
const size_t last_sep_index = this->path_.rfind(SEPARATOR);
if (last_sep_index == std::string::npos) {
return StringRefNull(this->path_);
}
return StringRefNull(this->path_.c_str() + last_sep_index + 1);
}
bool AssetCatalogPath::operator==(const AssetCatalogPath &other_path) const
{
return this->path_ == other_path.path_;
}
bool AssetCatalogPath::operator!=(const AssetCatalogPath &other_path) const
{
return !(*this == other_path);
}
bool AssetCatalogPath::operator<(const AssetCatalogPath &other_path) const
{
return this->path_ < other_path.path_;
}
AssetCatalogPath AssetCatalogPath::operator/(const AssetCatalogPath &path_to_append) const
{
/* `"" / "path"` or `"path" / ""` should just result in `"path"` */
if (!*this) {
return path_to_append;
}
if (!path_to_append) {
return *this;
}
std::stringstream new_path;
new_path << this->path_ << SEPARATOR << path_to_append.path_;
return AssetCatalogPath(new_path.str());
}
AssetCatalogPath::operator bool() const
{
return !this->path_.empty();
}
std::ostream &operator<<(std::ostream &stream, const AssetCatalogPath &path_to_append)
{
stream << path_to_append.path_;
return stream;
}
AssetCatalogPath AssetCatalogPath::cleanup() const
{
std::stringstream clean_components;
bool first_component_seen = false;
this->iterate_components([&clean_components, &first_component_seen](StringRef component_name,
bool /*is_last_component*/) {
const std::string clean_component = cleanup_component(component_name);
if (clean_component.empty()) {
/* These are caused by leading, trailing, or double slashes. */
return;
}
/* If a previous path component has been streamed already, we need a path separator. This
* cannot use the `is_last_component` boolean, because the last component might be skipped due
* to the condition above. */
if (first_component_seen) {
clean_components << SEPARATOR;
}
first_component_seen = true;
clean_components << clean_component;
});
return AssetCatalogPath(clean_components.str());
}
std::string AssetCatalogPath::cleanup_component(StringRef component)
{
std::string cleaned = component.trim();
/* Replace colons with something else, as those are used in the CDF file as delimiter. */
std::replace(cleaned.begin(), cleaned.end(), ':', '-');
return cleaned;
}
bool AssetCatalogPath::is_contained_in(const AssetCatalogPath &other_path) const
{
if (!other_path) {
/* The empty path contains all other paths. */
return true;
}
if (this->path_ == other_path.path_) {
/* Weak is-in relation: equal paths contain each other. */
return true;
}
/* To be a child path of 'other_path', our path must be at least a separator and another
* character longer. */
if (this->length() < other_path.length() + 2) {
return false;
}
/* Create StringRef to be able to use .startswith(). */
const StringRef this_path(this->path_);
const bool prefix_ok = this_path.startswith(other_path.path_);
const char next_char = this_path[other_path.length()];
return prefix_ok && next_char == SEPARATOR;
}
AssetCatalogPath AssetCatalogPath::parent() const
{
if (!*this) {
return AssetCatalogPath("");
}
std::string::size_type last_sep_index = this->path_.rfind(SEPARATOR);
if (last_sep_index == std::string::npos) {
return AssetCatalogPath("");
}
return AssetCatalogPath(this->path_.substr(0, last_sep_index));
}
void AssetCatalogPath::iterate_components(ComponentIteratorFn callback) const
{
const char *next_slash_ptr;
for (const char *path_component = this->path_.data(); path_component && path_component[0];
/* Jump to one after the next slash if there is any. */
path_component = next_slash_ptr ? next_slash_ptr + 1 : nullptr) {
/* Note that this also treats backslashes as component separators, which
* helps in cleaning up backslash-separated paths. */
next_slash_ptr = BLI_path_slash_find(path_component);
const bool is_last_component = next_slash_ptr == nullptr;
/* Note that this won't be null terminated. */
const StringRef component_name = is_last_component ?
path_component :
StringRef(path_component,
next_slash_ptr - path_component);
callback(component_name, is_last_component);
}
}
AssetCatalogPath AssetCatalogPath::rebase(const AssetCatalogPath &from_path,
const AssetCatalogPath &to_path) const
{
if (!from_path) {
if (!to_path) {
return AssetCatalogPath("");
}
return to_path / *this;
}
if (!this->is_contained_in(from_path)) {
return AssetCatalogPath("");
}
if (*this == from_path) {
/* Early return, because otherwise the length+1 below is going to cause problems. */
return to_path;
}
/* When from_path = "test", we need to skip "test/" to get the rest of the path, hence the +1. */
const StringRef suffix = StringRef(this->path_).substr(from_path.length() + 1);
const AssetCatalogPath path_suffix(suffix);
return to_path / path_suffix;
}
} // namespace blender::bke