diff options
author | Jacques Lucke <jacques@blender.org> | 2021-10-03 15:10:26 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2021-10-03 15:10:26 +0300 |
commit | a8d6a86981b3bdcc8e9796a4465544523372c687 (patch) | |
tree | 111bc1e912f1e02d87575775a2f3e7f8fafa2ab1 | |
parent | c206fa9627c40b91d07e1abd951f06dbcf502f6d (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.hh | 658 |
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 |