nlib
OutputStream.h
[詳解]
1 
2 /*---------------------------------------------------------------------------*
3 
4  Project: CrossRoad
5  Copyright (C)2012-2016 Nintendo. All rights reserved.
6 
7  These coded instructions, statements, and computer programs contain
8  proprietary information of Nintendo of America Inc. and/or Nintendo
9  Company Ltd., and are protected by Federal copyright law. They may
10  not be disclosed to third parties or copied or duplicated in any form,
11  in whole or in part, without the prior written consent of Nintendo.
12 
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  BUFFERINGMODE_BLOCKBUFFERED = 0, // default
34  BUFFERINGMODE_LINEBUFFERED, // if console output
35  BUFFERINGMODE_UNBUFFERED
36  };
37 
38  public:
40  os_buf_curidx_(0),
41  os_buf_(NULL),
42  os_bufsize_(0),
43  errno_(0),
44  m_BufferingMode(BUFFERINGMODE_BLOCKBUFFERED) {}
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_ = reinterpret_cast<unsigned char*>(p);
109  os_bufsize_ = static_cast<int>(nbytes);
110  }
111  void SetError(errno_t e) const NLIB_NOEXCEPT {
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().
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>
159 class MiniBufOut {
160  public:
161  static NLIB_CEXPR const size_t buf_size = N;
162  NLIB_ALWAYS_INLINE MiniBufOut() NLIB_NOEXCEPT { cur_ = &buf_[0]; }
163  template<class OS>
164  NLIB_ALWAYS_INLINE bool Flush(OS* stream) NLIB_NOEXCEPT {
165  size_t n = cur_ - &buf_[0];
166  cur_ = &buf_[0];
167  return stream->Write(&buf_[0], n);
168  }
169  template<class OS>
170  NLIB_ALWAYS_INLINE bool CheckAndFlush(OS* stream, size_t n) NLIB_NOEXCEPT {
171  if (cur_ + n > &buf_[0] + N) {
172  NLIB_ASSERT(n <= N);
173  return Flush(stream);
174  }
175  return true;
176  }
177  NLIB_ALWAYS_INLINE void Advance(size_t n) NLIB_NOEXCEPT {
178  // CheckAndFlush(stream, n) must be successful beforehand.
179  cur_ += n;
180  }
181  NLIB_ALWAYS_INLINE uint8_t& operator[](size_t n) NLIB_NOEXCEPT {
182  // CheckAndFlush(stream, n + 1) must be successful beforehand.
183  return cur_[n];
184  }
185  template<class OS>
186  NLIB_ALWAYS_INLINE bool WriteAndAdvance(OS* stream, uint8_t data) NLIB_NOEXCEPT {
187  if (NLIB_LIKELY(CheckAndFlush(stream, 1))) {
188  *cur_ = data;
189  ++cur_;
190  return true;
191  }
192  return false;
193  }
194  template<class OS>
195  NLIB_ALWAYS_INLINE bool WriteAndAdvance(OS* stream,
196  const void* data, size_t n) NLIB_NOEXCEPT {
197  if (NLIB_LIKELY(CheckAndFlush(stream, n))) {
198  (void)nlib_memcpy(cur_, n, data, n);
199  cur_ += n;
200  return true;
201  }
202  return false;
203  }
204 
205  private:
206  uint8_t* cur_;
207  uint8_t buf_[N];
208  NLIB_DISALLOW_COPY_AND_ASSIGN(MiniBufOut);
209 };
210 
211 template<class T>
212 class MiniReallocOut {
213  public:
214  NLIB_ALWAYS_INLINE MiniReallocOut(T** mem, uint32_t* cur, uint32_t* memsize) NLIB_NOEXCEPT
215  : mem_(mem), cur_(cur), memsize_(memsize) {}
216  NLIB_ALWAYS_INLINE ~MiniReallocOut() NLIB_NOEXCEPT {}
217  NLIB_ALWAYS_INLINE bool Resize(uint32_t n) NLIB_NOEXCEPT {
218  if (n <= *memsize_) {
219  *cur_ = n;
220  } else {
221  void* p = nlib_realloc(*mem_, n * sizeof(**mem_));
222  if (!p) return false;
223  *mem_ = reinterpret_cast<T*>(p);
224  *memsize_ = n;
225  *cur_ = n;
226  }
227  return true;
228  }
229  NLIB_ALWAYS_INLINE bool Prepare(uint32_t n) NLIB_NOEXCEPT {
230  // T must be int, uint32_t, ... etc. for example
231  if (NLIB_UNLIKELY(*cur_ + n > *memsize_)) {
232  uint32_t newsize;
233  const uint32_t t = 4096 / sizeof(**mem_);
234  if (*cur_ + n >= t) {
235  newsize = ((*cur_ + n) + t - 1) & ~(t - 1);
236  } else {
237  newsize = 1 << (32 - nlib_clz(*cur_ + n - 1));
238  }
239  void* p = nlib_realloc(*mem_, newsize * sizeof(**mem_));
240  if (!p) return false;
241  *mem_ = reinterpret_cast<T*>(p);
242  *memsize_ = newsize;
243  }
244  return true;
245  }
246  NLIB_ALWAYS_INLINE T& operator[](uint32_t n) NLIB_NOEXCEPT {
247  // Prepare(n + 1) must be successful beforehand.
248  return (*mem_)[*cur_ + n];
249  }
250  NLIB_ALWAYS_INLINE void Append(const T& v) NLIB_NOEXCEPT {
251  // Prepare(1) must be successful beforehand.
252  (*mem_)[*cur_] = v;
253  ++(*cur_);
254  }
255  NLIB_ALWAYS_INLINE void Advance(uint32_t n) NLIB_NOEXCEPT {
256  // Prepare(n) must be successful beforehand.
257  *cur_ += n;
258  }
259 
260  private:
261  T** mem_;
262  uint32_t* cur_;
263  uint32_t* memsize_; // sizeof(*mem) * memsize_ bytes
264  NLIB_DISALLOW_COPY_AND_ASSIGN(MiniReallocOut);
265 };
266 
267 } // namespace detail
268 
269 NLIB_NAMESPACE_END
270 
271 #endif // INCLUDE_NN_NLIB_OUTPUTSTREAM_H_
bool Flush() noexcept
ストリームをフラッシュします。
Definition: OutputStream.h:98
#define NLIB_OVERRIDE
利用可能であればoverrideが定義されます。そうでない場合は空文字列です。
Definition: Config.h:223
#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:158
#define NLIB_SAFE_BOOL(class_name, exp)
クラス内に安全なoperator bool()を定義します。 可能であればC++11のexplicit boolを利用します。 ...
Definition: Config.h:173
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:553
#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:487
static errno_t nlib_memcpy(void *s1, size_t s1max, const void *s2, size_t n)
N1078のmemcpy_sに相当する実装です。
Definition: Platform.h:3251
#define NLIB_NOEXCEPT
環境に合わせてnoexcept 又は同等の定義がされます。
Definition: Config.h:99
#define NLIB_CEXPR
利用可能であればconstexprが定義されます。そうでない場合は空文字列です。
Definition: Config.h:93
virtual ~OutputStream() noexcept
デストラクタです。何もしません。
Definition: OutputStream.h:45
開発環境別の設定が書かれるファイルです。
NLIB_CHECK_RESULT void * nlib_realloc(void *ptr, size_t size)
C標準関数のrealloc()を呼び出すweak関数です。nlibはこの関数を経由してrealloc()を呼び出します。 ...
BufferingMode GetBufferingMode() const noexcept
バッファリングモードを取得します。
Definition: OutputStream.h:103
出力をラインバッファします。コンソールに出力する場合に設定されます。
Definition: OutputStream.h:34
BufferingMode m_BufferingMode
バッファリングモードが格納されています。
Definition: OutputStream.h:139
void ResetBuffer(void *p, size_t nbytes) noexcept
OutputStreamが持つバッファを設定します。
Definition: OutputStream.h:107
#define NLIB_FINAL
利用可能であればfinalが定義されます。そうでない場合は空文字列です。
Definition: Config.h:224
errno_t GetErrorValue() const noexcept
エラー値を取得します。
Definition: OutputStream.h:100
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