boost/spirit/home/classic/iterator/multi_pass.hpp
/*=============================================================================
Copyright (c) 2001, Daniel C. Nuffer
http://spirit.sourceforge.net/
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)
=============================================================================*/
#ifndef BOOST_SPIRIT_ITERATOR_MULTI_PASS_HPP
#define BOOST_SPIRIT_ITERATOR_MULTI_PASS_HPP
#include <boost/config.hpp>
#include <boost/throw_exception.hpp>
#include <deque>
#include <iterator>
#include <iostream>
#include <algorithm> // for std::swap
#include <exception> // for std::exception
#include <boost/limits.hpp>
#include <boost/iterator.hpp>
#include <boost/spirit/home/classic/namespace.hpp>
#include <boost/spirit/home/classic/core/assert.hpp> // for BOOST_SPIRIT_ASSERT
#include <boost/spirit/home/classic/iterator/fixed_size_queue.hpp>
#include <boost/detail/iterator.hpp> // for boost::detail::iterator_traits
#include <boost/spirit/home/classic/iterator/multi_pass_fwd.hpp>
namespace boost { namespace spirit {
BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
namespace impl {
template <typename T>
inline void mp_swap(T& t1, T& t2);
}
namespace multi_pass_policies
{
///////////////////////////////////////////////////////////////////////////////
// class ref_counted
// Implementation of an OwnershipPolicy used by multi_pass.
//
// Implementation modified from RefCounted class from the Loki library by
// Andrei Alexandrescu
///////////////////////////////////////////////////////////////////////////////
class ref_counted
{
protected:
ref_counted()
: count(new std::size_t(1))
{}
ref_counted(ref_counted const& x)
: count(x.count)
{}
// clone is called when a copy of the iterator is made, so increment
// the ref-count.
void clone()
{
++*count;
}
// called when a copy is deleted. Decrement the ref-count. Return
// value of true indicates that the last copy has been released.
bool release()
{
if (!--*count)
{
delete count;
count = 0;
return true;
}
return false;
}
void swap(ref_counted& x)
{
impl::mp_swap(count, x.count);
}
public:
// returns true if there is only one iterator in existence.
// std_deque StoragePolicy will free it's buffered data if this
// returns true.
bool unique() const
{
return *count == 1;
}
private:
std::size_t* count;
};
///////////////////////////////////////////////////////////////////////////////
// class first_owner
// Implementation of an OwnershipPolicy used by multi_pass
// This ownership policy dictates that the first iterator created will
// determine the lifespan of the shared components. This works well for
// spirit, since no dynamic allocation of iterators is done, and all copies
// are make on the stack.
//
// There is a caveat about using this policy together with the std_deque
// StoragePolicy. Since first_owner always returns false from unique(),
// std_deque will only release the queued data if clear_queue() is called.
///////////////////////////////////////////////////////////////////////////////
class first_owner
{
protected:
first_owner()
: first(true)
{}
first_owner(first_owner const&)
: first(false)
{}
void clone()
{
}
// return true to indicate deletion of resources
bool release()
{
return first;
}
void swap(first_owner&)
{
// if we're the first, we still remain the first, even if assigned
// to, so don't swap first_. swap is only called from operator=
}
public:
bool unique() const
{
return false; // no way to know, so always return false
}
private:
bool first;
};
///////////////////////////////////////////////////////////////////////////////
// class illegal_backtracking
// thrown by buf_id_check CheckingPolicy if an instance of an iterator is
// used after another one has invalidated the queue
///////////////////////////////////////////////////////////////////////////////
class illegal_backtracking : public std::exception
{
public:
illegal_backtracking() throw() {}
~illegal_backtracking() throw() {}
virtual const char*
what() const throw()
{ return "BOOST_SPIRIT_CLASSIC_NS::illegal_backtracking"; }
};
///////////////////////////////////////////////////////////////////////////////
// class buf_id_check
// Implementation of the CheckingPolicy used by multi_pass
// This policy is most effective when used together with the std_deque
// StoragePolicy.
// If used with the fixed_size_queue StoragePolicy, it will not detect
// iterator derefereces that are out of the range of the queue.
///////////////////////////////////////////////////////////////////////////////
class buf_id_check
{
protected:
buf_id_check()
: shared_buf_id(new unsigned long(0))
, buf_id(0)
{}
buf_id_check(buf_id_check const& x)
: shared_buf_id(x.shared_buf_id)
, buf_id(x.buf_id)
{}
// will be called from the destructor of the last iterator.
void destroy()
{
delete shared_buf_id;
shared_buf_id = 0;
}
void swap(buf_id_check& x)
{
impl::mp_swap(shared_buf_id, x.shared_buf_id);
impl::mp_swap(buf_id, x.buf_id);
}
// called to verify that everything is okay.
void check() const
{
if (buf_id != *shared_buf_id)
{
boost::throw_exception(illegal_backtracking());
}
}
// called from multi_pass::clear_queue, so we can increment the count
void clear_queue()
{
++*shared_buf_id;
++buf_id;
}
private:
unsigned long* shared_buf_id;
unsigned long buf_id;
};
///////////////////////////////////////////////////////////////////////////////
// class no_check
// Implementation of the CheckingPolicy used by multi_pass
// It does not do anything :-)
///////////////////////////////////////////////////////////////////////////////
class no_check
{
protected:
no_check() {}
no_check(no_check const&) {}
void destroy() {}
void swap(no_check&) {}
void check() const {}
void clear_queue() {}
};
///////////////////////////////////////////////////////////////////////////////
// class std_deque
// Implementation of the StoragePolicy used by multi_pass
// This stores all data in a std::deque, and keeps an offset to the current
// position. It stores all the data unless there is only one
// iterator using the queue.
// Note: a position is used instead of an iterator, because a push_back on
// a deque can invalidate any iterators.
///////////////////////////////////////////////////////////////////////////////
class std_deque
{
public:
template <typename ValueT>
class inner
{
private:
typedef std::deque<ValueT> queue_type;
queue_type* queuedElements;
mutable typename queue_type::size_type queuePosition;
protected:
inner()
: queuedElements(new queue_type)
, queuePosition(0)
{}
inner(inner const& x)
: queuedElements(x.queuedElements)
, queuePosition(x.queuePosition)
{}
// will be called from the destructor of the last iterator.
void destroy()
{
BOOST_SPIRIT_ASSERT(NULL != queuedElements);
delete queuedElements;
queuedElements = 0;
}
void swap(inner& x)
{
impl::mp_swap(queuedElements, x.queuedElements);
impl::mp_swap(queuePosition, x.queuePosition);
}
// This is called when the iterator is dereferenced. It's a template
// method so we can recover the type of the multi_pass iterator
// and call unique and access the m_input data member.
template <typename MultiPassT>
static typename MultiPassT::reference dereference(MultiPassT const& mp)
{
if (mp.queuePosition == mp.queuedElements->size())
{
// check if this is the only iterator
if (mp.unique())
{
// free up the memory used by the queue.
if (mp.queuedElements->size() > 0)
{
mp.queuedElements->clear();
mp.queuePosition = 0;
}
}
return mp.get_input();
}
else
{
return (*mp.queuedElements)[mp.queuePosition];
}
}
// This is called when the iterator is incremented. It's a template
// method so we can recover the type of the multi_pass iterator
// and call unique and access the m_input data member.
template <typename MultiPassT>
static void increment(MultiPassT& mp)
{
if (mp.queuePosition == mp.queuedElements->size())
{
// check if this is the only iterator
if (mp.unique())
{
// free up the memory used by the queue.
if (mp.queuedElements->size() > 0)
{
mp.queuedElements->clear();
mp.queuePosition = 0;
}
}
else
{
mp.queuedElements->push_back(mp.get_input());
++mp.queuePosition;
}
mp.advance_input();
}
else
{
++mp.queuePosition;
}
}
// called to forcibly clear the queue
void clear_queue()
{
queuedElements->clear();
queuePosition = 0;
}
// called to determine whether the iterator is an eof iterator
template <typename MultiPassT>
static bool is_eof(MultiPassT const& mp)
{
return mp.queuePosition == mp.queuedElements->size() &&
mp.input_at_eof();
}
// called by operator==
bool equal_to(inner const& x) const
{
return queuePosition == x.queuePosition;
}
// called by operator<
bool less_than(inner const& x) const
{
return queuePosition < x.queuePosition;
}
}; // class inner
}; // class std_deque
///////////////////////////////////////////////////////////////////////////////
// class fixed_size_queue
// Implementation of the StoragePolicy used by multi_pass
// fixed_size_queue keeps a circular buffer (implemented by
// BOOST_SPIRIT_CLASSIC_NS::fixed_size_queue class) that is size N+1 and stores N elements.
// It is up to the user to ensure that there is enough look ahead for their
// grammar. Currently there is no way to tell if an iterator is pointing
// to forgotten data. The leading iterator will put an item in the queue
// and remove one when it is incremented. No dynamic allocation is done,
// except on creation of the queue (fixed_size_queue constructor).
///////////////////////////////////////////////////////////////////////////////
template < std::size_t N>
class fixed_size_queue
{
public:
template <typename ValueT>
class inner
{
private:
typedef BOOST_SPIRIT_CLASSIC_NS::fixed_size_queue<ValueT, N> queue_type;
queue_type * queuedElements;
mutable typename queue_type::iterator queuePosition;
protected:
inner()
: queuedElements(new queue_type)
, queuePosition(queuedElements->begin())
{}
inner(inner const& x)
: queuedElements(x.queuedElements)
, queuePosition(x.queuePosition)
{}
// will be called from the destructor of the last iterator.
void destroy()
{
BOOST_SPIRIT_ASSERT(NULL != queuedElements);
delete queuedElements;
queuedElements = 0;
}
void swap(inner& x)
{
impl::mp_swap(queuedElements, x.queuedElements);
impl::mp_swap(queuePosition, x.queuePosition);
}
// This is called when the iterator is dereferenced. It's a template
// method so we can recover the type of the multi_pass iterator
// and access the m_input data member.
template <typename MultiPassT>
static typename MultiPassT::reference dereference(MultiPassT const& mp)
{
if (mp.queuePosition == mp.queuedElements->end())
{
return mp.get_input();
}
else
{
return *mp.queuePosition;
}
}
// This is called when the iterator is incremented. It's a template
// method so we can recover the type of the multi_pass iterator
// and access the m_input data member.
template <typename MultiPassT>
static void increment(MultiPassT& mp)
{
if (mp.queuePosition == mp.queuedElements->end())
{
// don't let the queue get larger than N
if (mp.queuedElements->size() >= N)
mp.queuedElements->pop_front();
mp.queuedElements->push_back(mp.get_input());
mp.advance_input();
}
++mp.queuePosition;
}
// no-op
void clear_queue()
{}
// called to determine whether the iterator is an eof iterator
template <typename MultiPassT>
static bool is_eof(MultiPassT const& mp)
{
return mp.queuePosition == mp.queuedElements->end() &&
mp.input_at_eof();
}
// called by operator==
bool equal_to(inner const& x) const
{
return queuePosition == x.queuePosition;
}
// called by operator<
bool less_than(inner const& x) const
{
return queuePosition < x.queuePosition;
}
}; // class inner
}; // class fixed_size_queue
///////////////////////////////////////////////////////////////////////////////
// class input_iterator
// Implementation of the InputPolicy used by multi_pass
// input_iterator encapsulates an input iterator of type InputT
///////////////////////////////////////////////////////////////////////////////
class input_iterator
{
public:
template <typename InputT>
class inner
{
private:
typedef
typename boost::detail::iterator_traits<InputT>::value_type
result_type;
public:
typedef result_type value_type;
private:
struct Data {
Data(InputT const &input_)
: input(input_), was_initialized(false)
{}
InputT input;
value_type curtok;
bool was_initialized;
};
// Needed by compilers not implementing the resolution to DR45. For
// reference, see
// http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#45.
friend struct Data;
public:
typedef
typename boost::detail::iterator_traits<InputT>::difference_type
difference_type;
typedef
typename boost::detail::iterator_traits<InputT>::pointer
pointer;
typedef
typename boost::detail::iterator_traits<InputT>::reference
reference;
protected:
inner()
: data(0)
{}
inner(InputT x)
: data(new Data(x))
{}
inner(inner const& x)
: data(x.data)
{}
void destroy()
{
delete data;
data = 0;
}
bool same_input(inner const& x) const
{
return data == x.data;
}
typedef
typename boost::detail::iterator_traits<InputT>::value_type
value_t;
void swap(inner& x)
{
impl::mp_swap(data, x.data);
}
void ensure_initialized() const
{
if (data && !data->was_initialized) {
data->curtok = *data->input; // get the first token
data->was_initialized = true;
}
}
public:
reference get_input() const
{
BOOST_SPIRIT_ASSERT(NULL != data);
ensure_initialized();
return data->curtok;
}
void advance_input()
{
BOOST_SPIRIT_ASSERT(NULL != data);
data->was_initialized = false; // should get the next token
++data->input;
}
bool input_at_eof() const
{
return !data || data->input == InputT();
}
private:
Data *data;
};
};
///////////////////////////////////////////////////////////////////////////////
// class lex_input
// Implementation of the InputPolicy used by multi_pass
// lex_input gets tokens (ints) from yylex()
///////////////////////////////////////////////////////////////////////////////
class lex_input
{
public:
template <typename InputT>
class inner
{
public:
typedef int value_type;
typedef std::ptrdiff_t difference_type;
typedef int* pointer;
typedef int& reference;
protected:
inner()
: curtok(new int(0))
{}
inner(InputT x)
: curtok(new int(x))
{}
inner(inner const& x)
: curtok(x.curtok)
{}
void destroy()
{
delete curtok;
curtok = 0;
}
bool same_input(inner const& x) const
{
return curtok == x.curtok;
}
void swap(inner& x)
{
impl::mp_swap(curtok, x.curtok);
}
public:
reference get_input() const
{
return *curtok;
}
void advance_input()
{
extern int yylex();
*curtok = yylex();
}
bool input_at_eof() const
{
return *curtok == 0;
}
private:
int* curtok;
};
};
///////////////////////////////////////////////////////////////////////////////
// class functor_input
// Implementation of the InputPolicy used by multi_pass
// functor_input gets tokens from a functor
// Note: the functor must have a typedef for result_type
// It also must have a static variable of type result_type defined to
// represent eof that is called eof.
///////////////////////////////////////////////////////////////////////////////
class functor_input
{
public:
template <typename FunctorT>
class inner
{
typedef typename FunctorT::result_type result_type;
public:
typedef result_type value_type;
typedef std::ptrdiff_t difference_type;
typedef result_type* pointer;
typedef result_type& reference;
protected:
inner()
: ftor(0)
, curtok(0)
{}
inner(FunctorT const& x)
: ftor(new FunctorT(x))
, curtok(new result_type((*ftor)()))
{}
inner(inner const& x)
: ftor(x.ftor)
, curtok(x.curtok)
{}
void destroy()
{
delete ftor;
ftor = 0;
delete curtok;
curtok = 0;
}
bool same_input(inner const& x) const
{
return ftor == x.ftor;
}
void swap(inner& x)
{
impl::mp_swap(curtok, x.curtok);
impl::mp_swap(ftor, x.ftor);
}
public:
reference get_input() const
{
return *curtok;
}
void advance_input()
{
if (curtok) {
*curtok = (*ftor)();
}
}
bool input_at_eof() const
{
return !curtok || *curtok == ftor->eof;
}
FunctorT& get_functor() const
{
return *ftor;
}
private:
FunctorT* ftor;
result_type* curtok;
};
};
} // namespace multi_pass_policies
///////////////////////////////////////////////////////////////////////////////
// iterator_base_creator
///////////////////////////////////////////////////////////////////////////////
namespace iterator_ { namespace impl {
// Meta-function to generate a std::iterator<> base class for multi_pass. This
// is used mainly to improve conformance of compilers not supporting PTS
// and thus relying on inheritance to recognize an iterator.
// We are using boost::iterator<> because it offers an automatic workaround
// for broken std::iterator<> implementations.
template <typename InputPolicyT, typename InputT>
struct iterator_base_creator
{
typedef typename InputPolicyT::BOOST_NESTED_TEMPLATE inner<InputT> input_t;
typedef boost::iterator
<
std::forward_iterator_tag,
typename input_t::value_type,
typename input_t::difference_type,
typename input_t::pointer,
typename input_t::reference
> type;
};
}}
///////////////////////////////////////////////////////////////////////////////
// class template multi_pass
///////////////////////////////////////////////////////////////////////////////
// The default multi_pass instantiation uses a ref-counted std_deque scheme.
template
<
typename InputT,
typename InputPolicy,
typename OwnershipPolicy,
typename CheckingPolicy,
typename StoragePolicy
>
class multi_pass
: public OwnershipPolicy
, public CheckingPolicy
, public StoragePolicy::template inner<
typename InputPolicy::template inner<InputT>::value_type>
, public InputPolicy::template inner<InputT>
, public iterator_::impl::iterator_base_creator<InputPolicy, InputT>::type
{
typedef OwnershipPolicy OP;
typedef CheckingPolicy CHP;
typedef typename StoragePolicy::template inner<
typename InputPolicy::template inner<InputT>::value_type> SP;
typedef typename InputPolicy::template inner<InputT> IP;
typedef typename
iterator_::impl::iterator_base_creator<InputPolicy, InputT>::type
IB;
public:
typedef typename IB::value_type value_type;
typedef typename IB::difference_type difference_type;
typedef typename IB::reference reference;
typedef typename IB::pointer pointer;
typedef InputT iterator_type;
multi_pass();
explicit multi_pass(InputT input);
#if BOOST_WORKAROUND(__GLIBCPP__, == 20020514)
multi_pass(int);
#endif // BOOST_WORKAROUND(__GLIBCPP__, == 20020514)
~multi_pass();
multi_pass(multi_pass const&);
multi_pass& operator=(multi_pass const&);
void swap(multi_pass& x);
reference operator*() const;
pointer operator->() const;
multi_pass& operator++();
multi_pass operator++(int);
void clear_queue();
bool operator==(const multi_pass& y) const;
bool operator<(const multi_pass& y) const;
private: // helper functions
bool is_eof() const;
};
template
<
typename InputT,
typename InputPolicy,
typename OwnershipPolicy,
typename CheckingPolicy,
typename StoragePolicy
>
inline
multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
multi_pass()
: OP()
, CHP()
, SP()
, IP()
{
}
template
<
typename InputT,
typename InputPolicy,
typename OwnershipPolicy,
typename CheckingPolicy,
typename StoragePolicy
>
inline
multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
multi_pass(InputT input)
: OP()
, CHP()
, SP()
, IP(input)
{
}
#if BOOST_WORKAROUND(__GLIBCPP__, == 20020514)
// The standard library shipped with gcc-3.1 has a bug in
// bits/basic_string.tcc. It tries to use iter::iter(0) to
// construct an iterator. Ironically, this happens in sanity
// checking code that isn't required by the standard.
// The workaround is to provide an additional constructor that
// ignores its int argument and behaves like the default constructor.
template
<
typename InputT,
typename InputPolicy,
typename OwnershipPolicy,
typename CheckingPolicy,
typename StoragePolicy
>
inline
multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
multi_pass(int)
: OP()
, CHP()
, SP()
, IP()
{
}
#endif // BOOST_WORKAROUND(__GLIBCPP__, == 20020514)
template
<
typename InputT,
typename InputPolicy,
typename OwnershipPolicy,
typename CheckingPolicy,
typename StoragePolicy
>
inline
multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
~multi_pass()
{
if (OP::release())
{
CHP::destroy();
SP::destroy();
IP::destroy();
}
}
template
<
typename InputT,
typename InputPolicy,
typename OwnershipPolicy,
typename CheckingPolicy,
typename StoragePolicy
>
inline
multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
multi_pass(
multi_pass const& x)
: OP(x)
, CHP(x)
, SP(x)
, IP(x)
{
OP::clone();
}
template
<
typename InputT,
typename InputPolicy,
typename OwnershipPolicy,
typename CheckingPolicy,
typename StoragePolicy
>
inline
multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>&
multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
operator=(
multi_pass const& x)
{
multi_pass temp(x);
temp.swap(*this);
return *this;
}
template
<
typename InputT,
typename InputPolicy,
typename OwnershipPolicy,
typename CheckingPolicy,
typename StoragePolicy
>
inline void
multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
swap(multi_pass& x)
{
OP::swap(x);
CHP::swap(x);
SP::swap(x);
IP::swap(x);
}
template
<
typename InputT,
typename InputPolicy,
typename OwnershipPolicy,
typename CheckingPolicy,
typename StoragePolicy
>
inline
typename multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
reference
multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
operator*() const
{
CHP::check();
return SP::dereference(*this);
}
template
<
typename InputT,
typename InputPolicy,
typename OwnershipPolicy,
typename CheckingPolicy,
typename StoragePolicy
>
inline
typename multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
pointer
multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
operator->() const
{
return &(operator*());
}
template
<
typename InputT,
typename InputPolicy,
typename OwnershipPolicy,
typename CheckingPolicy,
typename StoragePolicy
>
inline
multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>&
multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
operator++()
{
CHP::check();
SP::increment(*this);
return *this;
}
template
<
typename InputT,
typename InputPolicy,
typename OwnershipPolicy,
typename CheckingPolicy,
typename StoragePolicy
>
inline
multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>
multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
operator++(int)
{
multi_pass
<
InputT,
InputPolicy,
OwnershipPolicy,
CheckingPolicy,
StoragePolicy
> tmp(*this);
++*this;
return tmp;
}
template
<
typename InputT,
typename InputPolicy,
typename OwnershipPolicy,
typename CheckingPolicy,
typename StoragePolicy
>
inline void
multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
clear_queue()
{
SP::clear_queue();
CHP::clear_queue();
}
template
<
typename InputT,
typename InputPolicy,
typename OwnershipPolicy,
typename CheckingPolicy,
typename StoragePolicy
>
inline bool
multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
is_eof() const
{
return SP::is_eof(*this);
}
///// Comparisons
template
<
typename InputT,
typename InputPolicy,
typename OwnershipPolicy,
typename CheckingPolicy,
typename StoragePolicy
>
inline bool
multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
operator==(const multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy,
StoragePolicy>& y) const
{
bool is_eof_ = SP::is_eof(*this);
bool y_is_eof_ = SP::is_eof(y);
if (is_eof_ && y_is_eof_)
{
return true; // both are EOF
}
else if (is_eof_ ^ y_is_eof_)
{
return false; // one is EOF, one isn't
}
else if (!IP::same_input(y))
{
return false;
}
else
{
return SP::equal_to(y);
}
}
template
<
typename InputT,
typename InputPolicy,
typename OwnershipPolicy,
typename CheckingPolicy,
typename StoragePolicy
>
inline bool
multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy>::
operator<(const multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy,
StoragePolicy>& y) const
{
return SP::less_than(y);
}
template
<
typename InputT,
typename InputPolicy,
typename OwnershipPolicy,
typename CheckingPolicy,
typename StoragePolicy
>
inline
bool operator!=(
const multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy,
StoragePolicy>& x,
const multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy,
StoragePolicy>& y)
{
return !(x == y);
}
template
<
typename InputT,
typename InputPolicy,
typename OwnershipPolicy,
typename CheckingPolicy,
typename StoragePolicy
>
inline
bool operator>(
const multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy,
StoragePolicy>& x,
const multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy,
StoragePolicy>& y)
{
return y < x;
}
template
<
typename InputT,
typename InputPolicy,
typename OwnershipPolicy,
typename CheckingPolicy,
typename StoragePolicy
>
inline
bool operator>=(
const multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy,
StoragePolicy>& x,
const multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy,
StoragePolicy>& y)
{
return !(x < y);
}
template
<
typename InputT,
typename InputPolicy,
typename OwnershipPolicy,
typename CheckingPolicy,
typename StoragePolicy
>
inline
bool operator<=(
const multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy,
StoragePolicy>& x,
const multi_pass<InputT, InputPolicy, OwnershipPolicy, CheckingPolicy,
StoragePolicy>& y)
{
return !(y < x);
}
///// Generator function
template <typename InputT>
inline multi_pass<InputT,
multi_pass_policies::input_iterator, multi_pass_policies::ref_counted,
multi_pass_policies::buf_id_check, multi_pass_policies::std_deque>
make_multi_pass(InputT i)
{
return multi_pass<InputT,
multi_pass_policies::input_iterator, multi_pass_policies::ref_counted,
multi_pass_policies::buf_id_check, multi_pass_policies::std_deque>(i);
}
// this could be a template typedef, since such a thing doesn't
// exist in C++, we'll use inheritance to accomplish the same thing.
template <typename InputT, std::size_t N>
class look_ahead :
public multi_pass<
InputT,
multi_pass_policies::input_iterator,
multi_pass_policies::first_owner,
multi_pass_policies::no_check,
multi_pass_policies::fixed_size_queue<N> >
{
typedef multi_pass<
InputT,
multi_pass_policies::input_iterator,
multi_pass_policies::first_owner,
multi_pass_policies::no_check,
multi_pass_policies::fixed_size_queue<N> > base_t;
public:
look_ahead()
: base_t() {}
explicit look_ahead(InputT x)
: base_t(x) {}
look_ahead(look_ahead const& x)
: base_t(x) {}
#if BOOST_WORKAROUND(__GLIBCPP__, == 20020514)
look_ahead(int) // workaround for a bug in the library
: base_t() {} // shipped with gcc 3.1
#endif // BOOST_WORKAROUND(__GLIBCPP__, == 20020514)
// default generated operators destructor and assignment operator are okay.
};
template
<
typename InputT,
typename InputPolicy,
typename OwnershipPolicy,
typename CheckingPolicy,
typename StoragePolicy
>
void swap(
multi_pass<
InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy
> &x,
multi_pass<
InputT, InputPolicy, OwnershipPolicy, CheckingPolicy, StoragePolicy
> &y)
{
x.swap(y);
}
namespace impl {
template <typename T>
inline void mp_swap(T& t1, T& t2)
{
using std::swap;
using BOOST_SPIRIT_CLASSIC_NS::swap;
swap(t1, t2);
}
}
BOOST_SPIRIT_CLASSIC_NAMESPACE_END
}} // namespace BOOST_SPIRIT_CLASSIC_NS
#endif // BOOST_SPIRIT_ITERATOR_MULTI_PASS_HPP