/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2020, Danny Robson */ #pragma once #include #include /////////////////////////////////////////////////////////////////////////////// /// A minimal implementation of the standard concept library for use with /// compilers that lack it. /// /// Portions of this code are adapted from the standard and as such do not /// fall under the top copyright notice. /// /// clang#xxx: Remove me when clang includes an implementation of these. namespace cruft::concepts { template concept floating_point = std::is_floating_point_v; template concept integral = std::is_integral_v; template concept signed_integral = integral && std::is_signed_v; template concept unsigned_integral = integral && std::is_unsigned_v; template concept default_constructible = std::is_default_constructible_v; template concept copy_constructible = std::is_copy_constructible_v; template concept move_constructible = std::is_move_constructible_v; template concept destructible = std::is_nothrow_destructible_v; template concept same_as = std::is_same_v and std::is_same_v; template concept convertible_to = std::is_convertible_v && requires (From (&f)()) { static_cast (f()); }; template < typename LHS, typename RHS > concept assignable_from = std::is_lvalue_reference_v && // clang#xxx: common_reference_t is too annoying to implement as // a temporary fix for this temporary fix. Reintroduce this when // clang knows about common_reference_t. // std::common_reference_with< // std::remove_reference_t const&, // std::remove_reference_t const& // > && requires(LHS lhs, RHS&& rhs) { { lhs = std::forward(rhs) } -> same_as; }; template concept swappable = requires (T &&a, T &&b) { swap (a, b); }; template < class T > concept movable = std::is_object_v && move_constructible && assignable_from && swappable; template concept boolean = movable> && requires ( std::remove_reference_t const& b1, std::remove_reference_t const& b2, bool const a ) { { b1 } -> convertible_to; { !b1 } -> convertible_to; { b1 && b2 } -> same_as; { b1 && a } -> same_as; { a && b2 } -> same_as; { b1 || b2 } -> same_as; { b1 || a } -> same_as; { a || b2 } -> same_as; { b1 == b2 } -> convertible_to; { b1 == a } -> convertible_to; { a == b2 } -> convertible_to; { b1 != b2 } -> convertible_to; { b1 != a } -> convertible_to; { a != b2 } -> convertible_to; }; template concept equality_comparable = requires ( std::remove_reference_t const &a, std::remove_reference_t const &b ) { { a == b } -> boolean; { a != b } -> boolean; { b == a } -> boolean; { b != a } -> boolean; }; } /////////////////////////////////////////////////////////////////////////////// // C++ named requirements namespace cruft::concepts { /// Corresponds to the "Container" named requirement. template concept container = default_constructible && copy_constructible && move_constructible && destructible && equality_comparable && requires (T a, T b) { typename T::value_type; typename T::reference; typename T::const_reference; typename T::iterator; typename T::const_iterator; typename T::difference_type; typename T::size_type; { a = b } -> same_as; { a = std::move (b) } -> same_as; { a.begin () } -> same_as; { a.end () } -> same_as; { a.cbegin () } -> same_as; { a.cend () } -> same_as; { a.swap (b) } -> same_as; { swap (a, b) } -> same_as; { a.size () } -> same_as; { a.max_size () } -> same_as; { a.empty () } -> boolean; }; } /////////////////////////////////////////////////////////////////////////////// // Some handy non-standard concepts namespace cruft::concepts { template concept arithmetic = std::is_arithmetic_v; }