blob: 8535773d01bb626220412ce93c3b00eaf4f4f7e8 [file] [log] [blame]
/*=============================================================================
Copyright (c) 2003 Giovanni Bajo
Copyright (c) 2003 Thomas Witt
Copyright (c) 2003 Hartmut Kaiser
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)
=============================================================================*/
///////////////////////////////////////////////////////////////////////////////
//
// File Iterator structure
//
// The new structure is designed on layers. The top class (used by the user)
// is file_iterator, which implements a full random access iterator through
// the file, and some specific member functions (constructor that opens
// the file, make_end() to generate the end iterator, operator bool to check
// if the file was opened correctly).
//
// file_iterator implements the random access iterator interface by the means
// of boost::iterator_adaptor, that is inhering an object created with it.
// iterator_adaptor gets a low-level file iterator implementation (with just
// a few member functions) and a policy (that basically describes to it how
// the low-level file iterator interface is). The advantage is that
// with boost::iterator_adaptor only 5 functions are needed to implement
// a fully conformant random access iterator, instead of dozens of functions
// and operators.
//
// There are two low-level file iterators implemented in this module. The
// first (std_file_iterator) uses cstdio stream functions (fopen/fread), which
// support full buffering, and is available everywhere (it's standard C++).
// The second (mmap_file_iterator) is currently available only on Windows
// platforms, and uses memory mapped files, which gives a decent speed boost.
//
///////////////////////////////////////////////////////////////////////////////
//
// TODO LIST:
//
// - In the Win32 mmap iterator, we could check if keeping a handle to the
// opened file is really required. If it's not, we can just store the file
// length (for make_end()) and save performance. Notice that this should be
// tested under different Windows versions, the behaviour might change.
// - Add some error support (by the means of some exceptions) in case of
// low-level I/O failure.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_SPIRIT_FILE_ITERATOR_HPP
#define BOOST_SPIRIT_FILE_ITERATOR_HPP
#include <string>
#include <boost/config.hpp>
#include <boost/iterator_adaptors.hpp>
#include <boost/spirit/home/classic/namespace.hpp>
#include <boost/spirit/home/classic/core/safe_bool.hpp>
#include <boost/spirit/home/classic/iterator/file_iterator_fwd.hpp>
#if !defined(BOOST_SPIRIT_FILEITERATOR_STD)
# if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) \
&& !defined(BOOST_DISABLE_WIN32)
# define BOOST_SPIRIT_FILEITERATOR_WINDOWS
# elif defined(BOOST_HAS_UNISTD_H)
extern "C"
{
# include <unistd.h>
}
# ifdef _POSIX_MAPPED_FILES
# define BOOST_SPIRIT_FILEITERATOR_POSIX
# endif // _POSIX_MAPPED_FILES
# endif // BOOST_HAS_UNISTD_H
# if !defined(BOOST_SPIRIT_FILEITERATOR_WINDOWS) && \
!defined(BOOST_SPIRIT_FILEITERATOR_POSIX)
# define BOOST_SPIRIT_FILEITERATOR_STD
# endif
#endif // BOOST_SPIRIT_FILEITERATOR_STD
///////////////////////////////////////////////////////////////////////////////
namespace boost { namespace spirit {
BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
template <
typename CharT = char,
typename BaseIterator =
#ifdef BOOST_SPIRIT_FILEITERATOR_STD
fileiter_impl::std_file_iterator<CharT>
#else
fileiter_impl::mmap_file_iterator<CharT>
#endif
> class file_iterator;
///////////////////////////////////////////////////////////////////////////////
namespace fileiter_impl {
/////////////////////////////////////////////////////////////////////////
//
// file_iter_generator
//
// Template meta-function to invoke boost::iterator_adaptor
// NOTE: This cannot be moved into the implementation file because of
// a bug of MSVC 7.0 and previous versions (base classes types are
// looked up at compilation time, not instantion types, and
// file_iterator would break).
//
/////////////////////////////////////////////////////////////////////////
#if !defined(BOOST_ITERATOR_ADAPTORS_VERSION) || \
BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200
#error "Please use at least Boost V1.31.0 while compiling the file_iterator class!"
#else // BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200
template <typename CharT, typename BaseIteratorT>
struct file_iter_generator
{
public:
typedef BaseIteratorT adapted_t;
typedef typename adapted_t::value_type value_type;
typedef boost::iterator_adaptor <
file_iterator<CharT, BaseIteratorT>,
adapted_t,
value_type const,
std::random_access_iterator_tag,
boost::use_default,
std::ptrdiff_t
> type;
};
#endif // BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200
///////////////////////////////////////////////////////////////////////////////
} /* namespace impl */
///////////////////////////////////////////////////////////////////////////////
//
// file_iterator
//
// Iterates through an opened file.
//
// The main iterator interface is implemented by the iterator_adaptors
// library, which wraps a conforming iterator interface around the
// impl::BaseIterator class. This class merely derives the iterator_adaptors
// generated class to implement the custom constructors and make_end()
// member function.
//
///////////////////////////////////////////////////////////////////////////////
template<typename CharT, typename BaseIteratorT>
class file_iterator
: public fileiter_impl::file_iter_generator<CharT, BaseIteratorT>::type,
public safe_bool<file_iterator<CharT, BaseIteratorT> >
{
private:
typedef typename
fileiter_impl::file_iter_generator<CharT, BaseIteratorT>::type
base_t;
typedef typename
fileiter_impl::file_iter_generator<CharT, BaseIteratorT>::adapted_t
adapted_t;
public:
file_iterator()
{}
file_iterator(std::string fileName)
: base_t(adapted_t(fileName))
{}
file_iterator(const base_t& iter)
: base_t(iter)
{}
inline file_iterator& operator=(const base_t& iter);
file_iterator make_end(void);
// operator bool. This borrows a trick from boost::shared_ptr to avoid
// to interfere with arithmetic operations.
bool operator_bool(void) const
{ return this->base(); }
private:
friend class ::boost::iterator_core_access;
typename base_t::reference dereference() const
{
return this->base_reference().get_cur_char();
}
void increment()
{
this->base_reference().next_char();
}
void decrement()
{
this->base_reference().prev_char();
}
void advance(typename base_t::difference_type n)
{
this->base_reference().advance(n);
}
template <
typename OtherDerivedT, typename OtherIteratorT,
typename V, typename C, typename R, typename D
>
typename base_t::difference_type distance_to(
iterator_adaptor<OtherDerivedT, OtherIteratorT, V, C, R, D>
const &x) const
{
return x.base().distance(this->base_reference());
}
};
///////////////////////////////////////////////////////////////////////////////
BOOST_SPIRIT_CLASSIC_NAMESPACE_END
}} /* namespace BOOST_SPIRIT_CLASSIC_NS */
///////////////////////////////////////////////////////////////////////////////
#include <boost/spirit/home/classic/iterator/impl/file_iterator.ipp> /* implementation */
#endif /* BOOST_SPIRIT_FILE_ITERATOR_HPP */