From e3c2e3f554d940bb442e5cd6b726aa42bd6ad897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirit=20S=C3=A6lensminde?= Date: Sun, 2 Feb 2020 19:23:25 +0700 Subject: [PATCH] Refactor stream_from to remove some awkward template code (#273) * Refactor stream_from to remove some awkward template code This changes it to a simpler compile time list comprehension using a c++17 fold over the comma operator. * Add back in the check that we don't try to pull too many fields --- include/pqxx/stream_from.hxx | 61 +++++++++++++----------------------- include/pqxx/stream_to.hxx | 3 +- src/stream_from.cxx | 2 ++ 3 files changed, 25 insertions(+), 41 deletions(-) diff --git a/include/pqxx/stream_from.hxx b/include/pqxx/stream_from.hxx index 0d0297e1a..561a13d77 100644 --- a/include/pqxx/stream_from.hxx +++ b/include/pqxx/stream_from.hxx @@ -18,6 +18,7 @@ #include "pqxx/separated_list.hxx" #include "pqxx/transaction_base.hxx" +#include namespace pqxx @@ -52,6 +53,10 @@ public: bool get_raw_line(std::string &); template stream_from &operator>>(Tuple &); + /// Doing this with a variant is going to be horrifically borked + template + stream_from &operator>>(std::variant &) = delete; + private: internal::encoding_group m_copy_encoding = internal::encoding_group::MONOBYTE; @@ -69,19 +74,23 @@ private: bool extract_field( std::string const &, std::string::size_type &, std::string &) const; - template - auto tokenize_ith( - std::string const &, Tuple &, std::string::size_type, std::string &) const - -> typename std::enable_if_t<(std::tuple_size_v > I)>; - template - auto tokenize_ith( - std::string const &, Tuple &, std::string::size_type, std::string &) const - -> typename std::enable_if_t<(std::tuple_size_v <= I)>; - template void extract_value( std::string const &line, T &t, std::string::size_type &here, std::string &workspace) const; + + template + void do_extract( + const std::string &line, Tuple &t, std::string &workspace, + std::index_sequence) + { + std::string::size_type here{}; + (extract_value(line, std::get(t), here, workspace), ...); + if ( + here < line.size() and + not(here == line.size() - 1 and line[here] == '\n')) + throw usage_error{"Not all fields extracted from stream_from line"}; + } }; @@ -96,8 +105,7 @@ template inline stream_from::stream_from( transaction_base &tb, std::string_view table_name, Iter columns_begin, Iter columns_end) : - namedclass{"stream_from", table_name}, - transactionfocus{tb} + namedclass{"stream_from", table_name}, transactionfocus{tb} { set_up(tb, table_name, separated_list(",", columns_begin, columns_end)); } @@ -110,7 +118,9 @@ template stream_from &stream_from::operator>>(Tuple &t) std::string workspace; try { - tokenize_ith(m_current_line, t, 0, workspace); + constexpr auto tsize = std::tuple_size_v; + using indexes = std::make_index_sequence; + do_extract(m_current_line, t, workspace, indexes{}); m_retry_line = false; } catch (...) @@ -123,33 +133,6 @@ template stream_from &stream_from::operator>>(Tuple &t) } -template -auto stream_from::tokenize_ith( - std::string const &line, Tuple &t, std::string::size_type here, - std::string &workspace) const -> - typename std::enable_if_t<(std::tuple_size_v > I)> -{ - if (here >= line.size()) - throw usage_error{"Too few fields to extract from stream_from line."}; - - extract_value(line, std::get(t), here, workspace); - tokenize_ith(line, t, here, workspace); -} - - -template -auto stream_from::tokenize_ith( - std::string const &line, Tuple & /* t */, std::string::size_type here, - std::string & /* workspace */ - ) const -> typename std::enable_if_t<(std::tuple_size_v <= I)> -{ - // Zero-column line may still have a trailing newline - if ( - here < line.size() and not(here == line.size() - 1 and line[here] == '\n')) - throw usage_error{"Not all fields extracted from stream_from line"}; -} - - template void stream_from::extract_value( std::string const &line, T &t, std::string::size_type &here, diff --git a/include/pqxx/stream_to.hxx b/include/pqxx/stream_to.hxx index 28b3cae17..08a4fc335 100644 --- a/include/pqxx/stream_to.hxx +++ b/include/pqxx/stream_to.hxx @@ -151,8 +151,7 @@ template inline stream_to::stream_to( transaction_base &tb, std::string_view table_name, Iter columns_begin, Iter columns_end) : - namedclass{"stream_to", table_name}, - internal::transactionfocus{tb} + namedclass{"stream_to", table_name}, internal::transactionfocus{tb} { set_up(tb, table_name, separated_list(",", columns_begin, columns_end)); } diff --git a/src/stream_from.cxx b/src/stream_from.cxx index b30bb902e..3b5607872 100644 --- a/src/stream_from.cxx +++ b/src/stream_from.cxx @@ -154,6 +154,8 @@ void pqxx::stream_from::complete() bool pqxx::stream_from::extract_field( std::string const &line, std::string::size_type &i, std::string &s) const { + if (i >= line.size()) + throw usage_error{"Too few fields to extract from stream_from line."}; auto const next_seq{get_glyph_scanner(m_copy_encoding)}; s.clear(); bool is_null{false};