[algorithm] to_lower_copy / to_upper_copy with no output param assumes sequence to be same as input

It would seem: std::string foo = boost::algorithm::to_lower_copy< std::string >( "bar" ); isn't valid. Instead one has to do for example: std::string foo = boost::algorithm::to_lower_copy( std::string( "bar" ) ), which while perhaps just as terse and natural creates an extra unneeded temporary. I propose the following addition, as well as one for to_upper_copy: template<typename OutputSequenceT, typename RangeT> inline OutputSequenceT to_lower_copy( const RangeT& Input, const std::locale& Loc=std::locale()) { OutputSequenceT Output( ::boost::begin( Input ), ::boost::end( Input ) ); ::boost::algorithm::detail::transform_range( ::boost::as_literal( Output ), ::boost::algorithm::detail::to_lowerF< typename range_value<OutputSequenceT>::type >(Loc)); return Output; } Or perhaps I've missed something altogether :) Kind regards, Sebastian Karlsson

On Wed, Jun 22, 2011 at 3:05 PM, Sebastian Karlsson <sairony@gmail.com> wrote:
It would seem: std::string foo = boost::algorithm::to_lower_copy< std::string >( "bar" ); isn't valid. Instead one has to do for example: std::string foo = boost::algorithm::to_lower_copy( std::string( "bar" ) ), which while perhaps just as terse and natural creates an extra unneeded temporary. I propose the following addition, as well as one for to_upper_copy:
template<typename OutputSequenceT, typename RangeT> inline OutputSequenceT to_lower_copy( const RangeT& Input, const std::locale& Loc=std::locale()) { OutputSequenceT Output( ::boost::begin( Input ), ::boost::end( Input ) );
Doesn't this also do an unnecessary copy? Olaf

On Wed, Jun 22, 2011 at 3:56 PM, Olaf van der Spek <ml@vdspek.org> wrote:
On Wed, Jun 22, 2011 at 3:05 PM, Sebastian Karlsson <sairony@gmail.com> wrote:
It would seem: std::string foo = boost::algorithm::to_lower_copy< std::string >( "bar" ); isn't valid. Instead one has to do for example: std::string foo = boost::algorithm::to_lower_copy( std::string( "bar" ) ), which while perhaps just as terse and natural creates an extra unneeded temporary. I propose the following addition, as well as one for to_upper_copy:
template<typename OutputSequenceT, typename RangeT> inline OutputSequenceT to_lower_copy( const RangeT& Input, const std::locale& Loc=std::locale()) { OutputSequenceT Output( ::boost::begin( Input ), ::boost::end( Input ) );
Doesn't this also do an unnecessary copy?
Olaf
Maybe one would hope (N)RVO would kick in. But that would depend on the rest of the definition... - Jeff

On Thu, Jun 23, 2011 at 1:13 AM, Jeffrey Lee Hellrung, Jr. <jeffrey.hellrung@gmail.com> wrote:
OutputSequenceT Output( ::boost::begin( Input ), ::boost::end( Input ) );
Doesn't this also do an unnecessary copy?
Olaf
Maybe one would hope (N)RVO would kick in. But that would depend on the rest of the definition...
This isn't about the return value. But I agree, a variant of these algorithms (and others) that support different types for input and output would be nice. Olaf

2011/6/23 Olaf van der Spek <ml@vdspek.org>:
On Wed, Jun 22, 2011 at 3:05 PM, Sebastian Karlsson <sairony@gmail.com> wrote:
It would seem: std::string foo = boost::algorithm::to_lower_copy< std::string >( "bar" ); isn't valid. Instead one has to do for example: std::string foo = boost::algorithm::to_lower_copy( std::string( "bar" ) ), which while perhaps just as terse and natural creates an extra unneeded temporary. I propose the following addition, as well as one for to_upper_copy:
template<typename OutputSequenceT, typename RangeT> inline OutputSequenceT to_lower_copy( const RangeT& Input, const std::locale& Loc=std::locale()) { OutputSequenceT Output( ::boost::begin( Input ), ::boost::end( Input ) );
Doesn't this also do an unnecessary copy?
Olaf
It does, but it uses one less which as stated is a prime candidate for NRVO. The current approach needs one temporary for the return value as well as a temporary for argument conversion, which is basically only there to inform about the return type. Kind regards, Sebastian Karlsson

On Thu, Jun 23, 2011 at 1:26 PM, Sebastian Karlsson <sairony@gmail.com> wrote:
OutputSequenceT Output( ::boost::begin( Input ), ::boost::end( Input ) );
Doesn't this also do an unnecessary copy?
Olaf
It does, but it uses one less which as stated is a prime candidate for NRVO. The current approach needs one temporary for the return value as well as a temporary for argument conversion, which is basically only there to inform about the return type.
OutputSequenceT Output( ::boost::begin( Input ), ::boost::end( Input ) ); This one copies input to output. Then the function does case conversion. The original (AFAIK) does the case conversion while copying from input to output. Olaf

2011/6/23 Olaf van der Spek <ml@vdspek.org>:
On Thu, Jun 23, 2011 at 1:26 PM, Sebastian Karlsson <sairony@gmail.com> wrote:
OutputSequenceT Output( ::boost::begin( Input ), ::boost::end( Input ) );
Doesn't this also do an unnecessary copy?
Olaf
It does, but it uses one less which as stated is a prime candidate for NRVO. The current approach needs one temporary for the return value as well as a temporary for argument conversion, which is basically only there to inform about the return type.
OutputSequenceT Output( ::boost::begin( Input ), ::boost::end( Input ) );
This one copies input to output. Then the function does case conversion. The original (AFAIK) does the case conversion while copying from input to output.
Olaf
That appears to be truth, that's only a flaw in my implementation though, I'll see if I can fix it :) Kind regards, Sebastian Karlsson

2011/6/23 Sebastian Karlsson <sairony@gmail.com>:
2011/6/23 Olaf van der Spek <ml@vdspek.org>:
On Thu, Jun 23, 2011 at 1:26 PM, Sebastian Karlsson <sairony@gmail.com> wrote:
OutputSequenceT Output( ::boost::begin( Input ), ::boost::end( Input ) );
Doesn't this also do an unnecessary copy?
Olaf
It does, but it uses one less which as stated is a prime candidate for NRVO. The current approach needs one temporary for the return value as well as a temporary for argument conversion, which is basically only there to inform about the return type.
OutputSequenceT Output( ::boost::begin( Input ), ::boost::end( Input ) );
This one copies input to output. Then the function does case conversion. The original (AFAIK) does the case conversion while copying from input to output.
Olaf
That appears to be truth, that's only a flaw in my implementation though, I'll see if I can fix it :)
Kind regards, Sebastian Karlsson
Seems to be easier than I anticipated, just add output type as a param and slap it in as the return type for transform_range_copy, like so: template<typename SequenceT, typename OutputT > inline SequenceT to_lower_copy( const SequenceT& Input, const std::locale& Loc=std::locale()) { return ::boost::algorithm::detail::transform_range_copy< OutputT >( Input, ::boost::algorithm::detail::to_lowerF< typename range_value<SequenceT>::type >(Loc)); } Seems to work with the little testing I've been able to do so far. Kind regards, Sebastian Karlsson

On Thu, Jun 23, 2011 at 9:47 PM, Sebastian Karlsson <sairony@gmail.com> wrote:
Seems to be easier than I anticipated, just add output type as a param and slap it in as the return type for transform_range_copy, like so:
template<typename SequenceT, typename OutputT > inline SequenceT to_lower_copy(
Shouldn't the return type be OutputT?
const SequenceT& Input, const std::locale& Loc=std::locale()) { return ::boost::algorithm::detail::transform_range_copy< OutputT >( Input, ::boost::algorithm::detail::to_lowerF< typename range_value<SequenceT>::type >(Loc)); }
Seems to work with the little testing I've been able to do so far.
I'm not sure if C++ allows this, but SequenceT can be deduced while OutputT can not. Shouldn't OutputT therefore come first in the template list so that SequenceT can be deduced? Olaf

2011/6/24 Olaf van der Spek <ml@vdspek.org>:
On Thu, Jun 23, 2011 at 9:47 PM, Sebastian Karlsson <sairony@gmail.com> wrote:
Seems to be easier than I anticipated, just add output type as a param and slap it in as the return type for transform_range_copy, like so:
template<typename SequenceT, typename OutputT > inline SequenceT to_lower_copy(
Shouldn't the return type be OutputT?
const SequenceT& Input, const std::locale& Loc=std::locale()) { return ::boost::algorithm::detail::transform_range_copy< OutputT >( Input, ::boost::algorithm::detail::to_lowerF< typename range_value<SequenceT>::type >(Loc)); }
Seems to work with the little testing I've been able to do so far.
I'm not sure if C++ allows this, but SequenceT can be deduced while OutputT can not. Shouldn't OutputT therefore come first in the template list so that SequenceT can be deduced?
Olaf _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
You're correct on both accounts, I've fixed it and added a ticket to trac where hopefully one of the maintainers can take a closer look: https://svn.boost.org/trac/boost/ticket/5651 . Kind regards, Sebastian Karlsson
participants (3)
-
Jeffrey Lee Hellrung, Jr.
-
Olaf van der Spek
-
Sebastian Karlsson