// stream_shared_iterator.hpp // Copyright (c) 2010-2018 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_HPP #define LEXERTL_STREAM_SHARED_ITERATOR_HPP #include // memcpy #include #include #include #include "runtime_error.hpp" #include namespace lexertl { template class basic_stream_shared_iterator { public: using istream = std::basic_istream; using iterator_category = std::forward_iterator_tag; using difference_type = std::size_t; using value_type = char_type; using pointer = char_type *; using reference = char_type &; basic_stream_shared_iterator() : _master(false), _live(false), _index(shared::npos()), _shared(nullptr) { } 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(nullptr) { // Safe to call potentially throwing new now. _shared = new shared(stream_, buff_size_, increment_); ++_shared->_ref_count; _shared->_clients.push_back(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; _shared->_clients.push_back(this); _live = true; } } ~basic_stream_shared_iterator() { if (_shared) { --_shared->_ref_count; _shared->erase(this); if (_shared->_ref_count == 0) { delete _shared; _shared = nullptr; } } } 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) { if (rhs_._shared) { ++rhs_._shared->_ref_count; } } else if (!_live && rhs_._live) { rhs_._shared->_clients.push_back(this); if (!_shared) { ++rhs_._shared->_ref_count; } } else if (_live && !rhs_._live) { _shared->erase(this); if (!rhs_._shared) { --_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; using char_vector = std::vector; using iter_list = std::vector; 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_) { auto iter_ = std::find(_clients.begin(), _clients.end(), ptr_); if (iter_ != _clients.end()) _clients.erase(iter_); } std::size_t lowest() const { std::size_t lowest_ = npos(); auto iter_ = _clients.cbegin(); auto end_ = _clients.cend(); 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; auto iter_ = _clients.cbegin(); auto end_ = _clients.cend(); 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_) { auto iter_ = _clients.begin(); auto 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; 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; } } } }; using stream_shared_iterator = basic_stream_shared_iterator; using wstream_shared_iterator = basic_stream_shared_iterator; } #endif