Blender  V2.93
BLI_string_ref.hh
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 #pragma once
18 
46 #include <cstring>
47 #include <sstream>
48 #include <string>
49 #include <string_view>
50 
51 #include "BLI_span.hh"
52 #include "BLI_utildefines.h"
53 
54 namespace blender {
55 
56 class StringRef;
57 
63  protected:
64  const char *data_;
66 
67  constexpr StringRefBase(const char *data, const int64_t size) : data_(data), size_(size)
68  {
69  }
70 
71  public:
72  /* Similar to string_view::npos, but signed. */
73  static constexpr int64_t not_found = -1;
74 
78  constexpr int64_t size() const
79  {
80  return size_;
81  }
82 
83  constexpr bool is_empty() const
84  {
85  return size_ == 0;
86  }
87 
91  constexpr const char *data() const
92  {
93  return data_;
94  }
95 
96  constexpr operator Span<char>() const
97  {
98  return Span<char>(data_, size_);
99  }
100 
105  operator std::string() const
106  {
107  return std::string(data_, static_cast<size_t>(size_));
108  }
109 
110  constexpr operator std::string_view() const
111  {
112  return std::string_view(data_, static_cast<size_t>(size_));
113  }
114 
115  constexpr const char *begin() const
116  {
117  return data_;
118  }
119 
120  constexpr const char *end() const
121  {
122  return data_ + size_;
123  }
124 
125  constexpr IndexRange index_range() const
126  {
127  return IndexRange(size_);
128  }
129 
135  void unsafe_copy(char *dst) const
136  {
137  memcpy(dst, data_, static_cast<size_t>(size_));
138  dst[size_] = '\0';
139  }
140 
145  void copy(char *dst, const int64_t dst_size) const
146  {
147  if (size_ < dst_size) {
148  this->unsafe_copy(dst);
149  }
150  else {
151  BLI_assert(false);
152  dst[0] = '\0';
153  }
154  }
155 
160  template<size_t N> void copy(char (&dst)[N]) const
161  {
162  this->copy(dst, N);
163  }
164 
168  constexpr bool startswith(StringRef prefix) const;
169 
173  constexpr bool endswith(StringRef suffix) const;
174 
175  constexpr StringRef substr(int64_t start, const int64_t size) const;
176 
180  constexpr const char &front() const
181  {
182  BLI_assert(size_ >= 1);
183  return data_[0];
184  }
185 
189  constexpr const char &back() const
190  {
191  BLI_assert(size_ >= 1);
192  return data_[size_ - 1];
193  }
194 
199  constexpr int64_t find(char c, int64_t pos = 0) const;
200  constexpr int64_t find(StringRef str, int64_t pos = 0) const;
201  constexpr int64_t rfind(char c, int64_t pos = INT64_MAX) const;
203  constexpr int64_t find_first_of(StringRef chars, int64_t pos = 0) const;
204  constexpr int64_t find_first_of(char c, int64_t pos = 0) const;
205  constexpr int64_t find_last_of(StringRef chars, int64_t pos = INT64_MAX) const;
206  constexpr int64_t find_last_of(char c, int64_t pos = INT64_MAX) const;
207  constexpr int64_t find_first_not_of(StringRef chars, int64_t pos = 0) const;
208  constexpr int64_t find_first_not_of(char c, int64_t pos = 0) const;
209  constexpr int64_t find_last_not_of(StringRef chars, int64_t pos = INT64_MAX) const;
210  constexpr int64_t find_last_not_of(char c, int64_t pos = INT64_MAX) const;
211 };
212 
216 class StringRefNull : public StringRefBase {
217 
218  public:
219  constexpr StringRefNull() : StringRefBase("", 0)
220  {
221  }
222 
227  StringRefNull(const char *str) : StringRefBase(str, static_cast<int64_t>(strlen(str)))
228  {
229  BLI_assert(str != nullptr);
230  BLI_assert(data_[size_] == '\0');
231  }
232 
237  constexpr StringRefNull(const char *str, const int64_t size) : StringRefBase(str, size)
238  {
239  BLI_assert(static_cast<int64_t>(strlen(str)) == size);
240  }
241 
246  StringRefNull(const std::string &str) : StringRefNull(str.c_str())
247  {
248  }
249 
253  constexpr char operator[](const int64_t index) const
254  {
255  BLI_assert(index >= 0);
256  /* Use '<=' instead of just '<', so that the null character can be accessed as well. */
257  BLI_assert(index <= size_);
258  return data_[index];
259  }
260 
266  constexpr const char *c_str() const
267  {
268  return data_;
269  }
270 };
271 
275 class StringRef : public StringRefBase {
276  public:
277  constexpr StringRef() : StringRefBase(nullptr, 0)
278  {
279  }
280 
284  constexpr StringRef(StringRefNull other) : StringRefBase(other.data(), other.size())
285  {
286  }
287 
291  constexpr StringRef(const char *str)
292  : StringRefBase(str, str ? static_cast<int64_t>(std::char_traits<char>::length(str)) : 0)
293  {
294  }
295 
296  constexpr StringRef(const char *str, const int64_t length) : StringRefBase(str, length)
297  {
298  }
299 
304  constexpr StringRef(const char *begin, const char *one_after_end)
305  : StringRefBase(begin, static_cast<int64_t>(one_after_end - begin))
306  {
307  BLI_assert(begin <= one_after_end);
308  }
309 
314  StringRef(const std::string &str) : StringRefBase(str.data(), static_cast<int64_t>(str.size()))
315  {
316  }
317 
318  constexpr StringRef(std::string_view view)
319  : StringRefBase(view.data(), static_cast<int64_t>(view.size()))
320  {
321  }
322 
327  constexpr StringRef drop_prefix(const int64_t n) const
328  {
329  BLI_assert(n >= 0);
330  const int64_t clamped_n = std::min(n, size_);
331  const int64_t new_size = size_ - clamped_n;
332  return StringRef(data_ + clamped_n, new_size);
333  }
334 
339  constexpr StringRef drop_known_prefix(StringRef prefix) const
340  {
341  BLI_assert(this->startswith(prefix));
342  return this->drop_prefix(prefix.size());
343  }
344 
349  constexpr StringRef drop_suffix(const int64_t n) const
350  {
351  BLI_assert(n >= 0);
352  const int64_t new_size = std::max<int64_t>(0, size_ - n);
353  return StringRef(data_, new_size);
354  }
355 
359  constexpr char operator[](int64_t index) const
360  {
361  BLI_assert(index >= 0);
362  BLI_assert(index < size_);
363  return data_[index];
364  }
365 };
366 
367 /* More inline functions
368  ***************************************/
369 
370 inline std::ostream &operator<<(std::ostream &stream, StringRef ref)
371 {
372  stream << std::string(ref);
373  return stream;
374 }
375 
376 inline std::ostream &operator<<(std::ostream &stream, StringRefNull ref)
377 {
378  stream << std::string(ref.data(), (size_t)ref.size());
379  return stream;
380 }
381 
386 inline std::string operator+(StringRef a, StringRef b)
387 {
388  return std::string(a) + std::string(b);
389 }
390 
391 /* This does not compare StringRef and std::string_view, because of ambiguous overloads. This is
392  * not a problem when std::string_view is only used at api boundaries. To compare a StringRef and a
393  * std::string_view, one should convert the std::string_view to StringRef (which is very cheap).
394  * Ideally, we only use StringRef in our code to avoid this problem altogether. */
395 constexpr inline bool operator==(StringRef a, StringRef b)
396 {
397  if (a.size() != b.size()) {
398  return false;
399  }
400  return STREQLEN(a.data(), b.data(), (size_t)a.size());
401 }
402 
403 constexpr inline bool operator!=(StringRef a, StringRef b)
404 {
405  return !(a == b);
406 }
407 
408 constexpr inline bool operator<(StringRef a, StringRef b)
409 {
410  return std::string_view(a) < std::string_view(b);
411 }
412 
413 constexpr inline bool operator>(StringRef a, StringRef b)
414 {
415  return std::string_view(a) > std::string_view(b);
416 }
417 
418 constexpr inline bool operator<=(StringRef a, StringRef b)
419 {
420  return std::string_view(a) <= std::string_view(b);
421 }
422 
423 constexpr inline bool operator>=(StringRef a, StringRef b)
424 {
425  return std::string_view(a) >= std::string_view(b);
426 }
427 
431 constexpr inline bool StringRefBase::startswith(StringRef prefix) const
432 {
433  if (size_ < prefix.size_) {
434  return false;
435  }
436  for (int64_t i = 0; i < prefix.size_; i++) {
437  if (data_[i] != prefix.data_[i]) {
438  return false;
439  }
440  }
441  return true;
442 }
443 
447 constexpr inline bool StringRefBase::endswith(StringRef suffix) const
448 {
449  if (size_ < suffix.size_) {
450  return false;
451  }
452  const int64_t offset = size_ - suffix.size_;
453  for (int64_t i = 0; i < suffix.size_; i++) {
454  if (data_[offset + i] != suffix.data_[i]) {
455  return false;
456  }
457  }
458  return true;
459 }
460 
465 constexpr inline StringRef StringRefBase::substr(const int64_t start,
466  const int64_t max_size = INT64_MAX) const
467 {
468  BLI_assert(max_size >= 0);
469  BLI_assert(start >= 0);
470  const int64_t substr_size = std::min(max_size, size_ - start);
471  return StringRef(data_ + start, substr_size);
472 }
473 
474 constexpr inline int64_t index_or_npos_to_int64(size_t index)
475 {
476  /* The compiler will probably optimize this check away. */
477  if (index == std::string_view::npos) {
478  return StringRef::not_found;
479  }
480  return static_cast<int64_t>(index);
481 }
482 
483 constexpr inline int64_t StringRefBase::find(char c, int64_t pos) const
484 {
485  BLI_assert(pos >= 0);
486  return index_or_npos_to_int64(std::string_view(*this).find(c, static_cast<size_t>(pos)));
487 }
488 
490 {
491  BLI_assert(pos >= 0);
492  return index_or_npos_to_int64(std::string_view(*this).find(str, static_cast<size_t>(pos)));
493 }
494 
496 {
497  BLI_assert(pos >= 0);
498  return index_or_npos_to_int64(
499  std::string_view(*this).find_first_of(chars, static_cast<size_t>(pos)));
500 }
501 
502 constexpr inline int64_t StringRefBase::find_first_of(char c, int64_t pos) const
503 {
504  return this->find_first_of(StringRef(&c, 1), pos);
505 }
506 
508 {
509  BLI_assert(pos >= 0);
510  return index_or_npos_to_int64(
511  std::string_view(*this).find_last_of(chars, static_cast<size_t>(pos)));
512 }
513 
514 constexpr inline int64_t StringRefBase::find_last_of(char c, int64_t pos) const
515 {
516  return this->find_last_of(StringRef(&c, 1), pos);
517 }
518 
520 {
521  BLI_assert(pos >= 0);
522  return index_or_npos_to_int64(
523  std::string_view(*this).find_first_not_of(chars, static_cast<size_t>(pos)));
524 }
525 
526 constexpr inline int64_t StringRefBase::find_first_not_of(char c, int64_t pos) const
527 {
528  return this->find_first_not_of(StringRef(&c, 1), pos);
529 }
530 
532 {
533  BLI_assert(pos >= 0);
534  return index_or_npos_to_int64(
535  std::string_view(*this).find_last_not_of(chars, static_cast<size_t>(pos)));
536 }
537 
538 constexpr inline int64_t StringRefBase::find_last_not_of(char c, int64_t pos) const
539 {
540  return this->find_last_not_of(StringRef(&c, 1), pos);
541 }
542 
543 } // namespace blender
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define STREQLEN(a, b, n)
static AppView * view
SIMD_FORCE_INLINE btScalar length(const btQuaternion &q)
Return the length of a quaternion.
Definition: btQuaternion.h:895
void unsafe_copy(char *dst) const
constexpr const char * data() const
static constexpr int64_t not_found
constexpr int64_t rfind(char c, int64_t pos=INT64_MAX) const
constexpr const char & front() 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 & back() 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
void copy(char(&dst)[N]) const
constexpr bool is_empty() const
constexpr const char * end() const
constexpr int64_t rfind(StringRef str, int64_t pos=INT64_MAX) const
constexpr const char * begin() const
constexpr bool startswith(StringRef prefix) const
constexpr StringRef substr(int64_t start, const int64_t size) const
constexpr StringRefBase(const char *data, const int64_t size)
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(char *dst, const int64_t dst_size) const
StringRefNull(const char *str)
StringRefNull(const std::string &str)
constexpr char operator[](const int64_t index) const
constexpr StringRefNull(const char *str, const int64_t size)
constexpr const char * c_str() const
constexpr StringRef(const char *str, const int64_t length)
constexpr char operator[](int64_t index) const
constexpr StringRef(const char *begin, const char *one_after_end)
constexpr StringRef(std::string_view view)
constexpr StringRef drop_suffix(const int64_t n) const
constexpr StringRef drop_known_prefix(StringRef prefix) const
constexpr StringRef(StringRefNull other)
StringRef(const std::string &str)
constexpr StringRef(const char *str)
constexpr StringRef drop_prefix(const int64_t n) const
#define str(s)
uint pos
static unsigned c
Definition: RandGen.cpp:97
static unsigned a[3]
Definition: RandGen.cpp:92
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, StringRef ref)
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)
params N
#define min(a, b)
Definition: sort.c:51
__int64 int64_t
Definition: stdint.h:92
#define INT64_MAX
Definition: stdint.h:142