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:
Diffstat (limited to 'source/blender/blenlib/BLI_string_ref.hh')
-rw-r--r--source/blender/blenlib/BLI_string_ref.hh183
1 files changed, 162 insertions, 21 deletions
diff --git a/source/blender/blenlib/BLI_string_ref.hh b/source/blender/blenlib/BLI_string_ref.hh
index 06fc66f6b55..e30eccca891 100644
--- a/source/blender/blenlib/BLI_string_ref.hh
+++ b/source/blender/blenlib/BLI_string_ref.hh
@@ -14,8 +14,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_STRING_REF_HH__
-#define __BLI_STRING_REF_HH__
+#pragma once
/** \file
* \ingroup bli
@@ -38,13 +37,16 @@
* Both types are certainly very similar. The main benefit of using StringRef in Blender is that
* this allows us to add convenience methods at any time. Especially, when doing a lot of string
* manipulation, this helps to keep the code clean. Furthermore, we need StringRefNull anyway,
- * because there is a lot of C code that expects null-terminated strings. Once we use C++17,
- * implicit conversions to and from string_view can be added.
+ * because there is a lot of C code that expects null-terminated strings. Conversion between
+ * StringRef and string_view is very cheap and can be done at api boundaries at essentially no
+ * cost. Another benefit of using StringRef is that it uses signed integers, thus developers
+ * have to deal less with issues resulting from unsigned integers.
*/
#include <cstring>
#include <sstream>
#include <string>
+#include <string_view>
#include "BLI_span.hh"
#include "BLI_utildefines.h"
@@ -67,6 +69,9 @@ class StringRefBase {
}
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.
*/
@@ -75,6 +80,11 @@ class StringRefBase {
return size_;
}
+ bool is_empty() const
+ {
+ return size_ == 0;
+ }
+
/**
* Return a pointer to the start of the string.
*/
@@ -94,7 +104,12 @@ class StringRefBase {
*/
operator std::string() const
{
- return std::string(data_, (size_t)size_);
+ return std::string(data_, static_cast<size_t>(size_));
+ }
+
+ operator std::string_view() const
+ {
+ return std::string_view(data_, static_cast<size_t>(size_));
}
const char *begin() const
@@ -114,7 +129,7 @@ class StringRefBase {
*/
void unsafe_copy(char *dst) const
{
- memcpy(dst, data_, (size_t)size_);
+ memcpy(dst, data_, static_cast<size_t>(size_));
dst[size_] = '\0';
}
@@ -153,6 +168,41 @@ class StringRefBase {
bool endswith(StringRef suffix) const;
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.
+ */
+ 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.
+ */
+ const char &back() const
+ {
+ BLI_assert(size_ >= 1);
+ return data_[size_ - 1];
+ }
+
+ /**
+ * The behavior of those functions matches the standard library implementation of
+ * std::string_view.
+ */
+ int64_t find(char c, int64_t pos = 0) const;
+ int64_t find(StringRef str, int64_t pos = 0) const;
+ int64_t rfind(char c, int64_t pos = INT64_MAX) const;
+ int64_t rfind(StringRef str, int64_t pos = INT64_MAX) const;
+ int64_t find_first_of(StringRef chars, int64_t pos = 0) const;
+ int64_t find_first_of(char c, int64_t pos = 0) const;
+ int64_t find_last_of(StringRef chars, int64_t pos = INT64_MAX) const;
+ int64_t find_last_of(char c, int64_t pos = INT64_MAX) const;
+ int64_t find_first_not_of(StringRef chars, int64_t pos = 0) const;
+ int64_t find_first_not_of(char c, int64_t pos = 0) const;
+ int64_t find_last_not_of(StringRef chars, int64_t pos = INT64_MAX) const;
+ int64_t find_last_not_of(char c, int64_t pos = INT64_MAX) const;
};
/**
@@ -166,9 +216,10 @@ class StringRefNull : public StringRefBase {
}
/**
- * Construct a StringRefNull from a null terminated c-string. The pointer must not point to NULL.
+ * Construct a StringRefNull from a null terminated c-string. The pointer must not point to
+ * NULL.
*/
- StringRefNull(const char *str) : StringRefBase(str, (int64_t)strlen(str))
+ StringRefNull(const char *str) : StringRefBase(str, static_cast<int64_t>(strlen(str)))
{
BLI_assert(str != NULL);
BLI_assert(data_[size_] == '\0');
@@ -180,7 +231,7 @@ class StringRefNull : public StringRefBase {
*/
StringRefNull(const char *str, const int64_t size) : StringRefBase(str, size)
{
- BLI_assert((int64_t)strlen(str) == size);
+ BLI_assert(static_cast<int64_t>(strlen(str)) == size);
}
/**
@@ -232,7 +283,7 @@ class StringRef : public StringRefBase {
/**
* Create a StringRef from a null-terminated c-string.
*/
- StringRef(const char *str) : StringRefBase(str, str ? (int64_t)strlen(str) : 0)
+ StringRef(const char *str) : StringRefBase(str, str ? static_cast<int64_t>(strlen(str)) : 0)
{
}
@@ -245,7 +296,7 @@ class StringRef : public StringRefBase {
* second point points to a smaller address than the first one.
*/
StringRef(const char *begin, const char *one_after_end)
- : StringRefBase(begin, (int64_t)(one_after_end - begin))
+ : StringRefBase(begin, static_cast<int64_t>(one_after_end - begin))
{
BLI_assert(begin <= one_after_end);
}
@@ -254,12 +305,18 @@ class StringRef : public StringRefBase {
* 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(), (int64_t)str.size())
+ StringRef(const std::string &str) : StringRefBase(str.data(), static_cast<int64_t>(str.size()))
+ {
+ }
+
+ StringRef(std::string_view view) : StringRefBase(view.data(), static_cast<int64_t>(view.size()))
{
}
/**
- * Return a new StringRef that does not contain the first n chars.
+ * Returns a new StringRef that does not contain the first n chars.
+ *
+ * This is similar to std::string_view::remove_prefix.
*/
StringRef drop_prefix(const int64_t n) const
{
@@ -269,8 +326,8 @@ class StringRef : public StringRefBase {
}
/**
- * Return a new StringRef that with the given prefix being skipped.
- * Asserts that the string begins with the given prefix.
+ * Return a new StringRef with the given prefix being skipped. This invokes undefined behavior if
+ * the string does not begin with the given prefix.
*/
StringRef drop_prefix(StringRef prefix) const
{
@@ -279,6 +336,18 @@ class StringRef : public StringRefBase {
}
/**
+ * Return a new StringRef that does not contain the last n chars.
+ *
+ * This is similar to std::string_view::remove_suffix.
+ */
+ StringRef drop_suffix(const int64_t n) const
+ {
+ BLI_assert(n >= 0);
+ BLI_assert(n <= size_);
+ return StringRef(data_, size_ - n);
+ }
+
+ /**
* Get the char at the given index.
*/
char operator[](int64_t index) const
@@ -313,6 +382,10 @@ 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. */
inline bool operator==(StringRef a, StringRef b)
{
if (a.size() != b.size()) {
@@ -362,14 +435,82 @@ inline bool StringRefBase::endswith(StringRef suffix) const
/**
* Return a new #StringRef containing only a sub-string of the original string.
*/
-inline StringRef StringRefBase::substr(const int64_t start, const int64_t size) const
+inline StringRef StringRefBase::substr(const int64_t start,
+ const int64_t max_size = INT64_MAX) const
{
- BLI_assert(size >= 0);
+ BLI_assert(max_size >= 0);
BLI_assert(start >= 0);
- BLI_assert(start + size <= size_);
- return StringRef(data_ + start, size);
+ const int64_t substr_size = std::min(max_size, size_ - start);
+ return StringRef(data_ + start, substr_size);
}
-} // namespace blender
+inline int64_t index_or_npos_to_int64(size_t index)
+{
+ /* The compiler will probably optimize this check away. */
+ if (index == std::string_view::npos) {
+ return StringRef::not_found;
+ }
+ return static_cast<int64_t>(index);
+}
+
+inline 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)));
+}
+
+inline 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)));
+}
+
+inline 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)));
+}
+
+inline int64_t StringRefBase::find_first_of(char c, int64_t pos) const
+{
+ return this->find_first_of(StringRef(&c, 1), pos);
+}
+
+inline 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)));
+}
-#endif /* __BLI_STRING_REF_HH__ */
+inline int64_t StringRefBase::find_last_of(char c, int64_t pos) const
+{
+ return this->find_last_of(StringRef(&c, 1), pos);
+}
+
+inline 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)));
+}
+
+inline int64_t StringRefBase::find_first_not_of(char c, int64_t pos) const
+{
+ return this->find_first_not_of(StringRef(&c, 1), pos);
+}
+
+inline 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)));
+}
+
+inline int64_t StringRefBase::find_last_not_of(char c, int64_t pos) const
+{
+ return this->find_last_not_of(StringRef(&c, 1), pos);
+}
+
+} // namespace blender