sprint 1-alpha
|
00001 /****************************************************************************** 00002 * SPRINT::bufferize 00003 * 00004 * Copyright (C) 2005-2011 Paolo Medici <www.pmx.it> 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 * 00020 *******************************************************************************/ 00021 00025 #ifndef _BUFFERIZE_H 00026 #define _BUFFERIZE_H 00027 00028 namespace sprint { 00029 00031 class data_buffer { 00032 00034 struct _Rep { 00035 int m_size; 00036 int m_capacity; 00037 int m_pos; 00038 }; 00039 00041 inline _Rep *_M_rep() const 00042 { 00043 return reinterpret_cast<_Rep*>(m_data); 00044 } 00045 00047 unsigned char *m_data; 00048 00049 private: 00051 data_buffer(const data_buffer & src) { } 00052 00053 public: 00054 data_buffer(int capacity) { 00055 m_data = new unsigned char[ sizeof(_Rep) + capacity ]; 00056 _M_rep()->m_capacity = capacity; 00057 _M_rep()->m_pos = 0; 00058 _M_rep()->m_size = 0; 00059 } 00060 00061 ~data_buffer() { delete [] m_data; } 00062 00064 inline int capacity() const { return _M_rep()->m_capacity; } 00065 00067 inline int size() const { return _M_rep()->m_size; } 00069 inline void size(int s) { _M_rep()->m_size = s; } 00070 00072 inline int pos() const { return _M_rep()->m_pos; } 00073 inline void pos(int p) { _M_rep()->m_pos = p; } 00074 00076 inline void skip(int s) { _M_rep()->m_pos += s; } 00078 inline int remain() const { return _M_rep()->m_size - _M_rep()->m_pos; } 00079 00081 inline unsigned char *data() const { return m_data + sizeof(_Rep); } 00083 inline unsigned char *cur() const { return m_data + sizeof(_Rep) + _M_rep()->m_pos; } 00084 00086 inline unsigned char peek() { 00087 return m_data[sizeof(_Rep) + _M_rep()->m_pos]; 00088 } 00089 00091 inline unsigned char get() { 00092 return m_data[sizeof(_Rep) + _M_rep()->m_pos++]; 00093 } 00095 inline void put(unsigned char c) { 00096 m_data[sizeof(_Rep) + _M_rep()->m_pos] = c; 00097 _M_rep()->m_pos++; 00098 } 00099 00101 inline bool full() const { return _M_rep()->m_pos == _M_rep()->m_capacity; } 00102 00104 inline bool avail() const { return _M_rep()->m_pos<_M_rep()->m_size; } 00105 00107 int write(const unsigned char *src, int len) 00108 { 00109 int r = _M_rep()->m_capacity - _M_rep()->m_pos; 00110 if(r>0) 00111 { 00112 int copiable = std::min(len, r); 00113 ::memcpy(cur(), src, copiable); 00114 _M_rep()->m_pos += copiable; 00115 _M_rep()->m_size = _M_rep()->m_pos; // volendo si potrebbe scrivere ovunque nel buffer 00116 return copiable; 00117 } 00118 else 00119 return 0; 00120 } 00121 00123 int put(char c) 00124 { 00125 int r = _M_rep()->m_capacity - _M_rep()->m_pos; 00126 if(r>0) 00127 { 00128 *cur() = c; 00129 00130 _M_rep()->m_pos ++; 00131 _M_rep()->m_size = _M_rep()->m_pos; // volendo si potrebbe scrivere ovunque nel buffer 00132 return 1; 00133 } 00134 else 00135 return 0; 00136 } 00137 00141 int read(unsigned char *dst, int len) 00142 { 00143 int r = remain(); 00144 if( r>0 ) 00145 { 00146 int copiable = std::min(len, r); 00147 ::memcpy(dst, cur(), copiable); 00148 skip(copiable); 00149 return copiable; 00150 } 00151 else 00152 return 0; 00153 } 00154 00155 00156 00157 }; 00158 00169 template<class T> 00170 class read_buffer : public T { 00175 data_buffer m_buf; 00176 00178 bool m_valid; 00179 00180 private: 00181 00185 bool underrun() 00186 { 00187 int len = T::read( (char *) m_buf.data(), m_buf.capacity() ); 00188 if(len <=0 ) 00189 { 00190 m_valid = false; 00191 return false; 00192 } 00193 00194 m_buf.size (len); 00195 m_buf.pos(0); 00196 return true; 00197 } 00198 00202 int direct_read(unsigned char *dst, int len) 00203 { 00204 int readed = 0; 00205 while(len>0) 00206 { 00207 int read = T::read((char *) dst, len); 00208 if(read == -1) 00209 return -1; 00210 len -= read; 00211 dst += read; 00212 readed += read; 00213 } 00214 return readed; 00215 } 00216 00218 inline bool check_underrun() 00219 { 00220 while(!m_buf.avail()) 00221 { 00222 if(!valid()) 00223 return false; 00224 underrun(); 00225 } 00226 return true; 00227 } 00228 public: 00230 template<class P> 00231 read_buffer(const P & p, int capacity) : T(p), m_buf(capacity), m_valid(true) { } 00233 read_buffer(int capacity) : m_buf(capacity), m_valid(true) { } 00234 00236 inline bool valid() const { return m_valid && m_buf.size()!=-1; } 00237 00239 int remain() const { return m_buf.remain(); } 00240 00243 int readsome(unsigned char *dst, int len) 00244 { 00245 return check_underrun() ? m_buf.read(dst,len) : -1; 00246 } 00247 00249 int read(unsigned char *dst, int len) 00250 { 00251 int r; 00252 int p = 0; 00253 if(!valid()) 00254 return -1; 00255 // leggo intanto dal buffer quanto è presente 00256 r = m_buf.read(dst, len); 00257 p += r; 00258 00259 if(p<len) 00260 { 00261 // se sono qua read ha finito il buffer 00262 00263 // il dato rimanente da leggere è più piccolo dell'eventuale capacità? 00264 if((p-len)<m_buf.capacity()) 00265 { 00266 // underrun non garantisce però che il dato caricato sia esattamente size 00267 while(p<len) 00268 { 00269 if(!underrun()) 00270 return p; 00271 00272 p += m_buf.read(dst+p,len-p); 00273 } 00274 } 00275 else 00276 { 00277 // uso direttamente il buffer fornito dall'utente. 00278 // E' comunque più grande del buffer interno e risparmio un memcpy 00279 p += direct_read(dst+p, len-p); 00280 } 00281 } 00282 return p; 00283 } 00284 00285 // read and disband data 00286 inline int skip(int n) 00287 { 00288 // TODO: 00289 } 00290 00292 inline int peek() 00293 { 00294 return check_underrun() ? m_buf.peek() : -1; 00295 } 00296 00298 inline int get() 00299 { 00300 return check_underrun() ? m_buf.get() : -1; 00301 } 00302 }; 00303 00308 template<class T> 00309 class write_buffer: public T { 00310 00314 data_buffer m_buf; 00315 00317 bool m_valid; 00318 00319 public: 00320 00321 write_buffer(const T & t, int capacity) : T(t), m_buf(capacity), m_valid(true) { } 00322 ~write_buffer() { 00323 // empty buffer on exit 00324 flush(); 00325 } 00326 00328 bool good() const { return m_valid; } 00329 00331 bool write(const unsigned char *ptr, int n) 00332 { 00333 int p=0; 00334 // if the size of data is greater of buffer capacity buffer will be 00335 // bypassed 00336 if(n > m_buf.capacity()) 00337 { 00338 flush(); 00339 T::write(ptr, n); 00340 } 00341 else 00342 { 00343 // sposta i dati nel data_buffer, incrementando 00344 while(n>0) 00345 { 00346 int w = m_buf.write(ptr, n); 00347 n-=w; 00348 if(m_buf.full()) 00349 flush(); 00350 } 00351 } 00352 return true; 00353 } 00354 00356 bool flush() 00357 { 00358 if(!m_valid) 00359 return false; 00360 if(m_buf.size() > 0) 00361 { 00362 int n = m_buf.size(); 00363 unsigned char *src = m_buf.data(); 00365 while(n>0) 00366 { 00367 int r = T::write( src, n ); 00368 if(r<=0) 00369 { 00370 m_valid = false; 00371 return false; 00372 } 00373 n -=r; 00374 src+=r; 00375 } 00376 m_buf.size(0); 00377 m_buf.pos(0); 00378 } 00379 return true; 00380 } 00381 00383 inline bool put(unsigned char c) 00384 { 00385 m_buf.put(c); 00386 if(m_buf.full()) 00387 flush(); 00388 return true; 00389 } 00390 00391 }; 00392 00393 } 00394 00395 #endif