llbuffer.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787
  1. /**
  2. * @file llbuffer.cpp
  3. * @author Phoenix
  4. * @date 2005-09-20
  5. * @brief Implementation of the segments, buffers, and buffer arrays.
  6. *
  7. * $LicenseInfo:firstyear=2005&license=viewergpl$
  8. *
  9. * Copyright (c) 2005-2009, Linden Research, Inc.
  10. *
  11. * Second Life Viewer Source Code
  12. * The source code in this file ("Source Code") is provided by Linden Lab
  13. * to you under the terms of the GNU General Public License, version 2.0
  14. * ("GPL"), unless you have obtained a separate licensing agreement
  15. * ("Other License"), formally executed by you and Linden Lab. Terms of
  16. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  17. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  18. *
  19. * There are special exceptions to the terms and conditions of the GPL as
  20. * it is applied to this Source Code. View the full text of the exception
  21. * in the file doc/FLOSS-exception.txt in this software distribution, or
  22. * online at
  23. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  24. *
  25. * By copying, modifying or distributing this software, you acknowledge
  26. * that you have read and understood your obligations described above,
  27. * and agree to abide by those obligations.
  28. *
  29. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  30. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  31. * COMPLETENESS OR PERFORMANCE.
  32. * $/LicenseInfo$
  33. */
  34. #include "linden_common.h"
  35. #include <iterator> // for VS2010
  36. #include "llbuffer.h"
  37. #include "llmath.h"
  38. #include "llstl.h"
  39. ///////////////////////////////////////////////////////////////////////////////
  40. // LLHeapBuffer class
  41. ///////////////////////////////////////////////////////////////////////////////
  42. LLHeapBuffer::LLHeapBuffer()
  43. : mBuffer(NULL),
  44. mSize(0),
  45. mNextFree(NULL),
  46. mReclaimedBytes(0)
  47. {
  48. constexpr S32 DEFAULT_HEAP_BUFFER_SIZE = 16384;
  49. allocate(DEFAULT_HEAP_BUFFER_SIZE);
  50. }
  51. LLHeapBuffer::LLHeapBuffer(S32 size)
  52. : mBuffer(NULL),
  53. mSize(0),
  54. mNextFree(NULL),
  55. mReclaimedBytes(0)
  56. {
  57. allocate(size);
  58. }
  59. LLHeapBuffer::LLHeapBuffer(const U8* src, S32 len)
  60. : mBuffer(NULL),
  61. mSize(0),
  62. mNextFree(NULL),
  63. mReclaimedBytes(0)
  64. {
  65. if (len > 0 && src)
  66. {
  67. allocate(len);
  68. if (mBuffer)
  69. {
  70. memcpy(mBuffer, src, len);
  71. }
  72. }
  73. }
  74. // virtual
  75. LLHeapBuffer::~LLHeapBuffer()
  76. {
  77. delete[] mBuffer;
  78. mBuffer = NULL;
  79. mSize = 0;
  80. mNextFree = NULL;
  81. }
  82. S32 LLHeapBuffer::bytesLeft() const
  83. {
  84. return (mSize - (mNextFree - mBuffer));
  85. }
  86. // virtual
  87. bool LLHeapBuffer::createSegment(S32 channel, S32 size, LLSegment& segment)
  88. {
  89. // get actual size of the segment.
  90. S32 actual_size = llmin(size, (mSize - S32(mNextFree - mBuffer)));
  91. // bail if we cannot build a valid segment
  92. if (actual_size <= 0)
  93. {
  94. return false;
  95. }
  96. // Yay, we're done.
  97. segment = LLSegment(channel, mNextFree, actual_size);
  98. mNextFree += actual_size;
  99. return true;
  100. }
  101. // virtual
  102. bool LLHeapBuffer::reclaimSegment(const LLSegment& segment)
  103. {
  104. if (containsSegment(segment))
  105. {
  106. mReclaimedBytes += segment.size();
  107. if (mReclaimedBytes == mSize)
  108. {
  109. // We have reclaimed all of the memory from this buffer. Therefore,
  110. // we can reset the mNextFree to the start of the buffer, and reset
  111. // the reclaimed bytes.
  112. mReclaimedBytes = 0;
  113. mNextFree = mBuffer;
  114. }
  115. else if (mReclaimedBytes > mSize)
  116. {
  117. llwarns << "LLHeapBuffer reclaimed more memory than allocated."
  118. << " This is probably programmer error." << llendl;
  119. }
  120. return true;
  121. }
  122. return false;
  123. }
  124. // virtual
  125. bool LLHeapBuffer::containsSegment(const LLSegment& segment) const
  126. {
  127. // *NOTE: this check is fairly simple because heap buffers are
  128. // simple contiguous chunks of heap memory.
  129. if (mBuffer > segment.data() ||
  130. mBuffer + mSize < segment.data() + segment.size())
  131. {
  132. return false;
  133. }
  134. return true;
  135. }
  136. void LLHeapBuffer::allocate(S32 size)
  137. {
  138. mReclaimedBytes = 0;
  139. mBuffer = new U8[size];
  140. if (mBuffer)
  141. {
  142. mSize = size;
  143. mNextFree = mBuffer;
  144. }
  145. }
  146. ///////////////////////////////////////////////////////////////////////////////
  147. // LLBufferArray class
  148. ///////////////////////////////////////////////////////////////////////////////
  149. LLBufferArray::LLBufferArray()
  150. : mNextBaseChannel(0),
  151. mMutexp(NULL)
  152. {
  153. }
  154. LLBufferArray::~LLBufferArray()
  155. {
  156. std::for_each(mBuffers.begin(), mBuffers.end(), DeletePointer());
  157. mBuffers.clear();
  158. if (mMutexp)
  159. {
  160. delete mMutexp;
  161. }
  162. }
  163. // static
  164. LLChannelDescriptors LLBufferArray::makeChannelConsumer(const LLChannelDescriptors& channels)
  165. {
  166. LLChannelDescriptors rv(channels.out());
  167. return rv;
  168. }
  169. void LLBufferArray::setThreaded(bool threaded)
  170. {
  171. if (threaded)
  172. {
  173. if (!mMutexp)
  174. {
  175. mMutexp = new LLMutex();
  176. }
  177. }
  178. else if (mMutexp)
  179. {
  180. delete mMutexp;
  181. mMutexp = NULL;
  182. }
  183. }
  184. LLChannelDescriptors LLBufferArray::nextChannel()
  185. {
  186. LLChannelDescriptors rv(mNextBaseChannel++);
  187. return rv;
  188. }
  189. // mMutexp should be locked before calling this.
  190. S32 LLBufferArray::capacity() const
  191. {
  192. S32 total = 0;
  193. for (const_buffer_iterator_t iter = mBuffers.begin(), end = mBuffers.end();
  194. iter != end; ++iter)
  195. {
  196. total += (*iter)->capacity();
  197. }
  198. return total;
  199. }
  200. bool LLBufferArray::append(S32 channel, const U8* src, S32 len)
  201. {
  202. LLMutexLock lock(mMutexp);
  203. std::vector<LLSegment> segments;
  204. if (copyIntoBuffers(channel, src, len, segments))
  205. {
  206. mSegments.insert(mSegments.end(), segments.begin(), segments.end());
  207. return true;
  208. }
  209. return false;
  210. }
  211. // mMutexp should be locked before calling this.
  212. bool LLBufferArray::prepend(S32 channel, const U8* src, S32 len)
  213. {
  214. std::vector<LLSegment> segments;
  215. if (copyIntoBuffers(channel, src, len, segments))
  216. {
  217. mSegments.insert(mSegments.begin(), segments.begin(), segments.end());
  218. return true;
  219. }
  220. return false;
  221. }
  222. bool LLBufferArray::insertAfter(segment_iterator_t segment, S32 channel,
  223. const U8* src, S32 len)
  224. {
  225. std::vector<LLSegment> segments;
  226. LLMutexLock lock(mMutexp);
  227. if (mSegments.end() != segment)
  228. {
  229. ++segment;
  230. }
  231. if (copyIntoBuffers(channel, src, len, segments))
  232. {
  233. mSegments.insert(segment, segments.begin(), segments.end());
  234. return true;
  235. }
  236. return false;
  237. }
  238. // mMutexp should be locked before calling this.
  239. LLBufferArray::segment_iterator_t LLBufferArray::splitAfter(U8* address)
  240. {
  241. segment_iterator_t end = mSegments.end();
  242. segment_iterator_t it = getSegment(address);
  243. if (it == end)
  244. {
  245. return end;
  246. }
  247. // We have the location and the segment.
  248. U8* base = it->data();
  249. S32 size = it->size();
  250. if (address == base + size)
  251. {
  252. // No need to split, since this is the last byte of the segment. We do
  253. // not want to have zero length segments, since that will only incur
  254. // processing overhead with no advantage.
  255. return it;
  256. }
  257. S32 channel = it->getChannel();
  258. LLSegment segment1(channel, base, address - base + 1);
  259. *it = segment1;
  260. segment_iterator_t rv = it++;
  261. LLSegment segment2(channel, address + 1, size - (address - base) - 1);
  262. mSegments.insert(it, segment2);
  263. return rv;
  264. }
  265. // mMutexp should be locked before calling this.
  266. LLBufferArray::segment_iterator_t LLBufferArray::beginSegment()
  267. {
  268. return mSegments.begin();
  269. }
  270. // mMutexp should be locked before calling this.
  271. LLBufferArray::segment_iterator_t LLBufferArray::endSegment()
  272. {
  273. return mSegments.end();
  274. }
  275. // mMutexp should be locked before calling this.
  276. LLBufferArray::segment_iterator_t LLBufferArray::constructSegmentAfter(U8* address,
  277. LLSegment& segment)
  278. {
  279. segment_iterator_t rv = mSegments.begin();
  280. segment_iterator_t end = mSegments.end();
  281. if (!address)
  282. {
  283. if (rv != end)
  284. {
  285. segment = *rv;
  286. }
  287. }
  288. else
  289. {
  290. // we have an address - find the segment it is in.
  291. for ( ; rv != end; ++rv)
  292. {
  293. if (address >= rv->data() && address < rv->data() + rv->size())
  294. {
  295. if (++address < rv->data() + rv->size())
  296. {
  297. // it's in this segment - construct an appropriate
  298. // sub-segment.
  299. segment = LLSegment(rv->getChannel(), address,
  300. rv->size() - (address - rv->data()));
  301. }
  302. else
  303. {
  304. ++rv;
  305. if (rv != end)
  306. {
  307. segment = *rv;
  308. }
  309. }
  310. break;
  311. }
  312. }
  313. }
  314. if (rv == end)
  315. {
  316. segment = LLSegment();
  317. }
  318. return rv;
  319. }
  320. // mMutexp should be locked before calling this.
  321. LLBufferArray::segment_iterator_t LLBufferArray::getSegment(U8* address)
  322. {
  323. segment_iterator_t end = mSegments.end();
  324. if (!address)
  325. {
  326. return end;
  327. }
  328. segment_iterator_t it = mSegments.begin();
  329. for ( ; it != end; ++it)
  330. {
  331. if (address >= it->data() && address < it->data() + it->size())
  332. {
  333. // found it.
  334. return it;
  335. }
  336. }
  337. return end;
  338. }
  339. // mMutexp should be locked before calling this.
  340. LLBufferArray::const_segment_iterator_t LLBufferArray::getSegment(U8* address) const
  341. {
  342. const_segment_iterator_t end = mSegments.end();
  343. if (!address)
  344. {
  345. return end;
  346. }
  347. const_segment_iterator_t it = mSegments.begin();
  348. for ( ; it != end; ++it)
  349. {
  350. if (address >= it->data() && address < it->data() + it->size())
  351. {
  352. // found it.
  353. return it;
  354. }
  355. }
  356. return end;
  357. }
  358. #if 0
  359. U8* LLBufferArray::getAddressAfter(U8* address)
  360. {
  361. U8* rv = NULL;
  362. segment_iterator_t it = getSegment(address);
  363. segment_iterator_t end = mSegments.end();
  364. if (it != end)
  365. {
  366. if (++address < it->data() + it->size())
  367. {
  368. // it's in the same segment
  369. rv = address;
  370. }
  371. else
  372. {
  373. // it's in the next segment
  374. if (++it != end)
  375. {
  376. rv = it->data();
  377. }
  378. }
  379. }
  380. return rv;
  381. }
  382. #endif
  383. S32 LLBufferArray::countAfter(S32 channel, U8* start) const
  384. {
  385. S32 count = 0;
  386. S32 offset = 0;
  387. const_segment_iterator_t it;
  388. LLMutexLock lock(mMutexp);
  389. const_segment_iterator_t end = mSegments.end();
  390. if (start)
  391. {
  392. it = getSegment(start);
  393. if (it == end)
  394. {
  395. return count;
  396. }
  397. if (++start < it->data() + it->size())
  398. {
  399. // it's in the same segment
  400. offset = start - it->data();
  401. }
  402. else if (++it == end)
  403. {
  404. // it's in the next segment
  405. return count;
  406. }
  407. }
  408. else
  409. {
  410. it = mSegments.begin();
  411. }
  412. while (it != end)
  413. {
  414. if (it->isOnChannel(channel))
  415. {
  416. count += it->size() - offset;
  417. }
  418. offset = 0;
  419. ++it;
  420. }
  421. return count;
  422. }
  423. U8* LLBufferArray::readAfter(S32 channel, U8* start, U8* dest, S32& len) const
  424. {
  425. U8* rv = start;
  426. if (!dest || len <= 0)
  427. {
  428. return rv;
  429. }
  430. S32 bytes_left = len;
  431. len = 0;
  432. S32 bytes_to_copy = 0;
  433. const_segment_iterator_t it;
  434. LLMutexLock lock(mMutexp);
  435. const_segment_iterator_t end = mSegments.end();
  436. if (start)
  437. {
  438. it = getSegment(start);
  439. if (it == end)
  440. {
  441. return rv;
  442. }
  443. if (++start < it->data() + it->size() && it->isOnChannel(channel))
  444. {
  445. // copy the data out of this segment
  446. S32 bytes_in_segment = it->size() - (start - it->data());
  447. bytes_to_copy = llmin(bytes_left, bytes_in_segment);
  448. memcpy(dest, start, bytes_to_copy);
  449. len += bytes_to_copy;
  450. bytes_left -= bytes_to_copy;
  451. rv = start + bytes_to_copy - 1;
  452. ++it;
  453. }
  454. else
  455. {
  456. ++it;
  457. }
  458. }
  459. else
  460. {
  461. it = mSegments.begin();
  462. }
  463. while (bytes_left && it != end)
  464. {
  465. if (!it->isOnChannel(channel))
  466. {
  467. ++it;
  468. continue;
  469. }
  470. bytes_to_copy = llmin(bytes_left, it->size());
  471. memcpy(dest + len, it->data(), bytes_to_copy);
  472. len += bytes_to_copy;
  473. bytes_left -= bytes_to_copy;
  474. rv = it->data() + bytes_to_copy - 1;
  475. ++it;
  476. }
  477. return rv;
  478. }
  479. U8* LLBufferArray::seek(S32 channel, U8* start, S32 delta) const
  480. {
  481. const_segment_iterator_t it;
  482. const_segment_iterator_t end = mSegments.end();
  483. U8* rv = start;
  484. if (0 == delta)
  485. {
  486. if ((U8*)npos == start)
  487. {
  488. // someone is looking for end of data.
  489. segment_list_t::const_reverse_iterator rit = mSegments.rbegin();
  490. segment_list_t::const_reverse_iterator rend = mSegments.rend();
  491. while (rit != rend)
  492. {
  493. if (!rit->isOnChannel(channel))
  494. {
  495. ++rit;
  496. continue;
  497. }
  498. rv = rit->data() + rit->size();
  499. break;
  500. }
  501. }
  502. else if (start)
  503. {
  504. // This is sort of a weird case - check if zero bytes away from
  505. // current position is on channel and return start if that is true.
  506. // Otherwise, return NULL.
  507. it = getSegment(start);
  508. if (it == end || !it->isOnChannel(channel))
  509. {
  510. rv = NULL;
  511. }
  512. }
  513. else
  514. {
  515. // Start is NULL, so return the very first byte on the channel, or
  516. // NULL.
  517. it = mSegments.begin();
  518. while (it != end && !it->isOnChannel(channel))
  519. {
  520. ++it;
  521. }
  522. if (it != end)
  523. {
  524. rv = it->data();
  525. }
  526. }
  527. return rv;
  528. }
  529. if (start)
  530. {
  531. it = getSegment(start);
  532. if (it != end && it->isOnChannel(channel))
  533. {
  534. if (delta > 0)
  535. {
  536. S32 bytes_in_segment = it->size() - (start - it->data());
  537. S32 local_delta = llmin(delta, bytes_in_segment);
  538. rv += local_delta;
  539. delta -= local_delta;
  540. ++it;
  541. }
  542. else
  543. {
  544. S32 bytes_in_segment = start - it->data();
  545. S32 local_delta = llmin(abs(delta), bytes_in_segment);
  546. rv -= local_delta;
  547. delta += local_delta;
  548. }
  549. }
  550. }
  551. else if (delta < 0)
  552. {
  553. // start is NULL, and delta indicates seeking backwards - return NULL.
  554. return NULL;
  555. }
  556. else
  557. {
  558. // start is NULL and delta > 0
  559. it = mSegments.begin();
  560. }
  561. if (delta > 0)
  562. {
  563. // At this point, we have an iterator into the segments, and are
  564. // seeking forward until delta is zero or we run out
  565. while (delta && it != end)
  566. {
  567. if (!it->isOnChannel(channel))
  568. {
  569. ++it;
  570. continue;
  571. }
  572. if (delta <= it->size())
  573. {
  574. // it's in this segment
  575. rv = it->data() + delta;
  576. }
  577. delta -= it->size();
  578. ++it;
  579. }
  580. if (delta && it == end)
  581. {
  582. // Whoops - sought past end.
  583. rv = NULL;
  584. }
  585. }
  586. else //if (delta < 0)
  587. {
  588. // We are at the beginning of a segment, and need to search backwards.
  589. segment_list_t::const_reverse_iterator rit(it);
  590. segment_list_t::const_reverse_iterator rend = mSegments.rend();
  591. while (delta && rit != rend)
  592. {
  593. if (!rit->isOnChannel(channel))
  594. {
  595. ++rit;
  596. continue;
  597. }
  598. if (abs(delta) <= rit->size())
  599. {
  600. // it's in this segment.
  601. rv = rit->data() + rit->size() + delta;
  602. delta = 0;
  603. }
  604. else
  605. {
  606. delta += rit->size();
  607. }
  608. ++rit;
  609. }
  610. if (delta && rit == rend)
  611. {
  612. // sought past the beginning.
  613. rv = NULL;
  614. }
  615. }
  616. return rv;
  617. }
  618. // test use only
  619. bool LLBufferArray::takeContents(LLBufferArray& source)
  620. {
  621. LLMutexLock lock(mMutexp);
  622. source.lock();
  623. std::copy(source.mBuffers.begin(), source.mBuffers.end(),
  624. std::back_insert_iterator<buffer_list_t>(mBuffers));
  625. source.mBuffers.clear();
  626. std::copy(source.mSegments.begin(), source.mSegments.end(),
  627. std::back_insert_iterator<segment_list_t>(mSegments));
  628. source.mSegments.clear();
  629. source.mNextBaseChannel = 0;
  630. source.unlock();
  631. return true;
  632. }
  633. // mMutexp should be locked before calling this.
  634. LLBufferArray::segment_iterator_t LLBufferArray::makeSegment(S32 channel,
  635. S32 len)
  636. {
  637. // Start at the end of the buffers, because it is the most likely to have
  638. // free space.
  639. LLSegment segment;
  640. buffer_list_t::reverse_iterator it = mBuffers.rbegin();
  641. buffer_list_t::reverse_iterator end = mBuffers.rend();
  642. bool made_segment = false;
  643. for ( ; it != end; ++it)
  644. {
  645. if ((*it)->createSegment(channel, len, segment))
  646. {
  647. made_segment = true;
  648. break;
  649. }
  650. }
  651. segment_iterator_t send = mSegments.end();
  652. if (!made_segment)
  653. {
  654. LLBuffer* buf = new LLHeapBuffer;
  655. mBuffers.push_back(buf);
  656. if (!buf->createSegment(channel, len, segment))
  657. {
  658. // failed. this should never happen.
  659. return send;
  660. }
  661. }
  662. // store and return the newly made segment
  663. mSegments.insert(send, segment);
  664. std::list<LLSegment>::reverse_iterator rv = mSegments.rbegin();
  665. ++rv;
  666. send = rv.base();
  667. return send;
  668. }
  669. // mMutexp should be locked before calling this.
  670. bool LLBufferArray::eraseSegment(const segment_iterator_t& erase_iter)
  671. {
  672. // Find out which buffer contains the segment, and if it is found, ask it
  673. // to reclaim the memory.
  674. bool rv = false;
  675. LLSegment segment(*erase_iter);
  676. buffer_iterator_t iter = mBuffers.begin();
  677. buffer_iterator_t end = mBuffers.end();
  678. for ( ; iter != end; ++iter)
  679. {
  680. // We can safely call reclaimSegment on every buffer, and once it
  681. // returns true, the segment was found.
  682. if ((*iter)->reclaimSegment(segment))
  683. {
  684. rv = true;
  685. break;
  686. }
  687. }
  688. // No need to get the return value since we are not interested in the
  689. // interator retured by the call.
  690. (void)mSegments.erase(erase_iter);
  691. return rv;
  692. }
  693. // mMutexp should be locked before calling this.
  694. bool LLBufferArray::copyIntoBuffers(S32 channel, const U8* src, S32 len,
  695. std::vector<LLSegment>& segments)
  696. {
  697. if (!src || !len) return false;
  698. S32 copied = 0;
  699. LLSegment segment;
  700. buffer_iterator_t it = mBuffers.begin();
  701. buffer_iterator_t end = mBuffers.end();
  702. for ( ; it != end;)
  703. {
  704. if (!(*it)->createSegment(channel, len, segment))
  705. {
  706. ++it;
  707. continue;
  708. }
  709. segments.push_back(segment);
  710. S32 bytes = llmin(segment.size(), len);
  711. memcpy(segment.data(), src + copied, bytes);
  712. copied += bytes;
  713. len -= bytes;
  714. if (0 == len)
  715. {
  716. break;
  717. }
  718. }
  719. while (len)
  720. {
  721. LLBuffer* buf = new LLHeapBuffer;
  722. mBuffers.push_back(buf);
  723. if (!buf->createSegment(channel, len, segment))
  724. {
  725. // This totally failed - bail. This is the weird corner case were
  726. // we 'leak' memory. No worries about an actual leak - we will
  727. // still reclaim the memory later, but this particular buffer array
  728. // is hosed for some reason. This should never happen.
  729. return false;
  730. }
  731. segments.push_back(segment);
  732. memcpy(segment.data(), src + copied, segment.size());
  733. copied += segment.size();
  734. len -= segment.size();
  735. }
  736. return true;
  737. }