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