| 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); |
| + } |
| +}; |