Mercurial > repos > rliterman > csp2
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 |