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