Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow passing rvalues to soci::use() #1102

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions include/soci/bind-values.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ class use_type_vector: public std::vector<use_type_base *>

void exchange(use_type_ptr const& u) { push_back(u.get()); u.release(); }

template <typename T, typename Indicator>
void exchange(use_container<T, Indicator> const &uc)
template <typename T, typename Indicator, typename ByValueTag>
void exchange ( use_container<T, Indicator, ByValueTag> const &uc )
{
#ifdef SOCI_HAVE_BOOST
exchange_(uc, (typename boost::fusion::traits::is_sequence<T>::type *)NULL);
Expand Down Expand Up @@ -111,10 +111,24 @@ class use_type_vector: public std::vector<use_type_base *>
void exchange_(use_container<T, Indicator> const &uc, ...)
{ exchange(do_use(uc.t, uc.ind, uc.name, typename details::exchange_traits<T>::type_family())); }

template <typename T, typename Indicator>
void exchange_ ( use_container<T, Indicator, std::true_type> const &uc, ... )
{
using type_family_tag = typename details::exchange_traits<T>::type_family;
exchange ( do_use ( uc.t, uc.ind, uc.name, type_family_tag (), std::true_type () ) );
}

template <typename T>
void exchange_(use_container<T, details::no_indicator> const &uc, ...)
void exchange_ ( use_container<T, details::no_indicator> const &uc, ... )
{ exchange(do_use(uc.t, uc.name, typename details::exchange_traits<T>::type_family())); }

template <typename T>
void exchange_ ( use_container<T, details::no_indicator, std::true_type> const &uc, ... )
{
using type_family_tag = typename details::exchange_traits<T>::type_family;
exchange ( do_use ( uc.t, uc.name, type_family_tag (), std::true_type () ) );
}

template <typename T, typename Indicator>
void exchange_(use_container<const T, Indicator> const &uc, ...)
{ exchange(do_use(uc.t, uc.ind, uc.name, typename details::exchange_traits<T>::type_family())); }
Expand Down
8 changes: 4 additions & 4 deletions include/soci/statement.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ class SOCI_DECL statement_impl
{ intos_.exchange(ic); }

void exchange(use_type_ptr const & u) { uses_.exchange(u); }
template <typename T, typename Indicator>
void exchange(use_container<T, Indicator> const &uc)
template <typename T, typename Indicator, typename ByValueTag >
void exchange ( use_container<T, Indicator, ByValueTag> const &uc )
{ uses_.exchange(uc); }


Expand Down Expand Up @@ -198,8 +198,8 @@ class SOCI_DECL statement
template <typename T, typename Indicator>
void exchange(details::into_container<T, Indicator> const &ic) { impl_->exchange(ic); }
void exchange(details::use_type_ptr const & u) { impl_->exchange(u); }
template <typename T, typename Indicator>
void exchange(details::use_container<T, Indicator> const &uc) { impl_->exchange(uc); }
template <typename T, typename Indicator, typename ByValueTag>
void exchange(details::use_container<T, Indicator, ByValueTag> const &uc) { impl_->exchange(uc); }
void clean_up() { impl_->clean_up(); }
void bind_clean_up() { impl_->bind_clean_up(); }

Expand Down
27 changes: 27 additions & 0 deletions include/soci/type-conversion.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,21 @@ class conversion_use_type
SOCI_NOT_COPYABLE(conversion_use_type)
};

template <typename T>
class by_value_conversion_use_type : value_holder<T>, public conversion_use_type<T>
Comment on lines +186 to +187
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be really great to have at least some explanation about what this class is used for.

{
public:
by_value_conversion_use_type ( T const& t, std::string const& name = std::string () )
: value_holder<T> ( t, i_ok ), conversion_use_type<T> ( value_holder<T>::saved_val_, name )
{
}

by_value_conversion_use_type ( T const& t, const indicator& ind, std::string const& name = std::string () )
: value_holder<T> ( t, ind ), conversion_use_type<T> ( value_holder<T>::saved_val_, value_holder<T>::saved_ind_, name )
{
}
};

// this class is used to ensure correct order of construction
// of vector based into_type and use_type elements that use type_conversion

Expand Down Expand Up @@ -440,6 +455,18 @@ into_type_ptr do_into(std::vector<T> & t, std::vector<indicator> & ind,
new conversion_into_type<std::vector<T> >(t, ind, begin, end));
}

template <typename T>
use_type_ptr do_use ( T& t, std::string const& name, user_type_tag, std::true_type )
{
return use_type_ptr ( new by_value_conversion_use_type<T> ( t, name ) );
}

template <typename T>
use_type_ptr do_use ( T& t, indicator& ind, std::string const& name, user_type_tag, std::true_type )
{
return use_type_ptr ( new by_value_conversion_use_type<T> ( t, ind, name ) );
}

template <typename T>
use_type_ptr do_use(T & t, std::string const & name, user_type_tag)
{
Expand Down
42 changes: 42 additions & 0 deletions include/soci/use-type.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,36 @@ class use_type : public standard_use_type
{}
};

template <typename T>
struct value_holder
{
using value_type = T;
value_holder ( const T& t, const indicator& ind )
: saved_val_ ( t ),
saved_ind_ ( ind )
{
}
T saved_val_;
indicator saved_ind_;
};


template <typename T>
class by_value_use_type : value_holder<T>, public use_type<T>
{
public:
by_value_use_type ( T const& t, std::string const& name = std::string () )
: value_holder<T> (t, i_ok),
use_type<T> ( value_holder<T>::saved_val_, name )
{}

by_value_use_type ( T const& t, const indicator& ind, std::string const& name = std::string () )
: value_holder<T> ( t, ind ),
use_type<T> ( value_holder<T>::saved_val_, value_holder<T>::saved_ind_, name )
{}
};


template <typename T>
class use_type<std::vector<T> > : public vector_use_type
{
Expand Down Expand Up @@ -257,6 +287,18 @@ class use_type<std::vector<T> > : public vector_use_type

// helper dispatchers for basic types

template <typename T>
use_type_ptr do_use ( T& t, std::string const& name, basic_type_tag, std::true_type )
{
return use_type_ptr ( new by_value_use_type<T> ( t, name ) );
}

template <typename T>
use_type_ptr do_use ( T& t, indicator& ind, std::string const& name, basic_type_tag, std::true_type )
{
return use_type_ptr ( new by_value_use_type<T> ( t, ind, name ) );
}

template <typename T>
use_type_ptr do_use(T & t, std::string const & name, basic_type_tag)
{
Expand Down
20 changes: 13 additions & 7 deletions include/soci/use.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace soci

namespace details
{
template <typename T, typename Indicator>
template <typename T, typename Indicator, typename ByValueTag = std::false_type>
struct use_container
{
use_container(T &_t, Indicator &_ind, const std::string &_name)
Expand All @@ -32,8 +32,8 @@ struct use_container
};

typedef void no_indicator;
template <typename T>
struct use_container<T, no_indicator>
template <typename T, typename ByValueTag>
struct use_container<T, no_indicator, ByValueTag>
{
use_container(T &_t, const std::string &_name)
: t(_t), name(_name) {}
Expand All @@ -48,10 +48,16 @@ struct use_container<T, no_indicator>

// soci::use is deleted for rvalues because it will likely lead to subtle stack-use-after-scope bugs.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is not true any more and really should be updated, it's just too confusing otherwise.

template <typename T>
details::use_container<T, details::no_indicator> use(T &&t, const std::string &name = std::string()) = delete;
auto use ( T &&t, const std::string &name = std::string () )
{
return details::use_container<T, details::no_indicator, std::true_type> ( t, name );
}

template <typename T>
details::use_container<const T, indicator> use(T &&t, indicator & ind, std::string const &name = std::string()) = delete;
auto use ( T &&t, indicator &&ind, std::string const &name = std::string () )
{
return details::use_container<T, indicator, std::true_type> ( t, ind, name );
}

template <typename T>
details::use_container<T, details::no_indicator> use(T &t, const std::string &name = std::string())
Expand All @@ -66,8 +72,8 @@ details::use_container<T, indicator> use(T &t, indicator & ind, std::string cons
{ return details::use_container<T, indicator>(t, ind, name); }

template <typename T>
details::use_container<const T, indicator> use(T const &t, indicator & ind, std::string const &name = std::string())
{ return details::use_container<const T, indicator>(t, ind, name); }
auto use(T const &t, indicator const & ind, std::string const &name = std::string())
{ return details::use_container<const T, const indicator>(t, ind, name); }

// vector containers
template <typename T>
Expand Down
67 changes: 67 additions & 0 deletions tests/common-tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,73 @@ TEST_CASE_METHOD(common_tests, "Basic functionality", "[core][basics]")
CHECK(fetchEnd == false);
}

TEST_CASE_METHOD ( common_tests, "Rvalues in use", "[core][basics][rvalue]" )
{
soci::session sql ( backEndFactory_, connectString_ );
// base types
{
auto_table_creator tableCreator ( tc_.table_creator_1 ( sql ) );
int r;
statement s ( sql );
s.alloc ();
s.prepare ( "insert into soci_test (id) values (:t)" );
{
s.exchange ( use ( 3 ) );
}
s.define_and_bind ();
s.execute ( true );
sql << "select id from soci_test", into ( r );
CHECK ( r == 3 );
}
{
auto_table_creator tableCreator ( tc_.table_creator_1 ( sql ) );
int r{0};
indicator r_ind;
statement s ( sql );
s.alloc ();
s.prepare ( "insert into soci_test (id) values (:t)" );
{
s.exchange ( use ( 3, i_null ) );
}
s.define_and_bind ();
s.execute ( true );
sql << "select id from soci_test", into ( r, r_ind );
CHECK ( r == 0 );
CHECK ( r_ind == i_null );
}
// conversion types
{
auto_table_creator tableCreator ( tc_.table_creator_1 ( sql ) );
int r;
statement s ( sql );
s.alloc ();
s.prepare ( "insert into soci_test (id) values (:t)" );
{
s.exchange ( use ( MyInt ( 3 ) ) );
}
s.define_and_bind ();
s.execute ( true );
sql << "select id from soci_test", into ( r );
CHECK ( r == 3 );
}
{
auto_table_creator tableCreator ( tc_.table_creator_1 ( sql ) );
int r{-1};
indicator r_ind;
statement s ( sql );
s.alloc ();
s.prepare ( "insert into soci_test (id) values (:t)" );
{
s.exchange ( use ( MyInt ( 3 ), i_null ) );
}
s.define_and_bind ();
s.execute ( true );
sql << "select id from soci_test", into ( r, r_ind );
CHECK ( r == -1 );
CHECK ( r_ind == i_null );
}
}

// "into" tests, type conversions, etc.
TEST_CASE_METHOD(common_tests, "Use and into", "[core][into]")
{
Expand Down
Loading
Loading