Buffer.hh 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * https://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. #ifndef avro_Buffer_hh__
  19. #define avro_Buffer_hh__
  20. #ifndef _WIN32
  21. #include <sys/uio.h>
  22. #endif
  23. #include <utility>
  24. #include <vector>
  25. #include "../Config.hh"
  26. #include "detail/BufferDetail.hh"
  27. #include "detail/BufferDetailIterator.hh"
  28. /**
  29. * \file Buffer.hh
  30. *
  31. * \brief Definitions for InputBuffer and OutputBuffer classes
  32. *
  33. **/
  34. namespace avro {
  35. class OutputBuffer;
  36. class InputBuffer;
  37. /**
  38. * The OutputBuffer (write-only buffer)
  39. *
  40. * Use cases for OutputBuffer
  41. *
  42. * - write message to buffer using ostream class or directly
  43. * - append messages to headers
  44. * - building up streams of messages via append
  45. * - converting to read-only buffers for sending
  46. * - extracting parts of the messages into read-only buffers
  47. *
  48. * -# ASIO access:
  49. * - write to a buffer(s) by asio using iterator
  50. * - convert to read buffer for deserializing
  51. *
  52. * OutputBuffer is assignable and copy-constructable. On copy or assignment,
  53. * only a pointer is copied, so the two resulting copies are identical, so
  54. * modifying one will modify both.
  55. **/
  56. class AVRO_DECL OutputBuffer {
  57. public:
  58. typedef detail::size_type size_type;
  59. typedef detail::data_type data_type;
  60. /**
  61. * The asio library expects a const_iterator (the const-ness refers to the
  62. * fact that the underlying avro of buffers will not be modified, even
  63. * though the data in those buffers is being modified). The iterator
  64. * provides the list of addresses an operation can write to.
  65. **/
  66. typedef detail::OutputBufferIterator const_iterator;
  67. /**
  68. * Default constructor. Will pre-allocate at least the requested size, but
  69. * can grow larger on demand.
  70. *
  71. * Destructor uses the default, which resets a shared pointer, deleting the
  72. * underlying data if no other copies of exist.
  73. *
  74. * Copy and assignment operators are not explicitly provided because the
  75. * default ones work fine. The default makes only a shallow copy, so the
  76. * copies will refer to the same memory. This is required by asio
  77. * functions, which will implicitly make copies for asynchronous
  78. * operations. Therefore, the user must be careful that if they create
  79. * multiple copies of the same OutputBuffer, only one is being modified
  80. * otherwise undefined behavior may occur.
  81. *
  82. **/
  83. explicit OutputBuffer(size_type reserveSize = 0) : pimpl_(new detail::BufferImpl) {
  84. if (reserveSize) {
  85. reserve(reserveSize);
  86. }
  87. }
  88. /**
  89. * Reserve enough space for a wroteTo() operation. When using writeTo(),
  90. * the buffer will grow dynamically as needed. But when using the iterator
  91. * to write (followed by wroteTo()), data may only be written to the space
  92. * available, so this ensures there is enough room in the buffer before
  93. * the write operation.
  94. **/
  95. void reserve(size_type reserveSize) {
  96. pimpl_->reserveFreeSpace(reserveSize);
  97. }
  98. /**
  99. * Write a block of data to the buffer. The buffer size will automatically
  100. * grow if the size is larger than what is currently free.
  101. **/
  102. size_type writeTo(const data_type *data, size_type size) {
  103. return pimpl_->writeTo(data, size);
  104. }
  105. /**
  106. * Write a single value to the buffer. The buffer size will automatically
  107. * grow if there is not room for the byte. The value must be a
  108. * "fundamental" type, e.g. int, float, etc. (otherwise use the other
  109. * writeTo tests).
  110. **/
  111. template<typename T>
  112. void writeTo(T val) {
  113. pimpl_->writeTo(val, std::is_fundamental<T>());
  114. }
  115. /**
  116. * Update the state of the buffer after writing through the iterator
  117. * interface. This function exists primarily for the boost:asio which
  118. * writes directly to the buffer using its iterator. In this case, the
  119. * internal state of the buffer does not reflect that the data was written
  120. * This informs the buffer how much data was written.
  121. *
  122. * The buffer does not automatically resize in this case, the bytes written
  123. * cannot exceed the amount of free space. Attempting to write more will
  124. * throw a std::length_error exception.
  125. **/
  126. size_type wroteTo(size_type size) {
  127. size_type wrote = 0;
  128. if (size) {
  129. if (size > freeSpace()) {
  130. throw std::length_error("Impossible to write more data than free space");
  131. }
  132. wrote = pimpl_->wroteTo(size);
  133. }
  134. return wrote;
  135. }
  136. /**
  137. * Does the buffer have any data?
  138. **/
  139. bool empty() const {
  140. return (pimpl_->size() == 0);
  141. }
  142. /**
  143. * Returns the size of the buffer, in bytes.
  144. */
  145. size_type size() const {
  146. return pimpl_->size();
  147. }
  148. /**
  149. * Returns the current free space that is available to write to in the
  150. * buffer, in bytes. This is not a strict limit in size, as writeTo() can
  151. * automatically increase capacity if necessary.
  152. **/
  153. size_type freeSpace() const {
  154. return pimpl_->freeSpace();
  155. }
  156. /**
  157. * Appends the data in the argument to the end of this buffer. The
  158. * argument can be either an InputBuffer or OutputBuffer.
  159. *
  160. **/
  161. template<class BufferType>
  162. void append(const BufferType &buf) {
  163. // don't append an empty buffer
  164. if (buf.size()) {
  165. pimpl_->append(*(buf.pimpl_.get()));
  166. }
  167. }
  168. /**
  169. * Return an iterator pointing to the first data chunk of this buffer
  170. * that may be written to.
  171. **/
  172. const_iterator begin() const {
  173. return const_iterator(pimpl_->beginWrite());
  174. }
  175. /**
  176. * Return the end iterator for writing.
  177. **/
  178. const_iterator end() const {
  179. return const_iterator(pimpl_->endWrite());
  180. }
  181. /**
  182. * Discard any data in this buffer.
  183. **/
  184. void discardData() {
  185. pimpl_->discardData();
  186. }
  187. /**
  188. * Discard the specified number of bytes from this data, starting at the beginning.
  189. * Throws if the size is greater than the number of bytes.
  190. **/
  191. void discardData(size_t bytes) {
  192. if (bytes > 0) {
  193. if (bytes < pimpl_->size()) {
  194. pimpl_->discardData(bytes);
  195. } else if (bytes == pimpl_->size()) {
  196. pimpl_->discardData();
  197. } else {
  198. throw std::out_of_range("trying to discard more data than exists");
  199. }
  200. }
  201. }
  202. /**
  203. * Remove bytes from this buffer, starting from the beginning, and place
  204. * them into a new buffer. Throws if the number of requested bytes exceeds
  205. * the size of the buffer. Data and freeSpace in the buffer after bytes
  206. * remains in this buffer.
  207. **/
  208. InputBuffer extractData(size_type bytes);
  209. /**
  210. * Remove all bytes from this buffer, returning them in a new buffer.
  211. * After removing data, some freeSpace may remain in this buffer.
  212. **/
  213. InputBuffer extractData();
  214. /**
  215. * Clone this buffer, creating a copy that contains the same data.
  216. **/
  217. OutputBuffer clone() const {
  218. detail::BufferImpl::SharedPtr newImpl(new detail::BufferImpl(*pimpl_));
  219. return OutputBuffer(newImpl);
  220. }
  221. /**
  222. * Add unmanaged data to the buffer. The buffer will not automatically
  223. * free the data, but it will call the supplied function when the data is
  224. * no longer referenced by the buffer (or copies of the buffer).
  225. **/
  226. void appendForeignData(const data_type *data, size_type size, const detail::free_func &func) {
  227. pimpl_->appendForeignData(data, size, func);
  228. }
  229. /**
  230. * Returns the number of chunks that contain free space.
  231. **/
  232. int numChunks() const {
  233. return pimpl_->numFreeChunks();
  234. }
  235. /**
  236. * Returns the number of chunks that contain data
  237. **/
  238. int numDataChunks() const {
  239. return pimpl_->numDataChunks();
  240. }
  241. private:
  242. friend class InputBuffer;
  243. friend class BufferReader;
  244. explicit OutputBuffer(detail::BufferImpl::SharedPtr pimpl) : pimpl_(std::move(pimpl)) {}
  245. detail::BufferImpl::SharedPtr pimpl_; ///< Must never be null.
  246. };
  247. /**
  248. * The InputBuffer (read-only buffer)
  249. *
  250. * InputBuffer is an immutable buffer which that may be constructed from an
  251. * OutputBuffer, or several of OutputBuffer's methods. Once the data is
  252. * transfered to an InputBuffer it cannot be modified, only read (via
  253. * BufferReader, istream, or its iterator).
  254. *
  255. * Assignments and copies are shallow copies.
  256. *
  257. * -# ASIO access: - iterate using const_iterator for sending messages
  258. *
  259. **/
  260. class AVRO_DECL InputBuffer {
  261. public:
  262. typedef detail::size_type size_type;
  263. typedef detail::data_type data_type;
  264. // needed for asio
  265. typedef detail::InputBufferIterator const_iterator;
  266. /**
  267. * Default InputBuffer creates an empty buffer.
  268. *
  269. * Copy/assignment functions use the default ones. They will do a shallow
  270. * copy, and because InputBuffer is immutable, the copies will be
  271. * identical.
  272. *
  273. * Destructor also uses the default, which resets a shared pointer,
  274. * deleting the underlying data if no other copies of exist.
  275. **/
  276. InputBuffer() : pimpl_(new detail::BufferImpl) {}
  277. /**
  278. * Construct an InputBuffer that contains the contents of an OutputBuffer.
  279. * The two buffers will have the same contents, but this copy will be
  280. * immutable, while the the OutputBuffer may still be written to.
  281. *
  282. * If you wish to move the data from the OutputBuffer to a new InputBuffer
  283. * (leaving only free space in the OutputBuffer),
  284. * OutputBuffer::extractData() will do this more efficiently.
  285. *
  286. * Implicit conversion is allowed.
  287. **/
  288. // NOLINTNEXTLINE(google-explicit-constructor)
  289. InputBuffer(const OutputBuffer &src) : pimpl_(new detail::BufferImpl(*src.pimpl_)) {}
  290. /**
  291. * Does the buffer have any data?
  292. **/
  293. bool empty() const {
  294. return (pimpl_->size() == 0);
  295. }
  296. /**
  297. * Returns the size of the buffer, in bytes.
  298. **/
  299. size_type size() const {
  300. return pimpl_->size();
  301. }
  302. /**
  303. * Return an iterator pointing to the first data chunk of this buffer
  304. * that contains data.
  305. **/
  306. const_iterator begin() const {
  307. return const_iterator(pimpl_->beginRead());
  308. }
  309. /**
  310. * Return the end iterator.
  311. **/
  312. const_iterator end() const {
  313. return const_iterator(pimpl_->endRead());
  314. }
  315. /**
  316. * Returns the number of chunks containing data.
  317. **/
  318. int numChunks() const {
  319. return pimpl_->numDataChunks();
  320. }
  321. private:
  322. friend class OutputBuffer; // for append function
  323. friend class istreambuf;
  324. friend class BufferReader;
  325. explicit InputBuffer(const detail::BufferImpl::SharedPtr &pimpl) : pimpl_(pimpl) {}
  326. /**
  327. * Class to indicate that a copy of a OutputBuffer to InputBuffer should be
  328. * a shallow copy, used to enable reading of the contents of an
  329. * OutputBuffer without need to convert it to InputBuffer using a deep
  330. * copy. It is private and only used by BufferReader and istreambuf
  331. * classes.
  332. *
  333. * Writing to an OutputBuffer while it is being read may lead to undefined
  334. * behavior.
  335. **/
  336. class ShallowCopy {};
  337. /**
  338. * Make a shallow copy of an OutputBuffer in order to read it without
  339. * causing conversion overhead.
  340. **/
  341. InputBuffer(const OutputBuffer &src, const ShallowCopy &) : pimpl_(src.pimpl_) {}
  342. /**
  343. * Make a shallow copy of an InputBuffer. The default copy constructor
  344. * already provides shallow copy, this is just provided for generic
  345. * algorithms that wish to treat InputBuffer and OutputBuffer in the same
  346. * manner.
  347. **/
  348. InputBuffer(const InputBuffer &src, const ShallowCopy &) : pimpl_(src.pimpl_) {}
  349. detail::BufferImpl::ConstSharedPtr pimpl_; ///< Must never be null.
  350. };
  351. /*
  352. * Implementations of some OutputBuffer functions are inlined here
  353. * because InputBuffer definition was required before.
  354. */
  355. inline InputBuffer OutputBuffer::extractData() {
  356. detail::BufferImpl::SharedPtr newImpl(new detail::BufferImpl);
  357. if (pimpl_->size()) {
  358. pimpl_->extractData(*newImpl);
  359. }
  360. return InputBuffer(newImpl);
  361. }
  362. inline InputBuffer OutputBuffer::extractData(size_type bytes) {
  363. if (bytes > pimpl_->size()) {
  364. throw std::out_of_range("trying to extract more data than exists");
  365. }
  366. detail::BufferImpl::SharedPtr newImpl(new detail::BufferImpl);
  367. if (bytes > 0) {
  368. if (bytes < pimpl_->size()) {
  369. pimpl_->extractData(*newImpl, bytes);
  370. } else {
  371. pimpl_->extractData(*newImpl);
  372. }
  373. }
  374. return InputBuffer(newImpl);
  375. }
  376. #ifndef _WIN32
  377. /**
  378. * Create an array of iovec structures from the buffer. This utility is used
  379. * to support writev and readv function calls. The caller should ensure the
  380. * buffer object is not deleted while using the iovec vector.
  381. *
  382. * If the BufferType is an InputBuffer, the iovec will point to the data that
  383. * already exists in the buffer, for reading.
  384. *
  385. * If the BufferType is an OutputBuffer, the iovec will point to the free
  386. * space, which may be written to. Before writing, the caller should call
  387. * OutputBuffer::reserve() to create enough room for the desired write (which
  388. * can be verified by calling OutputBuffer::freeSpace()), and after writing,
  389. * they MUST call OutputBuffer::wroteTo(), otherwise the buffer will not know
  390. * the space is not free anymore.
  391. *
  392. **/
  393. template<class BufferType>
  394. inline void toIovec(BufferType &buf, std::vector<struct iovec> &iov) {
  395. const int chunks = buf.numChunks();
  396. iov.resize(chunks);
  397. typename BufferType::const_iterator iter = buf.begin();
  398. for (int i = 0; i < chunks; ++i) {
  399. iov[i].iov_base = const_cast<typename BufferType::data_type *>(iter->data());
  400. iov[i].iov_len = iter->size();
  401. ++iter;
  402. }
  403. }
  404. #endif
  405. } // namespace avro
  406. #endif