PageRenderTime 30ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llmessage/llbuffer.h

https://bitbucket.org/lindenlab/viewer-beta/
C++ Header | 625 lines | 118 code | 59 blank | 448 comment | 0 complexity | e3f0ce10aa6bdaaf439b4e2ad6d2bbdd MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llbuffer.h
  3. * @author Phoenix
  4. * @date 2005-09-20
  5. * @brief Declaration of buffer and buffer arrays primarily used in I/O.
  6. *
  7. * $LicenseInfo:firstyear=2005&license=viewerlgpl$
  8. * Second Life Viewer Source Code
  9. * Copyright (C) 2010, Linden Research, Inc.
  10. *
  11. * This library is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU Lesser General Public
  13. * License as published by the Free Software Foundation;
  14. * version 2.1 of the License only.
  15. *
  16. * This library is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. * Lesser General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Lesser General Public
  22. * License along with this library; if not, write to the Free Software
  23. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  24. *
  25. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  26. * $/LicenseInfo$
  27. */
  28. #ifndef LL_LLBUFFER_H
  29. #define LL_LLBUFFER_H
  30. /**
  31. * Declaration of classes used for minimizing calls to new[],
  32. * memcpy(), and delete[]. Typically, you would create an LLBufferArray,
  33. * feed it data, modify and add segments as you process it, and feed
  34. * it to a sink.
  35. */
  36. #include <list>
  37. #include <vector>
  38. class LLMutex;
  39. /**
  40. * @class LLChannelDescriptors
  41. * @brief A way simple interface to accesss channels inside a buffer
  42. */
  43. class LLChannelDescriptors
  44. {
  45. public:
  46. // enumeration for segmenting the channel information
  47. enum { E_CHANNEL_COUNT = 3 };
  48. LLChannelDescriptors() : mBaseChannel(0) {}
  49. explicit LLChannelDescriptors(S32 base) : mBaseChannel(base) {}
  50. S32 in() const { return mBaseChannel; }
  51. S32 out() const { return mBaseChannel + 1; }
  52. //S32 err() const { return mBaseChannel + 2; }
  53. protected:
  54. S32 mBaseChannel;
  55. };
  56. /**
  57. * @class LLSegment
  58. * @brief A segment is a single, contiguous chunk of memory in a buffer
  59. *
  60. * Each segment represents a contiguous addressable piece of memory
  61. * which is located inside a buffer. The segment is not responsible
  62. * for allocation or deallcoation of the data. Each segment is a light
  63. * weight object, and simple enough to copy around, use, and generate
  64. * as necessary.
  65. * This is the preferred interface for working with memory blocks,
  66. * since it is the only way to safely, inexpensively, and directly
  67. * access linear blocks of memory.
  68. */
  69. class LLSegment
  70. {
  71. public:
  72. LLSegment();
  73. LLSegment(S32 channel, U8* data, S32 data_len);
  74. ~LLSegment();
  75. /**
  76. * @brief Check if this segment is on the given channel.
  77. *
  78. */
  79. bool isOnChannel(S32 channel) const;
  80. /**
  81. * @brief Get the channel
  82. */
  83. S32 getChannel() const;
  84. /**
  85. * @brief Set the channel
  86. */
  87. void setChannel(S32 channel);
  88. /**
  89. * @brief Return a raw pointer to the current data set.
  90. *
  91. * The pointer returned can be used for reading or even adjustment
  92. * if you are a bit crazy up to size() bytes into memory.
  93. * @return A potentially NULL pointer to the raw buffer data
  94. */
  95. U8* data() const;
  96. /**
  97. * @brief Return the size of the segment
  98. */
  99. S32 size() const;
  100. /**
  101. * @brief Check if two segments are the same.
  102. *
  103. * Two segments are considered equal if they are on the same
  104. * channel and cover the exact same address range.
  105. * @param rhs the segment to compare with this segment.
  106. * @return Returns true if they are equal.
  107. */
  108. bool operator==(const LLSegment& rhs) const;
  109. protected:
  110. S32 mChannel;
  111. U8* mData;
  112. S32 mSize;
  113. };
  114. /**
  115. * @class LLBuffer
  116. * @brief Abstract base class for buffers
  117. *
  118. * This class declares the interface necessary for buffer arrays. A
  119. * buffer is not necessarily a single contiguous memory chunk, so
  120. * please do not circumvent the segment API.
  121. */
  122. class LLBuffer
  123. {
  124. public:
  125. /**
  126. * @brief The buffer base class should have no responsibilities
  127. * other than an interface.
  128. */
  129. virtual ~LLBuffer() {}
  130. /**
  131. * @brief Generate a segment for this buffer.
  132. *
  133. * The segment returned is always contiguous memory. This call can
  134. * fail if no contiguous memory is available, eg, offset is past
  135. * the end. The segment returned may be smaller than the requested
  136. * size. The segment will never be larger than the requested size.
  137. * @param channel The channel for the segment.
  138. * @param offset The offset from zero in the buffer.
  139. * @param size The requested size of the segment.
  140. * @param segment[out] The out-value from the operation
  141. * @return Returns true if a segment was found.
  142. */
  143. virtual bool createSegment(S32 channel, S32 size, LLSegment& segment) = 0;
  144. /**
  145. * @brief Reclaim a segment from this buffer.
  146. *
  147. * This method is called on a buffer object when a caller is done
  148. * with a contiguous segment of memory inside this buffer. Since
  149. * segments can be cut arbitrarily outside of the control of the
  150. * buffer, this segment may not match any segment returned from
  151. * <code>createSegment()</code>.
  152. * @param segment The contiguous buffer segment to reclaim.
  153. * @return Returns true if the call was successful.
  154. */
  155. virtual bool reclaimSegment(const LLSegment& segment) = 0;
  156. /**
  157. * @brief Test if a segment is inside this buffer.
  158. *
  159. * @param segment The contiguous buffer segment to test.
  160. * @return Returns true if the segment is in the bufffer.
  161. */
  162. virtual bool containsSegment(const LLSegment& segment) const = 0;
  163. /**
  164. * @brief Return the current number of bytes allocated.
  165. *
  166. * This was implemented as a debugging tool, and it is not
  167. * necessarily a good idea to use it for anything else.
  168. */
  169. virtual S32 capacity() const = 0;
  170. };
  171. /**
  172. * @class LLHeapBuffer
  173. * @brief A large contiguous buffer allocated on the heap with new[].
  174. *
  175. * This class is a simple buffer implementation which allocates chunks
  176. * off the heap. Once a buffer is constructed, it's buffer has a fixed
  177. * length.
  178. */
  179. class LLHeapBuffer : public LLBuffer
  180. {
  181. public:
  182. /**
  183. * @brief Construct a heap buffer with a reasonable default size.
  184. */
  185. LLHeapBuffer();
  186. /**
  187. * @brief Construct a heap buffer with a specified size.
  188. *
  189. * @param size The minimum size of the buffer.
  190. */
  191. explicit LLHeapBuffer(S32 size);
  192. /**
  193. * @brief Construct a heap buffer of minimum size len, and copy from src.
  194. *
  195. * @param src The source of the data to be copied.
  196. * @param len The minimum size of the buffer.
  197. */
  198. LLHeapBuffer(const U8* src, S32 len);
  199. /**
  200. * @brief Simple destruction.
  201. */
  202. virtual ~LLHeapBuffer();
  203. /**
  204. * @brief Get the number of bytes left in the buffer.
  205. *
  206. * Note that this is not a virtual function, and only available in
  207. * the LLHeapBuffer as a debugging aid.
  208. * @return Returns the number of bytes left.
  209. */
  210. S32 bytesLeft() const;
  211. /**
  212. * @brief Generate a segment for this buffer.
  213. *
  214. * The segment returned is always contiguous memory. This call can
  215. * fail if no contiguous memory is available, eg, offset is past
  216. * the end. The segment returned may be smaller than the requested
  217. * size. It is up to the caller to delete the segment returned.
  218. * @param channel The channel for the segment.
  219. * @param offset The offset from zero in the buffer
  220. * @param size The requested size of the segment
  221. * @param segment[out] The out-value from the operation
  222. * @return Returns true if a segment was found.
  223. */
  224. virtual bool createSegment(S32 channel, S32 size, LLSegment& segment);
  225. /**
  226. * @brief reclaim a segment from this buffer.
  227. *
  228. * This method is called on a buffer object when a caller is done
  229. * with a contiguous segment of memory inside this buffer. Since
  230. * segments can be cut arbitrarily outside of the control of the
  231. * buffer, this segment may not match any segment returned from
  232. * <code>createSegment()</code>.
  233. * This call will fail if the segment passed in is note completely
  234. * inside the buffer, eg, if the segment starts before this buffer
  235. * in memory or ends after it.
  236. * @param segment The contiguous buffer segment to reclaim.
  237. * @return Returns true if the call was successful.
  238. */
  239. virtual bool reclaimSegment(const LLSegment& segment);
  240. /**
  241. * @brief Test if a segment is inside this buffer.
  242. *
  243. * @param segment The contiguous buffer segment to test.
  244. * @return Returns true if the segment is in the bufffer.
  245. */
  246. virtual bool containsSegment(const LLSegment& segment) const;
  247. /**
  248. * @brief Return the current number of bytes allocated.
  249. */
  250. virtual S32 capacity() const { return mSize; }
  251. protected:
  252. U8* mBuffer;
  253. S32 mSize;
  254. U8* mNextFree;
  255. S32 mReclaimedBytes;
  256. private:
  257. /**
  258. * @brief Helper method to allocate a buffer and correctly set
  259. * intertnal state of this buffer.
  260. */
  261. void allocate(S32 size);
  262. };
  263. /**
  264. * @class LLBufferArray
  265. * @brief Class to represent scattered memory buffers and in-order segments
  266. * of that buffered data.
  267. *
  268. * *NOTE: This class needs to have an iovec interface
  269. */
  270. class LLBufferArray
  271. {
  272. public:
  273. typedef std::vector<LLBuffer*> buffer_list_t;
  274. typedef buffer_list_t::iterator buffer_iterator_t;
  275. typedef buffer_list_t::const_iterator const_buffer_iterator_t;
  276. typedef std::list<LLSegment> segment_list_t;
  277. typedef segment_list_t::const_iterator const_segment_iterator_t;
  278. typedef segment_list_t::iterator segment_iterator_t;
  279. enum { npos = 0xffffffff };
  280. LLBufferArray();
  281. ~LLBufferArray();
  282. /* @name Channel methods
  283. */
  284. //@{
  285. /**
  286. * @brief Generate the a channel descriptor which consumes the
  287. * output for the channel passed in.
  288. */
  289. static LLChannelDescriptors makeChannelConsumer(
  290. const LLChannelDescriptors& channels);
  291. /**
  292. * @brief Generate the next channel descriptor for this buffer array.
  293. *
  294. * The channel descriptor interface is how the buffer array
  295. * clients can know where to read and write data. Use this
  296. * interface to get the 'next' channel set for usage. This is a
  297. * bit of a simple hack until it's utility indicates it should be
  298. * extended.
  299. * @return Returns a valid channel descriptor set for input and output.
  300. */
  301. LLChannelDescriptors nextChannel();
  302. //@}
  303. /* @name Data methods
  304. */
  305. //@{
  306. /**
  307. * @brief Return the sum of all allocated bytes.
  308. */
  309. S32 capacity() const;
  310. // These methods will be useful once there is any kind of buffer
  311. // besides a heap buffer.
  312. //bool append(EBufferChannel channel, LLBuffer* data);
  313. //bool prepend(EBufferChannel channel, LLBuffer* data);
  314. //bool insertAfter(
  315. // segment_iterator_t segment,
  316. // EBufferChannel channel,
  317. // LLBuffer* data);
  318. /**
  319. * @brief Put data on a channel at the end of this buffer array.
  320. *
  321. * The data is copied from src into the buffer array. At least one
  322. * new segment is created and put on the end of the array. This
  323. * object will internally allocate new buffers if necessary.
  324. * @param channel The channel for this data
  325. * @param src The start of memory for the data to be copied
  326. * @param len The number of bytes of data to copy
  327. * @return Returns true if the method worked.
  328. */
  329. bool append(S32 channel, const U8* src, S32 len);
  330. /**
  331. * @brief Put data on a channel at the front of this buffer array.
  332. *
  333. * The data is copied from src into the buffer array. At least one
  334. * new segment is created and put in the front of the array. This
  335. * object will internally allocate new buffers if necessary.
  336. * @param channel The channel for this data
  337. * @param src The start of memory for the data to be copied
  338. * @param len The number of bytes of data to copy
  339. * @return Returns true if the method worked.
  340. */
  341. bool prepend(S32 channel, const U8* src, S32 len);
  342. /**
  343. * @brief Insert data into a buffer array after a particular segment.
  344. *
  345. * The data is copied from src into the buffer array. At least one
  346. * new segment is created and put in the array. This object will
  347. * internally allocate new buffers if necessary.
  348. * @param segment The segment in front of the new segments location
  349. * @param channel The channel for this data
  350. * @param src The start of memory for the data to be copied
  351. * @param len The number of bytes of data to copy
  352. * @return Returns true if the method worked.
  353. */
  354. bool insertAfter(
  355. segment_iterator_t segment,
  356. S32 channel,
  357. const U8* src,
  358. S32 len);
  359. /**
  360. * @brief Count bytes in the buffer array on the specified channel
  361. *
  362. * @param channel The channel to count.
  363. * @param start The start address in the array for counting. You
  364. * can specify NULL to start at the beginning.
  365. * @return Returns the number of bytes in the channel after start
  366. */
  367. S32 countAfter(S32 channel, U8* start) const;
  368. /**
  369. * @brief Count all bytes on channel.
  370. *
  371. * Helper method which just calls countAfter().
  372. * @param channel The channel to count.
  373. * @return Returns the number of bytes in the channel.
  374. */
  375. S32 count(S32 channel) const
  376. {
  377. return countAfter(channel, NULL);
  378. }
  379. /**
  380. * @brief Read bytes in the buffer array on the specified channel
  381. *
  382. * You should prefer iterating over segments is possible since
  383. * this method requires you to allocate large buffers - precisely
  384. * what this class is trying to prevent. This method will skip
  385. * any segments which are not on the given channel, so this method
  386. * would usually be used to read a channel and copy that to a log
  387. * or a socket buffer or something.
  388. * @param channel The channel to read.
  389. * @param start The start address in the array for reading. You
  390. * can specify NULL to start at the beginning.
  391. * @param dest The destination of the data read. This must be at
  392. * least len bytes long.
  393. * @param len[in,out] <b>in</b> How many bytes to read. <b>out</b> How
  394. * many bytes were read.
  395. * @return Returns the address of the last read byte.
  396. */
  397. U8* readAfter(S32 channel, U8* start, U8* dest, S32& len) const;
  398. /**
  399. * @brief Find an address in a buffer array
  400. *
  401. * @param channel The channel to seek in.
  402. * @param start The start address in the array for the seek
  403. * operation. You can specify NULL to start the seek at the
  404. * beginning, or pass in npos to start at the end.
  405. * @param delta How many bytes to seek through the array.
  406. * @return Returns the address of the last read byte.
  407. */
  408. U8* seek(S32 channel, U8* start, S32 delta) const;
  409. //@}
  410. /* @name Buffer interaction
  411. */
  412. //@{
  413. /**
  414. * @brief Take the contents of another buffer array
  415. *
  416. * This method simply strips the contents out of the source
  417. * buffery array - segments, buffers, etc, and appends them to
  418. * this instance. After this operation, the source is empty and
  419. * ready for reuse.
  420. * @param source The source buffer
  421. * @return Returns true if the operation succeeded.
  422. */
  423. bool takeContents(LLBufferArray& source);
  424. //@}
  425. /* @name Segment methods
  426. */
  427. //@{
  428. /**
  429. * @brief Split a segments so that address is the last address of
  430. * one segment, and the rest of the original segment becomes
  431. * another segment on the same channel.
  432. *
  433. * After this method call,
  434. * <code>getLastSegmentAddress(*getSegment(address)) ==
  435. * address</code> should be true. This call will only create a new
  436. * segment if the statement above is false before the call. Since
  437. * you usually call splitAfter() to change a segment property, use
  438. * getSegment() to perform those operations.
  439. * @param address The address which will become the last address
  440. * of the segment it is in.
  441. * @return Returns an iterator to the segment which contains
  442. * <code>address</code> which is <code>endSegment()</code> on
  443. * failure.
  444. */
  445. segment_iterator_t splitAfter(U8* address);
  446. /**
  447. * @brief Get the first segment in the buffer array.
  448. *
  449. * @return Returns the segment if there is one.
  450. */
  451. segment_iterator_t beginSegment();
  452. /**
  453. * @brief Get the one-past-the-end segment in the buffer array
  454. *
  455. * @return Returns the iterator for an invalid segment location.
  456. */
  457. segment_iterator_t endSegment();
  458. /**
  459. * @brief Get the segment which holds the given address.
  460. *
  461. * As opposed to some methods, passing a NULL will result in
  462. * returning the end segment.
  463. * @param address An address in the middle of the sought segment.
  464. * @return Returns the iterator for the segment or endSegment() on
  465. * failure.
  466. */
  467. const_segment_iterator_t getSegment(U8* address) const;
  468. /**
  469. * @brief Get the segment which holds the given address.
  470. *
  471. * As opposed to some methods, passing a NULL will result in
  472. * returning the end segment.
  473. * @param address An address in the middle of the sought segment.
  474. * @return Returns the iterator for the segment or endSegment() on
  475. * failure.
  476. */
  477. segment_iterator_t getSegment(U8* address);
  478. /**
  479. * @brief Get a segment iterator after address, and a constructed
  480. * segment to represent the next linear block of memory.
  481. *
  482. * This method is a helper by giving you the largest segment
  483. * possible in the out-value param after the address provided. The
  484. * iterator will be useful for iteration, while the segment can be
  485. * used for direct access to memory after address if the return
  486. * values isnot end. Passing in NULL will return beginSegment()
  487. * which may be endSegment(). The segment returned will only be
  488. * zero length if the return value equals end.
  489. * This is really just a helper method, since all the information
  490. * returned could be constructed through other methods.
  491. * @param address An address in the middle of the sought segment.
  492. * @param segment[out] segment to be used for reading or writing
  493. * @return Returns an iterator which contains at least segment or
  494. * endSegment() on failure.
  495. */
  496. segment_iterator_t constructSegmentAfter(U8* address, LLSegment& segment);
  497. /**
  498. * @brief Make a new segment at the end of buffer array
  499. *
  500. * This method will attempt to create a new and empty segment of
  501. * the specified length. The segment created may be shorter than
  502. * requested.
  503. * @param channel[in] The channel for the newly created segment.
  504. * @param length[in] The requested length of the segment.
  505. * @return Returns an iterator which contains at least segment or
  506. * endSegment() on failure.
  507. */
  508. segment_iterator_t makeSegment(S32 channel, S32 length);
  509. /**
  510. * @brief Erase the segment if it is in the buffer array.
  511. *
  512. * @param iter An iterator referring to the segment to erase.
  513. * @return Returns true on success.
  514. */
  515. bool eraseSegment(const segment_iterator_t& iter);
  516. /**
  517. * @brief Lock the mutex if it exists
  518. * This method locks mMutexp to make accessing LLBufferArray thread-safe
  519. */
  520. void lock();
  521. /**
  522. * @brief Unlock the mutex if it exists
  523. */
  524. void unlock();
  525. /**
  526. * @brief Return mMutexp
  527. */
  528. LLMutex* getMutex();
  529. /**
  530. * @brief Set LLBufferArray to be shared across threads or not
  531. * This method is to create mMutexp if is threaded.
  532. * @param threaded Indicates this LLBufferArray instance is shared across threads if true.
  533. */
  534. void setThreaded(bool threaded);
  535. //@}
  536. protected:
  537. /**
  538. * @brief Optimally put data in buffers, and reutrn segments.
  539. *
  540. * This is an internal function used to create buffers as
  541. * necessary, and sequence the segments appropriately for the
  542. * various ways to copy data from src into this.
  543. * If this method fails, it may actually leak some space inside
  544. * buffers, but I am not too worried about the slim possibility
  545. * that we may have some 'dead' space which will be recovered when
  546. * the buffer (which we will not lose) is deleted. Addressing this
  547. * weakness will make the buffers almost as complex as a general
  548. * memory management system.
  549. * @param channel The channel for this data
  550. * @param src The start of memory for the data to be copied
  551. * @param len The number of bytes of data to copy
  552. * @param segments Out-value for the segments created.
  553. * @return Returns true if the method worked.
  554. */
  555. bool copyIntoBuffers(
  556. S32 channel,
  557. const U8* src,
  558. S32 len,
  559. std::vector<LLSegment>& segments);
  560. protected:
  561. S32 mNextBaseChannel;
  562. buffer_list_t mBuffers;
  563. segment_list_t mSegments;
  564. LLMutex* mMutexp;
  565. };
  566. #endif // LL_LLBUFFER_H