mirror of https://github.com/JAJames/jessilib.git
Jessica James
3 years ago
3 changed files with 264 additions and 1 deletions
@ -0,0 +1,49 @@ |
|||
//
|
|||
// Created by jessi on 11/9/2021.
|
|||
//
|
|||
|
|||
#pragma once |
|||
|
|||
#include <string_view> |
|||
#include <vector> |
|||
|
|||
namespace jessilib { |
|||
|
|||
/** Splits an input string into substrings */ |
|||
template<typename InStringT, typename ResultT = std::vector<InStringT>> |
|||
constexpr ResultT split(const InStringT& in_string, typename InStringT::value_type in_delim) { |
|||
ResultT result; |
|||
// Nothing to return
|
|||
if (in_string.empty()) { |
|||
return result; |
|||
} |
|||
|
|||
// If only MSVC didn't suck, we could use begin() and end()...
|
|||
auto begin = in_string.data(); |
|||
auto end = in_string.data() + in_string.size(); |
|||
for (auto itr = begin; itr != end; ++itr) { |
|||
if (*itr == in_delim) { |
|||
// Push token to result
|
|||
result.emplace_back(begin, itr - begin); |
|||
begin = itr + 1; |
|||
} |
|||
} |
|||
|
|||
// begin == end only if last character was in_delim
|
|||
if (begin == end) { |
|||
result.emplace_back(); |
|||
} |
|||
else { |
|||
result.emplace_back(begin, end - begin); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
/** Splits an input string into view substrings (same as split, but different default return type) */ |
|||
template<typename InStringT, typename ResultT = std::vector<std::basic_string_view<typename InStringT::value_type>>> |
|||
constexpr ResultT split_view(const InStringT& in_string, typename InStringT::value_type in_delim) { |
|||
return split<InStringT, ResultT>(in_string, in_delim); |
|||
} |
|||
|
|||
} // namespace jessilib
|
@ -0,0 +1,214 @@ |
|||
/**
|
|||
* Copyright (C) 2021 Jessica James. |
|||
* |
|||
* Permission to use, copy, modify, and/or distribute this software for any |
|||
* purpose with or without fee is hereby granted, provided that the above |
|||
* copyright notice and this permission notice appear in all copies. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
|||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
|||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
|||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|||
* |
|||
* Written by Jessica James <jessica.aj@outlook.com> |
|||
*/ |
|||
|
|||
#include "split.hpp" |
|||
#include <cassert> |
|||
#include <deque> |
|||
#include <list> |
|||
#include "test.hpp" |
|||
|
|||
using namespace jessilib; |
|||
using namespace std::literals; |
|||
|
|||
// empty strings
|
|||
|
|||
using char_types = ::testing::Types<char, unsigned char, signed char, wchar_t, char8_t, char16_t, char32_t>; |
|||
using text_char_types = ::testing::Types<char, unsigned char, signed char, wchar_t, char8_t, char16_t, char32_t>; |
|||
|
|||
template<typename T> |
|||
class SplitSVTest : public ::testing::Test { |
|||
public: |
|||
}; |
|||
TYPED_TEST_SUITE(SplitSVTest, char_types); |
|||
|
|||
template<typename T> |
|||
class SplitSringTest : public ::testing::Test { |
|||
public: |
|||
}; |
|||
TYPED_TEST_SUITE(SplitSringTest, char_types); |
|||
|
|||
template<typename T> |
|||
class SplitViewSVTest : public ::testing::Test { |
|||
public: |
|||
}; |
|||
TYPED_TEST_SUITE(SplitViewSVTest, char_types); |
|||
|
|||
template<typename T> |
|||
class SplitViewStringTest : public ::testing::Test { |
|||
public: |
|||
}; |
|||
TYPED_TEST_SUITE(SplitViewStringTest, char_types); |
|||
|
|||
template<typename T> |
|||
std::basic_string<T> make_word(size_t length = 8, T delim = static_cast<T>(0)) { |
|||
std::basic_string<T> result; |
|||
|
|||
if (length == 0) { |
|||
throw std::runtime_error{ "length == 0" }; |
|||
} |
|||
|
|||
result.push_back(delim + 1); |
|||
while (result.size() < length) { |
|||
auto chr = result.back() + 1; |
|||
if (chr == delim) { |
|||
++chr; |
|||
} |
|||
result.push_back(chr); |
|||
} |
|||
|
|||
if (result.size() != length) { |
|||
std::string errmsg = std::to_string(result.size()) + " != " + std::to_string(length) + "; result.size() != length"; |
|||
throw std::runtime_error{ errmsg }; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
template<typename T> |
|||
std::basic_string_view<T> make_word_view(size_t length = 8, T delim = static_cast<T>(0)) { |
|||
static std::basic_string<T> s_result; |
|||
s_result = make_word(length, delim); |
|||
return s_result; |
|||
} |
|||
|
|||
TYPED_TEST(SplitSVTest, empty) { |
|||
std::basic_string_view<TypeParam> empty; |
|||
std::vector<decltype(empty)> split_result = split(empty, static_cast<TypeParam>(0)); |
|||
EXPECT_TRUE(split_result.empty()); |
|||
} |
|||
|
|||
TYPED_TEST(SplitSVTest, single_word) { |
|||
std::basic_string_view<TypeParam> single_word = make_word_view<TypeParam>(); |
|||
std::vector<decltype(single_word)> split_result = split(single_word, static_cast<TypeParam>(0)); |
|||
EXPECT_EQ(split_result.size(), 1); |
|||
EXPECT_EQ(split_result[0].size(), 8); |
|||
} |
|||
|
|||
TYPED_TEST(SplitSVTest, single_word_trailing_delim) { |
|||
auto word = make_word<TypeParam>(); |
|||
word += static_cast<TypeParam>(0); |
|||
std::basic_string_view<TypeParam> single_word = word; |
|||
std::vector<decltype(single_word)> split_result = split(single_word, static_cast<TypeParam>(0)); |
|||
EXPECT_EQ(split_result.size(), 2); |
|||
EXPECT_EQ(split_result[0].size(), 8); |
|||
EXPECT_EQ(split_result[1].size(), 0); |
|||
} |
|||
|
|||
TYPED_TEST(SplitSVTest, single_word_prefix_delim) { |
|||
std::basic_string<TypeParam> word; |
|||
word += static_cast<TypeParam>(0); |
|||
word += make_word<TypeParam>(); |
|||
std::basic_string_view<TypeParam> single_word = word; |
|||
std::vector<decltype(single_word)> split_result = split(single_word, static_cast<TypeParam>(0)); |
|||
EXPECT_EQ(split_result.size(), 2); |
|||
EXPECT_EQ(split_result[0].size(), 0); |
|||
EXPECT_EQ(split_result[1].size(), 8); |
|||
} |
|||
|
|||
TYPED_TEST(SplitSVTest, single_word_surround_delim) { |
|||
std::basic_string<TypeParam> word; |
|||
word += static_cast<TypeParam>(0); |
|||
word += make_word<TypeParam>(); |
|||
word += static_cast<TypeParam>(0); |
|||
std::basic_string_view<TypeParam> single_word = word; |
|||
std::vector<decltype(single_word)> split_result = split(single_word, static_cast<TypeParam>(0)); |
|||
EXPECT_EQ(split_result.size(), 3); |
|||
EXPECT_EQ(split_result[0].size(), 0); |
|||
EXPECT_EQ(split_result[1].size(), 8); |
|||
EXPECT_EQ(split_result[2].size(), 0); |
|||
} |
|||
|
|||
TYPED_TEST(SplitSVTest, two_words) { |
|||
auto word = make_word<TypeParam>(); |
|||
word += static_cast<TypeParam>(0); |
|||
word += make_word<TypeParam>(); |
|||
std::basic_string_view<TypeParam> words = word; |
|||
std::vector<decltype(words)> split_result = split(words, static_cast<TypeParam>(0)); |
|||
EXPECT_EQ(split_result.size(), 2); |
|||
EXPECT_EQ(split_result[0].size(), 8); |
|||
EXPECT_EQ(split_result[1].size(), 8); |
|||
} |
|||
|
|||
TYPED_TEST(SplitSVTest, three_words) { |
|||
auto word = make_word<TypeParam>(3); |
|||
word += static_cast<TypeParam>(0); |
|||
word += make_word<TypeParam>(5); |
|||
word += static_cast<TypeParam>(0); |
|||
word += make_word<TypeParam>(9); |
|||
std::basic_string_view<TypeParam> words = word; |
|||
std::vector<decltype(words)> split_result = split(words, static_cast<TypeParam>(0)); |
|||
EXPECT_EQ(split_result.size(), 3); |
|||
EXPECT_EQ(split_result[0].size(), 3); |
|||
EXPECT_EQ(split_result[1].size(), 5); |
|||
EXPECT_EQ(split_result[2].size(), 9); |
|||
} |
|||
|
|||
/** std::string split test, really just testing compilation */ |
|||
|
|||
TYPED_TEST(SplitSringTest, empty) { |
|||
std::basic_string<TypeParam> empty; |
|||
std::vector<decltype(empty)> split_result = split(empty, static_cast<TypeParam>(0)); |
|||
EXPECT_TRUE(split_result.empty()); |
|||
} |
|||
|
|||
TYPED_TEST(SplitSringTest, single_word) { |
|||
std::basic_string<TypeParam> single_word = make_word<TypeParam>(); |
|||
std::vector<decltype(single_word)> split_result = split(single_word, static_cast<TypeParam>(0)); |
|||
EXPECT_EQ(split_result.size(), 1); |
|||
EXPECT_EQ(split_result[0].size(), 8); |
|||
} |
|||
|
|||
/** Some basic tests for compiling with different containers */ |
|||
|
|||
TYPED_TEST(SplitSVTest, empty_deque) { |
|||
std::basic_string_view<TypeParam> empty; |
|||
std::deque<decltype(empty)> split_result = split<decltype(empty), std::deque<decltype(empty)>>(empty, static_cast<TypeParam>(0)); |
|||
EXPECT_TRUE(split_result.empty()); |
|||
} |
|||
|
|||
TYPED_TEST(SplitSVTest, empty_list) { |
|||
std::basic_string_view<TypeParam> empty; |
|||
std::list<decltype(empty)> split_result = split<decltype(empty), std::list<decltype(empty)>>(empty, static_cast<TypeParam>(0)); |
|||
EXPECT_TRUE(split_result.empty()); |
|||
} |
|||
|
|||
/** SplitViewSVTest, really just compilation tests */ |
|||
|
|||
TYPED_TEST(SplitViewSVTest, empty) { |
|||
std::basic_string_view<TypeParam> empty; |
|||
std::vector<decltype(empty)> split_result = split_view(empty, static_cast<TypeParam>(0)); |
|||
EXPECT_TRUE(split_result.empty()); |
|||
} |
|||
|
|||
TYPED_TEST(SplitViewSVTest, single_word) { |
|||
std::basic_string_view<TypeParam> single_word = make_word_view<TypeParam>(); |
|||
std::vector<decltype(single_word)> split_result = split_view(single_word, static_cast<TypeParam>(0)); |
|||
EXPECT_EQ(split_result.size(), 1); |
|||
} |
|||
|
|||
TYPED_TEST(SplitViewStringTest, empty) { |
|||
std::basic_string<TypeParam> empty; |
|||
std::vector<std::basic_string_view<TypeParam>> split_result = split_view(empty, static_cast<TypeParam>(0)); |
|||
EXPECT_TRUE(split_result.empty()); |
|||
} |
|||
|
|||
TYPED_TEST(SplitViewStringTest, single_word) { |
|||
std::basic_string<TypeParam> single_word = make_word<TypeParam>(); |
|||
std::vector<std::basic_string_view<TypeParam>> split_result = split_view(single_word, static_cast<TypeParam>(0)); |
|||
EXPECT_EQ(split_result.size(), 1); |
|||
} |
Loading…
Reference in new issue