Toolbox snapshot
The Reactive C++ Toolbox
Loading...
Searching...
No Matches
Stream.hpp
Go to the documentation of this file.
1// The Reactive C++ Toolbox.
2// Copyright (C) 2013-2019 Swirly Cloud Limited
3// Copyright (C) 2022 Reactive Markets Limited
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17#ifndef TOOLBOX_UTIL_STREAM_HPP
18#define TOOLBOX_UTIL_STREAM_HPP
19
23
24namespace toolbox {
25inline namespace util {
26
27namespace detail {
28struct ResetState {};
29TOOLBOX_API std::ostream& operator<<(std::ostream& os, ResetState) noexcept;
30} // namespace detail
31
34constexpr detail::ResetState reset_state{};
35
37template <std::size_t MaxN>
38class OStream final : public OStreamBase<OStream<MaxN>> {
39 public:
41 explicit OStream(std::nullptr_t) noexcept
42 : storage_(nullptr)
43 {
44 }
45
48 : storage_(std::move(storage))
49 {
50 }
51
54 : storage_(make_storage())
55 {
56 }
57 ~OStream() = default;
58
59 // Copy.
60 OStream(const OStream&) = delete;
61 OStream& operator=(const OStream&) = delete;
62
63 // Move.
64 OStream(OStream&&) = delete;
66
68 const char* data() const noexcept { return storage_.get(); }
69 bool empty() const noexcept { return bytes_written_ == 0u; }
70 std::size_t size() const noexcept { return bytes_written_; }
71 std::string_view str() const noexcept { return std::string_view{data(), size()}; }
72
73 // returns false if overflowed or output error.
74 // return true otherwise.
75 explicit operator bool() const noexcept { return !badbit_; }
76
79 {
81 storage_.swap(storage);
82 reset();
83 return storage;
84 }
85
88 {
89 storage_ = std::move(storage);
90 reset();
91 }
92
95 {
96 bytes_written_ = 0u;
97 badbit_ = false;
98 }
99
100 private:
102
103 std::size_t available() noexcept
104 {
105 if (storage_ != nullptr) [[likely]] {
106 return MaxN - bytes_written_;
107 } else {
108 return 0u;
109 }
110 }
111
112 char* wptr() noexcept
113 {
114 assert(storage_ != nullptr);
115 void* buf_base = storage_.get();
116 return static_cast<char*>(buf_base) + bytes_written_;
117 }
118
119 // Required by CRTP base (BasicOStream)
120 char* do_prepare_space(std::size_t num_bytes)
121 {
122 if (num_bytes <= available()) [[likely]] {
123 return wptr();
124 } else {
125 return nullptr;
126 }
127 }
128
129 // Required by CRTP base (BasicOStream)
130 void do_relinquish_space(std::size_t consumed_num_bytes)
131 {
132 bytes_written_ += consumed_num_bytes;
133 assert(bytes_written_ <= MaxN);
134 }
135
136 // Required by CRTP base (BasicOStream)
137 void do_set_badbit() { badbit_ = true; }
138
139 StoragePtr<MaxN> storage_;
140 std::size_t bytes_written_{0u};
141 bool badbit_{false};
142};
143
144template <std::size_t MaxN>
145class OStaticStream final : public OStreamBase<OStaticStream<MaxN>> {
146 public:
147 OStaticStream() = default;
148 ~OStaticStream() = default;
149
150 // Copy.
151 OStaticStream(const OStaticStream&) = delete;
153
154 // Move.
157
158 const char* data() const noexcept { return buf_; }
159 bool empty() const noexcept { return bytes_written_ == 0u; }
160 std::size_t size() const noexcept { return std::min(bytes_written_, MaxN); }
161 std::string_view str() const noexcept { return std::string_view{buf_, size()}; }
162
163 // returns false if overflowed or output error.
164 // return true otherwise.
165 explicit operator bool() const { return !badbit_; }
166
169 {
170 bytes_written_ = 0;
171 badbit_ = false;
172 };
173
174 private:
176
177 std::size_t available() noexcept { return BufSize - bytes_written_; }
178
179 char* wptr() noexcept { return buf_ + bytes_written_; }
180
181 // Required by CRTP base (BasicOStream)
182 char* do_prepare_space(std::size_t num_bytes)
183 {
184 if (num_bytes <= available()) [[likely]] {
185 return wptr();
186 } else {
187 return nullptr;
188 }
189 }
190
191 // Required by CRTP base (BasicOStream)
192 void do_relinquish_space(std::size_t consumed_num_bytes)
193 {
194 std::size_t new_written_count = bytes_written_ + consumed_num_bytes;
195 if (new_written_count > MaxN) [[unlikely]] {
196 badbit_ = true;
197 } else {
198 bytes_written_ = new_written_count;
199 }
200 }
201
202 // Required by CRTP base (BasicOStream)
203 void do_set_badbit() { badbit_ = true; }
204
205 // size the buffer slightly bigger than requested as it allows
206 // for higher performance outputting in OStreamBase. However, this
207 // is an internal detail, not visible to user via API.
208 static constexpr std::size_t BufSize
210
211 char buf_[BufSize];
212 std::size_t bytes_written_{0u};
213 bool badbit_{false};
214};
215
216// Similar to std::ostream_iterator, but this works with any "Streamable" type.
217template <class StreamT>
218 requires Streamable<StreamT>
220 public:
221 OStreamIterator() = delete;
222
223 explicit OStreamIterator(StreamT& os, const char* delim = nullptr) noexcept
224 : os_(&os)
225 , delim_(delim)
226 {
227 }
228
229 template <class T>
230 OStreamIterator& operator=(const T& value)
231 {
232 *os_ << value;
233 if (delim_) [[unlikely]] {
234 *os_ << delim_;
235 }
236 return *this;
237 }
238
239 OStreamIterator& operator*() noexcept { return *this; }
241 OStreamIterator& operator++(int) noexcept { return *this; }
242
243 // required by std::output_iterator concept
245
246 private:
247 // Pointer (instead of reference) because this class needs to be assignable
248 // to satisfy std::output_iterator concept (references can't be assigned).
249 StreamT* os_;
250 const char* delim_{nullptr};
251};
252
253// similar to std::experimental::ostream_joiner, but this works with any "Streamable" type.
254template <class StreamT, class DelimT>
255 requires Streamable<StreamT>
257 public:
258 OStreamJoiner() = delete;
259 ~OStreamJoiner() = default;
260
262 : os_(os)
263 {
264 }
265
266 explicit OStreamJoiner(StreamT& os,
267 DelimT delim) noexcept(std::is_nothrow_move_constructible_v<DelimT>)
268 : os_(&os)
269 , delim_(std::move(delim))
270 {
271 }
272
273 template <class T>
274 OStreamJoiner& operator=(const T& value)
275 {
276 if (!first_) {
277 *os_ << delim_;
278 }
279 *os_ << value;
280 first_ = false;
281 return *this;
282 }
283
284 OStreamJoiner& operator*() noexcept { return *this; }
285 OStreamJoiner& operator++() noexcept { return *this; }
286 OStreamJoiner& operator++(int) noexcept { return *this; }
287
288 // required by std::output_iterator concept
290
291 private:
292 // Pointer (instead of reference) because this class needs to be assignable
293 // to satisfy std::output_iterator concept (references can't be assigned).
294 StreamT* os_;
295 DelimT delim_;
296 bool first_{true};
297};
298
299static_assert(std::output_iterator<OStreamIterator<OStream<4096>>, const char&>, "");
300static_assert(std::output_iterator<OStreamJoiner<OStream<4096>, int>, const char&>, "");
301
302} // namespace util
303} // namespace toolbox
304
305#endif // TOOLBOX_UTIL_STREAM_HPP
#define TOOLBOX_API
Definition Config.h:39
OStaticStream & operator=(OStaticStream &&)=delete
OStaticStream(OStaticStream &&)=delete
const char * data() const noexcept
Definition Stream.hpp:158
OStaticStream & operator=(const OStaticStream &)=delete
bool empty() const noexcept
Definition Stream.hpp:159
std::size_t size() const noexcept
Definition Stream.hpp:160
void reset() noexcept
Reset the current position back to the beginning of the buffer.
Definition Stream.hpp:168
std::string_view str() const noexcept
Definition Stream.hpp:161
OStaticStream(const OStaticStream &)=delete
OStreamIterator(StreamT &os, const char *delim=nullptr) noexcept
Definition Stream.hpp:223
OStreamIterator & operator*() noexcept
Definition Stream.hpp:239
OStreamIterator & operator=(const T &value)
Definition Stream.hpp:230
OStreamIterator & operator++(int) noexcept
Definition Stream.hpp:241
OStreamIterator & operator++() noexcept
Definition Stream.hpp:240
OStreamJoiner & operator=(const T &value)
Definition Stream.hpp:274
OStreamJoiner & operator++() noexcept
Definition Stream.hpp:285
OStreamJoiner(StreamT &os) noexcept
Definition Stream.hpp:261
OStreamJoiner(StreamT &os, DelimT delim) noexcept(std::is_nothrow_move_constructible_v< DelimT >)
Definition Stream.hpp:266
OStreamJoiner & operator++(int) noexcept
Definition Stream.hpp:286
OStreamJoiner & operator*() noexcept
Definition Stream.hpp:284
OStream uses a dynamic storage acquired from the custom allocator.
Definition Stream.hpp:38
OStream(std::nullptr_t) noexcept
Constructor for initialising the StreamBuf with a null buffer.
Definition Stream.hpp:41
static StoragePtr< MaxN > make_storage()
Definition Stream.hpp:67
void reset() noexcept
Reset the current position back to the beginning of the buffer.
Definition Stream.hpp:94
StoragePtr< MaxN > release_storage() noexcept
Release the managed storage.
Definition Stream.hpp:78
OStream(OStream &&)=delete
OStream & operator=(OStream &&)=delete
std::string_view str() const noexcept
Definition Stream.hpp:71
OStream(StoragePtr< MaxN > storage) noexcept
Constructor for initialising the StreamBuf with pre-allocated storage.
Definition Stream.hpp:47
std::size_t size() const noexcept
Definition Stream.hpp:70
void set_storage(StoragePtr< MaxN > storage) noexcept
Update the internal storage and clear i/o state.
Definition Stream.hpp:87
OStream()
Default constructor allocates required storage.
Definition Stream.hpp:53
bool empty() const noexcept
Definition Stream.hpp:69
OStream & operator=(const OStream &)=delete
const char * data() const noexcept
Definition Stream.hpp:68
OStream(const OStream &)=delete
STL namespace.
StreamT & operator<<(StreamT &os, PutPercentiles pp)
Definition Utility.hpp:68
constexpr detail::ResetState reset_state
Definition Stream.hpp:34
std::unique_ptr< char[], detail::StorageDeleter< SizeN > > StoragePtr
Pointer to an uninitialised char array of SizeN, freed with delete[].
Definition Storage.hpp:33
constexpr auto bind() noexcept
Definition Slot.hpp:97