diff --git a/example/csv/main.cpp b/example/csv/main.cpp new file mode 100644 index 00000000..ef2dedf5 --- /dev/null +++ b/example/csv/main.cpp @@ -0,0 +1,137 @@ +/*============================================================================= + Copyright (c) 2011-2016 Bolero MURAKAMI + https://github.com/bolero-MURAKAMI/Sprout + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +template +using subbed_array = sprout::sub_array >; + +template +struct csv_parser_settings { +public: + typedef Char value_type; +private: + value_type delim_; + value_type quote_; + value_type escape_; +public: + constexpr csv_parser_settings(value_type delim = Char(','), value_type quote = Char('\"')) + : delim_(delim), quote_(quote), escape_(quote) + {} + constexpr csv_parser_settings(value_type delim, value_type quote, value_type escape) + : delim_(delim), quote_(quote), escape_(escape) + {} + constexpr value_type delimiter() const { + return delim_; + } + constexpr value_type quote() const { + return quote_; + } + constexpr value_type escape() const { + return escape_; + } +}; + +template +constexpr subbed_array, L> +parse_csv(String const& src, csv_parser_settings settings = csv_parser_settings()) { + typedef typename String::value_type value_type; + subbed_array, L> result = {}; + result.window(0, 1); + result.back().window(0, 0); + auto delimiters = sprout::make_string(settings.delimiter(), value_type('\r'), value_type('\n')); + auto first = sprout::begin(src), last = sprout::end(src); + while (first != last) { + if (*first == settings.quote()) { + // quoted element + ++first; + auto end_quote = sprout::find(first, last, settings.quote()); + while (true) { + if (end_quote == last) { + throw 0; + } + auto next = sprout::next(end_quote); + if (next != last) { + if (*next == settings.escape()) { + // escaped quote + ++next; + end_quote = sprout::find(next, last, settings.quote()); + continue; + } + if (!sprout::any_of_equal(delimiters.begin(), delimiters.end(), *next)) { + throw 0; + } + if (*next == value_type('\r') && sprout::next(next) != last && *sprout::next(next) == value_type('\n')) { + ++next; + } + } + result.back().push_back( + ResultString(sprout::addressof(*first), sprout::distance(first, end_quote)) + ); + first = next; + break; + } + } else { + // no quoted element + auto next = sprout::find_first_of(first, last, delimiters.begin(), delimiters.end()); + if (next != last) { + if (*next == value_type('\r') && sprout::next(next) != last && *sprout::next(next) == value_type('\n')) { + ++next; + } + } + result.back().push_back( + ResultString(sprout::addressof(*first), sprout::distance(first, next)) + ); + first = next; + } + if (first != last) { + if ((*first == value_type('\r') || *first == value_type('\n')) && sprout::next(first) != last) { + result.offset(0, 1); + result.back().window(0, 0); + } + ++first; + } + } + return result; +} + +#include +#include + +int main() { + using namespace sprout::udl; + constexpr auto src = R"( +(no quoted),a,b,c +(quoted),"d","e","f" +(escaped),"""g""","""h""","""i""" +(comma),"j,k","l,m","n,o" +(new line),"p +q","r +s","t +u" +)"_sv; + constexpr auto result = parse_csv<16, 16>(src); + for (auto const& field : result) { + for (auto const& elem : field) { + std::cout + << elem << std::endl + << "----" << std::endl + ; + } + std::cout + << "----------------------------------------" << std::endl + ; + } +} diff --git a/sprout/ctype/ascii.hpp b/sprout/ctype/ascii.hpp index 08f3a61a..dacd757a 100644 --- a/sprout/ctype/ascii.hpp +++ b/sprout/ctype/ascii.hpp @@ -249,7 +249,7 @@ namespace sprout { return sprout::ascii::detail::get_value(c) & sprout::ascii::detail::lower ? c - (0x61 - 0x41) : c; \ } \ inline SPROUT_CONSTEXPR bool \ - SPROUT_PP_CAT(is, SPROUT_PP_CAT(PREFIX, classified))(sprout::ctypes::mask_t m, CHAR_TYPE c) { \ + SPROUT_PP_CAT(is, SPROUT_PP_CAT(PREFIX, classified))(sprout::ctypes::mask m, CHAR_TYPE c) { \ return (m | sprout::ctypes::alnum && (sprout::ascii::detail::get_value(c) & (sprout::ascii::detail::alpha | sprout::ascii::detail::digit))) \ || (m | sprout::ctypes::alpha && (sprout::ascii::detail::get_value(c) & sprout::ascii::detail::alpha)) \ || (m | sprout::ctypes::blank && (sprout::ascii::detail::get_value(c) & sprout::ascii::detail::blank)) \ diff --git a/sprout/ctype/functor.hpp b/sprout/ctype/functor.hpp index bf38f1f7..e954357a 100644 --- a/sprout/ctype/functor.hpp +++ b/sprout/ctype/functor.hpp @@ -384,9 +384,9 @@ namespace sprout { typedef T argument_type; typedef bool result_type; private: - sprout::ctypes::mask_t m_; + sprout::ctypes::mask m_; public: - explicit SPROUT_CONSTEXPR is_classified(sprout::ctypes::mask_t m) + explicit SPROUT_CONSTEXPR is_classified(sprout::ctypes::mask m) : m_(m) {} SPROUT_CONSTEXPR bool @@ -399,9 +399,9 @@ namespace sprout { public: typedef bool result_type; private: - sprout::ctypes::mask_t m_; + sprout::ctypes::mask m_; public: - explicit SPROUT_CONSTEXPR is_classified(sprout::ctypes::mask_t m) + explicit SPROUT_CONSTEXPR is_classified(sprout::ctypes::mask m) : m_(m) {} template diff --git a/sprout/ctype/mask.hpp b/sprout/ctype/mask.hpp index 392e9e40..9bc2d4ab 100644 --- a/sprout/ctype/mask.hpp +++ b/sprout/ctype/mask.hpp @@ -10,40 +10,59 @@ #include #include +#include namespace sprout { namespace ctypes { // - // mask_t + // mask // - typedef std::ctype_base::mask mask_t; - - // - // space - // print - // cntrl - // upper - // lower - // alpha - // digit - // punct - // xdigit - // blank - // alnum - // graph - // - SPROUT_STATIC_CONSTEXPR sprout::ctypes::mask_t space = std::ctype_base::space; - SPROUT_STATIC_CONSTEXPR sprout::ctypes::mask_t print = std::ctype_base::print; - SPROUT_STATIC_CONSTEXPR sprout::ctypes::mask_t cntrl = std::ctype_base::cntrl; - SPROUT_STATIC_CONSTEXPR sprout::ctypes::mask_t upper = std::ctype_base::upper; - SPROUT_STATIC_CONSTEXPR sprout::ctypes::mask_t lower = std::ctype_base::lower; - SPROUT_STATIC_CONSTEXPR sprout::ctypes::mask_t alpha = std::ctype_base::alpha; - SPROUT_STATIC_CONSTEXPR sprout::ctypes::mask_t digit = std::ctype_base::digit; - SPROUT_STATIC_CONSTEXPR sprout::ctypes::mask_t punct = std::ctype_base::punct; - SPROUT_STATIC_CONSTEXPR sprout::ctypes::mask_t xdigit = std::ctype_base::xdigit; - SPROUT_STATIC_CONSTEXPR sprout::ctypes::mask_t blank = /*std::ctype_base::blank*/1 << 9; - SPROUT_STATIC_CONSTEXPR sprout::ctypes::mask_t alnum = std::ctype_base::alnum; - SPROUT_STATIC_CONSTEXPR sprout::ctypes::mask_t graph = std::ctype_base::graph; + enum mask { + space = std::ctype_base::space, + print = std::ctype_base::print, + cntrl = std::ctype_base::cntrl, + upper = std::ctype_base::upper, + lower = std::ctype_base::lower, + alpha = std::ctype_base::alpha, + digit = std::ctype_base::digit, + punct = std::ctype_base::punct, + xdigit = std::ctype_base::xdigit, +#if SPROUT_GCC_EARLIER(5, 0, 0) + blank = 0x0001, +#else // #if SPROUT_GCC_EARLIER(5, 0, 0) + blank = std::ctype_base::blank, +#endif // #if SPROUT_GCC_EARLIER(5, 0, 0) + alnum = std::ctype_base::alnum, + graph = std::ctype_base::graph + }; + inline SPROUT_CONSTEXPR sprout::ctypes::mask + operator&(sprout::ctypes::mask x, sprout::ctypes::mask y) { + return sprout::ctypes::mask(static_cast(x) & static_cast(y)); + } + inline SPROUT_CONSTEXPR sprout::ctypes::mask + operator|(sprout::ctypes::mask x, sprout::ctypes::mask y) { + return sprout::ctypes::mask(static_cast(x) | static_cast(y)); + } + inline SPROUT_CONSTEXPR sprout::ctypes::mask + operator^(sprout::ctypes::mask x, sprout::ctypes::mask y) { + return sprout::ctypes::mask(static_cast(x) ^ static_cast(y)); + } + inline SPROUT_CONSTEXPR sprout::ctypes::mask + operator~(sprout::ctypes::mask x) { + return sprout::ctypes::mask(~static_cast(x)); + } + inline SPROUT_CXX14_CONSTEXPR sprout::ctypes::mask& + operator&=(sprout::ctypes::mask& x, sprout::ctypes::mask y) { + return x = x & y; + } + inline SPROUT_CXX14_CONSTEXPR sprout::ctypes::mask& + operator|=(sprout::ctypes::mask& x, sprout::ctypes::mask y) { + return x = x | y; + } + inline SPROUT_CXX14_CONSTEXPR sprout::ctypes::mask& + operator^=(sprout::ctypes::mask& x, sprout::ctypes::mask y) { + return x = x ^ y; + } } // namespace ctypes } // namespace sprout