core/vil/vil_stream_core.cxx
Go to the documentation of this file.
00001 // This is core/vil/vil_stream_core.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \author fsm
00008 
00009 #include "vil_stream_core.h"
00010 #include <vcl_cassert.h>
00011 #include <vcl_cstddef.h> // for vcl_size_t
00012 #include <vcl_limits.h>
00013 
00014 vil_stream_core::vil_stream_core(unsigned block_size)
00015     : curpos_(0), blocksize_(block_size), tailpos_(0)
00016 { }
00017 
00018 //--------------------------------------------------------------------------------
00019 
00020 vil_stream_core::~vil_stream_core()
00021 {
00022   for (unsigned i=0; i<block_.size(); ++i)
00023     delete [] block_[i];
00024   block_.clear();
00025 }
00026 
00027 //--------------------------------------------------------------------------------
00028 
00029 vil_streampos vil_stream_core::read(void *buf, vil_streampos n)
00030 {
00031   assert(n>=0);
00032 
00033   vil_streampos rv = m_transfer((char*)buf, curpos_, n, true);
00034   curpos_ += rv;
00035   return rv;
00036 }
00037 
00038 //--------------------------------------------------------------------------------
00039 
00040 vil_streampos vil_stream_core::write(void const *buf, vil_streampos n)
00041 {
00042   assert(n>=0);
00043   vil_streampos rv = m_transfer(static_cast<char*>(const_cast<void *>(buf)), curpos_, n, false);
00044   curpos_ += rv;
00045   return rv;
00046 }
00047 
00048 //--------------------------------------------------------------------------------
00049 
00050 vil_streampos vil_stream_core::m_transfer(char *buf, vil_streampos pos, vil_streampos n, bool read_into_buf)
00051 {
00052   assert(n>=0);
00053   assert(pos>=0);
00054 
00055   if (read_into_buf)
00056   {
00057     if (pos+n > tailpos_)
00058     {
00059       if (pos > tailpos_)
00060         n = 0;
00061       else
00062         n = tailpos_ - pos;
00063     }
00064     if (n==0L) return 0;
00065   }
00066   else
00067     // chunk up to the required size :
00068     while (blocksize_*block_.size() < (unsigned long)(pos+n))
00069       block_.push_back(new char [blocksize_]);
00070 
00071   // transfer data
00072   {
00073     char         *tbuf = buf;
00074     vil_streampos tpos = pos;
00075     vil_streampos tn   = n;
00076     while (tn>0) {
00077       vil_streampos bl = tpos/(long)blocksize_;     // which block
00078       vil_streampos s = tpos - (long)blocksize_*bl; // start index in block_
00079       vil_streampos z = ((tn+s > (long)blocksize_) ? (long)blocksize_-s : tn); // number of bytes to write
00080       // it would take a very large in-memory stream for this assert to fail (>2GB).
00081       // That should not happen.  If it does, then we have to think of plan b.
00082       assert( (vcl_size_t)bl <= vcl_numeric_limits< vcl_size_t >::max() );
00083       char *tmp = block_[(vcl_size_t)bl];
00084       if (read_into_buf)
00085         for (vil_streampos k=0; k<z; ++k)
00086           tbuf[k] = tmp[s+k]; // prefer memcpy ?
00087       else
00088       {
00089         assert (s+z <= (long)blocksize_);
00090         for (vil_streampos k=0; k<z; ++k)
00091           tmp[s+k] = tbuf[k]; // prefer memcpy ?
00092       }
00093       tbuf += z;
00094       tn   -= z;
00095       tpos += z;
00096     }
00097   }
00098 
00099   // update tailpos_
00100   if (tailpos_ < pos+n)
00101     tailpos_ = pos+n;
00102 
00103   // always succeed.
00104   return n;
00105 }