string: allow tokenisation of c arrays

This commit is contained in:
Danny Robson 2017-09-15 15:22:29 +10:00
parent 9c5b471b24
commit cfa272a80a
2 changed files with 55 additions and 25 deletions

View File

@ -40,7 +40,20 @@ namespace util {
tokeniser (Iterator first, Iterator last, value_type separator);
struct iterator {
template <typename ContainerT>
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<std::string::const_iterator> make_tokeniser (const std::string&, std::string::value_type);
tokeniser<std::string::const_iterator> make_tokeniser (std::string&&, std::string::value_type) = delete;
tokeniser<const char*> make_tokeniser (const char*, char);
///////////////////////////////////////////////////////////////////////////
template <typename CharT, std::size_t LengthV>
auto
make_tokeniser (CharT (&data)[LengthV], CharT separator)
{
return tokeniser { std::begin (data), std::end (data), separator };
}
//-------------------------------------------------------------------------
tokeniser<std::string::const_iterator>
make_tokeniser (const std::string&, std::string::value_type);
//-------------------------------------------------------------------------
tokeniser<std::string::const_iterator>
make_tokeniser (std::string&&, std::string::value_type) = delete;
//-------------------------------------------------------------------------
tokeniser<const char*>
make_tokeniser (const char*, char);
}

View File

@ -1,6 +1,9 @@
#include "tap.hpp"
#include "string.hpp"
#include "types.hpp"
#include "iterator.hpp"
#include <vector>
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 ();
}