|
#pragma once
#include "tlsObject.hpp"
#include <cassert>
#include <list>
#include <vector>
typedef unsigned char BYTE;
typedef std::vector<BYTE> Buffer;
////////////////////////////////////////////////////////////////////////////////
//
// MultiChannelBuffer
// ------------------
//
// Models a noninterleaved multi channel buffer that uses/presupposes the fact
// that all channels are equal in size and writing/reading is always done
// to/from all channels.
// Supports a single writer and multiple readers/consumers from different
// threads. The writer and the readers are generally completely independent so
// they must use the query interface functions to see if/how much can they
// read/write.
//
// (todo) rename to QueryMultiChannelBuffer or some nicer name that will better
// emphasize its usage.
//
////////////////////////////////////////////////////////////////////////////////
class MultiChannelBuffer
{
public:
MultiChannelBuffer();
size_t channelSize () const { return channelSize_; }
size_t numberOfChannels() const { assert( channelSize() ); return totalSize() / channelSize(); }
size_t totalSize () const { return buffer_.size(); }
bool hasUnreadInput() const;
void reset();
void resize( size_t numberOfChannels, size_t bytesPerChannel, size_t maximumExpectedWriteChunk );
class Reader;
Reader createNewReader() const;
class WritePointers;
size_t canWrite() const;
WritePointers getWritePointers( size_t sz );
size_t bytesWritten() const { return bytesWritten_; }
private: // WritePointers private interface.
void writeCompletedCallback( size_t sizeOfWrittenChunk );
private:
//typedef std::vector<Reader *> Readers;
typedef std::list<Reader *> Readers;
Readers & readers() { return readers_; }
bool isReaderRegistered( Reader const & reader ) const;
void registerReader ( Reader & reader ) const;
void unregisterReader ( Reader & reader ) const;
Buffer::const_iterator MultiChannelBuffer::slowestReaderPosition() const;
bool isInResetState() const;
bool allReadersHaveTheSameEndMarker() const;
Buffer::iterator writeCursor () const { return writePosition_ ; }
size_t writeCursorOffset() const { return writeCursor() - buffer_.begin(); }
private:
mutable Buffer buffer_ ;
mutable Readers readers_;
mutable Buffer::iterator writePosition_;
size_t channelSize_;
size_t bytesWritten_;
size_t minimumSpaceThatMustRemain_;
};
////////////////////////////////////////////////////////////////////////////////
//
// MultiChannelBuffer::Reader
// --------------------------
//
// Models a single reader of a MultiChannelBuffer.
//
////////////////////////////////////////////////////////////////////////////////
class MultiChannelBuffer::Reader
{
public:
Reader( Reader const & );
~Reader() { parent_.unregisterReader( *this ); }
class ChannelIterator;
ChannelIterator getChunk( size_t desiredChunkSize );
size_t availableDataPerChannel() const { return availableDataPerChannel_; }
MultiChannelBuffer const & parent() const { return parent_; }
private:
void operator=( Reader const & );
private: // MultiChannelBuffer private interface.
friend class MultiChannelBuffer;
Reader( Buffer::const_iterator const & firstChannelBeginning, MultiChannelBuffer const & parent )
:
firstChannelBeginning_ ( firstChannelBeginning ),
availableDataPerChannel_( 0 ),
parent_ ( parent )
{ parent.registerReader( *this ); }
private:
Buffer::const_iterator firstChannelBeginning_ ;
size_t availableDataPerChannel_;
MultiChannelBuffer const & parent_;
};
////////////////////////////////////////////////////////////////////////////////
//
// MultiChannelBuffer::Reader::ChannelIterator
// -------------------------------------------
//
// Models an iterator over channels (i.e. over, to the corresponding reader,
// available/readable chunks of those channels) of a Reader's
// MultiChannelBuffer.
//
// (todo) make it atleast resemble an STL-like iterator.
//
////////////////////////////////////////////////////////////////////////////////
class MultiChannelBuffer::Reader::ChannelIterator
{
public:
typedef Buffer::const_iterator const_iterator;
const_iterator const & begin() const { return currentBegin_; }
const_iterator end () const { return begin() + availableDataPerChannel_; }
size_t size() const { return availableDataPerChannel_; }
BYTE const * operator*() const { return &*begin(); }
ChannelIterator & operator++();
bool operator<( ChannelIterator const & other ) const { return currentBegin_ < other.currentBegin_; }
private:
void operator=( ChannelIterator const & );
private: // Reader private interface.
friend class Reader;
ChannelIterator( const_iterator const & firstChannel, size_t const availableDataPerChannel, size_t const channelSize )
:
currentBegin_ ( firstChannel ),
availableDataPerChannel_( availableDataPerChannel ),
channelSize_ ( channelSize )
{}
private:
const_iterator currentBegin_ ;
size_t availableDataPerChannel_;
size_t const channelSize_ ;
};
////////////////////////////////////////////////////////////////////////////////
//
// MultiChannelBuffer::WritePointers
// ---------------------------------
//
// Used by a MultiChannelBuffer to provide a writer with pointers/locations
// where to write the data and to report back to the MultiChannelBuffer when the
// write has finished (and thus new data is available).
//
////////////////////////////////////////////////////////////////////////////////
class MultiChannelBuffer::WritePointers
{
public:
BYTE * operator[]( size_t const index ) const { return &firstChannelWritePosition_[ index * channelSize_ ]; }
~WritePointers();
private: // MultiChannelBuffer private interface.
friend MultiChannelBuffer;
WritePointers( Buffer::iterator firstChannelWritePosition, size_t channelSize, size_t writeChunkSize, MultiChannelBuffer & parent );
private: // Non copyable.
void operator=( WritePointers const & );
public: // RVO does not seem to work for this class (only NVRO in release).
WritePointers ( WritePointers const & );
private:
Buffer::iterator const firstChannelWritePosition_;
size_t const channelSize_ ;
size_t const writeChunkSize_ ;
MultiChannelBuffer & parent_ ;
};
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.