// bslstl_istringstream.h                                             -*-C++-*-
#ifndef INCLUDED_BSLSTL_ISTRINGSTREAM
#define INCLUDED_BSLSTL_ISTRINGSTREAM

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a C++03-compatible 'istringstream' class.
//
//@CLASSES:
//  bsl::istringstream: C++03-compatible 'istringstream' class
//
//@CANONICAL_HEADER: bsl_sstream.h
//
//@SEE_ALSO:
//
//@DESCRIPTION: This component is for internal use only.  Please include
// '<bsl_sstream.h>' instead.
//
// This component defines a class template, 'bsl::basic_istringstream',
// implementing a standard input stream that provides a constructor (as well as
// a manipulator) allowing clients to set the sequence of characters
// from which input is streamed to a supplied 'bsl::basic_string' (see
// 27.8.3 [istringstream] of the C++11 standard).  This component also defines
// two standard aliases, 'bsl::istringstream' and 'bsl::wistringstream', that
// refer to specializations of the 'bsl::basic_istringstream' template for
// 'char' and 'wchar_t' types, respectively.  The 'bsl::basic_istringstream'
// template has three parameters, 'CHAR_TYPE', 'CHAR_TRAITS', and 'ALLOCATOR'.
// The 'CHAR_TYPE' and 'CHAR_TRAITS' parameters respectively define the
// character type for the string-stream and a type providing a set of
// operations the string-stream 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 string-stream's 'ALLOCATOR' template parameter
// determines how that string-stream will allocate memory.  The
// 'basic_istringstream' 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::istringstream' and 'bsl::wistringstream' both use 'bsl::allocator'.
//
///'bslma'-Style Allocators
/// - - - - - - - - - - - -
// If the type supplied for the 'ALLOCATOR' template parameter of an
// 'istringstream' instantiation is 'bsl::allocator', then objects of that
// string-stream type will conform to the standard behavior of a
// 'bslma'-allocator-enabled type.  Such a string-stream 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 string-stream throughout its lifetime;
// otherwise, the string-stream will use the default allocator installed at the
// time of the string-stream's construction (see 'bslma_default').
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Basic Input Operations
///- - - - - - - - - - - - - - - - -
// The following example demonstrates the use of 'bsl::istringstream' to read
// data of various types from a 'bsl::string' object.
//
// Suppose we want to implement a simplified converter from 'bsl::string' to a
// generic type, 'TYPE'.  We use 'bsl::istringstream' to implement the
// 'fromString' function.  We initialize the input stream with the string
// passed as a parameter and then we read the data from the input stream with
// 'operator>>':
//..
//  template <class TYPE>
//  TYPE fromString(const bsl::string& from)
//  {
//      bsl::istringstream in(from);
//      TYPE val;
//      in >> val;
//      return val;
//  }
//..
// Finally, we verify that our 'fromString' function works on some simple test
// cases:
//..
//  assert(fromString<int>("1234") == 1234);
//
//  assert(fromString<short>("-5") == -5);
//
//  assert(fromString<bsl::string>("abc") == "abc");
//..

#include <bslscm_version.h>

#include <bslma_isstdallocator.h>
#include <bslma_usesbslmaallocator.h>

#include <bslmf_enableif.h>
#include <bslmf_issame.h>
#include <bslmf_movableref.h>

#include <bsls_compilerfeatures.h>
#include <bsls_keyword.h>
#include <bsls_libraryfeatures.h>
#include <bsls_platform.h>

#include <bslstl_string.h>
#include <bslstl_stringview.h>
#include <bslstl_stringbuf.h>

#include <ios>

#include <istream>

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_STREAM_MOVE
# include <utility>
#endif

namespace bsl {

                          // =========================
                          // class basic_istringstream
                          // =========================

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
class basic_istringstream
    : private StringBufContainer<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>
    , public std::basic_istream<CHAR_TYPE, CHAR_TRAITS> {
    // This class implements a standard input stream that provides a
    // constructor and manipulator for setting the sequence of characters from
    // which input is streamed to a supplied 'bsl::basic_string'.

  private:
    // PRIVATE TYPES
    typedef basic_stringbuf<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>   StreamBufType;
    typedef StringBufContainer<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>
                                                                 BaseType;
    typedef bsl::basic_string<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> StringType;
    typedef bsl::basic_string_view<CHAR_TYPE, CHAR_TRAITS>       ViewType;
    typedef std::basic_istream<CHAR_TYPE, CHAR_TRAITS>           BaseStream;
    typedef std::ios_base                                        ios_base;

    typedef BloombergLP::bslmf::MovableRefUtil                   MoveUtil;

  private:
    // NOT IMPLEMENTED
    basic_istringstream(const basic_istringstream&);             // = delete
    basic_istringstream& operator=(const basic_istringstream&);  // = delete

  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;

    // CREATORS
    explicit
    basic_istringstream(const allocator_type& allocator = allocator_type());
    explicit
    basic_istringstream(ios_base::openmode    modeBitMask,
                        const allocator_type& allocator = allocator_type());
    explicit
    basic_istringstream(const StringType&     initialString,
                        const allocator_type& allocator = allocator_type());
    basic_istringstream(const StringType&     initialString,
                        ios_base::openmode    modeBitMask,
                        const allocator_type& allocator = allocator_type());
        // Create a 'basic_istringstream' object.  Optionally specify a
        // 'modeBitMask' indicating whether the underlying stream-buffer may
        // also be written to ('rdbuf' is created using
        // 'modeBitMask | ios_base::in').  If 'modeBitMask' is not supplied,
        // 'rdbuf' will be created using 'ios_base::in'.  Optionally specify an
        // 'initialString' indicating the sequence of characters from which
        // input will be streamed.  If 'initialString' is not supplied, there
        // will not be data to stream (until a subsequent call to the 'str'
        // manipulator).  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.  If
        // 'initialString' is passed by 'MovableRef', it is left in a valid but
        // unspecified state.

    explicit
    basic_istringstream(
                     BloombergLP::bslmf::MovableRef<StringType> initialString);
    basic_istringstream(
                      BloombergLP::bslmf::MovableRef<StringType> initialString,
                      const allocator_type&                      allocator);
    basic_istringstream(
                      BloombergLP::bslmf::MovableRef<StringType> initialString,
                      ios_base::openmode                         modeBitMask);
    basic_istringstream(
                      BloombergLP::bslmf::MovableRef<StringType> initialString,
                      ios_base::openmode                         modeBitMask,
                      const allocator_type&                      allocator);
        // Create a 'basic_istringstream' object.  Use the specified
        // 'initialString' indicating the initial sequence of characters from
        // which input will be streamed.  Optionally specify a 'modeBitMask'
        // indicating whether the underlying stream-buffer may also be written
        // to ('rdbuf' is created using 'modeBitMask | ios_base::in').  If
        // 'modeBitMask' is not supplied, 'rdbuf' will be created using
        // 'ios_base::in'.  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>
    basic_istringstream(
        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_istringstream' object.  Use the specified
        // 'initialString' indicating the sequence of characters from which
        // input will be streamed.  'rdbuf' is created using 'ios_base::in'.
        // 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(initialString.begin(),
               initialString.end(),
               ios_base::in,
               allocator)
    , BaseStream(BaseType::rdbuf())
    {
    }

    template <class SALLOC>
    basic_istringstream(
        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_istringstream' object.  Use the specified
        // 'initialString' indicating the sequence of characters from which
        // input will be streamed.  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(initialString.begin(),
               initialString.end(),
               modeBitMask | ios_base::in,
               allocator)
    , BaseStream(BaseType::rdbuf())
    {
    }

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_STREAM_MOVE
    basic_istringstream(basic_istringstream&& original);
        // Create a 'basic_istringstream' 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.
#endif

    //! ~basic_istringstream() = default;
        // Destroy this object.

    // MANIPULATORS
#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_STREAM_MOVE
    basic_istringstream& operator=(basic_istringstream&& 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 provided as
        // input by this stream to the specified 'value'.  If 'value' is passed
        // by 'MovableRef', it is left in a valid but unspecified state.
        //
        // Note: implemented inline due to Sun CC compilation error.
    {
        this->rdbuf()->str(value);
    }

#ifdef BSLS_COMPILERFEATURES_SUPPORT_REF_QUALIFIERS
    StringType str() &&;
        // Return the internally buffered sequence of characters maintained by
        // this stream, leaving the stream empty.
#endif

    // ACCESSORS
    StreamBufType *rdbuf() const;
        // Return an address providing modifiable access to the
        // 'basic_stringbuf' object that is internally used by this string
        // stream to buffer unformatted characters.

#ifdef BSLS_COMPILERFEATURES_SUPPORT_REF_QUALIFIERS
    StringType str() const &;
#else
    StringType str() const;
#endif
        // Return the internally buffered sequence of characters maintained by
        // this stream object.

#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 a copy of the internally buffered sequence of characters
        // maintained by this stream object in a 'basic_string' that uses the
        // specified 'allocator'.
        //
        // Note: implemented inline due to Sun CC compilation error.
    {
        return this->rdbuf()->str(allocator);
    }
#endif

    ViewType view() const BSLS_KEYWORD_NOEXCEPT;
        // Return a view of the internally buffered sequence of characters
        // maintained by this stream object.
};

// STANDARD TYPEDEFS
typedef basic_istringstream<char, char_traits<char>, allocator<char> >
                                                                 istringstream;
typedef basic_istringstream<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >
                                                                wistringstream;

// ============================================================================
//                       TEMPLATE FUNCTION DEFINITIONS
// ============================================================================

                          // -------------------------
                          // class basic_istringstream
                          // -------------------------

// CREATORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
basic_istringstream<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::
basic_istringstream(const allocator_type& allocator)
: BaseType(ios_base::in, allocator)
, BaseStream(BaseType::rdbuf())
{
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
basic_istringstream<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::
basic_istringstream(ios_base::openmode    modeBitMask,
                    const allocator_type& allocator)
: BaseType(modeBitMask | ios_base::in, allocator)
, BaseStream(BaseType::rdbuf())
{
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
basic_istringstream<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::
basic_istringstream(const StringType&     initialString,
                    const allocator_type& allocator)
: BaseType(initialString, ios_base::in, allocator)
, BaseStream(BaseType::rdbuf())
{
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
basic_istringstream<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::
basic_istringstream(const StringType&     initialString,
                    ios_base::openmode    modeBitMask,
                    const allocator_type& allocator)
: BaseType(initialString, modeBitMask | ios_base::in, allocator)
, BaseStream(BaseType::rdbuf())
{
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
basic_istringstream<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::
basic_istringstream(BloombergLP::bslmf::MovableRef<StringType> initialString)
: BaseType(MoveUtil::move(initialString), ios_base::in)
, BaseStream(BaseType::rdbuf())
{
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
basic_istringstream<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::
basic_istringstream(BloombergLP::bslmf::MovableRef<StringType> initialString,
                    const allocator_type&                      allocator)
: BaseType(MoveUtil::move(initialString), ios_base::in, allocator)
, BaseStream(BaseType::rdbuf())
{
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
basic_istringstream<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::
basic_istringstream(BloombergLP::bslmf::MovableRef<StringType> initialString,
                    ios_base::openmode                         modeBitMask)
: BaseType(MoveUtil::move(initialString), modeBitMask | ios_base::in)
, BaseStream(BaseType::rdbuf())
{
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
basic_istringstream<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::
basic_istringstream(BloombergLP::bslmf::MovableRef<StringType> initialString,
                    ios_base::openmode                         modeBitMask,
                    const allocator_type&                      allocator)
: BaseType(MoveUtil::move(initialString),
           modeBitMask | ios_base::in,
           allocator)
, BaseStream(BaseType::rdbuf())
{
}

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_STREAM_MOVE
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
basic_istringstream<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::
basic_istringstream(basic_istringstream&& original)
: BaseType(std::move(original))
, BaseStream(std::move(original))
{
    BaseStream::set_rdbuf(BaseType::rdbuf());
}
#endif

// MANIPULATORS
#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_STREAM_MOVE
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
basic_istringstream<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>&
basic_istringstream<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::
operator=(basic_istringstream&& rhs)
{
    this->BaseType::operator=(std::move(rhs));
    this->BaseStream::operator=(std::move(rhs));

    return *this;
}
#endif

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
void basic_istringstream<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::str(
                                                       const StringType& value)
{
    this->rdbuf()->str(value);
}

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
void basic_istringstream<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::str(
                              BloombergLP::bslmf::MovableRef<StringType> value)
{
    this->rdbuf()->str(MoveUtil::move(value));
}

#ifdef BSLS_COMPILERFEATURES_SUPPORT_REF_QUALIFIERS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename basic_istringstream<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::StringType
basic_istringstream<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::str() &&
{
    return std::move(*this->rdbuf()).str();
}
#endif

// ACCESSORS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename
basic_istringstream<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::StreamBufType *
basic_istringstream<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::rdbuf() const
{
    return this->BaseType::rdbuf();
}

#ifdef BSLS_COMPILERFEATURES_SUPPORT_REF_QUALIFIERS
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename basic_istringstream<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::StringType
basic_istringstream<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::str() const &
{
    return this->rdbuf()->str();
}
#else
template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename basic_istringstream<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::StringType
basic_istringstream<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::str() const
{
    return this->rdbuf()->str();
}
#endif

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
inline
typename basic_istringstream<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::ViewType
basic_istringstream<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR>::view()
                                                    const BSLS_KEYWORD_NOEXCEPT
{
    return this->rdbuf()->view();
}

}  // close namespace bsl

// ============================================================================
//                                TYPE TRAITS
// ============================================================================

namespace BloombergLP {
namespace bslma {

template <class CHAR_TYPE, class CHAR_TRAITS, class ALLOCATOR>
struct UsesBslmaAllocator<
        bsl::basic_istringstream<CHAR_TYPE, CHAR_TRAITS, ALLOCATOR> >
    : bsl::true_type
{};

}  // close namespace bslma
}  // close enterprise namespace

#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 ----------------------------------