Files
workinf_Blender_Wasm/blender-5.2.0/source/blender/blenlib/BLI_ustring.hh
2026-08-12 04:47:48 -04:00

190 lines
4.8 KiB
C++

/* SPDX-FileCopyrightText: 2026 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include <atomic>
#include <string>
#include <string_view>
#ifdef WITH_WEB
/* The Web data target does not compile OpenImageIO. Keep the UString API
* available for DNA/node data while using a deterministic local representation. */
#else
#include <OpenImageIO/ustring.h>
#endif
#include "BLI_fixed_string.hh"
#include "BLI_hash.hh"
#include "BLI_string_ref.hh"
namespace blender {
/**
* This is a thin wrapper around OpenImageIO's ustring class. Additionally it also provides
* conversions to our StringRef types.
*
* See the OpenImageIO documentation for more details:
* https://openimageio.readthedocs.io/en/stable/imageioapi.html#efficient-unique-strings-ustring
*/
class UString {
private:
/**
* Using a member instead of inheritance because it simplifies avoiding various ambiguities with
* operator overloads (especially equality comparison between UString, StringRef, std::string,
* std::string_view, OpenImageIO::string_view, etc.).
*/
#ifdef WITH_WEB
std::string ustr_;
#else
OIIO::ustring ustr_;
#endif
public:
UString() = default;
#ifdef WITH_WEB
explicit UString(const char *str) : ustr_(str ? str : "") {}
explicit UString(const StringRef str) : ustr_(std::string_view(str)) {}
#else
explicit UString(const StringRef str) : ustr_(std::string_view(str)) {}
#endif
/** A constructor that is meant to generate as little code as possible at the call site. */
static UString from_ptr_noinline(const char *str);
/**
* Access the underlying string as a #StringRefNull.
*
* Note: This is not an implicit conversion to work around ambiguous function calls.
*/
StringRefNull ref() const
{
#ifdef WITH_WEB
return StringRefNull(ustr_.c_str(), ustr_.length());
#else
return StringRefNull(ustr_.c_str(), ustr_.length());
#endif
}
const std::string &string() const
{
#ifdef WITH_WEB
return ustr_;
#else
return ustr_.string();
#endif
}
const char *c_str() const
{
return ustr_.c_str();
}
friend bool operator==(const UString &a, const UString &b)
{
return a.ustr_ == b.ustr_;
}
friend bool operator==(const UString &a, const StringRef b)
{
return a.ref() == b;
}
uint64_t hash() const
{
#ifdef WITH_WEB
/* FNV-1a is stable across native/Web builds and does not require OIIO. */
uint64_t result = UINT64_C(14695981039346656037);
for (const unsigned char byte : ustr_) {
result ^= byte;
result *= UINT64_C(1099511628211);
}
return result;
#else
return ustr_.hash();
#endif
}
int64_t size() const
{
return int64_t(ustr_.size());
}
bool is_empty() const
{
return ustr_.empty();
}
char operator[](const int64_t i) const
{
/* Accessing null char at end is allowed too. */
BLI_assert(i >= 0 && i <= this->size());
return ustr_[i];
}
};
/**
* Define DefaultHash for UString keys so that it uses the cached hash on ustrings but also
* supports hashing arbitrary (non-unique) strings in the same way.
*
* Note: The string hashes produced here are different from e.g. DefaultHash<StringRef>. That is
* fine though. The only requirement is that all hashes defined in this template specialization are
* compatible with each other.
*/
template<> struct DefaultHash<UString> {
uint64_t operator()(const UString &value) const
{
return value.hash();
}
constexpr uint64_t operator()(const StringRef value) const
{
#ifdef WITH_WEB
uint64_t result = UINT64_C(14695981039346656037);
for (const unsigned char byte : value) {
result ^= byte;
result *= UINT64_C(1099511628211);
}
return result;
#else
/* This is the hash function used by OpenImageIO::ustring::make_unique internally. */
return OIIO::Strutil::strhash64(value.size(), value.data());
#endif
}
};
/**
* Create a UString from a string literal. This is a template function so that each string is only
* made unique once and not every time the literal is used.
*
* Note: OpenImageIO defines a similar `_us` string literal operator. However, it newly constructs
* the ustring in each invocation instead of caching it in a static variable. Caching it like here
* likely only works in C++20.
*/
template<FixedString FStr> inline UString operator""_ustr()
{
static const UString static_ustr = UString::from_ptr_noinline(FStr.data);
return static_ustr;
}
/**
* Support using the `fmt` library with #UString.
*/
inline std::string_view format_as(UString str)
{
return str.string();
}
} // namespace blender
/**
* Disable conflicting range formatter in fmtlib. Otherwise we will get compile errors
* where fmtlib doesn't know if it should use the formatter from format.h or ranges.h.
*/
namespace fmt {
template<> struct is_range<blender::UString, char> : std::false_type {};
} // namespace fmt