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