From 5f6eef34781a73fb64e03e7b7069daf0ebaf2605 Mon Sep 17 00:00:00 2001 From: Christos Houtouridis Date: Sun, 13 Oct 2019 19:56:47 +0300 Subject: [PATCH] meta: Compilation correction for previous 3 commits --- include/utl/concepts/concepts.h | 34 ++ include/utl/concepts/defines.h | 69 +++ include/utl/concepts/iterators.h | 70 +++ include/utl/concepts/stl.h | 751 +++++++++++++++++++++++++++++++ include/utl/utility/invoke.h | 187 ++++++++ test/tests/TConcepts.cpp | 422 +++++++++++++++++ test/tests/Tinvoke.cpp | 72 +++ 7 files changed, 1605 insertions(+) create mode 100644 include/utl/concepts/concepts.h create mode 100644 include/utl/concepts/defines.h create mode 100644 include/utl/concepts/iterators.h create mode 100644 include/utl/concepts/stl.h create mode 100644 include/utl/utility/invoke.h create mode 100644 test/tests/TConcepts.cpp create mode 100644 test/tests/Tinvoke.cpp diff --git a/include/utl/concepts/concepts.h b/include/utl/concepts/concepts.h new file mode 100644 index 0000000..e6c2784 --- /dev/null +++ b/include/utl/concepts/concepts.h @@ -0,0 +1,34 @@ +/*! + * \file /utl/concepts/concepts.h + * \brief Concepts main include header + * + * Copyright (C) 2018-2019 Christos Choutouridis + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef __utl_concepts_concepts_h__ +#define __utl_consepts_concepts_h__ + +#include + +#include +#include +#include + +/*! + * \defgroup concepts + */ + +#endif /* __utl_concepts_concepts_h__ */ diff --git a/include/utl/concepts/defines.h b/include/utl/concepts/defines.h new file mode 100644 index 0000000..58aac8c --- /dev/null +++ b/include/utl/concepts/defines.h @@ -0,0 +1,69 @@ +/*! + * \file /utl/concepts/defines.h + * \brief Concepts defines + * + * Copyright (C) 2018-2019 Christos Choutouridis + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef __utl_concepts_defines_h__ +#define __utl_concepts_defines_h__ + +//!\defgroup concepts +//!@{ + +/*! + * \brief + * utl typename constraints wrapper + * + * \example + * \code + * template struct lala { }; + * // will expand to something like: + * // template struct lala { }; + * // or + * // template struct lala { }; + * \endcode + */ +#if CXX_CONCEPTS + #define utlConstrainType(_Concept_) _Concept_ +#else + #define utlConstrainType(_Concept_) typename +#endif + +/*! \brief + * utl concept keyword syntax wrapper + */ +#if CXX_CONCEPTS + #if __cpp_concepts <= 201507L + #define _utlConcept concept bool + #else + #define _utlConcept concept + #endif +#else + #define _utlConcept constexpr bool +#endif + +#ifndef CXX_LIB_INVOKE + #ifdef __cpp_lib_invoke + #define CXX_LIB_INVOKE __cpp_lib_invoke + #else + #define CXX_LIB_INVOKE 0 + #endif +#endif + +//! @} + +#endif /* __utl_concepts_defines_h__ */ diff --git a/include/utl/concepts/iterators.h b/include/utl/concepts/iterators.h new file mode 100644 index 0000000..e0965d8 --- /dev/null +++ b/include/utl/concepts/iterators.h @@ -0,0 +1,70 @@ +/*! + * \file /utl/impl/concepts/iterators.h + * \brief utl iterator concept support header + * + * Copyright (C) 2018 Christos Choutouridis + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef __utl_concepts_iterator_h__ +#define __utl_concepts_iterator_h__ + +#include +#include +#include + +/*! + * \ingroup concepts + * \defgroup iterators + */ +//! @{ +namespace utl { + + #if CXX_CONCEPTS + template + _utlConcept WeaklyIncrementable = + Semiregular && + requires(I i) { + { ++i } -> Same&; // not required to be equality preserving + i++; // not required to be equality preserving + }; + #else + namespace detail { + template using try_ppI = decltype (++(std::declval())); + template using try_Ipp = decltype (std::declval()++); + } + template + _utlConcept WeaklyIncrementable = + Semiregular + && Same<_ref_t, meta::detected_t>> + && meta::is_detected>::value; + #endif + + #if CXX_CONCEPTS + template + _utlConcept DeviceIterator = + requires(I i) { + { *i } -> auto&&; // Requires: i is dereferenceable + } && + WeaklyIncrementable; + + #else + + #endif + +} + +//! @} +#endif /* __utl_concepts_iterator_h__ */ diff --git a/include/utl/concepts/stl.h b/include/utl/concepts/stl.h new file mode 100644 index 0000000..6b4d445 --- /dev/null +++ b/include/utl/concepts/stl.h @@ -0,0 +1,751 @@ +/*! + * \file /utl/concepts/stl.h + * \brief STL's Concepts + * + * Copyright (C) 2018 - 2019 Christos Choutouridis + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef __utl_concepts_stl_h__ +#define __utl_concepts_stl_h__ + +#include +#include +#include + +#include + +/*! + * \brief + * STL's core language concepts + * + * We provide std concepts in case host's stl does not provide them yet. + * + * For more information \see https://en.cppreference.com/w/cpp/concepts + */ +//! @{ +namespace utl { + + template + using remove_cvref_t = std::remove_cv_t< std::remove_reference_t >; + + template + using cref_ = const std::remove_reference_t&; + + template + using _ref_t = std::add_lvalue_reference_t; + + /*! + * Same + */ + template + _utlConcept Same = meta::same_::value; + +// template +// _utlConcept Decayed = Same>; + + /*! + * DerivedFrom + */ + template + _utlConcept DerivedFrom = + std::is_base_of::value && + std::is_convertible::value; + + + /*! + * ConvertibleTo + */ + template + #if CXX_CONCEPTS + _utlConcept ConvertibleTo = + std::is_convertible::value && + requires(From (&f)()) { + static_cast(f()); + }; + #else + _utlConcept ConvertibleTo = std::is_convertible::value; + #endif + + /*! + * Common Reference + */ + //! @{ + namespace common_impl { + //! \see https://ericniebler.github.io/std/wg21/D0022.html + // ========== common reference =========== + template + using __cond_res = + decltype(false ? std::declval()() : std::declval()()); + + template + struct __copy_cv_ { + static_assert(!std::is_reference::value); + template using apply = To; + }; + template + struct __copy_cv_ { + template using apply = const To; + }; + template + struct __copy_cv_ { + template using apply = volatile To; + }; + template + struct __copy_cv_ { + template using apply = const volatile To; + }; + template + using __copy_cv = meta::invoke<__copy_cv_, To>; + + // CREF [meta.trans.other]/2.1 + template + using __cref = std::add_lvalue_reference_t>; + + // COMMON_REF [meta.trans.other]/2 + template + struct __common_ref_ { + static_assert(std::is_reference::value, ""); + static_assert(std::is_reference::value, ""); + }; + + template + using __common_ref = meta::eval<__common_ref_>; + + // [meta.trans.other]/2.5 + template + using __lref_res = __cond_res< + __copy_cv &, + __copy_cv & + >; + + // [meta.trans.other]/2.6 + template> + using __rref_res = std::remove_reference_t&&; + + template + struct __common_ref_, + meta::when>::value>> > { + using type = __lref_res; + }; + + template + struct __common_ref_, + meta::when>>, + meta::when>>> > { + using type = __rref_res; + }; + + // [meta.trans.other]/2.7 + template + struct __common_ref_, + meta::when>>> > { + using type = __common_ref; + }; + + // [meta.trans.other]/2.8 + template + struct __common_ref_, + meta::when>>> > { + using type = __common_ref; + }; + + template + struct __xref { + template using apply = U; + }; + template + struct __xref { + template using apply = const U; + }; + template + struct __xref { + template using apply = volatile U; + }; + template + struct __xref { + template using apply = const volatile U; + }; + template + struct __xref { + template using apply = + std::add_lvalue_reference_t, U>>; + }; + template + struct __xref { + template using apply = + std::add_rvalue_reference_t, U>>; + }; + + template class, + template class + > + struct basic_common_reference { }; + + template + using __basic_common_reference_t = meta::eval< + basic_common_reference< + remove_cvref_t, + remove_cvref_t, + __xref::template apply, + __xref::template apply + > + >; + + template + struct common_reference {}; + + template + using common_reference_t = meta::eval< + common_reference + >; + + // [meta.trans.other]/5.2 + template + struct common_reference { + using type = T; + }; + + // [meta.trans.other]/5.3.4 + template + struct __common_reference3 + : std::common_type {}; + + // [meta.trans.other]/5.3.3 + template + struct __common_reference3>> { + using type = __cond_res; + }; + + template + struct __common_reference2 + : __common_reference3 {}; + + // [meta.trans.other]/5.3.2 + template + struct __common_reference2>> { + using type = __basic_common_reference_t; + }; + + template + struct __common_reference + : __common_reference2 { }; + + template + struct __common_reference::value && std::is_reference::value>> { + using type = __common_ref; + }; + + template + struct common_reference : __common_reference { }; + + // [meta.trans.other]/5.4 + template + //requires requires { typename common_reference_t; } + struct common_reference + : common_reference < + common_reference_t, V, W... + > {}; + } + + template + using common_reference = common_impl::common_reference; + + template + using common_reference_t = meta::eval< + common_reference + >; + + //! @} + + + //FIXME: CommonReference needs better implementation + template + _utlConcept CommonReference = + Same, common_reference_t> && + ConvertibleTo> && + ConvertibleTo>; + + + // != std::Common on CommonReference + template + _utlConcept Common = + #if CXX_CONCEPTS + Same, std::common_type_t> && + requires { + static_cast>(std::declval()); + static_cast>(std::declval()); + }; +// } && +// CommonReference< +// std::add_lvalue_reference_t, +// std::add_lvalue_reference_t> && +// CommonReference< +// std::add_lvalue_reference_t>, +// std::common_reference_t< +// std::add_lvalue_reference_t, +// std::add_lvalue_reference_t +// > +// >; + #else +// meta::and_ < + Same, std::common_type_t>; //> +// meta::bool_, +// std::add_lvalue_reference_t +// >>, +// meta::bool_< CommonReference< +// std::add_lvalue_reference_t>, +// common_reference_t< +// std::add_lvalue_reference_t, +// std::add_lvalue_reference_t +// > +// >> +// >::value; + #endif + + /*! + * Integral + */ + template + _utlConcept Integral = std::is_integral::value; + + /*! + * Signed Integral + */ + template + _utlConcept SignedIntegral = Integral && std::is_signed::value; + + /*! + * Unsigned Integral + */ + template + _utlConcept UnsignedIntegral = Integral && !std::is_signed::value; + + + template + _utlConcept MoveAssignable = std::is_move_assignable::value; + + template + _utlConcept CopyAssignable = std::is_copy_assignable::value; + + /*! + * Assignable + * \note != std:: on CommonReference + */ + template + _utlConcept Assignable = + #if CXX_CONCEPTS + std::is_lvalue_reference::value && +// CommonReference< +// const std::remove_reference_t&, +// const std::remove_reference_t&> && + requires(LHS lhs, RHS&& rhs) { + lhs = std::forward(rhs); + requires Same< + decltype(lhs = std::forward(rhs)), LHS + >; + }; + #else + std::is_assignable::value; + #endif + + /*! + * Swappable, SwappableWith + */ + //! @{ + #if CXX_VER < CXX_VER_STD_17 + namespace swappable_with_impl { + struct is_swappable_with_ { + // can apply std::swap + template(), std::declval<_Up&>())), + typename + = decltype(std::swap(std::declval<_Up&>(), std::declval<_Tp&>()))> + static meta::true_ check(int); + // can not apply std::swap + template static meta::false_ check(...); + }; + } + template + struct is_swappable_with + : swappable_with_impl::is_swappable_with_ { + using type = decltype(check<_Tp, _Up>(0)); + }; + #else + using is_swappable = std::is_swappable; + using is_swappable_with = std::is_swappable_with; + #endif + + // != std:: on CommonReference + template + _utlConcept SwappableWith = + is_swappable_with::type::value && + is_swappable_with::type::value && + is_swappable_with::type::value && + is_swappable_with::type::value; +// std::CommonReference< +// const std::remove_reference_t&, +// const std::remove_reference_t& +// >; + + // != std:: we use is_swappable_with now is_swappable + template + _utlConcept Swappable = is_swappable_with::type::value; + //! @} + + /*! + * Destructible + */ + template + _utlConcept Destructible = std::is_nothrow_destructible::value; + + /*! + * Constructible + */ + template + _utlConcept Constructible = + Destructible && std::is_constructible::value; + /*! + * DefaultConstructible + */ + template + _utlConcept DefaultConstructible = Constructible; + + /*! + * MoveConstructible + * \note + * Another approach would be std::is_move_constructible::value; + */ + template + _utlConcept MoveConstructible = + Constructible && ConvertibleTo; + + /*! + * CopyConstructible + */ + template + _utlConcept CopyConstructible = + MoveConstructible && + Constructible> && ConvertibleTo<_ref_t, T> && + Constructible> && ConvertibleTo, T> && + Constructible && ConvertibleTo; + + /*! + * Movable + */ + template + _utlConcept Movable = + std::is_object::value && + MoveConstructible && + Assignable<_ref_t, T> && + Swappable; + + + /*! + * Copyable + */ + template + _utlConcept Copyable = + CopyConstructible && + Movable && + Assignable<_ref_t, const _ref_t>; + + + /*! + * Boolean + */ + #if CXX_CONCEPTS + template + _utlConcept Boolean = + Movable> && + requires(const std::remove_reference_t& b1, + const std::remove_reference_t& b2, const bool a) { + requires ConvertibleTo&, bool>; + !b1; requires ConvertibleTo; + b1 && a; requires Same; + b1 || a; requires Same; + b1 && b2; requires Same; + a && b2; requires Same; + b1 || b2; requires Same; + a || b2; requires Same; + b1 == b2; requires ConvertibleTo; + b1 == a; requires ConvertibleTo; + a == b2; requires ConvertibleTo; + b1 != b2; requires ConvertibleTo; + b1 != a; requires ConvertibleTo; + a != b2; requires ConvertibleTo; + }; + #else + namespace details { + template + struct is_boolean_ { + using type = meta::false_; + }; + + template + struct is_boolean_ >())>, + meta::use_if_same_t>() == std::declval>())>, + meta::use_if_same_t>() != std::declval>())>, + meta::use_if_same_t>() && std::declval>())>, + meta::use_if_same_t>() || std::declval>())> + >> { + using type = meta::true_; + }; + + template + using is_boolean_t = meta::eval < + is_boolean_ + >; + } + template + _utlConcept Boolean = + Movable> && + //ConvertibleTo&, bool> && + ConvertibleTo, bool> && + Same>; + #endif + + + namespace details { + template + struct is_weakly_equality_comparable_with_ { + using type = meta::false_; + }; + + template + struct is_weakly_equality_comparable_with_>() == std::declval>())>, + meta::use_if_same_t>() != std::declval>())>, + meta::use_if_same_t>() == std::declval>())>, + meta::use_if_same_t>() != std::declval>())> + >> { + using type = meta::true_; + }; + + template + using is_weakly_equality_comparable_with_t = meta::eval< + is_weakly_equality_comparable_with_ + >; + } + + template + _utlConcept WeaklyEqualityComparableWith = + #if CXX_CONCEPTS + requires(const std::remove_reference_t& t, + const std::remove_reference_t& u) { + t == u; requires Boolean; + t != u; requires Boolean; + u == t; requires Boolean; + u != t; requires Boolean; + }; + #else + Same>; + #endif + + template + _utlConcept EqualityComparable = WeaklyEqualityComparableWith; + + template + _utlConcept EqualityComparableWith = + EqualityComparable && + EqualityComparable && +// CommonReference< +// const std::remove_reference_t&, +// const std::remove_reference_t&> && +// EqualityComparable< +// common_reference_t< +// const std::remove_reference_t&, +// const std::remove_reference_t&>> && + WeaklyEqualityComparableWith; + + + + #if CXX_CONCEPTS + template + _utlConcept StrictTotallyOrdered = + EqualityComparable && + requires(const std::remove_reference_t& a, + const std::remove_reference_t& b) { + a < b; requires Boolean; + a > b; requires Boolean b)>; + a <= b; requires Boolean; + a >= b; requires Boolean= b)>; + }; + #else + namespace details { + template + struct is_strict_totally_ordered_ { + using type = meta::false_; + }; + + template + struct is_strict_totally_ordered_ >() < std::declval>())>, + meta::use_if_same_t>() > std::declval>())>, + meta::use_if_same_t>() <= std::declval>())>, + meta::use_if_same_t>() >= std::declval>())> + >> { + using type = meta::true_; + }; + + template + using is_strict_totally_ordered_t = meta::eval < + is_strict_totally_ordered_ + >; + } + template + _utlConcept StrictTotallyOrdered = + EqualityComparable && + Same >; + #endif + + #if CXX_CONCEPTS + template + _utlConcept StrictTotallyOrderedWith = + StrictTotallyOrdered && + StrictTotallyOrdered && +// CommonReference< +// const std::remove_reference_t&, +// const std::remove_reference_t& +// > && +// StrictTotallyOrdered< +// common_reference_t< +// const std::remove_reference_t&, +// const std::remove_reference_t& +// > +// > && + EqualityComparableWith && + requires(const std::remove_reference_t& t, + const std::remove_reference_t& u) { + t < u; requires Boolean; + t > u; requires Boolean u)>; + t <= u; requires Boolean; + t >= u; requires Boolean= u)>; + u < t; requires Boolean; + u > t; requires Boolean t)>; + u <= t; requires Boolean; + u >= t; requires Boolean= t)>; + }; + #else + namespace details { + template + struct is_strict_totally_ordered_with_ { + using type = meta::false_; + }; + + template + struct is_strict_totally_ordered_with_ >() < std::declval>())>, + meta::use_if_same_t>() > std::declval>())>, + meta::use_if_same_t>() <= std::declval>())>, + meta::use_if_same_t>() >= std::declval>())>, + meta::use_if_same_t>() < std::declval>())>, + meta::use_if_same_t>() > std::declval>())>, + meta::use_if_same_t>() <= std::declval>())>, + meta::use_if_same_t>() >= std::declval>())> + >> { + using type = meta::true_; + }; + + template + using is_strict_totally_ordered_with_t = meta::eval < + is_strict_totally_ordered_with_ + >; + } + template + _utlConcept StrictTotallyOrderedWith = + StrictTotallyOrdered && + StrictTotallyOrdered && + EqualityComparableWith && + Same >; + #endif + + /*! + * Semiregular + */ + template + _utlConcept Semiregular = Copyable && DefaultConstructible; + + /*! + * Regular + */ + template + _utlConcept Regular = Semiregular && EqualityComparable; + + /*! + * Scalar + */ + template + _utlConcept Scalar = + std::is_scalar::value && Regular; + + /*! + * Arithmetic + */ + template + _utlConcept Arithmetic = + std::is_arithmetic::value && Scalar && StrictTotallyOrdered; + + /*! + * FloatingPoint + */ + template + _utlConcept FloatingPoint = + std::is_floating_point::value && Arithmetic; + + /*! + * Invocable + */ + template + _utlConcept Invocable = is_invocable::value; +// requires(F&& f, Args&&... args) { +// invoke(std::forward(f), std::forward(args)...); +// }; + + template< class F, class... Args > + _utlConcept RegularInvocable = Invocable; + + template < class F, class... Args > + _utlConcept Predicate = + RegularInvocable && + Boolean>; + + template + _utlConcept Relation = + Predicate && Predicate && + Predicate && Predicate; + + template < class R, class T, class U > + _utlConcept StrictWeakOrder = Relation; +} +//! @} + + + + +#endif /* __utl_concepts_stl_h__ */ diff --git a/include/utl/utility/invoke.h b/include/utl/utility/invoke.h new file mode 100644 index 0000000..29dcba8 --- /dev/null +++ b/include/utl/utility/invoke.h @@ -0,0 +1,187 @@ +/*! + * \file utl/utility/invoke.h + * \brief invoke() and invoke() traits implementation + * + * Copyright (C) 2018-2019 Christos Choutouridis + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more detail. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +#ifndef __utl_utility_invoke_h__ +#define __utl_utility_invoke_h__ + +#include +#include + +#include +#include +#include + +/*! + * \ingroup utility + * \defgroup invoke + * + */ +//! @{ +namespace utl { + + namespace detail { + + template + struct is_ref_wrapper : meta::false_ {}; + template + struct is_ref_wrapper> : meta::true_ {}; + + // 1 + template >::value && + std::is_base_of>::value, + int> =0 + > + decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) { + return (std::forward(t1).*f)(std::forward(args)...); + } + + // 2 + template >::value && + is_ref_wrapper>::value, + int> =0 + > + decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) { + return (t1.get().*f)(std::forward(args)...); + } + + // 3 + template >::value && + !std::is_base_of>::value && + !is_ref_wrapper>::value, + int> =0 + > + decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) { + return ((*std::forward(t1)).*f)(std::forward(args)...); + } + + // 4 + template >::value && + std::is_base_of>::value, + int> =0 + > + decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) { + return std::forward(t1).*f; + } + + // 5 + template >::value && + is_ref_wrapper>::value, + int> =0 + > + decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) { + return t1.get().*f; + } + + // 6 + template >::value && + !std::is_base_of>::value && + !is_ref_wrapper>::value, + int> =0 + > + decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) { + return (*std::forward(t1)).*f; + } + + template + decltype(auto) invoke_impl_(F&& f, Args&&... args) { + return std::forward(f)(std::forward(args)...); + } + + } // namespace detail + + //! Invoke a callable object (for C++14) + template + inline decltype(auto) invoke(_Callable&& fn, _Args&&... args) { + return detail::invoke_impl_( + std::forward<_Callable>(fn), std::forward<_Args>(args)... + ); + } + //! @} + + //! std::is_invocable trait for C++11 + template + struct is_invocable : + std::is_constructible< + std::function, + std::reference_wrapper::type> + > { }; + + //! std::is_invocable_r trait for C++11 + template + struct is_invocable_r : + std::is_constructible< + std::function, + std::reference_wrapper::type> + > { }; + + /*! + * invoke_result (SFINAE friendly) + */ + //! @{ + namespace detail { + template + struct try_invoke { + using type = decltype ( + detail::invoke_impl_(std::declval<_Callable&&>(), std::declval<_Args&&>()...) + ); + }; + + template + struct invoke_result_ { + using type = meta::nil_; + }; + + template + struct invoke_result_ { + using type = meta::invoke_t< + meta::quote, _Callable, _Args... + >; + }; + } + //! invoke_result (for C++14) + template + using invoke_result = detail::invoke_result_< + is_invocable<_Callable, _Args...>::value, + _Callable, + _Args... + >; + + //! invoke_result_t (for C++14) + template + using invoke_result_t = meta::eval < + invoke_result<_Callable, _Args...> + >; +} + +//! @} + + +#endif /* __utl_utility_invoke_h__ */ diff --git a/test/tests/TConcepts.cpp b/test/tests/TConcepts.cpp new file mode 100644 index 0000000..e922a45 --- /dev/null +++ b/test/tests/TConcepts.cpp @@ -0,0 +1,422 @@ +/*! + * \file Tmeta.cpp + * + * Copyright (C) 2018 Christos Choutouridis + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include +#include +#include + + +namespace test_concepts { + using namespace utl; + + /* + * Fixture like types + */ + struct Empty { }; + struct HaveOnlyCopy { + HaveOnlyCopy(const HaveOnlyCopy&) = default; + HaveOnlyCopy(HaveOnlyCopy&&) = delete; + HaveOnlyCopy& operator= (const HaveOnlyCopy&) = default; + HaveOnlyCopy& operator= (HaveOnlyCopy&&) = delete; + }; + struct HaveOnlyMove { + HaveOnlyMove(const HaveOnlyMove&) = delete; + HaveOnlyMove(HaveOnlyMove&&) = default; + HaveOnlyMove& operator= (const HaveOnlyMove&) = delete; + HaveOnlyMove& operator= (HaveOnlyMove&&) = default; + }; + struct HaveCopyAndMove { + HaveCopyAndMove(const HaveCopyAndMove&) = default; + HaveCopyAndMove(HaveCopyAndMove&&) = default; + HaveCopyAndMove& operator= (const HaveCopyAndMove&) = default; + HaveCopyAndMove& operator= (HaveCopyAndMove&&) = default; + }; + class HavePerfectForwarding { + public: template HavePerfectForwarding(T&&) { } + }; + class Base { }; + class Derived1 : public Base { }; + class Derived2 : public Derived1 { }; + class HaveOperatorBase { + public: operator Base() { return base; } + Base base; + }; + + + struct A { + int a_; + public: + A(int a =0) : a_{a} { }; + A(const A&) = default; + A(A&&) = default; + }; + bool operator== (const A& l, const A& r) { return l.a_ == r.a_; } + bool operator!= (const A& l, const A& r) { return l.a_ != r.a_; } + + struct B { + int b_; + public: + B(int b =0) : b_{b} { }; + B(const B&) = default; + B(B&&) = default; + B& operator= (const B&) = default; + B& operator= (B&&) = default; + }; + bool operator== (const B& l, const B& r) { return l.b_ == r.b_; } + bool operator!= (const B& l, const B& r) { return l.b_ != r.b_; } + bool operator< (const B& l, const B& r) { return l.b_ < r.b_; } + bool operator<= (const B& l, const B& r) { return l.b_ <= r.b_; } + bool operator> (const B& l, const B& r) { return l.b_ > r.b_; } + bool operator>= (const B& l, const B& r) { return l.b_ >= r.b_; } + + + TEST(TConcepts, Same) { + // Same + EXPECT_EQ (true, (Same)); + EXPECT_EQ (false, (Same)); + EXPECT_EQ (true, (Same)); + EXPECT_EQ (true, (Same)); + EXPECT_EQ (false, (Same)); + EXPECT_EQ (false, (Same)); + } + + TEST(TConcepts, DerivedFrom) { + // DerivedFrom + EXPECT_EQ (true, (DerivedFrom)); + EXPECT_EQ (true, (DerivedFrom)); + EXPECT_EQ (true, (DerivedFrom)); + EXPECT_EQ (false, (DerivedFrom)); + EXPECT_EQ (false, (DerivedFrom)); + EXPECT_EQ (false, (DerivedFrom)); + } + + TEST(TConcepts, ConvertibleTo) { + // ConvertibleTo + EXPECT_EQ (true, (ConvertibleTo)); + EXPECT_EQ (false, (ConvertibleTo)); + EXPECT_EQ (false, (ConvertibleTo)); + EXPECT_EQ (true, (ConvertibleTo)); + EXPECT_EQ (true, (ConvertibleTo)); + EXPECT_EQ (true, (ConvertibleTo)); + } + + TEST(TConcepts, CommonReference) { + // CommonReference + EXPECT_EQ (true, (CommonReference)); + EXPECT_EQ (true, (CommonReference)); + EXPECT_EQ (true, (CommonReference)); + EXPECT_EQ (false, (CommonReference)); + //FIXME: CommonReference needs SFINAE friendly implementation + //EXPECT_EQ (false, (CommonReference)); <- yields compiler error + + // Common + EXPECT_EQ (true, (Common)); + EXPECT_EQ (true, (Common)); + EXPECT_EQ (true, (Common)); + EXPECT_EQ (true, (Common)); + EXPECT_EQ (true, (Common)); + } + + TEST(TConcepts, Integral) { + // Integral + EXPECT_EQ (false, (Integral)); + EXPECT_EQ (true, (Integral)); + EXPECT_EQ (true, (Integral)); + EXPECT_EQ (false, (Integral)); + EXPECT_EQ (false, (Integral)); + EXPECT_EQ (true, (Integral::value_type>)); + EXPECT_EQ (false, (Integral::type>)); + + // SignedIntegral + EXPECT_EQ (false, (SignedIntegral)); + EXPECT_EQ (true, (SignedIntegral)); + EXPECT_EQ (false, (SignedIntegral)); + EXPECT_EQ (false, (SignedIntegral)); + EXPECT_EQ (false, (SignedIntegral)); + EXPECT_EQ (false, (SignedIntegral)); + EXPECT_EQ (true, (SignedIntegral::value_type>)); + + // UnsignedIntegral + EXPECT_EQ (false, (UnsignedIntegral)); + EXPECT_EQ (true, (UnsignedIntegral)); + EXPECT_EQ (false, (UnsignedIntegral)); + EXPECT_EQ (false, (UnsignedIntegral)); + EXPECT_EQ (false, (UnsignedIntegral)); + EXPECT_EQ (true, (UnsignedIntegral::value_type>)); + } + + TEST(TConcepts, Assignable) { + // MoveAssignable + EXPECT_EQ (false, (MoveAssignable)); + EXPECT_EQ (true, (MoveAssignable)); + EXPECT_EQ (true, (MoveAssignable)); + EXPECT_EQ (true, (MoveAssignable)); + EXPECT_EQ (false, (MoveAssignable)); + EXPECT_EQ (true, (MoveAssignable)); + EXPECT_EQ (true, (MoveAssignable)); + EXPECT_EQ (true, (MoveAssignable)); + EXPECT_EQ (true, (MoveAssignable)); + + // CopyAssignable + EXPECT_EQ (false, (CopyAssignable)); + EXPECT_EQ (true, (CopyAssignable)); + EXPECT_EQ (true, (CopyAssignable)); + EXPECT_EQ (true, (CopyAssignable)); + EXPECT_EQ (true, (CopyAssignable)); + EXPECT_EQ (false, (CopyAssignable)); + EXPECT_EQ (true, (CopyAssignable)); + EXPECT_EQ (true, (CopyAssignable)); + EXPECT_EQ (true, (CopyAssignable)); + + // Assignable + EXPECT_EQ (false, (Assignable)); + EXPECT_EQ (false, (Assignable)); + EXPECT_EQ (true, (Assignable)); + EXPECT_EQ (false, (Assignable)); + EXPECT_EQ (false, (Assignable)); + EXPECT_EQ (true, (Assignable)); + EXPECT_EQ (false, (Assignable)); + EXPECT_EQ (true, (Assignable)); + EXPECT_EQ (true , (Assignable)); + EXPECT_EQ (true, (Assignable)); + } + + TEST(TConcepts, Swappable) { + // Swappable, SwappableWith + EXPECT_EQ (false, (Swappable)); + EXPECT_EQ (true, (Swappable)); + EXPECT_EQ (true, (Swappable)); + EXPECT_EQ (true, (Swappable)); + EXPECT_EQ (true, (SwappableWith)); + EXPECT_EQ (false, (SwappableWith)); + EXPECT_EQ (false, (SwappableWith)); + + // Destructible + EXPECT_EQ (false, (Destructible)); + EXPECT_EQ (true, (Destructible)); + EXPECT_EQ (true, (Destructible)); + EXPECT_EQ (true, (Destructible)); + EXPECT_EQ (true, (Destructible)); + EXPECT_EQ (true, (Destructible)); + } + + TEST(TConcepts, Constructible) { + // Constructible + EXPECT_EQ (false, (Constructible)); + EXPECT_EQ (true, (Constructible)); + EXPECT_EQ (true, (Constructible)); + EXPECT_EQ (false, (Constructible)); + EXPECT_EQ (true, (Constructible)); + + // DefaultConstructible + EXPECT_EQ (false, (DefaultConstructible)); + EXPECT_EQ (true, (DefaultConstructible)); + EXPECT_EQ (false, (DefaultConstructible)); + EXPECT_EQ (true, (DefaultConstructible)); + EXPECT_EQ (true, (DefaultConstructible)); + EXPECT_EQ (false, (DefaultConstructible)); + EXPECT_EQ (false, (DefaultConstructible)); + EXPECT_EQ (false, (DefaultConstructible)); + + // MoveConstructible + EXPECT_EQ (false, (MoveConstructible)); + EXPECT_EQ (true, (MoveConstructible)); + EXPECT_EQ (true, (MoveConstructible)); + EXPECT_EQ (true, (MoveConstructible)); + EXPECT_EQ (true, (MoveConstructible)); + EXPECT_EQ (false, (MoveConstructible)); + EXPECT_EQ (true, (MoveConstructible)); + EXPECT_EQ (true , (MoveConstructible)); + + // CopyConstructible + EXPECT_EQ (false, (CopyConstructible)); + EXPECT_EQ (true, (CopyConstructible)); + EXPECT_EQ (true, (CopyConstructible)); + EXPECT_EQ (true, (CopyConstructible)); + EXPECT_EQ (false, (CopyConstructible)); + EXPECT_EQ (false, (CopyConstructible)); + EXPECT_EQ (true, (CopyConstructible)); + EXPECT_EQ (true , (CopyConstructible)); + } + + TEST(TConcepts, MovableCopyable) { + // Movable + EXPECT_EQ (false, (Movable)); + EXPECT_EQ (true, (Movable)); + EXPECT_EQ (true, (Movable)); + EXPECT_EQ (true, (Movable)); + EXPECT_EQ (true, (Movable)); + EXPECT_EQ (false, (Movable)); + EXPECT_EQ (true, (Movable)); + EXPECT_EQ (true , (Movable)); + + // Copyable + EXPECT_EQ (false, (Copyable)); + EXPECT_EQ (true, (Copyable)); + EXPECT_EQ (true, (Copyable)); + EXPECT_EQ (true, (Copyable)); + EXPECT_EQ (false, (Copyable)); + EXPECT_EQ (false, (Copyable)); + EXPECT_EQ (true, (Copyable)); + EXPECT_EQ (true , (Copyable)); + } + + TEST(TConcepts, Boolean) { + // Boolean + EXPECT_EQ (false, (Boolean)); + EXPECT_EQ (true, (Boolean)); + EXPECT_EQ (true, (Boolean)); + EXPECT_EQ (true, (Boolean)); + EXPECT_EQ (true, (Boolean)); + EXPECT_EQ (true, (Boolean)); + EXPECT_EQ (false, (Boolean)); + } + + TEST(TConcepts, Comparable) { + // EqualityComparable + EXPECT_EQ (false, (EqualityComparable)); + EXPECT_EQ (true, (EqualityComparable)); + EXPECT_EQ (true, (EqualityComparable)); + EXPECT_EQ (false, (EqualityComparable)); + EXPECT_EQ (true, (EqualityComparable)); + + // EqualityComparableWith + EXPECT_EQ (false, (EqualityComparableWith)); + EXPECT_EQ (false, (EqualityComparableWith)); + EXPECT_EQ (true, (EqualityComparableWith)); + EXPECT_EQ (true, (EqualityComparableWith)); + EXPECT_EQ (true, (EqualityComparableWith)); + EXPECT_EQ (false, (EqualityComparableWith)); + EXPECT_EQ (false, (EqualityComparableWith)); + EXPECT_EQ (true, (EqualityComparableWith)); + EXPECT_EQ (false, (EqualityComparableWith)); + + // StrictTotallyOrdered + EXPECT_EQ (false, (StrictTotallyOrdered)); + EXPECT_EQ (true, (StrictTotallyOrdered)); + EXPECT_EQ (true, (StrictTotallyOrdered)); + EXPECT_EQ (true, (StrictTotallyOrdered)); + EXPECT_EQ (false, (StrictTotallyOrdered)); + EXPECT_EQ (false, (StrictTotallyOrdered)); + EXPECT_EQ (true, (StrictTotallyOrdered)); + + // StrictTotallyOrderedWith + EXPECT_EQ (false, (StrictTotallyOrderedWith)); + EXPECT_EQ (false, (StrictTotallyOrderedWith)); + EXPECT_EQ (true, (StrictTotallyOrderedWith)); + EXPECT_EQ (true, (StrictTotallyOrderedWith)); + EXPECT_EQ (false, (StrictTotallyOrderedWith)); + EXPECT_EQ (false, (StrictTotallyOrderedWith)); + EXPECT_EQ (false, (StrictTotallyOrderedWith)); + EXPECT_EQ (true, (StrictTotallyOrderedWith)); + EXPECT_EQ (false, (StrictTotallyOrderedWith)); + } + + TEST(TConcepts, Types) { + // Semiregular + EXPECT_EQ (false, (Semiregular)); + EXPECT_EQ (true, (Semiregular)); + EXPECT_EQ (true, (Semiregular)); + EXPECT_EQ (false, (Semiregular)); + EXPECT_EQ (false, (Semiregular)); + EXPECT_EQ (false, (Semiregular)); + EXPECT_EQ (false, (Semiregular)); + EXPECT_EQ (true, (Semiregular)); + + // Regular + EXPECT_EQ (false, (Regular)); + EXPECT_EQ (true, (Regular)); + EXPECT_EQ (true, (Regular)); + EXPECT_EQ (false, (Regular)); + EXPECT_EQ (false, (Regular)); + EXPECT_EQ (false, (Regular)); + EXPECT_EQ (false, (Regular)); + EXPECT_EQ (false, (Regular)); + EXPECT_EQ (true, (Regular)); + + // Scalar + EXPECT_EQ (false, (Scalar)); + EXPECT_EQ (true, (Scalar)); + EXPECT_EQ (true, (Scalar)); + EXPECT_EQ (false, (Scalar)); + EXPECT_EQ (false, (Scalar)); + + // Arithmetic + EXPECT_EQ (false, (Arithmetic)); + EXPECT_EQ (true, (Arithmetic)); + EXPECT_EQ (false, (Arithmetic)); + EXPECT_EQ (false, (Arithmetic)); + EXPECT_EQ (false, (Arithmetic)); + + // FloatingPoint + EXPECT_EQ (false, (FloatingPoint)); + EXPECT_EQ (true, (FloatingPoint)); + EXPECT_EQ (true, (FloatingPoint)); + EXPECT_EQ (false, (FloatingPoint)); + EXPECT_EQ (false, (FloatingPoint)); + EXPECT_EQ (false, (FloatingPoint)); + EXPECT_EQ (false, (FloatingPoint)); + } + + struct Inv { + void operator() (int) { }; + void operator() () { }; + }; + struct Pred { + bool operator () (int) { return true; } + bool operator () (int, int) { return true; } + }; + TEST(TConcepts, Callable) { + EXPECT_EQ (true, (Invocable)); + EXPECT_EQ (true, (Invocable)); + EXPECT_EQ (true, (Invocable)); + EXPECT_EQ (false, (Invocable)); + + EXPECT_EQ (true, (RegularInvocable)); + + EXPECT_EQ (false, (Predicate)); + EXPECT_EQ (true, (Predicate)); + EXPECT_EQ (false, (Predicate)); + + EXPECT_EQ (true, (Relation)); + EXPECT_EQ (true, (Relation)); + EXPECT_EQ (false, (Relation)); + + EXPECT_EQ (true, (StrictWeakOrder)); + EXPECT_EQ (false, (StrictWeakOrder)); + } + + struct Incr { + Incr& operator++() { return *this; } + Incr operator++(int) { return *this; } + }; + int type_printer (int* i) { return *i; } + TEST(TConcepts, Iterators) { + +// type_printer(detail::try_ppI{}); +// type_printer(detail::try_Ipp{}); +// type_printer(meta::detected_t{}); + EXPECT_EQ (true, (WeaklyIncrementable)); + EXPECT_EQ (false, (WeaklyIncrementable)); + EXPECT_EQ (false, (WeaklyIncrementable)); + EXPECT_EQ (true, (WeaklyIncrementable)); + EXPECT_EQ (false, (WeaklyIncrementable)); + } +} + diff --git a/test/tests/Tinvoke.cpp b/test/tests/Tinvoke.cpp new file mode 100644 index 0000000..5d1ca05 --- /dev/null +++ b/test/tests/Tinvoke.cpp @@ -0,0 +1,72 @@ +/*! + * \file Tinvoke.cpp + * + * Copyright (C) 2018-2019 Christos Choutouridis + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include +#include +#include + +namespace test_meta { + using namespace utl; + + /* + * Types to behave like Fixtures + */ + int Ifun(int i) { return i; } + struct Ifoo { + int operator() (int i) { + return i; + } + }; + + struct Ibar { + Ibar(int num) : num_(num) {} + int echo(int i) const { return i; } + int get() const { return num_; } + int num_; + }; + + /* + * Test invoke() + */ + TEST(Tinvoke, Invoke) { + Ifoo ifoo{}; + const Ibar ibar{42}; + + EXPECT_EQ (42, invoke(Ifun, 42)); + EXPECT_EQ (42, invoke([] () { return Ifun(42); })); + EXPECT_EQ (42, invoke(Ifoo{}, 42)); + EXPECT_EQ (42, invoke(ifoo, 42)); + EXPECT_EQ (42, invoke(&Ibar::echo, ibar, 42)); + EXPECT_EQ (42, invoke(&Ibar::get, ibar)); + + EXPECT_EQ (true, (is_invocable::value)); + EXPECT_EQ (false, (is_invocable::value)); + EXPECT_EQ (false, (is_invocable::value)); + EXPECT_EQ (false, (is_invocable::value)); + + EXPECT_EQ (true, (is_invocable_r::value)); + EXPECT_EQ (false, (is_invocable_r::value)); + EXPECT_EQ (false, (is_invocable_r::value)); + + EXPECT_EQ (true, (std::is_same>())); + EXPECT_EQ (true, (std::is_same>())); + EXPECT_EQ (true, (std::is_same>())); + + } +}