69 changes: 62 additions & 7 deletions boost/range/access/front.hpp
@@ -1,7 +1,7 @@
// Boost.Range 2.0 Extension library
// via PStade Oven Library
//
// Copyright Akira Takahashi 2011.
// Copyright Akira Takahashi 2011-2013.
// Copyright Shunsuke Sogame 2005-2007.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
Expand All @@ -17,6 +17,7 @@
#include <boost/range/value_type.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/assert.hpp>
#include <boost/optional.hpp>

namespace boost {

Expand All @@ -33,15 +34,15 @@ namespace boost {
> {};

template <class SinglePassRange>
BOOST_DEDUCED_TYPENAME range_reference<SinglePassRange>::type
typename range_reference<SinglePassRange>::type
operator()(SinglePassRange& rng) const
{
BOOST_ASSERT(!boost::empty(rng));
return *boost::begin(rng);
}

template <class SinglePassRange>
BOOST_DEDUCED_TYPENAME range_reference<const SinglePassRange>::type
typename range_reference<const SinglePassRange>::type
operator()(const SinglePassRange& rng) const
{
BOOST_ASSERT(!boost::empty(rng));
Expand All @@ -60,43 +61,97 @@ namespace boost {
> {};

template <class SinglePassRange>
BOOST_DEDUCED_TYPENAME range_value<SinglePassRange>::type
typename range_value<SinglePassRange>::type
operator()(const SinglePassRange& rng) const
{
BOOST_ASSERT(!boost::empty(rng));
return *boost::begin(rng);
}
};

struct optional_front_t {
template <class Signature>
struct result;

template <class F, class SinglePassRange>
struct result<F(SinglePassRange&)> {
typedef boost::optional<
typename range_reference<
typename remove_reference<SinglePassRange>::type
>::type
> type;
};

template <class SinglePassRange>
boost::optional<typename range_reference<SinglePassRange>::type>
operator()(SinglePassRange& rng) const
{
if (boost::begin(rng) != boost::end(rng)) {
return *boost::begin(rng);
}
else {
return boost::none;
}
}

template <class SinglePassRange>
boost::optional<typename range_reference<const SinglePassRange>::type>
operator()(const SinglePassRange& rng) const
{
if (boost::begin(rng) != boost::end(rng)) {
return *boost::begin(rng);
}
else {
return boost::none;
}
}
};

const front_t front = {};
const value_front_t value_front = {};
const optional_front_t optional_front = {};

template <class SinglePassRange>
BOOST_DEDUCED_TYPENAME range_reference<SinglePassRange>::type
typename range_reference<SinglePassRange>::type
operator|(SinglePassRange& rng, const front_t& f)
{
return f(rng);
}

template <class SinglePassRange>
BOOST_DEDUCED_TYPENAME range_reference<const SinglePassRange>::type
typename range_reference<const SinglePassRange>::type
operator|(const SinglePassRange& rng, const front_t& f)
{
return f(rng);
}

template <class SinglePassRange>
BOOST_DEDUCED_TYPENAME range_value<SinglePassRange>::type
typename range_value<SinglePassRange>::type
operator|(const SinglePassRange& rng, const value_front_t& f)
{
return f(rng);
}

template <class SinglePassRange>
boost::optional<typename range_reference<SinglePassRange>::type>
operator|(SinglePassRange& rng, const optional_front_t& f)
{
return f(rng);
}

template <class SinglePassRange>
boost::optional<typename range_reference<const SinglePassRange>::type>
operator|(const SinglePassRange& rng, const optional_front_t& f)
{
return f(rng);
}

} // namespace range_detail

namespace range { namespace access {
using ::boost::range_detail::front;
using ::boost::range_detail::value_front;
using ::boost::range_detail::optional_front;
}} // namespace range::access
}

Expand Down
5 changes: 4 additions & 1 deletion libs/range/doc/reference/access.qbk
@@ -1,16 +1,19 @@
[/
Copyright 2011 Akira Takahashi
Copyright 2011-2013 Akira Takahashi
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:range_access Range Access]

[include access/at.qbk]
[include access/value_at.qbk]
[include access/optional_at.qbk]
[include access/back.qbk]
[include access/value_back.qbk]
[include access/optional_back.qbk]
[include access/front.qbk]
[include access/value_front.qbk]
[include access/optional_front.qbk]

[endsect]

64 changes: 64 additions & 0 deletions libs/range/doc/reference/access/optional_at.qbk
@@ -0,0 +1,64 @@
[/
Copyright 2013 Akira Takahashi
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 at]

`at` returns the N-th referent from the beginning of the range.
This accessor returns `boost::optional<T&>`. If exist N-th element, returns the element of `boost::optional`. If range is empty, returns `boost::none`.

[table
[[Syntax] [Code]]
[[Pipe] [`rng | boost::range::access::optional_at(n)`]]
[[Function] [`boost::range::access::optional_at(rng, n)`]]
]

* [*Range Category:] __random_access_range__
* [*Range Return Type:] `boost::optional<boost::range_reference<Range>::type>`

[heading Header]
``
#include <boost/range/access/at.hpp>
``
or
``
#include <boost/range/access.hpp>
``

[heading Namespace]
``
boost::range::access
``

[heading Example]

``
#include <iostream>
#include <vector>
#include <boost/assign/list_of.hpp>
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/access/at.hpp>

int main()
{
using namespace boost::adaptors;
using namespace boost::range::access;

std::vector<int> v = boost::assign::list_of(1)(2)(3);

if (boost::optional<int&> x = v | optional_at(1)) {
std::cout << x.get() << std::endl;
}
else {
std::cout << "not found" << std::endl;
}
}
``

This would produce the output:
``
2
``
[endsect]

66 changes: 66 additions & 0 deletions libs/range/doc/reference/access/optional_back.qbk
@@ -0,0 +1,66 @@
[/
Copyright 2013 Akira Takahashi
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 back]

`back` returns the last referent in the range.
This accessor returns `boost::optional<T&>`. If exist last element, returns the element of `boost::optional`. If range is empty, returns `boost::none`.

[table
[[Syntax] [Code]]
[[Pipe] [`rng | boost::range::access::optional_back`]]
[[Function] [`boost::range::access::optional_back(rng)`]]
]

* [*Range Category:] __bidirectional_range__
* [*Range Return Type:] `boost::optional<boost::range_reference<Range>::type>`

[heading Header]
``
#include <boost/range/access/back.hpp>
``
or
``
#include <boost/range/access.hpp>
``

[heading Namespace]
``
boost::range::access
``

[heading Example]

``
#include <iostream>
#include <vector>
#include <boost/assign/list_of.hpp>
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/access/back.hpp>

bool is_even(int x) { return x % 2 == 0; }

int main()
{
using namespace boost::adaptors;
using namespace boost::range::access;

std::vector<int> v = boost::assign::list_of(1)(1)(2);

if (boost::optional<int&> x = v | filtered(is_even) | optional_back) {
std::cout << x.get() << std::endl;
}
else {
std::cout << "not found" << std::endl;
}
}
``

This would produce the output:
``
2
``
[endsect]

67 changes: 67 additions & 0 deletions libs/range/doc/reference/access/optional_front.qbk
@@ -0,0 +1,67 @@
[/
Copyright 2013 Akira Takahashi
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 optional_front]

`optional_front` returns the first referent in the range.
This accessor returns `boost::optional<T&>`. If exist first element, returns the element of `boost::optional`. If range is empty, returns `boost::none`.

[table
[[Syntax] [Code]]
[[Pipe] [`rng | boost::range::access::optional_front`]]
[[Function] [`boost::range::access::optional_front(rng)`]]
]

* [*Range Category:] __single_pass_range__
* [*Range Return Type:] `boost::optional<boost::range_reference<Range>::type>`

[heading Header]
``
#include <boost/range/access/front.hpp>
``
or
``
#include <boost/range/access.hpp>
``

[heading Namespace]
``
boost::range::access
``

[heading Example]

``
#include <iostream>
#include <vector>
#include <boost/assign/list_of.hpp>
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/access/front.hpp>

bool is_even(int x) { return x % 2 == 0; }

int main()
{
using namespace boost::adaptors;
using namespace boost::range::access;

std::vector<int> v = boost::assign::list_of(1)(2)(3);

if (boost::optional<int&> x = v | filtered(is_even) | optional_front) {
std::cout << x.get() << std::endl;
}
else {
std::cout << "not found" << std::endl;
}
}
``

This would produce the output:
``
2
``

[endsect]

21 changes: 20 additions & 1 deletion libs/range/test/access_test/at.cpp
@@ -1,7 +1,7 @@
// Boost.Range 2.0 Extension library
// via PStade Oven Library
//
// Copyright Akira Takahashi 2011.
// Copyright Akira Takahashi 2011-2013.
// Copyright Shunsuke Sogame 2005-2007.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
Expand All @@ -22,6 +22,7 @@ void test()
{
using boost::range::access::at;
using boost::range::access::value_at;
using boost::range::access::optional_at;

// operator style
{
Expand All @@ -38,6 +39,15 @@ void test()
const RandomAccessContainer expected = boost::assign::list_of(3)(1)(0)(2)(5);
BOOST_TEST(boost::equal(c, expected));
}
{
RandomAccessContainer c = boost::assign::list_of(3)(1)(4);
BOOST_TEST((c | optional_at(2)).get() == 4);
BOOST_TEST(!(c | optional_at(3)).is_initialized());

(c | optional_at(2)).get() = 0;
const RandomAccessContainer expected = boost::assign::list_of(3)(1)(0);
BOOST_TEST(boost::equal(c, expected));
}

// function style
{
Expand All @@ -54,6 +64,15 @@ void test()
const RandomAccessContainer expected = boost::assign::list_of(3)(1)(0)(2)(5);
BOOST_TEST(boost::equal(c, expected));
}
{
RandomAccessContainer c = boost::assign::list_of(3)(1)(4);
BOOST_TEST(optional_at(c, 2).get() == 4);
BOOST_TEST(!optional_at(c, 3).is_initialized());

optional_at(c, 2).get() = 0;
const RandomAccessContainer expected = boost::assign::list_of(3)(1)(0);
BOOST_TEST(boost::equal(c, expected));
}

// result_of
{
Expand Down
29 changes: 28 additions & 1 deletion libs/range/test/access_test/back.cpp
@@ -1,7 +1,7 @@
// Boost.Range 2.0 Extension library
// via PStade Oven Library
//
// Copyright Akira Takahashi 2011.
// Copyright Akira Takahashi 2011-2013.
// Copyright Shunsuke Sogame 2005-2007.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
Expand All @@ -22,6 +22,7 @@ void test()
{
using boost::range::access::back;
using boost::range::access::value_back;
using boost::range::access::optional_back;

// operator style
{
Expand All @@ -38,6 +39,19 @@ void test()
const BidirectionalContainer expected = boost::assign::list_of(3)(1)(4)(2)(0);
BOOST_TEST(boost::equal(c, expected));
}
{
BidirectionalContainer c = boost::assign::list_of(1)(2)(3);
BOOST_TEST((c | optional_back).get() == 3);

boost::optional<int&> opt = c | optional_back;
opt.get() = 0;

const BidirectionalContainer expected = boost::assign::list_of(1)(2)(0);
BOOST_TEST(boost::equal(c, expected));

BidirectionalContainer c2;
BOOST_TEST(!(c2 | optional_back).is_initialized());
}

// function style
{
Expand All @@ -54,6 +68,19 @@ void test()
const BidirectionalContainer expected = boost::assign::list_of(3)(1)(4)(2)(0);
BOOST_TEST(boost::equal(c, expected));
}
{
BidirectionalContainer c = boost::assign::list_of(1)(2)(3);
BOOST_TEST(optional_back(c).get() == 3);

boost::optional<int&> opt = optional_back(c);
opt.get() = 0;

const BidirectionalContainer expected = boost::assign::list_of(1)(2)(0);
BOOST_TEST(boost::equal(c, expected));

BidirectionalContainer c2;
BOOST_TEST(!optional_back(c2).is_initialized());
}

// result_of
{
Expand Down
27 changes: 25 additions & 2 deletions libs/range/test/access_test/front.cpp
@@ -1,7 +1,7 @@
// Boost.Range 2.0 Extension library
// via PStade Oven Library
//
// Copyright Akira Takahashi 2011.
// Copyright Akira Takahashi 2011-2013.
// Copyright Shunsuke Sogame 2005-2007.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
Expand All @@ -25,6 +25,7 @@ void test()
using boost::adaptors::dropped;
using boost::range::access::front;
using boost::range::access::value_front;
using boost::range::access::optional_front;

// operator style
{
Expand All @@ -41,6 +42,17 @@ void test()
const SinglePassContainer expected = boost::assign::list_of(1)(2)(0)(4)(5)(6);
BOOST_TEST(boost::equal(c, expected));
}
{
SinglePassContainer c = boost::assign::list_of(1)(2)(3);
BOOST_TEST((c | dropped(1) | optional_front).get() == 2);
BOOST_TEST(!(c | dropped(3) | optional_front).is_initialized());

boost::optional<int&> opt = c | dropped(1) | optional_front;
opt.get() = 0;

const SinglePassContainer expected = boost::assign::list_of(1)(0)(3);
BOOST_TEST(boost::equal(c, expected));
}

// function style
{
Expand All @@ -57,6 +69,18 @@ void test()
const SinglePassContainer expected = boost::assign::list_of(1)(2)(0)(4)(5)(6);
BOOST_TEST(boost::equal(c, expected));
}
{
SinglePassContainer c = boost::assign::list_of(1)(2)(3);
BOOST_TEST(optional_front(c | dropped(1)).get() == 2);
BOOST_TEST(!optional_front(c | dropped(3)).is_initialized());

boost::optional<int&> opt = optional_front(c | dropped(1));
opt.get() = 0;

const SinglePassContainer expected = boost::assign::list_of(1)(0)(3);
BOOST_TEST(boost::equal(c, expected));
}


// result_of
{
Expand All @@ -79,7 +103,6 @@ void test()
expected
));
}

}

int main()
Expand Down