Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <jacques@blender.org>2021-10-03 15:10:26 +0300
committerJacques Lucke <jacques@blender.org>2021-10-03 15:10:26 +0300
commita8d6a86981b3bdcc8e9796a4465544523372c687 (patch)
tree111bc1e912f1e02d87575775a2f3e7f8fafa2ab1
parentc206fa9627c40b91d07e1abd951f06dbcf502f6d (diff)
Cleanup: move StringRef method definitions out of class
This makes the classes more appealing to look at and makes it easier to see what different methods are available.
-rw-r--r--source/blender/blenlib/BLI_string_ref.hh658
1 files changed, 353 insertions, 305 deletions
diff --git a/source/blender/blenlib/BLI_string_ref.hh b/source/blender/blenlib/BLI_string_ref.hh
index dcf66bbf5ad..79d1f73bb93 100644
--- a/source/blender/blenlib/BLI_string_ref.hh
+++ b/source/blender/blenlib/BLI_string_ref.hh
@@ -64,135 +64,35 @@ class StringRefBase {
const char *data_;
int64_t size_;
- constexpr StringRefBase(const char *data, const int64_t size) : data_(data), size_(size)
- {
- }
+ constexpr StringRefBase(const char *data, const int64_t size);
public:
/* Similar to string_view::npos, but signed. */
static constexpr int64_t not_found = -1;
- /**
- * Return the (byte-)length of the referenced string, without any null-terminator.
- */
- constexpr int64_t size() const
- {
- return size_;
- }
-
- constexpr bool is_empty() const
- {
- return size_ == 0;
- }
-
- /**
- * Return a pointer to the start of the string.
- */
- constexpr const char *data() const
- {
- return data_;
- }
-
- constexpr operator Span<char>() const
- {
- return Span<char>(data_, size_);
- }
-
- /**
- * Implicitly convert to std::string. This is convenient in most cases, but you have to be a bit
- * careful not to convert to std::string accidentally.
- */
- operator std::string() const
- {
- return std::string(data_, static_cast<size_t>(size_));
- }
-
- constexpr operator std::string_view() const
- {
- return std::string_view(data_, static_cast<size_t>(size_));
- }
-
- constexpr const char *begin() const
- {
- return data_;
- }
+ constexpr int64_t size() const;
+ constexpr bool is_empty() const;
+ constexpr const char *data() const;
+ constexpr operator Span<char>() const;
- constexpr const char *end() const
- {
- return data_ + size_;
- }
+ operator std::string() const;
+ constexpr operator std::string_view() const;
- constexpr IndexRange index_range() const
- {
- return IndexRange(size_);
- }
+ constexpr const char *begin() const;
+ constexpr const char *end() const;
- /**
- * Copy the string into a buffer. The buffer has to be one byte larger than the size of the
- * string, because the copied string will be null-terminated. Only use this when you are
- * absolutely sure that the buffer is large enough.
- */
- void unsafe_copy(char *dst) const
- {
- if (size_ > 0) {
- memcpy(dst, data_, static_cast<size_t>(size_));
- }
- dst[size_] = '\0';
- }
+ constexpr IndexRange index_range() const;
- /**
- * Copy the string into a buffer. The copied string will be null-terminated. This invokes
- * undefined behavior when dst_size is too small. (Should we define the behavior?)
- */
- void copy(char *dst, const int64_t dst_size) const
- {
- if (size_ < dst_size) {
- this->unsafe_copy(dst);
- }
- else {
- BLI_assert(false);
- dst[0] = '\0';
- }
- }
+ void unsafe_copy(char *dst) const;
+ void copy(char *dst, const int64_t dst_size) const;
+ template<size_t N> void copy(char (&dst)[N]) const;
- /**
- * Copy the string into a char array. The copied string will be null-terminated. This invokes
- * undefined behavior when dst is too small.
- */
- template<size_t N> void copy(char (&dst)[N]) const
- {
- this->copy(dst, N);
- }
-
- /**
- * Returns true when the string begins with the given prefix. Otherwise false.
- */
constexpr bool startswith(StringRef prefix) const;
-
- /**
- * Returns true when the string ends with the given suffix. Otherwise false.
- */
constexpr bool endswith(StringRef suffix) const;
-
constexpr StringRef substr(int64_t start, const int64_t size) const;
- /**
- * Get the first char in the string. This invokes undefined behavior when the string is empty.
- */
- constexpr const char &front() const
- {
- BLI_assert(size_ >= 1);
- return data_[0];
- }
-
- /**
- * Get the last char in the string. This invokes undefined behavior when the string is empty.
- */
- constexpr const char &back() const
- {
- BLI_assert(size_ >= 1);
- return data_[size_ - 1];
- }
+ constexpr const char &front() const;
+ constexpr const char &back() const;
/**
* The behavior of those functions matches the standard library implementation of
@@ -211,15 +111,7 @@ class StringRefBase {
constexpr int64_t find_last_not_of(StringRef chars, int64_t pos = INT64_MAX) const;
constexpr int64_t find_last_not_of(char c, int64_t pos = INT64_MAX) const;
- /**
- * Return a new StringRef that does not contain leading and trailing whitespace.
- */
constexpr StringRef trim() const;
-
- /**
- * Return a new StringRef that removes all the leading and trailing characters
- * that occur in `characters_to_remove`.
- */
constexpr StringRef trim(StringRef characters_to_remove) const;
constexpr StringRef trim(char character_to_remove) const;
};
@@ -230,57 +122,13 @@ class StringRefBase {
class StringRefNull : public StringRefBase {
public:
- constexpr StringRefNull() : StringRefBase("", 0)
- {
- }
-
- /**
- * Construct a StringRefNull from a null terminated c-string. The pointer must not point to
- * NULL.
- */
- StringRefNull(const char *str) : StringRefBase(str, static_cast<int64_t>(strlen(str)))
- {
- BLI_assert(str != nullptr);
- BLI_assert(data_[size_] == '\0');
- }
-
- /**
- * Construct a StringRefNull from a null terminated c-string. This invokes undefined behavior
- * when the given size is not the correct size of the string.
- */
- constexpr StringRefNull(const char *str, const int64_t size) : StringRefBase(str, size)
- {
- BLI_assert(static_cast<int64_t>(strlen(str)) == size);
- }
+ constexpr StringRefNull();
+ constexpr StringRefNull(const char *str, const int64_t size);
+ StringRefNull(const char *str);
+ StringRefNull(const std::string &str);
- /**
- * Reference a std::string. Remember that when the std::string is destructed, the StringRefNull
- * will point to uninitialized memory.
- */
- StringRefNull(const std::string &str) : StringRefNull(str.c_str())
- {
- }
-
- /**
- * Get the char at the given index.
- */
- constexpr char operator[](const int64_t index) const
- {
- BLI_assert(index >= 0);
- /* Use '<=' instead of just '<', so that the null character can be accessed as well. */
- BLI_assert(index <= size_);
- return data_[index];
- }
-
- /**
- * Returns the beginning of a null-terminated char array.
- *
- * This is like ->data(), but can only be called on a StringRefNull.
- */
- constexpr const char *c_str() const
- {
- return data_;
- }
+ constexpr char operator[](const int64_t index) const;
+ constexpr const char *c_str() const;
};
/**
@@ -288,161 +136,126 @@ class StringRefNull : public StringRefBase {
*/
class StringRef : public StringRefBase {
public:
- constexpr StringRef() : StringRefBase(nullptr, 0)
- {
- }
-
- /**
- * StringRefNull can be converted into StringRef, but not the other way around.
- */
- constexpr StringRef(StringRefNull other) : StringRefBase(other.data(), other.size())
- {
- }
-
- /**
- * Create a StringRef from a null-terminated c-string.
- */
- constexpr StringRef(const char *str)
- : StringRefBase(str, str ? static_cast<int64_t>(std::char_traits<char>::length(str)) : 0)
- {
- }
-
- constexpr StringRef(const char *str, const int64_t length) : StringRefBase(str, length)
- {
- }
-
- /**
- * Create a StringRef from a start and end pointer. This invokes undefined behavior when the
- * second point points to a smaller address than the first one.
- */
- constexpr StringRef(const char *begin, const char *one_after_end)
- : StringRefBase(begin, static_cast<int64_t>(one_after_end - begin))
- {
- BLI_assert(begin <= one_after_end);
- }
-
- /**
- * Reference a std::string. Remember that when the std::string is destructed, the StringRef
- * will point to uninitialized memory.
- */
- StringRef(const std::string &str) : StringRefBase(str.data(), static_cast<int64_t>(str.size()))
- {
- }
-
- constexpr StringRef(std::string_view view)
- : StringRefBase(view.data(), static_cast<int64_t>(view.size()))
- {
- }
-
- /**
- * Returns a new StringRef that does not contain the first n chars. This invokes undefined
- * behavior when n is negative.
- */
- constexpr StringRef drop_prefix(const int64_t n) const
- {
- BLI_assert(n >= 0);
- const int64_t clamped_n = std::min(n, size_);
- const int64_t new_size = size_ - clamped_n;
- return StringRef(data_ + clamped_n, new_size);
- }
+ constexpr StringRef();
+ constexpr StringRef(StringRefNull other);
+ constexpr StringRef(const char *str);
+ constexpr StringRef(const char *str, const int64_t length);
+ constexpr StringRef(const char *begin, const char *one_after_end);
+ constexpr StringRef(std::string_view view);
+ StringRef(const std::string &str);
+
+ constexpr StringRef drop_prefix(const int64_t n) const;
+ constexpr StringRef drop_known_prefix(StringRef prefix) const;
+ constexpr StringRef drop_suffix(const int64_t n) const;
+
+ constexpr char operator[](int64_t index) const;
+};
- /**
- * Return a new StringRef with the given prefix being skipped. This invokes undefined behavior if
- * the string does not begin with the given prefix.
- */
- constexpr StringRef drop_known_prefix(StringRef prefix) const
- {
- BLI_assert(this->startswith(prefix));
- return this->drop_prefix(prefix.size());
- }
+/* --------------------------------------------------------------------
+ * #StringRefBase inline methods.
+ */
- /**
- * Return a new StringRef that does not contain the last n chars. This invokes undefined behavior
- * when n is negative.
- */
- constexpr StringRef drop_suffix(const int64_t n) const
- {
- BLI_assert(n >= 0);
- const int64_t new_size = std::max<int64_t>(0, size_ - n);
- return StringRef(data_, new_size);
- }
+constexpr StringRefBase::StringRefBase(const char *data, const int64_t size)
+ : data_(data), size_(size)
+{
+}
- /**
- * Get the char at the given index.
- */
- constexpr char operator[](int64_t index) const
- {
- BLI_assert(index >= 0);
- BLI_assert(index < size_);
- return data_[index];
- }
-};
+/**
+ * Return the (byte-)length of the referenced string, without any null-terminator.
+ */
+constexpr int64_t StringRefBase::size() const
+{
+ return size_;
+}
-/* More inline functions
- ***************************************/
+constexpr bool StringRefBase::is_empty() const
+{
+ return size_ == 0;
+}
-inline std::ostream &operator<<(std::ostream &stream, StringRef ref)
+/**
+ * Return a pointer to the start of the string.
+ */
+constexpr const char *StringRefBase::data() const
{
- stream << std::string(ref);
- return stream;
+ return data_;
}
-inline std::ostream &operator<<(std::ostream &stream, StringRefNull ref)
+constexpr StringRefBase::operator Span<char>() const
{
- stream << std::string(ref.data(), (size_t)ref.size());
- return stream;
+ return Span<char>(data_, size_);
}
/**
- * Adding two #StringRefs will allocate an std::string.
- * This is not efficient, but convenient in most cases.
+ * Implicitly convert to std::string. This is convenient in most cases, but you have to be a bit
+ * careful not to convert to std::string accidentally.
*/
-inline std::string operator+(StringRef a, StringRef b)
+inline StringRefBase::operator std::string() const
{
- return std::string(a) + std::string(b);
+ return std::string(data_, static_cast<size_t>(size_));
}
-/* This does not compare StringRef and std::string_view, because of ambiguous overloads. This is
- * not a problem when std::string_view is only used at api boundaries. To compare a StringRef and a
- * std::string_view, one should convert the std::string_view to StringRef (which is very cheap).
- * Ideally, we only use StringRef in our code to avoid this problem altogether. */
-constexpr inline bool operator==(StringRef a, StringRef b)
+constexpr StringRefBase::operator std::string_view() const
{
- if (a.size() != b.size()) {
- return false;
- }
- return STREQLEN(a.data(), b.data(), (size_t)a.size());
+ return std::string_view(data_, static_cast<size_t>(size_));
}
-constexpr inline bool operator!=(StringRef a, StringRef b)
+constexpr const char *StringRefBase::begin() const
{
- return !(a == b);
+ return data_;
}
-constexpr inline bool operator<(StringRef a, StringRef b)
+constexpr const char *StringRefBase::end() const
{
- return std::string_view(a) < std::string_view(b);
+ return data_ + size_;
}
-constexpr inline bool operator>(StringRef a, StringRef b)
+constexpr IndexRange StringRefBase::index_range() const
{
- return std::string_view(a) > std::string_view(b);
+ return IndexRange(size_);
}
-constexpr inline bool operator<=(StringRef a, StringRef b)
+/**
+ * Copy the string into a buffer. The buffer has to be one byte larger than the size of the
+ * string, because the copied string will be null-terminated. Only use this when you are
+ * absolutely sure that the buffer is large enough.
+ */
+inline void StringRefBase::unsafe_copy(char *dst) const
{
- return std::string_view(a) <= std::string_view(b);
+ if (size_ > 0) {
+ memcpy(dst, data_, static_cast<size_t>(size_));
+ }
+ dst[size_] = '\0';
}
-constexpr inline bool operator>=(StringRef a, StringRef b)
+/**
+ * Copy the string into a buffer. The copied string will be null-terminated. This invokes
+ * undefined behavior when dst_size is too small. (Should we define the behavior?)
+ */
+inline void StringRefBase::copy(char *dst, const int64_t dst_size) const
{
- return std::string_view(a) >= std::string_view(b);
+ if (size_ < dst_size) {
+ this->unsafe_copy(dst);
+ }
+ else {
+ BLI_assert(false);
+ dst[0] = '\0';
+ }
+}
+
+/**
+ * Copy the string into a char array. The copied string will be null-terminated. This invokes
+ * undefined behavior when dst is too small.
+ */
+template<size_t N> inline void StringRefBase::copy(char (&dst)[N]) const
+{
+ this->copy(dst, N);
}
/**
* Return true when the string starts with the given prefix.
*/
-constexpr inline bool StringRefBase::startswith(StringRef prefix) const
+constexpr bool StringRefBase::startswith(StringRef prefix) const
{
if (size_ < prefix.size_) {
return false;
@@ -458,7 +271,7 @@ constexpr inline bool StringRefBase::startswith(StringRef prefix) const
/**
* Return true when the string ends with the given suffix.
*/
-constexpr inline bool StringRefBase::endswith(StringRef suffix) const
+constexpr bool StringRefBase::endswith(StringRef suffix) const
{
if (size_ < suffix.size_) {
return false;
@@ -476,8 +289,8 @@ constexpr inline bool StringRefBase::endswith(StringRef suffix) const
* Return a new #StringRef containing only a sub-string of the original string. This invokes
* undefined if the start or max_size is negative.
*/
-constexpr inline StringRef StringRefBase::substr(const int64_t start,
- const int64_t max_size = INT64_MAX) const
+constexpr StringRef StringRefBase::substr(const int64_t start,
+ const int64_t max_size = INT64_MAX) const
{
BLI_assert(max_size >= 0);
BLI_assert(start >= 0);
@@ -485,7 +298,25 @@ constexpr inline StringRef StringRefBase::substr(const int64_t start,
return StringRef(data_ + start, substr_size);
}
-constexpr inline int64_t index_or_npos_to_int64(size_t index)
+/**
+ * Get the first char in the string. This invokes undefined behavior when the string is empty.
+ */
+constexpr const char &StringRefBase::front() const
+{
+ BLI_assert(size_ >= 1);
+ return data_[0];
+}
+
+/**
+ * Get the last char in the string. This invokes undefined behavior when the string is empty.
+ */
+constexpr const char &StringRefBase::back() const
+{
+ BLI_assert(size_ >= 1);
+ return data_[size_ - 1];
+}
+
+constexpr int64_t index_or_npos_to_int64(size_t index)
{
/* The compiler will probably optimize this check away. */
if (index == std::string_view::npos) {
@@ -494,62 +325,62 @@ constexpr inline int64_t index_or_npos_to_int64(size_t index)
return static_cast<int64_t>(index);
}
-constexpr inline int64_t StringRefBase::find(char c, int64_t pos) const
+constexpr int64_t StringRefBase::find(char c, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(std::string_view(*this).find(c, static_cast<size_t>(pos)));
}
-constexpr inline int64_t StringRefBase::find(StringRef str, int64_t pos) const
+constexpr int64_t StringRefBase::find(StringRef str, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(std::string_view(*this).find(str, static_cast<size_t>(pos)));
}
-constexpr inline int64_t StringRefBase::find_first_of(StringRef chars, int64_t pos) const
+constexpr int64_t StringRefBase::find_first_of(StringRef chars, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(
std::string_view(*this).find_first_of(chars, static_cast<size_t>(pos)));
}
-constexpr inline int64_t StringRefBase::find_first_of(char c, int64_t pos) const
+constexpr int64_t StringRefBase::find_first_of(char c, int64_t pos) const
{
return this->find_first_of(StringRef(&c, 1), pos);
}
-constexpr inline int64_t StringRefBase::find_last_of(StringRef chars, int64_t pos) const
+constexpr int64_t StringRefBase::find_last_of(StringRef chars, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(
std::string_view(*this).find_last_of(chars, static_cast<size_t>(pos)));
}
-constexpr inline int64_t StringRefBase::find_last_of(char c, int64_t pos) const
+constexpr int64_t StringRefBase::find_last_of(char c, int64_t pos) const
{
return this->find_last_of(StringRef(&c, 1), pos);
}
-constexpr inline int64_t StringRefBase::find_first_not_of(StringRef chars, int64_t pos) const
+constexpr int64_t StringRefBase::find_first_not_of(StringRef chars, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(
std::string_view(*this).find_first_not_of(chars, static_cast<size_t>(pos)));
}
-constexpr inline int64_t StringRefBase::find_first_not_of(char c, int64_t pos) const
+constexpr int64_t StringRefBase::find_first_not_of(char c, int64_t pos) const
{
return this->find_first_not_of(StringRef(&c, 1), pos);
}
-constexpr inline int64_t StringRefBase::find_last_not_of(StringRef chars, int64_t pos) const
+constexpr int64_t StringRefBase::find_last_not_of(StringRef chars, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(
std::string_view(*this).find_last_not_of(chars, static_cast<size_t>(pos)));
}
-constexpr inline int64_t StringRefBase::find_last_not_of(char c, int64_t pos) const
+constexpr int64_t StringRefBase::find_last_not_of(char c, int64_t pos) const
{
return this->find_last_not_of(StringRef(&c, 1), pos);
}
@@ -559,6 +390,9 @@ constexpr StringRef StringRefBase::trim() const
return this->trim(" \t\r\n");
}
+/**
+ * Return a new StringRef that does not contain leading and trailing whitespace.
+ */
constexpr StringRef StringRefBase::trim(const char character_to_remove) const
{
return this->trim(StringRef(&character_to_remove, 1));
@@ -584,4 +418,218 @@ constexpr StringRef StringRefBase::trim(StringRef characters_to_remove) const
return this->substr(find_front, substr_len);
}
+/* --------------------------------------------------------------------
+ * #StringRefNull inline methods.
+ */
+
+constexpr StringRefNull::StringRefNull() : StringRefBase("", 0)
+{
+}
+
+/**
+ * Construct a StringRefNull from a null terminated c-string. This invokes undefined behavior
+ * when the given size is not the correct size of the string.
+ */
+constexpr StringRefNull::StringRefNull(const char *str, const int64_t size)
+ : StringRefBase(str, size)
+{
+ BLI_assert(static_cast<int64_t>(strlen(str)) == size);
+}
+
+/**
+ * Construct a StringRefNull from a null terminated c-string. The pointer must not point to
+ * NULL.
+ */
+inline StringRefNull::StringRefNull(const char *str)
+ : StringRefBase(str, static_cast<int64_t>(strlen(str)))
+{
+ BLI_assert(str != nullptr);
+ BLI_assert(data_[size_] == '\0');
+}
+
+/**
+ * Reference a std::string. Remember that when the std::string is destructed, the StringRefNull
+ * will point to uninitialized memory.
+ */
+inline StringRefNull::StringRefNull(const std::string &str) : StringRefNull(str.c_str())
+{
+}
+
+/**
+ * Get the char at the given index.
+ */
+constexpr char StringRefNull::operator[](const int64_t index) const
+{
+ BLI_assert(index >= 0);
+ /* Use '<=' instead of just '<', so that the null character can be accessed as well. */
+ BLI_assert(index <= size_);
+ return data_[index];
+}
+
+/**
+ * Returns the beginning of a null-terminated char array.
+ *
+ * This is like ->data(), but can only be called on a StringRefNull.
+ */
+constexpr const char *StringRefNull::c_str() const
+{
+ return data_;
+}
+
+/* --------------------------------------------------------------------
+ * #StringRef inline methods.
+ */
+
+constexpr StringRef::StringRef() : StringRefBase(nullptr, 0)
+{
+}
+
+/**
+ * StringRefNull can be converted into StringRef, but not the other way around.
+ */
+constexpr StringRef::StringRef(StringRefNull other) : StringRefBase(other.data(), other.size())
+{
+}
+
+/**
+ * Create a StringRef from a null-terminated c-string.
+ */
+constexpr StringRef::StringRef(const char *str)
+ : StringRefBase(str, str ? static_cast<int64_t>(std::char_traits<char>::length(str)) : 0)
+{
+}
+
+constexpr StringRef::StringRef(const char *str, const int64_t length) : StringRefBase(str, length)
+{
+}
+
+/**
+ * Returns a new StringRef that does not contain the first n chars. This invokes undefined
+ * behavior when n is negative.
+ */
+constexpr StringRef StringRef::drop_prefix(const int64_t n) const
+{
+ BLI_assert(n >= 0);
+ const int64_t clamped_n = std::min(n, size_);
+ const int64_t new_size = size_ - clamped_n;
+ return StringRef(data_ + clamped_n, new_size);
+}
+
+/**
+ * Return a new StringRef with the given prefix being skipped. This invokes undefined behavior if
+ * the string does not begin with the given prefix.
+ */
+constexpr StringRef StringRef::drop_known_prefix(StringRef prefix) const
+{
+ BLI_assert(this->startswith(prefix));
+ return this->drop_prefix(prefix.size());
+}
+
+/**
+ * Return a new StringRef that does not contain the last n chars. This invokes undefined behavior
+ * when n is negative.
+ */
+constexpr StringRef StringRef::drop_suffix(const int64_t n) const
+{
+ BLI_assert(n >= 0);
+ const int64_t new_size = std::max<int64_t>(0, size_ - n);
+ return StringRef(data_, new_size);
+}
+
+/**
+ * Get the char at the given index.
+ */
+constexpr char StringRef::operator[](int64_t index) const
+{
+ BLI_assert(index >= 0);
+ BLI_assert(index < size_);
+ return data_[index];
+}
+
+/**
+ * Create a StringRef from a start and end pointer. This invokes undefined behavior when the
+ * second point points to a smaller address than the first one.
+ */
+constexpr StringRef::StringRef(const char *begin, const char *one_after_end)
+ : StringRefBase(begin, static_cast<int64_t>(one_after_end - begin))
+{
+ BLI_assert(begin <= one_after_end);
+}
+
+/**
+ * Reference a std::string. Remember that when the std::string is destructed, the StringRef
+ * will point to uninitialized memory.
+ */
+inline StringRef::StringRef(const std::string &str)
+ : StringRefBase(str.data(), static_cast<int64_t>(str.size()))
+{
+}
+
+constexpr StringRef::StringRef(std::string_view view)
+ : StringRefBase(view.data(), static_cast<int64_t>(view.size()))
+{
+}
+
+/* --------------------------------------------------------------------
+ * Operator overloads
+ */
+
+inline std::ostream &operator<<(std::ostream &stream, StringRef ref)
+{
+ stream << std::string(ref);
+ return stream;
+}
+
+inline std::ostream &operator<<(std::ostream &stream, StringRefNull ref)
+{
+ stream << std::string(ref.data(), (size_t)ref.size());
+ return stream;
+}
+
+/**
+ * Adding two #StringRefs will allocate an std::string.
+ * This is not efficient, but convenient in most cases.
+ */
+inline std::string operator+(StringRef a, StringRef b)
+{
+ return std::string(a) + std::string(b);
+}
+
+/* This does not compare StringRef and std::string_view, because of ambiguous overloads. This is
+ * not a problem when std::string_view is only used at api boundaries. To compare a StringRef and a
+ * std::string_view, one should convert the std::string_view to StringRef (which is very cheap).
+ * Ideally, we only use StringRef in our code to avoid this problem altogether. */
+constexpr bool operator==(StringRef a, StringRef b)
+{
+ if (a.size() != b.size()) {
+ return false;
+ }
+ return STREQLEN(a.data(), b.data(), (size_t)a.size());
+}
+
+constexpr bool operator!=(StringRef a, StringRef b)
+{
+ return !(a == b);
+}
+
+constexpr bool operator<(StringRef a, StringRef b)
+{
+ return std::string_view(a) < std::string_view(b);
+}
+
+constexpr bool operator>(StringRef a, StringRef b)
+{
+ return std::string_view(a) > std::string_view(b);
+}
+
+constexpr bool operator<=(StringRef a, StringRef b)
+{
+ return std::string_view(a) <= std::string_view(b);
+}
+
+constexpr bool operator>=(StringRef a, StringRef b)
+{
+ return std::string_view(a) >= std::string_view(b);
+}
+
} // namespace blender