string_splitter.h 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. // Copyright 2016 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef COMPONENTS_URL_PATTERN_INDEX_STRING_SPLITTER_H_
  5. #define COMPONENTS_URL_PATTERN_INDEX_STRING_SPLITTER_H_
  6. #include <iterator>
  7. #include "base/check_op.h"
  8. #include "base/memory/raw_ptr.h"
  9. #include "base/strings/string_piece.h"
  10. namespace url_pattern_index {
  11. // A zero-allocation string splitter. Splits a string into non-empty tokens
  12. // divided by separator characters as defined by the IsSeparator predicate.
  13. // However, instead of materializing and returning a collection of all tokens in
  14. // the string, it provides an InputIterator that can be used to extract the
  15. // tokens.
  16. //
  17. // TODO(pkalinnikov): Move it to "base/strings" after some generalization.
  18. template <typename IsSeparator>
  19. class StringSplitter {
  20. public:
  21. class Iterator {
  22. public:
  23. using iterator_category = std::input_iterator_tag;
  24. using value_type = base::StringPiece;
  25. using difference_type = std::ptrdiff_t;
  26. using pointer = base::StringPiece*;
  27. using reference = base::StringPiece&;
  28. // Creates an iterator, which points to the leftmost token within the
  29. // |splitter|'s |text|, starting from |head|.
  30. Iterator(const StringSplitter& splitter,
  31. base::StringPiece::const_iterator head)
  32. : splitter_(&splitter), current_(head, 0), end_(splitter.text_.end()) {
  33. DCHECK_GE(head, splitter_->text_.begin());
  34. DCHECK_LE(head, end_);
  35. Advance();
  36. }
  37. bool operator==(const Iterator& rhs) const {
  38. return current_.begin() == rhs.current_.begin();
  39. }
  40. bool operator!=(const Iterator& rhs) const { return !operator==(rhs); }
  41. base::StringPiece operator*() const { return current_; }
  42. const base::StringPiece* operator->() const { return &current_; }
  43. Iterator& operator++() {
  44. Advance();
  45. return *this;
  46. }
  47. Iterator operator++(int) {
  48. Iterator copy(*this);
  49. operator++();
  50. return copy;
  51. }
  52. private:
  53. void Advance() {
  54. base::StringPiece::const_iterator begin = current_.end();
  55. while (begin != end_ && splitter_->is_separator_(*begin))
  56. ++begin;
  57. base::StringPiece::const_iterator end = begin;
  58. while (end != end_ && !splitter_->is_separator_(*end))
  59. ++end;
  60. current_ = base::StringPiece(begin, end - begin);
  61. }
  62. raw_ptr<const StringSplitter<IsSeparator>> splitter_;
  63. // Contains the token currently pointed to by the iterator.
  64. base::StringPiece current_;
  65. // Always points to the text_.end().
  66. base::StringPiece::const_iterator end_;
  67. };
  68. // Constructs a splitter for iterating over non-empty tokens contained in the
  69. // |text|. |is_separator| predicate is used to determine whether a certain
  70. // character is a separator.
  71. StringSplitter(base::StringPiece text,
  72. IsSeparator is_separator = IsSeparator())
  73. : text_(text), is_separator_(is_separator) {}
  74. Iterator begin() const { return Iterator(*this, text_.begin()); }
  75. Iterator end() const { return Iterator(*this, text_.end()); }
  76. private:
  77. base::StringPiece text_;
  78. IsSeparator is_separator_;
  79. };
  80. template <typename IsSeparator>
  81. StringSplitter<IsSeparator> CreateStringSplitter(base::StringPiece text,
  82. IsSeparator is_separator) {
  83. return StringSplitter<IsSeparator>(text, is_separator);
  84. }
  85. } // namespace url_pattern_index
  86. #endif // COMPONENTS_URL_PATTERN_INDEX_STRING_SPLITTER_H_