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