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