BufferReader.hh

Go to the documentation of this file.
00001 
00019 #ifndef avro_BufferReader_hh__
00020 #define avro_BufferReader_hh__
00021 
00022 #include "Buffer.hh"
00023 
00032 namespace avro {
00033 
00039 class BufferReader : private boost::noncopyable 
00040 {
00041 
00042   public:
00043 
00044     typedef detail::data_type data_type;
00045     typedef detail::size_type size_type;
00046     
00047   private:
00048 
00049     size_type chunkRemaining() const {
00050         return iter_->dataSize() - chunkPos_;
00051     }
00052 
00053     void incrementChunk(size_type howmuch) {
00054         bytesRemaining_ -= howmuch;
00055         chunkPos_ += howmuch;
00056         if(chunkPos_ == iter_->dataSize()) {
00057             chunkPos_ = 0;
00058             ++iter_;
00059         }
00060     }
00061 
00062     void rewind() {
00063         iter_ = bufferImpl_->beginRead();
00064         bytesRemaining_ = bytes_;
00065         chunkPos_ = 0;
00066     }
00067 
00068     const data_type *addr() const {
00069         return iter_->tellReadPos() + chunkPos_;
00070     }
00071 
00072   public:
00073 
00074     BufferReader(const InputBuffer &buf) :
00075         bufferImpl_(buf.pimpl_),
00076         iter_(bufferImpl_->beginRead()),
00077         bytes_(bufferImpl_->size()),
00078         bytesRemaining_(bytes_),
00079         chunkPos_(0)
00080     { }
00081 
00082     BufferReader(const OutputBuffer &buf) :
00083         bufferImpl_(buf.pimpl_),
00084         iter_(bufferImpl_->beginRead()),
00085         bytes_(bufferImpl_->size()),
00086         bytesRemaining_(bytes_),
00087         chunkPos_(0)
00088     { }
00089 
00094     size_type bytesRemaining() const {
00095         return bytesRemaining_;
00096     }
00097 
00102     size_type bytesRead() const {
00103         return bytes_ - bytesRemaining_;
00104     }
00105 
00110     size_type read(data_type *data, size_type size) { 
00111 
00112         if(size > bytesRemaining_) {
00113             size = bytesRemaining_;
00114         }
00115         size_type sizeToRead = size;
00116 
00117         while(sizeToRead) {
00118             const size_type toRead = std::min(sizeToRead, chunkRemaining());
00119             memcpy(data, addr(), toRead);
00120             sizeToRead -= toRead;
00121             data += toRead;
00122             incrementChunk(toRead);
00123         }
00124 
00125         return size;
00126     }
00127 
00132     bool read(std::string &str, size_type size) { 
00133         if(size > bytesRemaining_) {
00134             return false;
00135         }
00136 
00137         if(size <= chunkRemaining()) {
00138             fastStringRead(str, size);
00139         }
00140         else {
00141             slowStringRead(str, size);
00142         }
00143 
00144         return true;
00145     }
00146 
00147 
00154     template<typename T>
00155     bool read(T &val)  {
00156         return read(val, boost::is_fundamental<T>());
00157     }
00158 
00163     bool skip(size_type bytes) {
00164         bool skipped = false;
00165         if(bytes <= bytesRemaining_) {
00166             doSkip(bytes);
00167             skipped = true;
00168         }
00169         return skipped;
00170     }
00171 
00176     bool seek(size_type pos) {
00177         if(pos > bytes_) {
00178             return false;
00179         }
00180 
00181         size_type toSkip = pos;
00182         size_type curPos = bytesRead();
00183         // if the seek position is ahead, we can use skip to get there
00184         if(pos >= curPos) {
00185             toSkip -= curPos;
00186         }
00187         // if the seek position is ahead of the start of the chunk we can back up to
00188         // start of the chunk
00189         else if(pos >= (curPos - chunkPos_)) {
00190             curPos -= chunkPos_;
00191             bytesRemaining_ += chunkPos_;
00192             chunkPos_ = 0;
00193             toSkip -= curPos;
00194         }
00195         else {
00196             rewind();
00197         }
00198         doSkip(toSkip);
00199         return true;
00200     }
00201 
00202     bool peek(char &val) {
00203         bool ret = (bytesRemaining_ > 0);
00204         if(ret) {
00205             val = *(addr());
00206         }
00207         return ret;
00208     }
00209 
00210     InputBuffer copyData(size_type bytes) {
00211         if(bytes > bytesRemaining_) {
00212             // force no copy
00213             bytes = 0;
00214         }
00215         detail::BufferImpl::SharedPtr newImpl(new detail::BufferImpl);
00216         if(bytes) {
00217             bufferImpl_->copyData(*newImpl, iter_, chunkPos_, bytes);
00218             doSkip(bytes);
00219         }
00220         return InputBuffer(newImpl);
00221     }
00222 
00223   private:
00224 
00225     void doSkip(size_type sizeToSkip) {
00226 
00227         while(sizeToSkip) {
00228             const size_type toSkip = std::min(sizeToSkip, chunkRemaining());
00229             sizeToSkip -= toSkip;
00230             incrementChunk(toSkip);
00231         }
00232     }
00233 
00234     template<typename T>
00235     bool read(T &val, const boost::true_type&)
00236     {
00237         if(sizeof(T) > bytesRemaining_) {
00238             return false;
00239         }
00240 
00241         if (sizeof(T) <= chunkRemaining()) {
00242             val = *(reinterpret_cast<const T*> (addr()));
00243             incrementChunk(sizeof(T));
00244         }
00245         else {
00246             read(reinterpret_cast<data_type *>(&val), sizeof(T));
00247         }
00248         return true;
00249     }
00250 
00252     template<typename T>
00253     bool read(T &val, const boost::false_type&)
00254     {
00255         BOOST_STATIC_ASSERT(sizeof(T)==0);
00256         return false;
00257     }
00258 
00259     void fastStringRead(std::string &str, size_type sizeToCopy) {
00260         str.assign(addr(), sizeToCopy);
00261         incrementChunk(sizeToCopy);
00262     }
00263             
00264     void slowStringRead(std::string &str, size_type sizeToCopy) {
00265         str.clear();
00266         str.reserve(sizeToCopy);
00267         while(sizeToCopy) {
00268             const size_type toCopy = std::min(sizeToCopy, chunkRemaining());
00269             str.append(addr(), toCopy);
00270             sizeToCopy -= toCopy;
00271             incrementChunk(toCopy);
00272         }
00273     }
00274 
00275     detail::BufferImpl::ConstSharedPtr bufferImpl_;
00276     detail::BufferImpl::ChunkList::const_iterator iter_;
00277     size_type bytes_;
00278     size_type bytesRemaining_;
00279     size_type chunkPos_;
00280 };
00281 
00282 
00283 } // namespace
00284 
00285 #endif
Generated on Thu Sep 2 18:40:54 2010 for Avro C++ by  doxygen 1.6.3