diff options
Diffstat (limited to 'db/mork/src/morkSink.cpp')
-rw-r--r-- | db/mork/src/morkSink.cpp | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/db/mork/src/morkSink.cpp b/db/mork/src/morkSink.cpp new file mode 100644 index 000000000..1d4089c0a --- /dev/null +++ b/db/mork/src/morkSink.cpp @@ -0,0 +1,292 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _MDB_ +#include "mdb.h" +#endif + +#ifndef _MORK_ +#include "mork.h" +#endif + +#ifndef _MORKSINK_ +#include "morkSink.h" +#endif + +#ifndef _MORKENV_ +#include "morkEnv.h" +#endif + +#ifndef _MORKBLOB_ +#include "morkBlob.h" +#endif + +//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 + +/*virtual*/ morkSink::~morkSink() +{ + mSink_At = 0; + mSink_End = 0; +} + +/*virtual*/ void +morkSpool::FlushSink(morkEnv* ev) // sync mSpool_Coil->mBuf_Fill +{ + morkCoil* coil = mSpool_Coil; + if ( coil ) + { + mork_u1* body = (mork_u1*) coil->mBuf_Body; + if ( body ) + { + mork_u1* at = mSink_At; + mork_u1* end = mSink_End; + if ( at >= body && at <= end ) // expected cursor order? + { + mork_fill fill = (mork_fill) (at - body); // current content size + if ( fill <= coil->mBlob_Size ) + coil->mBuf_Fill = fill; + else + { + coil->BlobFillOverSizeError(ev); + coil->mBuf_Fill = coil->mBlob_Size; // make it safe + } + } + else + this->BadSpoolCursorOrderError(ev); + } + else + coil->NilBufBodyError(ev); + } + else + this->NilSpoolCoilError(ev); +} + +/*virtual*/ void +morkSpool::SpillPutc(morkEnv* ev, int c) // grow coil and write byte +{ + morkCoil* coil = mSpool_Coil; + if ( coil ) + { + mork_u1* body = (mork_u1*) coil->mBuf_Body; + if ( body ) + { + mork_u1* at = mSink_At; + mork_u1* end = mSink_End; + if ( at >= body && at <= end ) // expected cursor order? + { + mork_size size = coil->mBlob_Size; + mork_fill fill = (mork_fill) (at - body); // current content size + if ( fill <= size ) // less content than medium size? + { + coil->mBuf_Fill = fill; + if ( at >= end ) // need to grow the coil? + { + if ( size > 2048 ) // grow slower over 2K? + size += 512; + else + { + mork_size growth = ( size * 4 ) / 3; // grow by 33% + if ( growth < 64 ) // grow faster under (64 * 3)? + growth = 64; + size += growth; + } + if ( coil->GrowCoil(ev, size) ) // made coil bigger? + { + body = (mork_u1*) coil->mBuf_Body; + if ( body ) // have a coil body? + { + mSink_At = at = body + fill; + mSink_End = end = body + coil->mBlob_Size; + } + else + coil->NilBufBodyError(ev); + } + } + if ( ev->Good() ) // seem ready to write byte c? + { + if ( at < end ) // morkSink::Putc() would succeed? + { + *at++ = (mork_u1) c; + mSink_At = at; + coil->mBuf_Fill = fill + 1; + } + else + this->BadSpoolCursorOrderError(ev); + } + } + else // fill exceeds size + { + coil->BlobFillOverSizeError(ev); + coil->mBuf_Fill = coil->mBlob_Size; // make it safe + } + } + else + this->BadSpoolCursorOrderError(ev); + } + else + coil->NilBufBodyError(ev); + } + else + this->NilSpoolCoilError(ev); +} + +// ````` ````` ````` ````` ````` ````` ````` ````` +// public: // public non-poly morkSink methods + +/*virtual*/ +morkSpool::~morkSpool() +// Zero all slots to show this sink is disabled, but destroy no memory. +// Note it is typically unnecessary to flush this coil sink, since all +// content is written directly to the coil without any buffering. +{ + mSink_At = 0; + mSink_End = 0; + mSpool_Coil = 0; +} + +morkSpool::morkSpool(morkEnv* ev, morkCoil* ioCoil) +// After installing the coil, calls Seek(ev, 0) to prepare for writing. +: morkSink() +, mSpool_Coil( 0 ) +{ + mSink_At = 0; // set correctly later in Seek() + mSink_End = 0; // set correctly later in Seek() + + if ( ev->Good() ) + { + if ( ioCoil ) + { + mSpool_Coil = ioCoil; + this->Seek(ev, /*pos*/ 0); + } + else + ev->NilPointerError(); + } +} + +// ----- All boolean return values below are equal to ev->Good(): ----- + +/*static*/ void +morkSpool::BadSpoolCursorOrderError(morkEnv* ev) +{ + ev->NewError("bad morkSpool cursor order"); +} + +/*static*/ void +morkSpool::NilSpoolCoilError(morkEnv* ev) +{ + ev->NewError("nil mSpool_Coil"); +} + +mork_bool +morkSpool::Seek(morkEnv* ev, mork_pos inPos) +// Changed the current write position in coil's buffer to inPos. +// For example, to start writing the coil from scratch, use inPos==0. +{ + morkCoil* coil = mSpool_Coil; + if ( coil ) + { + mork_size minSize = (mork_size) (inPos + 64); + + if ( coil->mBlob_Size < minSize ) + coil->GrowCoil(ev, minSize); + + if ( ev->Good() ) + { + coil->mBuf_Fill = (mork_fill) inPos; + mork_u1* body = (mork_u1*) coil->mBuf_Body; + if ( body ) + { + mSink_At = body + inPos; + mSink_End = body + coil->mBlob_Size; + } + else + coil->NilBufBodyError(ev); + } + } + else + this->NilSpoolCoilError(ev); + + return ev->Good(); +} + +mork_bool +morkSpool::Write(morkEnv* ev, const void* inBuf, mork_size inSize) +// write inSize bytes of inBuf to current position inside coil's buffer +{ + // This method is conceptually very similar to morkStream::Write(), + // and this code was written while looking at that method for clues. + + morkCoil* coil = mSpool_Coil; + if ( coil ) + { + mork_u1* body = (mork_u1*) coil->mBuf_Body; + if ( body ) + { + if ( inBuf && inSize ) // anything to write? + { + mork_u1* at = mSink_At; + mork_u1* end = mSink_End; + if ( at >= body && at <= end ) // expected cursor order? + { + // note coil->mBuf_Fill can be stale after morkSink::Putc(): + mork_pos fill = at - body; // current content size + mork_num space = (mork_num) (end - at); // space left in body + if ( space < inSize ) // not enough to hold write? + { + mork_size minGrowth = space + 16; + mork_size minSize = coil->mBlob_Size + minGrowth; + if ( coil->GrowCoil(ev, minSize) ) + { + body = (mork_u1*) coil->mBuf_Body; + if ( body ) + { + mSink_At = at = body + fill; + mSink_End = end = body + coil->mBlob_Size; + space = (mork_num) (end - at); // space left in body + } + else + coil->NilBufBodyError(ev); + } + } + if ( ev->Good() ) + { + if ( space >= inSize ) // enough room to hold write? + { + MORK_MEMCPY(at, inBuf, inSize); // into body + mSink_At = at + inSize; // advance past written bytes + coil->mBuf_Fill = fill + inSize; // "flush" to fix fill + } + else + ev->NewError("insufficient morkSpool space"); + } + } + else + this->BadSpoolCursorOrderError(ev); + } + } + else + coil->NilBufBodyError(ev); + } + else + this->NilSpoolCoilError(ev); + + return ev->Good(); +} + +mork_bool +morkSpool::PutString(morkEnv* ev, const char* inString) +// call Write() with inBuf=inString and inSize=strlen(inString), +// unless inString is null, in which case we then do nothing at all. +{ + if ( inString ) + { + mork_size size = MORK_STRLEN(inString); + this->Write(ev, inString, size); + } + return ev->Good(); +} + +//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 |