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