blob: b51a0e87fd8a127ae1224fa625cc1c75d8d5dcea [file] [log] [blame]
pkalinnikove77a62e2016-06-24 10:21:401// 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
Pavel Kalinnikovd7970632017-06-20 09:07:345#ifndef COMPONENTS_URL_PATTERN_INDEX_STRING_SPLITTER_H_
6#define COMPONENTS_URL_PATTERN_INDEX_STRING_SPLITTER_H_
pkalinnikove77a62e2016-06-24 10:21:407
8#include <iterator>
9
10#include "base/logging.h"
11#include "base/strings/string_piece.h"
12
Pavel Kalinnikovd7970632017-06-20 09:07:3413namespace url_pattern_index {
pkalinnikove77a62e2016-06-24 10:21:4014
15// A zero-allocation string splitter. Splits a string into non-empty tokens
16// divided by separator characters as defined by the IsSeparator predicate.
17// However, instead of materializing and returning a collection of all tokens in
18// the string, it provides an InputIterator that can be used to extract the
19// tokens.
20//
21// TODO(pkalinnikov): Move it to "base/strings" after some generalization.
22template <typename IsSeparator>
23class StringSplitter {
24 public:
25 class Iterator
26 : public std::iterator<std::input_iterator_tag, base::StringPiece> {
27 public:
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)
pkalinnikov854818d62016-07-22 11:55:1032 : splitter_(&splitter), current_(head, 0), end_(splitter.text_.end()) {
33 DCHECK_GE(head, splitter_->text_.begin());
pkalinnikove77a62e2016-06-24 10:21:4034 DCHECK_LE(head, end_);
35
36 Advance();
37 }
38
39 bool operator==(const Iterator& rhs) const {
40 return current_.begin() == rhs.current_.begin();
41 }
42
43 bool operator!=(const Iterator& rhs) const { return !operator==(rhs); }
44
45 base::StringPiece operator*() const { return current_; }
46 const base::StringPiece* operator->() const { return &current_; }
47
48 Iterator& operator++() {
49 Advance();
50 return *this;
51 }
52
53 Iterator operator++(int) {
54 Iterator copy(*this);
55 operator++();
56 return copy;
57 }
58
59 private:
60 void Advance() {
61 auto begin = current_.end();
pkalinnikov854818d62016-07-22 11:55:1062 while (begin != end_ && splitter_->is_separator_(*begin))
pkalinnikove77a62e2016-06-24 10:21:4063 ++begin;
64 auto end = begin;
pkalinnikov854818d62016-07-22 11:55:1065 while (end != end_ && !splitter_->is_separator_(*end))
pkalinnikove77a62e2016-06-24 10:21:4066 ++end;
67 current_ = base::StringPiece(begin, end - begin);
68 }
69
pkalinnikov854818d62016-07-22 11:55:1070 const StringSplitter* splitter_;
pkalinnikove77a62e2016-06-24 10:21:4071
72 // Contains the token currently pointed to by the iterator.
73 base::StringPiece current_;
74 // Always points to the text_.end().
75 base::StringPiece::const_iterator end_;
76 };
77
78 // Constructs a splitter for iterating over non-empty tokens contained in the
79 // |text|. |is_separator| predicate is used to determine whether a certain
80 // character is a separator.
81 StringSplitter(base::StringPiece text,
82 IsSeparator is_separator = IsSeparator())
83 : text_(text), is_separator_(is_separator) {}
84
85 Iterator begin() const { return Iterator(*this, text_.begin()); }
86 Iterator end() const { return Iterator(*this, text_.end()); }
87
88 private:
89 base::StringPiece text_;
90 IsSeparator is_separator_;
91};
92
93template <typename IsSeparator>
94StringSplitter<IsSeparator> CreateStringSplitter(base::StringPiece text,
95 IsSeparator is_separator) {
96 return StringSplitter<IsSeparator>(text, is_separator);
97}
98
Pavel Kalinnikovd7970632017-06-20 09:07:3499} // namespace url_pattern_index
pkalinnikove77a62e2016-06-24 10:21:40100
Pavel Kalinnikovd7970632017-06-20 09:07:34101#endif // COMPONENTS_URL_PATTERN_INDEX_STRING_SPLITTER_H_