Program Listing for File non_modifyng_sequence_ops.h

Return to documentation for file (include/shad/core/impl/non_modifyng_sequence_ops.h)

//===------------------------------------------------------------*- C++ -*-===//
//
//                                     SHAD
//
//      The Scalable High-performance Algorithms and Data Structure Library
//
//===----------------------------------------------------------------------===//
//
// Copyright 2018 Battelle Memorial Institute
//
// 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.
//
//===----------------------------------------------------------------------===//

#ifndef INCLUDE_SHAD_CORE_IMPL_NON_MODIFYING_SEQUENCE_OPS_H
#define INCLUDE_SHAD_CORE_IMPL_NON_MODIFYING_SEQUENCE_OPS_H

#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <iterator>

#include "shad/core/execution.h"
#include "shad/distributed_iterator_traits.h"
#include "shad/runtime/runtime.h"

#include "impl_patterns.h"

namespace shad {
namespace impl {

template <typename ForwardItr, typename UnaryPredicate>
bool all_of(distributed_sequential_tag&& policy, ForwardItr first,
            ForwardItr last, UnaryPredicate p) {
  using itr_traits = distributed_iterator_traits<ForwardItr>;

  return distributed_folding_map_early_termination(
      // range
      first, last,
      // kernel
      [](ForwardItr first, ForwardItr last, const bool partial_solution,
         UnaryPredicate p) {
        // local processing
        auto lrange = itr_traits::local_range(first, last);
        auto local_res = std::all_of(lrange.begin(), lrange.end(), p);
        // update the partial solution
        return local_res;
      },
      // halt condition
      [](const bool x) { return !x; },
      // initial solution
      true,
      // map arguments
      p);
}

template <typename ForwardItr, typename UnaryPredicate>
bool all_of(distributed_parallel_tag&& policy, ForwardItr first,
            ForwardItr last, UnaryPredicate p) {
  using itr_traits = distributed_iterator_traits<ForwardItr>;
  using value_t = typename itr_traits::value_type;

  // distributed map
  auto map_res = distributed_map(
      // range
      first, last,
      // kernel
      [](ForwardItr first, ForwardItr last, UnaryPredicate p) -> uint8_t {
        using local_iterator_t = typename itr_traits::local_iterator_type;

        // local map
        auto lrange = itr_traits::local_range(first, last);

        auto map_res = local_map(
            // range
            lrange.begin(), lrange.end(),
            // kernel
            [&](const local_iterator_t& b, const local_iterator_t& e)
                -> uint8_t { return std::all_of(b, e, p); });

        // local reduce
        return std::all_of(map_res.begin(), map_res.end(),
                           [](bool x) { return x; });
      },
      // map arguments
      p);

  // reduce
  return std::all_of(map_res.begin(), map_res.end(), [](bool x) { return x; });
}

template <typename ForwardItr, typename UnaryPredicate>
bool any_of(distributed_sequential_tag&& policy, ForwardItr first,
            ForwardItr last, UnaryPredicate p) {
  using itr_traits = distributed_iterator_traits<ForwardItr>;

  return distributed_folding_map_early_termination(
      // range
      first, last,
      // kernel
      [](ForwardItr first, ForwardItr last, const bool partial_solution,
         UnaryPredicate p) {
        // local processing
        auto lrange = itr_traits::local_range(first, last);
        auto local_res = std::any_of(lrange.begin(), lrange.end(), p);
        // update the partial solution
        return local_res;
      },
      // halt condition
      [](const bool x) { return x; },
      // initial solution
      false,
      // map arguments
      p);
}

template <typename ForwardItr, typename UnaryPredicate>
bool any_of(distributed_parallel_tag&& policy, ForwardItr first,
            ForwardItr last, UnaryPredicate p) {
  using itr_traits = distributed_iterator_traits<ForwardItr>;
  using value_t = typename itr_traits::value_type;

  // distributed map
  auto map_res = distributed_map(
      // range
      first, last,
      // kernel
      [](ForwardItr first, ForwardItr last, UnaryPredicate p) -> uint8_t {
        using local_iterator_t = typename itr_traits::local_iterator_type;

        // local map
        auto lrange = itr_traits::local_range(first, last);

        auto map_res = local_map(
            // range
            lrange.begin(), lrange.end(),
            // kernel
            [&](local_iterator_t b, local_iterator_t e) -> uint8_t {
              return std::any_of(b, e, p);
            });

        // local reduce
        return std::any_of(map_res.begin(), map_res.end(),
                           [](bool x) { return x; });
      },
      // map arguments
      p);

  // reduce
  return std::any_of(map_res.begin(), map_res.end(), [](bool x) { return x; });
}

template <typename ForwardItr, typename T>
ForwardItr find(distributed_sequential_tag&& policy, ForwardItr first,
                ForwardItr last, const T& value) {
  using itr_traits = distributed_iterator_traits<ForwardItr>;

  return distributed_folding_map_early_termination(
      // range
      first, last,
      // kernel
      [](ForwardItr first, ForwardItr last, const ForwardItr partial_solution,
         const T& value) {
        // local processing
        auto lrange = itr_traits::local_range(first, last);
        auto local_res = std::find(lrange.begin(), lrange.end(), value);
        // update the partial solution
        return (local_res != lrange.end())
                   ? itr_traits::iterator_from_local(first, last, local_res)
                   : partial_solution;
      },
      // halt condition
      [&](const ForwardItr x) { return x != last; },
      // initial solution
      last,
      // map arguments
      value);
}

template <typename ForwardItr, typename T>
ForwardItr find(distributed_parallel_tag&& policy, ForwardItr first,
                ForwardItr last, const T& value) {
  using itr_traits = distributed_iterator_traits<ForwardItr>;
  using value_t = typename itr_traits::value_type;

  // distributed map
  auto map_res = distributed_map(
      // range
      first, last,
      // kernel
      [](ForwardItr first, ForwardItr last, const T& value) {
        using local_iterator_t = typename itr_traits::local_iterator_type;

        // local map
        auto lrange = itr_traits::local_range(first, last);

        auto map_res = local_map(
            // range
            lrange.begin(), lrange.end(),
            // kernel
            [&](local_iterator_t b, local_iterator_t e) {
              auto res = std::find(b, e, value);
              return res != e ? res : lrange.end();
            });

        // local reduce
        auto found = std::find_if(
            map_res.begin(), map_res.end(),
            [&](const local_iterator_t& i) { return i != lrange.end(); });
        return found != map_res.end()
                   ? itr_traits::iterator_from_local(first, last, *found)
                   : last;
      },
      // map arguments
      value);

  // reduce
  auto found = std::find_if(map_res.begin(), map_res.end(),
                            [&](ForwardItr i) { return i != last; });
  return found != map_res.end() ? *found : last;
}

template <typename ForwardItr, typename UnaryPredicate>
ForwardItr find_if(distributed_sequential_tag&& policy, ForwardItr first,
                   ForwardItr last, UnaryPredicate p) {
  using itr_traits = distributed_iterator_traits<ForwardItr>;

  return distributed_folding_map_early_termination(
      // range
      first, last,
      // kernel
      [](ForwardItr first, ForwardItr last, const ForwardItr partial_solution,
         UnaryPredicate p) {
        // local processing
        auto lrange = itr_traits::local_range(first, last);
        auto local_res = std::find_if(lrange.begin(), lrange.end(), p);
        // update the partial solution
        return (local_res != lrange.end())
                   ? itr_traits::iterator_from_local(first, last, local_res)
                   : partial_solution;
      },
      // halt condition
      [&](const ForwardItr x) { return x != last; },
      // initial solution
      last,
      // map arguments
      p);
}

template <typename ForwardItr, typename UnaryPredicate>
ForwardItr find_if(distributed_parallel_tag&& policy, ForwardItr first,
                   ForwardItr last, UnaryPredicate p) {
  using itr_traits = distributed_iterator_traits<ForwardItr>;
  using value_t = typename itr_traits::value_type;

  // distributed map
  auto map_res = distributed_map(
      // range
      first, last,
      // kernel
      [](ForwardItr first, ForwardItr last, UnaryPredicate p) {
        using local_iterator_t = typename itr_traits::local_iterator_type;

        // local map
        auto lrange = itr_traits::local_range(first, last);

        auto map_res = local_map(
            // range
            lrange.begin(), lrange.end(),
            // kernel
            [&](local_iterator_t b, local_iterator_t e) {
              auto res = std::find_if(b, e, p);
              return res != e ? res : lrange.end();
            });

        // local reduce
        auto found = std::find_if(
            map_res.begin(), map_res.end(),
            [&](const local_iterator_t& i) { return i != lrange.end(); });
        return found != map_res.end()
                   ? itr_traits::iterator_from_local(first, last, *found)
                   : last;
      },
      // map arguments
      p);

  // reduce
  auto found = std::find_if(map_res.begin(), map_res.end(),
                            [&](ForwardItr i) { return i != last; });
  return found != map_res.end() ? *found : last;
}

template <typename ForwardItr, typename UnaryPredicate>
ForwardItr find_if_not(distributed_sequential_tag&& policy, ForwardItr first,
                       ForwardItr last, UnaryPredicate p) {
  using itr_traits = distributed_iterator_traits<ForwardItr>;

  return distributed_folding_map_early_termination(
      // range
      first, last,
      // kernel
      [](ForwardItr first, ForwardItr last, const ForwardItr partial_solution,
         UnaryPredicate p) {
        // local processing
        auto lrange = itr_traits::local_range(first, last);
        auto local_res = std::find_if_not(lrange.begin(), lrange.end(), p);
        // update the partial solution
        return (local_res != lrange.end())
                   ? itr_traits::iterator_from_local(first, last, local_res)
                   : partial_solution;
      },
      // halt condition
      [&](const ForwardItr x) { return x != last; },
      // initial solution
      last,
      // map arguments
      p);
}

template <typename ForwardItr, typename UnaryPredicate>
ForwardItr find_if_not(distributed_parallel_tag&& policy, ForwardItr first,
                       ForwardItr last, UnaryPredicate p) {
  using itr_traits = distributed_iterator_traits<ForwardItr>;
  using value_t = typename itr_traits::value_type;

  // distributed map
  auto map_res = distributed_map(
      // range
      first, last,
      // kernel
      [](ForwardItr first, ForwardItr last, UnaryPredicate p) {
        using local_iterator_t = typename itr_traits::local_iterator_type;

        // local map
        auto lrange = itr_traits::local_range(first, last);

        auto map_res = local_map(
            // range
            lrange.begin(), lrange.end(),
            // kernel
            [&](local_iterator_t b, local_iterator_t e) {
              auto res = std::find_if_not(b, e, p);
              return res != e ? res : lrange.end();
            });

        // local reduce
        auto found = std::find_if(
            map_res.begin(), map_res.end(),
            [&](const local_iterator_t& i) { return i != lrange.end(); });
        return found != map_res.end()
                   ? itr_traits::iterator_from_local(first, last, *found)
                   : last;
      },
      // map arguments
      p);

  // reduce
  auto found = std::find_if(map_res.begin(), map_res.end(),
                            [&](ForwardItr i) { return i != last; });
  return found != map_res.end() ? *found : last;
}

template <typename ForwardItr, typename UnaryPredicate>
void for_each(distributed_sequential_tag&& policy, ForwardItr first,
              ForwardItr last, UnaryPredicate p) {
  using itr_traits = distributed_iterator_traits<ForwardItr>;

  distributed_folding_map_void(
      // range
      first, last,
      // kernel
      [](ForwardItr first, ForwardItr last, UnaryPredicate p) {
        // local processing
        auto lrange = itr_traits::local_range(first, last);
        std::for_each(lrange.begin(), lrange.end(), p);
      },
      // map arguments
      p);
}

template <typename ForwardItr, typename UnaryPredicate>
void for_each(distributed_parallel_tag&& policy, ForwardItr first,
              ForwardItr last, UnaryPredicate p) {
  using itr_traits = distributed_iterator_traits<ForwardItr>;

  // distributed map
  distributed_map_void(
      // range
      first, last,
      // kernel
      [](ForwardItr first, ForwardItr last, UnaryPredicate p) {
        using local_iterator_t = typename itr_traits::local_iterator_type;

        // local map
        auto lrange = itr_traits::local_range(first, last);

        local_map_void(
            // range
            lrange.begin(), lrange.end(),
            // kernel
            [&](local_iterator_t b, local_iterator_t e) {
              std::for_each(b, e, p);
            });
      },
      // map arguments
      p);
}

template <typename InputItr, typename T>
typename shad::distributed_iterator_traits<InputItr>::difference_type count(
    distributed_sequential_tag&& policy, InputItr first, InputItr last,
    const T& value) {
  using itr_traits = distributed_iterator_traits<InputItr>;
  using res_t =
      typename shad::distributed_iterator_traits<InputItr>::difference_type;

  return distributed_folding_map(
      // range
      first, last,
      // kernel
      [](InputItr first, InputItr last, res_t cnt, const T& value) {
        // local processing
        auto lrange = itr_traits::local_range(first, last);
        auto local_res = std::count(lrange.begin(), lrange.end(), value);
        // update the partial solution
        return cnt + local_res;
      },
      // initial solution
      res_t{0},
      // map arguments
      value);
}

template <typename InputItr, typename T>
typename shad::distributed_iterator_traits<InputItr>::difference_type count(
    distributed_parallel_tag&& policy, InputItr first, InputItr last,
    const T& value) {
  using itr_traits = distributed_iterator_traits<InputItr>;
  using res_t =
      typename shad::distributed_iterator_traits<InputItr>::difference_type;

  // distributed map
  auto map_res = distributed_map(
      // range
      first, last,
      // kernel
      [](InputItr first, InputItr last, const T& value) {
        using local_iterator_t = typename itr_traits::local_iterator_type;

        // local map
        auto lrange = itr_traits::local_range(first, last);

        auto map_res = local_map(
            // range
            lrange.begin(), lrange.end(),
            // kernel
            [&](local_iterator_t b, local_iterator_t e) {
              return std::count(b, e, value);
            });

        // local reduce
        return std::accumulate(
            map_res.begin(), map_res.end(), res_t{0},
            [](const res_t& acc, const res_t& x) { return acc + x; });
      },
      // map arguments
      value);

  // reduce
  return std::accumulate(
      map_res.begin(), map_res.end(), res_t{0},
      [](const res_t& acc, const res_t& x) { return acc + x; });
}

template <typename InputItr, typename UnaryPredicate>
typename shad::distributed_iterator_traits<InputItr>::difference_type count_if(
    distributed_sequential_tag&& policy, InputItr first, InputItr last,
    UnaryPredicate p) {
  using itr_traits = distributed_iterator_traits<InputItr>;
  using res_t =
      typename shad::distributed_iterator_traits<InputItr>::difference_type;

  return distributed_folding_map(
      // range
      first, last,
      // kernel
      [](InputItr first, InputItr last, res_t cnt, UnaryPredicate p) {
        // local processing
        auto lrange = itr_traits::local_range(first, last);
        auto local_res = std::count_if(lrange.begin(), lrange.end(), p);
        // update the partial solution
        return cnt + local_res;
      },
      // initial solution
      res_t{0},
      // map arguments
      p);
}

template <typename InputItr, typename UnaryPredicate>
typename shad::distributed_iterator_traits<InputItr>::difference_type count_if(
    distributed_parallel_tag&& policy, InputItr first, InputItr last,
    UnaryPredicate p) {
  using itr_traits = distributed_iterator_traits<InputItr>;
  using res_t =
      typename shad::distributed_iterator_traits<InputItr>::difference_type;

  // distributed map
  auto map_res = distributed_map(
      // range
      first, last,
      // kernel
      [](InputItr first, InputItr last, UnaryPredicate p) {
        using local_iterator_t = typename itr_traits::local_iterator_type;

        // local map
        auto lrange = itr_traits::local_range(first, last);

        auto map_res = local_map(
            // range
            lrange.begin(), lrange.end(),
            // kernel
            [&](local_iterator_t b, local_iterator_t e) {
              return std::count_if(b, e, p);
            });

        // local reduce
        return std::accumulate(
            map_res.begin(), map_res.end(), res_t{0},
            [](const res_t& acc, const res_t& x) { return acc + x; });
      },
      // map arguments
      p);

  // reduce
  return std::accumulate(
      map_res.begin(), map_res.end(), res_t{0},
      [](const res_t& acc, const res_t& x) { return acc + x; });
}

}  // namespace impl
}  // namespace shad

#endif /* INCLUDE_SHAD_CORE_IMPL_NON_MODIFYING_SEQUENCE_OPS_H */