add a new range adaptor boost::adaptors::ref_unwrapped

The new adaptor is like boost::adaptors::indirected, but for
std::reference_wrapper values (instead of pointer). It calls
.get() on every value and returns the result. It is useful for
range-based iteration of ranges of std::reference_wrapper (or
related) types.
This commit is contained in:
Robin Eckert
2015-11-04 19:12:26 +01:00
parent 78a8f5bf3d
commit 3225aaf82b
6 changed files with 285 additions and 0 deletions

View File

@ -172,6 +172,7 @@ rng | boost::adaptors::adaptor_generator
[include adaptors/indirected.qbk]
[include adaptors/map_keys.qbk]
[include adaptors/map_values.qbk]
[include adaptors/ref_unwrapped.qbk]
[include adaptors/replaced.qbk]
[include adaptors/replaced_if.qbk]
[include adaptors/reversed.qbk]

View File

@ -0,0 +1,32 @@
[/
Copyright 2015 Robin Eckert
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)
/]
[section:ref_unwrapped ref_unwrapped]
[table
[[Syntax] [Code]]
[[Pipe] [`rng | boost::adaptors::ref_unwrapped`]]
[[Function] [`boost::adaptors::ref_unwrap(rng)`]]
]
This adaptor produces a range than applies `.get()` on all values in
the range. It is useful for iterating ranges of
`std::reference_wrapper` values or values using similar semantics.
The adaptor is C++11 (and above) only.
* [*Precondition:] The `value_type` of the range has a `.get() const`.
* [*Postcondition:] For all elements `x` in the returned range, `x` is the result of `y.get()` where `y` is the corresponding element in the original range.
* [*Range Category:] __single_pass_range__
* [*Range Return Type:] `boost::unwrap_ref_range<decltype(rng)>`
* [*Returned Range Category:] The range category of `rng`.
[section:ref_unwrapped_example ref_unwrapped example]
[import ../../../test/adaptor_test/ref_unwrapped_example.cpp]
[ref_unwrapped_example]
[endsect]
This would produce the output `123`.
[endsect]

View File

@ -0,0 +1,102 @@
// Boost.Range library
//
// Copyright Robin Eckert 2015.
// Copyright Thorsten Ottosen, Neil Groves 2006 - 2008. Use, modification and
// distribution is subject to 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)
//
// For more information, see http://www.boost.org/libs/range/
//
#ifndef BOOST_RANGE_ADAPTOR_REF_UNWRAPPED_HPP
#define BOOST_RANGE_ADAPTOR_REF_UNWRAPPED_HPP
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/reference.hpp>
#include <boost/range/concepts.hpp>
#include <utility>
#if !defined(BOOST_NO_CXX11_DECLTYPE)
namespace boost
{
namespace range_detail
{
struct ref_unwrapped_forwarder {};
template<class SinglePassRange>
struct unwrap_ref
{
typedef BOOST_DEDUCED_TYPENAME
range_reference<SinglePassRange>::type argument_type;
using result_type = decltype(std::declval<argument_type>().get() );
result_type operator()( argument_type &&r ) const
{
return r.get();
}
};
template<class SinglePassRange>
class unwrap_ref_range
: public transformed_range<unwrap_ref<SinglePassRange>,
SinglePassRange>
{
using base = transformed_range<unwrap_ref<SinglePassRange>,
SinglePassRange>;
public:
using transform_fn_type = unwrap_ref<SinglePassRange>;
using source_range_type = SinglePassRange;
unwrap_ref_range(transform_fn_type fn, source_range_type &rng)
: base(fn, rng)
{
}
unwrap_ref_range(const base &other) : base(other) {}
};
template<class SinglePassRange>
inline unwrap_ref_range<SinglePassRange>
operator|(SinglePassRange& r, ref_unwrapped_forwarder)
{
BOOST_RANGE_CONCEPT_ASSERT((
SinglePassRangeConcept<SinglePassRange>));
return operator|( r,
boost::adaptors::transformed(unwrap_ref<SinglePassRange>()));
}
}
using range_detail::unwrap_ref_range;
namespace adaptors
{
namespace
{
const range_detail::ref_unwrapped_forwarder ref_unwrapped =
range_detail::ref_unwrapped_forwarder();
}
template<class SinglePassRange>
inline unwrap_ref_range<SinglePassRange>
ref_unwrap(SinglePassRange& rng)
{
BOOST_RANGE_CONCEPT_ASSERT((
SinglePassRangeConcept<SinglePassRange>));
return unwrap_ref_range<SinglePassRange>(
range_detail::unwrap_ref<SinglePassRange>(), rng );
}
} // 'adaptors'
}
#endif
#endif

View File

@ -59,6 +59,8 @@ test-suite range :
[ range-test adaptor_test/indexed ]
[ range-test adaptor_test/indirected ]
[ range-test adaptor_test/map ]
[ range-test adaptor_test/ref_unwrapped ]
[ range-test adaptor_test/ref_unwrapped_example ]
[ range-test adaptor_test/replaced ]
[ range-test adaptor_test/replaced_if ]
[ range-test adaptor_test/reversed ]

View File

@ -0,0 +1,101 @@
// Boost.Range library
//
// Copyright Robin Eckert 2015. Use, modification and distribution is
// subject to 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)
//
//
// For more information, see http://www.boost.org/libs/range/
//
#include <boost/range/adaptor/ref_unwrapped.hpp>
#define BOOST_TEST_MAIN
#include <boost/test/test_tools.hpp>
#include <boost/test/unit_test.hpp>
#include <vector>
#if !defined(BOOST_NO_CXX11_AUTO_DECLARATIONS) && !defined(BOOST_NO_CXX11_RANGE_BASED_FOR)
namespace boost
{
BOOST_AUTO_TEST_CASE(test_mutable)
{
int one = 1;
int two = 2;
int three = 3;
std::vector<std::reference_wrapper<int>> input_values{one, two, three};
const std::vector<int*> expected{&one, &two, &three};
std::vector<int*> actual;
for (auto&& value : input_values | adaptors::ref_unwrapped)
{
actual.push_back(&value);
}
BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(),
expected.end(),
actual.begin(),
actual.end());
}
BOOST_AUTO_TEST_CASE(test_const_range)
{
int one = 1;
int two = 2;
int three = 3;
const std::vector<std::reference_wrapper<int>> input_values{one, two, three};
const std::vector<int*> expected{&one, &two, &three};
std::vector<int*> actual;
for (auto&& value : input_values | adaptors::ref_unwrapped)
{
actual.push_back(&value);
}
BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(),
expected.end(),
actual.begin(),
actual.end());
}
BOOST_AUTO_TEST_CASE(test_const_reference)
{
const int one = 1;
const int two = 2;
const int three = 3;
const std::vector<std::reference_wrapper<const int>> input_values{one, two, three};
const std::vector<const int*> expected{&one, &two, &three};
std::vector<const int*> actual;
for (auto&& value : input_values | adaptors::ref_unwrapped)
{
actual.push_back(&value);
}
BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(),
expected.end(),
actual.begin(),
actual.end());
}
}
#else
BOOST_AUTO_TEST_CASE(empty)
{
// C++11 only
}
#endif

View File

@ -0,0 +1,47 @@
// Boost.Range library
//
// Copyright Robin Eckert 2015. Use, modification and distribution is
// subject to 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)
//
//
// For more information, see http://www.boost.org/libs/range/
//
//[ref_unwrapped_example
#include <boost/range/adaptor/ref_unwrapped.hpp>
#include <iostream>
#include <vector>
struct example
{
int value;
};
int main(int argc, const char* argv[])
{
//<-
#if !defined(BOOST_NO_CXX11_DECLTYPE) \
&& !defined(BOOST_NO_CXX11_RANGE_BASED_FOR) \
&& !defined(BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX) \
&& !defined(BOOST_NO_CXX11_AUTO_DECLARATIONS)
//->
using boost::adaptors::ref_unwrapped;
example one{1};
example two{2};
example three{3};
std::vector<std::reference_wrapper<example> > input{one, two, three};
for (auto&& entry : input | ref_unwrapped)
{
std::cout << entry.value;
}
return 0;
//<-
#endif
//->
}
//]