mirror of
https://github.com/boostorg/iterator.git
synced 2025-05-12 14:01:37 +00:00
initial commit
[SVN r19978]
This commit is contained in:
parent
3f49409843
commit
2c89e2b15a
680
include/boost/iterator/zip_iterator.hpp
Executable file
680
include/boost/iterator/zip_iterator.hpp
Executable file
@ -0,0 +1,680 @@
|
|||||||
|
// (C) Copyright David Abrahams and Thomas Becker 2000. Permission to
|
||||||
|
// copy, use, modify, sell and distribute this software is granted
|
||||||
|
// provided this copyright notice appears in all copies. This software
|
||||||
|
// is provided "as is" without express or implied warranty, and with
|
||||||
|
// no claim as to its suitability for any purpose.
|
||||||
|
//
|
||||||
|
// Compilers Tested:
|
||||||
|
// =================
|
||||||
|
// Metrowerks Codewarrior Pro 7.2, 8.3
|
||||||
|
// gcc 2.95.3
|
||||||
|
// gcc 3.2
|
||||||
|
// Microsoft VC 6sp5 (test fails due to some compiler bug)
|
||||||
|
// Microsoft VC 7 (works)
|
||||||
|
// Microsoft VC 7.1
|
||||||
|
// Intel 5
|
||||||
|
// Intel 6
|
||||||
|
// Intel 7.1
|
||||||
|
// Intel 8
|
||||||
|
// Borland 5.5.1 (broken due to lack of support from Boost.Tuples)
|
||||||
|
|
||||||
|
#ifndef BOOST_ZIP_ITERATOR_TMB_07_13_2003_HPP_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <boost/iterator.hpp>
|
||||||
|
#include <boost/iterator/iterator_traits.hpp>
|
||||||
|
#include <boost/iterator/iterator_facade.hpp>
|
||||||
|
#include <boost/iterator/iterator_adaptor.hpp> // for enable_if_convertible
|
||||||
|
#include <boost/iterator/iterator_categories.hpp>
|
||||||
|
|
||||||
|
#include <boost/tuple/tuple.hpp>
|
||||||
|
|
||||||
|
#if BOOST_WORKAROUND(__GNUC__, == 2) || BOOST_WORKAROUND(__MWERKS__, <= 0x2407)
|
||||||
|
# include <boost/type_traits/remove_cv.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/type_traits/is_same.hpp>
|
||||||
|
#include <boost/mpl/and.hpp>
|
||||||
|
#include <boost/mpl/apply.hpp>
|
||||||
|
#include <boost/mpl/apply_if.hpp>
|
||||||
|
#include <boost/mpl/lambda.hpp>
|
||||||
|
#include <boost/mpl/placeholders.hpp>
|
||||||
|
#include <boost/mpl/aux_/lambda_support.hpp>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
// Zip iterator forward declaration for zip_iterator_base
|
||||||
|
template<typename IteratorTuple>
|
||||||
|
class zip_iterator;
|
||||||
|
|
||||||
|
// One important design goal of the zip_iterator is to isolate all
|
||||||
|
// functionality whose implementation relies on the current tuple
|
||||||
|
// implementation. This goal has been achieved as follows: Inside
|
||||||
|
// the namespace detail there is a namespace tuple_impl_specific.
|
||||||
|
// This namespace encapsulates all functionality that is specific
|
||||||
|
// to the current Boost tuple implementation. More precisely, the
|
||||||
|
// namespace tuple_impl_specific provides the following tuple
|
||||||
|
// algorithms and meta-algorithms for the current Boost tuple
|
||||||
|
// implementation:
|
||||||
|
//
|
||||||
|
// tuple_meta_transform
|
||||||
|
// tuple_meta_accumulate
|
||||||
|
// tuple_transform
|
||||||
|
// tuple_for_each
|
||||||
|
//
|
||||||
|
// If the tuple implementation changes, all that needs to be
|
||||||
|
// replaced is the implementation of these four (meta-)algorithms.
|
||||||
|
//
|
||||||
|
// Unfortunately, some compilers, including Metrowerks Codewarrior
|
||||||
|
// 4.2.5.766 and gcc 3.3, were unable to handle the template
|
||||||
|
// code involved (Metrowerks: internal compiler error, gcc 3.3:
|
||||||
|
// segmentation fault). Therefore, rather regrettably, for those
|
||||||
|
// compilers, the encapsulation of the tuple implementation-
|
||||||
|
// specific code is not nearly as nice and clean as it should be.
|
||||||
|
// In order to emphasize this point, I have provided the entire
|
||||||
|
// namespace detail in this file twice: the first version is the
|
||||||
|
// clean one with the nice encapsulation, the second one is the
|
||||||
|
// dirty one.
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
// Functors to be used with tuple algorithms
|
||||||
|
//
|
||||||
|
template<typename DiffType>
|
||||||
|
class advance_iterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
advance_iterator(DiffType step) : m_step(step) {}
|
||||||
|
|
||||||
|
template<typename Iterator>
|
||||||
|
void operator()(Iterator& it) const
|
||||||
|
{ it += m_step; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
DiffType m_step;
|
||||||
|
};
|
||||||
|
//
|
||||||
|
struct increment_iterator
|
||||||
|
{
|
||||||
|
template<typename Iterator>
|
||||||
|
void operator()(Iterator& it)
|
||||||
|
{ ++it; }
|
||||||
|
};
|
||||||
|
//
|
||||||
|
struct decrement_iterator
|
||||||
|
{
|
||||||
|
template<typename Iterator>
|
||||||
|
void operator()(Iterator& it)
|
||||||
|
{ --it; }
|
||||||
|
};
|
||||||
|
//
|
||||||
|
struct dereference_iterator
|
||||||
|
{
|
||||||
|
template<typename Iterator>
|
||||||
|
struct apply
|
||||||
|
{
|
||||||
|
#if BOOST_WORKAROUND(__GNUC__, == 2) || BOOST_WORKAROUND(__MWERKS__, <= 0x2407)
|
||||||
|
typedef typename
|
||||||
|
std::iterator_traits<
|
||||||
|
typename boost::remove_cv<Iterator>::type
|
||||||
|
>::reference
|
||||||
|
type;
|
||||||
|
#else
|
||||||
|
typedef typename
|
||||||
|
std::iterator_traits<Iterator>::reference
|
||||||
|
type;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Iterator>
|
||||||
|
typename apply<Iterator>::type operator()(Iterator& it)
|
||||||
|
{ return *it; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// The namespace tuple_impl_specific provides two meta-
|
||||||
|
// algorithms and two algorithms for tuples.
|
||||||
|
//
|
||||||
|
namespace tuple_impl_specific
|
||||||
|
{
|
||||||
|
// Meta-transform algorithm for tuples
|
||||||
|
//
|
||||||
|
template<typename Tuple, class UnaryMetaFun>
|
||||||
|
struct tuple_meta_transform;
|
||||||
|
|
||||||
|
template<typename Tuple, class UnaryMetaFun>
|
||||||
|
struct tuple_meta_transform_impl
|
||||||
|
{
|
||||||
|
typedef tuples::cons<
|
||||||
|
typename mpl::apply1<
|
||||||
|
typename mpl::lambda<UnaryMetaFun>::type
|
||||||
|
, typename Tuple::head_type
|
||||||
|
>::type
|
||||||
|
, typename tuple_meta_transform<
|
||||||
|
typename Tuple::tail_type
|
||||||
|
, UnaryMetaFun
|
||||||
|
>::type
|
||||||
|
> type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Tuple, class UnaryMetaFun>
|
||||||
|
struct tuple_meta_transform
|
||||||
|
: mpl::apply_if<
|
||||||
|
boost::is_same<Tuple, tuples::null_type>
|
||||||
|
, mpl::identity<tuples::null_type>
|
||||||
|
, tuple_meta_transform_impl<Tuple, UnaryMetaFun>
|
||||||
|
>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
// Meta-accumulate algorithm for tuples. Note: The template
|
||||||
|
// parameter StartType corresponds to the initial value in
|
||||||
|
// ordinary accumulation.
|
||||||
|
//
|
||||||
|
template<class Tuple, class BinaryMetaFun, class StartType>
|
||||||
|
struct tuple_meta_accumulate;
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename Tuple
|
||||||
|
, class BinaryMetaFun
|
||||||
|
, typename StartType
|
||||||
|
>
|
||||||
|
struct tuple_meta_accumulate_impl
|
||||||
|
{
|
||||||
|
typedef typename mpl::apply2<
|
||||||
|
typename mpl::lambda<BinaryMetaFun>::type
|
||||||
|
, typename Tuple::head_type
|
||||||
|
, typename tuple_meta_accumulate<
|
||||||
|
typename Tuple::tail_type
|
||||||
|
, BinaryMetaFun
|
||||||
|
, StartType
|
||||||
|
>::type
|
||||||
|
>::type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename Tuple
|
||||||
|
, class BinaryMetaFun
|
||||||
|
, typename StartType
|
||||||
|
>
|
||||||
|
struct tuple_meta_accumulate
|
||||||
|
: mpl::apply_if<
|
||||||
|
#if BOOST_WORKAROUND(BOOST_MSVC, == 1200)
|
||||||
|
mpl::or_<
|
||||||
|
#endif
|
||||||
|
boost::is_same<Tuple, tuples::null_type>
|
||||||
|
#if BOOST_WORKAROUND(BOOST_MSVC, == 1200)
|
||||||
|
, boost::is_same<Tuple,int>
|
||||||
|
>
|
||||||
|
#endif
|
||||||
|
, mpl::identity<StartType>
|
||||||
|
, tuple_meta_accumulate_impl<
|
||||||
|
Tuple
|
||||||
|
, BinaryMetaFun
|
||||||
|
, StartType
|
||||||
|
>
|
||||||
|
>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \
|
||||||
|
|| ( \
|
||||||
|
BOOST_WORKAROUND(BOOST_INTEL_CXX_VERSION, != 0) && defined(_MSC_VER) \
|
||||||
|
)
|
||||||
|
// Not sure why intel's partial ordering fails in this case, but I'm
|
||||||
|
// assuming int's an MSVC bug-compatibility feature.
|
||||||
|
|
||||||
|
# define BOOST_TUPLE_ALGO_DISPATCH
|
||||||
|
# define BOOST_TUPLE_ALGO(algo) algo##_impl
|
||||||
|
# define BOOST_TUPLE_ALGO_TERMINATOR , int
|
||||||
|
# define BOOST_TUPLE_ALGO_RECURSE , ...
|
||||||
|
#else
|
||||||
|
# define BOOST_TUPLE_ALGO(algo) algo
|
||||||
|
# define BOOST_TUPLE_ALGO_TERMINATOR
|
||||||
|
# define BOOST_TUPLE_ALGO_RECURSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// transform algorithm for tuples. The template parameter Fun
|
||||||
|
// must be a unary functor which is also a unary metafunction
|
||||||
|
// class that computes its return type based on its argument
|
||||||
|
// type. For example:
|
||||||
|
//
|
||||||
|
// struct to_ptr
|
||||||
|
// {
|
||||||
|
// template <class Arg>
|
||||||
|
// struct apply
|
||||||
|
// {
|
||||||
|
// typedef Arg* type;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// template <class Arg>
|
||||||
|
// Arg* operator()(Arg x);
|
||||||
|
// };
|
||||||
|
template<typename Fun>
|
||||||
|
tuples::null_type BOOST_TUPLE_ALGO(tuple_transform)
|
||||||
|
(tuples::null_type const&, Fun BOOST_TUPLE_ALGO_TERMINATOR)
|
||||||
|
{ return tuples::null_type(); }
|
||||||
|
|
||||||
|
template<typename Tuple, typename Fun>
|
||||||
|
typename tuple_meta_transform<
|
||||||
|
Tuple
|
||||||
|
, Fun
|
||||||
|
>::type
|
||||||
|
|
||||||
|
BOOST_TUPLE_ALGO(tuple_transform)(
|
||||||
|
const Tuple& t,
|
||||||
|
Fun f
|
||||||
|
BOOST_TUPLE_ALGO_RECURSE
|
||||||
|
)
|
||||||
|
{
|
||||||
|
typedef typename tuple_meta_transform<
|
||||||
|
typename Tuple::tail_type
|
||||||
|
, Fun
|
||||||
|
>::type transformed_tail_type;
|
||||||
|
|
||||||
|
return tuples::cons<
|
||||||
|
typename mpl::apply1<Fun, typename Tuple::head_type>::type
|
||||||
|
, transformed_tail_type
|
||||||
|
>(
|
||||||
|
f(boost::tuples::get<0>(t)),
|
||||||
|
tuple_transform(t.get_tail(), f)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef BOOST_TUPLE_ALGO_DISPATCH
|
||||||
|
template<typename Tuple, typename Fun>
|
||||||
|
typename tuple_meta_transform<
|
||||||
|
Tuple
|
||||||
|
, Fun
|
||||||
|
>::type
|
||||||
|
|
||||||
|
tuple_transform(
|
||||||
|
const Tuple& t,
|
||||||
|
Fun f
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return tuple_transform_impl(t, f, 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// for_each algorithm for tuples.
|
||||||
|
//
|
||||||
|
template<typename Fun>
|
||||||
|
Fun BOOST_TUPLE_ALGO(tuple_for_each)(
|
||||||
|
tuples::null_type
|
||||||
|
, Fun f BOOST_TUPLE_ALGO_TERMINATOR
|
||||||
|
)
|
||||||
|
{ return f; }
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Tuple, typename Fun>
|
||||||
|
Fun BOOST_TUPLE_ALGO(tuple_for_each)(
|
||||||
|
Tuple& t
|
||||||
|
, Fun f BOOST_TUPLE_ALGO_RECURSE)
|
||||||
|
{
|
||||||
|
f( t.get_head() );
|
||||||
|
return tuple_for_each(t.get_tail(), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef BOOST_TUPLE_ALGO_DISPATCH
|
||||||
|
template<typename Tuple, typename Fun>
|
||||||
|
Fun
|
||||||
|
tuple_for_each(
|
||||||
|
Tuple& t,
|
||||||
|
Fun f
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return tuple_for_each_impl(t, f, 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Equality of tuples. NOTE: "==" for tuples currently (7/2003)
|
||||||
|
// has problems under some compilers, so I just do my own.
|
||||||
|
// No point in bringing in a bunch of #ifdefs here. This is
|
||||||
|
// going to go away with the next tuple implementation anyway.
|
||||||
|
//
|
||||||
|
bool tuple_equal(tuples::null_type, tuples::null_type)
|
||||||
|
{ return true; }
|
||||||
|
|
||||||
|
template<typename Tuple1, typename Tuple2>
|
||||||
|
bool tuple_equal(
|
||||||
|
Tuple1 const& t1,
|
||||||
|
Tuple2 const& t2
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return t1.get_head() == t2.get_head() &&
|
||||||
|
tuple_equal(t1.get_tail(), t2.get_tail());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// end namespace tuple_impl_specific
|
||||||
|
|
||||||
|
template<typename Iterator>
|
||||||
|
struct iterator_reference
|
||||||
|
{
|
||||||
|
typedef typename iterator_traits<Iterator>::reference type;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef BOOST_MPL_NO_FULL_LAMBDA_SUPPORT
|
||||||
|
// Hack because BOOST_MPL_AUX_LAMBDA_SUPPORT doesn't seem to work
|
||||||
|
// out well. Instantiating the nested apply template also
|
||||||
|
// requires instantiating iterator_traits on the
|
||||||
|
// placeholder. Instead we just specialize it as a metafunction
|
||||||
|
// class.
|
||||||
|
template<>
|
||||||
|
struct iterator_reference<mpl::_1>
|
||||||
|
{
|
||||||
|
template <class T>
|
||||||
|
struct apply : iterator_reference<T> {};
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Metafunction to obtain the type of the tuple whose element types
|
||||||
|
// are the reference types of an iterator tuple.
|
||||||
|
//
|
||||||
|
template<typename IteratorTuple>
|
||||||
|
struct tuple_of_references
|
||||||
|
: tuple_impl_specific::tuple_meta_transform<
|
||||||
|
IteratorTuple,
|
||||||
|
iterator_reference<mpl::_1>
|
||||||
|
>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
// Metafunction to obtain the minimal traversal tag in a tuple
|
||||||
|
// of iterators.
|
||||||
|
//
|
||||||
|
template<typename IteratorTuple>
|
||||||
|
struct minimum_traversal_category_in_iterator_tuple
|
||||||
|
{
|
||||||
|
typedef typename tuple_impl_specific::tuple_meta_transform<
|
||||||
|
IteratorTuple
|
||||||
|
, traversal_category<mpl::_1>
|
||||||
|
>::type tuple_of_traversal_tags;
|
||||||
|
|
||||||
|
typedef typename tuple_impl_specific::tuple_meta_accumulate<
|
||||||
|
tuple_of_traversal_tags
|
||||||
|
, minimum_category<mpl::_1,mpl::_2>
|
||||||
|
, random_access_traversal_tag
|
||||||
|
>::type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if BOOST_WORKAROUND(BOOST_MSVC, == 1200) // ETI workaround
|
||||||
|
template <>
|
||||||
|
struct minimum_traversal_category_in_iterator_tuple<int>
|
||||||
|
{
|
||||||
|
typedef int type;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<typename Iterator>
|
||||||
|
struct iterator_is_readable
|
||||||
|
: is_tag<
|
||||||
|
readable_iterator_tag
|
||||||
|
, typename access_category<Iterator>::type
|
||||||
|
>
|
||||||
|
{
|
||||||
|
BOOST_MPL_AUX_LAMBDA_SUPPORT(1, iterator_is_readable, (Iterator))
|
||||||
|
};
|
||||||
|
|
||||||
|
# ifdef BOOST_MPL_NO_FULL_LAMBDA_SUPPORT
|
||||||
|
// Hack because BOOST_MPL_AUX_LAMBDA_SUPPORT doesn't seem to work
|
||||||
|
// out well. Instantiating the nested apply template also
|
||||||
|
// requires instantiating iterator_traits on the
|
||||||
|
// placeholder. Instead we just specialize it as a metafunction
|
||||||
|
// class.
|
||||||
|
template <>
|
||||||
|
struct iterator_is_readable<mpl::_1>
|
||||||
|
{
|
||||||
|
template <class T>
|
||||||
|
struct apply : iterator_is_readable<T>
|
||||||
|
{};
|
||||||
|
};
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// We need to call tuple_meta_accumulate with mpl::and_ as the
|
||||||
|
// accumulating functor. To this end, we need to wrap it into
|
||||||
|
// a struct that has exactly two arguments (that is, template
|
||||||
|
// parameters) and not five, like mpl::and_ does.
|
||||||
|
//
|
||||||
|
template<typename Arg1, typename Arg2>
|
||||||
|
struct and_with_two_args
|
||||||
|
: mpl::and_<Arg1, Arg2>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
# ifdef BOOST_MPL_NO_FULL_LAMBDA_SUPPORT
|
||||||
|
// Hack because BOOST_MPL_AUX_LAMBDA_SUPPORT doesn't seem to work
|
||||||
|
// out well. In this case I think it's an MPL bug
|
||||||
|
template<>
|
||||||
|
struct and_with_two_args<mpl::_1,mpl::_2>
|
||||||
|
{
|
||||||
|
template <class A1, class A2>
|
||||||
|
struct apply : mpl::and_<A1,A2>
|
||||||
|
{};
|
||||||
|
};
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// Metafunction to assert that all iterators in a tuple are
|
||||||
|
// readable.
|
||||||
|
//
|
||||||
|
// Probably not worth it, IMO. Why not a writable zip_iterator
|
||||||
|
// anyway? -- dwa.
|
||||||
|
//
|
||||||
|
template<typename IteratorTuple>
|
||||||
|
struct all_iterators_in_tuple_readable
|
||||||
|
{
|
||||||
|
|
||||||
|
typedef typename tuple_impl_specific::tuple_meta_transform<
|
||||||
|
IteratorTuple,
|
||||||
|
iterator_is_readable<mpl::_1>
|
||||||
|
>::type tuple_of_readability_bools;
|
||||||
|
|
||||||
|
typedef typename tuple_impl_specific::tuple_meta_accumulate<
|
||||||
|
tuple_of_readability_bools,
|
||||||
|
and_with_two_args<mpl::_1,mpl::_2>
|
||||||
|
, mpl::bool_<true>
|
||||||
|
>::type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Class zip_iterator_base
|
||||||
|
//
|
||||||
|
// Builds and exposes the iterator facade type from which the zip
|
||||||
|
// iterator will be derived.
|
||||||
|
//
|
||||||
|
template<typename IteratorTuple>
|
||||||
|
struct zip_iterator_base
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
#if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
|
||||||
|
// seems to give vc7's parser fits, and vc6 needs help here too
|
||||||
|
BOOST_STATIC_ASSERT(
|
||||||
|
detail::all_iterators_in_tuple_readable<
|
||||||
|
IteratorTuple
|
||||||
|
>::type::value
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
// Reference type is the type of the tuple obtained from the
|
||||||
|
// iterators' reference types.
|
||||||
|
typedef typename
|
||||||
|
detail::tuple_of_references<IteratorTuple>::type reference;
|
||||||
|
|
||||||
|
// Value type is the same as reference type.
|
||||||
|
typedef reference value_type;
|
||||||
|
|
||||||
|
// Difference type is the first iterator's difference type
|
||||||
|
typedef typename iterator_traits<
|
||||||
|
typename tuples::element<0, IteratorTuple>::type
|
||||||
|
>::difference_type difference_type;
|
||||||
|
|
||||||
|
// Traversal catetgory is the minimum traversal category in the
|
||||||
|
// iterator tuple.
|
||||||
|
typedef typename
|
||||||
|
detail::minimum_traversal_category_in_iterator_tuple<
|
||||||
|
IteratorTuple
|
||||||
|
>::type traversal_category;
|
||||||
|
|
||||||
|
// Access category is readable_iterator_tag. It has been
|
||||||
|
// asserted that all iterators in the tuple are readable.
|
||||||
|
typedef readable_iterator_tag access_category;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// The iterator facade type from which the zip iterator will
|
||||||
|
// be derived.
|
||||||
|
typedef iterator_facade<
|
||||||
|
zip_iterator<IteratorTuple>,
|
||||||
|
value_type,
|
||||||
|
access_category,
|
||||||
|
traversal_category,
|
||||||
|
reference,
|
||||||
|
difference_type
|
||||||
|
> type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct zip_iterator_base<int>
|
||||||
|
{
|
||||||
|
typedef int type;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// zip_iterator class definition
|
||||||
|
//
|
||||||
|
template<typename IteratorTuple>
|
||||||
|
class zip_iterator :
|
||||||
|
public detail::zip_iterator_base<IteratorTuple>::type
|
||||||
|
{
|
||||||
|
|
||||||
|
// Typedef super_t as our base class.
|
||||||
|
typedef typename
|
||||||
|
detail::zip_iterator_base<IteratorTuple>::type super_t;
|
||||||
|
|
||||||
|
// iterator_core_access is the iterator's best friend.
|
||||||
|
friend class iterator_core_access;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Construction
|
||||||
|
// ============
|
||||||
|
|
||||||
|
// Default constructor
|
||||||
|
zip_iterator() { }
|
||||||
|
|
||||||
|
// Constructor from iterator tuple
|
||||||
|
zip_iterator(IteratorTuple iterator_tuple)
|
||||||
|
: m_iterator_tuple(iterator_tuple)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
// Copy constructor
|
||||||
|
template<typename OtherIteratorTuple>
|
||||||
|
zip_iterator(
|
||||||
|
const zip_iterator<OtherIteratorTuple>& other,
|
||||||
|
typename enable_if_convertible<
|
||||||
|
OtherIteratorTuple,
|
||||||
|
IteratorTuple
|
||||||
|
>::type* = 0
|
||||||
|
) : m_iterator_tuple(other.get_iterator_tuple())
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Get method for the iterator tuple.
|
||||||
|
const IteratorTuple& get_iterator_tuple() const
|
||||||
|
{ return m_iterator_tuple; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// Implementation of Iterator Operations
|
||||||
|
// =====================================
|
||||||
|
|
||||||
|
// Dereferencing returns a tuple built from the dereferenced
|
||||||
|
// iterators in the iterator tuple.
|
||||||
|
typename super_t::reference dereference() const
|
||||||
|
{
|
||||||
|
return detail::tuple_impl_specific::tuple_transform(
|
||||||
|
get_iterator_tuple(),
|
||||||
|
detail::dereference_iterator()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Two zip iterators are equal if all iterators in the iterator
|
||||||
|
// tuple are equal. NOTE: It should be possible to implement this
|
||||||
|
// as
|
||||||
|
//
|
||||||
|
// return get_iterator_tuple() == other.get_iterator_tuple();
|
||||||
|
//
|
||||||
|
// but equality of tuples currently (7/2003) does not compile
|
||||||
|
// under several compilers. No point in bringing in a bunch
|
||||||
|
// of #ifdefs here.
|
||||||
|
//
|
||||||
|
template<typename OtherIteratorTuple>
|
||||||
|
bool equal(const zip_iterator<OtherIteratorTuple>& other) const
|
||||||
|
{
|
||||||
|
return detail::tuple_impl_specific::tuple_equal(
|
||||||
|
get_iterator_tuple(),
|
||||||
|
other.get_iterator_tuple()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advancing a zip iterator means to advance all iterators in the
|
||||||
|
// iterator tuple.
|
||||||
|
void advance(typename super_t::difference_type n)
|
||||||
|
{
|
||||||
|
detail::tuple_impl_specific::tuple_for_each(
|
||||||
|
m_iterator_tuple,
|
||||||
|
detail::advance_iterator<typename super_t::difference_type>(n)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Incrementing a zip iterator means to increment all iterators in
|
||||||
|
// the iterator tuple.
|
||||||
|
void increment()
|
||||||
|
{
|
||||||
|
detail::tuple_impl_specific::tuple_for_each(
|
||||||
|
m_iterator_tuple,
|
||||||
|
detail::increment_iterator()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrementing a zip iterator means to decrement all iterators in
|
||||||
|
// the iterator tuple.
|
||||||
|
void decrement()
|
||||||
|
{
|
||||||
|
detail::tuple_impl_specific::tuple_for_each(
|
||||||
|
m_iterator_tuple,
|
||||||
|
detail::decrement_iterator()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Distance is calculated using the first iterator in the tuple.
|
||||||
|
template<typename OtherIteratorTuple>
|
||||||
|
typename super_t::difference_type distance_to(
|
||||||
|
const zip_iterator<OtherIteratorTuple>& other
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
return boost::tuples::get<0>(other.get_iterator_tuple()) -
|
||||||
|
boost::tuples::get<0>(this->get_iterator_tuple());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data Members
|
||||||
|
// ============
|
||||||
|
|
||||||
|
// The iterator tuple.
|
||||||
|
IteratorTuple m_iterator_tuple;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Make function for zip iterator
|
||||||
|
//
|
||||||
|
template<typename IteratorTuple>
|
||||||
|
zip_iterator<IteratorTuple>
|
||||||
|
make_zip_iterator(IteratorTuple t)
|
||||||
|
{ return zip_iterator<IteratorTuple>(t); }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
982
test/zip_iterator_test.cpp
Executable file
982
test/zip_iterator_test.cpp
Executable file
@ -0,0 +1,982 @@
|
|||||||
|
// (C) Copyright Dave Abrahams and Thomas Becker 2003. Permission to
|
||||||
|
// copy, use, modify, sell and distribute this software is granted
|
||||||
|
// provided this copyright notice appears in all copies. This software
|
||||||
|
// is provided "as is" without express or implied warranty, and with
|
||||||
|
// no claim as to its suitability for any purpose.
|
||||||
|
//
|
||||||
|
|
||||||
|
// File:
|
||||||
|
// =====
|
||||||
|
// zip_iterator_test_main.cpp
|
||||||
|
|
||||||
|
// Author:
|
||||||
|
// =======
|
||||||
|
// Thomas Becker
|
||||||
|
|
||||||
|
// Created:
|
||||||
|
// ========
|
||||||
|
// Jul 15, 2003
|
||||||
|
|
||||||
|
// Purpose:
|
||||||
|
// ========
|
||||||
|
// Test driver for zip_iterator.hpp
|
||||||
|
|
||||||
|
// Compilers Tested:
|
||||||
|
// =================
|
||||||
|
// Metrowerks Codewarrior Pro 7.2, 8.3
|
||||||
|
// gcc 2.95.3
|
||||||
|
// gcc 3.2
|
||||||
|
// Microsoft VC 6sp5 (test fails due to some compiler bug)
|
||||||
|
// Microsoft VC 7 (works)
|
||||||
|
// Microsoft VC 7.1
|
||||||
|
// Intel 5
|
||||||
|
// Intel 6
|
||||||
|
// Intel 7.1
|
||||||
|
// Intel 8
|
||||||
|
// Borland 5.5.1 (broken due to lack of support from Boost.Tuples)
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Includes
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <boost/iterator/zip_iterator.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <list>
|
||||||
|
#include <set>
|
||||||
|
#include <boost/tuple/tuple.hpp>
|
||||||
|
#include <boost/iterator/transform_iterator.hpp>
|
||||||
|
#include <boost/type_traits/is_same.hpp>
|
||||||
|
#include <boost/detail/workaround.hpp>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
// Uncomment to see static assert.
|
||||||
|
// #define PROVOKE_STATIC_ASSERT
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Fake iterator for testing zip iterator categories
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class fake_writable_iterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef int& reference;
|
||||||
|
typedef int value_type;
|
||||||
|
typedef int* pointer;
|
||||||
|
typedef ptrdiff_t difference_type;
|
||||||
|
typedef boost::iterator_tag<
|
||||||
|
boost::writable_iterator_tag,
|
||||||
|
boost::forward_traversal_tag
|
||||||
|
> iterator_category;
|
||||||
|
};
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Das Main Funktion
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int main( void )
|
||||||
|
{
|
||||||
|
|
||||||
|
std::cout << "\n"
|
||||||
|
<< "***********************************************\n"
|
||||||
|
<< "* *\n"
|
||||||
|
<< "* Test driver for boost::zip_iterator *\n"
|
||||||
|
<< "* Copyright Thomas Becker 2003 *\n"
|
||||||
|
<< "* *\n"
|
||||||
|
<< "***********************************************\n\n"
|
||||||
|
<< std::flush;
|
||||||
|
|
||||||
|
size_t num_successful_tests = 0;
|
||||||
|
size_t num_failed_tests = 0;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Make sure tuples are supported
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::cout << "Basic tuple support: "
|
||||||
|
<< std::flush;
|
||||||
|
|
||||||
|
typedef boost::tuples::tuple<int, double> mytuple;
|
||||||
|
mytuple t1;
|
||||||
|
boost::tuples::get<0>(t1) = 42;
|
||||||
|
boost::tuples::get<1>(t1) = 42.1;
|
||||||
|
|
||||||
|
if( 2 == boost::tuples::length<mytuple>::value &&
|
||||||
|
42 == boost::tuples::get<0>(t1) &&
|
||||||
|
42.1 == boost::tuples::get<1>(t1)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
++num_successful_tests;
|
||||||
|
std::cout << "OK" << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++num_failed_tests = 0;
|
||||||
|
std::cout << "not OK" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Make sure iterator adaptor is supported
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::cout << "Basic iterator adaptor support: "
|
||||||
|
<< std::flush;
|
||||||
|
|
||||||
|
std::set<int> s;
|
||||||
|
s.insert(42);
|
||||||
|
s.insert(43);
|
||||||
|
s.insert(44);
|
||||||
|
|
||||||
|
typedef boost::transform_iterator<
|
||||||
|
std::binder1st<std::plus<int> >,
|
||||||
|
std::set<int>::iterator
|
||||||
|
>
|
||||||
|
add_seven_iterator;
|
||||||
|
|
||||||
|
typedef boost::transform_iterator<
|
||||||
|
std::binder1st<std::plus<int> >,
|
||||||
|
std::set<int>::const_iterator
|
||||||
|
>
|
||||||
|
const_add_seven_iterator;
|
||||||
|
|
||||||
|
add_seven_iterator set_run(s.begin(), std::bind1st(std::plus<int>(), 7));
|
||||||
|
add_seven_iterator set_end(s.end(), std::bind1st(std::plus<int>(), 7));
|
||||||
|
|
||||||
|
const_add_seven_iterator const_set_run(s.begin(), std::bind1st(std::plus<int>(), 7));
|
||||||
|
// set_run = const_set_run; // Error: can't convert from const to non-const
|
||||||
|
const_set_run = set_run;
|
||||||
|
|
||||||
|
if( 49 == *set_run &&
|
||||||
|
50 == *++set_run &&
|
||||||
|
51 == *++set_run &&
|
||||||
|
set_end == ++set_run &&
|
||||||
|
49 == *const_set_run &&
|
||||||
|
50 == *++const_set_run &&
|
||||||
|
51 == *++const_set_run &&
|
||||||
|
set_end == ++const_set_run
|
||||||
|
)
|
||||||
|
{
|
||||||
|
++num_successful_tests;
|
||||||
|
std::cout << "OK" << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++num_failed_tests = 0;
|
||||||
|
std::cout << "not OK" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Zip iterator construction and dereferencing
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::cout << "Zip iterator construction and dereferencing: "
|
||||||
|
<< std::flush;
|
||||||
|
|
||||||
|
std::vector<double> vect1(3);
|
||||||
|
vect1[0] = 42.;
|
||||||
|
vect1[1] = 43.;
|
||||||
|
vect1[2] = 44.;
|
||||||
|
|
||||||
|
std::set<int> intset;
|
||||||
|
intset.insert(52);
|
||||||
|
intset.insert(53);
|
||||||
|
intset.insert(54);
|
||||||
|
//
|
||||||
|
|
||||||
|
boost::zip_iterator<
|
||||||
|
boost::tuples::tuple<
|
||||||
|
std::set<int>::iterator
|
||||||
|
, std::vector<double>::iterator
|
||||||
|
>
|
||||||
|
>
|
||||||
|
zip_it_mixed(
|
||||||
|
boost::make_tuple(
|
||||||
|
intset.begin()
|
||||||
|
, vect1.begin()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
boost::tuples::tuple<int, double> val_tuple(
|
||||||
|
*zip_it_mixed);
|
||||||
|
|
||||||
|
boost::tuples::tuple<const int&, double&> ref_tuple(
|
||||||
|
*zip_it_mixed);
|
||||||
|
|
||||||
|
double dblOldVal = boost::tuples::get<1>(ref_tuple);
|
||||||
|
boost::tuples::get<1>(ref_tuple) -= 41.;
|
||||||
|
|
||||||
|
if( 52 == boost::tuples::get<0>(val_tuple) &&
|
||||||
|
42. == boost::tuples::get<1>(val_tuple) &&
|
||||||
|
52 == boost::tuples::get<0>(ref_tuple) &&
|
||||||
|
1. == boost::tuples::get<1>(ref_tuple) &&
|
||||||
|
1. == *vect1.begin()
|
||||||
|
)
|
||||||
|
{
|
||||||
|
++num_successful_tests;
|
||||||
|
std::cout << "OK" << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++num_failed_tests = 0;
|
||||||
|
std::cout << "not OK" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Undo change to vect1
|
||||||
|
boost::tuples::get<1>(ref_tuple) = dblOldVal;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Zip iterator with 12 components
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::cout << "Zip iterators with 12 components: "
|
||||||
|
<< std::flush;
|
||||||
|
|
||||||
|
// Declare 12 containers
|
||||||
|
//
|
||||||
|
std::list<int> li1;
|
||||||
|
li1.push_back(1);
|
||||||
|
std::set<int> se1;
|
||||||
|
se1.insert(2);
|
||||||
|
std::vector<int> ve1;
|
||||||
|
ve1.push_back(3);
|
||||||
|
//
|
||||||
|
std::list<int> li2;
|
||||||
|
li2.push_back(4);
|
||||||
|
std::set<int> se2;
|
||||||
|
se2.insert(5);
|
||||||
|
std::vector<int> ve2;
|
||||||
|
ve2.push_back(6);
|
||||||
|
//
|
||||||
|
std::list<int> li3;
|
||||||
|
li3.push_back(7);
|
||||||
|
std::set<int> se3;
|
||||||
|
se3.insert(8);
|
||||||
|
std::vector<int> ve3;
|
||||||
|
ve3.push_back(9);
|
||||||
|
//
|
||||||
|
std::list<int> li4;
|
||||||
|
li4.push_back(10);
|
||||||
|
std::set<int> se4;
|
||||||
|
se4.insert(11);
|
||||||
|
std::vector<int> ve4;
|
||||||
|
ve4.push_back(12);
|
||||||
|
|
||||||
|
// typedefs for cons lists of iterators.
|
||||||
|
typedef boost::tuples::cons<
|
||||||
|
std::set<int>::iterator,
|
||||||
|
boost::tuples::tuple<
|
||||||
|
std::vector<int>::iterator,
|
||||||
|
std::list<int>::iterator,
|
||||||
|
std::set<int>::iterator,
|
||||||
|
std::vector<int>::iterator,
|
||||||
|
std::list<int>::iterator,
|
||||||
|
std::set<int>::iterator,
|
||||||
|
std::vector<int>::iterator,
|
||||||
|
std::list<int>::iterator,
|
||||||
|
std::set<int>::iterator,
|
||||||
|
std::vector<int>::const_iterator
|
||||||
|
>::inherited
|
||||||
|
> cons_11_its_type;
|
||||||
|
//
|
||||||
|
typedef boost::tuples::cons<
|
||||||
|
std::list<int>::const_iterator,
|
||||||
|
cons_11_its_type
|
||||||
|
> cons_12_its_type;
|
||||||
|
|
||||||
|
// typedefs for cons lists for dereferencing the zip iterator
|
||||||
|
// made from the cons list above.
|
||||||
|
typedef boost::tuples::cons<
|
||||||
|
const int&,
|
||||||
|
boost::tuples::tuple<
|
||||||
|
int&,
|
||||||
|
int&,
|
||||||
|
const int&,
|
||||||
|
int&,
|
||||||
|
int&,
|
||||||
|
const int&,
|
||||||
|
int&,
|
||||||
|
int&,
|
||||||
|
const int&,
|
||||||
|
const int&
|
||||||
|
>::inherited
|
||||||
|
> cons_11_refs_type;
|
||||||
|
//
|
||||||
|
typedef boost::tuples::cons<
|
||||||
|
const int&,
|
||||||
|
cons_11_refs_type
|
||||||
|
> cons_12_refs_type;
|
||||||
|
|
||||||
|
// typedef for zip iterator with 12 elements
|
||||||
|
typedef boost::zip_iterator<cons_12_its_type> zip_it_12_type;
|
||||||
|
|
||||||
|
// Declare a 12-element zip iterator.
|
||||||
|
zip_it_12_type zip_it_12(
|
||||||
|
cons_12_its_type(
|
||||||
|
li1.begin(),
|
||||||
|
cons_11_its_type(
|
||||||
|
se1.begin(),
|
||||||
|
boost::make_tuple(
|
||||||
|
ve1.begin(),
|
||||||
|
li2.begin(),
|
||||||
|
se2.begin(),
|
||||||
|
ve2.begin(),
|
||||||
|
li3.begin(),
|
||||||
|
se3.begin(),
|
||||||
|
ve3.begin(),
|
||||||
|
li4.begin(),
|
||||||
|
se4.begin(),
|
||||||
|
ve4.begin()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Dereference, mess with the result a little.
|
||||||
|
cons_12_refs_type zip_it_12_dereferenced(*zip_it_12);
|
||||||
|
boost::tuples::get<9>(zip_it_12_dereferenced) = 42;
|
||||||
|
|
||||||
|
// Make a copy and move it a little to force some instantiations.
|
||||||
|
zip_it_12_type zip_it_12_copy(zip_it_12);
|
||||||
|
++zip_it_12_copy;
|
||||||
|
|
||||||
|
if( boost::tuples::get<11>(zip_it_12.get_iterator_tuple()) == ve4.begin() &&
|
||||||
|
boost::tuples::get<11>(zip_it_12_copy.get_iterator_tuple()) == ve4.end() &&
|
||||||
|
1 == boost::tuples::get<0>(zip_it_12_dereferenced) &&
|
||||||
|
12 == boost::tuples::get<11>(zip_it_12_dereferenced) &&
|
||||||
|
42 == *(li4.begin())
|
||||||
|
)
|
||||||
|
{
|
||||||
|
++num_successful_tests;
|
||||||
|
std::cout << "OK" << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++num_failed_tests = 0;
|
||||||
|
std::cout << "not OK" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Zip iterator incrementing and dereferencing
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::cout << "Zip iterator ++ and *: "
|
||||||
|
<< std::flush;
|
||||||
|
|
||||||
|
std::vector<double> vect2(3);
|
||||||
|
vect2[0] = 2.2;
|
||||||
|
vect2[1] = 3.3;
|
||||||
|
vect2[2] = 4.4;
|
||||||
|
|
||||||
|
boost::zip_iterator<
|
||||||
|
boost::tuples::tuple<
|
||||||
|
std::vector<double>::const_iterator,
|
||||||
|
std::vector<double>::const_iterator
|
||||||
|
>
|
||||||
|
>
|
||||||
|
zip_it_begin(
|
||||||
|
boost::make_tuple(
|
||||||
|
vect1.begin(),
|
||||||
|
vect2.begin()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
boost::zip_iterator<
|
||||||
|
boost::tuples::tuple<
|
||||||
|
std::vector<double>::const_iterator,
|
||||||
|
std::vector<double>::const_iterator
|
||||||
|
>
|
||||||
|
>
|
||||||
|
zip_it_run(
|
||||||
|
boost::make_tuple(
|
||||||
|
vect1.begin(),
|
||||||
|
vect2.begin()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
boost::zip_iterator<
|
||||||
|
boost::tuples::tuple<
|
||||||
|
std::vector<double>::const_iterator,
|
||||||
|
std::vector<double>::const_iterator
|
||||||
|
>
|
||||||
|
>
|
||||||
|
zip_it_end(
|
||||||
|
boost::make_tuple(
|
||||||
|
vect1.end(),
|
||||||
|
vect2.end()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if( zip_it_run == zip_it_begin &&
|
||||||
|
42. == boost::tuples::get<0>(*zip_it_run) &&
|
||||||
|
2.2 == boost::tuples::get<1>(*zip_it_run) &&
|
||||||
|
43. == boost::tuples::get<0>(*(++zip_it_run)) &&
|
||||||
|
3.3 == boost::tuples::get<1>(*zip_it_run) &&
|
||||||
|
44. == boost::tuples::get<0>(*(++zip_it_run)) &&
|
||||||
|
4.4 == boost::tuples::get<1>(*zip_it_run) &&
|
||||||
|
zip_it_end == ++zip_it_run
|
||||||
|
)
|
||||||
|
{
|
||||||
|
++num_successful_tests;
|
||||||
|
std::cout << "OK" << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++num_failed_tests = 0;
|
||||||
|
std::cout << "not OK" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Zip iterator decrementing and dereferencing
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::cout << "Zip iterator -- and *: "
|
||||||
|
<< std::flush;
|
||||||
|
|
||||||
|
if( zip_it_run == zip_it_end &&
|
||||||
|
zip_it_end == zip_it_run-- &&
|
||||||
|
44. == boost::tuples::get<0>(*zip_it_run) &&
|
||||||
|
4.4 == boost::tuples::get<1>(*zip_it_run) &&
|
||||||
|
43. == boost::tuples::get<0>(*(--zip_it_run)) &&
|
||||||
|
3.3 == boost::tuples::get<1>(*zip_it_run) &&
|
||||||
|
42. == boost::tuples::get<0>(*(--zip_it_run)) &&
|
||||||
|
2.2 == boost::tuples::get<1>(*zip_it_run) &&
|
||||||
|
zip_it_begin == zip_it_run
|
||||||
|
)
|
||||||
|
{
|
||||||
|
++num_successful_tests;
|
||||||
|
std::cout << "OK" << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++num_failed_tests = 0;
|
||||||
|
std::cout << "not OK" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Zip iterator copy construction and equality
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::cout << "Zip iterator copy construction and equality: "
|
||||||
|
<< std::flush;
|
||||||
|
|
||||||
|
boost::zip_iterator<
|
||||||
|
boost::tuples::tuple<
|
||||||
|
std::vector<double>::const_iterator,
|
||||||
|
std::vector<double>::const_iterator
|
||||||
|
>
|
||||||
|
> zip_it_run_copy(zip_it_run);
|
||||||
|
|
||||||
|
if(zip_it_run == zip_it_run && zip_it_run == zip_it_run_copy)
|
||||||
|
{
|
||||||
|
++num_successful_tests;
|
||||||
|
std::cout << "OK" << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++num_failed_tests = 0;
|
||||||
|
std::cout << "not OK" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Zip iterator inequality
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::cout << "Zip iterator inequality: "
|
||||||
|
<< std::flush;
|
||||||
|
|
||||||
|
if(!(zip_it_run != zip_it_run_copy) && zip_it_run != ++zip_it_run_copy)
|
||||||
|
{
|
||||||
|
++num_successful_tests;
|
||||||
|
std::cout << "OK" << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++num_failed_tests = 0;
|
||||||
|
std::cout << "not OK" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Zip iterator less than
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::cout << "Zip iterator less than: "
|
||||||
|
<< std::flush;
|
||||||
|
|
||||||
|
// Note: zip_it_run_copy == zip_it_run + 1
|
||||||
|
//
|
||||||
|
if( zip_it_run < zip_it_run_copy &&
|
||||||
|
!( zip_it_run < --zip_it_run_copy) &&
|
||||||
|
zip_it_run == zip_it_run_copy
|
||||||
|
)
|
||||||
|
{
|
||||||
|
++num_successful_tests;
|
||||||
|
std::cout << "OK" << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++num_failed_tests = 0;
|
||||||
|
std::cout << "not OK" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Zip iterator less than or equal
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::cout << "zip iterator less than or equal: "
|
||||||
|
<< std::flush;
|
||||||
|
|
||||||
|
// Note: zip_it_run_copy == zip_it_run
|
||||||
|
//
|
||||||
|
++zip_it_run;
|
||||||
|
zip_it_run_copy += 2;
|
||||||
|
|
||||||
|
if( zip_it_run <= zip_it_run_copy &&
|
||||||
|
zip_it_run <= --zip_it_run_copy &&
|
||||||
|
!( zip_it_run <= --zip_it_run_copy) &&
|
||||||
|
zip_it_run <= zip_it_run
|
||||||
|
)
|
||||||
|
{
|
||||||
|
++num_successful_tests;
|
||||||
|
std::cout << "OK" << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++num_failed_tests = 0;
|
||||||
|
std::cout << "not OK" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Zip iterator greater than
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::cout << "Zip iterator greater than: "
|
||||||
|
<< std::flush;
|
||||||
|
|
||||||
|
// Note: zip_it_run_copy == zip_it_run - 1
|
||||||
|
//
|
||||||
|
if( zip_it_run > zip_it_run_copy &&
|
||||||
|
!( zip_it_run > ++zip_it_run_copy) &&
|
||||||
|
zip_it_run == zip_it_run_copy
|
||||||
|
)
|
||||||
|
{
|
||||||
|
++num_successful_tests;
|
||||||
|
std::cout << "OK" << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++num_failed_tests = 0;
|
||||||
|
std::cout << "not OK" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Zip iterator greater than or equal
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::cout << "Zip iterator greater than or equal: "
|
||||||
|
<< std::flush;
|
||||||
|
|
||||||
|
++zip_it_run;
|
||||||
|
|
||||||
|
// Note: zip_it_run == zip_it_run_copy + 1
|
||||||
|
//
|
||||||
|
if( zip_it_run >= zip_it_run_copy &&
|
||||||
|
--zip_it_run >= zip_it_run_copy &&
|
||||||
|
! (zip_it_run >= ++zip_it_run_copy)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
++num_successful_tests;
|
||||||
|
std::cout << "OK" << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++num_failed_tests = 0;
|
||||||
|
std::cout << "not OK" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Zip iterator + int
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::cout << "Zip iterator + int: "
|
||||||
|
<< std::flush;
|
||||||
|
|
||||||
|
// Note: zip_it_run == zip_it_run_copy - 1
|
||||||
|
//
|
||||||
|
zip_it_run = zip_it_run + 2;
|
||||||
|
++zip_it_run_copy;
|
||||||
|
|
||||||
|
if( zip_it_run == zip_it_run_copy && zip_it_run == zip_it_begin + 3 )
|
||||||
|
{
|
||||||
|
++num_successful_tests;
|
||||||
|
std::cout << "OK" << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++num_failed_tests = 0;
|
||||||
|
std::cout << "not OK" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Zip iterator - int
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::cout << "Zip iterator - int: "
|
||||||
|
<< std::flush;
|
||||||
|
|
||||||
|
// Note: zip_it_run == zip_it_run_copy, and both are at end position
|
||||||
|
//
|
||||||
|
zip_it_run = zip_it_run - 2;
|
||||||
|
--zip_it_run_copy;
|
||||||
|
--zip_it_run_copy;
|
||||||
|
|
||||||
|
if( zip_it_run == zip_it_run_copy && (zip_it_run - 1) == zip_it_begin )
|
||||||
|
{
|
||||||
|
++num_successful_tests;
|
||||||
|
std::cout << "OK" << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++num_failed_tests = 0;
|
||||||
|
std::cout << "not OK" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Zip iterator +=
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::cout << "Zip iterator +=: "
|
||||||
|
<< std::flush;
|
||||||
|
|
||||||
|
// Note: zip_it_run == zip_it_run_copy, and both are at begin + 1
|
||||||
|
//
|
||||||
|
zip_it_run += 2;
|
||||||
|
if( zip_it_run == zip_it_begin + 3 )
|
||||||
|
{
|
||||||
|
++num_successful_tests;
|
||||||
|
std::cout << "OK" << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++num_failed_tests = 0;
|
||||||
|
std::cout << "not OK" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Zip iterator -=
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::cout << "Zip iterator -=: "
|
||||||
|
<< std::flush;
|
||||||
|
|
||||||
|
// Note: zip_it_run is at end position, zip_it_run_copy is at
|
||||||
|
// begin plus one.
|
||||||
|
//
|
||||||
|
zip_it_run -= 2;
|
||||||
|
if( zip_it_run == zip_it_run_copy )
|
||||||
|
{
|
||||||
|
++num_successful_tests;
|
||||||
|
std::cout << "OK" << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++num_failed_tests = 0;
|
||||||
|
std::cout << "not OK" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Zip iterator getting member iterators
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::cout << "Zip iterator member iterators: "
|
||||||
|
<< std::flush;
|
||||||
|
|
||||||
|
// Note: zip_it_run and zip_it_run_copy are both at
|
||||||
|
// begin plus one.
|
||||||
|
//
|
||||||
|
if( boost::tuples::get<0>(zip_it_run.get_iterator_tuple()) == vect1.begin() + 1 &&
|
||||||
|
boost::tuples::get<1>(zip_it_run.get_iterator_tuple()) == vect2.begin() + 1
|
||||||
|
)
|
||||||
|
{
|
||||||
|
++num_successful_tests;
|
||||||
|
std::cout << "OK" << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++num_failed_tests = 0;
|
||||||
|
std::cout << "not OK" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Making zip iterators
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::cout << "Making zip iterators: "
|
||||||
|
<< std::flush;
|
||||||
|
|
||||||
|
std::vector<boost::tuples::tuple<double, double> >
|
||||||
|
vect_of_tuples(3);
|
||||||
|
|
||||||
|
std::copy(
|
||||||
|
boost::make_zip_iterator(
|
||||||
|
boost::make_tuple(
|
||||||
|
vect1.begin(),
|
||||||
|
vect2.begin()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
boost::make_zip_iterator(
|
||||||
|
boost::make_tuple(
|
||||||
|
vect1.end(),
|
||||||
|
vect2.end()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
vect_of_tuples.begin()
|
||||||
|
);
|
||||||
|
|
||||||
|
if( 42. == boost::tuples::get<0>(*vect_of_tuples.begin()) &&
|
||||||
|
2.2 == boost::tuples::get<1>(*vect_of_tuples.begin()) &&
|
||||||
|
43. == boost::tuples::get<0>(*(vect_of_tuples.begin() + 1)) &&
|
||||||
|
3.3 == boost::tuples::get<1>(*(vect_of_tuples.begin() + 1)) &&
|
||||||
|
44. == boost::tuples::get<0>(*(vect_of_tuples.begin() + 2)) &&
|
||||||
|
4.4 == boost::tuples::get<1>(*(vect_of_tuples.begin() + 2))
|
||||||
|
)
|
||||||
|
{
|
||||||
|
++num_successful_tests;
|
||||||
|
std::cout << "OK" << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++num_failed_tests = 0;
|
||||||
|
std::cout << "not OK" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Zip iterator non-const --> const conversion
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::cout << "Zip iterator non-const to const conversion: "
|
||||||
|
<< std::flush;
|
||||||
|
|
||||||
|
boost::zip_iterator<
|
||||||
|
boost::tuples::tuple<
|
||||||
|
std::set<int>::const_iterator,
|
||||||
|
std::vector<double>::const_iterator
|
||||||
|
>
|
||||||
|
>
|
||||||
|
zip_it_const(
|
||||||
|
boost::make_tuple(
|
||||||
|
intset.begin(),
|
||||||
|
vect2.begin()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
//
|
||||||
|
boost::zip_iterator<
|
||||||
|
boost::tuples::tuple<
|
||||||
|
std::set<int>::iterator,
|
||||||
|
std::vector<double>::const_iterator
|
||||||
|
>
|
||||||
|
>
|
||||||
|
zip_it_half_const(
|
||||||
|
boost::make_tuple(
|
||||||
|
intset.begin(),
|
||||||
|
vect2.begin()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
//
|
||||||
|
boost::zip_iterator<
|
||||||
|
boost::tuples::tuple<
|
||||||
|
std::set<int>::iterator,
|
||||||
|
std::vector<double>::iterator
|
||||||
|
>
|
||||||
|
>
|
||||||
|
zip_it_non_const(
|
||||||
|
boost::make_tuple(
|
||||||
|
intset.begin(),
|
||||||
|
vect2.begin()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
zip_it_half_const = ++zip_it_non_const;
|
||||||
|
zip_it_const = zip_it_half_const;
|
||||||
|
++zip_it_const;
|
||||||
|
// zip_it_non_const = ++zip_it_const; // Error: can't convert from const to non-const
|
||||||
|
|
||||||
|
if( 54 == boost::tuples::get<0>(*zip_it_const) &&
|
||||||
|
4.4 == boost::tuples::get<1>(*zip_it_const) &&
|
||||||
|
53 == boost::tuples::get<0>(*zip_it_half_const) &&
|
||||||
|
3.3 == boost::tuples::get<1>(*zip_it_half_const)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
++num_successful_tests;
|
||||||
|
std::cout << "OK" << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++num_failed_tests = 0;
|
||||||
|
std::cout << "not OK" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Zip iterator categories
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::cout << "Zip iterator categories: "
|
||||||
|
<< std::flush;
|
||||||
|
|
||||||
|
// The big iterator of the previous test has vector, list, and set iterators.
|
||||||
|
// Therefore, it must be bidirectional, but not random access.
|
||||||
|
bool bBigItIsBidirectionalIterator = boost::is_same<
|
||||||
|
boost::bidirectional_traversal_tag,
|
||||||
|
boost::traversal_category<zip_it_12_type>::type
|
||||||
|
>::value;
|
||||||
|
//
|
||||||
|
bool bBigItIsRandomAccessIterator = boost::is_same<
|
||||||
|
boost::random_access_traversal_tag,
|
||||||
|
boost::traversal_category<zip_it_12_type>::type
|
||||||
|
>::value;
|
||||||
|
//
|
||||||
|
bool bBigItIsReadableIterator = boost::is_same<
|
||||||
|
boost::readable_iterator_tag,
|
||||||
|
boost::access_category<zip_it_12_type>::type
|
||||||
|
>::value;
|
||||||
|
//
|
||||||
|
bool bBigItIsReadableLValueIterator = boost::is_same<
|
||||||
|
boost::readable_lvalue_iterator_tag,
|
||||||
|
boost::access_category<zip_it_12_type>::type
|
||||||
|
>::value;
|
||||||
|
|
||||||
|
// A combining iterator with all vector iterators must have random access
|
||||||
|
// traversal.
|
||||||
|
//
|
||||||
|
typedef boost::zip_iterator<
|
||||||
|
boost::tuples::tuple<
|
||||||
|
std::vector<double>::const_iterator,
|
||||||
|
std::vector<double>::const_iterator
|
||||||
|
>
|
||||||
|
> all_vects_type;
|
||||||
|
|
||||||
|
bool bAllVectsIsRandomAccessIterator = boost::is_same<
|
||||||
|
boost::random_access_traversal_tag,
|
||||||
|
boost::traversal_category<all_vects_type>::type
|
||||||
|
>::value;
|
||||||
|
//
|
||||||
|
bool bAllVectsIsReadableIterator = boost::is_same<
|
||||||
|
boost::readable_iterator_tag,
|
||||||
|
boost::access_category<all_vects_type>::type
|
||||||
|
>::value;
|
||||||
|
//
|
||||||
|
bool bAllVectsIsReadableLValueIterator = boost::is_same<
|
||||||
|
boost::readable_lvalue_iterator_tag,
|
||||||
|
boost::access_category<all_vects_type>::type
|
||||||
|
>::value;
|
||||||
|
|
||||||
|
// Test if the meta function all_iterators_readable, which is used
|
||||||
|
// for compile-time asserting, works.
|
||||||
|
//
|
||||||
|
bool bAllIteratorsReadable1 =
|
||||||
|
boost::detail::all_iterators_in_tuple_readable<
|
||||||
|
boost::tuples::tuple<
|
||||||
|
std::vector<int>::const_iterator,
|
||||||
|
std::set<double>::iterator
|
||||||
|
>
|
||||||
|
>::type::value;
|
||||||
|
|
||||||
|
bool bAllIteratorsReadable2 =
|
||||||
|
boost::detail::all_iterators_in_tuple_readable<
|
||||||
|
boost::tuples::tuple<
|
||||||
|
std::vector<int>::const_iterator,
|
||||||
|
fake_writable_iterator,
|
||||||
|
std::set<double>::iterator
|
||||||
|
>
|
||||||
|
>::type::value;
|
||||||
|
|
||||||
|
// Compile-time assert because of non-readable iterator.
|
||||||
|
//
|
||||||
|
#ifdef PROVOKE_STATIC_ASSERT
|
||||||
|
typedef boost::zip_iterator<
|
||||||
|
boost::tuples::tuple<
|
||||||
|
fake_writable_iterator
|
||||||
|
>
|
||||||
|
>no_compile_type;
|
||||||
|
|
||||||
|
no_compile_type no_compile;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// The big test.
|
||||||
|
if( bBigItIsBidirectionalIterator &&
|
||||||
|
! bBigItIsRandomAccessIterator &&
|
||||||
|
bBigItIsReadableIterator &&
|
||||||
|
! bBigItIsReadableLValueIterator &&
|
||||||
|
bAllVectsIsRandomAccessIterator &&
|
||||||
|
! bAllVectsIsReadableLValueIterator &&
|
||||||
|
bAllVectsIsReadableIterator &&
|
||||||
|
bAllIteratorsReadable1 &&
|
||||||
|
! bAllIteratorsReadable2
|
||||||
|
)
|
||||||
|
{
|
||||||
|
++num_successful_tests;
|
||||||
|
std::cout << "OK" << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++num_failed_tests = 0;
|
||||||
|
std::cout << "not OK" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Done
|
||||||
|
//
|
||||||
|
std::cout << "\nTest Result:"
|
||||||
|
<< "\n============"
|
||||||
|
<< "\nNumber of successful tests: " << static_cast<unsigned int>(num_successful_tests)
|
||||||
|
<< "\nNumber of failed tests: " << static_cast<unsigned int>(num_failed_tests)
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user