mirror of
https://github.com/YACReader/yacreader
synced 2025-07-18 13:04:28 -04:00
Add commit 43aab01 of BenHanson/lexertl14 from github
This commit is contained in:
committed by
Luis Ángel San Martín
parent
c4f792bd40
commit
d3de52ca82
352
YACReaderLibrary/lexertl/stream_shared_iterator.hpp
Normal file
352
YACReaderLibrary/lexertl/stream_shared_iterator.hpp
Normal file
@ -0,0 +1,352 @@
|
||||
// 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 <algorithm>
|
||||
// memcpy
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
#include "runtime_error.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace lexertl
|
||||
{
|
||||
template<typename char_type>
|
||||
class basic_stream_shared_iterator
|
||||
{
|
||||
public:
|
||||
using istream = std::basic_istream<char_type>;
|
||||
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<char_type>;
|
||||
using iter_list = std::vector<basic_stream_shared_iterator *>;
|
||||
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<std::size_t>(_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<std::size_t>(_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<size_t>(_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<std::size_t>(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<char>;
|
||||
using wstream_shared_iterator = basic_stream_shared_iterator<wchar_t>;
|
||||
}
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user