#include <algorithm>
#include <array>
#include <cassert>
#include <concepts>
#include <map>
#include <ranges>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "test_macros.h"
template <std::ranges::view View, std::ranges::range Expected>
constexpr bool is_equal(View& view, const Expected& expected) {
return std::ranges::equal(view, expected, std::ranges::equal);
}
template <class T, class Separator, class U, std::size_t M>
constexpr bool test_function_call(T&& input, Separator&& separator, std::array<U, M> expected) {
std::ranges::split_view v(input, separator);
return is_equal(v, expected);
}
template <class T, class Separator, class U, std::size_t M>
constexpr bool test_with_piping(T&& input, Separator&& separator, std::array<U, M> expected) {
auto expected_it = expected.begin();
for (auto e : input | std::ranges::views::split(separator)) {
if (expected_it == expected.end())
return false;
if (!std::ranges::equal(e, *expected_it))
return false;
++expected_it;
}
return expected_it == expected.end();
}
constexpr bool test_l_r_values() {
using namespace std::string_view_literals;
{
{
auto input = "abc"sv;
auto sep = " "sv;
[[maybe_unused]] std::ranges::split_view v(input, sep);
}
{
const auto input = "abc"sv;
const auto sep = " "sv;
[[maybe_unused]] std::ranges::split_view v(input, sep);
}
{
auto input = "abc"sv;
auto sep = " "sv;
[[maybe_unused]] std::ranges::split_view v(std::move(input), std::move(sep));
}
{
const auto input = "abc"sv;
const auto sep = " "sv;
[[maybe_unused]] std::ranges::split_view v(std::move(input), std::move(sep));
}
}
return true;
}
constexpr bool test_string_literal_separator() {
using namespace std::string_view_literals;
{
std::ranges::split_view v("abc def"sv, ' ');
assert(is_equal(v, std::array{"abc"sv, "def"sv}));
}
{
std::ranges::split_view v("abc def"sv, " ");
assert(is_equal(v, std::array{"abc def"sv}));
}
{
std::ranges::split_view v("abc \0def"sv, " ");
assert(is_equal(v, std::array{"abc"sv, "def"sv}));
}
return true;
}
template <class T>
constexpr std::string_view sv(T&& str) {
return std::string_view(str);
};
template <class T, class Separator, class U, std::size_t M>
constexpr void test_one(T&& input, Separator&& separator, std::array<U, M> expected) {
assert(test_function_call(input, separator, expected));
assert(test_with_piping(input, separator, expected));
}
constexpr bool test_string_literals() {
using namespace std::string_view_literals;
char short_sep = ' ';
auto long_sep = "12"sv;
{
std::array expected = {"abc"sv, std::string_view("def", sizeof("def"))};
assert(test_function_call("abc def", short_sep, expected));
assert(test_with_piping("abc def", short_sep, expected));
assert(test_function_call("abc12def", long_sep, expected));
assert(test_with_piping("abc12def", long_sep, expected));
}
{
std::array expected = {std::string_view("", 1)};
assert(test_function_call("", short_sep, expected));
assert(test_with_piping("", short_sep, expected));
assert(test_function_call("", long_sep, expected));
assert(test_with_piping("", long_sep, expected));
}
{
const char input[] = "abc def";
std::array expected_unsplit = {std::string_view(input, sizeof(input))};
std::array expected_split = {"abc"sv, std::string_view("def", sizeof("def"))};
assert(test_function_call(input, " ", expected_unsplit));
assert(test_function_call("abc \0def", " ", expected_split));
}
{
auto empty_sep = ""sv;
std::array expected = {"a"sv, "b"sv, "c"sv, "\0"sv};
assert(test_function_call("abc", empty_sep, expected));
assert(test_with_piping("abc", empty_sep, expected));
}
return true;
}
bool test_nontrivial_characters() {
using Map = std::map<std::string, int>;
using Vec = std::vector<Map>;
Map sep = {{"yyy", 999}};
Map m1 = {
{"a", 1},
{"bc", 2},
};
Map m2 = {
{"def", 3},
};
Map m3 = {
{"g", 4},
{"hijk", 5},
};
Vec expected1 = {m1, m2};
Vec expected2 = {m3};
std::ranges::split_view v(Vec{m1, m2, sep, m3}, sep);
auto outer = v.begin();
assert(outer != v.end());
auto inner = (*outer).begin();
assert(*inner++ == m1);
assert(*inner++ == m2);
assert(inner == (*outer).end());
++outer;
assert(outer != v.end());
inner = (*outer).begin();
assert(*inner++ == m3);
assert(inner == (*outer).end());
++outer;
assert(outer == v.end());
return true;
}
constexpr bool main_test() {
using namespace std::string_view_literals;
char short_sep = ' ';
auto long_sep = "12"sv;
{
std::array expected = {"abc"sv, "def"sv};
test_one("abc def"sv, short_sep, expected);
test_one("abc12def"sv, long_sep, expected);
}
{
std::array expected = {"abc"sv, ""sv, ""sv, ""sv, "def"sv};
test_one("abc def"sv, short_sep, expected);
test_one("abc12121212def"sv, long_sep, expected);
}
{
std::array expected = {"abc"sv, "def"sv, ""sv};
test_one("abc def "sv, short_sep, expected);
test_one("abc12def12"sv, long_sep, expected);
}
{
std::array expected = {""sv, "abc"sv, "def"sv};
test_one(" abc def"sv, short_sep, expected);
test_one("12abc12def"sv, long_sep, expected);
}
{
std::array expected = {"abc"sv};
test_one("abc"sv, short_sep, expected);
test_one("abc"sv, long_sep, expected);
}
{
std::array expected = {""sv, ""sv};
test_one(" "sv, short_sep, expected);
test_one("12"sv, long_sep, expected);
}
{
std::array expected = {""sv, ""sv, ""sv, ""sv};
test_one(" "sv, short_sep, expected);
test_one("121212"sv, long_sep, expected);
}
{
auto overlapping_sep = "aaa"sv;
std::array expected = {""sv, "aa"sv};
test_one("aaaaa"sv, overlapping_sep, expected);
}
{
std::array expected = {""sv, ""sv, "abc"sv, ""sv, ""sv, "def"sv, ""sv, ""sv};
test_one(" abc def "sv, short_sep, expected);
test_one("1212abc121212def1212"sv, long_sep, expected);
}
{
std::array expected = {""sv, "a"sv, "b"sv, "c"sv, ""sv};
test_one(" a b c "sv, short_sep, expected);
test_one("12a12b12c12"sv, long_sep, expected);
}
{
auto overlapping_sep = "ab"sv;
std::array expected = {"a"sv, "aa"sv, ""sv, "b"sv};
test_one("aabaaababb"sv, overlapping_sep, expected);
}
{
std::array<std::string_view, 0> expected = {};
test_one(""sv, short_sep, expected);
test_one(""sv, long_sep, expected);
}
{
auto empty_sep = ""sv;
std::array expected = {"a"sv, "b"sv, "c"sv};
test_one("abc"sv, empty_sep, expected);
test_one("abc"sv, empty_sep, expected);
}
{
std::array expected = {"abc"sv, "def"sv};
test_one("abc\0def"sv, '\0', expected);
test_one("abc\0\0def"sv, "\0\0"sv, expected);
}
{
test_function_call("abc def", ' ', std::array{"abc"sv, "def"sv});
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test_function_call(L"abc def", L' ', std::array{L"abc"sv, L"def"sv});
#endif
test_function_call(u8"abc def", u8' ', std::array{u8"abc"sv, u8"def"sv});
test_function_call(u"abc def", u' ', std::array{u"abc"sv, u"def"sv});
test_function_call(U"abc def", U' ', std::array{U"abc"sv, U"def"sv});
}
{
std::array expected = {std::array{1, 2, 3}, std::array{4, 5, 6}};
test_one(std::array{1, 2, 3, 0, 4, 5, 6}, 0, expected);
test_one(std::array{1, 2, 3, 0, 0, 0, 4, 5, 6}, std::array{0, 0, 0}, expected);
}
return true;
}
constexpr bool example_test() {
std::string str{"the quick brown fox"};
std::vector<std::string_view> result;
for (auto r : std::views::split(str, ' ')) {
result.emplace_back(r.begin(), r.end());
}
using namespace std::string_view_literals;
auto expected = {"the"sv, "quick"sv, "brown"sv, "fox"sv};
assert(std::ranges::equal(result, expected));
return true;
}
int main(int, char**) {
example_test();
static_assert(example_test());
test_string_literals();
static_assert(test_string_literals());
test_l_r_values();
static_assert(test_l_r_values());
test_string_literal_separator();
static_assert(test_string_literal_separator());
test_nontrivial_characters();
return 0;
}