comparison CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/include/kj/io.h @ 69:33d812a61356

planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author jpayne
date Tue, 18 Mar 2025 17:55:14 -0400
parents
children
comparison
equal deleted inserted replaced
67:0e9998148a16 69:33d812a61356
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
2 // Licensed under the MIT License:
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21
22 #pragma once
23
24 #include <stddef.h>
25 #include "common.h"
26 #include "array.h"
27 #include "exception.h"
28 #include <stdint.h>
29
30 KJ_BEGIN_HEADER
31
32 namespace kj {
33
34 // =======================================================================================
35 // Abstract interfaces
36
37 class InputStream {
38 public:
39 virtual ~InputStream() noexcept(false);
40
41 size_t read(void* buffer, size_t minBytes, size_t maxBytes);
42 // Reads at least minBytes and at most maxBytes, copying them into the given buffer. Returns
43 // the size read. Throws an exception on errors. Implemented in terms of tryRead().
44 //
45 // maxBytes is the number of bytes the caller really wants, but minBytes is the minimum amount
46 // needed by the caller before it can start doing useful processing. If the stream returns less
47 // than maxBytes, the caller will usually call read() again later to get the rest. Returning
48 // less than maxBytes is useful when it makes sense for the caller to parallelize processing
49 // with I/O.
50 //
51 // Never blocks if minBytes is zero. If minBytes is zero and maxBytes is non-zero, this may
52 // attempt a non-blocking read or may just return zero. To force a read, use a non-zero minBytes.
53 // To detect EOF without throwing an exception, use tryRead().
54 //
55 // If the InputStream can't produce minBytes, it MUST throw an exception, as the caller is not
56 // expected to understand how to deal with partial reads.
57
58 virtual size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) = 0;
59 // Like read(), but may return fewer than minBytes on EOF.
60
61 inline void read(void* buffer, size_t bytes) { read(buffer, bytes, bytes); }
62 // Convenience method for reading an exact number of bytes.
63
64 virtual void skip(size_t bytes);
65 // Skips past the given number of bytes, discarding them. The default implementation read()s
66 // into a scratch buffer.
67
68 String readAllText(uint64_t limit = kj::maxValue);
69 Array<byte> readAllBytes(uint64_t limit = kj::maxValue);
70 // Read until EOF and return as one big byte array or string. Throw an exception if EOF is not
71 // seen before reading `limit` bytes.
72 //
73 // To prevent runaway memory allocation, consider using a more conservative value for `limit` than
74 // the default, particularly on untrusted data streams which may never see EOF.
75 };
76
77 class OutputStream {
78 public:
79 virtual ~OutputStream() noexcept(false);
80
81 virtual void write(const void* buffer, size_t size) = 0;
82 // Always writes the full size. Throws exception on error.
83
84 virtual void write(ArrayPtr<const ArrayPtr<const byte>> pieces);
85 // Equivalent to write()ing each byte array in sequence, which is what the default implementation
86 // does. Override if you can do something better, e.g. use writev() to do the write in a single
87 // syscall.
88 };
89
90 class BufferedInputStream: public InputStream {
91 // An input stream which buffers some bytes in memory to reduce system call overhead.
92 // - OR -
93 // An input stream that actually reads from some in-memory data structure and wants to give its
94 // caller a direct pointer to that memory to potentially avoid a copy.
95
96 public:
97 virtual ~BufferedInputStream() noexcept(false);
98
99 ArrayPtr<const byte> getReadBuffer();
100 // Get a direct pointer into the read buffer, which contains the next bytes in the input. If the
101 // caller consumes any bytes, it should then call skip() to indicate this. This always returns a
102 // non-empty buffer or throws an exception. Implemented in terms of tryGetReadBuffer().
103
104 virtual ArrayPtr<const byte> tryGetReadBuffer() = 0;
105 // Like getReadBuffer() but may return an empty buffer on EOF.
106 };
107
108 class BufferedOutputStream: public OutputStream {
109 // An output stream which buffers some bytes in memory to reduce system call overhead.
110 // - OR -
111 // An output stream that actually writes into some in-memory data structure and wants to give its
112 // caller a direct pointer to that memory to potentially avoid a copy.
113
114 public:
115 virtual ~BufferedOutputStream() noexcept(false);
116
117 virtual ArrayPtr<byte> getWriteBuffer() = 0;
118 // Get a direct pointer into the write buffer. The caller may choose to fill in some prefix of
119 // this buffer and then pass it to write(), in which case write() may avoid a copy. It is
120 // incorrect to pass to write any slice of this buffer which is not a prefix.
121 };
122
123 // =======================================================================================
124 // Buffered streams implemented as wrappers around regular streams
125
126 class BufferedInputStreamWrapper: public BufferedInputStream {
127 // Implements BufferedInputStream in terms of an InputStream.
128 //
129 // Note that the underlying stream's position is unpredictable once the wrapper is destroyed,
130 // unless the entire stream was consumed. To read a predictable number of bytes in a buffered
131 // way without going over, you'd need this wrapper to wrap some other wrapper which itself
132 // implements an artificial EOF at the desired point. Such a stream should be trivial to write
133 // but is not provided by the library at this time.
134
135 public:
136 explicit BufferedInputStreamWrapper(InputStream& inner, ArrayPtr<byte> buffer = nullptr);
137 // Creates a buffered stream wrapping the given non-buffered stream. No guarantee is made about
138 // the position of the inner stream after a buffered wrapper has been created unless the entire
139 // input is read.
140 //
141 // If the second parameter is non-null, the stream uses the given buffer instead of allocating
142 // its own. This may improve performance if the buffer can be reused.
143
144 KJ_DISALLOW_COPY_AND_MOVE(BufferedInputStreamWrapper);
145 ~BufferedInputStreamWrapper() noexcept(false);
146
147 // implements BufferedInputStream ----------------------------------
148 ArrayPtr<const byte> tryGetReadBuffer() override;
149 size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override;
150 void skip(size_t bytes) override;
151
152 private:
153 InputStream& inner;
154 Array<byte> ownedBuffer;
155 ArrayPtr<byte> buffer;
156 ArrayPtr<byte> bufferAvailable;
157 };
158
159 class BufferedOutputStreamWrapper: public BufferedOutputStream {
160 // Implements BufferedOutputStream in terms of an OutputStream. Note that writes to the
161 // underlying stream may be delayed until flush() is called or the wrapper is destroyed.
162
163 public:
164 explicit BufferedOutputStreamWrapper(OutputStream& inner, ArrayPtr<byte> buffer = nullptr);
165 // Creates a buffered stream wrapping the given non-buffered stream.
166 //
167 // If the second parameter is non-null, the stream uses the given buffer instead of allocating
168 // its own. This may improve performance if the buffer can be reused.
169
170 KJ_DISALLOW_COPY_AND_MOVE(BufferedOutputStreamWrapper);
171 ~BufferedOutputStreamWrapper() noexcept(false);
172
173 void flush();
174 // Force the wrapper to write any remaining bytes in its buffer to the inner stream. Note that
175 // this only flushes this object's buffer; this object has no idea how to flush any other buffers
176 // that may be present in the underlying stream.
177
178 // implements BufferedOutputStream ---------------------------------
179 ArrayPtr<byte> getWriteBuffer() override;
180 void write(const void* buffer, size_t size) override;
181
182 private:
183 OutputStream& inner;
184 Array<byte> ownedBuffer;
185 ArrayPtr<byte> buffer;
186 byte* bufferPos;
187 UnwindDetector unwindDetector;
188 };
189
190 // =======================================================================================
191 // Array I/O
192
193 class ArrayInputStream: public BufferedInputStream {
194 public:
195 explicit ArrayInputStream(ArrayPtr<const byte> array);
196 KJ_DISALLOW_COPY_AND_MOVE(ArrayInputStream);
197 ~ArrayInputStream() noexcept(false);
198
199 // implements BufferedInputStream ----------------------------------
200 ArrayPtr<const byte> tryGetReadBuffer() override;
201 size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override;
202 void skip(size_t bytes) override;
203
204 private:
205 ArrayPtr<const byte> array;
206 };
207
208 class ArrayOutputStream: public BufferedOutputStream {
209 public:
210 explicit ArrayOutputStream(ArrayPtr<byte> array);
211 KJ_DISALLOW_COPY_AND_MOVE(ArrayOutputStream);
212 ~ArrayOutputStream() noexcept(false);
213
214 ArrayPtr<byte> getArray() {
215 // Get the portion of the array which has been filled in.
216 return arrayPtr(array.begin(), fillPos);
217 }
218
219 // implements BufferedInputStream ----------------------------------
220 ArrayPtr<byte> getWriteBuffer() override;
221 void write(const void* buffer, size_t size) override;
222
223 private:
224 ArrayPtr<byte> array;
225 byte* fillPos;
226 };
227
228 class VectorOutputStream: public BufferedOutputStream {
229 public:
230 explicit VectorOutputStream(size_t initialCapacity = 4096);
231 KJ_DISALLOW_COPY_AND_MOVE(VectorOutputStream);
232 ~VectorOutputStream() noexcept(false);
233
234 ArrayPtr<byte> getArray() {
235 // Get the portion of the array which has been filled in.
236 return arrayPtr(vector.begin(), fillPos);
237 }
238
239 void clear() { fillPos = vector.begin(); }
240
241 // implements BufferedInputStream ----------------------------------
242 ArrayPtr<byte> getWriteBuffer() override;
243 void write(const void* buffer, size_t size) override;
244
245 private:
246 Array<byte> vector;
247 byte* fillPos;
248
249 void grow(size_t minSize);
250 };
251
252 // =======================================================================================
253 // File descriptor I/O
254
255 class AutoCloseFd {
256 // A wrapper around a file descriptor which automatically closes the descriptor when destroyed.
257 // The wrapper supports move construction for transferring ownership of the descriptor. If
258 // close() returns an error, the destructor throws an exception, UNLESS the destructor is being
259 // called during unwind from another exception, in which case the close error is ignored.
260 //
261 // If your code is not exception-safe, you should not use AutoCloseFd. In this case you will
262 // have to call close() yourself and handle errors appropriately.
263
264 public:
265 inline AutoCloseFd(): fd(-1) {}
266 inline AutoCloseFd(decltype(nullptr)): fd(-1) {}
267 inline explicit AutoCloseFd(int fd): fd(fd) {}
268 inline AutoCloseFd(AutoCloseFd&& other) noexcept: fd(other.fd) { other.fd = -1; }
269 KJ_DISALLOW_COPY(AutoCloseFd);
270 ~AutoCloseFd() noexcept(false);
271
272 inline AutoCloseFd& operator=(AutoCloseFd&& other) {
273 AutoCloseFd old(kj::mv(*this));
274 fd = other.fd;
275 other.fd = -1;
276 return *this;
277 }
278
279 inline AutoCloseFd& operator=(decltype(nullptr)) {
280 AutoCloseFd old(kj::mv(*this));
281 return *this;
282 }
283
284 inline operator int() const { return fd; }
285 inline int get() const { return fd; }
286
287 operator bool() const = delete;
288 // Deleting this operator prevents accidental use in boolean contexts, which
289 // the int conversion operator above would otherwise allow.
290
291 inline bool operator==(decltype(nullptr)) { return fd < 0; }
292 inline bool operator!=(decltype(nullptr)) { return fd >= 0; }
293
294 inline int release() {
295 // Release ownership of an FD. Not recommended.
296 int result = fd;
297 fd = -1;
298 return result;
299 }
300
301 private:
302 int fd;
303 };
304
305 inline auto KJ_STRINGIFY(const AutoCloseFd& fd)
306 -> decltype(kj::toCharSequence(implicitCast<int>(fd))) {
307 return kj::toCharSequence(implicitCast<int>(fd));
308 }
309
310 class FdInputStream: public InputStream {
311 // An InputStream wrapping a file descriptor.
312
313 public:
314 explicit FdInputStream(int fd): fd(fd) {}
315 explicit FdInputStream(AutoCloseFd fd): fd(fd), autoclose(mv(fd)) {}
316 KJ_DISALLOW_COPY_AND_MOVE(FdInputStream);
317 ~FdInputStream() noexcept(false);
318
319 size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override;
320
321 inline int getFd() const { return fd; }
322
323 private:
324 int fd;
325 AutoCloseFd autoclose;
326 };
327
328 class FdOutputStream: public OutputStream {
329 // An OutputStream wrapping a file descriptor.
330
331 public:
332 explicit FdOutputStream(int fd): fd(fd) {}
333 explicit FdOutputStream(AutoCloseFd fd): fd(fd), autoclose(mv(fd)) {}
334 KJ_DISALLOW_COPY_AND_MOVE(FdOutputStream);
335 ~FdOutputStream() noexcept(false);
336
337 void write(const void* buffer, size_t size) override;
338 void write(ArrayPtr<const ArrayPtr<const byte>> pieces) override;
339
340 inline int getFd() const { return fd; }
341
342 private:
343 int fd;
344 AutoCloseFd autoclose;
345 };
346
347 // =======================================================================================
348 // Win32 Handle I/O
349
350 #ifdef _WIN32
351
352 class AutoCloseHandle {
353 // A wrapper around a Win32 HANDLE which automatically closes the handle when destroyed.
354 // The wrapper supports move construction for transferring ownership of the handle. If
355 // CloseHandle() returns an error, the destructor throws an exception, UNLESS the destructor is
356 // being called during unwind from another exception, in which case the close error is ignored.
357 //
358 // If your code is not exception-safe, you should not use AutoCloseHandle. In this case you will
359 // have to call close() yourself and handle errors appropriately.
360
361 public:
362 inline AutoCloseHandle(): handle((void*)-1) {}
363 inline AutoCloseHandle(decltype(nullptr)): handle((void*)-1) {}
364 inline explicit AutoCloseHandle(void* handle): handle(handle) {}
365 inline AutoCloseHandle(AutoCloseHandle&& other) noexcept: handle(other.handle) {
366 other.handle = (void*)-1;
367 }
368 KJ_DISALLOW_COPY(AutoCloseHandle);
369 ~AutoCloseHandle() noexcept(false);
370
371 inline AutoCloseHandle& operator=(AutoCloseHandle&& other) {
372 AutoCloseHandle old(kj::mv(*this));
373 handle = other.handle;
374 other.handle = (void*)-1;
375 return *this;
376 }
377
378 inline AutoCloseHandle& operator=(decltype(nullptr)) {
379 AutoCloseHandle old(kj::mv(*this));
380 return *this;
381 }
382
383 inline operator void*() const { return handle; }
384 inline void* get() const { return handle; }
385
386 operator bool() const = delete;
387 // Deleting this operator prevents accidental use in boolean contexts, which
388 // the void* conversion operator above would otherwise allow.
389
390 inline bool operator==(decltype(nullptr)) { return handle != (void*)-1; }
391 inline bool operator!=(decltype(nullptr)) { return handle == (void*)-1; }
392
393 inline void* release() {
394 // Release ownership of an FD. Not recommended.
395 void* result = handle;
396 handle = (void*)-1;
397 return result;
398 }
399
400 private:
401 void* handle; // -1 (aka INVALID_HANDLE_VALUE) if not valid.
402 };
403
404 class HandleInputStream: public InputStream {
405 // An InputStream wrapping a Win32 HANDLE.
406
407 public:
408 explicit HandleInputStream(void* handle): handle(handle) {}
409 explicit HandleInputStream(AutoCloseHandle handle): handle(handle), autoclose(mv(handle)) {}
410 KJ_DISALLOW_COPY_AND_MOVE(HandleInputStream);
411 ~HandleInputStream() noexcept(false);
412
413 size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override;
414
415 private:
416 void* handle;
417 AutoCloseHandle autoclose;
418 };
419
420 class HandleOutputStream: public OutputStream {
421 // An OutputStream wrapping a Win32 HANDLE.
422
423 public:
424 explicit HandleOutputStream(void* handle): handle(handle) {}
425 explicit HandleOutputStream(AutoCloseHandle handle): handle(handle), autoclose(mv(handle)) {}
426 KJ_DISALLOW_COPY_AND_MOVE(HandleOutputStream);
427 ~HandleOutputStream() noexcept(false);
428
429 void write(const void* buffer, size_t size) override;
430
431 private:
432 void* handle;
433 AutoCloseHandle autoclose;
434 };
435
436 #endif // _WIN32
437
438 } // namespace kj
439
440 KJ_END_HEADER