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