// -*- C++ -*-
// -----------------------------------------------------------------------------------------------------
// Copyright (c) 2006-2021, Knut Reinert & Freie Universität Berlin
// Copyright (c) 2016-2021, 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 The [\<iterator\> header](https://en.cppreference.com/w/cpp/header/iterator) from C++20's standard library.
 * \author Hannes Hauswedell <hannes.hauswedell AT fu-berlin.de>
 */

#pragma once

#include <iterator>

/*!\defgroup std_iterator iterator
 * \ingroup std
 * \brief The [\<iterator\> header](https://en.cppreference.com/w/cpp/header/iterator) from C++20's standard library.
 */

// import API that changed behaviour from C++-17 to C++20 into std::cpp20
#ifdef __cpp_lib_ranges
namespace std
{
namespace cpp20
{
// see https://github.com/orgs/seqan/projects/4#card-37029069
using ::std::back_inserter;
// using ::std::front_inserter;
// using ::std::insert_iterator;
// using ::std::istream_iterator;
// using ::std::istreambuf_iterator;
using ::std::ostream_iterator;
using ::std::ostreambuf_iterator;
} // namespace cpp20
} // namespace std
#endif // __cpp_lib_ranges

#ifndef __cpp_lib_ranges // implement C++20 iterators via range-v3

//!\cond
#ifndef RANGES_DEEP_STL_INTEGRATION
#define RANGES_DEEP_STL_INTEGRATION 1
#endif
//!\endcond

#include <range/v3/iterator/access.hpp>
#include <range/v3/iterator/concepts.hpp>
#include <range/v3/iterator/default_sentinel.hpp>
#include <range/v3/iterator/insert_iterators.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/iterator/stream_iterators.hpp>
#include <range/v3/iterator/traits.hpp>

#include <seqan3/std/concepts>

// ============================================================================
//  namespace aliasing
// ============================================================================

namespace std
{

namespace
{
// https://eel.is/c++draft/iterator.synopsis

// ========================================
// [iterator.assoc.types], associated types
// ========================================

// [incrementable.traits], incrementable traits
using ::ranges::cpp20::incrementable_traits;
using ::ranges::cpp20::iter_difference_t;

// [readable.traits], indirectly readable traits
using ::ranges::cpp20::indirectly_readable_traits;
using ::ranges::cpp20::iter_value_t;

// [iterator.traits], iterator traits
using ::ranges::cpp20::iter_reference_t;
using ::ranges::cpp20::iter_rvalue_reference_t;

// ======================================
// [iterator.concepts], iterator concepts
// ======================================

// [iterator.concept.readable], concept indirectly_readable
using ranges::cpp20::indirectly_readable;
// using ::ranges::cpp20::iter_common_reference_t;

// [iterator.concept.writable], concept indirectly_writable
using ::ranges::cpp20::indirectly_writable;

// [iterator.concept.winc], concept weakly_incrementable
using ::ranges::cpp20::weakly_incrementable;

// [iterator.concept.inc], concept incrementable
using ::ranges::cpp20::incrementable;

// [iterator.concept.iterator], concept input_or_output_iterator
using ::ranges::cpp20::input_or_output_iterator;

// [iterator.concept.sentinel], concept sentinel_for
using ::ranges::cpp20::sentinel_for;

// [iterator.concept.sizedsentinel], concept sized_sentinel_for
// using ::ranges::cpp20::disable_sized_sentinel_for;
using ::ranges::cpp20::sized_sentinel_for;

// [iterator.concept.input], concept input_iterator
using ::ranges::cpp20::input_iterator;

// [iterator.concept.output], concept output_iterator
using ::ranges::cpp20::output_iterator;

// [iterator.concept.forward], concept forward_iterator
using ::ranges::cpp20::forward_iterator;

// [iterator.concept.bidir], concept bidirectional_iterator
using ::ranges::cpp20::bidirectional_iterator;

// [iterator.concept.random.access], concept random_­access_­iterator
using ::ranges::cpp20::random_access_iterator;

// [iterator.concept.contiguous], concept contiguous_iterator
using ::ranges::cpp20::contiguous_iterator;

// ==================================================
// [indirectcallable], indirect callable requirements
// ==================================================

// [indirectcallable.indirectinvocable], indirect callables
using ::ranges::cpp20::indirectly_unary_invocable;
using ::ranges::cpp20::indirectly_regular_unary_invocable;
using ::ranges::cpp20::indirect_unary_predicate;
// using ::ranges::cpp20::indirect_binary_predicate;
// using ::ranges::cpp20::indirect_equivalence_relation;
using ::ranges::cpp20::indirect_strict_weak_order;
using ::ranges::cpp20::indirect_result_t;

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

// ========================================
// [alg.req], common algorithm requirements
// ========================================

// [alg.req.ind.move], concept indirectly_movable
using ::ranges::cpp20::indirectly_movable;
using ::ranges::cpp20::indirectly_movable_storable;

// [alg.req.ind.copy], concept indirectly_copyable
using ::ranges::cpp20::indirectly_copyable;
using ::ranges::cpp20::indirectly_copyable_storable;

// [alg.req.ind.swap], concept indirectly_swappable
using ::ranges::cpp20::indirectly_swappable;

// [alg.req.ind.cmp], concept indirectly_comparable
// using ::ranges::cpp20::indirectly_comparable;

// [alg.req.permutable], concept permutable
using ::ranges::cpp20::permutable;

// [alg.req.mergeable], concept mergeable
using ::ranges::cpp20::mergeable;

// [alg.req.sortable], concept sortable
using ::ranges::cpp20::sortable;

// =================================
// [iterator.primitives], primitives
// =================================

// [std.iterator.tags], iterator tags
using ::ranges::contiguous_iterator_tag;

// ======================================================
// [predef.iterators], predefined iterators and sentinels
// ======================================================

// [insert.iterators], insert iterators
namespace cpp20
{
// see https://github.com/orgs/seqan/projects/4#card-37029069
using ::ranges::cpp20::back_inserter;
// using ::ranges::cpp20::front_inserter;
// using ::ranges::cpp20::insert_iterator;
// using ::ranges::cpp20::istream_iterator;
// using ::ranges::cpp20::istreambuf_iterator;
using ::ranges::cpp20::ostream_iterator;
using ::ranges::cpp20::ostreambuf_iterator;
} // namespace cpp20

// [iterators.common], common iterators
// using ::ranges::cpp20::common_iterator;

// [default.sentinels], default sentinels
using ::ranges::cpp20::default_sentinel_t;
using ::ranges::cpp20::default_sentinel;

// [iterators.counted], counted iterators
// using ::ranges::cpp20::counted_iterator;

// [unreachable.sentinels], unreachable sentinels
// using ::ranges::cpp20::unreachable_sentinel_t;
// using ::ranges::cpp20::unreachable_sentinel;

// [iterator.range], range access
// using ::ranges::cpp20::ssize;
} // anonymous namespace

} // namespace std

namespace std::ranges
{

namespace
{
// =============================================
// [iterator.cust], customization points
// =============================================

// [iterator.cust.move], ranges::iter_move
using ::ranges::cpp20::iter_move;

// [iterator.cust.swap], ranges::iter_swap
// using ::ranges::cpp20::iter_swap;

// =============================================
// [range.iter.ops], range iterator operations
// =============================================

// [range.iter.op.advance], ranges::advance
using ::ranges::cpp20::advance;

// [range.iter.op.distance], ranges::distance
using ::ranges::cpp20::distance;

// [range.iter.op.next], ranges::next
using ::ranges::cpp20::next;

// [range.iter.op.prev], ranges::prev
using ::ranges::cpp20::prev;
} // anonymous namespace

} // namespace std::ranges

#endif // __cpp_lib_ranges
