nlib
OutputStream.h
Go to the documentation of this file.
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
Flushes the stream.
Definition: OutputStream.h:98
#define NLIB_OVERRIDE
Defines override if it is available for use. If not, holds an empty string.
Definition: Config.h:249
#define NLIB_ALWAYS_INLINE
Indicates that the compiler is forced to perform inline expansion of functions.
Definition: Platform_unix.h:95
uint64_t Pos64() const noexcept
Returns the current position in the stream as a 64-bit integer.
Definition: OutputStream.h:52
void SetError(errno_t e) const noexcept
Sets an error to OutputStream.
Definition: OutputStream.h:111
#define NLIB_DISALLOW_COPY_AND_ASSIGN(TypeName)
Prohibits use of the copy constructor and assignment operator for the class specified by TypeName...
Definition: Config.h:183
#define NLIB_SAFE_BOOL(class_name, exp)
Defines a safe operator bool function in the class. Uses the C++11 explicit bool if it is available f...
Definition: Config.h:199
The output is line buffered. This mode is set when data is output to the console. ...
Definition: OutputStream.h:34
size_t Pos() const noexcept
Returns the current position in the stream.
Definition: OutputStream.h:51
#define NLIB_UNLIKELY(x)
Indicates to the compiler that condition x is likely to be false.
Definition: Platform_unix.h:98
#define RSIZE_MAX
Defines a value somewhat smaller than the maximum value of size_t.
Definition: Platform.h:219
static int nlib_clz32(uint32_t x)
Returns the number of consecutive zero bits, with respect to the most significant bit (MSB)...
Definition: Platform.h:2690
#define NLIB_VIS_PUBLIC
Symbols for functions and classes are made available outside of the library.
Definition: Platform_unix.h:87
constexpr OutputStream() noexcept
Instantiates the object with default parameters (default constructor).
Definition: OutputStream.h:39
The class for OutputStream objects for which no actual writing takes place.
Definition: OutputStream.h:145
bool Write(int b) noexcept
Writes one byte of data to the stream.
Definition: OutputStream.h:53
#define NLIB_LIKELY(x)
Indicates to the compiler that condition x is likely to be true.
Definition: Platform_unix.h:97
Class that wraps errno_t. This class improves visual representations in the Visual Studio debugger...
Definition: Config.h:404
#define NLIB_NOEXCEPT
Defines noexcept geared to the environment, or the equivalent.
Definition: Config.h:109
#define NLIB_CEXPR
Defines constexpr if it is available for use. If not, holds an empty string.
Definition: Config.h:111
virtual ~OutputStream() noexcept
Destructor.
Definition: OutputStream.h:45
A file that contains the configuration information for each development environment.
void * nlib_realloc(void *ptr, size_t size)
A weak function that calls the C standard function realloc. nlib calls realloc via this function...
BufferingMode GetBufferingMode() const noexcept
Gets the buffering mode.
Definition: OutputStream.h:103
#define NLIB_FINAL
Defines final if it is available for use. If not, holds an empty string.
Definition: Config.h:250
#define NLIB_STATIC_ASSERT(exp)
Defines a static assertion. Uses static_assert if it is available for use.
Definition: Config.h:174
unsigned char nlib_byte_t
This type will be defined as std::byte in a typedef of C++17 or later.
Definition: Platform.h:314
bool Write(const void *p, size_t n) noexcept
Writes n bytes of data to the stream.
Definition: OutputStream.h:67
#define NLIB_NONNULL
Indicates that you cannot specify NULL for all arguments.
BufferingMode
The buffering mode for OutputStream.
Definition: OutputStream.h:32
The base class for output streams. This class cannot be instantiated.
Definition: OutputStream.h:30
bool WriteGather(const nlib_fd_iovec *iov, int iovcnt) noexcept
Writes data from multiple non-continuous buffers to a stream.
Definition: OutputStream.h:85
int errno_t
Indicates with an int-type typedef that a POSIX error value is returned as the return value...
Definition: NMalloc.h:37