llbufferstream.cpp

Go to the documentation of this file.
00001 
00034 #include "linden_common.h"
00035 #include "llbufferstream.h"
00036 
00037 #include "llbuffer.h"
00038 #include "llmemtype.h"
00039 
00040 static const S32 DEFAULT_OUTPUT_SEGMENT_SIZE = 1024 * 4;
00041 
00042 /*
00043  * LLBufferStreamBuf
00044  */
00045 LLBufferStreamBuf::LLBufferStreamBuf(
00046         const LLChannelDescriptors& channels,
00047         LLBufferArray* buffer) :
00048         mChannels(channels),
00049         mBuffer(buffer)
00050 {
00051         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00052 }
00053 
00054 LLBufferStreamBuf::~LLBufferStreamBuf()
00055 {
00056         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00057         sync();
00058 }
00059 
00060 // virtual
00061 int LLBufferStreamBuf::underflow()
00062 {
00063         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00064         //lldebugs << "LLBufferStreamBuf::underflow()" << llendl;
00065         if(!mBuffer)
00066         {
00067                 return EOF;
00068         }
00069 
00070         LLBufferArray::segment_iterator_t iter;
00071         LLBufferArray::segment_iterator_t end = mBuffer->endSegment();
00072         U8* last_pos = (U8*)gptr();
00073         LLSegment segment;
00074         if(last_pos)
00075         {
00076                 // Back up into a piece of memory we know that we have
00077                 // allocated so that calls for the next segment based on
00078                 // 'after' will succeed.
00079                 --last_pos;
00080                 iter = mBuffer->splitAfter(last_pos);
00081                 if(iter != end)
00082                 {
00083                         // We need to clear the read segment just in case we have
00084                         // an early exit in the function and never collect the
00085                         // next segment. Calling eraseSegment() with the same
00086                         // segment twice is just like double deleting -- nothing
00087                         // good comes from it.
00088                         mBuffer->eraseSegment(iter++);
00089                         if(iter != end) segment = (*iter);
00090                 }
00091                 else
00092                 {
00093                         // This should never really happen, but somehow, the
00094                         // istream is telling the buf that it just finished
00095                         // reading memory that is not in the buf. I think this
00096                         // would only happen if there were a bug in the c++ stream
00097                         // class. Just bail.
00098                         // *TODO: can we set the fail bit on the stream somehow?
00099                         return EOF;
00100                 }
00101         }
00102         else
00103         {
00104                 // Get iterator to full segment containing last_pos
00105                 // and construct sub-segment starting at last_pos.
00106                 // Note: segment may != *it at this point
00107                 iter = mBuffer->constructSegmentAfter(last_pos, segment);
00108         }
00109         if(iter == end)
00110         {
00111                 return EOF;
00112         }
00113 
00114         // Iterate through segments to find a non-empty segment on input channel.
00115         while((!segment.isOnChannel(mChannels.in()) || (segment.size() == 0)))
00116         {
00117                 ++iter;
00118                 if(iter == end)
00119                 {
00120                         return EOF;
00121                 }
00122 
00123                 segment = *(iter);
00124         }
00125 
00126         // set up the stream to read from the next segment.
00127         char* start = (char*)segment.data();
00128         setg(start, start, start + segment.size());
00129         return *gptr();
00130 }
00131 
00132 // virtual
00133 int LLBufferStreamBuf::overflow(int c)
00134 {
00135         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00136         if(!mBuffer)
00137         {
00138                 return EOF;
00139         }
00140         if(EOF == c)
00141         {
00142                 // if someone puts an EOF, I suppose we should sync and return
00143                 // success.
00144                 if(0 == sync())
00145                 {
00146                         return 1;
00147                 }
00148                 else
00149                 {
00150                         return EOF;
00151                 }
00152         }
00153 
00154         // since we got here, we have a buffer, and we have a character to
00155         // put on it.
00156         LLBufferArray::segment_iterator_t it;
00157         it = mBuffer->makeSegment(mChannels.out(), DEFAULT_OUTPUT_SEGMENT_SIZE);
00158         if(it != mBuffer->endSegment())
00159         {
00160                 char* start = (char*)(*it).data();
00161                 (*start) = (char)(c);
00162                 setp(start + 1, start + (*it).size());
00163                 return c;
00164         }
00165         else
00166         {
00167                 return EOF;
00168         }
00169 }
00170 
00171 // virtual
00172 int LLBufferStreamBuf::sync()
00173 {
00174         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00175         int return_value = -1;
00176         if(!mBuffer)
00177         {
00178                 return return_value;
00179         }
00180 
00181         // This chunk of code is not necessary because typically, users of
00182         // the stream will read until EOF. Therefore, underflow was called
00183         // and the segment was discarded before the sync() was called in
00184         // the destructor. Theoretically, we could keep some more data
00185         // around and detect the rare case where an istream was deleted
00186         // before reading to the end, but that will only leave behind some
00187         // unavailable but still referenced memory. Also, if another
00188         // istream is constructed, it will re-read that segment, and then
00189         // discard it.
00190         //U8* last_pos = (U8*)gptr();
00191         //if(last_pos)
00192         //{
00193         //      // Looks like we read something. Discard what we have read.
00194         //      // gptr() actually returns the currrent position, but we call
00195         //      // it last_pos because of how it is used in the split call
00196         //      // below.
00197         //      --last_pos;
00198         //      LLBufferArray::segment_iterator_t iter;
00199         //      iter = mBuffer->splitAfter(last_pos);
00200         //      if(iter != mBuffer->endSegment())
00201         //      {
00202         //              // We need to clear the read segment just in case we have
00203         //              // an early exit in the function and never collect the
00204         //              // next segment. Calling eraseSegment() with the same
00205         //              // segment twice is just like double deleting -- nothing
00206         //              // good comes from it.
00207         //              mBuffer->eraseSegment(iter);
00208         //      }
00209         //}
00210 
00211         // set the put pointer so that we force an overflow on the next
00212         // write.
00213         U8* address = (U8*)pptr();
00214         setp(NULL, NULL);
00215 
00216         // *NOTE: I bet we could just --address if address is not NULL.
00217         // Need to think about that.
00218         address = mBuffer->seek(mChannels.out(), address, -1);
00219         if(address)
00220         {
00221                 LLBufferArray::segment_iterator_t it;
00222                 it = mBuffer->splitAfter(address);
00223                 LLBufferArray::segment_iterator_t end = mBuffer->endSegment();
00224                 if(it != end)
00225                 {
00226                         ++it;
00227                         if(it != end)
00228                         {
00229                                 mBuffer->eraseSegment(it);
00230                         }
00231                         return_value = 0;
00232                 }
00233         }
00234         else
00235         {
00236                 // nothing was put on the buffer, so the sync() is a no-op.
00237                 return_value = 0;
00238         }
00239         return return_value;
00240 }
00241 
00242 // virtual
00243 #if( LL_WINDOWS || __GNUC__ > 2)
00244 LLBufferStreamBuf::pos_type LLBufferStreamBuf::seekoff(
00245         LLBufferStreamBuf::off_type off,
00246         std::ios::seekdir way,
00247         std::ios::openmode which)
00248 #else
00249 streampos LLBufferStreamBuf::seekoff(
00250         streamoff off,
00251         std::ios::seekdir way,
00252         std::ios::openmode which)
00253 #endif
00254 {
00255         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00256         if(!mBuffer
00257            || ((way == std::ios::beg) && (off < 0))
00258            || ((way == std::ios::end) && (off > 0)))
00259         {
00260                 return -1;
00261         }
00262         U8* address = NULL;
00263         if(which & std::ios::in)
00264         {
00265                 U8* base_addr = NULL;
00266                 switch(way)
00267                 {
00268                 case std::ios::end:
00269                         base_addr = (U8*)LLBufferArray::npos;
00270                         break;
00271                 case std::ios::cur:
00272                         // get the current get pointer and adjust it for buffer
00273                         // array semantics.
00274                         base_addr = (U8*)gptr();
00275                         break;
00276                 case std::ios::beg:
00277                 default:
00278                         // NULL is fine
00279                         break;
00280                 }
00281                 address = mBuffer->seek(mChannels.in(), base_addr, off);
00282                 if(address)
00283                 {
00284                         LLBufferArray::segment_iterator_t iter;
00285                         iter = mBuffer->getSegment(address);
00286                         char* start = (char*)(*iter).data();
00287                         setg(start, (char*)address, start + (*iter).size());
00288                 }
00289                 else
00290                 {
00291                         address = (U8*)(-1);
00292                 }
00293         }
00294         if(which & std::ios::out)
00295         {
00296                 U8* base_addr = NULL;
00297                 switch(way)
00298                 {
00299                 case std::ios::end:
00300                         base_addr = (U8*)LLBufferArray::npos;
00301                         break;
00302                 case std::ios::cur:
00303                         // get the current put pointer and adjust it for buffer
00304                         // array semantics.
00305                         base_addr = (U8*)pptr();
00306                         break;
00307                 case std::ios::beg:
00308                 default:
00309                         // NULL is fine
00310                         break;
00311                 }
00312                 address = mBuffer->seek(mChannels.out(), base_addr, off);
00313                 if(address)
00314                 {
00315                         LLBufferArray::segment_iterator_t iter;
00316                         iter = mBuffer->getSegment(address);
00317                         setp((char*)address, (char*)(*iter).data() + (*iter).size());
00318                 }
00319                 else
00320                 {
00321                         address = (U8*)(-1);
00322                 }
00323         }
00324 
00325 #if( LL_WINDOWS || __GNUC__ > 2 )
00326         S32 rv = (S32)(intptr_t)address;
00327         return (pos_type)rv;
00328 #else
00329         return (streampos)address;
00330 #endif
00331 }
00332 
00333 
00334 /*
00335  * LLBufferStream
00336  */
00337 LLBufferStream::LLBufferStream(
00338         const LLChannelDescriptors& channels,
00339         LLBufferArray* buffer) :
00340         std::iostream(&mStreamBuf),
00341         mStreamBuf(channels, buffer)
00342 {
00343         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00344 }
00345 
00346 LLBufferStream::~LLBufferStream()
00347 {
00348         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00349 }

Generated on Thu Jul 1 06:08:20 2010 for Second Life Viewer by  doxygen 1.4.7