welder
0.1.0
Bindings for annotated C++ types, from C++26 reflection
Toggle main menu visibility
Loading...
Searching...
No Matches
array_interface.hpp
Go to the documentation of this file.
1
#pragma once
2
#include <array>
3
#include <cstddef>
4
#include <meta>
5
#include <string>
6
#include <type_traits>
7
#include <utility>
8
28
29
namespace
welder::inline v0::
rods::python
{
30
32
consteval
std::string
ai_uint_string
(std::size_t n) {
33
if
(n == 0)
34
return
"0"
;
35
std::string s{};
36
for
(; n; n /= 10)
37
s.insert(s.begin(),
char
(
'0'
+ n % 10));
38
return
s;
39
}
40
43
consteval
bool
ai_is_unsigned
(std::meta::info t) {
44
t = std::meta::dealias(t);
45
for
(std::meta::info u :
46
{^^
unsigned
char, ^^
unsigned
short, ^^
unsigned
int, ^^
unsigned
long,
47
^^
unsigned
long
long, ^^char8_t, ^^char16_t, ^^
char32_t
})
48
if
(t == u)
49
return
true
;
50
return
false
;
51
}
52
63
consteval
std::string
numpy_typestr
(std::meta::info t) {
64
t = std::meta::dealias(t);
65
if
(std::meta::is_enum_type(t))
66
t = std::meta::dealias(std::meta::underlying_type(t));
67
if
(t == ^^
bool
)
68
return
"|b1"
;
69
if
(t == ^^
float
)
70
return
"<f4"
;
71
if
(t == ^^
double
)
72
return
"<f8"
;
73
if
(!std::meta::is_arithmetic_type(t) || t == ^^
long
double
)
74
return
""
;
// no portable NumPy scalar
75
const
std::size_t sz{std::meta::size_of(t)};
76
const
char
code{
ai_is_unsigned
(t) ?
'u'
:
'i'
};
77
const
char
prefix{sz == 1 ?
'|'
:
'<'
};
78
return
std::string{prefix} + code +
ai_uint_string
(sz);
79
}
80
83
template
<
class
E>
84
consteval
const
char
*
ai_typestr
() {
85
return
std::define_static_string(
"|V"
+
ai_uint_string
(
sizeof
(E)));
86
}
87
90
consteval
bool
ai_all_fields_numpy
(std::meta::info E) {
91
const
auto
members{std::meta::nonstatic_data_members_of(
92
E, std::meta::access_context::unchecked())};
93
if
(members.empty())
94
return
false
;
95
for
(std::meta::info m : members)
96
if
(
numpy_typestr
(std::meta::type_of(m)).empty())
97
return
false
;
98
return
true
;
99
}
100
105
template
<
class
E>
106
consteval
bool
pod_array_eligible
() {
107
return
std::is_class_v<E> && std::is_trivially_copyable_v<E> &&
108
std::is_standard_layout_v<E> &&
ai_all_fields_numpy
(^^E);
109
}
110
113
consteval
std::size_t
ai_entry_count
(std::meta::info E) {
114
std::size_t n{0}, running{0};
115
for
(std::meta::info m : std::meta::nonstatic_data_members_of(
116
E, std::meta::access_context::unchecked())) {
117
// offset_of(m).bytes is std::ptrdiff_t (signed); a field offset is
118
// non-negative, so cast to size_t (avoids -Werror=narrowing/sign-conversion).
119
const
std::size_t off{
120
static_cast<
std::size_t
>
(std::meta::offset_of(m).bytes)};
121
if
(off > running)
122
++n;
// interior padding
123
++n;
// the field
124
running = off + std::meta::size_of(std::meta::type_of(m));
125
}
126
if
(running < std::meta::size_of(E))
127
++n;
// trailing padding
128
return
n;
129
}
130
136
template
<std::meta::info E>
137
consteval
std::array<std::pair<const char*, const char*>, ai_entry_count(E)>
138
ai_descr
() {
139
std::array<std::pair<const char*, const char*>,
ai_entry_count
(E)> out{};
140
std::size_t i{0}, running{0};
141
for
(std::meta::info m : std::meta::nonstatic_data_members_of(
142
E, std::meta::access_context::unchecked())) {
143
// offset_of(m).bytes is std::ptrdiff_t (signed); a field offset is
144
// non-negative, so cast to size_t (avoids -Werror=narrowing/sign-conversion).
145
const
std::size_t off{
146
static_cast<
std::size_t
>
(std::meta::offset_of(m).bytes)};
147
if
(off > running)
148
out[i++] = {
""
, std::define_static_string(
"|V"
+
149
ai_uint_string
(off - running))};
150
out[i++] = {std::define_static_string(std::meta::identifier_of(m)),
151
std::define_static_string(
numpy_typestr
(std::meta::type_of(m)))};
152
running = off + std::meta::size_of(std::meta::type_of(m));
153
}
154
if
(running < std::meta::size_of(E))
155
out[i++] = {
""
, std::define_static_string(
156
"|V"
+
ai_uint_string
(std::meta::size_of(E) - running))};
157
return
out;
158
}
159
160
}
// namespace welder::inline v0::rods::python
welder::rods::python
Definition
array_interface.hpp:29
welder::rods::python::pod_array_eligible
consteval bool pod_array_eligible()
Is std::vector<E> viewable as a NumPy structured array — i.e.
Definition
array_interface.hpp:106
welder::rods::python::ai_typestr
consteval const char * ai_typestr()
The array-interface typestr for the whole element E — an opaque |V<sizeof> void field; the per-field ...
Definition
array_interface.hpp:84
welder::rods::python::ai_entry_count
consteval std::size_t ai_entry_count(std::meta::info E)
The number of array-interface descr entries for E — one per field, plus one per padding gap (interior...
Definition
array_interface.hpp:113
welder::rods::python::ai_all_fields_numpy
consteval bool ai_all_fields_numpy(std::meta::info E)
Whether every one of a POD struct's fields maps to a NumPy scalar (so the descr is complete).
Definition
array_interface.hpp:90
welder::rods::python::numpy_typestr
consteval std::string numpy_typestr(std::meta::info t)
The NumPy typestr for arithmetic type t ('<' little-endian, '|' for a single byte),...
Definition
array_interface.hpp:63
welder::rods::python::ai_is_unsigned
consteval bool ai_is_unsigned(std::meta::info t)
Is t one of the unsigned integer fundamental types?
Definition
array_interface.hpp:43
welder::rods::python::ai_descr
consteval std::array< std::pair< const char *, const char * >, ai_entry_count(E)> ai_descr()
The NumPy array-interface descr for E: a splice-ready std::array of (name, typestr) pairs — each fiel...
Definition
array_interface.hpp:138
welder::rods::python::ai_uint_string
consteval std::string ai_uint_string(std::size_t n)
Decimal render of n (constexpr std::to_string is unavailable on gcc-16).
Definition
array_interface.hpp:32
src
welder
rods
python
array_interface.hpp
Generated by
1.17.0