PageRenderTime 25ms CodeModel.GetById 8ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

/mordor/streams/stream.h

http://github.com/mozy/mordor
C Header | 254 lines | 66 code | 28 blank | 160 comment | 0 complexity | 99c93a57afcb4ee649f2439ca547df62 MD5 | raw file
  1#ifndef __MORDOR_STREAM_H__
  2#define __MORDOR_STREAM_H__
  3// Copyright (c) 2009 - Mozy, Inc.
  4
  5#include <string>
  6
  7#include <boost/noncopyable.hpp>
  8#include <boost/shared_ptr.hpp>
  9#include <boost/signals2/signal.hpp>
 10
 11#include "mordor/predef.h"
 12
 13namespace Mordor {
 14
 15struct Buffer;
 16
 17/// @brief Byte-oriented stream
 18/// @details
 19/// Stream is the main interface for dealing with a stream of data.  It can
 20/// represent half or full duplex streams, as well as random access streams
 21/// or sequential only streams.  By default, a Stream advertises that it
 22/// cannot support any operations, and calling any of them will result in an
 23/// assertion.  close() and flush() are always safe to call.
 24///
 25/// Streams are not thread safe, except for cancelRead() and cancelWrite(),
 26/// and it is safe to call read() at the same time as write() (assuming the
 27/// Stream supports both, and don't supportSeek()).  read() and write() are
 28/// @b not re-entrant.
 29class Stream : boost::noncopyable
 30{
 31public:
 32    typedef boost::shared_ptr<Stream> ptr;
 33
 34    /// Flags for which end of a Stream to close
 35    enum CloseType {
 36        /// Neither (should not be passed to close(); only useful for keeping
 37        /// track of the current state of a Stream)
 38        NONE  = 0x00,
 39        /// Further reads from this Stream should fail;
 40        /// further writes on the "other" end of this Stream should fail.
 41        READ  = 0x01,
 42        /// Further writes to this Stream should fail;
 43        /// further reads on the "other" end of this Stream should receive EOF.
 44        WRITE = 0x02,
 45        /// The default; closes both the read and write directions
 46        BOTH  = 0x03
 47    };
 48
 49    /// Flags for where to seek from
 50    enum Anchor {
 51        /// Relative to the beginning of the stream
 52        BEGIN,
 53        /// Relative to the current position in the stream
 54        CURRENT,
 55        /// Relative to the end of the stream
 56        END
 57    };
 58
 59public:
 60    /// Cleans up the underlying implementation, possibly by ungracefully
 61    /// closing it.
 62    virtual ~Stream() {}
 63
 64    /// @return If it is valid to call close() with READ or WRITE
 65    virtual bool supportsHalfClose() { return false; }
 66    /// @return If it is valid to call read()
 67    virtual bool supportsRead() { return false; }
 68    /// @return If it is valid to call write()
 69    virtual bool supportsWrite() { return false; }
 70    /// @return If it is valid to call seek() with any parameters
 71    virtual bool supportsSeek() { return false; }
 72    /// @note
 73    /// If supportsSeek(), then the default implementation supportsTell().
 74    /// @return If it is valid to call tell() or call seek(0, CURRENT)
 75    virtual bool supportsTell() { return supportsSeek(); }
 76    /// @return If it is valid to call size()
 77    virtual bool supportsSize() { return false; }
 78    /// @return If it is valid to call truncate()
 79    virtual bool supportsTruncate() { return false; }
 80    /// @return If it is valid to call find()
 81    virtual bool supportsFind() { return false; }
 82    /// @return If it is valid to call unread()
 83    virtual bool supportsUnread() { return false; }
 84
 85    /// @brief Gracefully close the Stream
 86    /// @details
 87    /// It is valid to call close() multiple times without error.
 88    /// @param type Which ends of the stream to close
 89    /// @pre type == BOTH || type == READ || type == WRITE
 90    /// @pre if (type != BOTH) supportsHalfClose()
 91    virtual void close(CloseType type = BOTH) {}
 92
 93    /// @brief Read data from the Stream
 94    /// @details
 95    /// read() is allowed to return less than length, even if there is more
 96    /// data available. A return value of 0 is the @b only reliable method of
 97    /// detecting EOF. If an exception is thrown, you can be assured that
 98    /// nothing was read from the underlying implementation.
 99    /// @param buffer The Buffer to read in to
100    /// @param length The maximum amount to read
101    /// @return The amount actually read
102    /// @pre supportsRead()
103    virtual size_t read(Buffer &buffer, size_t length);
104    /// @copydoc read(Buffer &, size_t)
105    /// @brief Convenience function to call read() without first creating a
106    /// Buffer
107    /// @note
108    /// A default implementation is provided which calls
109    /// read(Buffer &, size_t).  Only implement if it can be more efficient
110    /// than creating a new Buffer.
111    virtual size_t read(void *buffer, size_t length);
112    /// @brief Cancels a read that is currently blocked
113    /// @details
114    /// Must be called from a different Fiber/Thread than the one that is
115    /// blocked. This is safe to call on any Stream, but may not have any
116    /// effect.
117    virtual void cancelRead() {}
118
119    /// @brief Write data to the Stream
120    /// @details
121    /// write() is allowed to return less than length. If is @b not allowed to
122    /// return 0. If an exception is thrown, you can be assured that nothing
123    /// was written to the underlying implementation.
124    /// @pre @c buffer.readAvailable() >= @c length
125    /// @return The amount actually written
126    /// @pre supportsWrite()
127    virtual size_t write(const Buffer &buffer, size_t length);
128
129    /// @copydoc write(const Buffer &, size_t)
130    /// @brief Convenience function to call write() without first creating a
131    /// Buffer
132    /// @note
133    /// A default implementation is provided which calls
134    /// write(const Buffer &, size_t).  Only implement if it can be more
135    /// efficient than creating a new Buffer.
136    virtual size_t write(const void *buffer, size_t length);
137    /// @copydoc write(const Buffer &, size_t)
138    /// @brief
139    /// Convenience function to call write() with a null-terminated string
140    /// @note
141    /// A default implementation is provided which calls
142    /// write(const void *, size_t).  Cannot be overridden.
143    size_t write(const char *string);
144    /// @brief Cancels a write that is currently blocked
145    /// @details
146    /// Must be called from a different Fiber/Thread than the one that is
147    /// blocked. This is safe to call on any Stream, but may not have any
148    /// effect.
149    virtual void cancelWrite() {}
150
151    /// @brief Change the current stream pointer
152    /// @param offset Where to seek to
153    /// @param anchor Where to seek from
154    /// @exception std::invalid_argument The resulting position would be
155    /// negative
156    /// @return The new stream pointer position
157    /// @pre supportsSeek() || supportsTell()
158    virtual long long seek(long long offset, Anchor anchor = BEGIN);
159
160    /// @brief Convenience method to call seek(0, CURRENT)
161    /// @note Cannot be overridden.
162    /// @return The current stream pointer position
163    /// @pre supportsTell()
164    long long tell() { return seek(0, CURRENT); }
165
166    /// @brief Return the size of the stream
167    /// @return The size of the stream
168    /// @pre supportsSize()
169    virtual long long size();
170
171    /// @brief Truncate the stream
172    /// @param size The new size of the stream
173    /// @pre supportsTruncate()
174    virtual void truncate(long long size);
175
176    /// @brief Flush the stream
177
178    /// flush() ensures that nothing is left in internal buffers, and has been
179    /// fully written to the underlying implementation.  It is safe to call
180    /// flush() on any Stream.  In some cases, flush() may not return until
181    /// all data has been read from the other end of a pipe-like Stream.
182    /// @param flushParent Also flush() a parent stream(), if there is one
183    virtual void flush(bool flushParent = true) {}
184
185    //@{
186    /// @brief Find a delimiter by looking ahead in the stream
187    /// @param delimiter The byte to look for
188    /// @param sanitySize The maximum amount to look ahead before throwing an
189    /// exception
190    /// @param throwIfNotFound Instead of throwing an exception on error, it
191    /// will return a negative number.  Negate and subtract 1 to find out how
192    /// much buffered data is available before hitting the error
193    /// @exception BufferOverflowException @c delimiter was not found before
194    /// @c sanitySize
195    /// @exception UnexpectedEofException EOF was reached without finding
196    /// @c delimiter
197    /// @return Offset from the current stream position of the found
198    /// @c delimiter
199    /// @pre supportsFind()
200    virtual ptrdiff_t find(char delimiter, size_t sanitySize = ~0,
201        bool throwIfNotFound = true);
202    virtual ptrdiff_t find(const std::string &delimiter,
203        size_t sanitySize = ~0, bool throwIfNotFound = true);
204    //@}
205
206    /// @brief Convenience function for calling find() then read(), and return
207    /// the results in a std::string
208    /// @details
209    /// getDelimited() is provided so that users of the Stream class do not
210    /// need to be aware of if or where a Stream that supportsFind() is in
211    /// the stack of FilterStreams, and forcing all FilterStreams to deal with
212    /// it. Instead, the operaton is broken up into find() and read().
213    /// FilterStreams just pass the find() on to the parent, and do their stuff
214    /// on the actual data as they see it in the read().
215    /// @note Cannot be overridden.
216    /// @param delimiter The byte to look for
217    /// @param eofIsDelimiter Instead of throwing an exception if the delimiter
218    /// is not found, return the remainder of the stream.
219    /// @param includeDelimiter Include the delimiter in returned string
220    /// @return The data from the current stream position up to and possibly
221    /// including the delimiter
222    /// @pre supportsFind() && supportsRead()
223    std::string getDelimited(char delimiter = '\n',
224        bool eofIsDelimiter = false, bool includeDelimiter = true);
225    std::string getDelimited(const std::string &delimiter,
226        bool eofIsDelimiter = false, bool includeDelimiter = true);
227
228    /// @brief Return data to the stream to be read again
229
230    /// @param buffer The data to return
231    /// @param length How much data to return
232    /// @pre @c buffer.readAvailable() >= @c length
233    /// @pre supportsUnread()
234    virtual void unread(const Buffer &buffer, size_t length);
235
236    /// Event triggered when the remote end of the connection closes the
237    /// virtual circuit
238    ///
239    /// This event is triggered out-of-band of any read operation (i.e. there
240    /// may still be data to be read after this event has been received)
241    /// @note This event is optional, and will return a disconnected connection
242    /// if it is not supported.
243    virtual boost::signals2::connection onRemoteClose(
244        const boost::signals2::slot<void ()> &slot)
245    { return boost::signals2::connection(); }
246
247protected:
248    size_t read(Buffer &buffer, size_t length, bool coalesce);
249    size_t write(const Buffer &buffer, size_t length, bool coalesce);
250};
251
252}
253
254#endif