multi_pass.hpp
来自「Boost provides free peer-reviewed portab」· HPP 代码 · 共 1,308 行 · 第 1/3 页
HPP
1,308 行
/*============================================================================= 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_BEGINnamespace 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
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?