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