130 lines
4.6 KiB
C++
130 lines
4.6 KiB
C++
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup asset_system
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "BLI_function_ref.hh"
|
|
#include "BLI_string_ref.hh"
|
|
#include "BLI_sys_types.h"
|
|
|
|
#include <string>
|
|
|
|
namespace blender::asset_system {
|
|
|
|
/**
|
|
* Location of an Asset Catalog in the catalog tree, denoted by slash-separated path components.
|
|
*
|
|
* Each path component is a string that is not allowed to have slashes or colons. The latter is to
|
|
* make things easy to save in the colon-delimited Catalog Definition File format.
|
|
*
|
|
* The path of a catalog determines where in the catalog hierarchy the catalog is shown. Examples
|
|
* are "Characters/Ellie/Poses/Hand" or "Kit_bash/City/Skyscrapers". The path looks like a
|
|
* file-system path, with a few differences:
|
|
*
|
|
* - Only slashes are used as path component separators.
|
|
* - All paths are absolute, so there is no need for a leading slash.
|
|
*
|
|
* See https://developer.blender.org/docs/features/asset_system/backend/asset_catalogs/
|
|
*
|
|
* Paths are stored as byte sequences, and assumed to be UTF-8.
|
|
*/
|
|
class AssetCatalogPath {
|
|
friend std::ostream &operator<<(std::ostream &stream, const AssetCatalogPath &path_to_append);
|
|
|
|
/**
|
|
* The path itself, such as "Agents/Secret/327".
|
|
*/
|
|
std::string path_ = "";
|
|
|
|
public:
|
|
static const char SEPARATOR;
|
|
|
|
AssetCatalogPath() = default;
|
|
AssetCatalogPath(StringRef path);
|
|
AssetCatalogPath(std::string path);
|
|
AssetCatalogPath(const char *path);
|
|
AssetCatalogPath(const AssetCatalogPath &other_path) = default;
|
|
AssetCatalogPath(AssetCatalogPath &&other_path) noexcept;
|
|
~AssetCatalogPath() = default;
|
|
|
|
uint64_t hash() const;
|
|
uint64_t length() const; /* Length of the path in bytes. */
|
|
|
|
/** C-string representation of the path. */
|
|
const char *c_str() const;
|
|
const std::string &str() const;
|
|
|
|
/* The last path component, used as label in the tree view. */
|
|
StringRefNull name() const;
|
|
|
|
/* In-class operators, because of the implicit `AssetCatalogPath(StringRef)` constructor.
|
|
* Otherwise `string == string` could cast both sides to `AssetCatalogPath`. */
|
|
bool operator==(const AssetCatalogPath &other_path) const;
|
|
bool operator!=(const AssetCatalogPath &other_path) const;
|
|
bool operator<(const AssetCatalogPath &other_path) const;
|
|
AssetCatalogPath &operator=(const AssetCatalogPath &other_path) = default;
|
|
AssetCatalogPath &operator=(AssetCatalogPath &&other_path) = default;
|
|
|
|
/** Concatenate two paths, returning the new path. */
|
|
AssetCatalogPath operator/(const AssetCatalogPath &path_to_append) const;
|
|
|
|
/* False when the path is empty, true otherwise. */
|
|
operator bool() const;
|
|
|
|
/**
|
|
* Clean up the path. This ensures:
|
|
* - Every path component is stripped of its leading/trailing spaces.
|
|
* - Empty components (caused by double slashes or leading/trailing slashes) are removed.
|
|
* - Invalid characters are replaced with valid ones.
|
|
*/
|
|
[[nodiscard]] AssetCatalogPath cleanup() const;
|
|
|
|
/**
|
|
* \return true only if the given path is a parent of this catalog's path.
|
|
* When this catalog's path is equal to the given path, return true as well.
|
|
* In other words, this defines a weak subset.
|
|
*
|
|
* True: "some/path/there" is contained in "some/path" and "some".
|
|
* False: "path/there" is not contained in "some/path/there".
|
|
*
|
|
* Note that non-cleaned-up paths (so for example starting or ending with a
|
|
* slash) are not supported, and result in undefined behavior.
|
|
*/
|
|
bool is_contained_in(const AssetCatalogPath &other_path) const;
|
|
|
|
/**
|
|
* \return the parent path, or an empty path if there is no parent.
|
|
*/
|
|
AssetCatalogPath parent() const;
|
|
|
|
/**
|
|
* Change the initial part of the path from `from_path` to `to_path`.
|
|
* If this path does not start with `from_path`, return an empty path as result.
|
|
*
|
|
* Example:
|
|
*
|
|
* AssetCatalogPath path("some/path/to/some/catalog");
|
|
* path.rebase("some/path", "new/base") -> "new/base/to/some/catalog"
|
|
*/
|
|
AssetCatalogPath rebase(const AssetCatalogPath &from_path,
|
|
const AssetCatalogPath &to_path) const;
|
|
|
|
/** Call the callback function for each path component, in left-to-right order. */
|
|
using ComponentIteratorFn = FunctionRef<void(StringRef component_name, bool is_last_component)>;
|
|
void iterate_components(ComponentIteratorFn callback) const;
|
|
|
|
protected:
|
|
/** Strip leading/trailing spaces and replace disallowed characters. */
|
|
static std::string cleanup_component(StringRef component_name);
|
|
};
|
|
|
|
/** Output the path as string. */
|
|
std::ostream &operator<<(std::ostream &stream, const AssetCatalogPath &path_to_append);
|
|
|
|
} // namespace blender::asset_system
|