Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:54:12

0001 /*
0002  * SPDX-PackageName: "covfie, a part of the ACTS project"
0003  * SPDX-FileCopyrightText: 2022 CERN
0004  * SPDX-License-Identifier: MPL-2.0
0005  */
0006 
0007 #pragma once
0008 
0009 #include <concepts>
0010 #include <iostream>
0011 #include <memory>
0012 #include <optional>
0013 
0014 #include <covfie/core/definitions.hpp>
0015 #include <covfie/core/parameter_pack.hpp>
0016 namespace covfie::concepts {
0017 template <typename T>
0018 concept is_initial = T::is_initial == true;
0019 
0020 template <typename T>
0021 concept is_constructible_from_config_and_backend = requires(
0022     const typename T::configuration_t & c,
0023     typename T::backend_t::owning_data_t & b
0024 )
0025 {
0026     {typename T::owning_data_t(c, std::move(b))};
0027 };
0028 
0029 template <typename T>
0030 concept is_constructible_from_parameter_pack_len_gt1 =
0031     requires(parameter_pack<typename T::configuration_t, std::monostate> && p)
0032 {
0033     {typename T::owning_data_t(std::move(p))};
0034 };
0035 
0036 template <typename T>
0037 concept is_constructible_from_parameter_pack_len_eq1 =
0038     requires(parameter_pack<typename T::configuration_t> && p)
0039 {
0040     {typename T::owning_data_t(std::move(p))};
0041 };
0042 
0043 template <typename T>
0044 concept is_constructible_from_parameter_pack_self =
0045     requires(parameter_pack<typename T::owning_data_t> && p)
0046 {
0047     {typename T::owning_data_t(std::move(p))};
0048 };
0049 
0050 template <typename T>
0051 concept is_constructible_from_self_rvalue =
0052     requires(typename T::owning_data_t && p)
0053 {
0054     {typename T::owning_data_t(std::move(p))};
0055 };
0056 
0057 template <typename T>
0058 concept field_backend = requires
0059 {
0060     /*
0061      * Every backend should have an alias to itself. Not great, but sometimes
0062      * C++ necessitates these things.
0063      */
0064     typename T::this_t;
0065 
0066     /*
0067      * Check whether the backend has the required type definitions, which are
0068      * the input and output types of the contravariant and covariant parts of
0069      * the layer.
0070      */
0071     typename T::contravariant_input_t;
0072     typename T::covariant_output_t;
0073 
0074     /*
0075      * Confirm that the backend has both an owning and a non-owning data type.
0076      */
0077     typename T::owning_data_t;
0078     typename T::non_owning_data_t;
0079 
0080     /*
0081      * Every bit of data, owning and non-owning, must make available which
0082      * backend it belongs to.
0083      */
0084     typename T::owning_data_t::parent_t;
0085     typename T::non_owning_data_t::parent_t;
0086 
0087     /*
0088      * The non-owning data which we use on the GPU must be extremely simple,
0089      * because we cannot model destructors and such there properly.
0090      */
0091     requires std::is_trivially_destructible_v<typename T::non_owning_data_t>;
0092     requires
0093         std::is_trivially_copy_constructible_v<typename T::non_owning_data_t>;
0094     requires
0095         std::is_trivially_move_constructible_v<typename T::non_owning_data_t>;
0096 
0097     /*
0098      * Backends must declare whether they are initial or not; this must be done
0099      * through a static constexpr boolean.
0100      */
0101     T::is_initial;
0102     requires std::is_same_v<bool, std::decay_t<decltype(T::is_initial)>>;
0103 
0104     /*
0105      * Types must declare whether they are configuration-constructible, which
0106      * is to say they can be constructed from a configuration structure. Note
0107      * that the configuration is stricly for the transformer, and not for its
0108      * children.
0109      */
0110     typename T::configuration_t;
0111 
0112     requires std::is_trivially_destructible_v<typename T::configuration_t>;
0113     requires
0114         std::is_trivially_copy_constructible_v<typename T::configuration_t>;
0115     requires
0116         std::is_trivially_move_constructible_v<typename T::configuration_t>;
0117 
0118     requires requires(const typename T::owning_data_t & o)
0119     {
0120         {
0121             o.get_configuration()
0122         } -> std::same_as<typename T::configuration_t>;
0123     };
0124 
0125     /*
0126      * Check for additional constructability from parameter packs.
0127      */
0128     requires is_initial<T> || is_constructible_from_parameter_pack_len_gt1<T>;
0129     requires !is_initial<T> || is_constructible_from_parameter_pack_len_eq1<T>;
0130     requires is_constructible_from_parameter_pack_self<T>;
0131 
0132     /*
0133      * Check whether the field is constructible from itself.
0134      */
0135     requires is_constructible_from_self_rvalue<T>;
0136 
0137     /*
0138      * Check whether the owning data type can be read from a file.
0139      */
0140     requires requires(std::istream & fs)
0141     {
0142         {
0143             T::owning_data_t::read_binary(fs)
0144         } -> std::same_as<typename T::owning_data_t>;
0145     };
0146 
0147     requires requires(std::ostream & fs, const typename T::owning_data_t & o)
0148     {
0149         {
0150             T::owning_data_t::write_binary(fs, o)
0151         } -> std::same_as<void>;
0152     };
0153 
0154     requires is_initial<T> || is_constructible_from_config_and_backend<T>;
0155 
0156     //{typename T::owning_data_t()};
0157 
0158     requires requires(typename T::owning_data_t & d)
0159     {
0160         requires T::is_initial || requires
0161         {
0162             typename T::backend_t;
0163             {
0164                 d.get_backend()
0165             } -> std::same_as<typename T::backend_t::owning_data_t &>;
0166         };
0167 
0168         {typename T::owning_data_t(d)};
0169         {typename T::owning_data_t(std::move(d))};
0170 
0171         requires requires(typename T::owning_data_t & e)
0172         {
0173             {d = e};
0174             {d = std::move(e)};
0175         };
0176     };
0177 
0178     requires requires(const typename T::owning_data_t & d)
0179     {
0180         /*
0181          * Check whether a non-owning data type can be constructed from the
0182          * owning variant.
0183          */
0184         {typename T::non_owning_data_t(d)};
0185 
0186         /*
0187          * Any non-initial backend must allow an accessor method to access the
0188          * non-owning data type of its innards.
0189          */
0190         requires T::is_initial || requires
0191         {
0192             typename T::backend_t;
0193             {
0194                 d.get_backend()
0195             } -> std::same_as<const typename T::backend_t::owning_data_t &>;
0196         };
0197     };
0198 
0199     requires requires(typename T::non_owning_data_t & d)
0200     {
0201         /*
0202          * Just like how owning data types can spit out references to their
0203          * children, so can non-owning data types.
0204          */
0205         requires T::is_initial || requires
0206         {
0207             typename T::backend_t;
0208             {
0209                 d.get_backend()
0210             } -> std::same_as<typename T::backend_t::non_owning_data_t &>;
0211         };
0212     };
0213 
0214     /*
0215      * Check whether a non-owning object allows us to look up the magnetic
0216      * field, and whether that operation gives the correct result.
0217      */
0218     requires requires(const typename T::non_owning_data_t & d)
0219     {
0220         {
0221             d.at(std::declval<typename T::contravariant_input_t::vector_t>())
0222         } -> std::same_as<typename T::covariant_output_t::vector_t>;
0223 
0224         /*
0225          * Constant version of the requirement that non-owning data can be
0226          * introspected.
0227          */
0228         requires T::is_initial || requires
0229         {
0230             typename T::backend_t;
0231             {
0232                 d.get_backend()
0233             } -> std::same_as<const typename T::backend_t::non_owning_data_t &>;
0234         };
0235     };
0236 };
0237 
0238 template <typename T>
0239 concept array_1d_like_field_backend = field_backend<T> && requires
0240 {
0241     typename T::vector_t;
0242 
0243     requires requires(const typename T::owning_data_t & d)
0244     {
0245         {
0246             d.get_size()
0247         } -> std::unsigned_integral;
0248 
0249         {
0250             d.get_host_array()
0251         } -> std::same_as<std::unique_ptr<typename T::vector_t[]>>;
0252     };
0253 };
0254 
0255 template <typename T>
0256 concept vector_descriptor = true;
0257 }