Blender V5.0
BLI_string_ref.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#pragma once
6
33
34#include <cstring>
35#include <string>
36#include <string_view>
37
38#include "BLI_span.hh"
39
40namespace blender {
41
42class StringRef;
43
49 protected:
50 const char *data_;
52
53 constexpr StringRefBase(const char *data, int64_t size);
54
55 public:
57 static constexpr int64_t not_found = -1;
58
59 constexpr int64_t size() const;
60 constexpr bool is_empty() const;
61 constexpr const char *data() const;
62 constexpr operator Span<char>() const;
63
64 operator std::string() const;
65 constexpr operator std::string_view() const;
66
67 constexpr const char *begin() const;
68 constexpr const char *end() const;
69
70 constexpr IndexRange index_range() const;
71
77 void copy_utf8_truncated(char *dst, int64_t dst_size) const;
78 template<size_t N> void copy_utf8_truncated(char (&dst)[N]) const;
79
88 void copy_bytes_truncated(char *dst, int64_t dst_size) const;
89 template<size_t N> void copy_bytes_truncated(char (&dst)[N]) const;
90
96 void copy_unsafe(char *dst) const;
97
98 constexpr bool startswith(StringRef prefix) const;
99 constexpr bool endswith(StringRef suffix) const;
100 constexpr StringRef substr(int64_t start, int64_t size) const;
101
102 constexpr const char &front() const;
103 constexpr const char &back() const;
104
109 constexpr int64_t find(char c, int64_t pos = 0) const;
110 constexpr int64_t find(StringRef str, int64_t pos = 0) const;
111 constexpr int64_t rfind(char c, int64_t pos = INT64_MAX) const;
112 constexpr int64_t rfind(StringRef str, int64_t pos = INT64_MAX) const;
113 constexpr int64_t find_first_of(StringRef chars, int64_t pos = 0) const;
114 constexpr int64_t find_first_of(char c, int64_t pos = 0) const;
115 constexpr int64_t find_last_of(StringRef chars, int64_t pos = INT64_MAX) const;
116 constexpr int64_t find_last_of(char c, int64_t pos = INT64_MAX) const;
117 constexpr int64_t find_first_not_of(StringRef chars, int64_t pos = 0) const;
118 constexpr int64_t find_first_not_of(char c, int64_t pos = 0) const;
119 constexpr int64_t find_last_not_of(StringRef chars, int64_t pos = INT64_MAX) const;
120 constexpr int64_t find_last_not_of(char c, int64_t pos = INT64_MAX) const;
121
122 constexpr StringRef trim() const;
123 constexpr StringRef trim(StringRef characters_to_remove) const;
124 constexpr StringRef trim(char character_to_remove) const;
125};
126
133
134 public:
135 constexpr StringRefNull();
136 constexpr StringRefNull(const char *str, int64_t size);
137 StringRefNull(std::nullptr_t) = delete;
138 constexpr StringRefNull(const char *str);
139 StringRefNull(const std::string &str);
140
141 constexpr char operator[](int64_t index) const;
142 constexpr const char *c_str() const;
143};
144
150class StringRef : public StringRefBase {
151 public:
152 constexpr StringRef();
153 constexpr StringRef(StringRefNull other);
154 constexpr StringRef(const char *str);
155 constexpr StringRef(const char *str, int64_t length);
156 constexpr StringRef(const char *begin, const char *one_after_end);
157 constexpr StringRef(std::string_view view);
158 constexpr StringRef(Span<char> span);
159 StringRef(const std::string &str);
160
161 constexpr StringRef drop_prefix(int64_t n) const;
162 constexpr StringRef drop_known_prefix(StringRef prefix) const;
163 constexpr StringRef drop_suffix(int64_t n) const;
164 constexpr StringRef drop_known_suffix(StringRef suffix) const;
165
166 constexpr char operator[](int64_t index) const;
167};
168
169/* -------------------------------------------------------------------- */
172
173constexpr StringRefBase::StringRefBase(const char *data, const int64_t size)
174 : data_(data), size_(size)
175{
176}
177
182{
183 return size_;
184}
185
186constexpr bool StringRefBase::is_empty() const
187{
188 return size_ == 0;
189}
190
194constexpr const char *StringRefBase::data() const
195{
196 return data_;
197}
198
199constexpr StringRefBase::operator Span<char>() const
200{
201 return Span<char>(data_, size_);
202}
203
208inline StringRefBase::operator std::string() const
209{
210 return std::string(data_, size_t(size_));
211}
212
213constexpr StringRefBase::operator std::string_view() const
214{
215 return std::string_view(data_, size_t(size_));
216}
217
218constexpr const char *StringRefBase::begin() const
219{
220 return data_;
221}
222
223constexpr const char *StringRefBase::end() const
224{
225 return data_ + size_;
226}
227
229{
230 return IndexRange(size_);
231}
232
233inline void StringRefBase::copy_unsafe(char *dst) const
234{
235 if (size_ > 0) {
236 memcpy(dst, data_, size_t(size_));
237 }
238 dst[size_] = '\0';
239}
240
241template<size_t N> inline void StringRefBase::copy_utf8_truncated(char (&dst)[N]) const
242{
243 this->copy_utf8_truncated(dst, N);
244}
245
246template<size_t N> inline void StringRefBase::copy_bytes_truncated(char (&dst)[N]) const
247{
248 this->copy_bytes_truncated(dst, N);
249}
250
254constexpr bool StringRefBase::startswith(StringRef prefix) const
255{
256 if (size_ < prefix.size_) {
257 return false;
258 }
259 for (int64_t i = 0; i < prefix.size_; i++) {
260 if (data_[i] != prefix.data_[i]) {
261 return false;
262 }
263 }
264 return true;
265}
266
270constexpr bool StringRefBase::endswith(StringRef suffix) const
271{
272 if (size_ < suffix.size_) {
273 return false;
274 }
275 const int64_t offset = size_ - suffix.size_;
276 for (int64_t i = 0; i < suffix.size_; i++) {
277 if (data_[offset + i] != suffix.data_[i]) {
278 return false;
279 }
280 }
281 return true;
282}
283
289 const int64_t max_size = INT64_MAX) const
290{
291 BLI_assert(max_size >= 0);
292 BLI_assert(start >= 0);
293 const int64_t substr_size = std::min(max_size, size_ - start);
294 return StringRef(data_ + start, substr_size);
295}
296
300constexpr const char &StringRefBase::front() const
301{
302 BLI_assert(size_ >= 1);
303 return data_[0];
304}
305
309constexpr const char &StringRefBase::back() const
310{
311 BLI_assert(size_ >= 1);
312 return data_[size_ - 1];
313}
314
315constexpr int64_t index_or_npos_to_int64(size_t index)
316{
317 /* The compiler will probably optimize this check away. */
318 if (index == std::string_view::npos) {
320 }
321 return int64_t(index);
322}
323
324constexpr int64_t StringRefBase::find(char c, int64_t pos) const
325{
326 BLI_assert(pos >= 0);
327 return index_or_npos_to_int64(std::string_view(*this).find(c, size_t(pos)));
328}
329
331{
332 BLI_assert(pos >= 0);
333 return index_or_npos_to_int64(std::string_view(*this).find(str, size_t(pos)));
334}
335
336constexpr int64_t StringRefBase::rfind(char c, int64_t pos) const
337{
338 BLI_assert(pos >= 0);
339 return index_or_npos_to_int64(std::string_view(*this).rfind(c, size_t(pos)));
340}
341
343{
344 BLI_assert(pos >= 0);
345 return index_or_npos_to_int64(std::string_view(*this).rfind(str, size_t(pos)));
346}
347
349{
350 BLI_assert(pos >= 0);
351 return index_or_npos_to_int64(std::string_view(*this).find_first_of(chars, size_t(pos)));
352}
353
355{
356 BLI_assert(pos >= 0);
357 return index_or_npos_to_int64(std::string_view(*this).find_first_of(c, size_t(pos)));
358}
359
361{
362 BLI_assert(pos >= 0);
363 return index_or_npos_to_int64(std::string_view(*this).find_last_of(chars, size_t(pos)));
364}
365
367{
368 BLI_assert(pos >= 0);
369 return index_or_npos_to_int64(std::string_view(*this).find_last_of(c, size_t(pos)));
370}
371
373{
374 BLI_assert(pos >= 0);
375 return index_or_npos_to_int64(std::string_view(*this).find_first_not_of(chars, size_t(pos)));
376}
377
379{
380 BLI_assert(pos >= 0);
381 return index_or_npos_to_int64(std::string_view(*this).find_first_not_of(c, size_t(pos)));
382}
383
385{
386 BLI_assert(pos >= 0);
387 return index_or_npos_to_int64(std::string_view(*this).find_last_not_of(chars, size_t(pos)));
388}
389
391{
392 BLI_assert(pos >= 0);
393 return index_or_npos_to_int64(std::string_view(*this).find_last_not_of(c, size_t(pos)));
394}
395
397{
398 return this->trim(" \t\r\n");
399}
400
404constexpr StringRef StringRefBase::trim(const char character_to_remove) const
405{
406 return this->trim(StringRef(&character_to_remove, 1));
407}
408
413constexpr StringRef StringRefBase::trim(StringRef characters_to_remove) const
414{
415 const int64_t find_front = this->find_first_not_of(characters_to_remove);
416 if (find_front == not_found) {
417 return StringRef();
418 }
419 const int64_t find_end = this->find_last_not_of(characters_to_remove);
420 /* `find_end` cannot be `not_found`, because that means the string is only
421 * `characters_to_remove`, in which case `find_front` would already have
422 * been `not_found`. */
423 BLI_assert_msg(find_end != not_found,
424 "forward search found characters-to-not-remove, but backward search did not");
425 const int64_t substr_len = find_end - find_front + 1;
426 return this->substr(find_front, substr_len);
427}
428
430
431/* -------------------------------------------------------------------- */
434
436
441constexpr StringRefNull::StringRefNull(const char *str, const int64_t size)
443{
444 BLI_assert(int64_t(std::char_traits<char>::length(str)) == size);
445}
446
451constexpr StringRefNull::StringRefNull(const char *str)
452 : StringRefBase(str, int64_t(std::char_traits<char>::length(str)))
453{
454 BLI_assert(str != nullptr);
455 BLI_assert(data_[size_] == '\0');
456}
457
462inline StringRefNull::StringRefNull(const std::string &str)
464{
465}
466
470constexpr char StringRefNull::operator[](const int64_t index) const
471{
472 BLI_assert(index >= 0);
473 /* Use '<=' instead of just '<', so that the null character can be accessed as well. */
474 BLI_assert(index <= size_);
475 return data_[index];
476}
477
483constexpr const char *StringRefNull::c_str() const
484{
485 return data_;
486}
487
489
490/* -------------------------------------------------------------------- */
493
495
499constexpr StringRef::StringRef(StringRefNull other) : StringRefBase(other.data(), other.size()) {}
500
504constexpr StringRef::StringRef(const char *str)
505 : StringRefBase(str, str ? int64_t(std::char_traits<char>::length(str)) : 0)
506{
507}
508
510{
511}
512
518{
519 BLI_assert(n >= 0);
520 const int64_t clamped_n = std::min(n, size_);
521 const int64_t new_size = size_ - clamped_n;
522 return StringRef(data_ + clamped_n, new_size);
523}
524
530{
531 BLI_assert(this->startswith(prefix));
532 return this->drop_prefix(prefix.size());
533}
534
540{
541 BLI_assert(n >= 0);
542 const int64_t new_size = std::max<int64_t>(0, size_ - n);
543 return StringRef(data_, new_size);
544}
545
551{
552 BLI_assert(this->endswith(suffix));
553 return this->drop_suffix(suffix.size());
554}
555
559constexpr char StringRef::operator[](int64_t index) const
560{
561 BLI_assert(index >= 0);
562 BLI_assert(index < size_);
563 return data_[index];
564}
565
570constexpr StringRef::StringRef(const char *begin, const char *one_after_end)
571 : StringRefBase(begin, int64_t(one_after_end - begin))
572{
573 BLI_assert(begin <= one_after_end);
574}
575
580inline StringRef::StringRef(const std::string &str)
582{
583}
584
585constexpr StringRef::StringRef(std::string_view view)
587{
588}
589
590constexpr StringRef::StringRef(Span<char> span) : StringRefBase(span.data(), span.size()) {}
591
593
594/* -------------------------------------------------------------------- */
597
598std::ostream &operator<<(std::ostream &stream, StringRef ref);
599std::ostream &operator<<(std::ostream &stream, StringRefNull ref);
600
605inline std::string operator+(StringRef a, StringRef b)
606{
607 return std::string(a) + std::string(b);
608}
609
620constexpr bool operator==(StringRef a, StringRef b)
621{
622 return std::string_view(a) == std::string_view(b);
623}
624
625constexpr bool operator!=(StringRef a, StringRef b)
626{
627 return std::string_view(a) != std::string_view(b);
628}
629
630constexpr bool operator<(StringRef a, StringRef b)
631{
632 return std::string_view(a) < std::string_view(b);
633}
634
635constexpr bool operator>(StringRef a, StringRef b)
636{
637 return std::string_view(a) > std::string_view(b);
638}
639
640constexpr bool operator<=(StringRef a, StringRef b)
641{
642 return std::string_view(a) <= std::string_view(b);
643}
644
645constexpr bool operator>=(StringRef a, StringRef b)
646{
647 return std::string_view(a) >= std::string_view(b);
648}
649
651
652/* -------------------------------------------------------------------- */
655
659inline std::string_view format_as(StringRef str)
660{
661 return str;
662}
663
665
666} // namespace blender
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
static AppView * view
long long int int64_t
void copy_unsafe(char *dst) const
constexpr const char & front() const
static constexpr int64_t not_found
constexpr int64_t rfind(char c, int64_t pos=INT64_MAX) const
constexpr int64_t find_last_of(StringRef chars, int64_t pos=INT64_MAX) const
constexpr int64_t find(char c, int64_t pos=0) const
constexpr const char * begin() const
constexpr const char * end() const
constexpr int64_t find_last_not_of(StringRef chars, int64_t pos=INT64_MAX) const
constexpr int64_t find_first_not_of(StringRef chars, int64_t pos=0) const
constexpr bool is_empty() const
constexpr StringRef substr(int64_t start, int64_t size) const
constexpr StringRefBase(const char *data, int64_t size)
void copy_bytes_truncated(char *dst, int64_t dst_size) const
Definition string_ref.cc:47
constexpr bool startswith(StringRef prefix) const
constexpr bool endswith(StringRef suffix) const
constexpr int64_t find_first_of(StringRef chars, int64_t pos=0) const
constexpr IndexRange index_range() const
constexpr int64_t size() const
void copy_utf8_truncated(char *dst, int64_t dst_size) const
Definition string_ref.cc:28
constexpr StringRef trim() const
constexpr const char * data() const
constexpr const char & back() const
constexpr const char * c_str() const
StringRefNull(std::nullptr_t)=delete
constexpr char operator[](int64_t index) const
constexpr StringRef drop_prefix(int64_t n) const
constexpr StringRef drop_suffix(int64_t n) const
constexpr char operator[](int64_t index) const
constexpr StringRef drop_known_prefix(StringRef prefix) const
constexpr StringRef drop_known_suffix(StringRef suffix) const
#define str(s)
#define INT64_MAX
uint pos
float length(VecOp< float, D >) RET
#define N
constexpr int64_t index_or_npos_to_int64(size_t index)
bool operator!=(const CPPType &a, const CPPType &b)
std::string_view format_as(StringRef str)
std::ostream & operator<<(std::ostream &stream, const eAlpha &space)
Definition BLI_color.cc:15
constexpr bool operator>=(StringRef a, StringRef b)
constexpr bool operator<(StringRef a, StringRef b)
constexpr bool operator<=(StringRef a, StringRef b)
constexpr bool operator>(StringRef a, StringRef b)
bool operator==(const CPPType &a, const CPPType &b)
std::string operator+(StringRef a, StringRef b)
i
Definition text_draw.cc:230