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