// bdlb_optionalprinter.h                                             -*-C++-*-
#ifndef INCLUDED_BDLB_OPTIONALPRINTER
#define INCLUDED_BDLB_OPTIONALPRINTER

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

//@PURPOSE: Provide a suite of helper classes for printing `bsl::optional`.
//
//@CLASSES:
//  bdlb::OptionalPrinter: utility for printing `bsl::optional`
//  bdlb::OptionalPrinterUtil: factory for constructing `bdlb::OptionalPrinter`
//
//@DESCRIPTION: This component provides utility classes `bdlb::OptionalPrinter`
// and `bdlb::OptionalPrinterUtil` for printing `bsl::optional`.
//
// The class `bdlb::OptionalPrinter` can also be used with `bsl::format` (it
// defines the `bslfmt::EnableStreamedFormatter` trait).  For information about
// the supported format options see
// [the `bslfmt` package documentation](bslfmt#Streaming-based Formatting).
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Printing `bsl::optional` to a Stream
///- - - - - - - - - - - - - - - - - - - - - - - -
// In this example, we demonstrate how to use `bdlb::OptionalPrinterUtil` to
// print `bsl::optional` to a stream:
// ```
// bsl::optional<int> value(42);
// bsl::cout << bdlb::OptionalPrinterUtil::makePrinter(value);
// ```

#include <bdlscm_version.h>

#include <bdlb_printmethods.h>

#include <bslfmt_enablestreamedformatter.h>
#include <bslmf_nestedtraitdeclaration.h>
#include <bsls_assert.h>

#include <bsl_optional.h>
#include <bsl_ostream.h>

namespace BloombergLP {
namespace bdlb {

                          // ======================
                          // struct OptionalPrinter
                          // ======================

/// Utility for printing `bsl::optional` to standard output streams.  This
/// class has `operator<<` defined for it, so it can be used, for example,
/// in `ball` logs.
template <class TYPE>
class OptionalPrinter {

    // DATA
    const bsl::optional<TYPE>* d_data_p;

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION(OptionalPrinter,
                                   bslfmt::EnableStreamedFormatter);

    // CREATORS

    /// Create `OptionalPrinter` with the specified `data`.
    explicit OptionalPrinter(const bsl::optional<TYPE> *data);

    // ACCESSORS

    /// Format this object to the specified output `stream` at the (absolute
    /// value of) the optionally specified indentation `level` and return a
    /// reference to `stream`.  If `level` is specified, optionally specify
    /// `spacesPerLevel`, the number of spaces per indentation level for
    /// this and all of its nested objects.  If `level` is negative,
    /// suppress indentation of the first line.  If `spacesPerLevel` is
    /// negative, format the entire output on one line, suppressing all but
    /// the initial indentation (as governed by `level`).  If `stream` is
    /// not valid on entry, this operation has no effect.
    bsl::ostream& print(bsl::ostream&              stream,
                        int                        level          = 0,
                        int                        spacesPerLevel = 4) const;
};

// FREE OPERATORS

/// Write the value of the specified `printer` object to the specified
/// output `stream` in a single-line format, and return a reference to
/// `stream`.  If `stream` is not valid on entry, this operation has no
/// effect.  Note that this human-readable format is not fully specified,
/// can change without notice, and is logically equivalent to:
/// ```
/// print(stream, 0, -1);
/// ```
template <class TYPE>
bsl::ostream&
operator<<(bsl::ostream& stream, const OptionalPrinter<TYPE>& printer);

                          // ==========================
                          // struct OptionalPrinterUtil
                          // ==========================

/// This utility `struct` provides a namespace for a function that creates a
/// `bdlb::OptionalPrinter` with its template argument deduced from a given
/// instance of `bsl::optional`.
struct OptionalPrinterUtil {
  public:
    // CLASS METHODS

    /// Return an `OptionalPrinter` that prints the specified `data`.
    template <class TYPE>
    static OptionalPrinter<TYPE> makePrinter(const bsl::optional<TYPE>& data);
};

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

                          // ----------------------
                          // struct OptionalPrinter
                          // ----------------------

// CREATORS
template <class TYPE>
OptionalPrinter<TYPE>::OptionalPrinter(const bsl::optional<TYPE>* data)
: d_data_p(data)
{
    BSLS_ASSERT(data);
}

// ACCESSORS
template <class TYPE>
bsl::ostream& OptionalPrinter<TYPE>::print(bsl::ostream& stream,
                                           int           level,
                                           int           spacesPerLevel) const
{
    if (!d_data_p->has_value()) {
        return bdlb::PrintMethods::print(stream,
                                         "NULL",
                                         level,
                                         spacesPerLevel);             // RETURN
    }

    return bdlb::PrintMethods::print(stream,
                                     *(*d_data_p),
                                     level,
                                     spacesPerLevel);
}

                          // --------------------------
                          // struct OptionalPrinterUtil
                          // --------------------------

// CLASS METHODS
template <class TYPE>
OptionalPrinter<TYPE>
OptionalPrinterUtil::makePrinter(const bsl::optional<TYPE>& data)
{
    return OptionalPrinter<TYPE>(&data);
}

}  // close package namespace

// FREE OPERATORS
template <class TYPE>
bsl::ostream& bdlb::operator<<(bsl::ostream&                      stream,
                               const bdlb::OptionalPrinter<TYPE>& object)
{
    return object.print(stream, 0, -1);
}

}  // close enterprise namespace

#endif  // INCLUDED_BDLB_OPTIONALPRINTER

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