Skip to content

Commit

Permalink
Refactor stream_from to remove some awkward template code (#273)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
KayEss authored Feb 2, 2020
1 parent 782a86e commit e3c2e3f
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 41 deletions.
61 changes: 22 additions & 39 deletions include/pqxx/stream_from.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include "pqxx/separated_list.hxx"
#include "pqxx/transaction_base.hxx"
#include <variant>


namespace pqxx
Expand Down Expand Up @@ -52,6 +53,10 @@ public:
bool get_raw_line(std::string &);
template<typename Tuple> stream_from &operator>>(Tuple &);

/// Doing this with a variant is going to be horrifically borked
template<typename... Vs>
stream_from &operator>>(std::variant<Vs...> &) = delete;

private:
internal::encoding_group m_copy_encoding =
internal::encoding_group::MONOBYTE;
Expand All @@ -69,19 +74,23 @@ private:
bool extract_field(
std::string const &, std::string::size_type &, std::string &) const;

template<typename Tuple, std::size_t I>
auto tokenize_ith(
std::string const &, Tuple &, std::string::size_type, std::string &) const
-> typename std::enable_if_t<(std::tuple_size_v<Tuple> > I)>;
template<typename Tuple, std::size_t I>
auto tokenize_ith(
std::string const &, Tuple &, std::string::size_type, std::string &) const
-> typename std::enable_if_t<(std::tuple_size_v<Tuple> <= I)>;

template<typename T>
void extract_value(
std::string const &line, T &t, std::string::size_type &here,
std::string &workspace) const;

template<typename Tuple, std::size_t... I>
void do_extract(
const std::string &line, Tuple &t, std::string &workspace,
std::index_sequence<I...>)
{
std::string::size_type here{};
(extract_value(line, std::get<I>(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"};
}
};


Expand All @@ -96,8 +105,7 @@ template<typename Iter>
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));
}
Expand All @@ -110,7 +118,9 @@ template<typename Tuple> stream_from &stream_from::operator>>(Tuple &t)
std::string workspace;
try
{
tokenize_ith<Tuple, 0>(m_current_line, t, 0, workspace);
constexpr auto tsize = std::tuple_size_v<Tuple>;
using indexes = std::make_index_sequence<tsize>;
do_extract(m_current_line, t, workspace, indexes{});
m_retry_line = false;
}
catch (...)
Expand All @@ -123,33 +133,6 @@ template<typename Tuple> stream_from &stream_from::operator>>(Tuple &t)
}


template<typename Tuple, std::size_t I>
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<Tuple> > I)>
{
if (here >= line.size())
throw usage_error{"Too few fields to extract from stream_from line."};

extract_value(line, std::get<I>(t), here, workspace);
tokenize_ith<Tuple, I + 1>(line, t, here, workspace);
}


template<typename Tuple, std::size_t I>
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<Tuple> <= 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<typename T>
void stream_from::extract_value(
std::string const &line, T &t, std::string::size_type &here,
Expand Down
3 changes: 1 addition & 2 deletions include/pqxx/stream_to.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,7 @@ template<typename Iter>
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));
}
Expand Down
2 changes: 2 additions & 0 deletions src/stream_from.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down

0 comments on commit e3c2e3f

Please sign in to comment.