diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llmessage/llbuffer.h | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llmessage/llbuffer.h')
-rw-r--r-- | linden/indra/llmessage/llbuffer.h | 512 |
1 files changed, 512 insertions, 0 deletions
diff --git a/linden/indra/llmessage/llbuffer.h b/linden/indra/llmessage/llbuffer.h new file mode 100644 index 0000000..cd76c90 --- /dev/null +++ b/linden/indra/llmessage/llbuffer.h | |||
@@ -0,0 +1,512 @@ | |||
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 | * 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 | #ifndef LL_LLBUFFER_H | ||
31 | #define LL_LLBUFFER_H | ||
32 | |||
33 | /** | ||
34 | * Declaration of classes used for minimizing calls to new[], | ||
35 | * memcpy(), and delete[]. Typically, you would create an LLHeapArray, | ||
36 | * feed it data, modify and add segments as you process it, and feed | ||
37 | * it to a sink. | ||
38 | */ | ||
39 | |||
40 | #include <list> | ||
41 | |||
42 | /** | ||
43 | * @class LLChannelDescriptors | ||
44 | * @brief A way simple interface to accesss channels inside a buffer | ||
45 | */ | ||
46 | class LLChannelDescriptors | ||
47 | { | ||
48 | public: | ||
49 | // enumeration for segmenting the channel information | ||
50 | enum { E_CHANNEL_COUNT = 3 }; | ||
51 | LLChannelDescriptors() : mBaseChannel(0) {} | ||
52 | explicit LLChannelDescriptors(S32 base) : mBaseChannel(base) {} | ||
53 | S32 in() const { return mBaseChannel; } | ||
54 | S32 out() const { return mBaseChannel + 1; } | ||
55 | //S32 err() const { return mBaseChannel + 2; } | ||
56 | protected: | ||
57 | S32 mBaseChannel; | ||
58 | }; | ||
59 | |||
60 | |||
61 | /** | ||
62 | * @class LLSegment | ||
63 | * @brief A segment is a single, contiguous chunk of memory in a buffer | ||
64 | * | ||
65 | * Each segment represents a contiguous addressable piece of memory | ||
66 | * which is located inside a buffer. The segment is not responsible | ||
67 | * for allocation or deallcoation of the data. Each segment is a light | ||
68 | * weight object, and simple enough to copy around, use, and generate | ||
69 | * as necessary. | ||
70 | * This is the preferred interface for working with memory blocks, | ||
71 | * since it is the only way to safely, inexpensively, and directly | ||
72 | * access linear blocks of memory. | ||
73 | */ | ||
74 | class LLSegment | ||
75 | { | ||
76 | public: | ||
77 | LLSegment(); | ||
78 | LLSegment(S32 channel, U8* data, S32 data_len); | ||
79 | ~LLSegment(); | ||
80 | |||
81 | /** | ||
82 | * @brief Check if this segment is on the given channel. | ||
83 | * | ||
84 | */ | ||
85 | bool isOnChannel(S32 channel) const; | ||
86 | |||
87 | /** | ||
88 | * @brief Get the channel | ||
89 | */ | ||
90 | S32 getChannel() const; | ||
91 | |||
92 | /** | ||
93 | * @brief Set the channel | ||
94 | */ | ||
95 | void setChannel(S32 channel); | ||
96 | |||
97 | /** | ||
98 | * @brief Return a raw pointer to the current data set. | ||
99 | * | ||
100 | * The pointer returned can be used for reading or even adjustment | ||
101 | * if you are a bit crazy up to size() bytes into memory. | ||
102 | * @return A potentially NULL pointer to the raw buffer data | ||
103 | */ | ||
104 | U8* data() const; | ||
105 | |||
106 | /** | ||
107 | * @brief Return the size of the segment | ||
108 | */ | ||
109 | S32 size() const; | ||
110 | |||
111 | protected: | ||
112 | S32 mChannel; | ||
113 | U8* mData; | ||
114 | S32 mSize; | ||
115 | }; | ||
116 | |||
117 | /** | ||
118 | * @class LLBuffer | ||
119 | * @brief Abstract base class for buffers | ||
120 | * | ||
121 | * This class declares the interface necessary for buffer arrays. A | ||
122 | * buffer is not necessarily a single contiguous memory chunk, so | ||
123 | * please do not circumvent the segment API. | ||
124 | */ | ||
125 | class LLBuffer | ||
126 | { | ||
127 | public: | ||
128 | /** | ||
129 | * @brief The buffer base class should have no responsibilities | ||
130 | * other than an interface. | ||
131 | */ | ||
132 | virtual ~LLBuffer() {} | ||
133 | |||
134 | /** | ||
135 | * @brief Generate a segment for this buffer. | ||
136 | * | ||
137 | * The segment returned is always contiguous memory. This call can | ||
138 | * fail if no contiguous memory is available, eg, offset is past | ||
139 | * the end. The segment returned may be smaller than the requested | ||
140 | * size. The segment will never be larger than the requested size. | ||
141 | * @param channel The channel for the segment. | ||
142 | * @param offset The offset from zero in the buffer. | ||
143 | * @param size The requested size of the segment. | ||
144 | * @param segment[out] The out-value from the operation | ||
145 | * @return Returns true if a segment was found. | ||
146 | */ | ||
147 | virtual bool createSegment(S32 channel, S32 size, LLSegment& segment) = 0; | ||
148 | }; | ||
149 | |||
150 | /** | ||
151 | * @class LLHeapBuffer | ||
152 | * @brief A large contiguous buffer allocated on the heap with new[]. | ||
153 | * | ||
154 | * This class is a simple buffer implementation which allocates chunks | ||
155 | * off the heap. Once a buffer is constructed, it's buffer has a fixed | ||
156 | * length. | ||
157 | */ | ||
158 | class LLHeapBuffer : public LLBuffer | ||
159 | { | ||
160 | public: | ||
161 | /** | ||
162 | * @brief Construct a heap buffer with a reasonable default size. | ||
163 | */ | ||
164 | LLHeapBuffer(); | ||
165 | |||
166 | /** | ||
167 | * @brief Construct a heap buffer with a specified size. | ||
168 | * | ||
169 | * @param size The minimum size of the buffer. | ||
170 | */ | ||
171 | explicit LLHeapBuffer(S32 size); | ||
172 | |||
173 | /** | ||
174 | * @brief Construct a heap buffer of minimum size len, and copy from src. | ||
175 | * | ||
176 | * @param src The source of the data to be copied. | ||
177 | * @param len The minimum size of the buffer. | ||
178 | */ | ||
179 | LLHeapBuffer(const U8* src, S32 len); | ||
180 | |||
181 | /** | ||
182 | * @brief Simple destruction. | ||
183 | */ | ||
184 | virtual ~LLHeapBuffer(); | ||
185 | |||
186 | /** | ||
187 | * @brief Get the number of bytes left in the buffer. | ||
188 | * | ||
189 | * @return Returns the number of bytes left. | ||
190 | */ | ||
191 | //virtual S32 bytesLeft() const; | ||
192 | |||
193 | /** | ||
194 | * @brief Generate a segment for this buffer. | ||
195 | * | ||
196 | * The segment returned is always contiguous memory. This call can | ||
197 | * fail if no contiguous memory is available, eg, offset is past | ||
198 | * the end. The segment returned may be smaller than the requested | ||
199 | * size. It is up to the caller to delete the segment returned. | ||
200 | * @param channel The channel for the segment. | ||
201 | * @param offset The offset from zero in the buffer | ||
202 | * @param size The requested size of the segment | ||
203 | * @param segment[out] The out-value from the operation | ||
204 | * @return Returns true if a segment was found. | ||
205 | */ | ||
206 | virtual bool createSegment(S32 channel, S32 size, LLSegment& segment); | ||
207 | |||
208 | protected: | ||
209 | U8* mBuffer; | ||
210 | S32 mSize; | ||
211 | U8* mNextFree; | ||
212 | |||
213 | private: | ||
214 | /** | ||
215 | * @brief Helper method to allocate a buffer and correctly set | ||
216 | * intertnal state of this buffer. | ||
217 | */ | ||
218 | void allocate(S32 size); | ||
219 | }; | ||
220 | |||
221 | /** | ||
222 | * @class LLBufferArray | ||
223 | * @brief Class to represent scattered memory buffers and in-order segments | ||
224 | * of that buffered data. | ||
225 | * | ||
226 | * NOTE: This class needs to have an iovec interface | ||
227 | */ | ||
228 | class LLBufferArray | ||
229 | { | ||
230 | public: | ||
231 | typedef std::vector<LLBuffer*> buffer_list_t; | ||
232 | typedef buffer_list_t::iterator buffer_iterator_t; | ||
233 | typedef std::list<LLSegment> segment_list_t; | ||
234 | typedef segment_list_t::const_iterator const_segment_iterator_t; | ||
235 | typedef segment_list_t::iterator segment_iterator_t; | ||
236 | enum { npos = 0xffffffff }; | ||
237 | |||
238 | LLBufferArray(); | ||
239 | ~LLBufferArray(); | ||
240 | |||
241 | /* @name Channel methods | ||
242 | */ | ||
243 | //@{ | ||
244 | /** | ||
245 | * @brief Generate the a channel descriptor which consumes the | ||
246 | * output for the channel passed in. | ||
247 | */ | ||
248 | static LLChannelDescriptors makeChannelConsumer( | ||
249 | const LLChannelDescriptors& channels); | ||
250 | |||
251 | /** | ||
252 | * @brief Generate the next channel descriptor for this buffer array. | ||
253 | * | ||
254 | * The channel descriptor interface is how the buffer array | ||
255 | * clients can know where to read and write data. Use this | ||
256 | * interface to get the 'next' channel set for usage. This is a | ||
257 | * bit of a simple hack until it's utility indicates it should be | ||
258 | * extended. | ||
259 | * @return Returns a valid channel descriptor set for input and output. | ||
260 | */ | ||
261 | LLChannelDescriptors nextChannel(); | ||
262 | //@} | ||
263 | |||
264 | /* @name Data methods | ||
265 | */ | ||
266 | //@{ | ||
267 | |||
268 | // These methods will be useful once there is any kind of buffer | ||
269 | // besides a heap buffer. | ||
270 | //bool append(EBufferChannel channel, LLBuffer* data); | ||
271 | //bool prepend(EBufferChannel channel, LLBuffer* data); | ||
272 | //bool insertAfter( | ||
273 | // segment_iterator_t segment, | ||
274 | // EBufferChannel channel, | ||
275 | // LLBuffer* data); | ||
276 | |||
277 | /** | ||
278 | * @brief Put data on a channel at the end of this buffer array. | ||
279 | * | ||
280 | * The data is copied from src into the buffer array. At least one | ||
281 | * new segment is created and put on the end of the array. This | ||
282 | * object will internally allocate new buffers if necessary. | ||
283 | * @param channel The channel for this data | ||
284 | * @param src The start of memory for the data to be copied | ||
285 | * @param len The number of bytes of data to copy | ||
286 | * @return Returns true if the method worked. | ||
287 | */ | ||
288 | bool append(S32 channel, const U8* src, S32 len); | ||
289 | |||
290 | /** | ||
291 | * @brief Put data on a channel at the front of this buffer array. | ||
292 | * | ||
293 | * The data is copied from src into the buffer array. At least one | ||
294 | * new segment is created and put in the front of the array. This | ||
295 | * object will internally allocate new buffers if necessary. | ||
296 | * @param channel The channel for this data | ||
297 | |||
298 | * @param src The start of memory for the data to be copied | ||
299 | * @param len The number of bytes of data to copy | ||
300 | * @return Returns true if the method worked. | ||
301 | */ | ||
302 | bool prepend(S32 channel, const U8* src, S32 len); | ||
303 | |||
304 | /** | ||
305 | * @brief Insert data into a buffer array after a particular segment. | ||
306 | * | ||
307 | * The data is copied from src into the buffer array. At least one | ||
308 | * new segment is created and put in the array. This object will | ||
309 | * internally allocate new buffers if necessary. | ||
310 | * @param segment The segment in front of the new segments location | ||
311 | * @param channel The channel for this data | ||
312 | * @param src The start of memory for the data to be copied | ||
313 | * @param len The number of bytes of data to copy | ||
314 | * @return Returns true if the method worked. | ||
315 | */ | ||
316 | bool insertAfter( | ||
317 | segment_iterator_t segment, | ||
318 | S32 channel, | ||
319 | const U8* src, | ||
320 | S32 len); | ||
321 | |||
322 | /** | ||
323 | * @brief Count bytes in the buffer array on the specified channel | ||
324 | * | ||
325 | * @param channel The channel to count. | ||
326 | * @param start The start address in the array for counting. You | ||
327 | * can specify NULL to start at the beginning. | ||
328 | * @return Returns the number of bytes in the channel after start | ||
329 | */ | ||
330 | S32 countAfter(S32 channel, U8* start) const; | ||
331 | |||
332 | /** | ||
333 | * @brief Read bytes in the buffer array on the specified channel | ||
334 | * | ||
335 | * You should prefer iterating over segments is possible since | ||
336 | * this method requires you to allocate large buffers - precisely | ||
337 | * what this class is trying to prevent. This method will skip | ||
338 | * any segments which are not on the given channel, so this method | ||
339 | * would usually be used to read a channel and copy that to a log | ||
340 | * or a socket buffer or something. | ||
341 | * @param channel The channel to read. | ||
342 | * @param start The start address in the array for reading. You | ||
343 | * can specify NULL to start at the beginning. | ||
344 | * @param dest The destination of the data read. This must be at | ||
345 | * least len bytes long. | ||
346 | * @param len[in,out] <b>in</b> How many bytes to read. <b>out</b> How | ||
347 | * many bytes were read. | ||
348 | * @return Returns the address of the last read byte. | ||
349 | */ | ||
350 | U8* readAfter(S32 channel, U8* start, U8* dest, S32& len) const; | ||
351 | |||
352 | /** | ||
353 | * @brief Find an address in a buffer array | ||
354 | * | ||
355 | * @param channel The channel to seek in. | ||
356 | * @param start The start address in the array for the seek | ||
357 | * operation. You can specify NULL to start the seek at the | ||
358 | * beginning, or pass in npos to start at the end. | ||
359 | * @param delta How many bytes to seek through the array. | ||
360 | * @return Returns the address of the last read byte. | ||
361 | */ | ||
362 | U8* seek(S32 channel, U8* start, S32 delta) const; | ||
363 | //@} | ||
364 | |||
365 | /* @name Buffer interaction | ||
366 | */ | ||
367 | //@{ | ||
368 | /** | ||
369 | * @brief Take the contents of another buffer array | ||
370 | * | ||
371 | * This method simply strips the contents out of the source | ||
372 | * buffery array - segments, buffers, etc, and appends them to | ||
373 | * this instance. After this operation, the source is empty and | ||
374 | * ready for reuse. | ||
375 | * @param source The source buffer | ||
376 | * @return Returns true if the operation succeeded. | ||
377 | */ | ||
378 | bool takeContents(LLBufferArray& source); | ||
379 | //@} | ||
380 | |||
381 | /* @name Segment methods | ||
382 | */ | ||
383 | //@{ | ||
384 | /** | ||
385 | * @brief Split a segments so that address is the last address of | ||
386 | * one segment, and the rest of the original segment becomes | ||
387 | * another segment on the same channel. | ||
388 | * | ||
389 | * After this method call, | ||
390 | * <code>getLastSegmentAddress(*getSegment(address)) == | ||
391 | * address</code> should be true. This call will only create a new | ||
392 | * segment if the statement above is false before the call. Since | ||
393 | * you usually call splitAfter() to change a segment property, use | ||
394 | * getSegment() to perform those operations. | ||
395 | * @param address The address which will become the last address | ||
396 | * of the segment it is in. | ||
397 | * @return Returns an iterator to the segment which contains | ||
398 | * <code>address</code> which is <code>endSegment()</code> on | ||
399 | * failure. | ||
400 | */ | ||
401 | segment_iterator_t splitAfter(U8* address); | ||
402 | |||
403 | /** | ||
404 | * @brief Get the first segment in the buffer array. | ||
405 | * | ||
406 | * @return Returns the segment if there is one. | ||
407 | */ | ||
408 | segment_iterator_t beginSegment(); | ||
409 | |||
410 | /** | ||
411 | * @brief Get the one-past-the-end segment in the buffer array | ||
412 | * | ||
413 | * @return Returns the iterator for an invalid segment location. | ||
414 | */ | ||
415 | segment_iterator_t endSegment(); | ||
416 | |||
417 | /** | ||
418 | * @brief Get the segment which holds the given address. | ||
419 | * | ||
420 | * As opposed to some methods, passing a NULL will result in | ||
421 | * returning the end segment. | ||
422 | * @param address An address in the middle of the sought segment. | ||
423 | * @return Returns the iterator for the segment or endSegment() on | ||
424 | * failure. | ||
425 | */ | ||
426 | const_segment_iterator_t getSegment(U8* address) const; | ||
427 | |||
428 | /** | ||
429 | * @brief Get the segment which holds the given address. | ||
430 | * | ||
431 | * As opposed to some methods, passing a NULL will result in | ||
432 | * returning the end segment. | ||
433 | * @param address An address in the middle of the sought segment. | ||
434 | * @return Returns the iterator for the segment or endSegment() on | ||
435 | * failure. | ||
436 | */ | ||
437 | segment_iterator_t getSegment(U8* address); | ||
438 | |||
439 | /** | ||
440 | * @brief Get a segment iterator after address, and a constructed | ||
441 | * segment to represent the next linear block of memory. | ||
442 | * | ||
443 | * This method is a helper by giving you the largest segment | ||
444 | * possible in the out-value param after the address provided. The | ||
445 | * iterator will be useful for iteration, while the segment can be | ||
446 | * used for direct access to memory after address if the return | ||
447 | * values isnot end. Passing in NULL will return beginSegment() | ||
448 | * which may be endSegment(). The segment returned will only be | ||
449 | * zero length if the return value equals end. | ||
450 | * This is really just a helper method, since all the information | ||
451 | * returned could be constructed through other methods. | ||
452 | * @param address An address in the middle of the sought segment. | ||
453 | * @param segment[out] segment to be used for reading or writing | ||
454 | * @return Returns an iterator which contains at least segment or | ||
455 | * endSegment() on failure. | ||
456 | */ | ||
457 | segment_iterator_t constructSegmentAfter(U8* address, LLSegment& segment); | ||
458 | |||
459 | /** | ||
460 | * @brief Make a new segment at the end of buffer array | ||
461 | * | ||
462 | * This method will attempt to create a new and empty segment of | ||
463 | * the specified length. The segment created may be shorter than | ||
464 | * requested. | ||
465 | * @param channel[in] The channel for the newly created segment. | ||
466 | * @param length[in] The requested length of the segment. | ||
467 | * @return Returns an iterator which contains at least segment or | ||
468 | * endSegment() on failure. | ||
469 | */ | ||
470 | segment_iterator_t makeSegment(S32 channel, S32 length); | ||
471 | |||
472 | /** | ||
473 | * @brief Erase the segment if it is in the buffer array. | ||
474 | * | ||
475 | * @param iter An iterator referring to the segment to erase. | ||
476 | * @return Returns true on success. | ||
477 | */ | ||
478 | bool eraseSegment(const segment_iterator_t& iter); | ||
479 | //@} | ||
480 | |||
481 | protected: | ||
482 | /** | ||
483 | * @brief Optimally put data in buffers, and reutrn segments. | ||
484 | * | ||
485 | * This is an internal function used to create buffers as | ||
486 | * necessary, and sequence the segments appropriately for the | ||
487 | * various ways to copy data from src into this. | ||
488 | * If this method fails, it may actually leak some space inside | ||
489 | * buffers, but I am not too worried about the slim possibility | ||
490 | * that we may have some 'dead' space which will be recovered when | ||
491 | * the buffer (which we will not lose) is deleted. Addressing this | ||
492 | * weakness will make the buffers almost as complex as a general | ||
493 | * memory management system. | ||
494 | * @param channel The channel for this data | ||
495 | * @param src The start of memory for the data to be copied | ||
496 | * @param len The number of bytes of data to copy | ||
497 | * @param segments Out-value for the segments created. | ||
498 | * @return Returns true if the method worked. | ||
499 | */ | ||
500 | bool copyIntoBuffers( | ||
501 | S32 channel, | ||
502 | const U8* src, | ||
503 | S32 len, | ||
504 | std::vector<LLSegment>& segments); | ||
505 | |||
506 | protected: | ||
507 | S32 mNextBaseChannel; | ||
508 | buffer_list_t mBuffers; | ||
509 | segment_list_t mSegments; | ||
510 | }; | ||
511 | |||
512 | #endif // LL_LLBUFFER_H | ||