1 /*
2     Copyright (c) 2009 NetAllied Systems GmbH
3 
4     This file is part of Common libBuffer.
5 
6     Licensed under the MIT Open Source License,
7     for details please see LICENSE file or the website
8     http://www.opensource.org/licenses/mit-license.php
9 */
10 
11 #ifndef __COMMON_BUFFER_H__
12 #define __COMMON_BUFFER_H__
13 
14 #include "CommonIBufferFlusher.h"
15 #include <string.h>
16 
17 namespace Common
18 {
19 	class Buffer
20 	{
21 	private:
22 		/** Pointer to the buffer.*/
23 		char* mBuffer;
24 
25 		/** The size of the buffer.*/
26 		size_t mBufferSize;
27 
28 		/** Pointer to the first unused byte in the buffer.*/
29 		char* mCurrentPos;
30 
31 		/** Minimum size of data that will be flushed directly without copying to the buffer. The current buffer will
32 		be flushed before. */
33 		size_t mDirectFlushSize;
34 
35 		/** Total number of bytes already passed to the flusher.*/
36 		size_t mBytesFlushed;
37 
38 		/** The flusher used to flush the buffer.*/
39 		IBufferFlusher* mFlusher;
40 
41 		bool mMarkSet;
42 
43 		bool mIsOverwriting;
44 
45 	public:
46 		Buffer(size_t bufferSize, IBufferFlusher* flusher);
47 
48 		virtual ~Buffer();
49 
50 		/** The flusher used to flush the buffer.*/
getFlusher()51 		IBufferFlusher* getFlusher() const { return mFlusher; }
52 
53 		/** Flushes the to using the buffer flusher.
54 		@return True on success, false otherwise.
55 		@note Calling this method does not force to flusher to flush its data. To force this call flushFlusher instead.*/
56 		bool flushBuffer();
57 
58 		/** Flushes the flusher. Call this to ensure that the data is really been handled by the flusher.
59 		This method implicitly calls flushBuffer.*/
60 		bool flushFlusher();
61 
62 		/** Copies @a length bytes into the buffer, starting at @a data .*/
63 		template<class T>
64 		bool copyToBuffer( const T* data, size_t length);
65 
66 		/** Copies null terminated @a text  into the buffer.*/
67 		bool copyToBuffer( const char* text);
68 
69 		/** Copies @a c  into the buffer.*/
70 		template<class T>
71 		bool copyToBuffer( const T& c);
72 
getBufferSize()73 		size_t getBufferSize() const { return mBufferSize; }
74 
75 		/** The number of bytes currently in the buffer.*/
76 		size_t getBytesUsed() const;
77 
78 		/** The number of bytes currently available in the buffer.*/
79 		size_t getBytesAvailable() const;
80 
81 		/** The number of bytes already copied to the buffer.*/
82 		size_t getBytesCopiedToBuffer() const;
83 
84 		/** @return True, if the buffer does not contain any data, false otherwise.*/
85 		size_t isEmpty() const;
86 
87 		/** Minimum size of data that will be flushed directly without copying to the buffer. The current buffer will
88 		be flushed before. */
89 		size_t getDirectFlushSize() const;
90 
91 		/** Minimum size of data that will be flushed directly without copying to the buffer. The current buffer will
92 		be flushed before. If @a directFlushSize is larger than the buffer size, the direct flush size will be set
93 		to the buffer size. */
94 		void setDirectFlushSize(size_t directFlushSize);
95 
96 		/**
97 		* Setting the start mark.
98 		* @return True if start mark could be set, otherwise false.
99 		*/
100 		bool startMark();
101 
102 		IBufferFlusher::MarkId endMark();
103 
104 	    bool jumpToMark(IBufferFlusher::MarkId markId, bool keepMarkId = false);
105 
106 	protected:
107 
108 		/** Provides access to the current position of the buffer for derived classes. Might be useful for
109 		implementations that want to write into the buffer directly. Use increaseCurrentPosition to tell the buffer
110 		how many bytes have been added to the buffer. Before writing into the buffer directly, use
111 		getBytesAvailable to ensure there is enough space available.*/
getCurrentPosition()112 		char* getCurrentPosition() { return mCurrentPos; }
113 
114 		/** Shifts the current position in the buffer by @a addedBytes bytes. No check is performed if the
115 		new position is beyond the buffers end.*/
116 		void increaseCurrentPosition( size_t addedBytes);
117 
118 		/** Shifts the current position in the buffer by 1 byte. No check is performed if the
119 		new position is beyond the buffers end.*/
120 		void increaseCurrentPosition();
121 
122 	private:
123         /** Disable default copy ctor. */
124 		Buffer( const Buffer& pre );
125         /** Disable default assignment operator. */
126 		const Buffer& operator= ( const Buffer& pre );
127 
128 		bool sendDataToFlusher( const char* buffer, size_t length);
129 	};
130 
131 
132 	//--------------------------------------------------------------------
133 	template<class T>
copyToBuffer(const T * data,size_t length)134 	bool Buffer::copyToBuffer( const T* data, size_t length )
135 	{
136 		static const size_t typeSize = sizeof(T);
137 		size_t arraySize = length * typeSize;
138 
139 		if ( arraySize >= mDirectFlushSize )
140 		{
141 			// the data is large enough to flush directly
142 			// flush the buffer first
143 			if ( !flushBuffer() )
144 			{
145 				// the buffer could not be flushed
146 				return false;
147 			}
148 
149 			// flush the new data directly
150 			return sendDataToFlusher( (const char *)data, arraySize );
151 		}
152 
153 		if ( arraySize > getBytesAvailable() )
154 		{
155 			// the new data does not fit into the buffer. We need to flush first.
156 			if ( !flushBuffer() )
157 			{
158 				// the buffer could not be flushed
159 				return false;
160 			}
161 		}
162 
163 		// copy data into buffer.
164 		memcpy( mCurrentPos, data, arraySize );
165 		mCurrentPos += arraySize;
166 		return true;
167 	}
168 
169 	//--------------------------------------------------------------------
170 	template<class T>
copyToBuffer(const T & c)171 	bool Buffer::copyToBuffer( const T& c )
172 	{
173 		static const size_t typeSize = sizeof(T);
174 		if ( mDirectFlushSize <= typeSize )
175 		{
176 			// the data is large enough to flush directly
177 			// flush the buffer first
178 			if ( !flushBuffer() )
179 			{
180 				// the buffer could not be flushed
181 				return false;
182 			}
183 
184 			// flush the new data directly
185 			return sendDataToFlusher( (const char *)&c, typeSize );
186 		}
187 
188 		if ( getBytesAvailable() < typeSize)
189 		{
190 			// the new data does not fit into the buffer. We need to flush first.
191 			if ( !flushBuffer() )
192 			{
193 				// the buffer could not be flushed
194 				return false;
195 			}
196 		}
197 
198 		// copy data into buffer.
199 		T* typePos = (T*)mCurrentPos;
200 		*typePos = c;
201 		mCurrentPos += typeSize;
202 		return true;
203 	}
204 
205 
206 
207 } // namespace COMMON
208 
209 #endif // __COMMON_BUFFER_H__
210