// -*- C++ -*-
// -----------------------------------------------------------------------------------------------------
// Copyright (c) 2006-2020, Knut Reinert & Freie Universität Berlin
// Copyright (c) 2016-2020, Knut Reinert & MPI für molekulare Genetik
// This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
// shipped with this file and also available at: https://github.com/seqan/seqan3/blob/master/LICENSE.md
// -----------------------------------------------------------------------------------------------------

/*!\file
 * \brief Adaptations of algorithms from the Ranges TS
 * \author René Rahn <rene.rahn AT fu-berlin.de>
 */

#pragma once

/*!\defgroup std_algorithm algorithm
 * \ingroup std
 * \brief The \<algorithm\> header with additional ranges algorithm from C++20's standard library.
 */

#include <algorithm>

#ifndef __cpp_lib_ranges  // If not C++20 ranges available, implement via range-v3.

#include <seqan3/std/ranges>

#include <range/v3/algorithm/all_of.hpp>
#include <range/v3/algorithm/copy.hpp>
#include <range/v3/algorithm/copy_n.hpp>
#include <range/v3/algorithm/equal.hpp>
#include <range/v3/algorithm/fill.hpp>
#include <range/v3/algorithm/find_if_not.hpp>
#include <range/v3/algorithm/find_if.hpp>
#include <range/v3/algorithm/find.hpp>
#include <range/v3/algorithm/for_each.hpp>
#include <range/v3/algorithm/generate.hpp>
#include <range/v3/algorithm/min_element.hpp>
#include <range/v3/algorithm/max_element.hpp>
#include <range/v3/algorithm/move_backward.hpp>
#include <range/v3/algorithm/move.hpp>
#include <range/v3/algorithm/reverse.hpp>
#include <range/v3/algorithm/sort.hpp>
#include <range/v3/algorithm/transform.hpp>

namespace std::ranges
{

namespace
{
// https://eel.is/c++draft/algorithm.syn

// [algorithms.results], algorithm result types
// using ::ranges::cpp20::in_fun_result;
// using ::ranges::cpp20::in_in_result;
// using ::ranges::cpp20::in_out_result;
// using ::ranges::cpp20::in_in_out_result;
// using ::ranges::cpp20::in_out_out_result;
// using ::ranges::cpp20::min_max_result;
// using ::ranges::cpp20::in_found_result;

// =====================================================
// [alg.nonmodifying], non-modifying sequence operations
// =====================================================

// [alg.all.of], all of
using ::ranges::cpp20::all_of;

// [alg.any.of], any of
// using ::ranges::cpp20::any_of;

// [alg.none.of], none of
// using ::ranges::cpp20::none_of;

// [alg.foreach], for each
// using ::ranges::cpp20::for_each_result;
using ::ranges::cpp20::for_each;
// using ::ranges::cpp20::for_each_n_result;
// using ::ranges::cpp20::for_each_n;

// [alg.find], find
using ::ranges::cpp20::find;
using ::ranges::cpp20::find_if;
using ::ranges::cpp20::find_if_not;

// [alg.find.end], find end
// using ::ranges::cpp20::find_end;

// [alg.find.first.of], find first
// using ::ranges::cpp20::find_first_of;

// [alg.adjacent.find], adjacent find
// using ::ranges::cpp20::adjacent_find;

// [alg.count], count
// using ::ranges::cpp20::count;
// using ::ranges::cpp20::count_if;

// [mismatch], mismatch
// using ::ranges::cpp20::mismatch;

// [alg.equal], equal
using ::ranges::cpp20::equal;

// [alg.is.permutation], is permutation
// using ::ranges::cpp20::is_permutation;

// [alg.search], search
// using ::ranges::cpp20::search;
// using ::ranges::cpp20::search_n;

// ========================================================
// [alg.modifying.operations], mutating sequence operations
// ========================================================

// [alg.copy], copy
// using ::ranges::cpp20::copy_result;
using ::ranges::cpp20::copy;
// using ::ranges::cpp20::copy_n_result;
using ::ranges::cpp20::copy_n;
// using ::ranges::cpp20::copy_if_result;
// using ::ranges::cpp20::copy_if;
// using ::ranges::cpp20::copy_backward_result;
// using ::ranges::cpp20::copy_backward;

// [alg.move], move
// using ::ranges::cpp20::move_result;
using ::ranges::cpp20::move;
// using ::ranges::cpp20::move_backward_result;
using ::ranges::cpp20::move_backward;

// [alg.swap], swap
// using ::ranges::cpp20::swap_ranges_result;
// using ::ranges::cpp20::swap_ranges;

// [alg.transform], transform
// using ::ranges::cpp20::unary_transform_result;
// using ::ranges::cpp20::binary_transform_result;
using ::ranges::cpp20::transform;

// [alg.replace], replace
// using ::ranges::cpp20::replace;
// using ::ranges::cpp20::replace_if;
// using ::ranges::cpp20::replace_copy_result;
// using ::ranges::cpp20::replace_copy;
// using ::ranges::cpp20::replace_copy_if_result;
// using ::ranges::cpp20::replace_copy_if;

// [alg.fill], fill
using ::ranges::cpp20::fill;
// using ::ranges::cpp20::fill_n;

// [alg.generate], generate
using ::ranges::cpp20::generate;

// [alg.remove], remove
// using ::ranges::cpp20::remove;
// using ::ranges::cpp20::remove_if;
// using ::ranges::cpp20::remove_copy_result;
// using ::ranges::cpp20::remove_copy;
// using ::ranges::cpp20::remove_copy_if_result;
// using ::ranges::cpp20::remove_copy_if;

// [alg.unique], unique
// using ::ranges::cpp20::unique;
// using ::ranges::cpp20::unique_copy_result;
// using ::ranges::cpp20::unique_copy;

// [alg.reverse], reverse
using ::ranges::cpp20::reverse;
// using ::ranges::cpp20::reverse_copy_result;
// using ::ranges::cpp20::reverse_copy;

// [alg.rotate], rotate
// using ::ranges::cpp20::rotate;
// using ::ranges::cpp20::rotate_copy_result;
// using ::ranges::cpp20::rotate_copy;

// [alg.random.sample], sample
// using ::ranges::cpp20::sample;

// [alg.random.shuffle], shuffle
// using ::ranges::cpp20::shuffle;

// =============================================
// [alg.sorting], sorting and related operations
// =============================================

// [alg.sort], sorting
using ::ranges::cpp20::sort;
// using ::ranges::cpp20::stable_sort;
// using ::ranges::cpp20::partial_sort;
// using ::ranges::cpp20::partial_sort_copy;
// using ::ranges::cpp20::is_sorted;
// using ::ranges::cpp20::is_sorted_until;

// [alg.nth.element], Nth element
// using ::ranges::cpp20::nth_element;

// [alg.binary.search], binary search
// using ::ranges::cpp20::lower_bound;
// using ::ranges::cpp20::upper_bound;
// using ::ranges::cpp20::equal_range;
// using ::ranges::cpp20::binary_search;

// [alg.partitions], partitions
// using ::ranges::cpp20::is_partitioned;
// using ::ranges::cpp20::partition;
// using ::ranges::cpp20::stable_partition;
// using ::ranges::cpp20::partition_copy_result;
// using ::ranges::cpp20::partition_copy;
// using ::ranges::cpp20::partition_point;

// [alg.merge], merge
// using ::ranges::cpp20::merge_result;
// using ::ranges::cpp20::merge;
// using ::ranges::cpp20::inplace_merge;

// [alg.set.operations], set operations
// using ::ranges::cpp20::includes;
// using ::ranges::cpp20::set_union_result;
// using ::ranges::cpp20::set_union;
// using ::ranges::cpp20::set_intersection_result;
// using ::ranges::cpp20::set_intersection;
// using ::ranges::cpp20::set_difference_result;
// using ::ranges::cpp20::set_difference;
// using ::ranges::cpp20::set_symmetric_difference_result;
// using ::ranges::cpp20::set_symmetric_difference;

// [alg.heap.operations], heap operations
// using ::ranges::cpp20::push_heap;
// using ::ranges::cpp20::pop_heap;
// using ::ranges::cpp20::make_heap;
// using ::ranges::cpp20::sort_heap;
// using ::ranges::cpp20::is_heap;
// using ::ranges::cpp20::is_heap_until;

// [alg.min.max], minimum and maximum
// using ::ranges::cpp20::min;
// using ::ranges::cpp20::max;
// using ::ranges::cpp20::minmax_result;
// using ::ranges::cpp20::minmax;
using ::ranges::cpp20::min_element;
using ::ranges::cpp20::max_element;
// using ::ranges::cpp20::minmax_element;

// [alg.clamp], bounded value
// using ::ranges::cpp20::clamp;

// [alg.lex.comparison], lexicographical comparison
// using ::ranges::cpp20::lexicographical_compare;

// [alg.permutation.generators], permutations
// using ::ranges::cpp20::next_permutation_result;
// using ::ranges::cpp20::next_permutation;
// using ::ranges::cpp20::prev_permutation_result;
// using ::ranges::cpp20::prev_permutation;

} // anonymous namespace

} // namespace std::ranges

#endif  // __cpp_lib_ranges
