#ifndef DDM__ALGORITHM__GENERATE_H__
#define DDM__ALGORITHM__GENERATE_H__

#include "../../ddm/iterator/GlobIter.h"
#include "../../ddm/algorithm/LocalRange.h"
#include "../../ddm/algorithm/Operation.h"

#include "../dart-impl/dart_communication.h"

#include <algorithm>


namespace ddm {

/**
 * Assigns each element in range [first, last) a value generated by the
 * given function object g.
 *
 * Being a collaborative operation, each unit will invoke the given
 * function on its local elements only.
 *
 * \tparam      ElementType    Type of the elements in the sequence
 *                             invoke, deduced from parameter \c gen
 * \tparam      UnaryFunction  Unary function with signature
 *                             \c void(ElementType &)
 *
 * \complexity  O(d) + O(nl), with \c d dimensions in the global iterators'
 *              pattern and \c nl local elements within the global range
 *
 * \ingroup     DDMAlgorithms
 */
template <
    typename ElementType,
    class    PatternType,
    class    UnaryFunction >
void generate (
  /// Iterator to the initial position in the sequence
  GlobIter<ElementType, PatternType> first,
  /// Iterator to the final position in the sequence
  GlobIter<ElementType, PatternType> last,
  /// Generator function
  UnaryFunction                      gen) {
  /// Global iterators to local range:
  auto lrange = ddm::local_range(first, last);
  auto lfirst = lrange.begin;
  auto llast  = lrange.end;

  std::generate(lfirst, llast, gen);
}

} // namespace ddm

#endif // DDM__ALGORITHM__GENERATE_H__
