BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslstl_syncbuf.h
Go to the documentation of this file.
1/// @file bslstl_syncbuf.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslstl_syncbuf.h -*-C++-*-
8#ifndef INCLUDED_BSLSTL_SYNCBUF
9#define INCLUDED_BSLSTL_SYNCBUF
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslstl_syncbuf bslstl_syncbuf
15/// @brief Provide a C++20-compatible `basic_syncbuf` class template.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslstl
19/// @{
20/// @addtogroup bslstl_syncbuf
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslstl_syncbuf-purpose"> Purpose</a>
25/// * <a href="#bslstl_syncbuf-classes"> Classes </a>
26/// * <a href="#bslstl_syncbuf-description"> Description </a>
27/// * <a href="#bslstl_syncbuf-usage"> Usage </a>
28/// * <a href="#bslstl_syncbuf-example-1-usage-with-existing-ostream"> Example 1: Usage with existing ostream </a>
29///
30/// # Purpose {#bslstl_syncbuf-purpose}
31/// Provide a C++20-compatible @ref basic_syncbuf class template.
32///
33/// # Classes {#bslstl_syncbuf-classes}
34///
35/// - bsl::basic_syncbuf: C++20-compatible @ref basic_syncbuf class template.
36/// - bsl::syncbuf: C++20-compatible `syncbuf` class.
37/// - bsl::wsyncbuf: C++20-compatible `wsyncbuf` class.
38///
39/// **Canonical header:** bsl_syncstream.h
40///
41/// @see bslstl_osyncstream
42///
43/// # Description {#bslstl_syncbuf-description}
44/// This component is for internal use only. Please include
45/// `<bsl_syncstream.h>` instead.
46///
47/// This component defines a class template, `bsl::basic_syncbuf`, that is a
48/// wrapper for a `bsl::basic_streambuf` (provided at construction time as a
49/// pointer). It accumulates output in its own internal buffer, and atomically
50/// transmits its entire contents to the wrapped buffer on destruction and when
51/// explicitly requested, so that they appear as a contiguous sequence of
52/// characters. It guarantees that there are no data races and no interleaving
53/// of characters sent to the wrapped buffer as long as all other outputs made
54/// to the same buffer are made through, possibly different, instances of
55/// `bsl::basic_syncbuf`.
56///
57/// Each `bsl::basic_syncbuf` has the associated "emit-on-sync" boolean flag
58/// that is `false` after the object construction and its value can be changed
59/// using the `set_emit_on_sync` member function call. If this flag has value
60/// `true`, the `emit` function is called by each `sync` call.
61///
62/// Types `bsl::syncbuf` and `bsl::wsyncbuf` are aliases for
63/// `bsl::basic_syncbuf<char>` and `bsl::basic_syncbuf<wchar_t>`, respectively.
64///
65/// ## Usage {#bslstl_syncbuf-usage}
66///
67///
68/// This section illustrates possible use of this component. But note that this
69/// component is not intended for direct usage - usually `osyncstream` should be
70/// used instead.
71///
72/// ### Example 1: Usage with existing ostream {#bslstl_syncbuf-example-1-usage-with-existing-ostream}
73///
74///
75/// The following example demonstrates temporary replacement of the underlying
76/// `streambuf` within the existing `ostream` object.
77/// @code
78/// /// Write atomically to the specified `os` output stream.
79/// void writeSync(bsl::ostream& os)
80/// {
81/// // Temporarily replace the underlying `streambuf`
82/// bsl::syncbuf buf(os.rdbuf());
83/// os.rdbuf(&buf);
84///
85/// // Write to the `syncbuf`
86/// os << "Hello, ";
87/// os << "World!\n";
88///
89/// // Restore the underlying `streambuf`
90/// os.rdbuf(buf.get_wrapped());
91///
92/// // The accumulated output will be atomically flushed/emitted here
93/// }
94/// @endcode
95/// Now call the function:
96/// @code
97/// writeSync(bsl::cout);
98/// @endcode
99/// @}
100/** @} */
101/** @} */
102
103/** @addtogroup bsl
104 * @{
105 */
106/** @addtogroup bslstl
107 * @{
108 */
109/** @addtogroup bslstl_syncbuf
110 * @{
111 */
112
113#include <bslscm_version.h>
114
115#include <bslalg_swaputil.h>
116
117#include <bslma_bslallocator.h>
119
120#include <bslmf_movableref.h>
121
122#include <bsls_assert.h>
123#include <bsls_bsllock.h>
124#include <bsls_exceptionutil.h>
125#include <bsls_keyword.h>
126#include <bsls_libraryfeatures.h>
127
128#include <bslstl_iosfwd.h>
129#include <bslstl_stringbuf.h>
130#include <bslstl_syncbufbase.h>
131
132#include <streambuf>
133#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_STREAM_MOVE
134#include <utility> // move
135#endif
136
137namespace bsl {
138
139// Internal type
140typedef BloombergLP::bsls::BslLock SyncBuf_Mutex;
141
142 // ===================
143 // class basic_syncbuf
144 // ===================
145
146/// This class implements a standard stream buffer providing an internal
147/// buffer to accumulate the written data in order to atomically transmit
148/// its entire contents to the wrapped buffer on destruction (or `emit`
149/// call).
150template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
151class basic_syncbuf : public std::basic_streambuf<CHAR_TYPE, CHAR_TRAITS>,
152 public BloombergLP::bslstl::SyncBufBase {
153
154 // PRIVATE TYPES
155 typedef BloombergLP::bslmf::MovableRefUtil MoveUtil;
156
157 // PRIVATE MANIPULATORS
158
159 /// This function is a private alias for `emit`. Note that this virtual
160 /// function implementation is private because the base class is
161 /// deliberately not a template (see @ref bslstl_syncbufbase ) and we don't
162 /// want to expose this method directly to users.
163 bool emitInternal() BSLS_KEYWORD_OVERRIDE;
164
165 /// This function is a private alias for `set_emit_on_sync`. Note that
166 /// this virtual function implementation is private because the base
167 /// class is deliberately not a template (see @ref bslstl_syncbufbase ) and
168 /// we don't want to expose this method directly to users.
169 void setEmitOnSync(bool value) BSLS_KEYWORD_NOEXCEPT BSLS_KEYWORD_OVERRIDE;
170
171 public:
172 // TYPES
173 typedef CHAR_TYPE char_type;
174 typedef typename CHAR_TRAITS::int_type int_type;
175 typedef typename CHAR_TRAITS::pos_type pos_type;
176 typedef typename CHAR_TRAITS::off_type off_type;
177 typedef CHAR_TRAITS traits_type;
178 typedef ALLOCATOR allocator_type;
179
180 typedef std::basic_streambuf<CHAR_TYPE, CHAR_TRAITS> streambuf_type;
181
182 private:
183 // DATA
184
185 // wrapped buffer
186 streambuf_type *d_wrapped_p;
187
188 // mutex for `emit`
189 SyncBuf_Mutex *d_mutex_p;
190
191 // "emit-on-sync" flag
192 bool d_emit_on_sync;
193
194 // sync call was requested
195 bool d_needs_sync;
196
197 // internal buffer
199
200 public:
201 // CREATORS
202
203 /// Create a @ref basic_syncbuf object without a wrapped buffer.
204 /// Optionally specify an `allocator` used to supply memory.
205 explicit basic_syncbuf(const ALLOCATOR& allocator = ALLOCATOR());
206
207 /// Create a @ref basic_syncbuf object. Set the specified `wrapped` as a
208 /// wrapped buffer. Optionally specify an `allocator` used to supply
209 /// memory.
210 explicit basic_syncbuf(streambuf_type *wrapped,
211 const ALLOCATOR& allocator = ALLOCATOR());
212
213 /// Call `emit`. Any exceptions thrown by `emit` are ignored.
215
216#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_STREAM_MOVE
217 basic_syncbuf(basic_syncbuf&& original);
218 /// Create a @ref basic_syncbuf object having the same value as the
219 /// specified `original` object by moving the contents of `original` to
220 /// the newly-created object. Optionally specify an `allocator` used
221 /// to supply memory. `original.get_wrapped() == nullptr` after the
222 /// call.
223 basic_syncbuf(basic_syncbuf&& original, const ALLOCATOR& allocator);
224#endif
225
226 // MANIPULATORS
227
228 /// Atomically transfer any characters buffered by this object to the
229 /// wrapped stream buffer, so that it appears in the output stream as a
230 /// contiguous sequence of characters. The wrapped stream buffer is
231 /// flushed if and only if a call was made to `sync` since the most
232 /// recent call to `emit` or construction. Return `true` if
233 /// `get_wrapped() != nullptr`, and all of the characters in the
234 /// associated output were successfully transferred, and the flush (if
235 /// any) succeeded; return `false` otherwise.
236 bool emit();
237
238 /// Call the `emit` function by each `sync` call if the specified
239 /// `value` is `true`.
241
242#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_STREAM_MOVE
243 /// Call `emit()` then assign to this object the value of the specified
244 /// `original`, and return a reference providing modifiable access to
245 /// this object. The contents of `original` are move-assigned to this
246 /// object. `original.get_wrapped() == nullptr` after the call.
247 basic_syncbuf& operator=(basic_syncbuf&& original);
248
249 /// Efficiently exchange the value of this object with the value of the
250 /// specified `other` object. The behavior is undefined unless either
251 /// `*this` and `other` allocators compare equal or
252 /// `propagate_on_container_swap` is `true`.
253 void swap(basic_syncbuf& other);
254#endif
255
256 // ACCESSORS
257
258 /// Return the allocator used to supply memory.
260
261 /// Return the wrapped buffer supplied at construction.
263
264 protected:
265 // PROTECTED MANIPULATORS
266
267 // Do nothing if `traits_type::eof()` is passed. Optionally specify
268 // `character` that has non-default value to add it to the internal
269 // buffer and return `traits_type::to_int_type(character)`. Return
270 // `traits_type::eof()` otherwise.
271 int_type overflow(int_type character = traits_type::eof())
273
274 /// Request the wrapped streambuf flush on the next `emit` call, then
275 /// call `emit` if the "emit-on-sync" flag is `true`. Return 0 on
276 /// success and -1 if the `emit` call has failed.
278
279 /// Write the specified `inputString` array of the specified `count`
280 /// characters to the internal buffer. Return the number of characters
281 /// successfully written.
282 std::streamsize xsputn(const char_type *inputString, std::streamsize count)
284};
285
286// STANDARD TYPEDEFS
287typedef basic_syncbuf<char> syncbuf;
288typedef basic_syncbuf<wchar_t> wsyncbuf;
289
290 // =======================
291 // class SyncBuf_MutexUtil
292 // =======================
293
294/// Internal mutex-related utils.
296
297 // CLASS METHODS
298
299 /// Return address of a mutex associated the specified `streambuf`
300 /// object (address). The behavior is undefined unless `streambuf` is
301 /// not null and points to `basic_streambuf<...>` object.
302 static SyncBuf_Mutex *get(void *streambuf) BSLS_KEYWORD_NOEXCEPT;
303};
304
305 // -------------------
306 // class basic_syncbuf
307 // -------------------
308
309// CREATORS
310template <class CHAR, class TRAITS, class ALLOCATOR>
312: d_wrapped_p(0)
313, d_mutex_p(0)
314, d_emit_on_sync(false)
315, d_needs_sync(false)
316, d_buff(allocator)
317{
318}
319
320template <class CHAR, class TRAITS, class ALLOCATOR>
322 streambuf_type *wrapped,
323 const ALLOCATOR& allocator)
324: d_wrapped_p(wrapped)
325, d_mutex_p(wrapped ? SyncBuf_MutexUtil::get(wrapped) : 0)
326, d_emit_on_sync(false)
327, d_needs_sync(false)
328, d_buff(allocator)
329{
330}
331
332template <class CHAR, class TRAITS, class ALLOCATOR>
334{
335 BSLS_TRY {
336 emit();
337 }
338 BSLS_CATCH(...) {
339 // ignore
340 }
341}
342
343#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_STREAM_MOVE
344template <class CHAR, class TRAITS, class ALLOCATOR>
346: d_wrapped_p(original.d_wrapped_p)
347, d_mutex_p(original.d_mutex_p)
348, d_emit_on_sync(original.d_emit_on_sync)
349, d_needs_sync(original.d_needs_sync)
350, d_buff(std::move(original.d_buff))
351{
352 original.d_wrapped_p = 0;
353 original.d_mutex_p = 0;
354}
355
356template <class CHAR, class TRAITS, class ALLOCATOR>
358 const ALLOCATOR& allocator)
359: d_wrapped_p(original.d_wrapped_p)
360, d_mutex_p(original.d_mutex_p)
361, d_emit_on_sync(original.d_emit_on_sync)
362, d_needs_sync(original.d_needs_sync)
363, d_buff(std::move(original.d_buff), allocator)
364{
365 original.d_wrapped_p = 0;
366 original.d_mutex_p = 0;
367}
368#endif
369
370// MANIPULATORS
371template <class CHAR, class TRAITS, class ALLOCATOR>
373{
374 if (!this->d_wrapped_p) {
375 return false; // RETURN
376 }
377
379 typedef typename string::size_type SizeType;
380
381 BloombergLP::bsls::BslLockGuard lock(this->d_mutex_p);
382 String s =
383#ifdef BSLS_COMPILERFEATURES_SUPPORT_REF_QUALIFIERS
384 std::move(d_buff).str();
385#else
386 d_buff.str();
387 d_buff.str(String());
388#endif
389 if (SizeType size = s.length()) {
390 SizeType n = this->d_wrapped_p->sputn(s.data(), size);
391 if (n != size) {
392 s.erase(0, n);
393 d_buff.str(MoveUtil::move(s));
394 return false; // RETURN
395 }
396 }
397 if (this->d_needs_sync) {
398 this->d_needs_sync = false;
399 if (this->d_wrapped_p->pubsync() != 0) {
400 return false; // RETURN
401 }
402 }
403 return true;
404}
405
406template <class CHAR, class TRAITS, class ALLOCATOR>
408{
409 return emit();
410}
411
412template <class CHAR, class TRAITS, class ALLOCATOR>
413inline
416{
417 d_emit_on_sync = value;
418}
419
420template <class CHAR, class TRAITS, class ALLOCATOR>
423{
424 set_emit_on_sync(value);
425}
426
427#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_STREAM_MOVE
428template <class CHAR, class TRAITS, class ALLOCATOR>
429basic_syncbuf<CHAR,TRAITS,ALLOCATOR>&
430basic_syncbuf<CHAR,TRAITS,ALLOCATOR>::operator=(basic_syncbuf&& original)
431{
432 emit();
433 if (&original != this) {
434 d_buff = std::move(original.d_buff);
435 this->d_wrapped_p = original.d_wrapped_p;
436 this->d_mutex_p = original.d_mutex_p;
437 this->d_emit_on_sync = original.d_emit_on_sync;
438 this->d_needs_sync = original.d_needs_sync;
439
440 original.d_wrapped_p = 0;
441 original.d_mutex_p = 0;
442 }
443 return *this;
444}
445
446template <class CHAR, class TRAITS, class ALLOCATOR>
447void basic_syncbuf<CHAR,TRAITS,ALLOCATOR>::swap(basic_syncbuf& other)
448{
449 BSLS_ASSERT(allocator_traits<ALLOCATOR>::propagate_on_container_swap::value
450 || get_allocator() == other.get_allocator());
451 typedef BloombergLP::bslalg::SwapUtil SwapUtil;
452 streambuf_type::swap(other);
453 SwapUtil::swap(&d_wrapped_p, &other.d_wrapped_p);
454 SwapUtil::swap(&d_mutex_p, &other.d_mutex_p);
455 SwapUtil::swap(&d_emit_on_sync, &other.d_emit_on_sync);
456 SwapUtil::swap(&d_needs_sync, &other.d_needs_sync);
457 d_buff.swap(other.d_buff);
458}
459#endif
460
461// ACCESSORS
462template <class CHAR, class TRAITS, class ALLOCATOR>
463inline
469
470template <class CHAR, class TRAITS, class ALLOCATOR>
471inline
477
478// PROTECTED MANIPULATORS
479template <class CHAR, class TRAITS, class ALLOCATOR>
482{
483 if (!traits_type::eq_int_type(character, traits_type::eof())) {
484 return d_buff.sputc(traits_type::to_char_type(character)); // RETURN
485 }
486 return traits_type::eof();
487}
488
489template <class CHAR, class TRAITS, class ALLOCATOR>
491{
492 this->d_needs_sync = true;
493 if (this->d_emit_on_sync && !emit()) {
494 return -1; // RETURN
495 }
496 return 0;
497}
498
499template <class CHAR, class TRAITS, class ALLOCATOR>
501 const char_type *inputString,
502 std::streamsize count)
503{
504 return d_buff.sputn(inputString, count);
505}
506
507// FREE FUNCTIONS
508#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_STREAM_MOVE
509/// Swap the specified `a` with the specified `b` using `a.swap(b)`
510/// expression.
511template <class CHAR, class TRAITS, class ALLOCATOR>
512inline
515{
516 a.swap(b);
517}
518#endif
519
520} // close namespace bsl
521
522
523// ============================================================================
524// TYPE TRAITS
525// ============================================================================
526
527
528namespace bslma {
529
530template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
531struct UsesBslmaAllocator<bsl::basic_syncbuf<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR> >
533{};
534
535} // close namespace bslma
536
537
538#endif
539
540// ----------------------------------------------------------------------------
541// Copyright 2023 Bloomberg Finance L.P.
542//
543// Licensed under the Apache License, Version 2.0 (the "License");
544// you may not use this file except in compliance with the License.
545// You may obtain a copy of the License at
546//
547// http://www.apache.org/licenses/LICENSE-2.0
548//
549// Unless required by applicable law or agreed to in writing, software
550// distributed under the License is distributed on an "AS IS" BASIS,
551// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
552// See the License for the specific language governing permissions and
553// limitations under the License.
554// ----------------------------- END-OF-FILE ----------------------------------
555
556/** @} */
557/** @} */
558/** @} */
Definition bslma_bslallocator.h:580
Definition bslstl_string.h:1281
AllocatorTraits::size_type size_type
Definition bslstl_string.h:1303
Definition bslstl_stringbuf.h:245
void swap(basic_stringbuf &other)
Definition bslstl_stringbuf.h:1586
void str(const StringType &value)
Definition bslstl_stringbuf.h:1538
allocator_type get_allocator() const BSLS_KEYWORD_NOEXCEPT
Return the allocator used by the underlying string to supply memory.
Definition bslstl_stringbuf.h:1629
Definition bslstl_syncbuf.h:152
CHAR_TYPE char_type
Definition bslstl_syncbuf.h:173
std::streamsize xsputn(const char_type *inputString, std::streamsize count) BSLS_KEYWORD_OVERRIDE
Definition bslstl_syncbuf.h:500
void set_emit_on_sync(bool value) BSLS_KEYWORD_NOEXCEPT
Definition bslstl_syncbuf.h:414
ALLOCATOR allocator_type
Definition bslstl_syncbuf.h:178
~basic_syncbuf() BSLS_KEYWORD_OVERRIDE
Call emit. Any exceptions thrown by emit are ignored.
Definition bslstl_syncbuf.h:333
CHAR_TRAITS traits_type
Definition bslstl_syncbuf.h:177
int_type overflow(int_type character=traits_type::eof()) BSLS_KEYWORD_OVERRIDE
Definition bslstl_syncbuf.h:481
int sync() BSLS_KEYWORD_OVERRIDE
Definition bslstl_syncbuf.h:490
CHAR_TRAITS::int_type int_type
Definition bslstl_syncbuf.h:174
std::basic_streambuf< CHAR_TYPE, CHAR_TRAITS > streambuf_type
Definition bslstl_syncbuf.h:180
bool emit()
Definition bslstl_syncbuf.h:372
basic_syncbuf(const ALLOCATOR &allocator=ALLOCATOR())
Definition bslstl_syncbuf.h:311
allocator_type get_allocator() const BSLS_KEYWORD_NOEXCEPT
Return the allocator used to supply memory.
Definition bslstl_syncbuf.h:464
CHAR_TRAITS::pos_type pos_type
Definition bslstl_syncbuf.h:175
streambuf_type * get_wrapped() const BSLS_KEYWORD_NOEXCEPT
Return the wrapped buffer supplied at construction.
Definition bslstl_syncbuf.h:473
CHAR_TRAITS::off_type off_type
Definition bslstl_syncbuf.h:176
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
#define BSLS_CATCH(X)
Definition bsls_exceptionutil.h:372
#define BSLS_TRY
Definition bsls_exceptionutil.h:370
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_KEYWORD_NOEXCEPT
Definition bsls_keyword.h:632
#define BSLS_KEYWORD_OVERRIDE
Definition bsls_keyword.h:653
Definition bdlb_printmethods.h:283
BSLS_KEYWORD_CONSTEXPR_CPP14 TYPE & get(array< TYPE, SIZE > &a) BSLS_KEYWORD_NOEXCEPT
BSLS_KEYWORD_CONSTEXPR size_t size(const TYPE(&)[DIMENSION]) BSLS_KEYWORD_NOEXCEPT
Return the dimension of the specified array argument.
Definition bslstl_iterator.h:1331
BloombergLP::bsls::BslLock SyncBuf_Mutex
Definition bslstl_syncbuf.h:140
Definition balxml_encoderoptions.h:68
Definition bdldfp_decimal.h:5188
Internal mutex-related utils.
Definition bslstl_syncbuf.h:295
static SyncBuf_Mutex * get(void *streambuf) BSLS_KEYWORD_NOEXCEPT
Definition bslma_usesbslmaallocator.h:343