// bdlat_arrayiterators.h                                             -*-C++-*-

// ----------------------------------------------------------------------------
//                                   NOTICE
//
// This component is not up to date with current BDE coding standards, and
// should not be used as an example for new development.
// ----------------------------------------------------------------------------

#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
///-----
// 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
                          // ========================

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
{
    // TBD doc

  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;

    template <class ELEM_TYPE>
    struct ValueSetter {
        // Manipulator to set the value of a newly-inserted element.
        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
    BackInsertIterator(TYPE* array);
        // Construct a back-insertion iterator to manipulate the specified
        // 'array'.

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

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

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

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

    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' 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++(int);
        // Do nothing and return a copy of this iterator.  This function is
        // used in generic algorithms that use the expression '*i++ = v'
};

template <class TYPE>
BackInsertIterator<TYPE> backInserter(TYPE *array);
    // 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, class ALLOC>
typename bsl::back_insert_iterator<bsl::vector<TYPE, ALLOC> >
backInserter(bsl::vector<TYPE, ALLOC> *array);
    // Specialization of 'backInserter' for 'bsl::vector'.  Return
    // 'bsl::back_insert_iterator instead of 'BackInsertIterator'.

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