Main Page | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members

RageUtil_CircularBuffer.h

Go to the documentation of this file.
00001 #ifndef RAGE_UTIL_CIRCULAR_BUFFER 00002 #define RAGE_UTIL_CIRCULAR_BUFFER 00003 00004 /* Lock-free circular buffer. This should be threadsafe if one thread is reading 00005 * and another is writing. */ 00006 template<class T> 00007 class CircBuf 00008 { 00009 T *buf; 00010 /* read_pos is the position data is read from; write_pos is the position 00011 * data is written to. If read_pos == write_pos, the buffer is empty. 00012 * 00013 * There will always be at least one position empty, as a completely full 00014 * buffer (read_pos == write_pos) is indistinguishable from an empty buffer. 00015 * 00016 * Invariants: read_pos < size, write_pos < size. */ 00017 unsigned size; 00018 00019 /* These are volatile to prevent reads and writes to them from being optimized. */ 00020 volatile unsigned read_pos, write_pos; 00021 00022 public: 00023 CircBuf() 00024 { 00025 buf = NULL; 00026 clear(); 00027 } 00028 00029 ~CircBuf() 00030 { 00031 delete[] buf; 00032 } 00033 00034 /* Return the number of elements available to read. */ 00035 unsigned num_readable() const 00036 { 00037 const int rpos = read_pos; 00038 const int wpos = write_pos; 00039 if( rpos < wpos ) 00040 /* The buffer looks like "eeeeDDDDeeee" (e = empty, D = data). */ 00041 return wpos - rpos; 00042 else if( rpos > wpos ) 00043 /* The buffer looks like "DDeeeeeeeeDD" (e = empty, D = data). */ 00044 return size - (rpos - wpos); 00045 else // if( rpos == wpos ) 00046 /* The buffer looks like "eeeeeeeeeeee" (e = empty, D = data). */ 00047 return 0; 00048 } 00049 00050 /* Return the number of elements writable. Note that there must always 00051 * be one */ 00052 unsigned num_writable() const 00053 { 00054 const int rpos = read_pos; 00055 const int wpos = write_pos; 00056 00057 int ret; 00058 if( rpos < wpos ) 00059 /* The buffer looks like "eeeeDDDDeeee" (e = empty, D = data). */ 00060 ret = size - (wpos - rpos); 00061 else if( rpos > wpos ) 00062 /* The buffer looks like "DDeeeeeeeeDD" (e = empty, D = data). */ 00063 ret = rpos - wpos; 00064 else // if( rpos == wpos ) 00065 /* The buffer looks like "eeeeeeeeeeee" (e = empty, D = data). */ 00066 ret = size; 00067 00068 /* Subtract one, to account for the element that we never fill. */ 00069 return ret - 1; 00070 } 00071 00072 unsigned capacity() const { return size; } 00073 00074 void reserve( unsigned n ) 00075 { 00076 clear(); 00077 delete[] buf; 00078 buf = NULL; 00079 00080 /* Reserve an extra byte. We'll never fill more than n bytes; the extra 00081 * byte is to guarantee that read_pos != write_pos when the buffer is full, 00082 * since that would be ambiguous with an empty buffer. */ 00083 if( n != 0 ) 00084 { 00085 buf = new T[n+1]; 00086 size = n+1; 00087 } 00088 else 00089 size = 0; 00090 } 00091 00092 void clear() 00093 { 00094 read_pos = write_pos = 0; 00095 } 00096 00097 /* Indicate that n elements have been written. */ 00098 void advance_write_pointer( int n ) 00099 { 00100 write_pos = (write_pos + n) % size; 00101 } 00102 00103 /* Indicate that n elements have been read. */ 00104 void advance_read_pointer( int n ) 00105 { 00106 read_pos = (read_pos + n) % size; 00107 } 00108 00109 void get_write_pointers( T *pPointers[2], unsigned pSizes[2] ) 00110 { 00111 const int rpos = read_pos; 00112 const int wpos = write_pos; 00113 00114 if( rpos <= wpos ) 00115 { 00116 /* The buffer looks like "eeeeDDDDeeee" or "eeeeeeeeeeee" (e = empty, D = data). */ 00117 pPointers[0] = buf+wpos; 00118 pPointers[1] = buf; 00119 00120 pSizes[0] = size - wpos; 00121 pSizes[1] = rpos; 00122 } 00123 else if( rpos > wpos ) 00124 { 00125 /* The buffer looks like "DDeeeeeeeeDD" (e = empty, D = data). */ 00126 pPointers[0] = buf+wpos; 00127 pPointers[1] = NULL; 00128 00129 pSizes[0] = rpos - wpos; 00130 pSizes[1] = 0; 00131 } 00132 00133 /* Subtract one, to account for the element that we never fill. */ 00134 if( pSizes[1] ) 00135 --pSizes[1]; 00136 else 00137 --pSizes[0]; 00138 } 00139 00140 void get_read_pointers( T *pPointers[2], unsigned pSizes[2] ) 00141 { 00142 const int rpos = read_pos; 00143 const int wpos = write_pos; 00144 00145 if( rpos < wpos ) 00146 { 00147 /* The buffer looks like "eeeeDDDDeeee" (e = empty, D = data). */ 00148 pPointers[0] = buf+rpos; 00149 pPointers[1] = NULL; 00150 00151 pSizes[0] = wpos - rpos; 00152 pSizes[1] = 0; 00153 } 00154 else if( rpos > wpos ) 00155 { 00156 /* The buffer looks like "DDeeeeeeeeDD" (e = empty, D = data). */ 00157 pPointers[0] = buf+rpos; 00158 pPointers[1] = buf; 00159 00160 pSizes[0] = size - rpos; 00161 pSizes[1] = wpos; 00162 } 00163 else 00164 { 00165 /* The buffer looks like "eeeeeeeeeeee" (e = empty, D = data). */ 00166 pPointers[0] = NULL; 00167 pPointers[1] = NULL; 00168 00169 pSizes[0] = 0; 00170 pSizes[1] = 0; 00171 } 00172 } 00173 00174 /* Write buffer_size elements from buffer, and advance the write pointer. If 00175 * the data will not fit entirely, the write pointer will be unchanged 00176 * and false will be returned. */ 00177 bool write( const T *buffer, unsigned buffer_size ) 00178 { 00179 T *p[2]; 00180 unsigned sizes[2]; 00181 get_write_pointers( p, sizes ); 00182 00183 if( buffer_size > sizes[0] + sizes[1] ) 00184 return false; 00185 00186 const int from_first = min( buffer_size, sizes[0] ); 00187 memcpy( p[0], buffer, from_first*sizeof(T) ); 00188 if( buffer_size > sizes[0] ) 00189 memcpy( p[1], buffer+from_first, max(buffer_size-sizes[0], 0u)*sizeof(T) ); 00190 00191 advance_write_pointer( buffer_size ); 00192 00193 return true; 00194 } 00195 00196 /* Read buffer_size elements from buffer, and advance the read pointer. If 00197 * the buffer can not be filled completely, the read pointer will be unchanged 00198 * and false will be returned. */ 00199 bool read( T *buffer, unsigned buffer_size ) 00200 { 00201 T *p[2]; 00202 unsigned sizes[2]; 00203 get_read_pointers( p, sizes ); 00204 00205 if( buffer_size > sizes[0] + sizes[1] ) 00206 return false; 00207 00208 const int from_first = min( buffer_size, sizes[0] ); 00209 memcpy( buffer, p[0], from_first*sizeof(T) ); 00210 if( buffer_size > sizes[0] ) 00211 memcpy( buffer+from_first, p[1], max(buffer_size-sizes[0], 0u)*sizeof(T) ); 00212 00213 /* Set the data that we just read to 0xFF. This way, if we're passing pointesr 00214 * through, we can tell if we accidentally get a stale pointer. */ 00215 memset( p[0], 0xFF, from_first*sizeof(T) ); 00216 if( buffer_size > sizes[0] ) 00217 memset( p[1], 0xFF, max(buffer_size-sizes[0], 0u)*sizeof(T) ); 00218 00219 advance_read_pointer( buffer_size ); 00220 return true; 00221 } 00222 }; 00223 00224 #endif 00225 00226 /* 00227 * Copyright (c) 2004 Glenn Maynard 00228 * All rights reserved. 00229 * 00230 * Permission is hereby granted, free of charge, to any person obtaining a 00231 * copy of this software and associated documentation files (the 00232 * "Software"), to deal in the Software without restriction, including 00233 * without limitation the rights to use, copy, modify, merge, publish, 00234 * distribute, and/or sell copies of the Software, and to permit persons to 00235 * whom the Software is furnished to do so, provided that the above 00236 * copyright notice(s) and this permission notice appear in all copies of 00237 * the Software and that both the above copyright notice(s) and this 00238 * permission notice appear in supporting documentation. 00239 * 00240 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00241 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00242 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF 00243 * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS 00244 * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT 00245 * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 00246 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 00247 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 00248 * PERFORMANCE OF THIS SOFTWARE. 00249 */

Generated on Thu Jan 27 20:57:30 2005 for StepMania by doxygen 1.3.7