summaryrefslogtreecommitdiffstats
path: root/db/mork/src/morkSink.h
diff options
context:
space:
mode:
Diffstat (limited to 'db/mork/src/morkSink.h')
-rw-r--r--db/mork/src/morkSink.h161
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_ */