io.h 12 KB
Newer Older
Kenton Varda's avatar
Kenton Varda committed
1 2
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
3
//
Kenton Varda's avatar
Kenton Varda committed
4 5 6 7 8 9
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
10
//
Kenton Varda's avatar
Kenton Varda committed
11 12
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
13
//
Kenton Varda's avatar
Kenton Varda committed
14 15 16 17 18 19 20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
21

22 23
#ifndef KJ_IO_H_
#define KJ_IO_H_
24

25 26 27 28
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif

Kenton Varda's avatar
Kenton Varda committed
29
#include <stddef.h>
Kenton Varda's avatar
Kenton Varda committed
30
#include "common.h"
31
#include "array.h"
32
#include "exception.h"
33

34
namespace kj {
35 36 37 38 39 40

// =======================================================================================
// Abstract interfaces

class InputStream {
public:
41
  virtual ~InputStream() noexcept(false);
42

43
  size_t read(void* buffer, size_t minBytes, size_t maxBytes);
44
  // Reads at least minBytes and at most maxBytes, copying them into the given buffer.  Returns
45
  // the size read.  Throws an exception on errors.  Implemented in terms of tryRead().
46 47 48 49 50 51 52
  //
  // maxBytes is the number of bytes the caller really wants, but minBytes is the minimum amount
  // needed by the caller before it can start doing useful processing.  If the stream returns less
  // than maxBytes, the caller will usually call read() again later to get the rest.  Returning
  // less than maxBytes is useful when it makes sense for the caller to parallelize processing
  // with I/O.
  //
53 54 55 56
  // Never blocks if minBytes is zero.  If minBytes is zero and maxBytes is non-zero, this may
  // attempt a non-blocking read or may just return zero.  To force a read, use a non-zero minBytes.
  // To detect EOF without throwing an exception, use tryRead().
  //
57 58 59 60 61 62
  // Cap'n Proto never asks for more bytes than it knows are part of the message.  Therefore, if
  // the InputStream happens to know that the stream will never reach maxBytes -- even if it has
  // reached minBytes -- it should throw an exception to avoid wasting time processing an incomplete
  // message.  If it can't even reach minBytes, it MUST throw an exception, as the caller is not
  // expected to understand how to deal with partial reads.

63 64 65
  virtual size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) = 0;
  // Like read(), but may return fewer than minBytes on EOF.

66 67 68 69 70 71 72 73 74 75
  inline void read(void* buffer, size_t bytes) { read(buffer, bytes, bytes); }
  // Convenience method for reading an exact number of bytes.

  virtual void skip(size_t bytes);
  // Skips past the given number of bytes, discarding them.  The default implementation read()s
  // into a scratch buffer.
};

class OutputStream {
public:
76
  virtual ~OutputStream() noexcept(false);
77 78 79 80

  virtual void write(const void* buffer, size_t size) = 0;
  // Always writes the full size.  Throws exception on error.

81
  virtual void write(ArrayPtr<const ArrayPtr<const byte>> pieces);
82 83 84 85 86 87 88 89 90 91 92 93
  // Equivalent to write()ing each byte array in sequence, which is what the default implementation
  // does.  Override if you can do something better, e.g. use writev() to do the write in a single
  // syscall.
};

class BufferedInputStream: public InputStream {
  // An input stream which buffers some bytes in memory to reduce system call overhead.
  // - OR -
  // An input stream that actually reads from some in-memory data structure and wants to give its
  // caller a direct pointer to that memory to potentially avoid a copy.

public:
94
  virtual ~BufferedInputStream() noexcept(false);
95

96
  ArrayPtr<const byte> getReadBuffer();
97 98
  // Get a direct pointer into the read buffer, which contains the next bytes in the input.  If the
  // caller consumes any bytes, it should then call skip() to indicate this.  This always returns a
99 100 101 102
  // non-empty buffer or throws an exception.  Implemented in terms of tryGetReadBuffer().

  virtual ArrayPtr<const byte> tryGetReadBuffer() = 0;
  // Like getReadBuffer() but may return an empty buffer on EOF.
103 104 105 106 107 108 109 110 111
};

class BufferedOutputStream: public OutputStream {
  // An output stream which buffers some bytes in memory to reduce system call overhead.
  // - OR -
  // An output stream that actually writes into some in-memory data structure and wants to give its
  // caller a direct pointer to that memory to potentially avoid a copy.

public:
112
  virtual ~BufferedOutputStream() noexcept(false);
113

114
  virtual ArrayPtr<byte> getWriteBuffer() = 0;
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
  // Get a direct pointer into the write buffer.  The caller may choose to fill in some prefix of
  // this buffer and then pass it to write(), in which case write() may avoid a copy.  It is
  // incorrect to pass to write any slice of this buffer which is not a prefix.
};

// =======================================================================================
// Buffered streams implemented as wrappers around regular streams

class BufferedInputStreamWrapper: public BufferedInputStream {
  // Implements BufferedInputStream in terms of an InputStream.
  //
  // Note that the underlying stream's position is unpredictable once the wrapper is destroyed,
  // unless the entire stream was consumed.  To read a predictable number of bytes in a buffered
  // way without going over, you'd need this wrapper to wrap some other wrapper which itself
  // implements an artificial EOF at the desired point.  Such a stream should be trivial to write
  // but is not provided by the library at this time.

public:
133
  explicit BufferedInputStreamWrapper(InputStream& inner, ArrayPtr<byte> buffer = nullptr);
134 135 136 137 138 139 140
  // Creates a buffered stream wrapping the given non-buffered stream.  No guarantee is made about
  // the position of the inner stream after a buffered wrapper has been created unless the entire
  // input is read.
  //
  // If the second parameter is non-null, the stream uses the given buffer instead of allocating
  // its own.  This may improve performance if the buffer can be reused.

141
  KJ_DISALLOW_COPY(BufferedInputStreamWrapper);
142
  ~BufferedInputStreamWrapper() noexcept(false);
143 144

  // implements BufferedInputStream ----------------------------------
145 146
  ArrayPtr<const byte> tryGetReadBuffer() override;
  size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override;
147 148 149 150
  void skip(size_t bytes) override;

private:
  InputStream& inner;
151 152 153
  Array<byte> ownedBuffer;
  ArrayPtr<byte> buffer;
  ArrayPtr<byte> bufferAvailable;
154 155 156 157 158 159 160
};

class BufferedOutputStreamWrapper: public BufferedOutputStream {
  // Implements BufferedOutputStream in terms of an OutputStream.  Note that writes to the
  // underlying stream may be delayed until flush() is called or the wrapper is destroyed.

public:
161
  explicit BufferedOutputStreamWrapper(OutputStream& inner, ArrayPtr<byte> buffer = nullptr);
162 163 164 165 166
  // Creates a buffered stream wrapping the given non-buffered stream.
  //
  // If the second parameter is non-null, the stream uses the given buffer instead of allocating
  // its own.  This may improve performance if the buffer can be reused.

167
  KJ_DISALLOW_COPY(BufferedOutputStreamWrapper);
168
  ~BufferedOutputStreamWrapper() noexcept(false);
169 170 171 172 173 174 175

  void flush();
  // Force the wrapper to write any remaining bytes in its buffer to the inner stream.  Note that
  // this only flushes this object's buffer; this object has no idea how to flush any other buffers
  // that may be present in the underlying stream.

  // implements BufferedOutputStream ---------------------------------
176
  ArrayPtr<byte> getWriteBuffer() override;
177 178 179 180
  void write(const void* buffer, size_t size) override;

private:
  OutputStream& inner;
181 182
  Array<byte> ownedBuffer;
  ArrayPtr<byte> buffer;
183
  byte* bufferPos;
184
  UnwindDetector unwindDetector;
185 186 187 188 189 190 191
};

// =======================================================================================
// Array I/O

class ArrayInputStream: public BufferedInputStream {
public:
192
  explicit ArrayInputStream(ArrayPtr<const byte> array);
193
  KJ_DISALLOW_COPY(ArrayInputStream);
194
  ~ArrayInputStream() noexcept(false);
195 196

  // implements BufferedInputStream ----------------------------------
197 198
  ArrayPtr<const byte> tryGetReadBuffer() override;
  size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override;
199 200 201
  void skip(size_t bytes) override;

private:
202
  ArrayPtr<const byte> array;
203 204 205 206
};

class ArrayOutputStream: public BufferedOutputStream {
public:
207
  explicit ArrayOutputStream(ArrayPtr<byte> array);
208
  KJ_DISALLOW_COPY(ArrayOutputStream);
209
  ~ArrayOutputStream() noexcept(false);
210

211
  ArrayPtr<byte> getArray() {
212
    // Get the portion of the array which has been filled in.
213
    return arrayPtr(array.begin(), fillPos);
214 215 216
  }

  // implements BufferedInputStream ----------------------------------
217
  ArrayPtr<byte> getWriteBuffer() override;
218 219 220
  void write(const void* buffer, size_t size) override;

private:
221
  ArrayPtr<byte> array;
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
  byte* fillPos;
};

// =======================================================================================
// File descriptor I/O

class AutoCloseFd {
  // A wrapper around a file descriptor which automatically closes the descriptor when destroyed.
  // The wrapper supports move construction for transferring ownership of the descriptor.  If
  // close() returns an error, the destructor throws an exception, UNLESS the destructor is being
  // called during unwind from another exception, in which case the close error is ignored.
  //
  // If your code is not exception-safe, you should not use AutoCloseFd.  In this case you will
  // have to call close() yourself and handle errors appropriately.

public:
  inline AutoCloseFd(): fd(-1) {}
Kenton Varda's avatar
Kenton Varda committed
239
  inline AutoCloseFd(decltype(nullptr)): fd(-1) {}
240
  inline explicit AutoCloseFd(int fd): fd(fd) {}
241
  inline AutoCloseFd(AutoCloseFd&& other) noexcept: fd(other.fd) { other.fd = -1; }
242
  KJ_DISALLOW_COPY(AutoCloseFd);
243
  ~AutoCloseFd() noexcept(false);
244

245 246 247 248 249 250 251 252 253 254 255 256
  inline AutoCloseFd& operator=(AutoCloseFd&& other) {
    AutoCloseFd old(kj::mv(*this));
    fd = other.fd;
    other.fd = -1;
    return *this;
  }

  inline AutoCloseFd& operator=(decltype(nullptr)) {
    AutoCloseFd old(kj::mv(*this));
    return *this;
  }

257 258
  inline operator int() const { return fd; }
  inline int get() const { return fd; }
259

260 261 262 263
  operator bool() const = delete;
  // Deleting this operator prevents accidental use in boolean contexts, which
  // the int conversion operator above would otherwise allow.

Kenton Varda's avatar
Kenton Varda committed
264 265
  inline bool operator==(decltype(nullptr)) { return fd < 0; }
  inline bool operator!=(decltype(nullptr)) { return fd >= 0; }
266 267 268

private:
  int fd;
269
  UnwindDetector unwindDetector;
270 271
};

272 273 274 275 276
inline auto KJ_STRINGIFY(const AutoCloseFd& fd)
    -> decltype(kj::toCharSequence(implicitCast<int>(fd))) {
  return kj::toCharSequence(implicitCast<int>(fd));
}

277 278 279 280
class FdInputStream: public InputStream {
  // An InputStream wrapping a file descriptor.

public:
281
  explicit FdInputStream(int fd): fd(fd) {}
Kenton Varda's avatar
Kenton Varda committed
282
  explicit FdInputStream(AutoCloseFd fd): fd(fd), autoclose(mv(fd)) {}
283
  KJ_DISALLOW_COPY(FdInputStream);
284
  ~FdInputStream() noexcept(false);
285

286
  size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override;
287 288 289 290 291 292 293 294 295 296

private:
  int fd;
  AutoCloseFd autoclose;
};

class FdOutputStream: public OutputStream {
  // An OutputStream wrapping a file descriptor.

public:
297
  explicit FdOutputStream(int fd): fd(fd) {}
Kenton Varda's avatar
Kenton Varda committed
298
  explicit FdOutputStream(AutoCloseFd fd): fd(fd), autoclose(mv(fd)) {}
299
  KJ_DISALLOW_COPY(FdOutputStream);
300
  ~FdOutputStream() noexcept(false);
301 302

  void write(const void* buffer, size_t size) override;
303
  void write(ArrayPtr<const ArrayPtr<const byte>> pieces) override;
304 305 306 307 308 309

private:
  int fd;
  AutoCloseFd autoclose;
};

310
}  // namespace kj
311

312
#endif  // KJ_IO_H_