/*  reducer_ostream.h                  -*- C++ -*-
 *
 *  Copyright (C) 2009-2018 Intel Corporation.  All Rights Reserved.
 *
 *  The source code contained or described herein and all documents related
 *  to the source code ("Material") are owned by Intel Corporation or its
 *  suppliers or licensors.  Title to the Material remains with Intel
 *  Corporation or its suppliers and licensors.  The Material is protected
 *  by worldwide copyright laws and treaty provisions.  No part of the
 *  Material may be used, copied, reproduced, modified, published, uploaded,
 *  posted, transmitted, distributed, or disclosed in any way without
 *  Intel's prior express written permission.
 *
 *  No license under any patent, copyright, trade secret or other
 *  intellectual property right is granted to or conferred upon you by
 *  disclosure or delivery of the Materials, either expressly, by
 *  implication, inducement, estoppel or otherwise.  Any license under such
 *  intellectual property rights must be express and approved by Intel in
 *  writing.
 */

/** @file reducer_ostream.h
 *
 *  @brief Defines a class for writing to an ostream in parallel.
 *
 *  @ingroup ReducersOstream
 *
 *  @see @ref ReducersOstream
 */

#ifndef REDUCER_OSTREAM_H_INCLUDED
#define REDUCER_OSTREAM_H_INCLUDED

#include <cilk/reducer.h>
#include <ostream>
#include <sstream>

/** @defgroup ReducersOstream Ostream Reducers
 *
 *  Ostream reducers allow multiple strands to write to an ostream in parallel.
 *
 *  @ingroup Reducers
 *
 *  You should be familiar with @ref pagereducers "Intel(R) Cilk(TM) Plus reducers",
 *  described in file reducers.md, and particularly with @ref reducers_using,
 *  before trying to use the information in this file.
 *
 *  @section redostream_usage Usage Example
 *
 *  One of the most common debugging techniques is adding `print` statements
 *  to the code being debugged. When the code is parallelized, the results can
 *  be less than satisfactory, as output from multiple strands is mingled in an
 *  unpredictable way. Like other reducers, an ostream reducer requires minimal
 *  recoding to guarantee that the output from parallelized computation will be
 *  ordered the same as though the computation were executed serially.
 *
 *      cilk::reducer<cilk::op_ostream> r(std::cerr);
 *      cilk_for (int i = 0; i != data.size(); ++i) {
 *          *r << "Iteration " << i << ":\n";
 *          ... some computation ...
 *          *r << "   Step 1:" << some information;
 *          ... some more computation ...
 *          *r << "   Step 2:" << some more information;
 *          ... still more computation ...
 *          *r << "   Step 3:" << still more information;
 *      }
 *
 *  Output on standard error:
 *
 *      Iteration 1:
 *          Step 1: ...
 *          Step 2: ...
 *          Step 3: ...
 *      Iteration 2:
 *          Step 1: ...
 *          Step 2: ...
 *          Step 3: ...
 *      Iteration 3:
 *          Step 1: ...
 *          Step 2: ...
 *          Step 3: ...
 *      ...
 *
 *  @section redostream_overview Overview
 *
 *  An "ostream reducer" is not really a reducer. It uses the reducer
 *  technology to coordinate operations on parallel strands to achieve
 *  the same behavior in a parallel computation that would be seen in a
 *  serial computation, but it does not have a monoid. It has a "monoid
 *  class," because that is part of the implementation framework, but it
 *  does not represent a mathematical monoid: there is no value type, no
 *  associative operation, and no identity value. The reducer is used for
 *  its side effect rather than to construct a value.
 *
 *  You might think of an ostream reducer as a relative of a
 *  @ref ReducersString "string reducer" which uses stream output
 *  syntax (`stream << value`) instead of string append syntax
 *  (`string += value`), and which writes its result string to an
 *  ostream instead of making it available as the reducer value.
 *
 *  Another difference is that "real" reducers protect their contained
 *  value quite strongly from improper access by the user. Ostream reducers,
 *  on the other hand, pretty much have to expose the ostream, since normal
 *  use of an ostream involves accessing its internal state. Furthermore,
 *  the ostream reducer just coordinates output to an existing ostream -
 *  there is nothing to keep the user from writing directly to the attached
 *  stream, with unpredictable results.
 *
 *  @section redostream_operations Operations
 *
 *  In the operation descriptions below, the type name `Ostream` refers to the
 *  reducer's ostream type, `std::basic_ostream<Char, Traits>`.
 *
 *  @subsection redostream_constructors Constructors
 *
 *  The only constructor is
 *
 *      reducer(const Ostream& os)
 *
 *  This creates a reducer that is associated with the existing ostream `os`.
 *  Anything "written to" the reducer will (eventually) be written to `os`.
 *
 *  @subsection redostream_get_set Set and Get
 *
 *  Just as a stream does not have a "value," neither does an ostream
 *  reducer. Therefore, none of the usual `set_value`, `get_value`,
 *  `move_in`, or `move_out` functions are available for ostream reducers.
 *
 *  @subsection redostream_initial Initial Values
 *
 *  Ostream reducers do not have default constructors.
 *
 *  @subsection redostream_view_ops View Operations
 *
 *  An ostream reducer view is actually a kind of `std::ostream`. Therefore,
 *  any operation that can be used on an ostream can be used on an ostream
 *  reducer view. For example:
 *
 *      reducer<op_ostream> r(cout);
 *      *r << setw(5) << (x=1) << endl;
 *
 *
 *  @section redostream_performance Performance Considerations
 *
 *  Ostream reducers work by creating a string stream for each non-leftmost
 *  view. When two strands are merged, the contents of the string buffer of the
 *  right view are written to the left view. Since all non-leftmost strands are
 *  eventually merged, all output is eventually written to the associated
 *  ostream.
 *
 *  This implementation has two consequences.
 *
 *  First, all output written to an ostream reducer on a stolen strand is kept
 *  in memory (in a string buffer) until the strand is merged with the leftmost
 *  strand. This means that some portion of the output written to an ostream
 *  reducer during a parallel computation - half of the total output, on
 *  average - will temporarily be held in memory during the computation.
 *  Obviously, ostream reducers will work better for small and moderate amounts
 *  of output.
 *
 *  Second, buffered ostream reducer content must be copied at every merge.
 *  The total amount of copying is potentially proportional to the total amount
 *  of output multiplied by the number of strands stolen during the computation.
 *
 *  In short, writing to an ostream in a parallel computation with an ostream
 *  reducer will always be less efficient than writing the same output directly
 *  to the ostream in a serial computation. The value of the ostream
 *  reducer is not in the writing of the ostream itself, but in removing the
 *  race and serialization obstacles that the ostream output would cause in an
 *  otherwise parallelizable computation.
 *
 *
 *  @section redostream_state Stream State
 *
 *  The reducer implementation can correctly order the output that is written
 *  to an ostream. However, an ostream has additional state that controls its
 *  behavior, such as its formatting attributes, error state, extensible arrays, *  and registered callbacks. If these are modified during the computation, the *  reducer implementation cannot guarantee that they will be the same in a
 *  parallel computation as in a serial computation. In particular:
 *
 *  -   In the serial execution, the ostream state in the continuation of a
 *      spawn will be the same as the state at the end of the spawned function.
 *      In the parallel execution, if the continuation is stolen, its view will
 *      contain a newly created ostream with the default initial state.
 *  -   In the serial execution, the ostream state following a sync is the same
 *      as the state before the sync. In the parallel execution, if the
 *      continuation is stolen, then the state following the sync will be the
 *      same as the state at the end of some spawned function.
 *
 *  In short, you must not make any assumptions about the stream state of an
 *  ostream reducer:
 *
 *  -   Following a `cilk_spawn`.
 *  -   Following a `cilk_sync`.
 *  -   At the start of an iteration of a `cilk_for` loop.
 *  -   Following the completion of a `cilk_for` loop.
 *
 *  @section redostream_types Type and Operator Requirements
 *
 *  `std::basic_ostream<Char, Traits>` must be a valid type.
*/

namespace cilk {

/** @ingroup ReducersOstream */
//@{

/** The ostream reducer view class.
 *
 *  This is the view class for reducers created with
 *  `cilk::reducer< cilk::op_basic_ostream<Char, Traits> >`. It holds the
 *  actual ostream for a parallel strand, and allows only stream output
 *  operations to be performed on it.
 *
 *  @note   The reducer "dereference" operation (`reducer::operator *()`)
 *          yields a reference to the view. Thus, for example, the view
 *          class's `<<` operation would be used in an expression like
 *          `*r << "x = " << x`, where `r` is an ostream reducer.
 *
 *  @tparam Char        The ostream element type (not the ostream type).
 *  @tparam Traits      The character traits type.
 *
 *  @see ReducersOstream
 *  @see op_basic_ostream
 */
template<typename Char, typename Traits>
class op_basic_ostream_view : public std::basic_ostream<Char, Traits>
{
    typedef std::basic_ostream<Char, Traits>  base;
    typedef std::basic_ostream<Char, Traits>  ostream_type;

    // A non-leftmost view is associated with a private string buffer. (The
    // leftmost view is associated with the buffer of the reducer's associated
    // ostream, so its private buffer is unused.)
    //
    std::basic_stringbuf<Char, Traits> m_buffer;

public:

    /** Value type. Required by @ref monoid_with_view.
     */
    typedef ostream_type value_type;

    /** Reduce operation. Required by @ref monoid_with_view.
     */
    void reduce(op_basic_ostream_view* other)
    {
        // Writing an empty buffer results in failure. Testing `sgetc()` is the
        // easiest way of checking for an empty buffer.
        if (other->m_buffer.sgetc() != Traits::eof()) {
            *this << (&other->m_buffer);
        }
    }

    /** Non-leftmost (identity) view constructor. The view is associated with
     *  its internal buffer. Required by @ref monoid_base.
     */
    op_basic_ostream_view() : base(&m_buffer) {}

    /** Leftmost view constructor. The view is associated with an existing
     *  ostream.
     */
    op_basic_ostream_view(const ostream_type& os) : base(0)
    {
        base::rdbuf(os.rdbuf());       // Copy stream buffer
        base::flags(os.flags());       // Copy formatting flags
        base::setstate(os.rdstate());  // Copy error state
    }

    /** Sets/gets.
     *
     *  These are all no-ops.
     */
    //@{

    void view_set_value(const value_type&)
        { assert("set_value() is not allowed on ostream reducers" && 0); }
    const value_type& view_get_value() const
        { assert("get_value() is not allowed on ostream reducers" && 0);
          return *this; }
    typedef value_type const& return_type_for_get_value;
    void view_move_in(const value_type&)
        { assert("move_in() is not allowed on ostream reducers" && 0); }
    void view_move_out(const value_type&)
        { assert("move_out() is not allowed on ostream reducers" && 0); }

    //@}
};

/** Ostream monoid class. Instantiate the cilk::reducer template class with an
 *  op_basic_ostream monoid to create an ostream reducer class:
 *
 *      cilk::reducer< cilk::op_basic_string<char> > r;
 *
 *  @tparam Char        The stream element type (not the stream type).
 *  @tparam Traits      The character traits type.
 *
 *  @see ReducersOstream
 *  @see op_basic_ostream_view
 *  @see reducer_ostream
 *  @see op_ostream
 *  @see op_wostream
 */
template<typename Char,
         typename Traits = std::char_traits<Char>,
         bool     Align = false>
class op_basic_ostream :
    public monoid_with_view< op_basic_ostream_view<Char, Traits>, Align >
{
    typedef monoid_with_view< op_basic_ostream_view<Char, Traits>, Align >
            base;
    typedef std::basic_ostream<Char, Traits>            ostream_type;
    typedef provisional_guard<typename base::view_type> view_guard;

public:

    /** View type of the monoid.
     */
    typedef typename base::view_type view_type;

    /** @name Construct function.
     *
     *  The only supported ostream reducer constructor takes a reference to
     *  an existing ostream.
     *
     *  @param os   The ostream destination for receive all data written to the
     *              reducer.
     */
    static void construct(
        op_basic_ostream*   monoid,
        view_type*          view,
        const ostream_type& os)
    {
        view_guard vg( new((void*) view) view_type(os) );
        vg.confirm_if( new((void*) monoid) op_basic_ostream );
    }
};


/**
 *  Convenience typedef for narrow ostreams.
 */
typedef op_basic_ostream<char> op_ostream;

/**
 *  Convenience typedef for wide ostreams.
 */
typedef op_basic_ostream<wchar_t> op_wostream;

/// @cond internal

class reducer_ostream;

/** Metafunction specialization for reducer conversion.
 *
 *  This specialization of the @ref legacy_reducer_downcast template class
 *  defined in reducer.h causes the `reducer<op_basic_ostream<char> >` class
 *  to have an `operator reducer_ostream& ()` conversion operator that
 *  statically downcasts the `reducer<op_basic_ostream<char> >` to
 *  `reducer_ostream`. (The reverse conversion, from `reducer_ostream` to
 *  `reducer<op_basic_ostream<char> >`, is just an upcast, which is provided
 *  for free by the language.)
 */
template<bool Align>
struct legacy_reducer_downcast<
    reducer<op_basic_ostream<char, std::char_traits<char>, Align> > >
{
    typedef reducer_ostream type;
};

/// @endcond

/** Deprecated ostream reducer class.
 *
 *  reducer_ostream is the same as @ref cilk::reducer<@ref op_ostream>, except
 *  that reducer_ostream is a proxy for the contained view, so that ostream
 *  operations can be applied directly to the reducer. For example, a number is
 *  written to a `reducer<op_ostream>` with `*r << x`, but a number can be
 *  written to a `reducer_ostream` with `r << x`.
 *
 *  @deprecated Users are strongly encouraged to use `reducer<monoid>`
 *              reducers rather than the old wrappers like reducer_ostream. The
 *              `reducer<monoid>` reducers show the reducer/monoid/view
 *              architecture more clearly, are more consistent in their
 *              implementation, and present a simpler model for new
 *              user-implemented reducers.
 *
 *  @note   Implicit conversions are provided between `%reducer_ostream`
 *          and `reducer<%op_ostream>`. This allows incremental code
 *          conversion: old code that used  `%reducer_ostream` can pass a
 *          `%reducer_ostream` to a converted function that now expects a
 *          pointer or reference to a `reducer<%op_ostream>`, and vice versa.
 *
 *  @tparam Char        The stream element type (not the stream type).
 *  @tparam Traits      The character traits type.
 *
 *  @see op_ostream
 *  @see reducer
 *  @see ReducersOstream
 */
class reducer_ostream :
      public reducer<op_basic_ostream<char, std::char_traits<char>, true> >
{
    typedef reducer<op_basic_ostream<char, std::char_traits<char>, true> > base;
    using base::view;
public:

    /// The view type for the reducer.
    typedef base::view_type        View;

    /// The monoid type for the reducer.
    typedef base::monoid_type      Monoid;

    /** Constructs an initial `reducer_ostream` from a `std::ostream`.  The
     *  specified stream is used as the eventual destination for all text
     *  streamed to this hyperobject.
     */
    explicit reducer_ostream(const std::ostream &os) : base(os) {}

    /** Returns a modifiable reference to the underlying 'ostream' object.
     */
    std::ostream& get_reference() { return view(); }

    /** Writes to the ostream.
     */
    template<typename T>
    std::ostream& operator<< (const T &v)
    {
        return view() << v;
    }

    /**
     * Calls a manipulator.
     *
     * @param _Pfn Pointer to the manipulator function.
     */
    reducer_ostream& operator<< (std::ostream &(*_Pfn)(std::ostream &))
    {
        (*_Pfn)(view());
        return *this;
    }

    /** @name Dereference
     *  @details Dereferencing a wrapper is a no-op. It simply returns the
     *  wrapper. Combined with the rule that the wrapper forwards view
     *  operations to its contained view, this means that view operations can
     *  be written the same way on reducers and wrappers, which is convenient
     *  for incrementally converting old code using wrappers to use reducers
     *  instead. That is:
     *
     *      reducer<op_ostream> r;
     *      *r << "a";      // *r returns the view
     *                      // operator<<() is a view member function
     *
     *      reducer_ostream w;
     *      *w << "a";      // *w returns the wrapper
     *                      // operator<<() is a wrapper member function
     *                      // that calls the corresponding view function
     */
    //@{
    reducer_ostream&       operator*()       { return *this; }
    reducer_ostream const& operator*() const { return *this; }

    reducer_ostream*       operator->()       { return this; }
    reducer_ostream const* operator->() const { return this; }
    //@}

    /** @name Upcast
     *  @details In Intel Cilk Plus library 0.9, reducers were always cache-aligned.
     *  In library  1.0, reducer cache alignment is optional. By default,
     *  reducers are unaligned (i.e., just naturally aligned), but legacy
     *  wrappers inherit from cache-aligned reducers for binary compatibility.
     *
     *  This means that a wrapper will automatically be upcast to its aligned
     *  reducer base class. The following conversion operators provide
     *  pseudo-upcasts to the corresponding unaligned reducer class.
     */
    //@{
    operator reducer<op_ostream>& ()
    {
        return *reinterpret_cast< reducer<op_ostream>* >(this);
    }
    operator const reducer<op_ostream>& () const
    {
        return *reinterpret_cast< const reducer<op_ostream>* >(this);
    }
    //@}
};

} // namespace cilk

#endif // REDUCER_OSTREAM_H_INCLUDED
