// bdlsb_fixedmeminstreambuf.h                                        -*-C++-*-
#ifndef INCLUDED_BDLSB_FIXEDMEMINSTREAMBUF
#define INCLUDED_BDLSB_FIXEDMEMINSTREAMBUF

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

//@PURPOSE: Provide an input 'basic_streambuf' using a client buffer.
//
//@CLASSES:
//   bdlsb::FixedMemInStreamBuf: input stream buffer using client memory
//
//@SEE_ALSO: bdlsb_fixedmemoutstreambuf, bdlsb_memoutstreambuf
//
//@DESCRIPTION: This component defines a class, 'bdlsb::FixedMemInStreamBuf',
// that implements the input portion of the 'bsl::basic_streambuf' protocol
// using a client-supplied memory buffer.  Method names necessarily correspond
// to the protocol-specified method names.  Clients supply the character buffer
// at stream buffer construction, and can later reinitialize the stream buffer
// with a different character buffer by calling the 'pubsetbuf' method.
//
// This component provides none of the output-related functionality of
// 'basic_streambuf' (see Streaming Architecture, below), nor does it use
// locales in any way.
//
///Streaming Architecture
///----------------------
// Stream buffers are designed to decouple device handling from content
// formatting, providing the requisite device handling and possible buffering
// services, and leaving the formatting to the client stream.  The standard
// C++ IOStreams library further partitions streaming into input streaming and
// output streaming, separating responsibilities for each at both the stream
// layer and the stream buffer layer.  The BDE streaming library for 'bdex',
// including all of 'bdlsb', follows this model.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Basic Use of the 'bdlsb::FixedMemInStreamBuf'
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// 'bdlsb::FixedMemInStreamBuf' can be used in situations when you already
// have an array of bytes in memory and you'd like to wrap it in an input
// stream to extract data in a formatted manner.  A
// 'bdlsb::FixedMemInStreamBuf' object refers to an externally managed buffer
// that is supplied either at construction, or using the 'pubsetbuf' method of
// the 'bsl::streambuf' base-class.
//
// First, we create an array of characters to provide data that needs to be
// parsed, and construct 'bdlsb::FixedMemInStreamBuf' on that array:
//..
//  {
//      const char *inputText = "1 1 2 3 5 8 13 21";
//      bdlsb::FixedMemInStreamBuf buffer(inputText, strlen(inputText));
//..
// Notice that 'bdlsb::FixedMemInStreamBuf' can be used with buffers referring
// to stack memory or to heap memory.
//
// Then, we use 'buffer' to construct a 'bsl::istream':
//..
//      bsl::istream stream(&buffer);
//..
// Finally, we can input the data from the stream in a formatted manner:
//..
//      int value;
//      while (stream >> value) {
//          cout << "Value is: " << value << endl;
//      }
//  }
//..
//
///Example 2: Scanning Input Data
/// - - - - - - - - - - - - - - -
// This example illustrates scanning of the input stream buffer for particular
// pattern ( digits, in our case ) and then using stream to read out found
// number.
//
// First, we create an array of characters to provide data that needs to be
// parsed, and construct 'bdlsb::FixedMemInStreamBuf' on that array:
//..
//  {
//      const char *inputText = "The answer is: 42.";
//      bdlsb::FixedMemInStreamBuf buffer(inputText, strlen(inputText));
//..
// Then, we use 'buffer' to construct a 'bsl::istream' that will be used later
// to read found number:
//..
//      bsl::istream stream(&buffer);
//..
// Next, we scan input buffer one character at a time searching for the first
// digit:
//..
//      char ch;
//      do {
//          ch = static_cast<char>(buffer.sbumpc());
//
//          if ( (ch >= '0') && (ch <= '9') ) {
//..
// Now, when the digit character is found, we return the first digit into the
// input stream buffer for subsequent read:
//..
//              buffer.sputbackc(ch);
//              int n;
//..
// Finally, we read out the whole number:
//..
//              stream >> n;
//              assert( 42 == n );
//              cout << "The answer is " << n << " indeed..." << endl;
//              break;
//          }
//      } while ( ch != EOF );
//  }
//..

#include <bdlscm_version.h>

#include <bsls_assert.h>
#include <bsls_platform.h>
#include <bsls_review.h>

#include <bsl_cstring.h>
#include <bsl_ios.h>       // for 'bsl::streamsize'
#include <bsl_streambuf.h>

#if defined(BSLS_PLATFORM_CMP_MSVC) && defined(min)
    // Note: on Windows -> WinDef.h:#define min(a,b) ...
#undef min
#endif

namespace BloombergLP {
namespace bdlsb {

                       // =========================
                       // class FixedMemInStreamBuf
                       // =========================

class FixedMemInStreamBuf : public bsl::streambuf {
    // This class implements the input functionality of the 'basic_streambuf'
    // protocol, using client-supplied 'char *' memory.

    // DATA
    char            *d_buffer_p;      // buffer (held, not owned)
    bsl::size_t      d_bufferSize;    // length of buffer

    // NOT IMPLEMENTED
    FixedMemInStreamBuf(const FixedMemInStreamBuf&);
    FixedMemInStreamBuf& operator=(const FixedMemInStreamBuf&);

  protected:
    // PROTECTED MANIPULATORS
    virtual pos_type seekoff(
                            off_type                offset,
                            bsl::ios_base::seekdir  way,
                            bsl::ios_base::openmode which = bsl::ios_base::in);
        // Set the position indicator to the relative specified 'offset' from
        // the base position indicated by the specified 'way' and return the
        // resulting absolute position on success or pos_type(-1) on failure.
        // Optionally specify 'which' area of the stream buffer.  The seek
        // operation will fail if 'which' does not include the flag
        // 'bsl::ios_base::in' or if the resulting absolute position is less
        // than zero or greater than the value returned by 'length'.

    virtual pos_type seekpos(
                            pos_type                position,
                            bsl::ios_base::openmode which = bsl::ios_base::in);
        // Set the position indicator to the specified 'position' and return
        // the resulting absolute position on success or pos_type(-1) on
        // failure.  Optionally specify 'which' area of the stream buffer.  The
        // 'seekpos' operation will fail if 'which' does not include the flag
        // 'bsl::ios_base::in' or if position is less then zero or greater
        // than the value returned by 'length'.

    virtual FixedMemInStreamBuf *setbuf(char  *buffer, bsl::streamsize length);
    FixedMemInStreamBuf *setbuf(const char *buffer, bsl::streamsize length);
        // Reinitialize this stream buffer to use the specified character
        // 'buffer' having the specified 'length'.  Return the pointer
        // providing modifiable access to this stream buffer.  The behavior is
        // undefined unless 'buffer != 0 && length > 0' or 'length == 0'.  Upon
        // re-initialization for use of the new buffer, neither the content nor
        // the next input position indicator are preserved.  Note that 'buffer'
        // is held but not owned.

    virtual bsl::streamsize showmanyc();
        // Return the number of characters currently available for reading
        // from this stream buffer, or -1 if there are none.

    virtual bsl::streamsize xsgetn(char_type       *destination,
                                   bsl::streamsize  length);
        // Read the specified 'length' number of characters into the specified
        // 'destination'.  Return the number of characters successfully read.
        // The behavior is undefined unless '0 <= length'.

  public:
    // CREATORS
    FixedMemInStreamBuf(const char *buffer, bsl::size_t length);
        // Create a 'FixedMemInStreamBuf' that provides access to the character
        // sequence in the specified 'buffer' of the specified 'length'.  The
        // behavior is undefined unless 'buffer != 0 && length > 0' or
        // 'length == 0'.

    ~FixedMemInStreamBuf();
        // Destroy this stream buffer.

    // MANIPULATORS
    FixedMemInStreamBuf *pubsetbuf(char            *buffer,
                                   bsl::streamsize  length);
    FixedMemInStreamBuf *pubsetbuf(const char      *buffer,
                                   bsl::streamsize  length);
        // Reinitialize this stream buffer to use the specified character
        // 'buffer' having the specified 'length'.  Return the address of this
        // modifiable stream buffer.  The behavior is undefined unless
        // 'buffer != 0 && length > 0' or 'length == 0'.  Upon reinitialization
        // for use of the new buffer, neither the content nor the next input
        // position indicator is preserved.  Note that 'buffer' is held but not
        // owned.

    // ACCESSORS
    const char *data() const;
        // Return the address of the non-modifiable character buffer held by
        // this stream buffer.

    bsl::size_t length() const;
        // Return the number of characters from the current input position to
        // the end of the stream buffer.  The function returns the same value
        // as 'seekoff(0, bsl::ios_base::beg)'.  The length is modified by a
        // call to 'seekpos', 'seekoff' or by reading characters from the
        // buffer.
};

// ============================================================================
//                              INLINE DEFINITIONS
// ============================================================================

                       // -------------------------
                       // class FixedMemInStreamBuf
                       // -------------------------

// PROTECTED MANIPULATORS
inline
FixedMemInStreamBuf::pos_type
FixedMemInStreamBuf::seekpos(pos_type                position,
                             bsl::ios_base::openmode which)
{
    return seekoff(static_cast<off_type>(position), bsl::ios_base::beg, which);
}


inline
FixedMemInStreamBuf *FixedMemInStreamBuf::setbuf(char            *buffer,
                                                 bsl::streamsize  length)

{
    BSLS_ASSERT(buffer || 0 == length);
    BSLS_ASSERT(0 <= length);

    // Reset pointers and length.
    d_buffer_p    = buffer;
    d_bufferSize  = static_cast<bsl::size_t>(length);
    setg(d_buffer_p, d_buffer_p, d_buffer_p + d_bufferSize);
    return this;
}

inline
FixedMemInStreamBuf *FixedMemInStreamBuf::setbuf(const char      *buffer,
                                                 bsl::streamsize  length)
{
    BSLS_ASSERT(buffer || 0 == length);
    BSLS_ASSERT(0 <= length);

    return setbuf(const_cast<char *>(buffer), length);
}

inline
bsl::streamsize FixedMemInStreamBuf::showmanyc()
{
    bsl::streamsize numChars = egptr() - gptr();
    if (0 == numChars) {
        return -1;                                                    // RETURN
    }
    return numChars;
}

inline
bsl::streamsize FixedMemInStreamBuf::xsgetn(char_type       *destination,
                                            bsl::streamsize  length)
{
    BSLS_ASSERT(destination);
    BSLS_ASSERT(0 <= length);

    bsl::streamsize charsLeft = egptr() - gptr();

    bsl::streamsize canCopy = charsLeft < length ? charsLeft : length;

    bsl::memcpy(destination, gptr(), static_cast<bsl::size_t>(canCopy));
    gbump(static_cast<int>(canCopy));
    return canCopy;
}

// CREATORS
inline
FixedMemInStreamBuf::FixedMemInStreamBuf(const char  *buffer,
                                         bsl::size_t  length)
: d_buffer_p(const_cast<char *>(buffer))
, d_bufferSize(length)
{
    BSLS_ASSERT(buffer || 0 == length);

    setg(d_buffer_p, d_buffer_p, d_buffer_p + d_bufferSize);
}

inline
FixedMemInStreamBuf::~FixedMemInStreamBuf()
{
}

// MANIPULATORS
inline
FixedMemInStreamBuf *FixedMemInStreamBuf::pubsetbuf(const char     *buffer,
                                                    bsl::streamsize length)
{
    BSLS_ASSERT(buffer || 0 == length);
    BSLS_ASSERT(0 <= length);

    return setbuf(buffer, length);
}

inline
FixedMemInStreamBuf *FixedMemInStreamBuf::pubsetbuf(char           *buffer,
                                                    bsl::streamsize length)
{
    BSLS_ASSERT(buffer || 0 == length);
    BSLS_ASSERT(0 <= length);

    return setbuf(buffer, length);
}

// ACCESSORS
inline
const char *FixedMemInStreamBuf::data() const
{
    return d_buffer_p;
}

inline
bsl::size_t FixedMemInStreamBuf::length() const
{
    return egptr() - gptr();
}

}  // close package namespace
}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2015 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 ----------------------------------