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