1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
5
* The contents of this file are subject to the Netscape Public License
6
* Version 1.1 (the "License"); you may not use this file except in
7
* compliance with the License. You may obtain a copy of the License at
8
* http://www.mozilla.org/NPL/
10
* Software distributed under the License is distributed on an "AS IS" basis,
11
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
* for the specific language governing rights and limitations under the
15
* The Original Code is mozilla.org code.
17
* The Initial Developer of the Original Code is
18
* Netscape Communications Corporation.
19
* Portions created by the Initial Developer are Copyright (C) 1999
20
* the Initial Developer. All Rights Reserved.
25
* Alternatively, the contents of this file may be used under the terms of
26
* either the GNU General Public License Version 2 or later (the "GPL"), or
27
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28
* in which case the provisions of the GPL or the LGPL are applicable instead
29
* of those above. If you wish to allow use of your version of this file only
30
* under the terms of either the GPL or the LGPL, and not to allow others to
31
* use your version of this file under the terms of the NPL, indicate your
32
* decision by deleting the provisions above and replace them with the notice
33
* and other provisions required by the GPL or the LGPL. If you do not delete
34
* the provisions above, a recipient may use your version of this file under
35
* the terms of any one of the NPL, the GPL or the LGPL.
37
* ***** END LICENSE BLOCK ***** */
50
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
52
/*| morkSink is intended to be a very cheap buffered i/o sink which
53
**| writes to bufs and other strings a single byte at a time. The
54
**| basic idea is that writing a single byte has a very cheap average
55
**| cost, because a polymophic function call need only occur when the
56
**| space between At and End is exhausted. The rest of the time a
57
**| very cheap inline method will write a byte, and then bump a pointer.
59
**|| At: the current position in some sequence of bytes at which to
60
**| write the next byte put into the sink. Presumably At points into
61
**| the private storage of some space which is not yet filled (except
62
**| when At reaches End, and the overflow must then spill). Note both
63
**| At and End are zeroed in the destructor to help show that a sink
64
**| is no longer usable; this is safe because At==End causes the case
65
**| where SpillPutc() is called to handled an exhausted buffer space.
67
**|| End: an address one byte past the last byte which can be written
68
**| without needing to make a buffer larger than previously. When At
69
**| and End are equal, this means there is no space to write a byte,
70
**| and that some underlying buffer space must be grown before another
71
**| byte can be written. Note At must always be less than or equal to
72
**| End, and otherwise an important invariant has failed severely.
74
**|| Buf: this original class slot has been commented out in the new
75
**| and more abstract version of this sink class, but the general idea
76
**| behind this slot should be explained to help design subclasses.
77
**| Each subclass should provide space into which At and End can point,
78
**| where End is beyond the last writable byte, and At is less than or
79
**| equal to this point inside the same buffer. With some kinds of
80
**| medium, such as writing to an instance of morkBlob, it is feasible
81
**| to point directly into the final resting place for all the content
82
**| written to the medium. Other mediums such as files, which write
83
**| only through function calls, will typically need a local buffer
84
**| to efficiently accumulate many bytes between such function calls.
86
**|| FlushSink: this flush method should move any buffered content to
87
**| it's final destination. For example, for buffered writes to a
88
**| string medium, where string methods are function calls and not just
89
**| inline macros, it is faster to accumulate many bytes in a small
90
**| local buffer and then move these en masse later in a single call.
92
**|| SpillPutc: when At is greater than or equal to End, this means an
93
**| underlying buffer has become full, so the buffer must be flushed
94
**| before a new byte can be written. The intention is that SpillPutc()
95
**| will be equivalent to calling FlushSink() followed by another call
96
**| to Putc(), where the flush is expected to make At less then End once
97
**| again. Except that FlushSink() need not make the underlying buffer
98
**| any larger, and SpillPutc() typically must make room for more bytes.
99
**| Note subclasses might want to guard against the case that both At
100
**| and End are null, which happens when a sink is destroyed, which sets
101
**| both these pointers to null as an indication the sink is disabled.
105
// ````` ````` ````` ````` ````` ````` ````` `````
106
public: // public sink virtual methods
108
virtual void FlushSink(morkEnv* ev) = 0;
109
virtual void SpillPutc(morkEnv* ev, int c) = 0;
111
// ````` ````` ````` ````` ````` ````` ````` `````
112
public: // member variables
114
mork_u1* mSink_At; // pointer into mSink_Buf
115
mork_u1* mSink_End; // one byte past last content byte
117
// define morkSink_kBufSize 256 /* small enough to go on stack */
119
// mork_u1 mSink_Buf[ morkSink_kBufSize + 4 ];
120
// want plus one for any needed end null byte; use plus 4 for alignment
122
// ````` ````` ````` ````` ````` ````` ````` `````
123
public: // public non-poly morkSink methods
125
virtual ~morkSink(); // zero both At and End; virtual for subclasses
126
morkSink() { } // does nothing; subclasses must set At and End suitably
128
void Putc(morkEnv* ev, int c)
130
if ( mSink_At < mSink_End )
131
*mSink_At++ = (mork_u1) c;
133
this->SpillPutc(ev, c);
137
/*| morkSpool: an output sink that efficiently writes individual bytes
138
**| or entire byte sequences to a coil instance, which grows as needed by
139
**| using the heap instance in the coil to grow the internal buffer.
141
**|| Note we do not "own" the coil referenced by mSpool_Coil, and
142
**| the lifetime of the coil is expected to equal or exceed that of this
143
**| sink by some external means. Typical usage might involve keeping an
144
**| instance of morkCoil and an instance of morkSpool in the same
145
**| owning parent object, which uses the spool with the associated coil.
147
class morkSpool : public morkSink { // for buffered i/o to a morkCoil
149
// ````` ````` ````` ````` ````` ````` ````` `````
150
public: // public sink virtual methods
152
// when morkSink::Putc() moves mSink_At, mSpool_Coil->mBuf_Fill is wrong:
154
virtual void FlushSink(morkEnv* ev); // sync mSpool_Coil->mBuf_Fill
155
virtual void SpillPutc(morkEnv* ev, int c); // grow coil and write byte
157
// ````` ````` ````` ````` ````` ````` ````` `````
158
public: // member variables
159
morkCoil* mSpool_Coil; // destination medium for written bytes
161
// ````` ````` ````` ````` ````` ````` ````` `````
162
public: // public non-poly morkSink methods
164
static void BadSpoolCursorOrderError(morkEnv* ev);
165
static void NilSpoolCoilError(morkEnv* ev);
167
virtual ~morkSpool();
168
// Zero all slots to show this sink is disabled, but destroy no memory.
169
// Note it is typically unnecessary to flush this coil sink, since all
170
// content is written directly to the coil without any buffering.
172
morkSpool(morkEnv* ev, morkCoil* ioCoil);
173
// After installing the coil, calls Seek(ev, 0) to prepare for writing.
175
// ----- All boolean return values below are equal to ev->Good(): -----
177
mork_bool Seek(morkEnv* ev, mork_pos inPos);
178
// Changed the current write position in coil's buffer to inPos.
179
// For example, to start writing the coil from scratch, use inPos==0.
181
mork_bool Write(morkEnv* ev, const void* inBuf, mork_size inSize);
182
// write inSize bytes of inBuf to current position inside coil's buffer
184
mork_bool PutBuf(morkEnv* ev, const morkBuf& inBuffer)
185
{ return this->Write(ev, inBuffer.mBuf_Body, inBuffer.mBuf_Fill); }
187
mork_bool PutString(morkEnv* ev, const char* inString);
188
// call Write() with inBuf=inString and inSize=strlen(inString),
189
// unless inString is null, in which case we then do nothing at all.
192
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
194
#endif /* _MORKSINK_ */