CXStream

From cxwiki

Revision as of 05:48, 26 February 2018 by Windwalkr (talk | contribs)

The CXStream class hierarchy provides support for readable and writeable streams, ranging from file streams and network sockets to adaptors such as data codecs. The underlying functionality is virtual, but non-virtual caching operations are provided transparently to avoid exessive virtual call overhead. As much as is possible, CXStream-derived classes provide completely generic behaviour, and CXStream-utilising functions accept a base CXStream* rather than specifying a more specialised derived type. This allows an application to create a CXStream of any type (potentially even creating something new) and pass it to an existing function or system.
 
This page documents the usage of CXStream (and its derived classes). For guidance on creating new CXStream-derived classes, see CXStream Development.
 
Any given CXStream-derived object may be used on any thread, or passed between threads, but is NOT reentrant, except where specifically noted.
 
It is expected that CXStream implementations will closely follow the expected behaviour detailed in this document. In scenarios where customised behaviour may be preferrable, that behaviour should either be exposed through additional APIs which do not affect the behaviour of the standard APIs, or via additional capabilities flags which should be explicitly enabled.
 

Read / Write

// Read from the current read cursor position in this stream. If the
// size is greater than zero, the output buffer must be non-null. The
// return value is the number of bytes successfully read.
// This function will normally block until the requested number of
// bytes have been read or until an error condition has resulted
// (eg. end-of-file, i/o error, disconnected, etc.) A non-blocking
// stream (which is not the default behaviour) will instead return
// after any non-zero number of bytes has been read, without 
// raising an error status.
StreamSize Read(void* __nullable o_buffer, StreamSize size);

// Writes to the current write cursor position in this stream. If
// the size is gerater than zero, the input buffer must be non-null.
// The return value is the number of bytes succesfully written.
// This function will normally block until the requested number of
// bytes have been written, or until an error condition has resulted
// (eg. end-of-file, i/o error, disconnected, etc.) A non-blocking
// stream (which is not the default behaviour) will instead return
// after any non-zero number of bytes has been written, without
// raising an error status.
StreamSize Write(const void* __nullable buffer, StreamSize size);

// Semantically equivalent to calling Read() with the specified
// size and then discarding the buffer. This may be more 
// performant in some implementations.
CXStream::StreamSize ReadDiscard(CXStream::StreamSize a_size);

// Semantically equivalent to calling Write(), however the
// implementation is free to write alternative data (including
// but not limited to all zeroes) or simply seek over the
// specified number of bytes. This may be used where an empty
// space is being left in the stream that is expected to be
// filled at a later time. The stream size and cursor are
// affected in the same manner as if this was a regular Write().
CXStream::StreamSize WriteDiscard(const void* __nonnull a_buffer, StreamSize a_size);

// Flush any cached or asychronous writes to the backing store.
// Since i/o error conditions (etc.) are not detectable until the
// actual output operation is attempted, it is necessary to call
// Flush() before GetStreamResult() if an accurate outcome is
// required.
void Flush(FlushFlags flags = FLUSH_FLAGS_BLOCK);

 

Cursor

//
StreamPos Seek(StreamPos a_pos, uint a_mode = STREAM_SEEK_START);

//
StreamPos Tell(void) const;

//
StreamSize GetSize(void) const;

//
void SetSize(StreamSize size);

//
void Truncate(void)

//
StreamSize GetRemain(void) const;

//
bool GetRemain(StreamSize& o_remain) const;

// End-of-File detection
bool IsEOF(void) const;

 

Capabilities Flags

enum
{
  CAPS_READ = 1,       // stream is readable
  CAPS_WRITE = 2,      // stream is writable
  CAPS_SIZE = 4,       // stream provider supports GetSize() and STREAM_SEEK_END
  CAPS_SEEK = 8,       // stream provider supports Seek() -- usually you actually want CAPS_TELL
  CAPS_TELL = 16,      // stream provider supports Tell()
  CAPS_UNIFIED_CURSOR = 32,    // stream has unified read / write cursor -- ie. Tell() is affected by both Read() and Write()
  CAPS_NO_REWIND = 64,  // stream cannot seek backwards, and GetSize() returns the number of bytes after the current position
  CAPS_SEEK_IN_WRITE_CACHE = 128, // since the original implementation did not support this, we have to flag if we support the technique.

  // "flag" caps
  CAPS_OPEN = 256,     // stream is open
  CAPS_EOF = 512,       // stream is known to be at the EOF position

  //
  CAPS_NON_BLOCKING = 1024,     // stream is in non-blocking mode
};

 

 

// get the capabilities flags for this stream
Flags32 GetCaps(void) const;

// request a change of capabilities for this stream
void SetCaps(const Flags32& caps, const Flags32& mask);

//
void SetCaps(const Flags32& caps);

//
void ClearCaps(const Flags32& caps);

// Provider-specific hints
void SetHint(uint32 hintEnum, uint32 hintValue);

 

Status

// Determine the last error that has occurred.
// Note: see Flush().
CXResultCode GetStreamResult(void) const;

// clear the error result
void ClearStreamResult(void);

//
void SetStreamResult(CXResultCode a_result) const;

//
void ConcatenateResult(CXResultCode a_result) const;

// shut down this stream, ready for another Open()
void Close(void);

//
bool IsOpen(void) const;

//
bool IsClosed(void) const;


 

 

Events

 

CXGenericEventRef GetStreamEvent(EventType eventType) const;