// Copyright (C) 2021-2022 Joel Rosdahl and other contributors // // See doc/AUTHORS.adoc for a complete list of contributors. // // This program is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the Free // Software Foundation; either version 3 of the License, or (at your option) // any later version. // // This program 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 // this program; if not, write to the Free Software Foundation, Inc., 51 // Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #pragma once #include #include #include namespace util { // An instance of this class can be used in a range-based for loop to split a // string into tokens at any of the characters in a string of delimiters. class Tokenizer { public: enum class Mode { include_empty, // Include empty tokens. skip_empty, // Skip empty tokens. }; enum class IncludeDelimiter { no, yes }; // Split `string` into tokens at any of the characters in `separators` which // must neither be the empty string nor a nullptr. Tokenizer(std::string_view string, const char* delimiters, Mode mode = Mode::skip_empty, IncludeDelimiter include_delimiter = IncludeDelimiter::no); class Iterator { public: Iterator(const Tokenizer& tokenizer, size_t start_pos); Iterator operator++(); bool operator!=(const Iterator& other) const; std::string_view operator*() const; private: const Tokenizer& m_tokenizer; size_t m_left; size_t m_right; void advance(bool initial); }; Iterator begin(); Iterator end(); private: friend Iterator; const std::string_view m_string; const char* const m_delimiters; const Mode m_mode; const IncludeDelimiter m_include_delimiter; }; inline Tokenizer::Tokenizer(const std::string_view string, const char* const delimiters, Tokenizer::Mode mode, Tokenizer::IncludeDelimiter include_delimiter) : m_string(string), m_delimiters(delimiters), m_mode(mode), m_include_delimiter(include_delimiter) { DEBUG_ASSERT(delimiters != nullptr && delimiters[0] != '\0'); } inline Tokenizer::Iterator::Iterator(const Tokenizer& tokenizer, const size_t start_pos) : m_tokenizer(tokenizer), m_left(start_pos), m_right(start_pos) { if (start_pos == 0) { advance(true); } else { DEBUG_ASSERT(start_pos == std::string_view::npos); } } inline Tokenizer::Iterator Tokenizer::Iterator::operator++() { advance(false); return *this; } inline bool Tokenizer::Iterator::operator!=(const Iterator& other) const { return &m_tokenizer != &other.m_tokenizer || m_left != other.m_left; } inline Tokenizer::Iterator Tokenizer::begin() { return Iterator(*this, 0); } inline Tokenizer::Iterator Tokenizer::end() { return Iterator(*this, std::string_view::npos); } } // namespace util