// stream_shared_iterator.hpp // Copyright (c) 2010-2012 Ben Hanson (http://www.benhanson.net/) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file licence_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef LEXERTL_STREAM_SHARED_ITERATOR_H #define LEXERTL_STREAM_SHARED_ITERATOR_H #include // memcpy #include #include #include #include #include "runtime_error.hpp" #include "size_t.hpp" #include namespace lexertl { template class basic_stream_shared_iterator { public: typedef std::basic_istream istream; typedef std::forward_iterator_tag iterator_category; typedef std::size_t difference_type; typedef char_type value_type; typedef char_type *pointer; typedef char_type &reference; basic_stream_shared_iterator () : _master (false), _live (false), _index (shared::npos ()), _shared (0) { } basic_stream_shared_iterator (istream &stream_, const std::size_t buff_size_ = 1024, const std::size_t increment_ = 1024) : _master (true), _live (false), _index (shared::npos ()), // For exception safety don't call new yet _shared (0) { // Safe to call potentially throwing new now. _shared = new shared (stream_, buff_size_, increment_); ++_shared->_ref_count; _iter = _shared->_clients.insert (_shared->_clients.end (), this); } basic_stream_shared_iterator (const basic_stream_shared_iterator &rhs_) : _master (false), _live (false), _index (rhs_._master ? rhs_._shared->lowest () : rhs_._index), _shared (rhs_._shared) { if (_shared) { // New copy of an iterator. // The assumption is that any copy must be live // even if the rhs is not (otherwise we will never // have a record of the start of the current range!) ++_shared->_ref_count; _iter = _shared->_clients.insert (_shared->_clients.end (), this); _live = true; } } ~basic_stream_shared_iterator () { if (_shared) { --_shared->_ref_count; _shared->erase (this); if (_shared->_ref_count == 0) { delete _shared; _shared = 0; } } } basic_stream_shared_iterator &operator = (const basic_stream_shared_iterator &rhs_) { if (this != &rhs_) { _master = false; _index = rhs_._master ? rhs_._shared->lowest () : rhs_._index; if (_live && !rhs_._live) { _shared->erase (this); if (!rhs_._shared) { --_shared->_ref_count; } } else if (!_live && rhs_._live) { rhs_._iter = rhs_._shared->_clients.insert (rhs_._shared-> _clients.end (), this); if (!_shared) { ++rhs_._shared->_ref_count; } } _live = rhs_._live; _shared = rhs_._shared; } return *this; } bool operator == (const basic_stream_shared_iterator &rhs_) const { return _index == rhs_._index && (_shared == rhs_._shared || (_index == shared::npos () || rhs_._index == shared::npos ()) && (!_shared || !rhs_._shared)); } bool operator != (const basic_stream_shared_iterator &rhs_) const { return !(*this == rhs_); } const char_type &operator * () { check_master (); return _shared->_buffer[_index]; } basic_stream_shared_iterator &operator ++ () { check_master (); ++_index; update_state (); return *this; } basic_stream_shared_iterator operator ++ (int) { basic_stream_shared_iterator iter_ = *this; check_master (); ++_index; update_state (); return iter_; } private: class shared { public: std::size_t _ref_count; typedef std::vector char_vector; typedef std::list iter_list; istream &_stream; std::size_t _increment; std::size_t _len; char_vector _buffer; iter_list _clients; shared (istream &stream_, const std::size_t buff_size_, const std::size_t increment_) : _ref_count (0), _increment (increment_), _stream (stream_) { _buffer.resize (buff_size_); _stream.read (&_buffer.front (), _buffer.size ()); _len = static_cast(_stream.gcount ()); } bool reload_buffer () { const std::size_t lowest_ = lowest (); std::size_t read_ = 0; if (lowest_ == 0) { // Resize buffer const std::size_t old_size_ = _buffer.size (); const std::size_t new_size_ = old_size_ + _increment; _buffer.resize (new_size_); _stream.read (&_buffer.front () + old_size_, _increment); read_ = static_cast(_stream.gcount ()); if (read_) { read_ += old_size_; _len = read_; } } else { // Some systems have memcpy in namespace std using namespace std; const size_t start_ = _buffer.size () - lowest_; const size_t len_ = _buffer.size () - start_; memcpy (&_buffer.front (), &_buffer[lowest_], start_ * sizeof (char_type)); _stream.read (&_buffer.front () + start_, len_); read_ = static_cast(_stream.gcount ()); subtract (lowest_); if (read_) { read_ += start_; _len = read_; } else { _len = highest (); } } return read_ != 0; } void erase (basic_stream_shared_iterator *ptr_) { if (ptr_->_iter != _clients.end ()) { _clients.erase (ptr_->_iter); ptr_->_iter = _clients.end (); } } std::size_t lowest () const { std::size_t lowest_ = npos (); typename iter_list::const_iterator iter_ = _clients.begin (); typename iter_list::const_iterator end_ = _clients.end (); for (; iter_ != end_; ++iter_) { const basic_stream_shared_iterator *ptr_ = *iter_; if (ptr_->_index < lowest_) { lowest_ = ptr_->_index; } } if (lowest_ == npos ()) { lowest_ = 0; } return lowest_; } std::size_t highest () const { std::size_t highest_ = 0; typename iter_list::const_iterator iter_ = _clients.begin (); typename iter_list::const_iterator end_ = _clients.end (); for (; iter_ != end_; ++iter_) { const basic_stream_shared_iterator *ptr_ = *iter_; if (ptr_->_index != npos () && ptr_->_index > highest_) { highest_ = ptr_->_index; } } return highest_; } void subtract (const std::size_t lowest_) { typename iter_list::iterator iter_ = _clients.begin (); typename iter_list::iterator end_ = _clients.end (); for (; iter_ != end_; ++iter_) { basic_stream_shared_iterator *ptr_ = *iter_; if (ptr_->_index != npos ()) { ptr_->_index -= lowest_; } } } static std::size_t npos () { return static_cast(~0); } private: shared &operator = (const shared &rhs_); }; bool _master; bool _live; std::size_t _index; shared *_shared; mutable typename shared::iter_list::iterator _iter; void check_master () { if (!_shared) { throw runtime_error ("Cannot manipulate null (end) " "stream_shared_iterators."); } if (_master) { _master = false; _live = true; _index = _shared->lowest (); } } void update_state () { if (_index >= _shared->_len) { if (!_shared->reload_buffer ()) { _shared->erase (this); _index = shared::npos (); _live = false; } } } }; typedef basic_stream_shared_iterator stream_shared_iterator; typedef basic_stream_shared_iterator wstream_shared_iterator; } #endif