nlib
OutputStream.h
[詳解]
1 
2 #pragma once
3 #ifndef INCLUDE_NN_NLIB_OUTPUTSTREAM_H_
4 #define INCLUDE_NN_NLIB_OUTPUTSTREAM_H_
5 
6 #include "nn/nlib/Config.h"
7 
8 NLIB_NAMESPACE_BEGIN
9 
10 // code snippets:
11 // OutputStream& stream = 'stream that inherits OutputStream';
12 // if (!stream.Write(dataptr, nbyte)) { error = stream.GetErrorValue(); .... }
13 // for (.....) { if (!stream.Write(byte)) { error = stream.GetErrorValue(); .... } }
14 // # you should Flush() and Close() explicitly
15 // if (!stream.Flush()) { error = stream.GetErrorValue(); .... } }
16 // if (!stream.Close()) { error = stream.GetErrorValue(); .... } }
18  public:
20  BUFFERINGMODE_BLOCKBUFFERED = 0, // default
21  BUFFERINGMODE_LINEBUFFERED, // if console output
22  BUFFERINGMODE_UNBUFFERED
23  };
24 
25  public:
27  os_buf_curidx_(0),
28  os_buf_(NULL),
29  os_bufsize_(0),
30  errno_(0),
31  m_BufferingMode(BUFFERINGMODE_BLOCKBUFFERED) {}
33  // NOTE:
34  // cannot call Close_() from this destructor.
35  // the destructor of the derived class has to call Close_() if needed.
36  }
37  // use Pos64() if you need a 64bit value on 32bit arch
38  size_t Pos() const NLIB_NOEXCEPT { return static_cast<size_t>(Pos64()); }
39  uint64_t Pos64() const NLIB_NOEXCEPT { return pos_ + os_buf_curidx_; }
40  bool Write(int b) NLIB_NOEXCEPT {
41  // NOTE:
42  // if the stream is closed,
43  // Write() will succeed before the internal buffer becomes full.
44  if (NLIB_UNLIKELY(os_buf_curidx_ == os_bufsize_)) {
45  if (NLIB_UNLIKELY(!this->Flush_(false))) return false;
46  if (NLIB_UNLIKELY(os_bufsize_ == 0)) {
47  this->SetError(EIO);
48  return false;
49  }
50  }
51  os_buf_[os_buf_curidx_++] = static_cast<unsigned char>(b & 0xff);
52  return true;
53  }
54  bool Write(const void* p, size_t n) NLIB_NOEXCEPT NLIB_NONNULL {
55 #ifndef NLIB_NONNULL_ENABLED
56  if (!p) {
57  this->SetError(EINVAL);
58  return false;
59  }
60 #endif
61  if (n > RSIZE_MAX) {
62  this->SetError(EINVAL);
63  return false;
64  }
65  if (os_buf_curidx_ + n <= os_bufsize_) {
66  nlib_memcpy(&os_buf_[os_buf_curidx_], n, p, n);
67  os_buf_curidx_ += n;
68  return true;
69  }
70  return this->Write_(p, n);
71  }
72  bool WriteGather(const nlib_fd_iovec* iov, int iovcnt) NLIB_NOEXCEPT NLIB_NONNULL {
73 #ifndef NLIB_NONNULL_ENABLED
74  if (!iov) {
75  this->SetError(EINVAL);
76  return false;
77  }
78 #endif
79  if (iovcnt < 0) {
80  this->SetError(EINVAL);
81  return false;
82  }
83  return this->WriteGather_(iov, iovcnt);
84  }
85  bool Flush() NLIB_NOEXCEPT { return Flush_(true); }
86  bool Close() NLIB_NOEXCEPT;
87  errno_t GetErrorValue() const NLIB_NOEXCEPT { return errno_; }
88  // returns true if there has been no errors
89  // you can also write the codes such that 'if (!!stream) { ... }'
90  BufferingMode GetBufferingMode() const NLIB_NOEXCEPT { return m_BufferingMode; }
91  NLIB_SAFE_BOOL(OutputStream, errno_ == 0)
92 
93  protected:
94  void ResetBuffer(void* p, size_t nbytes) NLIB_NOEXCEPT {
95  os_buf_ = reinterpret_cast<unsigned char*>(p);
96  os_bufsize_ = static_cast<int>(nbytes);
97  }
98  void SetError(errno_t e) const NLIB_NOEXCEPT {
99  if (errno_ == 0) errno_ = e;
100  }
101 
102  private:
103  virtual bool PushBuffer_(const void* p, size_t nbytes, bool do_flush) NLIB_NOEXCEPT = 0;
104  virtual bool Close_() NLIB_NOEXCEPT = 0;
105  virtual void* GetWorkBuffer_(size_t* nbytes) NLIB_NOEXCEPT;
106  virtual bool WriteGather_(const nlib_fd_iovec* iov, int iovcnt) NLIB_NOEXCEPT;
107  bool Write_(const void* p, size_t n) NLIB_NOEXCEPT;
108 
109  private:
110  bool Flush_(bool flush_device) NLIB_NOEXCEPT;
111  bool GetWorkBuffer_() NLIB_NOEXCEPT;
112 
113  private:
114  uint64_t pos_;
115  size_t os_buf_curidx_;
116  unsigned char* os_buf_;
117  size_t os_bufsize_;
118  mutable ErrnoT errno_;
119 
120  protected:
121  // NOTE:
122  // BufferingMode is for the codes which use OutputStream.
123  // OutputStream only shows the buffering mode which the user specified.
124  // for example, TextWriter (the user of OutputStream) has to decide
125  // when to call Flush() looking at GetBufferingMode().
127 
128  private:
130 };
131 
133  public:
136 
137  private:
138  unsigned char dummy_buf_[256];
139  virtual bool PushBuffer_(const void* p, size_t, bool do_flush) NLIB_NOEXCEPT NLIB_OVERRIDE;
140  virtual bool Close_() NLIB_NOEXCEPT NLIB_OVERRIDE { return true; }
141 };
142 
143 namespace detail {
144 
145 template<size_t N>
146 class MiniBufOut {
147  public:
148  static NLIB_CEXPR const size_t buf_size = N;
149  NLIB_ALWAYS_INLINE MiniBufOut() NLIB_NOEXCEPT { cur_ = &buf_[0]; }
150  template<class OS>
151  NLIB_ALWAYS_INLINE bool Flush(OS* stream) NLIB_NOEXCEPT {
152  size_t n = cur_ - &buf_[0];
153  cur_ = &buf_[0];
154  return stream->Write(&buf_[0], n);
155  }
156  template<class OS>
157  NLIB_ALWAYS_INLINE bool CheckAndFlush(OS* stream, size_t n) NLIB_NOEXCEPT {
158  if (cur_ + n > &buf_[0] + N) {
159  NLIB_ASSERT(n <= N);
160  return Flush(stream);
161  }
162  return true;
163  }
164  NLIB_ALWAYS_INLINE void Advance(size_t n) NLIB_NOEXCEPT {
165  // CheckAndFlush(stream, n) must be successful beforehand.
166  cur_ += n;
167  }
168  NLIB_ALWAYS_INLINE uint8_t& operator[](size_t n) NLIB_NOEXCEPT {
169  // CheckAndFlush(stream, n + 1) must be successful beforehand.
170  return cur_[n];
171  }
172  template<class OS>
173  NLIB_ALWAYS_INLINE bool WriteAndAdvance(OS* stream, uint8_t data) NLIB_NOEXCEPT {
174  if (NLIB_LIKELY(CheckAndFlush(stream, 1))) {
175  *cur_ = data;
176  ++cur_;
177  return true;
178  }
179  return false;
180  }
181  template<class OS>
182  NLIB_ALWAYS_INLINE bool WriteAndAdvance(OS* stream,
183  const void* data, size_t n) NLIB_NOEXCEPT {
184  if (NLIB_LIKELY(CheckAndFlush(stream, n))) {
185  (void)nlib_memcpy(cur_, n, data, n);
186  cur_ += n;
187  return true;
188  }
189  return false;
190  }
191 
192  private:
193  uint8_t* cur_;
194  uint8_t buf_[N];
195  NLIB_DISALLOW_COPY_AND_ASSIGN(MiniBufOut);
196 };
197 
198 template<class T>
199 class MiniReallocOut {
200  public:
201  NLIB_ALWAYS_INLINE MiniReallocOut(T** mem, uint32_t* cur, uint32_t* memsize) NLIB_NOEXCEPT
202  : mem_(mem), cur_(cur), memsize_(memsize) {}
203  NLIB_ALWAYS_INLINE ~MiniReallocOut() NLIB_NOEXCEPT {}
204  NLIB_ALWAYS_INLINE bool Resize(uint32_t n) NLIB_NOEXCEPT {
205  if (n <= *memsize_) {
206  *cur_ = n;
207  } else {
208  void* p = nlib_realloc(*mem_, n * sizeof(**mem_));
209  if (!p) return false;
210  *mem_ = reinterpret_cast<T*>(p);
211  *memsize_ = n;
212  *cur_ = n;
213  }
214  return true;
215  }
216  NLIB_ALWAYS_INLINE bool Prepare(uint32_t n) NLIB_NOEXCEPT {
217  // T must be int, uint32_t, ... etc. for example
218  if (NLIB_UNLIKELY(*cur_ + n > *memsize_)) {
219  uint32_t newsize;
220  const uint32_t t = 4096 / sizeof(**mem_);
221  if (*cur_ + n >= t) {
222  newsize = ((*cur_ + n) + t - 1) & ~(t - 1);
223  } else {
224  newsize = 1 << (32 - nlib_clz(*cur_ + n - 1));
225  }
226  void* p = nlib_realloc(*mem_, newsize * sizeof(**mem_));
227  if (!p) return false;
228  *mem_ = reinterpret_cast<T*>(p);
229  *memsize_ = newsize;
230  }
231  return true;
232  }
233  NLIB_ALWAYS_INLINE T& operator[](uint32_t n) NLIB_NOEXCEPT {
234  // Prepare(n + 1) must be successful beforehand.
235  return (*mem_)[*cur_ + n];
236  }
237  NLIB_ALWAYS_INLINE void Append(const T& v) NLIB_NOEXCEPT {
238  // Prepare(1) must be successful beforehand.
239  (*mem_)[*cur_] = v;
240  ++(*cur_);
241  }
242  NLIB_ALWAYS_INLINE void Advance(uint32_t n) NLIB_NOEXCEPT {
243  // Prepare(n) must be successful beforehand.
244  *cur_ += n;
245  }
246 
247  private:
248  T** mem_;
249  uint32_t* cur_;
250  uint32_t* memsize_; // sizeof(*mem) * memsize_ bytes
251  NLIB_DISALLOW_COPY_AND_ASSIGN(MiniReallocOut);
252 };
253 
254 } // namespace detail
255 
256 NLIB_NAMESPACE_END
257 
258 #endif // INCLUDE_NN_NLIB_OUTPUTSTREAM_H_
bool Flush() noexcept
ストリームをフラッシュします。
Definition: OutputStream.h:85
#define NLIB_OVERRIDE
利用可能であればoverrideが定義されます。そうでない場合は空文字列です。
Definition: Config.h:210
#define NLIB_ALWAYS_INLINE
コンパイラに関数をインライン展開するように強く示します。
Definition: Platform_unix.h:69
uint64_t Pos64() const noexcept
ストリーム上の現在位置を64bit整数で返します。
Definition: OutputStream.h:39
void SetError(errno_t e) const noexcept
OutputStreamにエラーを設定します。
Definition: OutputStream.h:98
#define NLIB_DISALLOW_COPY_AND_ASSIGN(TypeName)
TypeName で指定されたクラスのコピーコンストラクタと代入演算子を禁止します。
Definition: Config.h:145
#define NLIB_SAFE_BOOL(class_name, exp)
クラス内に安全なoperator bool()を定義します。 可能であればC++11のexplicit boolを利用します。 ...
Definition: Config.h:160
size_t Pos() const noexcept
ストリーム上の現在位置を返します。
Definition: OutputStream.h:38
#define NLIB_UNLIKELY(x)
条件xが偽になる傾向が高いことをコンパイラに示します。
Definition: Platform_unix.h:72
#define RSIZE_MAX
size_tの最大値よりいくらか小さい値が定義されています。
Definition: Platform.h:541
#define NLIB_VIS_PUBLIC
関数やクラス等のシンボルをライブラリの外部に公開します。
Definition: Platform_unix.h:61
constexpr OutputStream() noexcept
デフォルトコンストラクタです。
Definition: OutputStream.h:26
実際の書き込み動作を行わないOutputStreamです。
Definition: OutputStream.h:132
bool Write(int b) noexcept
ストリームに1バイトのデータを書き込みます。
Definition: OutputStream.h:40
#define NLIB_LIKELY(x)
条件xが真になる傾向が高いことをコンパイラに示します。
Definition: Platform_unix.h:71
errno_tをラップするクラスです。Visual Studioのデバッガ上での表示を改善します。
Definition: Config.h:474
static errno_t nlib_memcpy(void *s1, size_t s1max, const void *s2, size_t n)
N1078のmemcpy_sに相当する実装です。
Definition: Platform.h:3170
#define NLIB_NOEXCEPT
環境に合わせてnoexcept 又は同等の定義がされます。
Definition: Config.h:86
#define NLIB_CEXPR
利用可能であればconstexprが定義されます。そうでない場合は空文字列です。
Definition: Config.h:80
virtual ~OutputStream() noexcept
デストラクタです。何もしません。
Definition: OutputStream.h:32
開発環境別の設定が書かれるファイルです。
NLIB_CHECK_RESULT void * nlib_realloc(void *ptr, size_t size)
C標準関数のrealloc()を呼び出すweak関数です。nlibはこの関数を経由してrealloc()を呼び出します。 ...
BufferingMode GetBufferingMode() const noexcept
バッファリングモードを取得します。
Definition: OutputStream.h:90
出力をラインバッファします。コンソールに出力する場合に設定されます。
Definition: OutputStream.h:21
BufferingMode m_BufferingMode
バッファリングモードが格納されています。
Definition: OutputStream.h:126
void ResetBuffer(void *p, size_t nbytes) noexcept
OutputStreamが持つバッファを設定します。
Definition: OutputStream.h:94
#define NLIB_FINAL
利用可能であればfinalが定義されます。そうでない場合は空文字列です。
Definition: Config.h:211
errno_t GetErrorValue() const noexcept
エラー値を取得します。
Definition: OutputStream.h:87
bool Write(const void *p, size_t n) noexcept
ストリームにn バイトのデータを書き込みます。
Definition: OutputStream.h:54
#define NLIB_NONNULL
全ての引数にNULLを指定することができないことを示します。
Definition: Platform_unix.h:76
BufferingMode
OutputStreamのバッファリングモードです。
Definition: OutputStream.h:19
出力ストリームの基底クラスです。このクラスを実体化することはできません。
Definition: OutputStream.h:17
bool WriteGather(const nlib_fd_iovec *iov, int iovcnt) noexcept
複数の非連続のバッファからデータをストリームに書き出します。
Definition: OutputStream.h:72
int errno_t
intのtypedefで、戻り値としてPOSIXのエラー値を返すことを示します。
Definition: NMalloc.h:24