string: move tokeniser into the header

This allows more varied template parameters to be used.
This commit is contained in:
Danny Robson 2018-01-30 11:31:40 +11:00
parent 32a4aa23e5
commit c4e0cd31f9
4 changed files with 69 additions and 182 deletions

View File

@ -51,146 +51,3 @@ strbegins (const char *restrict str,
const char *restrict prefix) { const char *restrict prefix) {
return 0 == strncmp (prefix, str, strlen (prefix)); return 0 == strncmp (prefix, str, strlen (prefix));
} }
///////////////////////////////////////////////////////////////////////////////
template <typename Iterator>
tokeniser<Iterator>::tokeniser (Iterator _first,
Iterator _last,
value_type _separator):
m_range (_first, _last),
m_separator (_separator)
{ }
///////////////////////////////////////////////////////////////////////////////
template <typename Iterator>
typename tokeniser<Iterator>::iterator
tokeniser<Iterator>::cbegin (void) const
{
return iterator (
m_range,
m_separator
);
}
//-----------------------------------------------------------------------------
template <typename Iterator>
typename tokeniser<Iterator>::iterator
tokeniser<Iterator>::cend (void) const
{
return iterator (
{m_range.cend (), m_range.cend ()},
m_separator
);
}
//-----------------------------------------------------------------------------
template <typename Iterator>
typename tokeniser<Iterator>::iterator
tokeniser<Iterator>::begin (void) const
{
return cbegin ();
}
//-----------------------------------------------------------------------------
template <typename Iterator>
typename tokeniser<Iterator>::iterator
tokeniser<Iterator>::end (void) const
{
return cend ();
}
///////////////////////////////////////////////////////////////////////////////
template <typename Iterator>
tokeniser<Iterator>::iterator::iterator (range_type _range, value_type _separator):
m_separator (_separator),
m_range (_range.cbegin (),
std::find (_range.cbegin (),
_range.cend (),
_separator)),
m_end (_range.cend ())
{ }
//-----------------------------------------------------------------------------
template <typename Iterator>
typename tokeniser<Iterator>::iterator
tokeniser<Iterator>::iterator::operator++ (int)
{
iterator res(*this);
++*this;
return res;
}
//-----------------------------------------------------------------------------
template <typename Iterator>
typename tokeniser<Iterator>::iterator&
tokeniser<Iterator>::iterator::operator++ (void)&
{
auto newend = m_range.cend ();
if (newend != m_end) {
CHECK_EQ (*m_range.cend (), m_separator);
newend++;
}
m_range = {
newend,
std::find (newend, m_end, m_separator)
};
return *this;
}
//-----------------------------------------------------------------------------
template <typename Iterator>
typename tokeniser<Iterator>::range_type
tokeniser<Iterator>::iterator::operator* (void) const
{
return m_range;
}
//-----------------------------------------------------------------------------
template <typename Iterator>
bool
tokeniser<Iterator>::iterator::operator== (const iterator &rhs) const
{
return m_range == rhs.m_range && m_separator == rhs.m_separator;
}
//-----------------------------------------------------------------------------
template <typename Iterator>
bool
tokeniser<Iterator>::iterator::operator!= (const iterator &rhs) const
{
return !(*this == rhs);
}
///////////////////////////////////////////////////////////////////////////////
tokeniser<std::string::const_iterator>
util::make_tokeniser (const std::string &value, std::string::value_type separator)
{
return tokeniser<std::string::const_iterator> (value.cbegin (), value.cend (), separator);
}
//-----------------------------------------------------------------------------
tokeniser<const char*>
util::make_tokeniser (const char *str, char separator)
{
return tokeniser<const char*> (str, str + strlen (str), separator);
}
///////////////////////////////////////////////////////////////////////////////
template struct util::tokeniser<std::string::const_iterator>;
template struct util::tokeniser<const char*>;

View File

@ -14,9 +14,10 @@
* Copyright 2011-2016 Danny Robson <danny@nerdcruft.net> * Copyright 2011-2016 Danny Robson <danny@nerdcruft.net>
*/ */
#ifndef __UTIL_STRING_HPP #ifndef CRUFT_UTIL_STRING_HPP
#define __UTIL_STRING_HPP #define CRUFT_UTIL_STRING_HPP
#include "debug.hpp"
#include "view.hpp" #include "view.hpp"
@ -38,15 +39,14 @@ namespace util {
using value_type = typename std::iterator_traits<Iterator>::value_type; using value_type = typename std::iterator_traits<Iterator>::value_type;
using range_type = view<Iterator>; using range_type = view<Iterator>;
tokeniser (Iterator first, Iterator last, value_type separator); tokeniser (util::view<Iterator,Iterator> _range, value_type _separator):
m_range (_range),
m_separator (_separator)
{ ; }
template <typename ContainerT> tokeniser (const char *_range, char _separator):
tokeniser (ContainerT &container, typename ContainerT::value_type _separator): m_range (_range),
tokeniser ( m_separator (_separator)
std::begin (container),
std::end (container),
_separator
)
{ ; } { ; }
struct iterator : public std::iterator< struct iterator : public std::iterator<
@ -55,16 +55,54 @@ namespace util {
std::size_t std::size_t
> { > {
public: public:
iterator operator++ (int); iterator operator++ (int)
iterator& operator++ (void)&; {
iterator res(*this);
++*this;
return res;
}
range_type operator* (void) const; iterator& operator++ (void)&
{
auto newend = m_range.cend ();
if (newend != m_end) {
CHECK_EQ (*m_range.cend (), m_separator);
newend++;
}
bool operator== (const iterator&) const; m_range = {
bool operator!= (const iterator&) const; newend,
std::find (newend, m_end, m_separator)
};
return *this;
}
range_type operator* (void) const
{
return m_range;
}
bool operator== (const iterator &rhs) const
{
return m_range == rhs.m_range && m_separator == rhs.m_separator;
}
bool operator!= (const iterator &rhs) const
{
return !(*this == rhs);
}
private: private:
iterator (range_type range, value_type separator); iterator (range_type _range, value_type _separator):
m_separator (_separator),
m_range (_range.cbegin (),
std::find (_range.cbegin (),
_range.cend (),
_separator)
),
m_end (_range.cend ())
{ ; }
const value_type m_separator; const value_type m_separator;
range_type m_range; range_type m_range;
@ -73,11 +111,11 @@ namespace util {
friend tokeniser; friend tokeniser;
}; };
iterator cbegin (void) const; iterator cbegin (void) const { return { m_range, m_separator }; }
iterator begin (void) const; iterator begin (void) const { return { m_range, m_separator }; }
iterator cend (void) const; iterator cend (void) const { return { { m_range.cend (), m_range.cend () }, m_separator }; }
iterator end (void) const; iterator end (void) const { return { { m_range.cend (), m_range.cend () }, m_separator }; }
private: private:
const range_type m_range; const range_type m_range;
@ -85,6 +123,11 @@ namespace util {
}; };
template <typename ContainerT>
tokeniser (ContainerT&, typename ContainerT::value_type) -> tokeniser<typename ContainerT::iterator>;
tokeniser (const char*,char) -> tokeniser<const char*>;
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
template <typename CharT, std::size_t LengthV> template <typename CharT, std::size_t LengthV>
auto auto
@ -92,22 +135,6 @@ namespace util {
{ {
return tokeniser { std::begin (data), std::end (data), 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);
} }
#endif // __UTIL_STRING_HPP #endif // __UTIL_STRING_HPP

View File

@ -71,7 +71,7 @@ find_terminfo_path [[gnu::unused]] (const std::string &key)
// check colon seperated list in TERMINFO_DIRS // check colon seperated list in TERMINFO_DIRS
if (const char *dirs = getenv ("TERMINFO_DIRS")) { if (const char *dirs = getenv ("TERMINFO_DIRS")) {
auto tok = util::make_tokeniser (dirs, ':'); auto tok = util::tokeniser (dirs, ':');
for (auto i: tok) { for (auto i: tok) {
try { try {

View File

@ -29,8 +29,11 @@ main (int, char**)
{ "", "trailing empty" } { "", "trailing empty" }
}; };
for (const auto &[tok, expected]: util::zip (util::make_tokeniser (csv, ','), TESTS)) for (const auto tok: util::tokeniser (csv.c_str (), ','))
std::cout << '"' << tok << "\"\n";
for (const auto &[tok, expected]: util::zip (util::tokeniser (csv.c_str (), ','), TESTS))
tap.expect_eq (tok, expected.value, "%s", expected.message); tap.expect_eq (tok, expected.value, "%s", expected.message);
return tap.status (); return tap.status ();
} }