Browse Source

vector pass

master
Jessica James 3 years ago
parent
commit
5267a4726d
  1. 23
      src/include/split.hpp
  2. 57
      src/test/split.cpp

23
src/include/split.hpp

@ -47,7 +47,15 @@ using split_container_helper_t = decltype(split_container_helper_f<ContainerT, A
} // namespace impl } // namespace impl
/** Splits an input string into substrings */ /**
* Splits an input string into substrings
*
* @tparam ContainerT Container type to store the results in
* @tparam ContainerArgsT Optional template parameters for ContainerT
* @param in_string String to split
* @param in_delim Delimiter to split upon
* @return Container populated with
*/
template<template<typename...> typename ContainerT = std::vector, typename... ContainerArgsT, typename InputT> template<template<typename...> typename ContainerT = std::vector, typename... ContainerArgsT, typename InputT>
constexpr auto split(const InputT& in_string, typename InputT::value_type in_delim) { constexpr auto split(const InputT& in_string, typename InputT::value_type in_delim) {
using MemberT = typename impl::first_arg<ContainerArgsT..., std::basic_string<typename InputT::value_type>>::first_type; using MemberT = typename impl::first_arg<ContainerArgsT..., std::basic_string<typename InputT::value_type>>::first_type;
@ -63,13 +71,13 @@ constexpr auto split(const InputT& in_string, typename InputT::value_type in_del
for (auto itr = begin; itr != end; ++itr) { for (auto itr = begin; itr != end; ++itr) {
if (*itr == in_delim) { if (*itr == in_delim) {
// Push token to result // Push token to result
result.emplace_back(begin, itr - begin); result.emplace_back(begin, itr);
begin = itr + 1; begin = itr + 1;
} }
} }
// Push final token to the end; may be empty // Push final token to the end; may be empty
result.emplace_back(begin, end - begin); result.emplace_back(begin, end);
return result; return result;
} }
@ -79,8 +87,9 @@ constexpr auto split(const InputT& in_string, typename InputT::value_type in_del
* An empty pair if in_string is empty, * An empty pair if in_string is empty,
* otherwise if the delimiter is not present, a pair who's `second` member is empty and `first` member is equal to `in_string`, * otherwise if the delimiter is not present, a pair who's `second` member is empty and `first` member is equal to `in_string`,
* otherwise, a pair split at first instance of the delimiter * otherwise, a pair split at first instance of the delimiter
* Complexity: O(in_string.size())
* *
* @tparam InStringT String type being passed into split_once
* @tparam ResultMemberT String type used to populate the result
* @param in_string string to split * @param in_string string to split
* @param in_delim delimiter to split on * @param in_delim delimiter to split on
* @return A pair representing `in_string` split at a delimiter, with first half stored in `first` and second in `last` * @return A pair representing `in_string` split at a delimiter, with first half stored in `first` and second in `last`
@ -117,7 +126,7 @@ constexpr std::pair<ResultMemberT, ResultMemberT> split_once(const InStringT& in
* @param in_string String to split * @param in_string String to split
* @param in_delim Delimiter to split upon * @param in_delim Delimiter to split upon
* @param in_limit Maximum number of times to split * @param in_limit Maximum number of times to split
* @return ResultT containing to up `in_limit` + 1 substrings * @return Container containing to up `in_limit` + 1 substrings; result[in_limit] is the unprocessed remainder
*/ */
template<template<typename...> typename ContainerT = std::vector, typename... ContainerArgsT, typename InputT> template<template<typename...> typename ContainerT = std::vector, typename... ContainerArgsT, typename InputT>
constexpr auto split_n(const InputT& in_string, typename InputT::value_type in_delim, size_t in_limit) { constexpr auto split_n(const InputT& in_string, typename InputT::value_type in_delim, size_t in_limit) {
@ -134,14 +143,14 @@ constexpr auto split_n(const InputT& in_string, typename InputT::value_type in_d
for (auto itr = begin; itr != end && in_limit != 0; ++itr) { for (auto itr = begin; itr != end && in_limit != 0; ++itr) {
if (*itr == in_delim) { if (*itr == in_delim) {
// Push token to result // Push token to result
result.emplace_back(begin, itr - begin); result.emplace_back(begin, itr);
begin = itr + 1; begin = itr + 1;
--in_limit; --in_limit;
} }
} }
// Push final token to the end; may be empty // Push final token to the end; may be empty
result.emplace_back(begin, end - begin); result.emplace_back(begin, end);
return result; return result;
} }

57
src/test/split.cpp

@ -67,9 +67,9 @@ public:
}; };
TYPED_TEST_SUITE(SplitNTest, char_types); TYPED_TEST_SUITE(SplitNTest, char_types);
template<typename T> template<typename T, typename ResultT = std::basic_string<T>>
std::basic_string<T> make_word(size_t length = 8, T delim = static_cast<T>(0)) { ResultT make_word(size_t length = 8, T delim = static_cast<T>(0)) {
std::basic_string<T> result; ResultT result;
if (length == 0) { if (length == 0) {
return {}; return {};
@ -99,7 +99,7 @@ std::basic_string_view<T> make_word_view(size_t length = 8, T delim = static_cas
return s_result; return s_result;
} }
template<typename T> template<typename T, typename StringT = std::basic_string<T>>
struct RandomTestData { struct RandomTestData {
RandomTestData(T in_delim) RandomTestData(T in_delim)
: m_delim{ in_delim } { : m_delim{ in_delim } {
@ -116,21 +116,22 @@ struct RandomTestData {
auto random_words = word_count_distribution(randgen); auto random_words = word_count_distribution(randgen);
while (m_tokens.size() < random_words) { while (m_tokens.size() < random_words) {
m_tokens.push_back(make_word<T>(word_length_distribution(randgen))); m_tokens.push_back(make_word<T, StringT>(word_length_distribution(randgen)));
m_str += m_tokens.back(); m_str.insert(m_str.end(), m_tokens.back().begin(), m_tokens.back().end());
if (m_tokens.size() < random_words) { if (m_tokens.size() < random_words) {
m_str += m_delim; m_str.insert(m_str.end(), m_delim);
} }
} }
} }
std::basic_string<T> get_remainder(size_t in_times_split) { StringT get_remainder(size_t in_times_split) {
std::basic_string<T> result; StringT result;
while (in_times_split < m_tokens.size()) { while (in_times_split < m_tokens.size()) {
result += m_tokens[in_times_split]; auto& token = m_tokens[in_times_split];
result.insert(result.end(), token.begin(), token.end());
++in_times_split; ++in_times_split;
if (in_times_split < m_tokens.size()) { if (in_times_split < m_tokens.size()) {
result += m_delim; result.insert(result.end(), m_delim);
} }
} }
@ -138,8 +139,8 @@ struct RandomTestData {
} }
T m_delim; T m_delim;
std::basic_string<T> m_str; StringT m_str;
std::vector<std::basic_string<T>> m_tokens; std::vector<StringT> m_tokens;
}; };
TYPED_TEST(SplitSVTest, empty) { TYPED_TEST(SplitSVTest, empty) {
@ -224,6 +225,14 @@ TYPED_TEST(SplitOnceTest, random) {
EXPECT_EQ(split_result.second, data.get_remainder(1)); EXPECT_EQ(split_result.second, data.get_remainder(1));
} }
TYPED_TEST(SplitOnceTest, random_vector) {
RandomTestData<TypeParam, std::vector<TypeParam>> data{ static_cast<TypeParam>(0) };
std::pair<std::vector<TypeParam>, std::vector<TypeParam>> split_result = split_once(data.m_str, data.m_delim);
EXPECT_EQ(split_result.first, data.m_tokens[0]);
EXPECT_EQ(split_result.second, data.get_remainder(1));
}
TYPED_TEST(SplitOnceTest, random_view) { TYPED_TEST(SplitOnceTest, random_view) {
RandomTestData<TypeParam> data{ static_cast<TypeParam>(0) }; RandomTestData<TypeParam> data{ static_cast<TypeParam>(0) };
std::pair<std::basic_string_view<TypeParam>, std::basic_string_view<TypeParam>> split_result = split_once_view(data.m_str, data.m_delim); std::pair<std::basic_string_view<TypeParam>, std::basic_string_view<TypeParam>> split_result = split_once_view(data.m_str, data.m_delim);
@ -248,6 +257,20 @@ TYPED_TEST(SplitNTest, random) {
EXPECT_EQ(split_result[n], data.get_remainder(n)); EXPECT_EQ(split_result[n], data.get_remainder(n));
} }
TYPED_TEST(SplitNTest, random_vector) {
RandomTestData<TypeParam, std::vector<TypeParam>> data{ static_cast<TypeParam>(0) };
constexpr size_t n = 4;
std::vector<std::vector<TypeParam>> split_result = split_n<std::vector, std::vector<TypeParam>>(data.m_str, data.m_delim, n);
// Tokens shall be same up until last one (n + 1)
EXPECT_EQ(split_result.size(), n + 1);
for (size_t index = 0; index != n; ++index) {
EXPECT_EQ(split_result[index], data.m_tokens[index]);
}
EXPECT_EQ(split_result[n], data.get_remainder(n));
}
TYPED_TEST(SplitNTest, random_view) { TYPED_TEST(SplitNTest, random_view) {
RandomTestData<TypeParam> data{ static_cast<TypeParam>(0) }; RandomTestData<TypeParam> data{ static_cast<TypeParam>(0) };
constexpr size_t n = 4; constexpr size_t n = 4;
@ -279,7 +302,13 @@ TYPED_TEST(SplitSringTest, single_word) {
TYPED_TEST(SplitSringTest, random) { TYPED_TEST(SplitSringTest, random) {
RandomTestData<TypeParam> data{ static_cast<TypeParam>(0) }; RandomTestData<TypeParam> data{ static_cast<TypeParam>(0) };
auto split_result = split(data.m_str, data.m_delim); std::vector<std::basic_string<TypeParam>> split_result = split(data.m_str, data.m_delim);
EXPECT_EQ(split_result, data.m_tokens);
}
TYPED_TEST(SplitSringTest, random_vector) {
RandomTestData<TypeParam, std::vector<TypeParam>> data{ static_cast<TypeParam>(0) };
std::vector<std::vector<TypeParam>> split_result = split<std::vector, std::vector<TypeParam>>(data.m_str, data.m_delim);
EXPECT_EQ(split_result, data.m_tokens); EXPECT_EQ(split_result, data.m_tokens);
} }

Loading…
Cancel
Save