target_include_directories(ccache_lib PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
add_subdirectory(third_party)
+add_subdirectory(util)
#include "TemporaryFile.hpp"
#include "fmtmacros.hpp"
+#include <util/Tokenizer.hpp>
+
extern "C" {
#include "third_party/base32hex.h"
}
template<typename T>
std::vector<T>
-split_at(string_view input, const char* separators)
+split_into(string_view input, const char* separators)
{
- ASSERT(separators != nullptr && separators[0] != '\0');
-
std::vector<T> result;
-
- size_t start = 0;
- while (start < input.size()) {
- size_t end = input.find_first_of(separators, start);
-
- if (end == string_view::npos) {
- result.emplace_back(input.data() + start, input.size() - start);
- break;
- } else if (start != end) {
- result.emplace_back(input.data() + start, end - start);
- }
-
- start = end + 1;
+ for (const auto token : util::Tokenizer(input, separators)) {
+ result.emplace_back(token);
}
-
return result;
}
std::vector<string_view>
split_into_views(string_view input, const char* separators)
{
- return split_at<string_view>(input, separators);
+ return split_into<string_view>(input, separators);
}
std::vector<std::string>
split_into_strings(string_view input, const char* separators)
{
- return split_at<std::string>(input, separators);
+ return split_into<std::string>(input, separators);
}
std::string
--- /dev/null
+set(
+ sources
+ ${CMAKE_CURRENT_SOURCE_DIR}/Tokenizer.cpp
+)
+
+target_sources(ccache_lib PRIVATE ${sources})
--- /dev/null
+// Copyright (C) 2021 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
+
+#include "Tokenizer.hpp"
+
+namespace util {
+
+Tokenizer::Iterator
+Tokenizer::Iterator::operator++()
+{
+ if (m_pos >= m_string.size()) {
+ return *this;
+ }
+
+ m_pos = m_string.find_first_not_of(m_delimiters, m_pos + m_count);
+ if (m_pos == nonstd::string_view::npos) {
+ m_pos = m_string.size();
+ m_count = 0;
+ } else {
+ m_count = m_string.substr(m_pos).find_first_of(m_delimiters);
+ if (m_count == nonstd::string_view::npos) {
+ m_count = m_string.size() - m_pos;
+ }
+ }
+ return *this;
+}
+
+} // namespace util
--- /dev/null
+// Copyright (C) 2021 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 <third_party/nonstd/optional.hpp>
+#include <third_party/nonstd/string_view.hpp>
+
+namespace util {
+
+class Tokenizer
+{
+public:
+ Tokenizer(nonstd::string_view string, const char* delimiters);
+
+ class Iterator
+ {
+ public:
+ Iterator(nonstd::string_view string,
+ const char* delimiters,
+ size_t start_pos);
+
+ Iterator operator++();
+ bool operator!=(const Iterator& other) const;
+ nonstd::string_view operator*() const;
+
+ private:
+ const nonstd::string_view m_string;
+ const char* const m_delimiters;
+ size_t m_pos;
+ size_t m_count = 0;
+ };
+
+ Iterator begin();
+ Iterator end();
+
+private:
+ const nonstd::string_view m_string;
+ const char* const m_delimiters;
+};
+
+inline Tokenizer::Tokenizer(const nonstd::string_view string,
+ const char* const delimiters)
+ : m_string(string),
+ m_delimiters(delimiters)
+{
+ assert(delimiters != nullptr && delimiters[0] != '\0');
+}
+
+inline Tokenizer::Iterator::Iterator(const nonstd::string_view string,
+ const char* const delimiters,
+ const size_t start_pos)
+ : m_string(string),
+ m_delimiters(delimiters),
+ m_pos(start_pos)
+{
+ ++*this;
+}
+
+inline bool
+Tokenizer::Iterator::operator!=(const Iterator& other) const
+{
+ assert(m_string.data() == other.m_string.data());
+ assert(m_delimiters == other.m_delimiters);
+ return m_pos != other.m_pos || m_count != other.m_count;
+}
+
+inline nonstd::string_view
+Tokenizer::Iterator::operator*() const
+{
+ assert(m_pos < m_string.size());
+ return m_string.substr(m_pos, m_count);
+}
+
+inline Tokenizer::Iterator
+Tokenizer::begin()
+{
+ return Iterator(m_string, m_delimiters, 0);
+}
+
+inline Tokenizer::Iterator
+Tokenizer::end()
+{
+ return Iterator(m_string, m_delimiters, m_string.size());
+}
+
+} // namespace util
test_argprocessing.cpp
test_ccache.cpp
test_compopt.cpp
- test_hashutil.cpp)
+ test_hashutil.cpp
+ test_util_Tokenizer.cpp
+)
if(INODE_CACHE_SUPPORTED)
list(APPEND source_files test_InodeCache.cpp)
#endif
}
-TEST_CASE("Util::split_into_views")
-{
- {
- CHECK(Util::split_into_views("", "/").empty());
- }
- {
- CHECK(Util::split_into_views("///", "/").empty());
- }
- {
- auto s = Util::split_into_views("a/b", "/");
- REQUIRE(s.size() == 2);
- CHECK(s.at(0) == "a");
- CHECK(s.at(1) == "b");
- }
- {
- auto s = Util::split_into_views("a/b", "x");
- REQUIRE(s.size() == 1);
- CHECK(s.at(0) == "a/b");
- }
- {
- auto s = Util::split_into_views("a/b:c", "/:");
- REQUIRE(s.size() == 3);
- CHECK(s.at(0) == "a");
- CHECK(s.at(1) == "b");
- CHECK(s.at(2) == "c");
- }
- {
- auto s = Util::split_into_views(":a//b..:.c/:/.", "/:.");
- REQUIRE(s.size() == 3);
- CHECK(s.at(0) == "a");
- CHECK(s.at(1) == "b");
- CHECK(s.at(2) == "c");
- }
- {
- auto s = Util::split_into_views(".0.1.2.3.4.5.6.7.8.9.", "/:.+_abcdef");
- REQUIRE(s.size() == 10);
- CHECK(s.at(0) == "0");
- CHECK(s.at(9) == "9");
- }
-}
-
-TEST_CASE("Util::split_into_strings")
-{
- {
- CHECK(Util::split_into_strings("", "/").empty());
- }
- {
- CHECK(Util::split_into_strings("///", "/").empty());
- }
- {
- auto s = Util::split_into_strings("a/b", "/");
- REQUIRE(s.size() == 2);
- CHECK(s.at(0) == "a");
- CHECK(s.at(1) == "b");
- }
- {
- auto s = Util::split_into_strings("a/b", "x");
- REQUIRE(s.size() == 1);
- CHECK(s.at(0) == "a/b");
- }
- {
- auto s = Util::split_into_strings("a/b:c", "/:");
- REQUIRE(s.size() == 3);
- CHECK(s.at(0) == "a");
- CHECK(s.at(1) == "b");
- CHECK(s.at(2) == "c");
- }
- {
- auto s = Util::split_into_strings(":a//b..:.c/:/.", "/:.");
- REQUIRE(s.size() == 3);
- CHECK(s.at(0) == "a");
- CHECK(s.at(1) == "b");
- CHECK(s.at(2) == "c");
- }
- {
- auto s = Util::split_into_strings(".0.1.2.3.4.5.6.7.8.9.", "/:.+_abcdef");
- REQUIRE(s.size() == 10);
- CHECK(s.at(0) == "0");
- CHECK(s.at(9) == "9");
- }
-}
+// Util::split_into_strings and Util::split_into_views are tested implicitly in
+// test_Tokenizer.cpp.
TEST_CASE("Util::starts_with")
{
--- /dev/null
+// Copyright (C) 2021 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
+
+#include "../src/Util.hpp"
+
+#include "third_party/doctest.h"
+
+TEST_CASE("util::Tokenizer")
+{
+ CHECK(Util::split_into_views("", "/").empty());
+ CHECK(Util::split_into_views("///", "/").empty());
+ {
+ const auto s = Util::split_into_views("a/b", "/");
+ REQUIRE(s.size() == 2);
+ CHECK(s[0] == "a");
+ CHECK(s[1] == "b");
+ }
+ {
+ const auto s = Util::split_into_views("a/b", "x");
+ REQUIRE(s.size() == 1);
+ CHECK(s[0] == "a/b");
+ }
+ {
+ const auto s = Util::split_into_views("a/b:c", "/:");
+ REQUIRE(s.size() == 3);
+ CHECK(s[0] == "a");
+ CHECK(s[1] == "b");
+ CHECK(s[2] == "c");
+ }
+ {
+ const auto s = Util::split_into_views(":a//b..:.c/:/.", "/:.");
+ REQUIRE(s.size() == 3);
+ CHECK(s[0] == "a");
+ CHECK(s[1] == "b");
+ CHECK(s[2] == "c");
+ }
+ {
+ const auto s =
+ Util::split_into_views(".0.1.2.3.4.5.6.7.8.9.", "/:.+_abcdef");
+ REQUIRE(s.size() == 10);
+ CHECK(s[0] == "0");
+ CHECK(s[9] == "9");
+ }
+}