Blender  V3.3
BLI_string_ref.hh
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #pragma once
4 
32 #include <cstring>
33 #include <sstream>
34 #include <string>
35 #include <string_view>
36 
37 #include "BLI_span.hh"
38 #include "BLI_utildefines.h"
39 
40 namespace blender {
41 
42 class StringRef;
43 
49  protected:
50  const char *data_;
52 
53  constexpr StringRefBase(const char *data, int64_t size);
54 
55  public:
56  /* Similar to string_view::npos, but signed. */
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 
72  void unsafe_copy(char *dst) const;
73  void copy(char *dst, int64_t dst_size) const;
74  template<size_t N> void copy(char (&dst)[N]) const;
75 
76  constexpr bool startswith(StringRef prefix) const;
77  constexpr bool endswith(StringRef suffix) const;
78  constexpr StringRef substr(int64_t start, int64_t size) const;
79 
80  constexpr const char &front() const;
81  constexpr const char &back() const;
82 
87  constexpr int64_t find(char c, int64_t pos = 0) const;
88  constexpr int64_t find(StringRef str, int64_t pos = 0) const;
89  constexpr int64_t rfind(char c, int64_t pos = INT64_MAX) const;
90  constexpr int64_t rfind(StringRef str, int64_t pos = INT64_MAX) const;
91  constexpr int64_t find_first_of(StringRef chars, int64_t pos = 0) const;
92  constexpr int64_t find_first_of(char c, int64_t pos = 0) const;
93  constexpr int64_t find_last_of(StringRef chars, int64_t pos = INT64_MAX) const;
94  constexpr int64_t find_last_of(char c, int64_t pos = INT64_MAX) const;
95  constexpr int64_t find_first_not_of(StringRef chars, int64_t pos = 0) const;
96  constexpr int64_t find_first_not_of(char c, int64_t pos = 0) const;
97  constexpr int64_t find_last_not_of(StringRef chars, int64_t pos = INT64_MAX) const;
98  constexpr int64_t find_last_not_of(char c, int64_t pos = INT64_MAX) const;
99 
100  constexpr StringRef trim() const;
101  constexpr StringRef trim(StringRef characters_to_remove) const;
102  constexpr StringRef trim(char character_to_remove) const;
103 };
104 
108 class StringRefNull : public StringRefBase {
109 
110  public:
111  constexpr StringRefNull();
112  constexpr StringRefNull(const char *str, int64_t size);
113  StringRefNull(const char *str);
114  StringRefNull(const std::string &str);
115 
116  constexpr char operator[](int64_t index) const;
117  constexpr const char *c_str() const;
118 };
119 
123 class StringRef : public StringRefBase {
124  public:
125  constexpr StringRef();
126  constexpr StringRef(StringRefNull other);
127  constexpr StringRef(const char *str);
128  constexpr StringRef(const char *str, int64_t length);
129  constexpr StringRef(const char *begin, const char *one_after_end);
130  constexpr StringRef(std::string_view view);
131  StringRef(const std::string &str);
132 
133  constexpr StringRef drop_prefix(int64_t n) const;
134  constexpr StringRef drop_known_prefix(StringRef prefix) const;
135  constexpr StringRef drop_suffix(int64_t n) const;
136 
137  constexpr char operator[](int64_t index) const;
138 };
139 
140 /* -------------------------------------------------------------------- */
144 constexpr StringRefBase::StringRefBase(const char *data, const int64_t size)
145  : data_(data), size_(size)
146 {
147 }
148 
152 constexpr int64_t StringRefBase::size() const
153 {
154  return size_;
155 }
156 
157 constexpr bool StringRefBase::is_empty() const
158 {
159  return size_ == 0;
160 }
161 
165 constexpr const char *StringRefBase::data() const
166 {
167  return data_;
168 }
169 
170 constexpr StringRefBase::operator Span<char>() const
171 {
172  return Span<char>(data_, size_);
173 }
174 
179 inline StringRefBase::operator std::string() const
180 {
181  return std::string(data_, static_cast<size_t>(size_));
182 }
183 
184 constexpr StringRefBase::operator std::string_view() const
185 {
186  return std::string_view(data_, static_cast<size_t>(size_));
187 }
188 
189 constexpr const char *StringRefBase::begin() const
190 {
191  return data_;
192 }
193 
194 constexpr const char *StringRefBase::end() const
195 {
196  return data_ + size_;
197 }
198 
200 {
201  return IndexRange(size_);
202 }
203 
209 inline void StringRefBase::unsafe_copy(char *dst) const
210 {
211  if (size_ > 0) {
212  memcpy(dst, data_, static_cast<size_t>(size_));
213  }
214  dst[size_] = '\0';
215 }
216 
221 inline void StringRefBase::copy(char *dst, const int64_t dst_size) const
222 {
223  if (size_ < dst_size) {
224  this->unsafe_copy(dst);
225  }
226  else {
227  BLI_assert(false);
228  dst[0] = '\0';
229  }
230 }
231 
236 template<size_t N> inline void StringRefBase::copy(char (&dst)[N]) const
237 {
238  this->copy(dst, N);
239 }
240 
244 constexpr bool StringRefBase::startswith(StringRef prefix) const
245 {
246  if (size_ < prefix.size_) {
247  return false;
248  }
249  for (int64_t i = 0; i < prefix.size_; i++) {
250  if (data_[i] != prefix.data_[i]) {
251  return false;
252  }
253  }
254  return true;
255 }
256 
260 constexpr bool StringRefBase::endswith(StringRef suffix) const
261 {
262  if (size_ < suffix.size_) {
263  return false;
264  }
265  const int64_t offset = size_ - suffix.size_;
266  for (int64_t i = 0; i < suffix.size_; i++) {
267  if (data_[offset + i] != suffix.data_[i]) {
268  return false;
269  }
270  }
271  return true;
272 }
273 
279  const int64_t max_size = INT64_MAX) const
280 {
281  BLI_assert(max_size >= 0);
282  BLI_assert(start >= 0);
283  const int64_t substr_size = std::min(max_size, size_ - start);
284  return StringRef(data_ + start, substr_size);
285 }
286 
290 constexpr const char &StringRefBase::front() const
291 {
292  BLI_assert(size_ >= 1);
293  return data_[0];
294 }
295 
299 constexpr const char &StringRefBase::back() const
300 {
301  BLI_assert(size_ >= 1);
302  return data_[size_ - 1];
303 }
304 
305 constexpr int64_t index_or_npos_to_int64(size_t index)
306 {
307  /* The compiler will probably optimize this check away. */
308  if (index == std::string_view::npos) {
309  return StringRef::not_found;
310  }
311  return static_cast<int64_t>(index);
312 }
313 
314 constexpr int64_t StringRefBase::find(char c, int64_t pos) const
315 {
316  BLI_assert(pos >= 0);
317  return index_or_npos_to_int64(std::string_view(*this).find(c, static_cast<size_t>(pos)));
318 }
319 
321 {
322  BLI_assert(pos >= 0);
323  return index_or_npos_to_int64(std::string_view(*this).find(str, static_cast<size_t>(pos)));
324 }
325 
326 constexpr int64_t StringRefBase::rfind(char c, int64_t pos) const
327 {
328  BLI_assert(pos >= 0);
329  return index_or_npos_to_int64(std::string_view(*this).rfind(c, static_cast<size_t>(pos)));
330 }
331 
333 {
334  BLI_assert(pos >= 0);
335  return index_or_npos_to_int64(std::string_view(*this).rfind(str, static_cast<size_t>(pos)));
336 }
337 
339 {
340  BLI_assert(pos >= 0);
341  return index_or_npos_to_int64(
342  std::string_view(*this).find_first_of(chars, static_cast<size_t>(pos)));
343 }
344 
346 {
347  BLI_assert(pos >= 0);
348  return index_or_npos_to_int64(
349  std::string_view(*this).find_first_of(c, static_cast<size_t>(pos)));
350 }
351 
353 {
354  BLI_assert(pos >= 0);
355  return index_or_npos_to_int64(
356  std::string_view(*this).find_last_of(chars, static_cast<size_t>(pos)));
357 }
358 
360 {
361  BLI_assert(pos >= 0);
362  return index_or_npos_to_int64(std::string_view(*this).find_last_of(c, static_cast<size_t>(pos)));
363 }
364 
366 {
367  BLI_assert(pos >= 0);
368  return index_or_npos_to_int64(
369  std::string_view(*this).find_first_not_of(chars, static_cast<size_t>(pos)));
370 }
371 
373 {
374  BLI_assert(pos >= 0);
375  return index_or_npos_to_int64(
376  std::string_view(*this).find_first_not_of(c, static_cast<size_t>(pos)));
377 }
378 
380 {
381  BLI_assert(pos >= 0);
382  return index_or_npos_to_int64(
383  std::string_view(*this).find_last_not_of(chars, static_cast<size_t>(pos)));
384 }
385 
387 {
388  BLI_assert(pos >= 0);
389  return index_or_npos_to_int64(
390  std::string_view(*this).find_last_not_of(c, static_cast<size_t>(pos)));
391 }
392 
394 {
395  return this->trim(" \t\r\n");
396 }
397 
401 constexpr StringRef StringRefBase::trim(const char character_to_remove) const
402 {
403  return this->trim(StringRef(&character_to_remove, 1));
404 }
405 
410 constexpr StringRef StringRefBase::trim(StringRef characters_to_remove) const
411 {
412  const int64_t find_front = this->find_first_not_of(characters_to_remove);
413  if (find_front == not_found) {
414  return StringRef();
415  }
416  const int64_t find_end = this->find_last_not_of(characters_to_remove);
417  /* `find_end` cannot be `not_found`, because that means the string is only
418  * `characters_to_remove`, in which case `find_front` would already have
419  * been `not_found`. */
420  BLI_assert_msg(find_end != not_found,
421  "forward search found characters-to-not-remove, but backward search did not");
422  const int64_t substr_len = find_end - find_front + 1;
423  return this->substr(find_front, substr_len);
424 }
425 
428 /* -------------------------------------------------------------------- */
433 {
434 }
435 
440 constexpr StringRefNull::StringRefNull(const char *str, const int64_t size)
442 {
443  BLI_assert(static_cast<int64_t>(strlen(str)) == size);
444 }
445 
451  : StringRefBase(str, static_cast<int64_t>(strlen(str)))
452 {
453  BLI_assert(str != nullptr);
454  BLI_assert(data_[size_] == '\0');
455 }
456 
461 inline StringRefNull::StringRefNull(const std::string &str) : StringRefNull(str.c_str())
462 {
463 }
464 
468 constexpr char StringRefNull::operator[](const int64_t index) const
469 {
470  BLI_assert(index >= 0);
471  /* Use '<=' instead of just '<', so that the null character can be accessed as well. */
472  BLI_assert(index <= size_);
473  return data_[index];
474 }
475 
481 constexpr const char *StringRefNull::c_str() const
482 {
483  return data_;
484 }
485 
488 /* -------------------------------------------------------------------- */
492 constexpr StringRef::StringRef() : StringRefBase(nullptr, 0)
493 {
494 }
495 
499 constexpr StringRef::StringRef(StringRefNull other) : StringRefBase(other.data(), other.size())
500 {
501 }
502 
506 constexpr StringRef::StringRef(const char *str)
507  : StringRefBase(str, str ? static_cast<int64_t>(std::char_traits<char>::length(str)) : 0)
508 {
509 }
510 
511 constexpr StringRef::StringRef(const char *str, const int64_t length) : StringRefBase(str, length)
512 {
513 }
514 
519 constexpr StringRef StringRef::drop_prefix(const int64_t n) const
520 {
521  BLI_assert(n >= 0);
522  const int64_t clamped_n = std::min(n, size_);
523  const int64_t new_size = size_ - clamped_n;
524  return StringRef(data_ + clamped_n, new_size);
525 }
526 
532 {
533  BLI_assert(this->startswith(prefix));
534  return this->drop_prefix(prefix.size());
535 }
536 
541 constexpr StringRef StringRef::drop_suffix(const int64_t n) const
542 {
543  BLI_assert(n >= 0);
544  const int64_t new_size = std::max<int64_t>(0, size_ - n);
545  return StringRef(data_, new_size);
546 }
547 
551 constexpr char StringRef::operator[](int64_t index) const
552 {
553  BLI_assert(index >= 0);
554  BLI_assert(index < size_);
555  return data_[index];
556 }
557 
562 constexpr StringRef::StringRef(const char *begin, const char *one_after_end)
563  : StringRefBase(begin, static_cast<int64_t>(one_after_end - begin))
564 {
565  BLI_assert(begin <= one_after_end);
566 }
567 
572 inline StringRef::StringRef(const std::string &str)
573  : StringRefBase(str.data(), static_cast<int64_t>(str.size()))
574 {
575 }
576 
577 constexpr StringRef::StringRef(std::string_view view)
578  : StringRefBase(view.data(), static_cast<int64_t>(view.size()))
579 {
580 }
581 
584 /* -------------------------------------------------------------------- */
588 inline std::ostream &operator<<(std::ostream &stream, StringRef ref)
589 {
590  stream << std::string(ref);
591  return stream;
592 }
593 
594 inline std::ostream &operator<<(std::ostream &stream, StringRefNull ref)
595 {
596  stream << std::string(ref.data(), (size_t)ref.size());
597  return stream;
598 }
599 
604 inline std::string operator+(StringRef a, StringRef b)
605 {
606  return std::string(a) + std::string(b);
607 }
608 
609 /* This does not compare StringRef and std::string_view, because of ambiguous overloads. This is
610  * not a problem when std::string_view is only used at api boundaries. To compare a StringRef and a
611  * std::string_view, one should convert the std::string_view to StringRef (which is very cheap).
612  * Ideally, we only use StringRef in our code to avoid this problem altogether. */
613 constexpr bool operator==(StringRef a, StringRef b)
614 {
615  if (a.size() != b.size()) {
616  return false;
617  }
618  if (a.data() == b.data()) {
619  /* This also avoids passing null to the call below, which would results in an ASAN warning. */
620  return true;
621  }
622  return STREQLEN(a.data(), b.data(), (size_t)a.size());
623 }
624 
625 constexpr bool operator!=(StringRef a, StringRef b)
626 {
627  return !(a == b);
628 }
629 
630 constexpr bool operator<(StringRef a, StringRef b)
631 {
632  return std::string_view(a) < std::string_view(b);
633 }
634 
635 constexpr bool operator>(StringRef a, StringRef b)
636 {
637  return std::string_view(a) > std::string_view(b);
638 }
639 
640 constexpr bool operator<=(StringRef a, StringRef b)
641 {
642  return std::string_view(a) <= std::string_view(b);
643 }
644 
645 constexpr bool operator>=(StringRef a, StringRef b)
646 {
647  return std::string_view(a) >= std::string_view(b);
648 }
649 
652 } // namespace blender
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition: BLI_assert.h:53
#define STREQLEN(a, b, n)
static AppView * view
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
constexpr const char & front() const
void unsafe_copy(char *dst) 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
void copy(char *dst, int64_t dst_size) 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)
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
constexpr StringRef trim() const
constexpr const char * data() const
constexpr const char & back() const
constexpr const char * c_str() const
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
T * data_
Definition: eval_output.h:163
#define str(s)
uint pos
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
#define N
static unsigned c
Definition: RandGen.cpp:83
static unsigned a[3]
Definition: RandGen.cpp:78
T length(const vec_base< T, Size > &a)
constexpr bool operator!=(StringRef a, StringRef b)
constexpr int64_t index_or_npos_to_int64(size_t index)
constexpr bool operator==(StringRef a, StringRef b)
std::ostream & operator<<(std::ostream &stream, const eAlpha &space)
Definition: BLI_color.cc:7
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)
std::string operator+(StringRef a, StringRef b)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
#define min(a, b)
Definition: sort.c:35
__int64 int64_t
Definition: stdint.h:89
#define INT64_MAX
Definition: stdint.h:139