From cfa272a80a1808f26f9db0a84242a3b946fe8098 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Fri, 15 Sep 2017 15:22:29 +1000 Subject: [PATCH] string: allow tokenisation of c arrays --- string.hpp | 42 +++++++++++++++++++++++++++++++++++++----- test/string.cpp | 38 ++++++++++++++++++-------------------- 2 files changed, 55 insertions(+), 25 deletions(-) diff --git a/string.hpp b/string.hpp index d7c9434e..9fb0bef4 100644 --- a/string.hpp +++ b/string.hpp @@ -40,7 +40,20 @@ namespace util { tokeniser (Iterator first, Iterator last, value_type separator); - struct iterator { + template + tokeniser (ContainerT &container, typename ContainerT::value_type _separator): + tokeniser ( + std::begin (container), + std::end (container), + _separator + ) + { ; } + + struct iterator : public std::iterator< + std::forward_iterator_tag, + range_type, + std::size_t + > { public: iterator operator++ (int); iterator& operator++ (void)&; @@ -71,10 +84,29 @@ namespace util { const value_type m_separator; }; - - tokeniser make_tokeniser (const std::string&, std::string::value_type); - tokeniser make_tokeniser (std::string&&, std::string::value_type) = delete; - tokeniser make_tokeniser (const char*, char); + + /////////////////////////////////////////////////////////////////////////// + template + auto + make_tokeniser (CharT (&data)[LengthV], CharT separator) + { + return tokeniser { std::begin (data), std::end (data), separator }; + } + + + //------------------------------------------------------------------------- + tokeniser + make_tokeniser (const std::string&, std::string::value_type); + + + //------------------------------------------------------------------------- + tokeniser + make_tokeniser (std::string&&, std::string::value_type) = delete; + + + //------------------------------------------------------------------------- + tokeniser + make_tokeniser (const char*, char); } diff --git a/test/string.cpp b/test/string.cpp index 883c577b..b3e20cd5 100644 --- a/test/string.cpp +++ b/test/string.cpp @@ -1,6 +1,9 @@ #include "tap.hpp" #include "string.hpp" #include "types.hpp" +#include "iterator.hpp" + +#include int main (int, char**) @@ -8,28 +11,23 @@ main (int, char**) util::TAP::logger tap; const char csv[] = "\0,a,123,,this is a test,"; - const std::string values[] = { - { "\0", 1 }, - { "a" }, - { "123" }, - { "" }, - { "this is a test" }, - { "" } + + // expected test data must be a std::string so we can check embedded + // nulls (which are ambiguous when using a cstr). + struct foo { + const std::string value; + const char *message; + } TESTS[] = { + { "\0", "null" }, + { "a", "single letter" }, + { "123", "three digits" }, + { "", "empty string" }, + { "this is a test", "string with spaces" }, + { "", "trailing empty" } }; - std::string str (std::cbegin (csv), std::cbegin (csv) + std::size (csv)); - auto tok = util::make_tokeniser (str, ','); - auto t_cursor = tok.cbegin (); - auto v_cursor = std::cbegin (values); - - tap.expect_eq (*t_cursor++, *v_cursor++, "tokeniser, single letter"); - tap.expect_eq (*t_cursor++, *v_cursor++, "tokeniser, three digits"); - tap.expect_eq (*t_cursor++, *v_cursor++, "tokeniser, embedded null"); - tap.expect_eq (*t_cursor++, *v_cursor++, "tokeniser, empty string"); - tap.expect_eq (*t_cursor++, *v_cursor++, "tokeniser, string with spaces"); - tap.expect_eq (*t_cursor++, *v_cursor++, "tokeniser, trailing empty"); - - tap.expect_eq (t_cursor, tok.cend (), "tokeniser iterator at end"); + for (const auto &[tok, expected]: util::zip (util::make_tokeniser (csv, ','), TESTS)) + tap.expect (equal (tok, expected.value), "%s", expected.message); return tap.status (); }