// bslstl_stringbuf.h -*-C++-*- #ifndef INCLUDED_BSLSTL_STRINGBUF #define INCLUDED_BSLSTL_STRINGBUF #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a C++03-compatible 'stringbuf' class. // //@CLASSES: // bsl::stringbuf: C++03-compatible 'stringbuf' class // bsl::StringBufContainer: wrapper for 'basic_stringbuf' // //@CANONICAL_HEADER: bsl_sstream.h // //@SEE_ALSO: bslstl_stringstream, bslstl_ostringstream, bslstl_istringstream // //@DESCRIPTION: This component is for internal use only. Please include // '<bsl_sstream.h>' instead. // // This component defines a class template, 'bsl::basic_stringbuf', that // implements a standard string buffer, providing an unformatted character // input sequence and an unformatted character output sequence that // may be initialized or accessed using a string value (see 27.8.2 [stringbuf] // of the C++11 standard). This component also defines two standard aliases, // 'bsl::stringbuf' and 'bsl::wstringbuf', that refer to specializations of the // 'bsl::basic_stringbuf' template for 'char' and 'wchar_t' types, // respectively. As with any stream buffer class, 'bsl::basic_stringbuf' is // rarely used directly. Stream buffers provide low-level unformatted // input/output. They are usually plugged into 'std::basic_stream' classes to // provide higher-level formatted input and output via 'operator>>' and // 'operator<<'. 'bsl::basic_stringbuf' is used in the // 'bsl::basic_stringstream' family of classes and users should prefer those // classes over direct use of 'bsl::basic_stringbuf'. // // 'bsl::basic_stringbuf' derives from 'std::basic_streambuf' and implements // the necessary protected virtual methods. In this way 'bsl::basic_stringbuf' // customizes the behavior of 'std::basic_streambuf' to redirect the reading // and writing of characters to an internally-maintained sequence of characters // that can be initialized or accessed using a 'bsl::basic_string'. Note that // although the standard mandates functions that access and modify the // buffered sequence using a 'basic_string', it does not mandate that a // 'basic_stringbuf' internally store this buffer in a 'basic_string'; this // implementation currently uses a 'basic_string' as its internal buffer, but // that is subject to change without warning. // // The 'bsl::stringbuf' template has three parameters, 'CHAR_TYPE', // 'CHAR_TRAITS', and 'ALLOCATOR'. The 'CHAR_TYPE' and 'CHAR_TRAITS' // parameters respectively define the character type for the stream buffer and // a type providing a set of operations the stream buffer will use to // manipulate characters of that type, which must meet the character traits // requirements defined by the C++11 standard, 21.2 [char.traits]. The // 'ALLOCATOR' template parameter is described in the "Memory Allocation" // section below. // ///Memory Allocation ///----------------- // The type supplied as a stream buffer's 'ALLOCATOR' template parameter // determines how that stream buffer will allocate memory. The // 'basic_stringbuf' template supports allocators meeting the requirements // of the C++11 standard, 17.6.3.5 [allocator.requirements]; in addition, it // supports scoped-allocators derived from the 'bslma::Allocator' memory // allocation protocol. Clients intending to use 'bslma'-style allocators // should use 'bsl::allocator', which provides a C++11 standard-compatible // adapter for a 'bslma::Allocator' object. Note that the standard aliases // 'bsl::stringbuf' and 'bsl::wstringbuf' both use 'bsl::allocator'. // ///'bslma'-Style Allocators /// - - - - - - - - - - - - // If the type supplied for the 'ALLOCATOR' template parameter of a 'stringbuf' // instantiation is 'bsl::allocator', then objects of that stream buffer type // will conform to the standard behavior of a 'bslma'-allocator-enabled type. // Such a stream buffer accepts an optional 'bslma::Allocator' argument at // construction. If the address of a 'bslma::Allocator' object is explicitly // supplied at construction, it will be used to supply memory for the stream // buffer throughout its lifetime; otherwise, the stream buffer will use the // default allocator installed at the time of the stream buffer's construction // (see 'bslma_default'). // ///Usage ///----- // This section illustrates intended use of this component. // ///Example 1: Basic Operations ///- - - - - - - - - - - - - - // The following example demonstrates the use of 'bsl::stringbuf' to read and // write character data from and to a 'bsl::string' object. // // Suppose we want to implement a simplified converter from 'unsigned int' to // 'bsl::string' and back. First, we define the prototypes of two conversion // functions: //.. // bsl::string toString(unsigned int from); // unsigned int fromString(const bsl::string& from); //.. // Then, we use 'bsl::stringbuf' to implement the 'toString' function. We // write all digits into 'bsl::stringbuf' individually using 'sputc' methods // and then return the resulting 'bsl::string' object: //.. // #include <algorithm> // // bsl::string toString(unsigned int from) // { // bsl::stringbuf out; // // for (; from != 0; from /= 10) { // out.sputc('0' + from % 10); // } // // bsl::string result(out.str()); // std::reverse(result.begin(), result.end()); // return result; // } //.. // Now, we implement the 'fromString' function that converts from // 'bsl::string' to 'unsigned int' by using 'bsl::stringbuf' to read individual // digits from the string object: //.. // unsigned int fromString(const bsl::string& from) // { // unsigned int result = 0; // // for (bsl::stringbuf in(from); in.in_avail(); ) { // result = result * 10 + (in.sbumpc() - '0'); // } // // return result; // } //.. // Finally, we verify that the result of the round-trip conversion is identical // to the original value: //.. // unsigned int orig = 92872498; // unsigned int result = fromString(toString(orig)); // // assert(orig == result); //.. #include <bslscm_version.h> #include <bslstl_iosfwd.h> #include <bslstl_string.h> #include <bslstl_stringview.h> #include <bslalg_swaputil.h> #include <bslma_isstdallocator.h> #include <bslma_stdallocator.h> #include <bslma_usesbslmaallocator.h> #include <bslmf_enableif.h> #include <bslmf_issame.h> #include <bslmf_movableref.h> #include <bsls_assert.h> #include <bsls_compilerfeatures.h> #include <bsls_keyword.h> #include <bsls_libraryfeatures.h> #include <bsls_platform.h> #include <algorithm> #include <cstddef> #include <ios> #include <istream> #include <ostream> #include <streambuf> #ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_STREAM_MOVE # include <utility> #endif #include <limits.h> // for 'INT_MAX', 'INT_MIN' #ifndef BDE_OMIT_INTERNAL_DEPRECATED #ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES #include <bslalg_typetraits.h> #endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES #endif // BDE_OMIT_INTERNAL_DEPRECATED namespace BloombergLP { // 'BSLS_ASSERT' filename fix -- See {'bsls_assertimputil'} #ifdef BSLS_ASSERTIMPUTIL_AVOID_STRING_CONSTANTS extern const char s_bslstl_stringbuf_h[]; #undef BSLS_ASSERTIMPUTIL_FILE #define BSLS_ASSERTIMPUTIL_FILE BloombergLP::s_bslstl_stringbuf_h #endif } namespace bsl { using std::ios_base; // ===================== // class basic_stringbuf // ===================== template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> class basic_stringbuf : public std::basic_streambuf<CHAR_TYPE, CHAR_TRAITS> { // This class implements a standard stream buffer providing an unformatted // character input sequence and an unformatted character output sequence // that may be initialized or accessed using a string value. private: // PRIVATE TYPES typedef std::basic_streambuf<CHAR_TYPE, CHAR_TRAITS> BaseType; typedef bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> StringType; typedef bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS> ViewType; typedef BloombergLP::bslmf::MovableRefUtil MoveUtil; public: // TYPES typedef CHAR_TYPE char_type; typedef CHAR_TRAITS traits_type; typedef ALLOCATOR allocator_type; typedef typename traits_type::int_type int_type; typedef typename traits_type::off_type off_type; typedef typename traits_type::pos_type pos_type; private: // DATA StringType d_str; // internal character sequence buffer off_type d_endHint; // offset to one past the last known good // character in 'd_str' (Note that to enable // efficient buffering, 'd_str' may be resized // beyond the last written character, so // 'd_str.size()' may not accurately report // the current length of the character // sequence available for input. Extending // the size of 'd_str' and updating 'epptr' // (the end-of-output pointer) allows the // parent stream type to write additional // characters without 'overflow'. However, // care must be taken to refresh the cached // 'd_endHint' value as the parent stream will // update the current output position 'pptr', // without calling a method on this type.) ios_base::openmode d_mode; // 'stringbuf' open mode ('in', 'out', or both) private: // NOT IMPLEMENTED basic_stringbuf(const basic_stringbuf&); // = delete basic_stringbuf& operator=(const basic_stringbuf&); // = delete private: // PRIVATE MANIPULATORS pos_type updateInputPointers(char_type *currentInputPosition); // Update the input pointers ('eback', 'gptr', 'egptr') of this string // buffer, setting the beginning of the input sequence, 'eback', to the // address of the first character of the internal string // representation, 'd_str', the current position of the input sequence, // 'gptr', to the specified 'currentInputPosition', and the address // past the end of the accessible sequence, 'egptr', to the last // character in 'd_ptr' ('&d_ptr[0] + d_endHint'). Return the offset // of the current position of the input sequence from the start of the // sequence. The behavior is undefined unless this buffer is in input // mode and 'currentInputPosition' is within the range of accessible // characters in 'd_ptr'. pos_type updateOutputPointers(char_type *currentOutputPosition); // Update the output pointers ('pback', 'pptr', 'epptr') of this string // buffer, setting the beginning of the output sequence, 'pback', to // the address of the first character of the internal string // representation, 'd_str', the current position of the output // sequence, 'pptr', to the specified 'currentOutputPosition', and the // address past the end of the accessible sequence, 'epptr', to one // past the last character in 'd_ptr' ('&d_ptr[0] + d_ptr.size()'). // Return the offset of the current position of the output sequence // from the start of the sequence. The behavior is undefined unless // this buffer is in output mode, and 'currentOutputPosition' is within // the range of accessible characters in 'd_ptr'. void updateStreamPositions(off_type inputOffset = 0, off_type outputOffset = 0); // Update the input and output positions of this string buffer object // according to the current state of the internal string representation // 'd_ptr'. Optionally specify an 'inputOffset' indicating the current // input position's offset from the beginning of the sequence. // Optionally specify an 'outputOffset' indicating the current output // position's offset from the beginning of the sequence. If this // buffer is in output mode, set the beginning of the output sequence, // 'pback', to the address of the first character of 'd_ptr', the // current output position, 'pptr', to 'pback + outputOffset', and the // end of the output sequence, 'epptr', to one past the last character // in 'd_str' ('&d_ptr[0] + d_ptr.size()'). If this buffer is in input // mode, set the beginning of the input sequence, 'eback', to the // address of the first character of 'd_ptr', the current input // position, 'gptr', to 'eback + inputOffset', and the end of the input // sequence, 'egptr', to the last written character in 'd_str' // ('&d_ptr[0] + d_endHint'). bool extendInputArea(); // Attempt to expand the sequence of characters available for input // (i.e., update the end of input buffer position, 'egptr') to // incorporate additional characters that may have been written (as // output) to the stream. Return 'true' if the input buffer was // successfully extended, and 'false' otherwise. Note that the input // area as described by 'eback', 'gptr', and 'egptr' may become out of // sync with the characters actually available in the buffer as the // parent 'basic_streambuf' type may perform writes into the output // area (using 'pbase', 'pptr', and 'epptr') without calling any // methods of this object. // PRIVATE ACCESSORS pos_type streamSize() const; // Return the number of characters currently in the buffer. Note this // may not be 'd_str.size()', as this implementation resizes 'd_str' // beyond the number of written characters to provide more efficient // buffering, and it also may not be 'd_endHint', as that value may // currently be stale (as writes may have been performed through the // parent 'basic_streambuf' type without calling a method on this // object). bool arePointersValid(const char_type *first, const char_type *middle, const char_type *last) const; // Return 'true' if pointers form a valid range // ('first <= middle <= last') and 'first == d_str.data()' and // 'middle' and 'last' are in the range // '[d_str.data() .. d_str.data() + d_str.size()]', or all arguments // are 0, and 'false' otherwise. Note that this function is called in // defensive (i.e., "DEBUG" or "SAFE") build modes only. protected: // PROTECTED MANIPULATORS virtual pos_type seekoff( off_type offset, ios_base::seekdir whence, ios_base::openmode modeBitMask = ios_base::in | ios_base::out); // Set the current input position or the current output position (or // both) to the specified 'offset' from the specified 'whence' // location. Optionally specify a 'modeBitMask' indicating whether to // set the current input position, current output position, or both. // If 'whence' is 'ios_base::beg', set the current position to the // indicated 'offset' from the beginning of the stream; if 'whence' is // 'ios_base::end', set the current position to the indicated 'offset' // from the end of the stream; and if 'whence' is 'ios_base::cur', set // the current input or output position to the indicated 'offset' from // its current position. If 'whence' is 'ios_base::cur', then // 'modeBitMask' may be either 'ios_base::in' or 'ios_base::out', but // not both. Return the offset of the new position on success, and // 'pos_type(off_type(-1))' otherwise. virtual pos_type seekpos( pos_type absoluteOffset, ios_base::openmode modeBitMask = ios_base::in | ios_base::out); // Set the current input position or the current output position (or // both) to the specified 'absoluteOffset' from the beginning of the // stream. Optionally specify a 'modeBitMask' indicating whether to // set the current input position, current output position, or both. // Return the offset of the new position on success, and // 'pos_type(off_type(-1))' otherwise. virtual std::streamsize xsgetn(char_type *result, std::streamsize numCharacters); // Read up to the specified 'numCharacters' from this 'stringbuf' // object and store them in the specified 'result' array. Return the // number of characters loaded into 'result'. Note that if fewer than // 'numCharacters' characters are available in the buffer, all // available characters are loaded into 'result'. The behavior is // undefined unless 'result' refers to a contiguous sequence of at // least 'numCharacters' characters. virtual int_type underflow(); // Return the character at the current input position, if a character // is available, and 'traits_type::eof()' otherwise. Update the end // of the input area, 'egptr', if additional characters are available // (as may occur if additional characters have been written to the // string buffer). Note that this operation is similar to 'uflow', // but does not advance the current input position. virtual int_type uflow(); // Return the character at the current input position and advance the // input position by 1. If no character is available at the current // input position, return 'traits_type::eof()'. Update the end of the // input area, 'egptr', if additional characters are available (as may // occur if additional characters have been written to the string // buffer). Note that this operation is similar to 'underflow', but // advances the current input position. virtual int_type pbackfail(int_type character = traits_type::eof()); // Put back the specified 'character' into the input sequence so that // the next character read from the input sequence will be // 'character'. If 'character' is either 'traits_type::eof()' or is // the same as the previously read character from the input sequence, // then adjust the current input position, 'gptr', back one position. // If 'character' is neither 'traits_type::eof()' nor the character // previously read from the input sequence, but this string buffer was // opened for writing ('ios_base::out'), then adjust the input // sequence back one position and write 'character' to that position. // Return the character that was put back on success and // 'traits_type::eof()' if either the input position is currently at // the beginning of the sequence or if the previous character in the // input sequence is not 'character' and this buffer was not opened // for writing. virtual std::streamsize xsputn(const char_type *inputString, std::streamsize numCharacters); // Append the specified 'numCharacters' from the specified // 'inputString' to the output sequence starting at the current output // position ('pptr'). Update the current output position of this // string buffer to refer to the last appended character. Return the // number of characters that were appended. The behavior is undefined // unless 'inputString' refers to a contiguous sequence of at least // 'numCharacters' characters. virtual int_type overflow(int_type character = traits_type::eof()); // Append the specified 'character' to the output sequence of this // stream buffer at the current output position ('pptr'), and advance // the output position by one. This operation may update the end of // output area ('epptr') to allow for additional writes (e.g., by the // base 'basic_streambuf' type) to the output sequence without calling // a method on this type. Return the written character on success, and // 'traits_type::eof()' if 'character' is 'traits_type::eof()' or this // stream buffer was not opened for writing. public: // CREATORS explicit basic_stringbuf(const allocator_type& allocator = allocator_type()); explicit basic_stringbuf(ios_base::openmode modeBitMask, const allocator_type& allocator = allocator_type()); explicit basic_stringbuf(const StringType& initialString, const allocator_type& allocator = allocator_type()); basic_stringbuf(const StringType& initialString, ios_base::openmode modeBitMask, const allocator_type& allocator = allocator_type()); // Create a 'basic_stringbuf' object. Optionally specify a // 'modeBitMask' indicating whether this buffer may be read from, // written to, or both. If 'modeBitMask' is not supplied, this buffer // is created with 'ios_base::in | ios_base::out'. Optionally specify // an 'initialString' indicating the initial sequence of characters // that this buffer will access or manipulate. If 'initialString' is // not supplied, the initial sequence of characters will be empty. // Optionally specify the 'allocator' used to supply memory. If // 'allocator' is not supplied, a default-constructed object of the // (template parameter) 'ALLOCATOR' type is used. If the 'ALLOCATOR' // argument is of type 'bsl::allocator' (the default), then // 'allocator', if supplied, shall be convertible to // 'bslma::Allocator *'. If the 'ALLOCATOR' argument is of type // 'bsl::allocator' and 'allocator' is not supplied, the currently // installed default allocator will be used to supply memory. explicit basic_stringbuf(BloombergLP::bslmf::MovableRef<StringType> initialString); basic_stringbuf(BloombergLP::bslmf::MovableRef<StringType> initialString, const allocator_type& allocator); basic_stringbuf(BloombergLP::bslmf::MovableRef<StringType> initialString, ios_base::openmode modeBitMask); basic_stringbuf(BloombergLP::bslmf::MovableRef<StringType> initialString, ios_base::openmode modeBitMask, const allocator_type& allocator); // Create a 'basic_stringbuf' object. Use the specified // 'initialString' indicating the initial sequence of characters that // this buffer will access or manipulate. Optionally specify a // 'modeBitMask' indicating whether this buffer may be read from, // written to, or both. If 'modeBitMask' is not supplied, this buffer // is created with 'ios_base::in | ios_base::out'. Optionally specify // the 'allocator' used to supply memory. If 'allocator' is not // supplied, the allocator in 'initialString' is used. 'initialString' // is left in a valid but unspecified state. template <class SALLOC> explicit basic_stringbuf( const bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, SALLOC>& initialString, const allocator_type& allocator = allocator_type(), typename bsl::enable_if< !bsl::is_same<ALLOCATOR, SALLOC>::value, void *>::type = 0) // Create a 'basic_stringbuf' object. Use the specified // 'initialString' indicating the initial sequence of characters that // this buffer will access or manipulate. Optionally specify the // 'allocator' used to supply memory. If 'allocator' is not supplied, // a default-constructed object of the (template parameter) 'ALLOCATOR' // type is used. If the 'ALLOCATOR' argument is of type // 'bsl::allocator' (the default), then 'allocator', if supplied, shall // be convertible to 'bslma::Allocator *'. If the 'ALLOCATOR' argument // is of type 'bsl::allocator' and 'allocator' is not supplied, the // currently installed default allocator will be used to supply memory. // // Note: implemented inline due to Sun CC compilation error. : BaseType() , d_str(initialString.data(), initialString.size(), allocator) , d_endHint(initialString.size()) , d_mode(ios_base::in | ios_base::out) { updateStreamPositions(); } template <class SALLOC> basic_stringbuf( const bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, SALLOC>& initialString, ios_base::openmode modeBitMask, const allocator_type& allocator = allocator_type(), typename bsl::enable_if< !bsl::is_same<ALLOCATOR, SALLOC>::value, void *>::type = 0) // Create a 'basic_stringbuf' object. Use the specified // 'initialString' indicating the initial sequence of characters that // this buffer will access or manipulate. Use the specified // 'modeBitMask' to indicate whether this buffer may be read from, // written to, or both. Optionally specify the 'allocator' used to // supply memory. If 'allocator' is not supplied, a // default-constructed object of the (template parameter) 'ALLOCATOR' // type is used. If the 'ALLOCATOR' argument is of type // 'bsl::allocator' (the default), then 'allocator', if supplied, shall // be convertible to 'bslma::Allocator *'. If the 'ALLOCATOR' argument // is of type 'bsl::allocator' and 'allocator' is not supplied, the // currently installed default allocator will be used to supply memory. // // Note: implemented inline due to Sun CC compilation error. : BaseType() , d_str(initialString.data(), initialString.size(), allocator) , d_endHint(initialString.size()) , d_mode(modeBitMask) { updateStreamPositions(0, d_mode & ios_base::ate ? d_endHint : 0); } #ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_STREAM_MOVE basic_stringbuf(basic_stringbuf&& original); basic_stringbuf(basic_stringbuf&& original, const allocator_type& allocator); // Create a 'basic_stringbuf' object having the same value as the // specified 'original' object by moving the contents of 'original' to // the newly-created object. Optionally specify the 'allocator' used // to supply memory. 'original' is left in a valid but unspecified // state. #endif ~basic_stringbuf(); // Destroy this object. // MANIPULATORS #ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_STREAM_MOVE basic_stringbuf& operator=(basic_stringbuf&& rhs); // Assign to this object the value of the specified 'rhs', and return a // reference providing modifiable access to this object. The contents // of 'rhs' are move-assigned to this object. 'rhs' is left in a valid // but unspecified state. #endif void str(const StringType& value); void str(BloombergLP::bslmf::MovableRef<StringType> value); template <class SALLOC> typename bsl::enable_if<!bsl::is_same<ALLOCATOR, SALLOC>::value, void>::type str(const basic_string<CHAR_TYPE, CHAR_TRAITS, SALLOC>& value) // Reset the internally buffered sequence of characters to the // specified 'value'. Update the beginning and end of both the input // and output sequences to be the beginning and end of the updated // buffer, update the current input position to be the beginning of the // updated buffer, and update the current output position to be the end // of the updated buffer. If 'value' is passed by 'MovableRef', then // it is left in an unspecified but valid state. // // Note: implemented inline due to Sun CC compilation error. { d_str.assign(value.data(), value.size()); d_endHint = d_str.size(); updateStreamPositions(0, d_mode & ios_base::ate ? d_endHint : 0); } #ifdef BSLS_COMPILERFEATURES_SUPPORT_REF_QUALIFIERS StringType str() &&; // Return the currently buffered sequence of characters. If this // object was created only in input mode, the resultant 'StringType' // contains the character sequence in the range '[eback(), egptr())'. // If 'modeBitMask & ios_base::out' specified at construction is // nonzero then the resultant 'StringType' contains the character // sequence in the range '[pbase(), high_mark)', where 'high_mark' // represents the position one past the highest initialized character // in the buffer. Otherwise this object has been created in neither // input nor output mode and a zero length 'StringType' is returned. // This object is left in an empty state. #endif #ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY void swap(basic_stringbuf& other); // Efficiently exchange the value of this object with the value of the // specified 'other' object. This method provides the no-throw // exception-safety guarantee if '*this' and 'other' allocators compare // equal. The behavior is undefined unless either '*this' and 'other' // allocators compare equal or 'propagate_on_container_swap' is 'true'. // Note that this function is only available for C++11 (and later) // language standards because it requires that 'swap' be provided on // the (platform supplied) base class for this type. #endif // BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY // ACCESSORS allocator_type get_allocator() const BSLS_KEYWORD_NOEXCEPT; // Return the allocator used by the underlying string to supply memory. #ifdef BSLS_COMPILERFEATURES_SUPPORT_REF_QUALIFIERS StringType str() const &; #else StringType str() const; #endif // Return the currently buffered sequence of characters. If this // object was created only in input mode, the resultant 'StringType' // contains the character sequence in the range '[eback(), egptr())'. // If 'modeBitMask & ios_base::out' specified at construction is // nonzero then the resultant 'StringType' contains the character // sequence in the range '[pbase(), high_mark)', where 'high_mark' // represents the position one past the highest initialized character // in the buffer. Otherwise this object has been created in neither // input nor output mode and a zero length 'StringType' is returned. #ifndef BSLS_PLATFORM_CMP_SUN // To be enabled once {DRQS 168075157} is resolved template <class SALLOC> typename bsl::enable_if< bsl::IsStdAllocator<SALLOC>::value, basic_string<CHAR_TYPE, CHAR_TRAITS, SALLOC> >::type str(const SALLOC& allocator) const // Return the currently buffered sequence of characters in a // 'basic_string' that uses the specified 'allocator'. If this object // was created only in input mode, the resultant 'basic_string' // contains the character sequence in the range '[eback(), egptr())'. // If 'modeBitMask & ios_base::out' specified at construction is // nonzero then the resultant 'basic_string' contains the character // sequence in the range '[pbase(), high_mark)', where 'high_mark' // represents the position one past the highest initialized character // in the buffer. Otherwise this object has been created in neither // input nor output mode and a zero length 'basic_string' is returned. // // Note: implemented inline due to Sun CC compilation error. { return basic_string<CHAR_TYPE, CHAR_TRAITS, SALLOC>(view(), allocator); } #endif ViewType view() const BSLS_KEYWORD_NOEXCEPT; // Return a 'string_view' containing the currently buffered sequence of // characters. If this object was created only in input mode, the // resultant 'ViewType' contains the character sequence in the range // '[eback(), egptr())'. If 'modeBitMask & ios_base::out' specified at // construction is nonzero then the resultant 'StringType' contains the // character sequence in the range '[pbase(), high_mark)', where // 'high_mark' represents the position one past the highest initialized // character in the buffer. Otherwise this object has been created in // neither input nor output mode and a zero length 'ViewType' is // returned. }; // FREE FUNCTIONS #if defined(BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY) \ && defined(BSLS_LIBRARYFEATURES_HAS_CPP11_STREAM_MOVE) template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> void swap(basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& a, basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& b); // Efficiently exchange the values of the specified 'a' and 'b' objects. // This method provides the no-throw exception-safety guarantee if 'a' and // 'b' allocators compare equal. Note that this function is only available // for C++11 (and later) language standards. #endif // STANDARD TYPEDEFS typedef basic_stringbuf<char, char_traits<char>, allocator<char> > stringbuf; typedef basic_stringbuf<wchar_t, char_traits<wchar_t>, allocator<wchar_t> > wstringbuf; // ========================= // struct StringBufContainer // ========================= template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> class StringBufContainer { // This class enables the implementation of string-stream types by // providing a trivial type containing a 'basic_stringbuf' that is suitable // as a ('private') base class for a string-stream. Inheriting from // 'StringBufContainer' allows the string-stream to ensure that the // contained 'basic_stringbuf' is initialized before initializing other // base classes or data members without potentially overriding 'virtual' // methods in the 'basic_stringbuf' type. Note that implementations of // string-stream types must pass the address of a string-buffer to their // 'public' base class (e.g., 'basic_stream'), so the string-stream must // ensure (using 'private' inheritance) that the string-buffer is // initialized before constructing the 'public' base class. If a // string-stream implementation were to directly inherit from // 'basic_streambuf', then 'virtual' methods defined in that string-stream // (e.g., 'underflow') might incorrectly override those in the // 'basic_stringbuf' implementation. private: // PRIVATE TYPES typedef basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> StreamBufType; typedef bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> StringType; typedef BloombergLP::bslmf::MovableRefUtil MoveUtil; // DATA StreamBufType d_bufObj; // contained 'basic_stringbuf' private: // NOT IMPLEMENTED StringBufContainer(const StringBufContainer&); // = delete StringBufContainer& operator=(const StringBufContainer&); // = delete public: // CREATORS explicit StringBufContainer(const ALLOCATOR& allocator) : d_bufObj(allocator) { } StringBufContainer(ios_base::openmode modeBitMask, const ALLOCATOR& allocator) : d_bufObj(modeBitMask, allocator) { } StringBufContainer(const StringType& initialString, const ALLOCATOR& allocator) : d_bufObj(initialString, allocator) { } StringBufContainer(const StringType& initialString, ios_base::openmode modeBitMask, const ALLOCATOR& allocator) : d_bufObj(initialString, modeBitMask, allocator) { } StringBufContainer( BloombergLP::bslmf::MovableRef<StringType> initialString, ios_base::openmode modeBitMask, const ALLOCATOR& allocator) : d_bufObj(MoveUtil::move(initialString), modeBitMask, allocator) { } StringBufContainer( BloombergLP::bslmf::MovableRef<StringType> initialString, ios_base::openmode modeBitMask) : d_bufObj(MoveUtil::move(initialString), modeBitMask) { } template <class STRING_ITER> StringBufContainer(STRING_ITER first, STRING_ITER last, ios_base::openmode modeBitMask, const ALLOCATOR& allocator) : d_bufObj(modeBitMask, allocator) { StringType tempStr(first, last, allocator); d_bufObj.str(MoveUtil::move(tempStr)); } #ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_STREAM_MOVE StringBufContainer(StringBufContainer&& original) // Create a 'StringBufContainer' object having the same value as the // specified 'original' object by moving the contents of 'original' to // the newly-created object. 'original' is left in a valid but // unspecified state. : d_bufObj(std::move(original.d_bufObj)) { } StringBufContainer(StringBufContainer&& original, const ALLOCATOR& allocator) // Create a 'StringBufContainer' object using the specified 'allocator' to // supply memory and having the same value as the specified 'original' // object by moving the contents of 'original' to the newly-created object. // 'original' is left in a valid but unspecified state. : d_bufObj(std::move(original.d_bufObj), allocator) { } #endif //! ~StringBufContainer() = default; // MANIPULATORS #ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_STREAM_MOVE StringBufContainer& operator=(StringBufContainer&& rhs) // Assign to this object the value of the specified 'rhs', and return a // reference providing modifiable access to this object. The contents // of 'rhs' are move-assigned to this object. 'rhs' is left in a valid // but unspecified state. { d_bufObj = std::move(rhs.d_bufObj); return *this; } #endif #ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY void swap(StringBufContainer& other) // Efficiently exchange the value of this object with the value of the // specified 'other' object. { d_bufObj.swap(other.d_bufObj); } #endif // BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY // ACCESSORS StreamBufType *rdbuf() const { return const_cast<StreamBufType *>(&d_bufObj); } }; // ============================================================================ // TEMPLATE FUNCTION DEFINITIONS // ============================================================================ // --------------------- // class basic_stringbuf // --------------------- // PRIVATE MANIPULATORS template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> typename basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::pos_type basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>:: updateInputPointers(char_type *currentInputPosition) { BSLS_ASSERT(d_mode & ios_base::in); BSLS_ASSERT(&d_str[0] <= currentInputPosition); BSLS_ASSERT(currentInputPosition <= &d_str[0] + static_cast<std::ptrdiff_t>(streamSize())); char_type *dataPtr = &d_str[0]; this->setg(dataPtr, currentInputPosition, dataPtr + static_cast<std::ptrdiff_t>(streamSize())); return pos_type(currentInputPosition - dataPtr); } template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> typename basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::pos_type basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>:: updateOutputPointers(char_type *currentOutputPosition) { BSLS_ASSERT(d_mode & ios_base::out); BSLS_ASSERT(&d_str[0] <= currentOutputPosition); BSLS_ASSERT(currentOutputPosition <= &d_str[0] + d_str.size()); char_type *dataPtr = &d_str[0]; std::size_t dataSize = d_str.size(); pos_type outputPos = currentOutputPosition - dataPtr; this->setp(dataPtr, dataPtr + dataSize); pos_type bumpAmount = outputPos; while (bumpAmount > INT_MAX) { this->pbump(INT_MAX); bumpAmount -= INT_MAX; } if (bumpAmount) { this->pbump(int(bumpAmount)); } return outputPos; } template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> void basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>:: updateStreamPositions(off_type inputOffset, off_type outputOffset) { // Extend the internal buffer to the full capacity of the string to allow // us to use the full capacity for buffering output. d_str.resize(d_str.capacity()); char_type *dataPtr = &d_str[0]; if (d_mode & ios_base::out) { // Update the output position. std::size_t dataSize = d_str.size(); this->setp(dataPtr, dataPtr + dataSize); off_type bumpAmount = outputOffset; while (bumpAmount < INT_MIN) { this->pbump(INT_MIN); bumpAmount -= INT_MIN; } while (bumpAmount > INT_MAX) { this->pbump(INT_MAX); bumpAmount -= INT_MAX; } if (bumpAmount) { this->pbump(int(bumpAmount)); } } if (d_mode & ios_base::in) { // Update the input position. this->setg(dataPtr, dataPtr + inputOffset, dataPtr + static_cast<std::ptrdiff_t>(streamSize())); } } template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> bool basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::extendInputArea() { // Try to extend into written buffer. if (d_mode & ios_base::out && this->pptr() > this->egptr()) { d_endHint = streamSize(); updateInputPointers(this->gptr()); return true; // RETURN } return false; } // PRIVATE ACCESSORS template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> typename basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::pos_type basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::streamSize() const { pos_type size = std::max<off_type>(d_endHint, this->pptr() - this->pbase()); BSLS_ASSERT(size <= off_type(d_str.size())); return size; } template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> bool basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::arePointersValid( const char_type *first, const char_type *middle, const char_type *last) const { const bool isNull = first == 0; const char_type *bufferBegin = isNull ? 0 : d_str.data(); const char_type *bufferEnd = isNull ? 0 : d_str.data() + d_str.size(); return first == bufferBegin && last <= bufferEnd && first <= middle && middle <= last; } // PROTECTED MANIPULATORS template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> typename basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::pos_type basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::seekoff( off_type offset, ios_base::seekdir whence, ios_base::openmode modeBitMask) { // If 'whence' is 'ios_base::cur' (the current position), 'modeBitMask' // may not be both input and output mode. if (((modeBitMask & (ios_base::in | ios_base::out)) == (ios_base::in | ios_base::out)) && whence == ios_base::cur) { return pos_type(off_type(-1)); // RETURN } pos_type newPos = pos_type(off_type(-1)); // Set the current input position. if ((modeBitMask & ios_base::in) && (d_mode & ios_base::in)) { char_type *inputPtr = 0; switch (whence) { case ios_base::beg: { inputPtr = this->eback() + offset; } break; case ios_base::cur: { inputPtr = this->gptr() + offset; } break; case ios_base::end: { inputPtr = this->eback() + static_cast<std::ptrdiff_t>(streamSize()) + offset; } break; default: { BSLS_ASSERT_OPT(false && "invalid seekdir argument"); } } if (inputPtr < this->eback() || inputPtr > this->eback() + static_cast<std::ptrdiff_t>(streamSize())) { // 'inputPtr' is outside the valid range of the string buffer. return pos_type(off_type(-1)); // RETURN } newPos = updateInputPointers(inputPtr); } // Set the current output position. if ((modeBitMask & ios_base::out) && (d_mode & ios_base::out)) { char_type *outputPtr = 0; switch (whence) { case ios_base::beg: { outputPtr = this->pbase() + offset; } break; case ios_base::cur: { outputPtr = this->pptr() + offset; } break; case ios_base::end: { outputPtr = this->pbase() + static_cast<std::ptrdiff_t>(streamSize()) + offset; } break; default: BSLS_ASSERT_OPT(false && "invalid seekdir argument"); } if (outputPtr < this->pbase() || outputPtr > this->pbase() + static_cast<std::ptrdiff_t>(streamSize())) { // 'outputPtr' is outside the valid range of the string buffer. return pos_type(off_type(-1)); // RETURN } newPos = updateOutputPointers(outputPtr); } return newPos; } template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> inline typename basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::pos_type basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::seekpos( pos_type absoluteOffset, ios_base::openmode modeBitMask) { return basic_stringbuf::seekoff(off_type(absoluteOffset), ios_base::beg, modeBitMask); } template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> std::streamsize basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::xsgetn( char_type *result, std::streamsize numCharacters) { if ((d_mode & ios_base::in) == 0) { return 0; // RETURN } // Additional characters may become available for reading when the input // area is extended to account for any characters newly written to the // output sequence. extendInputArea(); if (this->gptr() != this->egptr()) { // There are characters available in this buffer. std::streamsize available = this->egptr() - this->gptr(); std::streamsize readChars = std::min(available, numCharacters); traits_type::copy(result, this->gptr(), std::size_t(readChars)); this->gbump(int(readChars)); return readChars; // RETURN } return 0; } template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> typename basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::int_type basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::underflow() { if ((d_mode & ios_base::in) == 0) { return traits_type::eof(); // RETURN } if (this->gptr() != this->egptr()) { // There are characters available in this buffer. return traits_type::to_int_type(*this->gptr()); // RETURN } if (extendInputArea()) { // Additional characters may become available after the input area is // extended. return this->basic_stringbuf::underflow(); // RETURN } return traits_type::eof(); } template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> typename basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::int_type basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::uflow() { if ((d_mode & ios_base::in) == 0) { return traits_type::eof(); // RETURN } if (this->gptr() != this->egptr()) { // There are characters available in this buffer. int_type c = traits_type::to_int_type(*this->gptr()); this->gbump(1); return c; // RETURN } if (extendInputArea()) { // Additional characters may become available after the input area is // extended. return this->basic_stringbuf::uflow(); // RETURN } return traits_type::eof(); } template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> typename basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::int_type basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::pbackfail( int_type character) { if (this->gptr() == this->eback()) { // The current position is at the start of the buffer, so we cannot // push back a character. return traits_type::eof(); // RETURN } if (traits_type::eq_int_type(character, traits_type::eof()) || traits_type::eq_int_type( character, traits_type::to_int_type(*(this->gptr() - 1)))) { // If 'character' is 'eof' or the previous input character, // simply move the current position back 1. this->gbump(-1); return traits_type::to_int_type(*this->gptr()); // RETURN } if (d_mode & ios_base::out) { // In output mode, if 'character' is not the previous input character, // overwrite the previous input character. this->gbump(-1); *this->gptr() = traits_type::to_char_type(character); return character; // RETURN } return traits_type::eof(); } template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> std::streamsize basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::xsputn( const char_type *inputString, std::streamsize numCharacters) { if ((d_mode & ios_base::out) == 0) { return 0; // RETURN } BSLS_ASSERT(this->pptr()); BSLS_ASSERT(this->pbase()); // Compute the space required. std::streamsize spaceLeft = d_str.data() + d_str.size() - this->pptr(); std::ptrdiff_t toOverwrite = std::ptrdiff_t(std::min(spaceLeft, numCharacters)); // Append the portion of 'inputString' that can be written without // resizing 'd_ptr'. traits_type::copy(this->pptr(), inputString, toOverwrite); off_type inputOffset = this->gptr() - this->eback(); if (numCharacters == toOverwrite) { // If all of 'inputString' has been written, just update the stream // positions. off_type newHigh = numCharacters + this->pptr() - this->pbase(); d_endHint = std::max(d_endHint, newHigh); updateStreamPositions(inputOffset, newHigh); } else { // If some characters remain to be written, append them to 'd_str' // (resizing 'd_str' in the process). d_str.append(inputString + toOverwrite, inputString + numCharacters); // Update the last written character cache, and the input stream // positions. d_endHint = d_str.size(); updateStreamPositions(inputOffset, d_endHint); } return numCharacters; } template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> typename basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::int_type basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::overflow( int_type character) { if ((d_mode & ios_base::out) == 0) { return traits_type::eof(); // RETURN } if (traits_type::eq_int_type(character, traits_type::eof())) { // Nothing to write, so just return success. return traits_type::not_eof(character); // RETURN } char_type c = traits_type::to_char_type(character); if (this->pptr() != this->epptr()) { // Additional space is available in 'd_str', so no need to resize the // buffer. *this->pptr() = c; this->pbump(1); d_endHint = streamSize(); } else { // Store the input offset so it can be used to restore the input and // output positions after the next resize. off_type inputOffset = this->gptr() - this->eback(); // Append the character, and expand the buffer. d_str.push_back(c); // Update the input sequence, restoring the current input position // from 'inputOffset', and updating the output sequence to reflect the // newly resized buffer. d_endHint = d_str.size(); updateStreamPositions(inputOffset, d_endHint); } return character; } // CREATORS template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>:: basic_stringbuf(const allocator_type& allocator) : BaseType() , d_str(allocator) , d_endHint(0) , d_mode(ios_base::in | ios_base::out) { updateStreamPositions(); } template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>:: basic_stringbuf(ios_base::openmode modeBitMask, const allocator_type& allocator) : BaseType() , d_str(allocator) , d_endHint(0) , d_mode(modeBitMask) { updateStreamPositions(); } template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>:: basic_stringbuf(const StringType& initialString, const allocator_type& allocator) : BaseType() , d_str(initialString, allocator) , d_endHint(initialString.size()) , d_mode(ios_base::in | ios_base::out) { updateStreamPositions(); } template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> inline basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>:: basic_stringbuf(const StringType& initialString, ios_base::openmode modeBitMask, const allocator_type& allocator) : BaseType() , d_str(initialString, allocator) , d_endHint(initialString.size()) , d_mode(modeBitMask) { updateStreamPositions(0, d_mode & ios_base::ate ? d_endHint : 0); } template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> inline basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>:: basic_stringbuf(BloombergLP::bslmf::MovableRef<StringType> initialString) : BaseType() , d_str(MoveUtil::move(initialString)) , d_endHint(d_str.size()) , d_mode(ios_base::in | ios_base::out) { updateStreamPositions(); } template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> inline basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>:: basic_stringbuf(BloombergLP::bslmf::MovableRef<StringType> initialString, const allocator_type& allocator) : BaseType() , d_str(MoveUtil::move(initialString), allocator) , d_endHint(d_str.size()) , d_mode(ios_base::in | ios_base::out) { updateStreamPositions(); } template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> inline basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>:: basic_stringbuf(BloombergLP::bslmf::MovableRef<StringType> initialString, ios_base::openmode modeBitMask) : BaseType() , d_str(MoveUtil::move(initialString)) , d_endHint(d_str.size()) , d_mode(modeBitMask) { updateStreamPositions(0, d_mode & ios_base::ate ? d_endHint : 0); } template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> inline basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>:: basic_stringbuf(BloombergLP::bslmf::MovableRef<StringType> initialString, ios_base::openmode modeBitMask, const allocator_type& allocator) : BaseType() , d_str(MoveUtil::move(initialString), allocator) , d_endHint(d_str.size()) , d_mode(modeBitMask) { updateStreamPositions(0, d_mode & ios_base::ate ? d_endHint : 0); } #ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_STREAM_MOVE template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> inline basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>:: basic_stringbuf(basic_stringbuf&& original) : BaseType() , d_str(std::move(original.d_str)) , d_endHint(std::move(original.d_endHint)) , d_mode(std::move(original.d_mode)) { // Capture the positions for later restoration const off_type inputOffset = original.gptr() - original.eback(); const off_type outputOffset = original.pptr() - original.pbase(); updateStreamPositions(inputOffset, outputOffset); this->pubimbue(original.getloc()); if (original.d_endHint > 0 && static_cast<size_t>(original.d_endHint) > original.d_str.size()) { // The move has moved away the string original.d_endHint = 0; original.updateStreamPositions(); } } template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> inline basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>:: basic_stringbuf(basic_stringbuf&& original, const allocator_type& allocator) : BaseType() , d_str(std::move(original.d_str), allocator) , d_endHint(std::move(original.d_endHint)) , d_mode(std::move(original.d_mode)) { // Capture the positions for later restoration const off_type inputOffset = original.gptr() - original.eback(); const off_type outputOffset = original.pptr() - original.pbase(); updateStreamPositions(inputOffset, outputOffset); this->pubimbue(original.getloc()); if (original.d_endHint > 0 && static_cast<size_t>(original.d_endHint) > original.d_str.size()) { // The move has moved away the string original.d_endHint = 0; original.updateStreamPositions(); } } #endif template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>:: ~basic_stringbuf() { if (d_mode & ios_base::in) { BSLS_ASSERT(arePointersValid(this->eback(), this->gptr(), this->egptr())); } if (d_mode & ios_base::out) { BSLS_ASSERT(arePointersValid(this->pbase(), this->pptr(), this->epptr())); } } // MANIPULATORS #ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_STREAM_MOVE template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> inline basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>:: operator=(basic_stringbuf&& rhs) { // Capture the positions for later restoration const off_type inputOffset = rhs.gptr() - rhs.eback(); const off_type inputSize = rhs.egptr() - rhs.eback(); const off_type outputOffset = rhs.pptr() - rhs.pbase(); const off_type outputSize = rhs.epptr() - rhs.pbase(); this->pubimbue(rhs.getloc()); d_str = std::move(rhs.d_str); d_endHint = std::move(rhs.d_endHint); d_mode = std::move(rhs.d_mode); // Fix the stream-position pointers char_type *dataPtr = &d_str[0]; // Update positions/pointers in the moved-to object this->setp(dataPtr, dataPtr + outputSize); this->pbump(static_cast<int>(outputOffset)); this->setg(dataPtr, dataPtr + inputOffset, dataPtr + inputSize); // Reset positions/pointers in the moved-from object if (rhs.d_endHint > 0 && static_cast<size_t>(rhs.d_endHint) > rhs.d_str.size()) { // The move has moved away the string rhs.d_endHint = 0; rhs.updateStreamPositions(); } return *this; } #endif template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> void basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::str( const StringType& value) { d_str = value; d_endHint = d_str.size(); updateStreamPositions(0, d_mode & ios_base::ate ? d_endHint : 0); } template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> void basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::str( BloombergLP::bslmf::MovableRef<StringType> value) { StringType& lvalue = value; d_str = MoveUtil::move(lvalue); d_endHint = d_str.size(); updateStreamPositions(0, d_mode & ios_base::ate ? d_endHint : 0); } #ifdef BSLS_COMPILERFEATURES_SUPPORT_REF_QUALIFIERS template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> typename basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::StringType basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::str() && { if (d_mode & ios_base::out) { d_str.resize(static_cast<typename StringType::size_type>(streamSize())); this->setp(d_str.data(), d_str.data()); } else if (d_mode & ios_base::in) { if (streamSize() > 0) { if (this->eback() != d_str.data()) { d_str.erase(0, this->eback() - d_str.data()); } d_str.resize(static_cast<typename StringType::size_type>( streamSize())); this->setg(d_str.data(), d_str.data(), d_str.data()); } } StringType ret = std::move(d_str); d_endHint = 0; updateStreamPositions(); return ret; } #endif #ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> void basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::swap( basic_stringbuf& other) { BSLS_ASSERT( bsl::allocator_traits<ALLOCATOR>::propagate_on_container_swap::value || d_str.get_allocator() == other.d_str.get_allocator()); // Capture the positions for the later restoration. Formally, // 'std::basic_streambuf::swap' exchanges the internal pointers and the // locale object. But 'bsl::string' swapping can invalidate pointers, so // we need to control this process manually. const off_type inputOffset = this->gptr() - this->eback(); const off_type outputOffset = this->pptr() - this->pbase(); const std::locale loc = this->getloc(); const off_type otherInputOffset = other.gptr() - other.eback(); const off_type otherOutputOffset = other.pptr() - other.pbase(); const std::locale otherLoc = other.getloc(); // Parent method invocation. this->BaseType::swap(other); // Swapping data members. this->pubimbue(otherLoc); other.pubimbue(loc); d_str.swap(other.d_str); BloombergLP::bslalg::SwapUtil::swap(&this->d_endHint, &other.d_endHint); BloombergLP::bslalg::SwapUtil::swap(&this->d_mode, &other.d_mode); // Fix the stream-position pointers. this->updateStreamPositions(otherInputOffset, otherOutputOffset); other.updateStreamPositions( inputOffset, outputOffset); } #endif // BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY // ACCESSORS template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> inline typename basic_stringbuf<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::allocator_type basic_stringbuf<CHAR_TYPE,CHAR_TRAITS,ALLOCATOR>::get_allocator() const BSLS_KEYWORD_NOEXCEPT { return d_str.get_allocator(); } template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> inline typename basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::StringType #ifdef BSLS_COMPILERFEATURES_SUPPORT_REF_QUALIFIERS basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::str() const & #else basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::str() const #endif { return StringType(view()); } template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> inline typename basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::ViewType basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::view() const BSLS_KEYWORD_NOEXCEPT { if (d_mode & ios_base::out) { return ViewType(d_str.begin(), static_cast<std::ptrdiff_t>(streamSize())); // RETURN } if (d_mode & ios_base::in) { return ViewType(this->eback(), this->egptr() - this->eback());// RETURN } return ViewType(); } } // close namespace bsl // FREE FUNCTIONS #if defined(BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY) \ && defined(BSLS_LIBRARYFEATURES_HAS_CPP11_STREAM_MOVE) template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> void bsl::swap(basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& a, basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>& b) { typedef BloombergLP::bslmf::MovableRefUtil MoveUtil; if (a.get_allocator() == b.get_allocator() || bsl::allocator_traits<ALLOCATOR>::propagate_on_container_swap::value) { a.swap(b); } else { basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> aCopy( MoveUtil::move(a), b.get_allocator()); basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> bCopy( MoveUtil::move(b), a.get_allocator()); swap(a, bCopy); swap(b, aCopy); } } #endif // ============================================================================ // TYPE TRAITS // ============================================================================ namespace BloombergLP { namespace bslma { template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR> struct UsesBslmaAllocator< bsl::basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> > : bsl::true_type {}; } // close namespace bslma } // close enterprise namespace // Undo 'BSLS_ASSERT' filename fix -- See {'bsls_assertimputil'} #ifdef BSLS_ASSERTIMPUTIL_AVOID_STRING_CONSTANTS #undef BSLS_ASSERTIMPUTIL_FILE #define BSLS_ASSERTIMPUTIL_FILE BSLS_ASSERTIMPUTIL_DEFAULTFILE #endif #endif // ---------------------------------------------------------------------------- // Copyright 2013 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------