welder 0.1.0
Bindings for annotated C++ types, from C++26 reflection
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
29namespace welder::inline v0::rods::python {
30
32consteval 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
43consteval 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
59consteval std::string numpy_typestr(std::meta::info t) {
60 t = std::meta::dealias(t);
61 if (t == ^^bool)
62 return "|b1";
63 if (t == ^^float)
64 return "<f4";
65 if (t == ^^double)
66 return "<f8";
67 if (!std::meta::is_arithmetic_type(t) || t == ^^long double)
68 return ""; // no portable NumPy scalar
69 const std::size_t sz{std::meta::size_of(t)};
70 const char code{ai_is_unsigned(t) ? 'u' : 'i'};
71 const char prefix{sz == 1 ? '|' : '<'};
72 return std::string{prefix} + code + ai_uint_string(sz);
73}
74
77template <class E>
78consteval const char* ai_typestr() {
79 return std::define_static_string("|V" + ai_uint_string(sizeof(E)));
80}
81
84consteval bool ai_all_fields_numpy(std::meta::info E) {
85 const auto members{std::meta::nonstatic_data_members_of(
86 E, std::meta::access_context::unchecked())};
87 if (members.empty())
88 return false;
89 for (std::meta::info m : members)
90 if (numpy_typestr(std::meta::type_of(m)).empty())
91 return false;
92 return true;
93}
94
99template <class E>
100consteval bool pod_array_eligible() {
101 return std::is_class_v<E> && std::is_trivially_copyable_v<E> &&
102 std::is_standard_layout_v<E> && ai_all_fields_numpy(^^E);
103}
104
107consteval std::size_t ai_entry_count(std::meta::info E) {
108 std::size_t n{0}, running{0};
109 for (std::meta::info m : std::meta::nonstatic_data_members_of(
110 E, std::meta::access_context::unchecked())) {
111 // offset_of(m).bytes is std::ptrdiff_t (signed); a field offset is
112 // non-negative, so cast to size_t (avoids -Werror=narrowing/sign-conversion).
113 const std::size_t off{
114 static_cast<std::size_t>(std::meta::offset_of(m).bytes)};
115 if (off > running)
116 ++n; // interior padding
117 ++n; // the field
118 running = off + std::meta::size_of(std::meta::type_of(m));
119 }
120 if (running < std::meta::size_of(E))
121 ++n; // trailing padding
122 return n;
123}
124
130template <std::meta::info E>
131consteval std::array<std::pair<const char*, const char*>, ai_entry_count(E)>
133 std::array<std::pair<const char*, const char*>, ai_entry_count(E)> out{};
134 std::size_t i{0}, running{0};
135 for (std::meta::info m : std::meta::nonstatic_data_members_of(
136 E, std::meta::access_context::unchecked())) {
137 // offset_of(m).bytes is std::ptrdiff_t (signed); a field offset is
138 // non-negative, so cast to size_t (avoids -Werror=narrowing/sign-conversion).
139 const std::size_t off{
140 static_cast<std::size_t>(std::meta::offset_of(m).bytes)};
141 if (off > running)
142 out[i++] = {"", std::define_static_string("|V" +
143 ai_uint_string(off - running))};
144 out[i++] = {std::define_static_string(std::meta::identifier_of(m)),
145 std::define_static_string(numpy_typestr(std::meta::type_of(m)))};
146 running = off + std::meta::size_of(std::meta::type_of(m));
147 }
148 if (running < std::meta::size_of(E))
149 out[i++] = {"", std::define_static_string(
150 "|V" + ai_uint_string(std::meta::size_of(E) - running))};
151 return out;
152}
153
154} // namespace welder::inline v0::rods::python
consteval bool pod_array_eligible()
Is std::vector<E> viewable as a NumPy structured array — i.e.
consteval const char * ai_typestr()
The array-interface typestr for the whole element E — an opaque |V<sizeof> void field; the per-field ...
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...
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).
consteval std::string numpy_typestr(std::meta::info t)
The NumPy typestr for arithmetic type t ('<' little-endian, '|' for a single byte),...
consteval bool ai_is_unsigned(std::meta::info t)
Is t one of the unsigned integer fundamental types?
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...
consteval std::string ai_uint_string(std::size_t n)
Decimal render of n (constexpr std::to_string is unavailable on gcc-16).