/**************************************************************************** * Copyright (c) 2017-2022 by the ArborX authors * * All rights reserved. * * * * This file is part of the ArborX library. ArborX is * * distributed under a BSD 3-clause license. For the licensing terms see * * the LICENSE file in the top-level directory. * * * * SPDX-License-Identifier: BSD-3-Clause * ****************************************************************************/ #ifndef ARBORX_ACCESS_TRAITS_HPP #define ARBORX_ACCESS_TRAITS_HPP #include #include #include #include #include namespace ArborX { struct PrimitivesTag {}; struct PredicatesTag {}; template struct AccessTraits { using not_specialized = void; // tag to detect existence of a specialization }; template using AccessTraitsNotSpecializedArchetypeAlias = typename Traits::not_specialized; template struct AccessTraits< View, Tag, std::enable_if_t{} && View::rank == 1>> { // Returns a const reference KOKKOS_FUNCTION static typename View::const_value_type &get(View const &v, int i) { return v(i); } KOKKOS_FUNCTION static typename View::size_type size(View const &v) { return v.extent(0); } using memory_space = typename View::memory_space; }; template struct AccessTraits< View, Tag, std::enable_if_t{} && View::rank == 2>> { template KOKKOS_FUNCTION static ExperimentalHyperGeometry::Point getPoint(std::index_sequence, View const &v, int i) { return {v(i, Is)...}; } // Returns by value KOKKOS_FUNCTION static auto get(View const &v, int i) { constexpr int dim = View::static_extent(1); if constexpr (dim > 0) // dimension known at compile time return getPoint(std::make_index_sequence(), v, i); else return Point{{v(i, 0), v(i, 1), v(i, 2)}}; } KOKKOS_FUNCTION static typename View::size_type size(View const &v) { return v.extent(0); } using memory_space = typename View::memory_space; }; namespace Details { // archetypal alias for a 'memory_space' type member in access traits template using AccessTraitsMemorySpaceArchetypeAlias = typename Traits::memory_space; // archetypal expression for 'size()' static member function in access traits template using AccessTraitsSizeArchetypeExpression = decltype(Traits::size(std::declval())); // archetypal expression for 'get()' static member function in access traits template using AccessTraitsGetArchetypeExpression = decltype(Traits::get(std::declval(), 0)); template using PredicateTagArchetypeAlias = typename P::Tag; template void check_valid_access_traits(PredicatesTag, Predicates const &) { using Access = AccessTraits; static_assert( !Kokkos::is_detected{}, "Must specialize 'AccessTraits'"); static_assert( Kokkos::is_detected{}, "AccessTraits must define 'memory_space' " "member type"); static_assert( Kokkos::is_memory_space< Kokkos::detected_t>{}, "'memory_space' member type must be a valid Kokkos memory space"); static_assert( Kokkos::is_detected{}, "AccessTraits must define 'size()' static " "member function"); static_assert( std::is_integral>{}, "size() static member function return type is not an integral type"); static_assert( Kokkos::is_detected{}, "AccessTraits must define 'get()' static " "member function"); using Predicate = std::decay_t>; using Tag = Kokkos::detected_t; static_assert(is_valid_predicate_tag::value, "Invalid tag for the predicates"); } struct DoNotCheckGetReturnType : std::false_type {}; template void check_valid_access_traits(PrimitivesTag, Primitives const &, CheckGetReturnType = {}) { using Access = AccessTraits; static_assert( !Kokkos::is_detected{}, "Must specialize 'AccessTraits'"); static_assert( Kokkos::is_detected{}, "AccessTraits must define 'memory_space' " "member type"); static_assert( Kokkos::is_memory_space< Kokkos::detected_t>{}, "'memory_space' member type must be a valid Kokkos memory space"); static_assert( Kokkos::is_detected{}, "AccessTraits must define 'size()' static " "member function"); static_assert( std::is_integral>{}, "size() static member function return type is not an integral type"); static_assert( Kokkos::is_detected{}, "AccessTraits must define 'get()' static " "member function"); using T = std::decay_t>; if constexpr (CheckGetReturnType()) { static_assert(GeometryTraits::is_point_v || GeometryTraits::is_box_v, "AccessTraits::get() return type " "must decay to a point or a box type"); } } template class AccessValuesI { private: using Access = AccessTraits; Values _values; public: explicit AccessValuesI(Values values) : _values(std::move(values)) {} using memory_space = typename Access::memory_space; using value_type = std::decay_t< Kokkos::detected_t>; KOKKOS_FUNCTION decltype(auto) operator()(int i) const { return Access::get(_values, i); } KOKKOS_FUNCTION auto size() const { return Access::size(_values); } using self_type = AccessValuesI; }; template class AccessValuesI, Tag> : public Kokkos::View { public: using self_type = Kokkos::View; }; template class AccessValuesI, Tag2> : public AccessValuesI { static_assert(std::is_same_v); }; template using AccessValues = typename AccessValuesI::self_type; } // namespace Details template struct AccessTraits, Tag> { using AccessValues = Details::AccessValuesI; using memory_space = typename AccessValues::memory_space; KOKKOS_FUNCTION static decltype(auto) get(AccessValues const &w, int i) { return w(i); } KOKKOS_FUNCTION static decltype(auto) size(AccessValues const &w) { return w.size(); } }; } // namespace ArborX #endif