nlib
InputStream.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_INPUTSTREAM_H_
17 #define INCLUDE_NN_NLIB_INPUTSTREAM_H_
18 
19 #include "nn/nlib/Config.h"
20 #include "nn/nlib/TypeTraits.h"
21 
22 NLIB_NAMESPACE_BEGIN
23 
24 // code snippets:
25 // InputStream& stream = 'stream that inherits InputStream';
26 // if (!stream.Read(dataptr, nbyte)) { error = stream.GetErrorValue(); ..... }
27 // while ((c = stream.Read()) >= 0) { c is [0x00 - 0xFF] }
28 // if (!stream) { error = stream.GetErrorValue(); ..... }
30  public:
32  is_buf_curidx_(0),
33  is_buf_endidx_(0),
34  is_buf_markidx_(static_cast<size_t>(-1)),
35  is_buf_(NULL),
36  is_bufsize_(0),
37  is_buf_readonly_(false),
38  is_mark_supported_(false),
39  errno_(0) {}
40  NLIB_CEXPR InputStream(bool is_mark_supported, bool is_buf_readonly) :
41  pos_(0),
42  is_buf_curidx_(0),
43  is_buf_endidx_(0),
44  is_buf_markidx_(static_cast<size_t>(-1)),
45  is_buf_(NULL),
46  is_bufsize_(0),
47  is_buf_readonly_(is_buf_readonly),
48  is_mark_supported_(is_mark_supported),
49  errno_(0) {}
51  // NOTE:
52  // cannot call Close_() from this destructor.
53  // the destructor of the derived class has to call Close_() if needed.
54  }
55  // returns true if there has been no errors
56  // you can also write the codes such that 'if (!!stream) { ... }'
57  errno_t GetErrorValue() const NLIB_NOEXCEPT { return errno_; }
58  // use Pos64() if you need a 64bit value on 32bit arch
59  size_t Pos() const NLIB_NOEXCEPT { return static_cast<size_t>(Pos64()); }
60  uint64_t Pos64() const NLIB_NOEXCEPT { return pos_ + is_buf_curidx_; }
62  if (*this && is_buf_curidx_ == is_buf_endidx_) {
63  CheckBuffer_();
64  return *this && is_buf_curidx_ == is_buf_endidx_;
65  }
66  return false;
67  }
68  // < 0 if EOS or error, otherwise returns a byte and ++pos
70  if (NLIB_UNLIKELY(is_buf_curidx_ == is_buf_endidx_)) {
71  CheckBuffer_();
72  if (NLIB_UNLIKELY(is_buf_curidx_ == is_buf_endidx_)) return -1;
73  }
74  return is_buf_[is_buf_curidx_++];
75  }
76  // < 0 if EOS or error, otherwise returns a byte and pos is unchanged
78  if (NLIB_UNLIKELY(is_buf_curidx_ == is_buf_endidx_)) {
79  CheckBuffer_();
80  if (NLIB_UNLIKELY(is_buf_curidx_ == is_buf_endidx_)) return -1;
81  }
82  return is_buf_[is_buf_curidx_];
83  }
84  // returns skipped number of bytes
85  size_t Skip(size_t nbytes) NLIB_NOEXCEPT;
86  size_t Read(void* ptr, size_t nbytes) NLIB_NOEXCEPT {
87 #ifndef NLIB_NONNULL_ENABLED
88  if (!ptr) {
89  this->SetError(EINVAL);
90  return 0;
91  }
92 #endif
93  if (nbytes > RSIZE_MAX) { // INT01-C
94  this->SetError(EINVAL);
95  return 0;
96  }
97  if (is_buf_curidx_ + nbytes <= is_buf_endidx_) {
98  nlib_memcpy(ptr, nbytes, &is_buf_[is_buf_curidx_], nbytes);
99  is_buf_curidx_ += nbytes;
100  return nbytes;
101  }
102  return this->Read_(ptr, nbytes);
103  }
104  template<size_t N>
105  size_t Read(nlib_byte_t (&buf)[N]) NLIB_NOEXCEPT {
106  return Read(&buf[0], N);
107  }
108  bool Close() NLIB_NOEXCEPT;
109  bool Mark(size_t readlimit) NLIB_NOEXCEPT;
110  bool GoBackToMark() NLIB_NOEXCEPT;
111  bool IsMarkSupported() const NLIB_NOEXCEPT { return is_mark_supported_; }
112  NLIB_SAFE_BOOL(InputStream, errno_ == 0)
113 
114  protected:
115  void
116  SetBuffer(void* p, size_t nbytes, bool is_mark_supported, bool is_buf_readonly) NLIB_NOEXCEPT {
117  NLIB_ASSERT(is_buf_readonly || !is_mark_supported);
118  NLIB_ASSERT(p);
119  NLIB_ASSERT(!is_mark_supported_ || is_buf_readonly_ || nbytes >= 1024);
120  is_buf_ = static_cast<unsigned char*>(p);
121  is_bufsize_ = static_cast<int>(nbytes);
122  is_mark_supported_ = is_mark_supported;
123  is_buf_readonly_ = is_buf_readonly;
124  }
125  void SetBuffer(void* p, size_t nbytes) NLIB_NOEXCEPT {
126  NLIB_ASSERT(p);
127  NLIB_ASSERT(!is_mark_supported_ || is_buf_readonly_ || nbytes >= 1024);
128  is_buf_ = static_cast<unsigned char*>(p);
129  is_bufsize_ = static_cast<int>(nbytes);
130  }
132  if (errno_ == 0) errno_ = e;
133  }
134 
135  private:
136  virtual size_t FillBuffer_(void* p, size_t nbytes) NLIB_NOEXCEPT = 0;
137  virtual bool Close_() NLIB_NOEXCEPT = 0;
138  // By default, Skip_() reads data on is_buf_.
139  // you can override it if you can implement more efficient code.
140  virtual size_t Skip_(size_t nbytes) NLIB_NOEXCEPT;
141 
142  private:
143  size_t Read_(void* ptr, size_t nbytes) NLIB_NOEXCEPT;
144  void CheckBuffer_() NLIB_NOEXCEPT;
145 
146  private:
147  uint64_t pos_;
148  size_t is_buf_curidx_;
149  size_t is_buf_endidx_;
150  size_t is_buf_markidx_;
151  unsigned char* is_buf_;
152  size_t is_bufsize_;
153  bool is_buf_readonly_;
154  bool is_mark_supported_;
155  mutable ErrnoT errno_;
156  // errno_ is changed only from derived classes.
157  // FillBuffer_() or Close_() changes errno_ in other words.
158 
160 };
161 
163  public:
165  virtual ~NullInputStream() NLIB_NOEXCEPT {}
166 
167  private:
168  char dummy_buf_[256];
169  virtual size_t FillBuffer_(void* p, size_t nbytes) NLIB_NOEXCEPT NLIB_OVERRIDE;
170  virtual bool Close_() NLIB_NOEXCEPT NLIB_OVERRIDE { return true; }
171  virtual size_t Skip_(size_t nbytes) NLIB_NOEXCEPT NLIB_OVERRIDE;
172 };
173 
174 namespace detail {
175 
176 template<size_t N>
177 class MiniBufIn {
178  public:
179  NLIB_STATIC_ASSERT(N >= 16);
180  static NLIB_CEXPR const size_t buf_size = N;
181  NLIB_ALWAYS_INLINE MiniBufIn() NLIB_NOEXCEPT { cur_ = end_ = &buf_[0]; }
182  template<class IS>
183  NLIB_ALWAYS_INLINE bool Prefetch(IS* stream, size_t n) NLIB_NOEXCEPT {
184  if (cur_ + n > end_) {
185  NLIB_ASSERT(n <= N);
186  size_t rem = end_ - cur_;
187  nlib_memmove(static_cast<void*>(&buf_[0]), N, cur_, rem);
188  size_t nread = stream->Read(&buf_[rem], N - rem);
189  cur_ = &buf_[0];
190  end_ = &buf_[0] + rem + nread;
191  return (nread + rem >= n);
192  }
193  return true;
194  }
195  template<class IS>
196  NLIB_ALWAYS_INLINE int Peek(IS* stream) NLIB_NOEXCEPT {
197  if (NLIB_UNLIKELY(cur_ == end_)) {
198  size_t nread = stream->Read(&buf_[0], N);
199  if (NLIB_UNLIKELY(nread == 0)) return -1;
200  cur_ = &buf_[0];
201  end_ = &buf_[0] + nread;
202  }
203  return *cur_;
204  }
205  template<class IS>
206  NLIB_ALWAYS_INLINE int Read(IS* stream) NLIB_NOEXCEPT {
207  if (NLIB_UNLIKELY(cur_ == end_)) {
208  size_t nread = stream->Read(&buf_[0], N);
209  if (NLIB_UNLIKELY(nread == 0)) return -1;
210  cur_ = &buf_[0] + 1;
211  end_ = &buf_[0] + nread;
212  return buf_[0];
213  } else {
214  int c = *cur_;
215  ++cur_;
216  return c;
217  }
218  }
219 
220  NLIB_ALWAYS_INLINE void Advance(size_t n) NLIB_NOEXCEPT {
221  // Prefetch(stream, n) must be successful beforehand
222  cur_ += n;
223  }
224  NLIB_ALWAYS_INLINE const uint8_t& operator[](size_t n) NLIB_NOEXCEPT {
225  // Prefetch(stream, n + 1) must be successful beforehand
226  return cur_[n];
227  }
228  template<class IS>
229  NLIB_ALWAYS_INLINE size_t ReadBytes(IS* stream, void* data, size_t nbytes) NLIB_NOEXCEPT {
230  if (cur_ + nbytes <= end_) {
231  nlib_memcpy(data, nbytes, cur_, nbytes);
232  cur_ += nbytes;
233  return nbytes;
234  }
235  uint8_t* p = static_cast<uint8_t*>(data);
236  size_t rem = end_ - cur_;
237  nlib_memcpy(static_cast<void*>(p), nbytes, cur_, rem);
238  cur_ = end_ = &buf_[0];
239  size_t nread = stream->Read(p + rem, nbytes - rem);
240  return nread + rem;
241  }
242  template<class IS, class T>
243  size_t Read(IS* stream, T* data, size_t count) NLIB_NOEXCEPT {
244  NLIB_STATIC_ASSERT(sizeof(*data) <= N);
245  NLIB_STATIC_ASSERT(IsPod<T>::value);
246  size_t nbytes = sizeof(*data) * count;
247  size_t nread = ReadBytes(stream, data, nbytes);
248  if (NLIB_LIKELY(nread == nbytes)) return count;
249  size_t mod = nread % sizeof(*data);
250  uint8_t* p = static_cast<uint8_t*>(static_cast<void*>(data));
251  nlib_memcpy(static_cast<void*>(&buf_[0]), N, p + nread - mod, mod);
252  end_ = &buf_[mod];
253  return nread / sizeof(*data);
254  }
255  NLIB_ALWAYS_INLINE size_t size() const NLIB_NOEXCEPT { return end_ - cur_; }
256 
257  private:
258  uint8_t* cur_;
259  uint8_t* end_;
260  uint8_t buf_[N];
261 };
262 
263 } // namespace detail
264 NLIB_NAMESPACE_END
265 
266 #endif // INCLUDE_NN_NLIB_INPUTSTREAM_H_
#define NLIB_OVERRIDE
利用可能であればoverrideが定義されます。そうでない場合は空文字列です。
Definition: Config.h:249
size_t Read(nlib_byte_t(&buf)[N]) noexcept
上記関数のテンプレートオーバーロードです。
Definition: InputStream.h:105
size_t Read(void *ptr, size_t nbytes) noexcept
ptr で示されるメモリにnbytes 読み込みます。
Definition: InputStream.h:86
#define NLIB_ALWAYS_INLINE
コンパイラに関数をインライン展開するように強く示します。
Definition: Platform_unix.h:95
C++11の標準ヘッダとなるtype_traitsの代用定義です。 コンパイラや標準ライブラリによってサポートされてい...
uint64_t Pos64() const noexcept
ストリーム上の現在位置を64bit値で返します。
Definition: InputStream.h:60
#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
errno_t GetErrorValue() const noexcept
エラー値を取得します。
Definition: InputStream.h:57
bool IsEos() noexcept
ストリームを最後まで読み終えている場合trueを返します。最後まで読み終えていない場合やエラーが発生して...
Definition: InputStream.h:61
#define NLIB_CHECK_RESULT
関数の呼び出し元が戻り値をチェックする必要があることを示します。
int Read() noexcept
ストリームから1バイトを読み込みます。
Definition: InputStream.h:69
#define NLIB_UNLIKELY(x)
条件xが偽になる傾向が高いことをコンパイラに示します。
Definition: Platform_unix.h:98
#define RSIZE_MAX
size_tの最大値よりいくらか小さい値が定義されています。
Definition: Platform.h:219
#define NLIB_VIS_PUBLIC
関数やクラス等のシンボルをライブラリの外部に公開します。
Definition: Platform_unix.h:87
size_t Pos() const noexcept
ストリーム上の現在位置を返します。
Definition: InputStream.h:59
virtual ~InputStream() noexcept
デストラクタです。 派生クラスから呼び出されます。
Definition: InputStream.h:50
#define NLIB_LIKELY(x)
条件xが真になる傾向が高いことをコンパイラに示します。
Definition: Platform_unix.h:97
constexpr InputStream() noexcept
デフォルトコンストラクタです。 派生クラスから呼び出されます。
Definition: InputStream.h:31
入力ストリームの基底クラスです。このクラスを実体化することはできません。
Definition: InputStream.h:29
errno_tをラップするクラスです。Visual Studioのデバッガ上での表示を改善します。
Definition: Config.h:404
int Peek() noexcept
ストリームを消費せずに次の1バイトを読み込みます。
Definition: InputStream.h:77
#define NLIB_NOEXCEPT
環境に合わせてnoexcept 又は同等の定義がされます。
Definition: Config.h:109
#define NLIB_CEXPR
利用可能であればconstexprが定義されます。そうでない場合は空文字列です。
Definition: Config.h:111
開発環境別の設定が書かれるファイルです。
void SetError(errno_t e) const noexcept
InputStreamにエラーを設定します。
Definition: InputStream.h:131
#define NLIB_FINAL
利用可能であればfinalが定義されます。そうでない場合は空文字列です。
Definition: Config.h:250
#define NLIB_STATIC_ASSERT(exp)
静的アサートが定義されます。利用可能であればstatic_assertを利用します。
Definition: Config.h:174
bool Read(BinaryReader *r, T *x)
この関数テンプレートを特殊化することで、ユーザー定義クラスに読み込むことができます。 ...
Definition: BinaryReader.h:161
常に0を読み込むストリームです。
Definition: InputStream.h:162
unsigned char nlib_byte_t
C++17以降でstd::byteにtypedefされる型です。
Definition: Platform.h:314
static errno_t nlib_memmove(void *s1, size_t s1max, const void *s2, size_t n)
N1078のmemmove_sに相当する実装です。
Definition: Platform.h:2530
int errno_t
intのtypedefで、戻り値としてPOSIXのエラー値を返すことを示します。
Definition: NMalloc.h:37