// -*- 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 [\<concepts\> header](https://en.cppreference.com/w/cpp/header/concepts) from C++20's standard library.
 * \author Hannes Hauswedell <hannes.hauswedell AT fu-berlin.de>
 */

#pragma once

#if __has_include(<concepts>)
#include <concepts>
#endif // __has_include(<concepts>)

#ifndef __cpp_lib_concepts // use range-v3 to emulate, if C++20 concepts are not available

#include <concepts/concepts.hpp>
#include <range/v3/functional/concepts.hpp>

/*!\defgroup std std
 * \brief A subset of the C++20 standard library made available in pre-C++20 contexts.
 *
 * \details
 *
 * This module provides many parts of the C++20 standard library (and some parts of the C++17 standard library
 * not available in GCC). They are only defined if not found in the compiler's standard library and are called exactly
 * like the originals so they can be used interchangeably. The actual implementation is provided by us or aliased
 * from the range-v3 library.
 *
 * \attention All of this sub-module is subject to change!
 *
 * In particular:
 *
 *   * We do not provide all C++20 library features, only those that are used by SeqAn.
 *   * All of these might change or be removed once C++20 is published.
 *   * The documentation of this module will likely be removed entirely in favour of links to
 *     https://en.cppreference.com
 *
 * It is best you consider every entity in this module as:
 *
 * \noapi
 *
 */

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

namespace std
{

// ==========================================
// [concepts.lang], language-related concepts
// ==========================================

// [concept.same], concept same_as
using ::concepts::same_as;

// [concept.derived], concept derived_from
using ::concepts::derived_from;

// [concept.convertible], concept convertible_to
using ::concepts::convertible_to;

// [concept.commonref], concept common_­reference_­with
using ::concepts::common_reference_with;

// [concept.common], concept common_with
using ::concepts::common_with;

// [concept.arithmetic], arithmetic concepts
using ::concepts::integral;
using ::concepts::signed_integral;
using ::concepts::unsigned_integral;
// using ::concepts::floating_point;
//!\cond
template <typename t>
META_CONCEPT floating_point = std::is_floating_point_v<t>;
//!\endcond

// [concept.assignable], concept assignable_from
using ::concepts::assignable_from;

// [concept.swappable], concept swappable
// namespace ranges { inline namespace unspecified { using ::concepts::swap; } }
using ::concepts::swappable;
using ::concepts::swappable_with;

// [concept.destructible], concept destructible
using ::concepts::destructible;

// [concept.constructible], concept constructible_from
using ::concepts::constructible_from;

// [concept.default.init], concept default_initializable
// using ::concepts::default_initializable;
//!\cond
template <class T>
META_CONCEPT default_initializable = ::concepts::default_constructible<T>;
//!\endcond

// [concept.moveconstructible], concept move_constructible
using ::concepts::move_constructible;

// [concept.copyconstructible], concept copy_constructible
using ::concepts::copy_constructible;

// =======================================
// [concepts.compare], comparison concepts
// =======================================

// [concept.equalitycomparable], concept equality_comparable
using ::concepts::equality_comparable;
using ::concepts::equality_comparable_with;

// [concept.totallyordered], concept totally_ordered
using ::concepts::totally_ordered;
using ::concepts::totally_ordered_with;

// [concept.object], object concepts
using ::concepts::movable;
using ::concepts::copyable;
using ::concepts::semiregular;
using ::concepts::regular;

// ======================================
// [concepts.callable], callable concepts
// ======================================

// [concept.invocable], concept invocable
using ::ranges::invocable;

// [concept.regularinvocable], concept regular_invocable
using ::ranges::regular_invocable;

// [concept.predicate], concept predicate
using ::ranges::predicate;

// [concept.relation], concept relation
using ::ranges::relation;

// [concept.equiv], concept equivalence_relation
// using ::ranges::equivalence_relation;

// [concept.strictweakorder], concept strict_weak_order
using ::ranges::strict_weak_order;

} // namespace std

#endif // not __has_include(<concepts>)
