diff --git a/doc/reference/adaptors.qbk b/doc/reference/adaptors.qbk index 2cead3648..ec6bbed76 100644 --- a/doc/reference/adaptors.qbk +++ b/doc/reference/adaptors.qbk @@ -173,6 +173,7 @@ rng | boost::adaptors::adaptor_generator [include adaptors/map_keys.qbk] [include adaptors/map_values.qbk] [include adaptors/ref_unwrapped.qbk] +[include adaptors/addressed.qbk] [include adaptors/replaced.qbk] [include adaptors/replaced_if.qbk] [include adaptors/reversed.qbk] diff --git a/doc/reference/adaptors/addressed.qbk b/doc/reference/adaptors/addressed.qbk new file mode 100644 index 000000000..60d282397 --- /dev/null +++ b/doc/reference/adaptors/addressed.qbk @@ -0,0 +1,40 @@ +[/ + Copyright 2022 Denis Mikhailov + 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:addressed addressed] + +[table + [[Syntax] [Code]] + [[Pipe] [`rng | boost::adaptors::addressed`]] + [[Function] [`boost::adaptors::addressof(rng)`]] +] + +This adaptor produces a range than applies `boost::addressof` on all values in +the range. + +* [*Precondition:] For any `value_type` of the range. +* [*Postcondition:] For all elements `x` in the returned range, `x` is the result of `boost::addressof(y)` where `y` is the corresponding element in the original range. +* [*Range Category:] __single_pass_range__ +* [*Range Return Type:] `boost::addressof_range` +* [*Returned Range Category:] The range category of `rng`. + +[section:addressed_example addressed example] +[import ../../../test/adaptor_test/addressed_example.cpp] +[addressed_example] +[endsect] + +This would produce the output: +`` +Element = 10 Address = 0x1b83310 +Element = 20 Address = 0x1b83314 +Element = 30 Address = 0x1b83318 +Element = 40 Address = 0x1b8331c +Element = 50 Address = 0x1b83320 +Element = 60 Address = 0x1b83324 +Element = 70 Address = 0x1b83328 +Element = 80 Address = 0x1b8332c +Element = 90 Address = 0x1b83330 +`` +[endsect] diff --git a/include/boost/range/adaptor/addressed.hpp b/include/boost/range/adaptor/addressed.hpp new file mode 100644 index 000000000..247910f1f --- /dev/null +++ b/include/boost/range/adaptor/addressed.hpp @@ -0,0 +1,126 @@ +// Boost.Range library +// +// Copyright Denis Mikhailov 2022. +// 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_ADDRESSED_HPP +#define BOOST_RANGE_ADAPTOR_ADDRESSED_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +namespace boost +{ + namespace range_detail + { + struct addressof_forwarder {}; + + template + struct addressof_value + { + BOOST_STATIC_ASSERT(boost::is_reference::value); + typedef typename boost::remove_reference::type* result_type; + typedef Reference argument_type; + + result_type operator()(argument_type x) const + { + return boost::addressof(x); + } + }; + + template< typename R > + struct addressof_range : + boost::iterator_range< + boost::transform_iterator< + addressof_value::type>, + typename boost::range_iterator::type> > + { + private: + typedef typename boost::range_reference::type reference_type; + typedef typename boost::range_iterator::type iterator_base; + typedef addressof_value Fn; + typedef boost::transform_iterator iterator; + typedef boost::iterator_range base; + + public: + addressof_range(R& r) + : base(iterator(boost::begin(r), Fn()), + iterator(boost::end(r), Fn())) + { } + }; + + template< class SinglePassRange > + inline addressof_range + operator|( SinglePassRange& r, addressof_forwarder ) + { + BOOST_RANGE_CONCEPT_ASSERT(( + SinglePassRangeConcept)); + + return addressof_range( r ); + } + + template< class SinglePassRange > + inline addressof_range + operator|( const SinglePassRange& r, addressof_forwarder ) + { + BOOST_RANGE_CONCEPT_ASSERT(( + SinglePassRangeConcept)); + + return addressof_range( r ); + } + + } + + using range_detail::addressof_range; + + namespace adaptors + { + namespace + { + const range_detail::addressof_forwarder addressed = + range_detail::addressof_forwarder(); + } + + template + inline addressof_range + addressof(SinglePassRange& rng) + { + BOOST_RANGE_CONCEPT_ASSERT(( + SinglePassRangeConcept)); + + return addressof_range( rng ); + } + + template + inline addressof_range + addressof(const SinglePassRange& rng) + { + BOOST_RANGE_CONCEPT_ASSERT(( + SinglePassRangeConcept)); + + return addressof_range( rng ); + } + } // 'adaptors' + +} + +#endif diff --git a/include/boost/range/adaptors.hpp b/include/boost/range/adaptors.hpp index 0530c4d36..48d4892ba 100644 --- a/include/boost/range/adaptors.hpp +++ b/include/boost/range/adaptors.hpp @@ -12,6 +12,7 @@ #ifndef BOOST_RANGE_ADAPTORS_HPP #define BOOST_RANGE_ADAPTORS_HPP +#include #include #include #include diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index cd2774e9f..623379567 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -61,6 +61,8 @@ test-suite range : [ range-test adaptor_test/map ] [ range-test adaptor_test/ref_unwrapped ] [ range-test adaptor_test/ref_unwrapped_example ] + [ range-test adaptor_test/addressed ] + [ range-test adaptor_test/addressed_example ] [ range-test adaptor_test/replaced ] [ range-test adaptor_test/replaced_if ] [ range-test adaptor_test/reversed ] diff --git a/test/adaptor_test/addressed.cpp b/test/adaptor_test/addressed.cpp new file mode 100644 index 000000000..23ded1636 --- /dev/null +++ b/test/adaptor_test/addressed.cpp @@ -0,0 +1,60 @@ +// Boost.Range library +// +// Copyright Denis Mikhailov 2022. +// 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/ +// + +#include + +#include +#include + +#include +#include + +#include + +namespace boost +{ + namespace + { + void simple_test() + { + using namespace boost::assign; + using namespace boost::adaptors; + std::vector a = list_of(1)(2)(3); + BOOST_CHECK(boost::copy_range >(a | addressed) + == list_of(&a[0])(&a[1])(&a[2])); + BOOST_CHECK(boost::copy_range >(addressof(a)) + == list_of(&a[0])(&a[1])(&a[2])); + } + + void simple_const_test() + { + using namespace boost::assign; + using namespace boost::adaptors; + const std::vector a = list_of(1)(2)(3); + BOOST_CHECK(boost::copy_range >(a | addressed) + == list_of(&a[0])(&a[1])(&a[2])); + BOOST_CHECK(boost::copy_range >(addressof(a)) + == list_of(&a[0])(&a[1])(&a[2])); + } + } +} + +boost::unit_test::test_suite* +init_unit_test_suite(int argc, char* argv[]) +{ + boost::unit_test::test_suite* test + = BOOST_TEST_SUITE( "RangeTestSuite.adaptor.addressed" ); + + test->add(BOOST_TEST_CASE(&boost::simple_test)); + test->add(BOOST_TEST_CASE(&boost::simple_const_test)); + + return test; +} diff --git a/test/adaptor_test/addressed_example.cpp b/test/adaptor_test/addressed_example.cpp new file mode 100644 index 000000000..ff2bcbba1 --- /dev/null +++ b/test/adaptor_test/addressed_example.cpp @@ -0,0 +1,104 @@ +// Boost.Range library +// +// Copyright Denis Mikhailov 2022. +// 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/ +// + +//[addressed_example + +//<- +#include +//-> + +#include +#include +#include +#include +#include + +//<- +#include +#include +#include + +namespace +{ + +template +void check_element_and_address( + Iterator1 test_first, + Iterator1 test_last, + Iterator2 reference_first, + Iterator2 reference_last) +{ + BOOST_CHECK_EQUAL( std::distance(test_first, test_last), + std::distance(reference_first, reference_last) ); + + Iterator1 test_it = test_first; + Iterator2 reference_it = reference_first; + for (; test_it != test_last; ++test_it, ++reference_it) + { + BOOST_CHECK_EQUAL(**test_it, *reference_it); + BOOST_CHECK_EQUAL(*test_it, boost::addressof(*reference_it)); + } +} + +template +void check_element_and_address( + const SinglePassRange1& test_rng, + const SinglePassRange2& reference_rng) +{ + check_element_and_address( + boost::begin(test_rng), boost::end(test_rng), + boost::begin(reference_rng), boost::end(reference_rng)); +} +//-> + +//<- +void addressed_example_test() +//-> +//=int main(int argc, const char* argv[]) +{ + using namespace boost::assign; + using namespace boost::adaptors; + + std::vector input; + input += 10,20,30,40,50,60,70,80,90; + +//<- +#ifndef BOOST_NO_CXX11_RANGE_BASED_FOR +//-> + for (const auto& address : input | addressed) + { + std::cout << "Element = " << *address + << " Address = " << address + << std::endl; + } +//<- +#endif // C++11 has range for loop +//-> + +//= return 0; +//=} +//] + check_element_and_address( + input | addressed, + input); +} +} + +boost::unit_test::test_suite* +init_unit_test_suite(int argc, char* argv[]) +{ + boost::unit_test::test_suite* test + = BOOST_TEST_SUITE( "RangeTestSuite.adaptor.addressed_example" ); + + test->add( BOOST_TEST_CASE( &addressed_example_test ) ); + + return test; +}