// bdlb_functionoutputiterator.h                                      -*-C++-*-
#ifndef INCLUDED_BDLB_FUNCTIONOUTPUTITERATOR
#define INCLUDED_BDLB_FUNCTIONOUTPUTITERATOR

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

//@PURPOSE: Provides an output iterator for a client-supplied functor.
//
//@CLASSES:
//  bdlb::FunctionOutputIterator: function output iterator template
//
//@SEE_ALSO: bdlb_nulloutputiterator
//
//@DESCRIPTION: This component provides an iterator template mechanism,
// 'bdlb::FunctionOutputIterator', that adapts a client supplied functor (or
// function pointer) to a C++ compliant output iterator.  This component allows
// clients to create custom output iterators easily.
//
// A 'bdlb::FunctionOutputIterator' instance's template parameter type
// 'FUNCTION' must be a functor (or function) that can be called as if it has
// the following signature:
//..
//  void operator()(const TYPE&)'
//..
// where 'TYPE' is the type of the object that will be assigned (by clients)
// to the dereferenced iterator.  For example:
//..
//  void myFunction(const int& value) {};
//  typedef void (*MyFunctionPtr)(const int&);
//  typedef bdlb::FunctionOutputIterator<MyFunctionPtr> MyFunctionIterator;
//
//  MyFunctionIterator it(&foo);
//  *it = 5;                       // Calls 'myFunction(5)'!
//..
// Notice that assigning 5 to the dereferenced output iterator invokes the
// function with the value 5.
//
// The provided output iterator has the following attributes:
//
//: o Meets the requirements for an output iterator according to the
//:   C++ Standard (C++11, Section 24.2.4 [output.iterators]).
//:
//: o Dereferencing an iterator and assigning to the result leads to a call
//:   of the functional object owned by the iterator.  The value assigned to
//:   the dereferenced iterator is passed to a call of the function or functor
//:   held by the iterator as a constant reference.  In other words, the
//:   assignment '*it = value' is equivalent to 'function(value)'.
//:
//: o Incrementing an iterator is a no-op.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Adapting a Free-Function to an Output Iterator
///- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Suppose we want use a provided function 'foo', that prints integers in some
// predefined format, to print each unique element of an array.  Instead of
// manually writing a loop and checking for duplicate elements, we would like
// to use a standard algorithm such as 'unique_copy'.  However, 'unique_copy'
// takes in an output iterator instead of a free function.  We can use
// 'bdlb::FunctionOutputIterator' to adapt 'foo' into an output iterator that
// is acceptable by 'unique_copy'.
//
// First, we define the type 'Function' and a function of that type 'foo':
//..
//  typedef void (*Function)(const int&);
//
//  void foo(const int& value)
//  {
//      bsl::cout << value << " ";
//  }
//..
// Then, we define a data sequence to process:
//..
//  enum { NUM_VALUES_1 = 7 };
//  const int array1[NUM_VALUES_1] = { 2, 3, 3, 5, 7, 11, 11 };
//..
// Next, we use 'bdlb::FunctionOutputIterator' to wrap 'foo' for use in the
// algorithm 'bsl::unqiue_copy':
//..
//  unique_copy(
//      array1,
//      array1 + NUM_VALUES,
//      bdlb::FunctionOutputIterator<Function>(&foo));
//..
// Notice, that each time 'bsl::unique_copy' copies an element from the
// supplied range and assigns it to the output iterator, the function 'foo' is
// called for the element.
//
// Finally, the resulting console output:
//..
//  2 3 5 7 11
//..
//
///Example 2: Adapting A Functor to An Output Iterator
///- - - - - - - - - - - - - - - - - - - - - - - - - -
// The following example demonstrates using a 'bdlb::FunctionOutputIterator'
// with a user defined functor object.  Consider the 'Accumulator' class for
// accumulating integer values into a total.  We want to adapt 'Accumulator'
// for use with the algorithm 'bsl::unique_copy'.
//
// First, we define an 'Accumulator' class that will total the values supplied
// to the 'increment' method:
//..
//  class Accumulator {
//      // This class provides a value accumulating functionality.
//
//      // DATA
//      int d_sum;
//    public:
//      // CREATORS
//      Accumulator() : d_sum(0) {};
//
//      // MANIPULATORS
//      void increment(int value) { d_sum += value; };
//
//      // ACCESSORS
//      int total() const { return d_sum; }
//  };
//..
// Next, we define a functor, 'AccumulatorFunctor', that adapts 'Accumulator'
// to a function object:
//..
//
//  class AccumulatorFunctor {
//      // This class implements a function object that invokes 'increment' in
//      // response of calling operator()(int).
//
//      // DATA
//      Accumulator *d_accumulator_p;  // accumulator (held, not owned)
//
//    public:
//      // CREATORS
//      explicit AccumulatorFunctor(Accumulator *accumulator)
//     : d_accumulator_p(accumulator)
//      {}
//
//      // MANIPULATORS
//      void operator()(int value) { d_accumulator_p->increment(value); };
//  };
//..
// Then, we define data sequence to process:
//..
//  enum { NUM_VALUES_2 = 7 };
//  const int   array2[NUM_VALUES_2] = { 2, 3, 3, 5, 7, 11, 11 };
//..
// Next, we create a 'bdlb::FunctionOutputIterator' for 'AccumulatorFunctor'
// and supply it to the 'bsl::unique_copy' algorithm to accumulate a sequence
// of values:
//..
//  Accumulator accumulator;
//  unique_copy(
//      array2,
//      array2 + NUM_VALUES_2,
//      bdlb::FunctionOutputIterator<AccumulatorFunctor>(
//          AccumulatorFunctor(&accumulator)));
//..
// Finally, we observe that 'accumulator' holds the accumulated total of
// unique values in 'array':
//..
//  assert(28 == accumulator.total());
//..

#include <bdlscm_version.h>

#include <bsls_libraryfeatures.h>

#include <bsl_iterator.h>

namespace BloombergLP {
namespace bdlb {

#if defined(BSLS_LIBRARYFEATURES_STDCPP_LIBCSTD)
// Sun Studio compilers have non-standard iterator behavior requiring iterators
// to inherit from 'iterator' (rather than simply meeting the needs of
// 'std::iterator_traits').  In addition, Sun Studio requires the 'value_type'
// of the iterator to be instantiable (i.e., not 'void' as permitted by the
// C++ standard).
#define BDLB_SUNITERATORWORKAROUND \
     : public bsl::iterator<bsl::output_iterator_tag, void *, void, void, void>
#else
#define BDLB_SUNITERATORWORKAROUND
#endif

                     // ============================
                     // class FunctionOutputIterator
                     // ============================

template <class FUNCTION>
class FunctionOutputIterator BDLB_SUNITERATORWORKAROUND {
    // Provide an output iterator that calls an object of the (template
    // parameter) type 'FUNCTION'.  If 'FUNCTION' is a functor, de-referencing
    // this iterator and assigning to the result (of dereferencing) will call
    // the 'operator()' of the functor with the assigned value as a parameter.
    // Similarly, if 'FUNCTION' if a function pointer type,  assigning to the
    // dereferenced iterator will call the function supplied at construction
    // with the assigned value as a parameter.

    // PRIVATE TYPES
    class AssignmentProxy {
        // Provide an object that can appear on the left side of an assignment
        // from 'TYPE'.  The assignment to an instance of 'AssignmentProxy'
        // results in a call of 'operator(TYPE)' of the functor or function
        // supplied at construction.  Instances of this class are created every
        // time an object of the host class is dereferenced.

        // DATA
        FUNCTION& d_function; // reference to functional object to be invoked
                              // when value assigned to the instance of this
                              // class
      public:
        // CREATORS
        explicit AssignmentProxy(FUNCTION& function);
            // Create 'AssignmentProxy' object having the specified 'function'
            // value.

        // MANIPULATORS
        template <class TYPE>
        AssignmentProxy& operator=(const TYPE& rhs);
            // Invoke 'd_function' with the specified 'rhs' as a parameter.
            // The behavior is undefined unless 'FUNCTION' is a function
            // pointer type and a valid function pointer was supplied at
            // construction.
    };

    // DATA
    FUNCTION d_function; // functional object to be invoked when value is
                         // assigned to dereferenced instance of this class

  public:
    // TYPES
    typedef bsl::output_iterator_tag iterator_category;
    typedef void                     difference_type;
    typedef void                     value_type;
    typedef void                     reference;
    typedef void                     pointer;
        // Provide type aliases required by C++ standard 'iterator_traits'.

    // CREATORS
    FunctionOutputIterator();
        // Create a 'FunctionOutputIterator' object that, when an assignment is
        // performed on the dereferenced object, will call a default
        // constructed instance of the (template parameter) type 'FUNCTION'
        // passing the assigned value as the argument.  Note that if 'FUNCTION'
        // is a function pointer type, then the default constructed 'FUNCTION'
        // will be 0, and the behavior when assigning to a dereferenced
        // iterator will be undefined.

    explicit FunctionOutputIterator(const FUNCTION& function);
        // Create 'FunctionOutputIterator' object that, when an assignment is
        // performed on the dereferenced object, will call the specified
        // 'function' passing the assigned value as the argument.

    //! FunctionOutputIterator(const FunctionOutputIterator &rhs) = default;
        // Create a 'FunctionOutputIterator' object that, when an assignment is
        // performed on the dereferenced object, will call the same function or
        // functor used by the specified 'rhs' object.

    //! ~FunctionOutputIterator() = default;
        // Destroy this object.


    // MANIPULATORS
    //! FunctionOutputIterator& operator=(
    //                            const FunctionOutputIterator &rhs) = default;
        // Assign to this object the value of the specified 'rhs' object, and
        // return a reference providing modifiable access to this object.

    AssignmentProxy operator*();
        // Return an object that can appear on the left-hand side of an
        // assignment from 'TYPE'.  When a value is assigned to the returned
        // value, invoke the functor or function indicated at construction
        // supplying the assigned value as the parameter.  This function is
        // non-'const' in accordance with the input iterator requirements, even
        // though '*this' is not modified.   Note that if 'FUNCTION' is a
        // function pointer type and a valid function pointer was not supplied
        // at construction, then the behavior when assigning to a dereferenced
        // iterator will be undefined.
};

// FREE OPERATORS
template <class FUNCTION>
inline
FunctionOutputIterator<FUNCTION>& operator++(
                                   FunctionOutputIterator<FUNCTION>& iterator);
    // Do nothing and return specified 'iterator'.

template <class FUNCTION>
inline
FunctionOutputIterator<FUNCTION> operator++(
                              FunctionOutputIterator<FUNCTION>& iterator, int);
    // Do nothing and return specified 'iterator'.

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

              // ---------------------------------------------
              // class FunctionOutputIterator::AssignmentProxy
              // ---------------------------------------------

// CREATORS
template <class FUNCTION>
inline
FunctionOutputIterator<FUNCTION>::AssignmentProxy::AssignmentProxy(
                                                            FUNCTION& function)
    : d_function(function)
{
}

// MANIPULATORS
template <class FUNCTION>
template <class TYPE>
inline
typename FunctionOutputIterator<FUNCTION>::AssignmentProxy&
FunctionOutputIterator<FUNCTION>::AssignmentProxy::operator=(const TYPE& rhs)
{
    d_function(rhs);
    return *this;
}
                        // ----------------------------
                        // class FunctionOutputIterator
                        // ----------------------------

// CREATORS
template <class FUNCTION>
inline
FunctionOutputIterator<FUNCTION>::FunctionOutputIterator()
    : d_function()
{
}

template <class FUNCTION>
inline
FunctionOutputIterator<FUNCTION>::FunctionOutputIterator(
                                                      const FUNCTION& function)
    : d_function(function)
{
}

// MANIPULATORS
template <class FUNCTION>
inline
typename FunctionOutputIterator<FUNCTION>::AssignmentProxy
FunctionOutputIterator<FUNCTION>::operator*()
{
    return AssignmentProxy(d_function);
}

// FREE OPERATORS
template <class FUNCTION>
inline
FunctionOutputIterator<FUNCTION>&
operator++(FunctionOutputIterator<FUNCTION>& iterator)
{
    return iterator;
}

template <class FUNCTION>
inline
FunctionOutputIterator<FUNCTION>
operator++(FunctionOutputIterator<FUNCTION>& iterator, int)
{
    return iterator;
}

#undef BDLB_SUNITERATORWORKAROUND

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

#endif
// ----------------------------------------------------------------------------
// Copyright 2019 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 ----------------------------------