PageRenderTime 1394ms CodeModel.GetById 1380ms RepoModel.GetById 1ms app.codeStats 0ms

/mordor/streams/memory.cpp

http://github.com/mozy/mordor
C++ | 199 lines | 167 code | 21 blank | 11 comment | 29 complexity | 417c411c02010732ef71742da4f14fc8 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. // Copyright (c) 2009 - Mozy, Inc.
  2. #include "memory.h"
  3. #include <stdexcept>
  4. #include "mordor/assert.h"
  5. namespace Mordor {
  6. MemoryStream::MemoryStream()
  7. : m_offset(0)
  8. {}
  9. MemoryStream::MemoryStream(const Buffer &b)
  10. : m_read(b),
  11. m_original(b),
  12. m_offset(0)
  13. {}
  14. size_t
  15. MemoryStream::read(Buffer &buffer, size_t length)
  16. {
  17. return readInternal(buffer, length);
  18. }
  19. size_t
  20. MemoryStream::read(void *buffer, size_t length)
  21. {
  22. return readInternal(buffer, length);
  23. }
  24. template <class T>
  25. size_t
  26. MemoryStream::readInternal(T &buffer, size_t length)
  27. {
  28. size_t todo = (std::min)(length, m_read.readAvailable());
  29. m_read.copyOut(buffer, todo);
  30. m_read.consume(todo);
  31. m_offset += todo;
  32. return todo;
  33. }
  34. size_t
  35. MemoryStream::write(const Buffer &buffer, size_t length)
  36. {
  37. return writeInternal(buffer, length);
  38. }
  39. size_t
  40. MemoryStream::write(const void *buffer, size_t length)
  41. {
  42. return writeInternal(buffer, length);
  43. }
  44. template <class T>
  45. size_t
  46. MemoryStream::writeInternal(const T &buffer, size_t length)
  47. {
  48. size_t size = m_original.readAvailable();
  49. if (m_offset == size) {
  50. m_original.copyIn(buffer, length);
  51. m_offset += length;
  52. } else if (m_offset > size) {
  53. // extend the stream, then write
  54. truncate(m_offset);
  55. m_original.copyIn(buffer, length);
  56. m_offset += length;
  57. } else {
  58. // write at offset
  59. Buffer original(m_original);
  60. // Truncate original to all data before the write
  61. m_original.truncate(m_offset);
  62. original.consume(m_offset);
  63. // copy in the write, advancing the stream pointer
  64. m_original.copyIn(buffer, length);
  65. m_offset += length;
  66. if (m_offset < size) {
  67. original.consume(length);
  68. // Copy in any remaining data beyond the write
  69. m_original.copyIn(original);
  70. // Reset our read buffer to the current stream pos
  71. m_read.clear();
  72. m_read.copyIn(original);
  73. }
  74. }
  75. return length;
  76. }
  77. long long
  78. MemoryStream::seek(long long offset, Anchor anchor)
  79. {
  80. size_t size = m_original.readAvailable();
  81. switch (anchor) {
  82. case BEGIN:
  83. if (offset < 0)
  84. MORDOR_THROW_EXCEPTION(std::invalid_argument("resulting offset is negative"));
  85. if ((unsigned long long)offset > (size_t)~0) {
  86. MORDOR_THROW_EXCEPTION(std::invalid_argument(
  87. "Memory stream position cannot exceed virtual address space."));
  88. }
  89. m_read.clear();
  90. m_read.copyIn(m_original, m_original.readAvailable());
  91. m_offset = (size_t)offset;
  92. m_read.consume((std::min)((size_t)offset, size));
  93. return (long long)m_offset;
  94. case CURRENT:
  95. if (offset < 0) {
  96. return seek(m_offset + offset, BEGIN);
  97. } else {
  98. // Optimized forward seek
  99. if (m_offset + offset > (size_t)~0) {
  100. MORDOR_THROW_EXCEPTION(std::invalid_argument(
  101. "Memory stream position cannot exceed virtual address space."));
  102. }
  103. if (m_offset <= size) {
  104. m_read.consume((std::min)((size_t)offset, size - m_offset));
  105. m_offset += (size_t)offset;
  106. }
  107. return (long long)m_offset;
  108. }
  109. case END:
  110. // Change this into a CURRENT to try and catch an optimized forward
  111. // seek
  112. return seek(size + offset - m_offset, CURRENT);
  113. default:
  114. MORDOR_ASSERT(false);
  115. return 0;
  116. }
  117. }
  118. long long
  119. MemoryStream::size()
  120. {
  121. return (long long)m_original.readAvailable();
  122. }
  123. void
  124. MemoryStream::truncate(long long size)
  125. {
  126. MORDOR_ASSERT(size >= 0);
  127. if ((unsigned long long)size > (size_t)~0) {
  128. MORDOR_THROW_EXCEPTION(std::invalid_argument(
  129. "Memory stream size cannot exceed virtual address space."));
  130. }
  131. size_t currentSize = m_original.readAvailable();
  132. if (currentSize == (size_t)size) {
  133. } else if (currentSize > (size_t)size) {
  134. m_original.truncate((size_t)size);
  135. if (m_offset > (size_t)size)
  136. m_read.clear();
  137. else
  138. m_read.truncate((size_t)size - m_offset);
  139. } else {
  140. size_t needed = (size_t)size - currentSize;
  141. m_original.reserve(needed);
  142. std::vector<iovec> iovs = m_original.writeBuffers(needed);
  143. for (std::vector<iovec>::iterator it(iovs.begin());
  144. it != iovs.end();
  145. ++it) {
  146. memset(it->iov_base, 0, it->iov_len);
  147. }
  148. m_original.produce(needed);
  149. // Reset the read buf so we're referencing the same memory
  150. m_read.clear();
  151. m_read.copyIn(m_original);
  152. m_read.consume((std::min)(m_offset, (size_t)size));
  153. }
  154. MORDOR_ASSERT(m_original.readAvailable() == (size_t)size);
  155. }
  156. ptrdiff_t
  157. MemoryStream::find(char delim, size_t sanitySize, bool throwIfNotFound)
  158. {
  159. ptrdiff_t result = m_read.find(delim,
  160. (std::min)(sanitySize, m_read.readAvailable()));
  161. if (result != -1)
  162. return result;
  163. if (throwIfNotFound)
  164. MORDOR_THROW_EXCEPTION(UnexpectedEofException());
  165. return -(ptrdiff_t)m_read.readAvailable() - 1;
  166. }
  167. ptrdiff_t
  168. MemoryStream::find(const std::string &str, size_t sanitySize, bool throwIfNotFound)
  169. {
  170. ptrdiff_t result = m_read.find(str,
  171. (std::min)(sanitySize, m_read.readAvailable()));
  172. if (result != -1)
  173. return result;
  174. if (throwIfNotFound)
  175. MORDOR_THROW_EXCEPTION(UnexpectedEofException());
  176. return -(ptrdiff_t)m_read.readAvailable() - 1;
  177. }
  178. }