1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
|
/*
* GridTools
*
* Copyright (c) 2014-2019, ETH Zurich
* All rights reserved.
*
* Please, refer to the LICENSE file in the root directory.
* SPDX-License-Identifier: BSD-3-Clause
*/
#pragma once
#include <functional>
#include <stdexcept>
#include <string>
#include <type_traits>
#include "common/for_each.hpp"
#include "common/make_indices.hpp"
#include "common/type_traits.hpp"
#include "array_descriptor.h"
namespace cpp_bindgen {
namespace _impl {
template <class T>
struct fill_extent_f {
template <class N>
void operator()(N, bindgen_fortran_array_descriptor &descriptor) const {
descriptor.dims[N::value] = std::extent<T, N::value>::value;
}
};
template <class fortran_type>
struct fortran_array_element_kind_impl;
template <>
struct fortran_array_element_kind_impl<bool>
: std::integral_constant<bindgen_fortran_array_kind, bindgen_fk_Bool> {};
template <>
struct fortran_array_element_kind_impl<int>
: std::integral_constant<bindgen_fortran_array_kind, bindgen_fk_Int> {};
template <>
struct fortran_array_element_kind_impl<short>
: std::integral_constant<bindgen_fortran_array_kind, bindgen_fk_Short> {};
template <>
struct fortran_array_element_kind_impl<long>
: std::integral_constant<bindgen_fortran_array_kind, bindgen_fk_Long> {};
template <>
struct fortran_array_element_kind_impl<long long>
: std::integral_constant<bindgen_fortran_array_kind, bindgen_fk_LongLong> {};
template <>
struct fortran_array_element_kind_impl<float>
: std::integral_constant<bindgen_fortran_array_kind, bindgen_fk_Float> {};
template <>
struct fortran_array_element_kind_impl<double>
: std::integral_constant<bindgen_fortran_array_kind, bindgen_fk_Double> {};
template <>
struct fortran_array_element_kind_impl<long double>
: std::integral_constant<bindgen_fortran_array_kind, bindgen_fk_LongDouble> {};
template <>
struct fortran_array_element_kind_impl<signed char>
: std::integral_constant<bindgen_fortran_array_kind, bindgen_fk_SignedChar> {};
} // namespace _impl
template <class, class = void>
struct fortran_array_element_kind;
template <class T>
struct fortran_array_element_kind<T, enable_if_t<std::is_integral<T>::value>>
: _impl::fortran_array_element_kind_impl<typename std::make_signed<T>::type> {};
template <class T>
struct fortran_array_element_kind<T, enable_if_t<std::is_floating_point<T>::value>>
: _impl::fortran_array_element_kind_impl<T> {};
namespace get_fortran_view_meta_impl {
template <class T, class Arr = remove_reference_t<T>, class ElementType = remove_all_extents_t<Arr>>
enable_if_t<std::is_array<Arr>::value && std::is_arithmetic<ElementType>::value,
bindgen_fortran_array_descriptor>
get_fortran_view_meta(T *) {
bindgen_fortran_array_descriptor descriptor;
descriptor.type = fortran_array_element_kind<ElementType>::value;
descriptor.rank = std::rank<Arr>::value;
descriptor.is_acc_present = false;
using indices = typename make_indices_c<std::rank<Arr>::value>::type;
cpp_bindgen::for_each<indices>(
std::bind(_impl::fill_extent_f<Arr>{}, std::placeholders::_1, std::ref(descriptor)));
return descriptor;
}
template <class T>
enable_if_t<(T::bindgen_view_rank::value > 0) &&
std::is_arithmetic<typename T::bindgen_view_element_type>::value &&
(T::bindgen_is_acc_present::value == T::bindgen_is_acc_present::value),
bindgen_fortran_array_descriptor>
get_fortran_view_meta(T *) {
bindgen_fortran_array_descriptor descriptor;
descriptor.type = fortran_array_element_kind<typename T::bindgen_view_element_type>::value;
descriptor.rank = T::bindgen_view_rank::value;
descriptor.is_acc_present = T::bindgen_is_acc_present::value;
return descriptor;
}
#ifdef CPP_BINDGEN_GT_LEGACY // remove once GT is at v2.0
template <class T>
enable_if_t<(T::gt_view_rank::value > 0) && std::is_arithmetic<typename T::gt_view_element_type>::value &&
(T::gt_is_acc_present::value == T::gt_is_acc_present::value),
bindgen_fortran_array_descriptor>
get_fortran_view_meta(T *) {
bindgen_fortran_array_descriptor descriptor;
descriptor.type = fortran_array_element_kind<typename T::gt_view_element_type>::value;
descriptor.rank = T::gt_view_rank::value;
descriptor.is_acc_present = T::gt_is_acc_present::value;
return descriptor;
}
#endif
template <class T>
using bindgen_fortran_array_view_t = decltype(
bindgen_make_fortran_array_view(std::declval<bindgen_fortran_array_descriptor *>(), std::declval<T *>()));
#ifdef CPP_BINDGEN_GT_LEGACY // remove once GT is at v2.0
template <class T>
using gt_fortran_array_view_t =
decltype(gt_make_fortran_array_view(std::declval<gt_fortran_array_descriptor *>(), std::declval<T *>()));
#endif
} // namespace get_fortran_view_meta_impl
using get_fortran_view_meta_impl::get_fortran_view_meta;
/**
* A type T is fortran_array_view_inspectable, one of the following conditions holds:
*
* - There exists a function
*
* @code
* bindgen_fortran_array_descriptor get_fortran_view_meta(T*)
* @endcode
*
* which returns the meta-data of the type `T`. type, rank and is_acc_present must be set correctly.
*
* - T defines T::bindgen_view_element_type as the element type of the array, T::bindgen_view_rank is an integral
* constant holding the rank of the type, and T::bindgen_is_acc_present is a bool_constant indicating whether
* the data is present on device (when compiling with OpenACC, this will pass a device pointer to the
* constructor).
*
* - T is a reference to a c-array.
*/
template <class, class = void>
struct is_fortran_array_view_inspectable : std::false_type {};
template <class T>
struct is_fortran_array_view_inspectable<T,
enable_if_t<std::is_same<decltype(get_fortran_view_meta(std::declval<add_pointer_t<T>>())),
bindgen_fortran_array_descriptor>::value>> : std::true_type {};
/**
* The concept of fortran_array_convertible requires that a fortran array described by a
* bindgen_fortran_array_descriptor can be converted into T:
*
* - T is fortran_array_convertible, if T is a reference to an array of a fortran-compatible type (arithmetic
* types).
* - T is fortran_array_convertible, if bindgen_fortran_array_descriptor is implicity convertible to T
* - T is fortran_array_convertible, if there exists a function with the following signature:
* @code
* T bindgen_make_fortran_array_view(bindgen_fortran_array_descriptor*, T*)
* @endcode
* .
*/
template <class, class = void>
struct is_fortran_array_convertible : std::false_type {};
template <class T>
struct is_fortran_array_convertible<T,
enable_if_t<std::is_same<decay_t<T>, bindgen_fortran_array_descriptor>::value ||
std::is_convertible<bindgen_fortran_array_descriptor, T>::value>> : std::true_type {};
template <class T>
struct is_fortran_array_convertible<T,
enable_if_t<std::is_lvalue_reference<T>::value && std::is_array<remove_reference_t<T>>::value &&
std::is_arithmetic<remove_all_extents_t<remove_reference_t<T>>>::value>> : std::true_type {};
// simplify this when support for CUDA 9.2 is gone, or if GT is at v2.0
template <class T>
struct is_fortran_array_convertible<T,
void_t<get_fortran_view_meta_impl::bindgen_fortran_array_view_t<T>,
enable_if_t<std::is_same<get_fortran_view_meta_impl::bindgen_fortran_array_view_t<T>,
T>::value>> //
> : std::true_type {};
#ifdef CPP_BINDGEN_GT_LEGACY // remove once GT is at v2.0
template <class T>
struct is_fortran_array_convertible<T,
void_t<get_fortran_view_meta_impl::gt_fortran_array_view_t<T>,
enable_if_t<std::is_same<get_fortran_view_meta_impl::gt_fortran_array_view_t<T>,
T>::value>> //
> : std::true_type {};
#endif
/**
* @brief A type is fortran_array_bindable if it is fortran_array_convertible
*
* A fortran_array_bindable type will appear in the c-bindings as a bindgen_fortran_array_descriptor.
*/
template <class T>
struct is_fortran_array_bindable : is_fortran_array_convertible<T> {};
/**
* @brief A type is fortran_array_wrappable if it is both fortran_array_bindable and
* fortran_array_view_inspectable.
*
* If used with the wrapper-versions of the export-function, fortran_array_wrappable types can be created from a
* fortran array in the fortran bindings, whereas fortran_array_convertible-types that are not bindable will
* appear as bindgen_fortran_array_descriptors and must be filled manually.
*/
template <class T>
struct is_fortran_array_wrappable
: bool_constant<is_fortran_array_bindable<T>::value && is_fortran_array_view_inspectable<T>::value> {};
template <class T>
enable_if_t<std::is_same<decay_t<T>, bindgen_fortran_array_descriptor>::value ||
std::is_convertible<bindgen_fortran_array_descriptor, T>::value,
T>
make_fortran_array_view(bindgen_fortran_array_descriptor *descriptor) {
return *descriptor;
}
template <class T>
enable_if_t<std::is_lvalue_reference<T>::value && std::is_array<remove_reference_t<T>>::value &&
std::is_arithmetic<remove_all_extents_t<remove_reference_t<T>>>::value,
T>
make_fortran_array_view(bindgen_fortran_array_descriptor *descriptor) {
static bindgen_fortran_array_descriptor cpp_meta = get_fortran_view_meta((add_pointer_t<T>){nullptr});
if (descriptor->type != cpp_meta.type) {
throw std::runtime_error("Types do not match: fortran-type (" + std::to_string(descriptor->type) +
") != c-type (" + std::to_string(cpp_meta.type) + ")");
}
if (descriptor->rank != cpp_meta.rank) {
throw std::runtime_error("Rank does not match: fortran-rank (" + std::to_string(descriptor->rank) +
") != c-rank (" + std::to_string(cpp_meta.rank) + ")");
}
for (int i = 0; i < descriptor->rank; ++i) {
if (cpp_meta.dims[i] != descriptor->dims[descriptor->rank - i - 1])
throw std::runtime_error("Extents do not match");
}
return *static_cast<remove_reference_t<T> *>(descriptor->data);
}
// simplify this when support for CUDA 9.2 is gone, or if GT is at v2.0
template <class T>
enable_if_t<std::is_same<get_fortran_view_meta_impl::bindgen_fortran_array_view_t<T>, T>::value,
get_fortran_view_meta_impl::bindgen_fortran_array_view_t<T>>
make_fortran_array_view(bindgen_fortran_array_descriptor *descriptor) {
return bindgen_make_fortran_array_view(descriptor, (T *){nullptr});
}
#ifdef CPP_BINDGEN_GT_LEGACY // remove once GT is at v2.0
template <class T>
enable_if_t<std::is_same<get_fortran_view_meta_impl::gt_fortran_array_view_t<T>, T>::value,
get_fortran_view_meta_impl::gt_fortran_array_view_t<T>>
make_fortran_array_view(bindgen_fortran_array_descriptor *descriptor) {
return gt_make_fortran_array_view(descriptor, (T *){nullptr});
}
#endif
} // namespace cpp_bindgen
#ifdef CPP_BINDGEN_GT_LEGACY // remove once GT is at v2.0
namespace gridtools {
namespace c_bindings {
using cpp_bindgen::fortran_array_element_kind;
using cpp_bindgen::is_fortran_array_bindable;
using cpp_bindgen::is_fortran_array_view_inspectable;
using cpp_bindgen::is_fortran_array_wrappable;
} // namespace c_bindings
} // namespace gridtools
#endif
|