diff options
Diffstat (limited to 'db/mork/src/morkSink.h')
-rw-r--r-- | db/mork/src/morkSink.h | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/db/mork/src/morkSink.h b/db/mork/src/morkSink.h new file mode 100644 index 000000000..4d501e76c --- /dev/null +++ b/db/mork/src/morkSink.h @@ -0,0 +1,161 @@ +/* -*- 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 _MORKSINK_ +#define _MORKSINK_ 1 + +#ifndef _MORK_ +#include "mork.h" +#endif + +#ifndef _MORKBLOB_ +#include "morkBlob.h" +#endif + +//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 + +/*| morkSink is intended to be a very cheap buffered i/o sink which +**| writes to bufs and other strings a single byte at a time. The +**| basic idea is that writing a single byte has a very cheap average +**| cost, because a polymophic function call need only occur when the +**| space between At and End is exhausted. The rest of the time a +**| very cheap inline method will write a byte, and then bump a pointer. +**| +**|| At: the current position in some sequence of bytes at which to +**| write the next byte put into the sink. Presumably At points into +**| the private storage of some space which is not yet filled (except +**| when At reaches End, and the overflow must then spill). Note both +**| At and End are zeroed in the destructor to help show that a sink +**| is no longer usable; this is safe because At==End causes the case +**| where SpillPutc() is called to handled an exhausted buffer space. +**| +**|| End: an address one byte past the last byte which can be written +**| without needing to make a buffer larger than previously. When At +**| and End are equal, this means there is no space to write a byte, +**| and that some underlying buffer space must be grown before another +**| byte can be written. Note At must always be less than or equal to +**| End, and otherwise an important invariant has failed severely. +**| +**|| Buf: this original class slot has been commented out in the new +**| and more abstract version of this sink class, but the general idea +**| behind this slot should be explained to help design subclasses. +**| Each subclass should provide space into which At and End can point, +**| where End is beyond the last writable byte, and At is less than or +**| equal to this point inside the same buffer. With some kinds of +**| medium, such as writing to an instance of morkBlob, it is feasible +**| to point directly into the final resting place for all the content +**| written to the medium. Other mediums such as files, which write +**| only through function calls, will typically need a local buffer +**| to efficiently accumulate many bytes between such function calls. +**| +**|| FlushSink: this flush method should move any buffered content to +**| its final destination. For example, for buffered writes to a +**| string medium, where string methods are function calls and not just +**| inline macros, it is faster to accumulate many bytes in a small +**| local buffer and then move these en masse later in a single call. +**| +**|| SpillPutc: when At is greater than or equal to End, this means an +**| underlying buffer has become full, so the buffer must be flushed +**| before a new byte can be written. The intention is that SpillPutc() +**| will be equivalent to calling FlushSink() followed by another call +**| to Putc(), where the flush is expected to make At less then End once +**| again. Except that FlushSink() need not make the underlying buffer +**| any larger, and SpillPutc() typically must make room for more bytes. +**| Note subclasses might want to guard against the case that both At +**| and End are null, which happens when a sink is destroyed, which sets +**| both these pointers to null as an indication the sink is disabled. +|*/ +class morkSink { + +// ````` ````` ````` ````` ````` ````` ````` ````` +public: // public sink virtual methods + + virtual void FlushSink(morkEnv* ev) = 0; + virtual void SpillPutc(morkEnv* ev, int c) = 0; + +// ````` ````` ````` ````` ````` ````` ````` ````` +public: // member variables + + mork_u1* mSink_At; // pointer into mSink_Buf + mork_u1* mSink_End; // one byte past last content byte + +// define morkSink_kBufSize 256 /* small enough to go on stack */ + + // mork_u1 mSink_Buf[ morkSink_kBufSize + 4 ]; + // want plus one for any needed end null byte; use plus 4 for alignment + +// ````` ````` ````` ````` ````` ````` ````` ````` +public: // public non-poly morkSink methods + + virtual ~morkSink(); // zero both At and End; virtual for subclasses + morkSink() { } // does nothing; subclasses must set At and End suitably + + void Putc(morkEnv* ev, int c) + { + if ( mSink_At < mSink_End ) + *mSink_At++ = (mork_u1) c; + else + this->SpillPutc(ev, c); + } +}; + +/*| morkSpool: an output sink that efficiently writes individual bytes +**| or entire byte sequences to a coil instance, which grows as needed by +**| using the heap instance in the coil to grow the internal buffer. +**| +**|| Note we do not "own" the coil referenced by mSpool_Coil, and +**| the lifetime of the coil is expected to equal or exceed that of this +**| sink by some external means. Typical usage might involve keeping an +**| instance of morkCoil and an instance of morkSpool in the same +**| owning parent object, which uses the spool with the associated coil. +|*/ +class morkSpool : public morkSink { // for buffered i/o to a morkCoil + +// ````` ````` ````` ````` ````` ````` ````` ````` +public: // public sink virtual methods + + // when morkSink::Putc() moves mSink_At, mSpool_Coil->mBuf_Fill is wrong: + + virtual void FlushSink(morkEnv* ev); // sync mSpool_Coil->mBuf_Fill + virtual void SpillPutc(morkEnv* ev, int c); // grow coil and write byte + +// ````` ````` ````` ````` ````` ````` ````` ````` +public: // member variables + morkCoil* mSpool_Coil; // destination medium for written bytes + +// ````` ````` ````` ````` ````` ````` ````` ````` +public: // public non-poly morkSink methods + + static void BadSpoolCursorOrderError(morkEnv* ev); + static void NilSpoolCoilError(morkEnv* ev); + + virtual ~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. + + morkSpool(morkEnv* ev, morkCoil* ioCoil); + // After installing the coil, calls Seek(ev, 0) to prepare for writing. + + // ----- All boolean return values below are equal to ev->Good(): ----- + + mork_bool 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. + + mork_bool Write(morkEnv* ev, const void* inBuf, mork_size inSize); + // write inSize bytes of inBuf to current position inside coil's buffer + + mork_bool PutBuf(morkEnv* ev, const morkBuf& inBuffer) + { return this->Write(ev, inBuffer.mBuf_Body, inBuffer.mBuf_Fill); } + + mork_bool 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. +}; + +//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 + +#endif /* _MORKSINK_ */ |