Index: src/plugin/TokenSequence.h |
=================================================================== |
new file mode 100644 |
--- /dev/null |
+++ b/src/plugin/TokenSequence.h |
@@ -0,0 +1,163 @@ |
+/* |
+ * This file is part of Adblock Plus <https://adblockplus.org/>, |
+ * Copyright (C) 2006-2015 Eyeo GmbH |
+ * |
+ * Adblock Plus is free software: you can redistribute it and/or modify |
+ * it under the terms of the GNU General Public License version 3 as |
+ * published by the Free Software Foundation. |
+ * |
+ * Adblock Plus is distributed in the hope that it will be useful, |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
+ * GNU General Public License for more details. |
+ * |
+ * You should have received a copy of the GNU General Public License |
+ * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
+ */ |
+ |
+template<class T> class TokenSequenceConstIterator; // forward declaration |
+ |
+/** |
+ * A sequence of delimited tokens contained within a given string. |
+ */ |
+template<class T> |
+class TokenSequence |
+{ |
+ typedef TokenSequenceConstIterator<T> ConstIterator; |
+ friend class ConstIterator; |
+ const T delimiters; |
+ const T value; |
+ |
+ /** |
+ * Default constructor is deleted |
+ */ |
+ TokenSequence(); // = delete |
+ |
+public: |
+ TokenSequence(const T& value, const T& delimiters) |
+ : value(value), delimiters(delimiters) |
+ { |
+ if (delimiters.empty()) |
+ { |
+ // If we don't have delimiter characters, the 'first_first_*' functions will have undefined behavior. |
+ throw std::runtime_error("Must have at least one delimiter character"); |
+ } |
+ } |
+ |
+ ConstIterator cbegin() const |
+ { |
+ return ConstIterator(*this, ConstIterator::BeginMarker()); |
+ } |
+ |
+ ConstIterator cend() const |
+ { |
+ return ConstIterator(*this, ConstIterator::EndMarker()); |
+ } |
+}; |
+ |
+/** |
+ * Iterator class for TokenSequence<T> |
+ * |
+ * All constructors are private, only available to TokenSequence<T> through a friend declaration. |
+ * |
+ * Invariant |
+ * if posFirstCharInToken == npos |
+ * iterator is "end()" |
+ * else |
+ * 0 <= posFirstCharInToken < posFirstCharNotInToken <= length of underlying container string |
+ * first token position = posFirstCharInToken |
+ * token length = posFirstCharNotInToken - posFirstCharInToken |
+ */ |
+template<class T> |
+class TokenSequenceConstIterator |
+{ |
+ typedef TokenSequence<T> Container; |
+ friend class Container; |
+ const Container& sequence; |
+ size_t posFirstCharInToken; |
+ size_t posFirstCharNotInToken; |
+ |
+ class BeginMarker {}; |
+ class EndMarker {}; |
+ |
+ /** |
+ * Default constructor is deleted |
+ */ |
+ TokenSequenceConstIterator(); // = delete |
+ |
+ /** |
+ * Constructor for cbegin() |
+ */ |
+ TokenSequenceConstIterator(const TokenSequence<T>& sequence, BeginMarker) |
+ : sequence(sequence) |
+ { |
+ Advance(0); |
+ } |
+ |
+ /** |
+ * Constructor for cend() |
+ */ |
+ TokenSequenceConstIterator(const TokenSequence<T>& sequence, EndMarker) |
+ : sequence(sequence), posFirstCharInToken(T::npos) |
+ { |
+ } |
+ |
+ /** |
+ * Find the next token beginning at or after the given position |
+ */ |
+ void Advance(size_t posStart) |
+ { |
+ posFirstCharInToken = sequence.value.find_first_not_of(sequence.delimiters, posStart); |
+ if (posFirstCharInToken == T::npos) |
+ { |
+ // If we've become an "end()" iterator, we're done. |
+ return; |
+ } |
+ posFirstCharNotInToken = sequence.value.find_first_of(sequence.delimiters, posFirstCharInToken + 1); |
+ if (posFirstCharNotInToken == T::npos) |
+ { |
+ posFirstCharNotInToken = sequence.value.length(); |
+ } |
+ } |
+ |
+public: |
+ bool operator==(const TokenSequenceConstIterator& other) const |
+ { |
+ if (&sequence != &other.sequence) |
+ { |
+ return false; // iterators to different sequences cannot be equal |
+ } |
+ // Iterators with the same initial token position will also have the same final final position |
+ // "end()" iterators use "npos" as their position |
+ return posFirstCharInToken == other.posFirstCharInToken; |
+ } |
+ |
+ bool operator!=(const TokenSequenceConstIterator& other) const |
+ { |
+ return !operator==(other); |
+ } |
+ |
+ void operator++() |
+ { |
+ if (posFirstCharInToken == T::npos) |
+ { |
+ return; // Incrementing "end()" yields "end()" |
+ } |
+ if (posFirstCharNotInToken >= sequence.value.length()) |
+ { |
+ // We are already at the end of the sequence. No need to search more. |
+ posFirstCharInToken = T::npos; |
+ return; |
+ } |
+ Advance(posFirstCharNotInToken + 1); |
+ } |
+ |
+ T operator*() const |
+ { |
+ if (posFirstCharInToken == T::npos) |
+ { |
+ throw std::runtime_error("Cannot dereference end() iterator"); |
+ } |
+ return sequence.value.substr(posFirstCharInToken, posFirstCharNotInToken - posFirstCharInToken); |
+ } |
+}; |