mirror of
https://github.com/boostorg/iterator.git
synced 2025-05-12 14:01:37 +00:00
Fixed postfix increment for incrementable and single-pass iterator facade
[SVN r23456]
This commit is contained in:
parent
02f606816d
commit
f49f68c8fe
@ -31,19 +31,39 @@ namespace boost {
|
|||||||
struct no_traversal_tag {};
|
struct no_traversal_tag {};
|
||||||
|
|
||||||
struct incrementable_traversal_tag
|
struct incrementable_traversal_tag
|
||||||
: no_traversal_tag {};
|
: no_traversal_tag
|
||||||
|
{
|
||||||
|
// incrementable_traversal_tag() {}
|
||||||
|
// incrementable_traversal_tag(std::output_iterator_tag const&) {};
|
||||||
|
};
|
||||||
|
|
||||||
struct single_pass_traversal_tag
|
struct single_pass_traversal_tag
|
||||||
: incrementable_traversal_tag {};
|
: incrementable_traversal_tag
|
||||||
|
{
|
||||||
|
// single_pass_traversal_tag() {}
|
||||||
|
// single_pass_traversal_tag(std::input_iterator_tag const&) {};
|
||||||
|
};
|
||||||
|
|
||||||
struct forward_traversal_tag
|
struct forward_traversal_tag
|
||||||
: single_pass_traversal_tag {};
|
: single_pass_traversal_tag
|
||||||
|
{
|
||||||
|
// forward_traversal_tag() {}
|
||||||
|
// forward_traversal_tag(std::forward_iterator_tag const&) {};
|
||||||
|
};
|
||||||
|
|
||||||
struct bidirectional_traversal_tag
|
struct bidirectional_traversal_tag
|
||||||
: forward_traversal_tag {};
|
: forward_traversal_tag
|
||||||
|
{
|
||||||
|
// bidirectional_traversal_tag() {};
|
||||||
|
// bidirectional_traversal_tag(std::bidirectional_iterator_tag const&) {};
|
||||||
|
};
|
||||||
|
|
||||||
struct random_access_traversal_tag
|
struct random_access_traversal_tag
|
||||||
: bidirectional_traversal_tag {};
|
: bidirectional_traversal_tag
|
||||||
|
{
|
||||||
|
// random_access_traversal_tag() {};
|
||||||
|
// random_access_traversal_tag(std::random_access_iterator_tag const&) {};
|
||||||
|
};
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <boost/mpl/apply_if.hpp>
|
#include <boost/mpl/apply_if.hpp>
|
||||||
#include <boost/mpl/or.hpp>
|
#include <boost/mpl/or.hpp>
|
||||||
#include <boost/mpl/and.hpp>
|
#include <boost/mpl/and.hpp>
|
||||||
|
#include <boost/mpl/not.hpp>
|
||||||
#include <boost/mpl/always.hpp>
|
#include <boost/mpl/always.hpp>
|
||||||
#include <boost/mpl/apply.hpp>
|
#include <boost/mpl/apply.hpp>
|
||||||
|
|
||||||
@ -118,12 +119,87 @@ namespace boost
|
|||||||
# endif
|
# endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// iterators whose dereference operators reference the same value
|
||||||
|
// for all iterators into the same sequence (like many input
|
||||||
|
// iterators) need help with their postfix ++: the referenced
|
||||||
|
// value must be read and stored away before the increment occurs
|
||||||
|
// so that *a++ yields the originally referenced element and not
|
||||||
|
// the next one.
|
||||||
|
//
|
||||||
|
// In general, we can't determine that such an iterator isn't
|
||||||
|
// writable -- we also need to store a copy of the old iterator so
|
||||||
|
// that it can be written into.
|
||||||
|
template <class Iterator>
|
||||||
|
class postfix_increment_proxy
|
||||||
|
{
|
||||||
|
typedef typename iterator_value<Iterator>::type value_type;
|
||||||
|
public:
|
||||||
|
explicit postfix_increment_proxy(Iterator const& x)
|
||||||
|
: stored_value(*x)
|
||||||
|
, stored_iterator(x)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Dereferencing must return a proxy so that both *r++ = o and
|
||||||
|
// value_type(*r++) can work. In this case, *r is the same as
|
||||||
|
// *r++, and the conversion operator below is used to ensure
|
||||||
|
// readability.
|
||||||
|
postfix_increment_proxy const&
|
||||||
|
operator*() const
|
||||||
|
{
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provides readability of *r++
|
||||||
|
operator value_type const&() const
|
||||||
|
{
|
||||||
|
return stored_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provides writability of *r++
|
||||||
|
template <class T>
|
||||||
|
T const& operator=(T const& x) const
|
||||||
|
{
|
||||||
|
*this->stored_iterator = x;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This overload just in case only non-const objects are writable
|
||||||
|
template <class T>
|
||||||
|
T& operator=(T& x) const
|
||||||
|
{
|
||||||
|
*this->stored_iterator = x;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
value_type stored_value;
|
||||||
|
Iterator stored_iterator;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Iterator, class Value, class Reference, class CategoryOrTraversal>
|
||||||
|
struct postfix_increment_result
|
||||||
|
: mpl::if_<
|
||||||
|
mpl::and_<
|
||||||
|
// This is only needed for readable iterators
|
||||||
|
is_convertible<Reference,Value>
|
||||||
|
|
||||||
|
// No multipass iterator can have values that disappear
|
||||||
|
// before positions can be re-visited
|
||||||
|
, mpl::not_<
|
||||||
|
is_convertible<
|
||||||
|
typename iterator_category_to_traversal<CategoryOrTraversal>::type
|
||||||
|
, forward_traversal_tag
|
||||||
|
>
|
||||||
|
>
|
||||||
|
>
|
||||||
|
, postfix_increment_proxy<Iterator>
|
||||||
|
, Iterator
|
||||||
|
>
|
||||||
|
{};
|
||||||
|
|
||||||
// operator->() needs special support for input iterators to strictly meet the
|
// operator->() needs special support for input iterators to strictly meet the
|
||||||
// standard's requirements. If *i is not a reference type, we must still
|
// standard's requirements. If *i is not a reference type, we must still
|
||||||
// produce a (constant) lvalue to which a pointer can be formed. We do that by
|
// produce a (constant) lvalue to which a pointer can be formed. We do that by
|
||||||
// returning an instantiation of this special proxy class template.
|
// returning an instantiation of this special proxy class template.
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
struct operator_arrow_proxy
|
struct operator_arrow_proxy
|
||||||
{
|
{
|
||||||
@ -138,7 +214,7 @@ namespace boost
|
|||||||
// A metafunction that gets the result type for operator->. Also
|
// A metafunction that gets the result type for operator->. Also
|
||||||
// has a static function make() which builds the result from a
|
// has a static function make() which builds the result from a
|
||||||
// Reference
|
// Reference
|
||||||
template <class Value, class Reference, class Pointer>
|
template <class ValueType, class Reference, class Pointer>
|
||||||
struct operator_arrow_result
|
struct operator_arrow_result
|
||||||
{
|
{
|
||||||
// CWPro8.3 won't accept "operator_arrow_result::type", and we
|
// CWPro8.3 won't accept "operator_arrow_result::type", and we
|
||||||
@ -147,7 +223,7 @@ namespace boost
|
|||||||
typedef typename mpl::if_<
|
typedef typename mpl::if_<
|
||||||
is_reference<Reference>
|
is_reference<Reference>
|
||||||
, Pointer
|
, Pointer
|
||||||
, operator_arrow_proxy<Value>
|
, operator_arrow_proxy<ValueType>
|
||||||
>::type type;
|
>::type type;
|
||||||
|
|
||||||
static type make(Reference x)
|
static type make(Reference x)
|
||||||
@ -165,13 +241,14 @@ namespace boost
|
|||||||
};
|
};
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
//
|
// A proxy return type for operator[], needed to deal with
|
||||||
// Iterator is actually an iterator_facade, so we do not have to
|
// iterators that may invalidate referents upon destruction.
|
||||||
// go through iterator_traits to access the traits.
|
// Consider the temporary iterator in *(a + n)
|
||||||
//
|
|
||||||
template <class Iterator>
|
template <class Iterator>
|
||||||
class operator_brackets_proxy
|
class operator_brackets_proxy
|
||||||
{
|
{
|
||||||
|
// Iterator is actually an iterator_facade, so we do not have to
|
||||||
|
// go through iterator_traits to access the traits.
|
||||||
typedef typename Iterator::reference reference;
|
typedef typename Iterator::reference reference;
|
||||||
typedef typename Iterator::value_type value_type;
|
typedef typename Iterator::value_type value_type;
|
||||||
|
|
||||||
@ -195,13 +272,17 @@ namespace boost
|
|||||||
Iterator m_iter;
|
Iterator m_iter;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class Value, class Reference>
|
// A metafunction that determines whether operator[] must return a
|
||||||
|
// proxy, or whether it can simply return a copy of the value_type.
|
||||||
|
template <class ValueType, class Reference>
|
||||||
struct use_operator_brackets_proxy
|
struct use_operator_brackets_proxy
|
||||||
: mpl::and_<
|
: mpl::not_<
|
||||||
// Really we want an is_copy_constructible trait here,
|
mpl::and_<
|
||||||
// but is_POD will have to suffice in the meantime.
|
// Really we want an is_copy_constructible trait here,
|
||||||
boost::is_POD<Value>
|
// but is_POD will have to suffice in the meantime.
|
||||||
, iterator_writability_disabled<Value,Reference>
|
boost::is_POD<ValueType>
|
||||||
|
, iterator_writability_disabled<ValueType,Reference>
|
||||||
|
>
|
||||||
>
|
>
|
||||||
{};
|
{};
|
||||||
|
|
||||||
@ -210,19 +291,19 @@ namespace boost
|
|||||||
{
|
{
|
||||||
typedef typename mpl::if_<
|
typedef typename mpl::if_<
|
||||||
use_operator_brackets_proxy<Value,Reference>
|
use_operator_brackets_proxy<Value,Reference>
|
||||||
, Value
|
|
||||||
, operator_brackets_proxy<Iterator>
|
, operator_brackets_proxy<Iterator>
|
||||||
|
, Value
|
||||||
>::type type;
|
>::type type;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class Iterator>
|
template <class Iterator>
|
||||||
operator_brackets_proxy<Iterator> make_operator_brackets_result(Iterator const& iter, mpl::false_)
|
operator_brackets_proxy<Iterator> make_operator_brackets_result(Iterator const& iter, mpl::true_)
|
||||||
{
|
{
|
||||||
return operator_brackets_proxy<Iterator>(iter);
|
return operator_brackets_proxy<Iterator>(iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Iterator>
|
template <class Iterator>
|
||||||
typename Iterator::value_type make_operator_brackets_result(Iterator const& iter, mpl::true_)
|
typename Iterator::value_type make_operator_brackets_result(Iterator const& iter, mpl::false_)
|
||||||
{
|
{
|
||||||
return *iter;
|
return *iter;
|
||||||
}
|
}
|
||||||
@ -385,6 +466,21 @@ namespace boost
|
|||||||
return f2.distance_to(f1);
|
return f2.distance_to(f1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Curiously Recurring Template interface.
|
||||||
|
//
|
||||||
|
template <class I, class V, class TC, class R, class D>
|
||||||
|
static I& derived(iterator_facade<I,V,TC,R,D>& facade)
|
||||||
|
{
|
||||||
|
return *static_cast<I*>(&facade);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class I, class V, class TC, class R, class D>
|
||||||
|
static I const& derived(iterator_facade<I,V,TC,R,D> const& facade)
|
||||||
|
{
|
||||||
|
return *static_cast<I const*>(&facade);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// objects of this class are useless
|
// objects of this class are useless
|
||||||
iterator_core_access(); //undefined
|
iterator_core_access(); //undefined
|
||||||
@ -428,7 +524,7 @@ namespace boost
|
|||||||
typedef detail::iterator_facade_types<
|
typedef detail::iterator_facade_types<
|
||||||
Value, CategoryOrTraversal, Reference, Difference
|
Value, CategoryOrTraversal, Reference, Difference
|
||||||
> associated_types;
|
> associated_types;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
typedef typename associated_types::value_type value_type;
|
typedef typename associated_types::value_type value_type;
|
||||||
@ -456,7 +552,7 @@ namespace boost
|
|||||||
>::make(*this->derived());
|
>::make(*this->derived());
|
||||||
}
|
}
|
||||||
|
|
||||||
typename detail::operator_brackets_result<Derived,Value,Reference>::type
|
typename detail::operator_brackets_result<Derived,Value,reference>::type
|
||||||
operator[](difference_type n) const
|
operator[](difference_type n) const
|
||||||
{
|
{
|
||||||
typedef detail::use_operator_brackets_proxy<Value,Reference> use_proxy;
|
typedef detail::use_operator_brackets_proxy<Value,Reference> use_proxy;
|
||||||
@ -473,13 +569,17 @@ namespace boost
|
|||||||
return this->derived();
|
return this->derived();
|
||||||
}
|
}
|
||||||
|
|
||||||
Derived operator++(int)
|
# if BOOST_WORKAROUND(BOOST_MSVC, == 1200)
|
||||||
|
typename detail::postfix_increment_result<Derived,Value,Reference,CategoryOrTraversal>::type
|
||||||
|
operator++(int)
|
||||||
{
|
{
|
||||||
Derived tmp(this->derived());
|
typename detail::postfix_increment_result<Derived,Value,Reference,CategoryOrTraversal>::type
|
||||||
|
tmp(this->derived());
|
||||||
++*this;
|
++*this;
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
Derived& operator--()
|
Derived& operator--()
|
||||||
{
|
{
|
||||||
iterator_core_access::decrement(this->derived());
|
iterator_core_access::decrement(this->derived());
|
||||||
@ -524,8 +624,26 @@ namespace boost
|
|||||||
# endif
|
# endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# if !BOOST_WORKAROUND(BOOST_MSVC, == 1200)
|
||||||
|
template <class I, class V, class TC, class R, class D>
|
||||||
|
typename detail::postfix_increment_result<I,V,R,TC>::type
|
||||||
|
operator++(
|
||||||
|
iterator_facade<I,V,TC,R,D>& i
|
||||||
|
, int
|
||||||
|
)
|
||||||
|
{
|
||||||
|
typename detail::postfix_increment_result<I,V,R,TC>::type
|
||||||
|
tmp(*static_cast<I*>(&i));
|
||||||
|
|
||||||
|
++i;
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Operator implementation. The library supplied operators
|
// Comparison operator implementation. The library supplied operators
|
||||||
// enables the user to provide fully interoperable constant/mutable
|
// enables the user to provide fully interoperable constant/mutable
|
||||||
// iterator types. I.e. the library provides all operators
|
// iterator types. I.e. the library provides all operators
|
||||||
// for all mutable/constant iterator combinations.
|
// for all mutable/constant iterator combinations.
|
||||||
|
@ -28,9 +28,20 @@
|
|||||||
# include <boost/iterator/is_lvalue_iterator.hpp>
|
# include <boost/iterator/is_lvalue_iterator.hpp>
|
||||||
|
|
||||||
# include <boost/iterator/detail/config_def.hpp>
|
# include <boost/iterator/detail/config_def.hpp>
|
||||||
|
# include <boost/detail/is_incrementable.hpp>
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
|
|
||||||
|
template <class Iterator, class T>
|
||||||
|
void readable_iterator_test_aux(Iterator i1, T v, mpl::true_)
|
||||||
|
{
|
||||||
|
assert(v == *i1++);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Iterator, class T>
|
||||||
|
void readable_iterator_test_aux(const Iterator i1, T v, mpl::false_)
|
||||||
|
{}
|
||||||
|
|
||||||
// Preconditions: *i == v
|
// Preconditions: *i == v
|
||||||
template <class Iterator, class T>
|
template <class Iterator, class T>
|
||||||
void readable_iterator_test(const Iterator i1, T v)
|
void readable_iterator_test(const Iterator i1, T v)
|
||||||
@ -45,6 +56,8 @@ void readable_iterator_test(const Iterator i1, T v)
|
|||||||
assert(v2 == v);
|
assert(v2 == v);
|
||||||
|
|
||||||
# if !BOOST_WORKAROUND(__MWERKS__, <= 0x2407)
|
# if !BOOST_WORKAROUND(__MWERKS__, <= 0x2407)
|
||||||
|
readable_iterator_test_aux(i1, v, detail::is_postfix_incrementable<Iterator>());
|
||||||
|
|
||||||
// I think we don't really need this as it checks the same things as
|
// I think we don't really need this as it checks the same things as
|
||||||
// the above code.
|
// the above code.
|
||||||
BOOST_STATIC_ASSERT(is_readable_iterator<Iterator>::value);
|
BOOST_STATIC_ASSERT(is_readable_iterator<Iterator>::value);
|
||||||
|
@ -42,6 +42,7 @@ test-suite iterator
|
|||||||
[ run indirect_iterator_test.cpp ]
|
[ run indirect_iterator_test.cpp ]
|
||||||
[ compile indirect_iterator_member_types.cpp ]
|
[ compile indirect_iterator_member_types.cpp ]
|
||||||
[ run filter_iterator_test.cpp ]
|
[ run filter_iterator_test.cpp ]
|
||||||
|
[ run iterator_facade.cpp ]
|
||||||
[ run reverse_iterator_test.cpp ]
|
[ run reverse_iterator_test.cpp ]
|
||||||
[ run counting_iterator_test.cpp ]
|
[ run counting_iterator_test.cpp ]
|
||||||
[ run interoperable.cpp ]
|
[ run interoperable.cpp ]
|
||||||
|
67
test/iterator_facade.cpp
Executable file
67
test/iterator_facade.cpp
Executable file
@ -0,0 +1,67 @@
|
|||||||
|
// Copyright David Abrahams 2004. 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)
|
||||||
|
|
||||||
|
// This is really an incomplete test; should be fleshed out.
|
||||||
|
|
||||||
|
#include <boost/iterator/iterator_facade.hpp>
|
||||||
|
#include <boost/iterator/new_iterator_tests.hpp>
|
||||||
|
|
||||||
|
// This is a really, really limited test so far. All we're doing
|
||||||
|
// right now is checking that the postfix++ proxy for single-pass
|
||||||
|
// iterators works properly.
|
||||||
|
template <class Ref>
|
||||||
|
class counter_iterator
|
||||||
|
: public boost::iterator_facade<
|
||||||
|
counter_iterator<Ref>
|
||||||
|
, int const
|
||||||
|
, boost::single_pass_traversal_tag
|
||||||
|
, Ref
|
||||||
|
>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
counter_iterator() {}
|
||||||
|
counter_iterator(int* state) : state(state) {}
|
||||||
|
|
||||||
|
void increment()
|
||||||
|
{
|
||||||
|
++*state;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref
|
||||||
|
dereference() const
|
||||||
|
{
|
||||||
|
return *state;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool equal(counter_iterator const& y) const
|
||||||
|
{
|
||||||
|
return *this->state == *y.state;
|
||||||
|
}
|
||||||
|
|
||||||
|
int* state;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct proxy
|
||||||
|
{
|
||||||
|
proxy(int& x) : state(x) {}
|
||||||
|
|
||||||
|
operator int const&() const
|
||||||
|
{
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
int& operator=(int x) { state = x; return state; }
|
||||||
|
|
||||||
|
int& state;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int state = 0;
|
||||||
|
boost::readable_iterator_test(counter_iterator<int const&>(&state), 0);
|
||||||
|
state = 3;
|
||||||
|
boost::readable_iterator_test(counter_iterator<proxy>(&state), 3);
|
||||||
|
boost::writable_iterator_test(counter_iterator<proxy>(&state), 9);
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user