// bdlat_arrayiterators.h                                             -*-C++-*-
#ifndef INCLUDED_BDLAT_ARRAYITERATORS
#define INCLUDED_BDLAT_ARRAYITERATORS

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

//@PURPOSE: Provide iterator support for bdlat_ArrayFunction-conformant types.
//
//@CLASSES:
//   bdlat_ArrayIterators::BackInsertIterator: class for appending to arrays
//
//@SEE_ALSO: bdlat_arrayfunctions
//
//@DESCRIPTION: This component provides a namespace `bdlat_ArrayIterators` that
// contains definitions for the `bdlat_ArrayIterators::BackInsertIterator`
// class template and the `backInserter` convenience function.  Additional
// iterator types may be added in the future.
//
// `BackInsertIterator<ARRAY_TYPE>` is an iterator type which, when used in an
// expression like "*i++ = v", appends the value `v` to the end of the
// `ARRAY_TYPE` object used to construct the iterator, `i`.  It meets the
// requirements of an STL output iterator and it can be instantiated for any
// type that meets the requirements described in `bdlat_arrayfunctions`.
// `BackInsertIterator` is similar to the standard `bsl::back_insert_iterator`
// class template, which works for STL sequence containers.
//
// The `backInserter` function template takes a parameter of type
// pointer-to-`ARRAY_TYPE`, where `ARRAY_TYPE` is a type that conforms to the
// interface described in the `bdlat_arrayfunctions` component, and returns an
// object of type `BackInsertIterator<ARRAY_TYPE>`.  It is a convenience
// function for creating a `BackInsertIterator` without declaring its exact
// type.  The `backInserter` function is similar to the standard
// `bsl::back_inserter` template function, which works for STL sequence
// containers.  In fact, `backInserter` is specialized for `bsl::vector` so
// that it returns an `bsl::back_insert_iterator`, just like
// `bsl::back_inserter` does.
//
///Thread Safety
///-------------
// A `BackInsertIterator` contains a pointer to an array object and multiple
// `backInsertIterator` objects may point to the same array object.  It is
// safe to access or modify two `BackInsertIterator` objects simultaneously,
// each from a separate thread, if they each refer to a different array
// object.  It is safe to access a single `BackInsertIterator` object
// simultaneously from two or more separate threads, provided no other thread
// is simultaneously modifying the iterator or its referenced array.  It is
// not safe to access or modify a `BackInsertIterator` object in one thread
// while another thread modifies the same iterator, its referenced array
// object, or another iterator referring to the same array.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Basic Usage
/// - - - - - - - - - - -
// To use the facilities in this component, you must of course include the
// header file:
// ```
// #include <bdlat_arrayiterators.h>
// ```
// The main use of the facilities in this component is for creating generic
// algorithms.  The following generic function appends a few integers to the
// end of an object of type `ARRAY` that adheres to the `bdlat_ArrayFunctions`
// interface.  It starts by creating a `BackInsertIterator`:
// ```
// template <typename ARRAY>
// void appendSome(ARRAY *arrayObj)
// {
//     bdlat_ArrayIterators::BackInsertIterator<ARRAY> it(arrayObj);
// ```
// Now, using the "*i++ = v" idiom, append the numbers 5 and 4 to the array
// object:
// ```
//     *it++ = 5;
//     *it++ = 4;
// ```
// Alternatively, one can use the iterator in a standard algorithm.  For
// example, the following code appends the numbers 3, 2, and 1 to the array
// object:
// ```
//     const int VALUES[] = { 3, 2, 1 };
//     const int NUM_VALUES = sizeof(VALUES) / sizeof(VALUES[0]);
//     bsl::copy(VALUES, VALUES + NUM_VALUES, it);
// }
// ```
// An alternative implementation of `appendSome` would use `backInserter` to
// create an iterator without declaring its exact type.  Note that, in this
// case, we do not create a variable `it`, but simply pass the iterator to a
// standard algorithm:
// ```
// template <typename ARRAY>
// void appendSome2(ARRAY *arrayObj)
// {
//     const int VALUES[] = { 5, 4, 3, 2, 1 };
//     const int NUM_VALUES = sizeof(VALUES) / sizeof(VALUES[0]);
//     bsl::copy(VALUES, VALUES + NUM_VALUES,
//               bdlat_ArrayIterators::backInserter(arrayObj));
// }
// ```
// In our main program, we need to construct an array that adheres to the
// `bdlat_arrayfunctions` interface:
// ```
// #include <vector>
//
// int main()
// {
//     typedef bsl::vector<int> my_IntArrayType;
// ```
// The result of calling `appendSome` is that the elements 5, 4, 3, 2 and 1
// are appended to the array:
// ```
//     my_IntArrayType array1;
//     appendSome(&array1);
//     assert(5 == array1[0]);
//     assert(4 == array1[1]);
//     assert(3 == array1[2]);
//     assert(2 == array1[3]);
//     assert(1 == array1[4]);
// ```
// The result of calling `appendSome2` is the same:
// ```
//     my_IntArrayType array2;
//     appendSome2(&array2);
//     assert(array2 == array1);
//
//     return 0;
// }
// ```

#include <bdlscm_version.h>

#include <bdlat_arrayfunctions.h>
#include <bdlat_bdeatoverrides.h>
#include <bdlat_valuetypefunctions.h>

#include <bsls_compilerfeatures.h>
#include <bsls_libraryfeatures.h>

#include <bsl_iterator.h>


namespace BloombergLP {

                        // ==============================
                        // namespace bdlat_ArrayIterators
                        // ==============================

namespace bdlat_ArrayIterators {

                          // ========================
                          // class BackInsertIterator
                          // ========================

/// TBD doc
template <class TYPE>
class BackInsertIterator
#if defined(BSLS_LIBRARYFEATURES_STDCPP_LIBCSTD)
// Sun CC workaround: iterators must be derived from 'std::iterator' to work
// with the native std library algorithms.  However, 'std::iterator' is
// deprecated in C++17, so do not rely on derivation unless required, to avoid
// deprecation warnings on modern compilers.
        : public bsl::iterator<
                        bsl::output_iterator_tag,
                        typename bdlat_ArrayFunctions::ElementType<TYPE>::Type,
                        void, void, void>
#endif  // BSLS_LIBRARYFEATURES_STDCPP_LIBCSTD
{

  public:
    // TYPES
    typedef bsl::output_iterator_tag                         iterator_category;
    typedef typename bdlat_ArrayFunctions::ElementType<TYPE>::Type
                                                             value_type;
    typedef void                                             difference_type;
    typedef void                                             pointer;
    typedef void                                             reference;

  private:
    // Random-access iterator for any type that meets the requirements of a
    // 'bdlat' array type.
    TYPE* d_array;

    /// Manipulator to set the value of a newly-inserted element.
    template <class ELEM_TYPE>
    struct ValueSetter {
        const ELEM_TYPE *d_value;

      public:
        ValueSetter(const ELEM_TYPE* value) : d_value(value) { }
        int operator()(value_type* element) {
            bdlat_ValueTypeFunctions::assign(element, *d_value);
            return 0;
        }
    };

  public:
    // CREATORS

    /// Construct a back-insertion iterator to manipulate the specified
    /// `array`.
    BackInsertIterator(TYPE* array);

#ifdef BSLS_COMPILERFEATURES_SUPPORT_DEFAULTED_FUNCTIONS
    /// Construct a copy of the specified `original`.
    BackInsertIterator(const BackInsertIterator& original) = default;
#endif

#ifdef DOXYGEN // Compiler-generated functions:
    ~BackInsertIterator();
        // Destroy this iterator
#endif

    // MANIPULATORS

    /// Assign this iterator the value of the specified `rhs`.
    BackInsertIterator& operator=(const BackInsertIterator& rhs);

    /// Append the specified `obj` to the end of the array manipulated by
    /// this iterator and return this iterator.
    template <class ELEM_TYPE>
    BackInsertIterator& operator=(const ELEM_TYPE& obj);

    /// Do nothing and return a reference to this modifiable iterator.  This
    /// function is used in generic algorithms that use the expression
    /// `*i++ = v` or `*++i = v`.
    BackInsertIterator& operator*();

    /// Do nothing and return a reference to this modifiable iterator.  This
    /// function is used in generic algorithms that use the expression
    /// `*++i = v`
    BackInsertIterator& operator++();

    /// Do nothing and return a copy of this iterator.  This function is
    /// used in generic algorithms that use the expression `*i++ = v`
    BackInsertIterator operator++(int);
};

/// Return a `BackInsertIterator` (of the appropriate type) to manipulate
/// the specified `array`.  Specializations of this function might return a
/// different back-inserter type.
template <class TYPE>
BackInsertIterator<TYPE> backInserter(TYPE *array);

/// Specialization of `backInserter` for `bsl::vector`.  Return
/// `bsl::back_insert_iterator instead of `BackInsertIterator'.
template <class TYPE, class ALLOC>
typename bsl::back_insert_iterator<bsl::vector<TYPE, ALLOC> >
backInserter(bsl::vector<TYPE, ALLOC> *array);

}  // close namespace bdlat_ArrayIterators

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

                   // ------------------------------
                   // namespace bdlat_ArrayIterators
                   // ------------------------------

                          // ------------------------
                          // class BackInsertIterator
                          // ------------------------

// CREATORS
template <class TYPE>
inline
bdlat_ArrayIterators::BackInsertIterator<TYPE>::BackInsertIterator(TYPE* array)
    : d_array(array)
{
}

// MANIPULATORS
template <class TYPE>
inline
bdlat_ArrayIterators::BackInsertIterator<TYPE>&
bdlat_ArrayIterators::BackInsertIterator<TYPE>::operator=(
    const BackInsertIterator& rhs)
{
    d_array = rhs.d_array;
    return *this;
}

template <class TYPE>
template <class ELEM_TYPE>
inline
bdlat_ArrayIterators::BackInsertIterator<TYPE>&
bdlat_ArrayIterators::BackInsertIterator<TYPE>::operator=(const ELEM_TYPE& obj)
{
    const int length = static_cast<int>(bdlat_ArrayFunctions::size(*d_array));
    bdlat_ArrayFunctions::resize(d_array, length + 1);
    ValueSetter<ELEM_TYPE> setter(&obj);
    bdlat_ArrayFunctions::manipulateElement(d_array, setter, length);

    return *this;
}

template <class TYPE>
inline
bdlat_ArrayIterators::BackInsertIterator<TYPE>&
bdlat_ArrayIterators::BackInsertIterator<TYPE>::operator*()
{
    return *this;
}

template <class TYPE>
inline
bdlat_ArrayIterators::BackInsertIterator<TYPE>&
bdlat_ArrayIterators::BackInsertIterator<TYPE>::operator++()
{
    return *this;
}

template <class TYPE>
inline
bdlat_ArrayIterators::BackInsertIterator<TYPE>
bdlat_ArrayIterators::BackInsertIterator<TYPE>::operator++(int)
{
    return *this;
}

                       // -------------------------
                       // namespace-level functions
                       // -------------------------

template <class TYPE>
inline
bdlat_ArrayIterators::BackInsertIterator<TYPE>
bdlat_ArrayIterators::backInserter(TYPE *array)
{
    return BackInsertIterator<TYPE>(array);
}

template <class TYPE, class ALLOC>
inline
typename bsl::back_insert_iterator<bsl::vector<TYPE, ALLOC> >
bdlat_ArrayIterators::backInserter(bsl::vector<TYPE, ALLOC> *array)
{
    return bsl::back_insert_iterator<bsl::vector<TYPE, ALLOC> >(*array);
}

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