// 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_keyword.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
                       // ==========================

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

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

  protected:
    // PROTECTED MANIPULATORS

    /// 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`.
    pos_type seekoff(off_type                offset,
                     bsl::ios_base::seekdir  fixedPosition,
                     bsl::ios_base::openmode which = bsl::ios_base::out)
                                                         BSLS_KEYWORD_OVERRIDE;

    /// 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`.
    pos_type seekpos(pos_type                position,
                     bsl::ios_base::openmode which = bsl::ios_base::out)
                                                         BSLS_KEYWORD_OVERRIDE;

    FixedMemOutStreamBuf *setbuf(char_type       *buffer,
                                 bsl::streamsize  length)
                                                         BSLS_KEYWORD_OVERRIDE;
        // 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

    /// 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(char            *buffer,
                         bsl::streamsize  length);

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

    // MANIPULATORS

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

    // ACCESSORS

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

    /// Return a pointer providing non-modifiable access to the character
    /// buffer held by this stream buffer (supplied at construction).
    const char *data() 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`.
    bsl::streamsize length() const;
};

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