// bdlsb_fixedmemoutstreambuf.h                                       -*-C++-*-
#ifndef INCLUDED_BDLSB_FIXEDMEMOUTSTREAMBUF
#define INCLUDED_BDLSB_FIXEDMEMOUTSTREAMBUF

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

//@PURPOSE: Provide an output 'basic_streambuf' using a client buffer.
//
//@CLASSES:
//   bdlsb::FixedMemOutStreamBuf: output stream buffer using client memory
//
//@SEE_ALSO: bdlsb_memoutstreambuf, bdlsb_fixedmeminstreambuf
//
//@DESCRIPTION: This component defines a class 'bdlsb::FixedMemOutStreamBuf'
// that implements the output 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 input-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 'bdesb', follows this model.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Directly Observing Stream Buffer Contents
/// - - - - - - - - - - - - - - - - - - - - - - - - - -
// Unlike most implementations of the 'bsl::basic_streambuf' concept,
// 'bdlsb::FixedMemOutStreamBuf' gives the user direct access to the stream's
// storage, both through the 'data' accessor and through the buffer originally
// supplied to the constructor.  Note that this can be useful in many contexts,
// such as when we need to perform extra security validation on buffer during
// the streaming process.
//
// First, we create an array to provide storage for the stream buffer, and
// construct a 'bdlsb::FixedMemOutStreamBuf' on that array:
//..
//  const int                   STORAGE_SIZE = 64;
//  char                        storage[STORAGE_SIZE];
//  bdlsb::FixedMemOutStreamBuf buffer(storage, STORAGE_SIZE);
//..
// Notice that 'storage' is on the stack.  'bdlsb::FixedMemOutStreamBuf' can be
// easily used without resorting to dynamic memory allocation.
//
// Then, we observe that 'buffer' already has a capacity of 64.  Note that this
// capacity is fixed at construction:
//..
//  assert(STORAGE_SIZE == buffer.capacity());
//  assert( 0 == buffer.length());
//  assert(buffer.data() == storage);
//..
// Next, we use 'buffer' to construct a 'bsl::ostream':
//..
//  bsl::ostream stream(&buffer);
//..
// Now, we output some data to the 'stream':
//..
//  stream << "The answer is " << 42 << ".";
//..
// Finally, we observe that the data is present in the storage array that we
// supplied to 'buffer':
//..
//  assert(17 == buffer.length());
//  assert(buffer.length() < STORAGE_SIZE);
//  assert(0 == strncmp("The answer is 42.", storage, 17));
//..
//
///Example 2: Fixed Buffer Size
/// - - - - - - - - - - - - - -
// Unlike most implementations of the 'bsl::basic_streambuf' concept,
// 'bdlsb::FixedMemOutStreamBuf' uses a buffer of limited size, provided to the
// constructor together with the address of the storage buffer.  That limit
// will not be exceeded even in case of superfluous data.  Symbols beyond this
// limit will be ignored.  Note that this can be useful if memory allocation
// should be strictly controlled.
//
// First, we create an array to provide storage for the stream buffer, fill it
// with some data and construct a 'bdlsb::FixedMemOutStreamBuf' on the part of
// that array:
//..
//  const unsigned int SMALL_STORAGE_SIZE = 16;
//  const unsigned int SMALL_BUFFER_CAPACITY = SMALL_STORAGE_SIZE/2;
//  char               smallStorage[SMALL_STORAGE_SIZE];
//  memset(smallStorage, 'Z', SMALL_STORAGE_SIZE);
//
//  bdlsb::FixedMemOutStreamBuf smallBuffer(smallStorage,
//                                          SMALL_BUFFER_CAPACITY);
//..
// Next, we write some characters to the buffer and check that it handles them
// correctly and superfluous data is ignored:
//..
//  bsl::streamsize returnedSize = smallBuffer.sputn("The answer is 42.", 17);
//  assert(SMALL_BUFFER_CAPACITY == returnedSize);
//  assert(SMALL_BUFFER_CAPACITY == smallBuffer.length());
//  assert('Z' == smallStorage[smallBuffer.length()]);
//..
// Then, we reset position indicator to the beginning of storage:
//..
//  smallBuffer.pubseekpos(0,bsl::ios_base::out);
//  assert(0 == smallBuffer.length());
//..
// Now, we write another string, containing fewer characters than the storage
// capacity:
//..
//  returnedSize = smallBuffer.sputn("Truth.", 6);
//..
// Finally, we observe that given string has been successfully placed to
// buffer:
//..
//  assert(6 == returnedSize);
//  assert(6 == smallBuffer.length());
//  assert(0 == strncmp("Truth.", smallStorage, 6));
//..

#include <bdlscm_version.h>

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

#include <bsl_cstdlib.h>
#include <bsl_cstring.h>
#include <bsl_ios.h>
#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 FixedMemOutStreamBuf
                       // ==========================

class FixedMemOutStreamBuf : public bsl::streambuf {
    // This class implements the output functionality of the 'basic_streambuf'
    // protocol for client-supplied memory.

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

  protected:
    // PROTECTED MANIPULATORS
    virtual pos_type seekoff(
                           off_type                offset,
                           bsl::ios_base::seekdir  fixedPosition,
                           bsl::ios_base::openmode which = bsl::ios_base::out);
        // Set the position indicator to the relative specified 'offset' from
        // the base position indicated by the specified 'fixedPosition' 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::out' 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::out);
        // 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::out' or if position is less then zero or greater
        // than the value returned by 'length'.

    virtual FixedMemOutStreamBuf *setbuf(char_type       *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
        // 'length == 0' or 'length > 0 && buffer != 0'.  Upon
        // re-initialization for use of the new buffer, the length and next
        // output location are reset to zero.  Note that 'buffer' is held but
        // not owned.

  public:
    // CREATORS
    FixedMemOutStreamBuf(char            *buffer,
                         bsl::streamsize  length);
        // Create an empty stream buffer that uses the specified character
        // 'buffer' of the specified 'length'.  The behavior is undefined
        // unless 'length == 0' or 'length > 0 && buffer != 0'.
        // Note that 'buffer' is held but not owned.

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

    // MANIPULATORS
    char *data();
        // Return a pointer providing modifiable access to the character buffer
        // held by this stream buffer (supplied at construction).

    // ACCESSORS
    bsl::streamsize capacity() const;
        // Return the number of characters in the buffer held by this stream
        // buffer.  See 'length', below, for the span of bytes actually
        // written.

    const char *data() const;
        // Return a pointer providing non-modifiable access to the character
        // buffer held by this stream buffer (supplied at construction).

    bsl::streamsize length() const;
        // Return the number of characters from the beginning of the buffer to
        // the current write position.  This function returns the same value
        // as 'seekoff(0, bsl::ios_base::end)'.  The length is modified by a
        // call to 'seekpos' or 'seekoff' and reset to zero by a call to
        // 'pubsetbuf'.
};

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

                       // --------------------------
                       // class FixedMemOutStreamBuf
                       // --------------------------

// PROTECTED MANIPULATORS
inline
FixedMemOutStreamBuf *
FixedMemOutStreamBuf::setbuf(char_type *buffer, bsl::streamsize length)
{
    BSLS_ASSERT(buffer || 0 == length);
    BSLS_ASSERT(0 <= length);

    // Reset pointers and length.
    setp(buffer, buffer + length);
    return this;
}

// CREATORS
inline
FixedMemOutStreamBuf::FixedMemOutStreamBuf(char            *buffer,
                                           bsl::streamsize  length)
{
    BSLS_ASSERT(buffer || 0 == length);
    BSLS_ASSERT(0 <= length);

    setp(buffer, buffer + length);
}

inline
FixedMemOutStreamBuf::~FixedMemOutStreamBuf()
{
}

// MANIPULATORS
inline
char *FixedMemOutStreamBuf::data()
{
    return pbase();
}

// ACCESSORS
inline
bsl::streamsize FixedMemOutStreamBuf::capacity() const
{
    return epptr() - pbase();
}

inline
const char *FixedMemOutStreamBuf::data() const
{
    return pbase();
}

inline
bsl::streamsize FixedMemOutStreamBuf::length() const
{
    return pptr() - pbase();
}

}  // 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 ----------------------------------