/*  reducer_list.h                  -*- C++ -*-
 *
 *  Copyright (C) 2009-2016, Intel Corporation
 *  All rights reserved.
 *  
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *  
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in
 *      the documentation and/or other materials provided with the
 *      distribution.
 *    * Neither the name of Intel Corporation nor the names of its
 *      contributors may be used to endorse or promote products derived
 *      from this software without specific prior written permission.
 *  
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 *  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
 *  WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *  
 *  *********************************************************************
 *  
 *  PLEASE NOTE: This file is a downstream copy of a file mainitained in
 *  a repository at cilkplus.org. Changes made to this file that are not
 *  submitted through the contribution process detailed at
 *  http://www.cilkplus.org/submit-cilk-contribution will be lost the next
 *  time that a new version is released. Changes only submitted to the
 *  GNU compiler collection or posted to the git repository at
 *  https://bitbucket.org/intelcilkruntime/intel-cilk-runtime.git are
 *  not tracked.
 *  
 *  We welcome your contributions to this open source project. Thank you
 *  for your assistance in helping us improve Cilk Plus.
 */

/** @file reducer_list.h
 *
 *  @brief Defines classes for parallel list creation by appending or
 *  prepending reducers.
 *
 *  @ingroup ReducersList
 *
 *  @see ReducersList
 */

#ifndef REDUCER_LIST_H_INCLUDED
#define REDUCER_LIST_H_INCLUDED

#include <cilk/reducer.h>
#include <list>

/** @defgroup ReducersList List Reducers
 *
 *  List-append and list-prepend reducers create standard lists by
 *  concatenating a set of lists or values in parallel.
 *
 *  @ingroup Reducers
 *
 *  You should be familiar with @ref pagereducers "Intel(R) Cilk(TM) Plus reducers"
 *  (from file `reducers.md`) and particularly with @ref reducers_using, before
 *  trying to use the information in this file.
 *
 *  @section redlist_usage Usage Example
 *
 *      // Create a list containing the labels of the nodes of a tree in
 *      // "inorder" (left subtree, root, right subtree).
 *
 *      struct Tree { Tree* left; Tree* right; string label; ... };
 *
 *      list<string> x;
 *      cilk::reducer< cilk::op_list_append<string> > xr(cilk::move_in(x));
 *      collect_labels(tree, xr);
 *      xr.move_out(x);
 *
 *      void collect_labels(Tree* node,
 *                          cilk::reducer< cilk::op_list_append<string> >& xr)
 *      {
 *          if (node) {
 *              cilk_spawn collect_labels(node->left, xr);
 *              xr->push_back(node->label);
 *              collect_labels(node->right, xr);
 *              cilk_sync;
 *          }
 *      }
 *
 *  @section redlist_monoid The Monoid
 *
 *  @subsection redlist_monoid_values Value Set
 *
 *  The __value set__ of a list reducer is the set of values of the class
 *  `std::list<Type, Allocator>`, which we refer to as the reducer's _list
 *  type_.
 *
 *  @subsection redlist_monoid_operator Operator
 *
 *  The operator of a list-append reducer is defined as
 *
 *      x CAT y == (every element of x, followed by every element of y)
 *
 *  The operator of a list-prepend reducer is defined as
 *
 *      x RCAT y == (every element of y, followed by every element of x)
 *
 *  @subsection redlist_monoid_identity Identity
 *
 *  The identity value of a list reducer is the empty list, which is the value
 *  of the expression `std::list<Type, Allocator>([allocator])`.
 *
 *  @section redlist_operations Operations
 *
 *  In the operation descriptions below, the type name `List` refers to the
 *  reducer's string type, `std::list<Type, Allocator>`.
 *
 *  @subsection redlist_constructors Constructors
 *
 *  Any argument list which is valid for a `std::list` constructor is valid for
 *  a list reducer constructor. The usual move-in constructor is also provided:
 *
 *      reducer(move_in(List& variable))
 *
 *  A list reducer with no constructor arguments, or with only an allocator
 *  argument, will initially contain the identity value, an empty list.
 *
 *  @subsection redlist_get_set Set and Get
 *
 *      r.set_value(const List& value)
 *      const List& = r.get_value() const
 *      r.move_in(List& variable)
 *      r.move_out(List& variable)
 *
 *  @subsection redlist_view_ops View Operations
 *
 *  The view of a list-append reducer provides the following member functions:
 *
 *      void push_back(const Type& element)
 *      void insert_back(List::size_type n, const Type& element)
 *      template <typename Iter> void insert_back(Iter first, Iter last)
 *      void splice_back(List& x)
 *      void splice_back(List& x, List::iterator i)
 *      void splice_back(List& x, List::iterator first, List::iterator last)
 *
 *  The view of a list-prepend reducer provides the following member functions:
 *
 *      void push_front(const Type& element)
 *      void insert_front(List::size_type n, const Type& element)
 *      template <typename Iter> void insert_front(Iter first, Iter last)
 *      void splice_front(List& x)
 *      void splice_front(List& x, List::iterator i)
 *      void splice_front(List& x, List::iterator first, List::iterator last)
 *
 *  The `push_back` and `push_front` functions are the same as the
 *  corresponding `std::list` functions. The `insert_back`, `splice_back`,
 *  `insert_front`, and `splice_front` functions are the same as the
 *  `std::list` `insert` and `splice` functions, with the first parameter
 *  fixed to the end or beginning of the list, respectively.
 *
 *  @section redlist_performance Performance Considerations
 *
 *  An efficient reducer requires that combining the values of two views (using
 *  the view `reduce()` function) be a constant-time operations. Two lists can
 *  be merged in constant time using the `splice()` function if they have the
 *  same allocator. Therefore, the lists for new views are created (by the view
 *  identity constructor) using the same allocator as the list that was created
 *  when the reducer was constructed.
 *
 *  The performance of adding elements to a list reducer depends on the view
 *  operations that are used:
 *
 *  *   The `push` functions add a single element to the list, and therefore
 *      take constant time.
 *  *   An `insert` function that inserts _N_ elements adds each of them
 *      individually, and therefore takes _O(N)_ time.
 *  *   A `splice` function that inserts _N_ elements just adjusts a couple of
 *      pointers, and therefore takes constant time, _if the splice is from a
 *      list with the same allocator as the reducer_. Otherwise, it is
 *      equivalent to an `insert`, and takes _O(N)_ time.
 *
 *  This means that for best performance, if you will be adding elements to a
 *  list reducer in batches, you should `splice` them from a list having the
 *  same allocator as the reducer.
 *
 *  The reducer `move_in` and `move_out` functions do a constant-time `swap` if
 *  the variable has the same allocator as the reducer, and a linear-time copy
 *  otherwise.
 *
 *  Note that the allocator of a list reducer is determined when the reducer is
 *  constructed. The following two examples may have very different behavior:
 *
 *      list<Element, Allocator> a_list;
 *
 *      reducer< list_append<Element, Allocator> reducer1(move_in(a_list));
 *      ... parallel computation ...
 *      reducer1.move_out(a_list);
 *
 *      reducer< list_append<Element, Allocator> reducer2;
 *      reducer2.move_in(a_list);
 *      ... parallel computation ...
 *      reducer2.move_out(a_list);
 *
 *  *   `reducer1` will be constructed with the same allocator as `a_list`,
 *      because the list was specified in the constructor. The `move_in`
 *      and `move_out` can therefore be done with a `swap` in constant time.
 *  *   `reducer2` will be constructed with a _default_ allocator,
 *      "`Allocator()`", which may or may not be the same as the allocator of
 *      `a_list`. Therefore, the `move_in` and `move_out` may have to be done
 *      with a copy in _O(N)_ time.
 *
 *  (All instances of an allocator type with no internal state (like
 *  `std::allocator`) are "the same". You only need to worry about the "same
 *  allocator" issue when you create list reducers with custom allocator types.)
 *
 *  @section redlist_types Type and Operator Requirements
 *
 *  `std::list<Type, Allocator>` must be a valid type.
 */


namespace cilk {

namespace internal {

/** @ingroup ReducersList */
//@{

/** Base class for list-append and prepend view classes.
 *
 *  @note   This class provides the definitions that are required for a class
 *          that will be used as the parameter of a @ref list_monoid_base
 *          specialization.
 *
 *  @tparam Type        The list element type (not the list type).
 *  @tparam Allocator   The list's allocator class.
 *
 *  @see ReducersList
 *  @see list_monoid_base
 */
template <typename Type, typename Allocator>
class list_view_base
{
protected:
    /// The type of the contained list.
    typedef std::list<Type, Allocator>  list_type;

    /// The list accumulator variable.
    list_type m_value;

public:

    /** @name Monoid support.
     */
    //@{

    /// Required by @ref monoid_with_view
    typedef list_type   value_type;

    /// Required by @ref list_monoid_base
    Allocator get_allocator() const
    {
        return m_value.get_allocator();
    }

    //@}


    /** @name Constructors.
     */
    //@{

    /// Standard list constructor.
    explicit list_view_base(const Allocator& a = Allocator()) : m_value(a) {}
    explicit list_view_base(
        typename list_type::size_type n,
        const Type& value = Type(),
        const Allocator& a = Allocator() ) : m_value(n, value, a) {}
    template <typename Iter>
    list_view_base(Iter first, Iter last, const Allocator& a = Allocator()) :
        m_value(first, last, a) {}
    list_view_base(const list_type& list) : m_value(list) {}

    /// Move-in constructor.
    explicit list_view_base(move_in_wrapper<value_type> w)
        : m_value(w.value().get_allocator())
    {
        m_value.swap(w.value());
    }

    //@}

    /** @name Reducer support.
     */
    //@{

    /// Required by reducer::move_in()
    void view_move_in(value_type& v)
    {
        if (m_value.get_allocator() == v.get_allocator())
            // Equal allocators. Do a (fast) swap.
            m_value.swap(v);
        else
            // Unequal allocators. Do a (slow) copy.
            m_value = v;
        v.clear();
    }

    /// Required by reducer::move_out()
    void view_move_out(value_type& v)
    {
        if (m_value.get_allocator() == v.get_allocator())
            // Equal allocators.  Do a (fast) swap.
            m_value.swap(v);
        else
            // Unequal allocators.  Do a (slow) copy.
            v = m_value;
        m_value.clear();
    }

    /// Required by reducer::set_value()
    void view_set_value(const value_type& v) { m_value = v; }

    /// Required by reducer::get_value()
    value_type const& view_get_value()     const { return m_value; }

    /// Type returned by view_get_value.
    typedef value_type const& return_type_for_get_value;

    // Required by legacy wrapper get_reference()
    value_type      & view_get_reference()       { return m_value; }
    value_type const& view_get_reference() const { return m_value; }

    //@}
};


/** Base class for list-append and prepend monoid classes.
 *
 *  The key to efficient reducers is that the `identity` operation, which
 * creates a new per-strand view, and the `reduce` operation, which combines
 *  two per-strand views, must be constant-time operations. Two lists can be
 *  concatenated in constant time only if they have the same allocator.
 *  Therefore, all the per-strand list accumulator variables must be created
 *   with the same allocator as the leftmost view list.
 *
 *  This means that a list reduction monoid must have a copy of the allocator
 *  of the leftmost view's list, so that it can use it in the `identity`
 *  operation. This, in turn, requires that list reduction monoids have a
 *  specialized `construct()` function, which constructs the leftmost view
 *  before the monoid, and then passes the leftmost view's allocator to the
 *  monoid constructor.
 *
 *  @tparam View    The list-append or prepend view class.
 *  @tparam Align   If `false` (the default), reducers instantiated on this
 *                  monoid will be naturally aligned (the Intel Cilk Plus library 1.0
 *                  behavior). If `true`, reducers instantiated on this monoid
 *                  will be cache-aligned for binary compatibility with
 *                  reducers in Intel Cilk Plus library version 0.9.
 *
 *  @see ReducersList
 *  @see list_view_base
 */
template <typename View, bool Align>
class list_monoid_base : public monoid_with_view<View, Align>
{
    typedef typename View::value_type           list_type;
    typedef typename list_type::allocator_type  allocator_type;
    typedef provisional_guard<View>             view_guard;

    allocator_type                              m_allocator;

public:

    /** Constructor.
     *
     *  There is no default constructor for list monoids, because the allocator
     *  must always be specified.
     *
     *  @param  allocator   The list allocator to be used when
     *                      identity-constructing new views.
     */
    list_monoid_base(const allocator_type& allocator = allocator_type()) :
        m_allocator(allocator) {}

    /** Creates an identity view.
     *
     *  List view identity constructors take the list allocator as an argument.
     *
     *  @param v    The address of the uninitialized memory in which the view
     *              will be constructed.
     */
    void identity(View *v) const { ::new((void*) v) View(m_allocator); }

    /** @name construct functions
     *
     *  All `construct()` functions first construct the leftmost view, using
     *  the optional @a x1, @a x2, and @a x3 arguments that were passed in from
     *  the reducer constructor. They then call the view's `get_allocator()`
     *  function to get the list allocator from its contained list, and pass it
     *  to the monoid constructor.
     */
    //@{

    template <typename Monoid>
    static void construct(Monoid* monoid, View* view)
    {
        view_guard vg( new((void*) view) View() );
        vg.confirm_if( new((void*) monoid) Monoid(view->get_allocator()) ); 
    }

    template <typename Monoid, typename T1>
    static void construct(Monoid* monoid, View* view, const T1& x1)
    {
        view_guard vg( new((void*) view) View(x1) );
        vg.confirm_if( new((void*) monoid) Monoid(view->get_allocator()) ); 
    }

    template <typename Monoid, typename T1, typename T2>
    static void construct(Monoid* monoid, View* view,
                          const T1& x1, const T2& x2)
    {
        view_guard vg( new((void*) view) View(x1, x2) );
        vg.confirm_if( new((void*) monoid) Monoid(view->get_allocator()) ); 
    }

    template <typename Monoid, typename T1, typename T2, typename T3>
    static void construct(Monoid* monoid, View* view,
                          const T1& x1, const T2& x2, const T3& x3)
    {
        view_guard vg( new((void*) view) View(x1, x2, x3) );
        vg.confirm_if( new((void*) monoid) Monoid(view->get_allocator()) ); 
    }

    //@}
};

//@}

} // namespace internal


/** @ingroup ReducersList */
//@{

/** The list-append reducer view class.
 *
 *  This is the view class for reducers created with
 *  `cilk::reducer< cilk::op_list_append<Type, Allocator> >`. It holds the
 *  accumulator variable for the reduction, and allows only append 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
 *          `push_back` operation would be used in an expression like
 *          `r->push_back(a)`, where `r` is a list-append reducer variable.
 *
 *  @tparam Type        The list element type (not the list type).
 *  @tparam Allocator   The list allocator type.
 *
 *  @see ReducersList
 *  @see op_list_append
 */
template <class Type,
          class Allocator = typename std::list<Type>::allocator_type>
class op_list_append_view : public internal::list_view_base<Type, Allocator>
{
    typedef internal::list_view_base<Type, Allocator>   base;
    typedef std::list<Type, Allocator>                  list_type;
    typedef typename list_type::iterator                iterator;

    iterator end() { return this->m_value.end(); }

public:

    /** @name Constructors.
     *
     *  All op_list_append_view constructors simply pass their arguments on to
     *  the @ref internal::list_view_base base class constructor.
     *
     *  @ref internal::list_view_base supports all the std::list constructor
     *  forms, as well as the reducer move_in constructor form.
     */
    //@{

    op_list_append_view() : base() {}

    template <typename T1>
    op_list_append_view(const T1& x1) : base(x1) {}

    template <typename T1, typename T2>
    op_list_append_view(const T1& x1, const T2& x2) : base(x1, x2) {}

    template <typename T1, typename T2, typename T3>
    op_list_append_view(const T1& x1, const T2& x2, const T3& x3) :
        base(x1, x2, x3) {}

    //@}

    /** @name View modifier operations.
     */
    //@{

    /** Adds an element at the end of the list.
     *
     *  This is equivalent to `list.push_back(element)`
     */
    void push_back(const Type& element)
        { this->m_value.push_back(element); }

    /** Inserts elements at the end of the list.
     *
     *  This is equivalent to `list.insert(list.end(), n, element)`
     */
    void insert_back(typename list_type::size_type n, const Type& element)
        { this->m_value.insert(end(), n, element); }

    /** Inserts elements at the end of the list.
     *
     *  This is equivalent to `list.insert(list.end(), first, last)`
     */
    template <typename Iter>
    void insert_back(Iter first, Iter last)
        { this->m_value.insert(end(), first, last); }

    /** Splices elements at the end of the list.
     *
     *  This is equivalent to `list.splice(list.end(), x)`
     */
    void splice_back(list_type& x) {
        if (x.get_allocator() == this->m_value.get_allocator())
            this->m_value.splice(end(), x);
        else {
            insert_back(x.begin(), x.end());
            x.clear();
        }
    }

    /** Splices elements at the end of the list.
     *
     *  This is equivalent to `list.splice(list.end(), x, i)`
     */
    void splice_back(list_type& x, iterator i) {
        if (x.get_allocator() == this->m_value.get_allocator())
            this->m_value.splice(end(), x, i);
        else {
            push_back(*i);
            x.erase(i);
        }
    }

    /** Splices elements at the end of the list.
     *
     *  This is equivalent to `list.splice(list.end(), x, first, last)`
     */
    void splice_back(list_type& x, iterator first, iterator last) {
        if (x.get_allocator() == this->m_value.get_allocator())
            this->m_value.splice(end(), x, first, last);
        else {
            insert_back(first, last);
            x.erase(first, last);
        }
    }

    //@}

    /** Reduces the views of two strands.
     *
     *  This function is invoked by the @ref op_list_append monoid to combine
     *  the views of two strands when the right strand merges with the left
     *  one. It appends the value contained in the right-strand view to the
     *  value contained in the left-strand view, and leaves the value in the
     *  right-strand view undefined.
     *
     *  @param  right   A pointer to the right-strand view. (`this` points to
     *                  the left-strand view.)
     *
     *  @note   Used only by the @ref op_list_append monoid to implement the
     *          monoid reduce operation.
     */
    void reduce(op_list_append_view* right)
    {
        __CILKRTS_ASSERT(
            this->m_value.get_allocator() == right->m_value.get_allocator());
        this->m_value.splice(end(), right->m_value);
    }
};


/** The list-prepend reducer view class.
 *
 *  This is the view class for reducers created with
 *  `cilk::reducer< cilk::op_list_prepend<Type, Allocator> >`. It holds the
 *  accumulator variable for the reduction, and allows only prepend 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
 *          `push_front` operation would be used in an expression like
 *          `r->push_front(a)`, where `r` is a list-prepend reducer variable.
 *
 *  @tparam Type        The list element type (not the list type).
 *  @tparam Allocator   The list allocator type.
 *
 *  @see ReducersList
 *  @see op_list_prepend
 */
template <class Type,
          class Allocator = typename std::list<Type>::allocator_type>
class op_list_prepend_view : public internal::list_view_base<Type, Allocator>
{
    typedef internal::list_view_base<Type, Allocator>   base;
    typedef std::list<Type, Allocator>                  list_type;
    typedef typename list_type::iterator                iterator;

    iterator begin() { return this->m_value.begin(); }

public:

    /** @name Constructors.
     *
     *  All op_list_prepend_view constructors simply pass their arguments on to
     *  the @ref internal::list_view_base base class constructor.
     *
     *  @ref internal::list_view_base supports all the std::list constructor
     *  forms, as well as the reducer move_in constructor form.
     *
     */
    //@{

    op_list_prepend_view() : base() {}

    template <typename T1>
    op_list_prepend_view(const T1& x1) : base(x1) {}

    template <typename T1, typename T2>
    op_list_prepend_view(const T1& x1, const T2& x2) : base(x1, x2) {}

    template <typename T1, typename T2, typename T3>
    op_list_prepend_view(const T1& x1, const T2& x2, const T3& x3) :
        base(x1, x2, x3) {}

    //@}

    /** @name View modifier operations.
     */
    //@{

    /** Adds an element at the beginning of the list.
     *
     *  This is equivalent to `list.push_front(element)`
     */
    void push_front(const Type& element)
        { this->m_value.push_front(element); }

    /** Inserts elements at the beginning of the list.
     *
     *  This is equivalent to `list.insert(list.begin(), n, element)`
     */
    void insert_front(typename list_type::size_type n, const Type& element)
        { this->m_value.insert(begin(), n, element); }

    /** Inserts elements at the beginning of the list.
     *
     *  This is equivalent to `list.insert(list.begin(), first, last)`
     */
    template <typename Iter>
    void insert_front(Iter first, Iter last)
        { this->m_value.insert(begin(), first, last); }

    /** Splices elements at the beginning of the list.
     *
     *  This is equivalent to `list.splice(list.begin(), x)`
     */
    void splice_front(list_type& x) {
        if (x.get_allocator() == this->m_value.get_allocator())
            this->m_value.splice(begin(), x);
        else {
            insert_front(x.begin(), x.begin());
            x.clear();
        }
    }

    /** Splices elements at the beginning of the list.
     *
     *  This is equivalent to `list.splice(list.begin(), x, i)`
     */
    void splice_front(list_type& x, iterator i) {
        if (x.get_allocator() == this->m_value.get_allocator())
            this->m_value.splice(begin(), x, i);
        else {
            push_front(*i);
            x.erase(i);
        }
    }

    /** Splices elements at the beginning of the list.
     *
     *  This is equivalent to `list.splice(list.begin(), x, first, last)`
     */
    void splice_front(list_type& x, iterator first, iterator last) {
        if (x.get_allocator() == this->m_value.get_allocator())
            this->m_value.splice(begin(), x, first, last);
        else {
            insert_front(first, last);
            x.erase(first, last);
        }
    }

    //@}

    /** Reduces the views of two strands.
     *
     *  This function is invoked by the @ref op_list_prepend monoid to combine
     *  the views of two strands when the right strand merges with the left
     *  one. It prepends the value contained in the right-strand view to the
     *  value contained in the left-strand view, and leaves the value in the
     *  right-strand view undefined.
     *
     *  @param  right   A pointer to the right-strand view. (`this` points to
     *                  the left-strand view.)
     *
     *  @note   Used only by the @ref op_list_prepend monoid to implement the
     *          monoid reduce operation.
     */
    /** Reduce operation.
     *
     *  Required by @ref monoid_base.
     */
    void reduce(op_list_prepend_view* right)
    {
        __CILKRTS_ASSERT(
            this->m_value.get_allocator() == right->m_value.get_allocator());
        this->m_value.splice(begin(), right->m_value);
    }
};



/** Monoid class for list-append reductions. Instantiate the cilk::reducer
 *  template class with a op_list_append monoid to create a list-append reducer
 *  class. For example, to create a list of strings:
 *
 *      cilk::reducer< cilk::op_list_append<std::string> > r;
 *
 *  @tparam Type    The list element type (not the list type).
 *  @tparam Alloc   The list allocator type.
 *  @tparam Align   If `false` (the default), reducers instantiated on this
 *                  monoid will be naturally aligned (the Intel Cilk Plus library 1.0
 *                  behavior). If `true`, reducers instantiated on this monoid
 *                  will be cache-aligned for binary compatibility with
 *                  reducers in Intel Cilk Plus library version 0.9.
 *
 *  @see ReducersList
 *  @see op_list_append_view
 */
template <typename Type,
          typename Allocator = typename std::list<Type>::allocator_type,
          bool Align = false>
struct op_list_append :
    public internal::list_monoid_base<op_list_append_view<Type, Allocator>, Align>
{
    /// Construct with default allocator.
    op_list_append() {}
    /// Construct with specified allocator.
    op_list_append(const Allocator& alloc) :
        internal::list_monoid_base<op_list_append_view<Type, Allocator>, Align>(alloc) {}
};

/** Monoid class for list-prepend reductions. Instantiate the cilk::reducer
 *  template class with a op_list_prepend monoid to create a list-prepend
 *  reducer class. For example, to create a list of strings:
 *
 *      cilk::reducer< cilk::op_list_prepend<std::string> > r;
 *
 *  @tparam Type    The list element type (not the list type).
 *  @tparam Alloc   The list allocator type.
 *  @tparam Align   If `false` (the default), reducers instantiated on this
 *                  monoid will be naturally aligned (the Intel Cilk Plus library 1.0
 *                  behavior). If `true`, reducers instantiated on this monoid
 *                  will be cache-aligned for binary compatibility with
 *                  reducers in Intel Cilk Plus library version 0.9.
 *
 *  @see ReducersList
 *  @see op_list_prepend_view
 */
template <typename Type,
          typename Allocator = typename std::list<Type>::allocator_type,
          bool Align = false>
struct op_list_prepend :
    public internal::list_monoid_base<op_list_prepend_view<Type, Allocator>, Align>
{
    /// Construct with default allocator.
    op_list_prepend() {}
    /// Construct with specified allocator.
    op_list_prepend(const Allocator& alloc) :
        internal::list_monoid_base<op_list_prepend_view<Type, Allocator>, Align>(alloc) {}
};


/** Deprecated list-append reducer wrapper class.
 *
 *  reducer_list_append is the same as
 *  @ref reducer<@ref op_list_append>, except that reducer_list_append is a
 *  proxy for the contained view, so that accumulator variable update
 *  operations can be applied directly to the reducer. For example, an element
 *  is appended to a `reducer<%op_list_append>` with `r->push_back(a)`, but an
 *  element can be appended to a `%reducer_list_append` with `r.push_back(a)`.
 *
 *  @deprecated Users are strongly encouraged to use `reducer<monoid>`
 *              reducers rather than the old wrappers like reducer_list_append.
 *              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_list_append`
 *          and `reducer<%op_list_append>`. This allows incremental code
 *          conversion: old code that used `%reducer_list_append` can pass a
 *          `%reducer_list_append` to a converted function that now expects a
 *          pointer or reference to a `reducer<%op_list_append>`, and vice
 *          versa.
 *
 *  @tparam Type        The value type of the list.
 *  @tparam Allocator   The allocator type of the list.
 *
 *  @see op_list_append
 *  @see reducer
 *  @see ReducersList
 */
template <class Type, class Allocator = std::allocator<Type> >
class reducer_list_append :
    public reducer<op_list_append<Type, Allocator, true> >
{
    typedef reducer<op_list_append<Type, Allocator, true> > base;
    using base::view;
public:

    /// The reducer's list type.
    typedef typename base::value_type list_type;

    /// The list's element type.
    typedef Type list_value_type;

    /// The reducer's primitive component type.
    typedef Type basic_value_type;

    /// The monoid type.
    typedef typename base::monoid_type Monoid;

    /** @name Constructors
     */
    //@{

    /** Constructs a reducer with an empty list.
     */
    reducer_list_append() {}

    /** Constructs a reducer with a specified initial list value.
     */
    reducer_list_append(const std::list<Type, Allocator> &initial_value) :
        base(initial_value) {}

    //@}


    /** @name Forwarded functions
     *  @details Functions that update the contained accumulator variable are
     *  simply forwarded to the contained @ref op_and_view. */
    //@{

    /// @copydoc op_list_append_view::push_back(const Type&)
    void push_back(const Type& element) { view().push_back(element); }

    //@}

    /** Allows mutable access to the list within the current view.
     *
     *  @warning    If this method is called before the parallel calculation is
     *              complete, the list returned by this method will be a partial
     *              result.
     *
     *  @returns    A mutable reference to the list within the current view.
     */
    list_type &get_reference() { return view().view_get_reference(); }

    /** Allows read-only access to the list within the current view.
     *
     *  @warning    If this method is called before the parallel calculation is
     *              complete, the list returned by this method will be a partial
     *              result.
     *
     *  @returns    A const reference to the list within the current view.
     */
    list_type const &get_reference() const { return view().view_get_reference(); }

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

    reducer_list_append*       operator->()       { return this; }
    reducer_list_append 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_list_append<Type, Allocator, false> >& ()
    {
        return *reinterpret_cast<
            reducer< op_list_append<Type, Allocator, false> >*
            >(this);
    }
    operator const reducer< op_list_append<Type, Allocator, false> >& () const
    {
        return *reinterpret_cast<
            const reducer< op_list_append<Type, Allocator, false> >*
            >(this);
    }
    //@}

};


/** Deprecated list-prepend reducer wrapper class.
 *
 *  reducer_list_prepend is the same as
 *  @ref reducer<@ref op_list_prepend>, except that reducer_list_prepend is a
 *  proxy for the contained view, so that accumulator variable update operations
 *  can be applied directly to the reducer. For example, an element is prepended
 *  to a `reducer<op_list_prepend>` with `r->push_back(a)`, but an element is
 *  prepended to a `reducer_list_prepend` with `r.push_back(a)`.
 *
 *  @deprecated Users are strongly encouraged to use `reducer<monoid>`
 *              reducers rather than the old wrappers like reducer_list_prepend.
 *              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_list_prepend`
 *          and `reducer<%op_list_prepend>`. This allows incremental code
 *          conversion: old code that used `%reducer_list_prepend` can pass a
 *          `%reducer_list_prepend` to a converted function that now expects a
 *          pointer or reference to a `reducer<%op_list_prepend>`, and vice
 *          versa.
 *
 *  @tparam Type        The value type of the list.
 *  @tparam Allocator   The allocator type of the list.
 *
 *  @see op_list_prepend
 *  @see reducer
 *  @see ReducersList
 */
template <class Type, class Allocator = std::allocator<Type> >
class reducer_list_prepend :
    public reducer<op_list_prepend<Type, Allocator, true> >
{
    typedef reducer<op_list_prepend<Type, Allocator, true> > base;
    using base::view;
public:

    /** The reducer's list type.
     */
    typedef typename base::value_type list_type;

    /** The list's element type.
     */
    typedef Type list_value_type;

    /** The reducer's primitive component type.
     */
    typedef Type basic_value_type;

    /** The monoid type.
     */
    typedef typename base::monoid_type Monoid;

    /** @name Constructors
     */
    //@{

    /** Constructs a reducer with an empty list.
     */
    reducer_list_prepend() {}

    /** Constructs a reducer with a specified initial list value.
     */
    reducer_list_prepend(const std::list<Type, Allocator> &initial_value) :
        base(initial_value) {}

    //@}

    /** @name Forwarded functions
     *  @details Functions that update the contained accumulator variable are
     *  simply forwarded to the contained @ref op_and_view.
     */
    //@{

    /// @copydoc op_list_prepend_view::push_front(const Type&)
    void push_front(const Type& element) { view().push_front(element); }

    //@}

    /** Allows mutable access to the list within the current view.
     *
     *  @warning    If this method is called before the parallel calculation is
     *              complete, the list returned by this method will be a partial
     *              result.
     *
     *  @returns    A mutable reference to the list within the current view.
     */
    list_type &get_reference() { return view().view_get_reference(); }

    /** Allows read-only access to the list within the current view.
     *
     *  @warning    If this method is called before the parallel calculation is
     *              complete, the list returned by this method will be a partial
     *              result.
     *
     *  @returns    A const reference to the list within the current view.
     */
    list_type const &get_reference() const { return view().view_get_reference(); }

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

    reducer_list_prepend*       operator->()       { return this; }
    reducer_list_prepend 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_list_prepend<Type, Allocator, false> >& ()
    {
        return *reinterpret_cast<
            reducer< op_list_prepend<Type, Allocator, false> >*
            >(this);
    }
    operator const reducer< op_list_prepend<Type, Allocator, false> >& () const
    {
        return *reinterpret_cast<
            const reducer< op_list_prepend<Type, Allocator, false> >*
            >(this);
    }
    //@}

};

/// @cond internal

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

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

/// @endcond

//@}

} // Close namespace cilk

#endif //  REDUCER_LIST_H_INCLUDED
