38 return std::string{std::meta::display_string_of(std::meta::dealias(type))};
53 bool pending_sep{
false};
55 const bool ok{(c >=
'A' && c <=
'Z') || (c >=
'a' && c <=
'z') ||
56 (c >=
'0' && c <=
'9') || c ==
'_'};
58 if (pending_sep && !out.empty())
68 if (out[0] >=
'0' && out[0] <=
'9')
69 out.insert(out.begin(),
'_');
88 auto keep = [](std::meta::info p) {
89 if (!std::meta::has_identifier(p))
91 const std::string
id{std::meta::identifier_of(p)};
94 return !(
id.size() >= 2 &&
id[0] ==
'_' &&
id[1] ==
'_');
96 std::vector<std::string> parts{};
98 std::meta::has_identifier(entity)
99 ? std::string{std::meta::identifier_of(entity)}
100 : std::string{std::meta::display_string_of(entity)},
104 for (std::meta::info e{entity};
105 std::meta::has_parent(e) && std::meta::parent_of(e) != ^^::;) {
106 e = std::meta::parent_of(e);
107 if (!(std::meta::is_namespace(e) ||
108 (std::meta::is_type(e) && std::meta::is_class_type(e))))
112 std::string{std::meta::identifier_of(e)},
116 for (
auto it{parts.rbegin()}; it != parts.rend(); ++it)
128 s.insert(s.begin(),
char(
'0' + n % 10));
156 if (!std::meta::is_type(arg))
157 return std::string{std::meta::display_string_of(arg)};
158 const std::meta::info type{std::meta::dealias(arg)};
160 if (std::meta::has_template_arguments(type) &&
161 std::meta::template_of(type) == ^^std::basic_string)
164 const auto args{std::meta::template_arguments_of(type)};
167 if (std::meta::template_of(type) == ^^std::array)
178 if (std::meta::has_template_arguments(type)) {
180 for (
const std::meta::info a : std::meta::template_arguments_of(type))
195 const std::meta::access_context ctx{std::meta::access_context::unprivileged()};
196 for (
const std::meta::info m : std::meta::members_of(style_type, ctx))
197 if (std::meta::is_function(m) && std::meta::has_identifier(m) &&
198 std::meta::identifier_of(m) ==
"transform_opaque_container")
200 for (
const std::meta::info b : std::meta::bases_of(style_type, ctx))
222template <
class Style, std::meta::info Enclosing, std::meta::info Container,
223 std::meta::info Member>
227 Style::transform_opaque_container(Enclosing, Container, Member)});
235 std::string tail{std::meta::identifier_of(ns)};
236 for (std::meta::info p{std::meta::parent_of(ns)};
237 p != std::meta::info{} && p != ^^:: && std::meta::has_identifier(p);
238 p = std::meta::parent_of(p))
239 tail = std::string{std::meta::identifier_of(p)} +
"::" + tail;
248 t = std::meta::dealias(t);
249 if (std::meta::is_fundamental_type(t))
251 return std::meta::has_template_arguments(t) &&
252 std::meta::template_of(t) == ^^std::basic_string;
255consteval bool opaque_eligible(std::meta::info type);
270 t = std::meta::dealias(t);
275 if (std::meta::is_class_type(t) || std::meta::is_enum_type(t))
278 return std::meta::is_namespace(std::meta::parent_of(t)) &&
289 const auto args{std::meta::template_arguments_of(type)};
301 const std::meta::info u{std::meta::dealias(type)};
304 std::size_t inner{0};
305 const auto args{std::meta::template_arguments_of(u)};
318consteval void collect_into(std::vector<std::meta::info>& out, std::meta::info type) {
319 const std::meta::info u{std::meta::dealias(std::meta::remove_cvref(type))};
322 const auto args{std::meta::template_arguments_of(u)};
330template <std::meta::info Type>
332 std::vector<std::meta::info> out{};
372 template <std::meta::info C,
class Style, std::meta::info Enclosing,
373 std::meta::info Site>
374 void add_one(
bool excluded,
bool styled_site) {
379 if (e.spelling == sp) {
380 e.excluded = e.excluded || excluded;
381 if (styled_site && !e.styled) {
387 entries.push_back({std::string{sp}, std::string{nm}, excluded, styled_site, depth});
394 template <std::meta::info SurfaceType,
class Style, std::meta::info Enclosing,
395 std::meta::info Site>
396 void collect([[maybe_unused]]
bool excluded, [[maybe_unused]]
bool styled_site) {
399 template for (
constexpr auto c :
409 template <std::meta::info Fn,
class Style>
411 template for (
constexpr auto p :
412 std::define_static_array(std::meta::parameters_of(Fn)))
415 if constexpr (!std::meta::is_constructor(Fn)) {
416 using R = [:std::meta::return_type_of(Fn):];
417 if constexpr (!std::is_void_v<R>)
418 collect<std::meta::return_type_of(Fn), Style, std::meta::parent_of(Fn),
419 Fn>(
false, styled_site);
429 std::string
render(
const std::string& ns)
const {
430 std::vector<entry> es{
entries};
431 std::sort(es.begin(), es.end(), [](
const entry& a,
const entry& b) {
432 return a.name < b.name;
434 for (std::size_t i{1}; i < es.size(); ++i)
435 if (!es[i].excluded && !es[i - 1].excluded &&
436 es[i].name == es[i - 1].name &&
437 es[i].spelling != es[i - 1].spelling)
438 return "#error welder: two distinct opaque containers derive the "
440 es[i].name +
"' (" + es[i - 1].spelling +
" vs " +
442 "); this generator cannot rename them automatically.\n";
443 std::sort(es.begin(), es.end(), [](
const entry& a,
const entry& b) {
444 return a.depth != b.depth ? a.depth < b.depth : a.name < b.name;
447 out +=
"#pragma once\n";
448 out +=
"// AUTO-GENERATED by welder (welder::rods::opaque_containers). Do not edit.\n";
450 out +=
"// Include AFTER your welded type headers and the active backend's\n";
451 out +=
"// <welder/rods/python/{pybind11,nanobind}/rod.hpp>, before the module.\n";
452 out +=
"#include <array>\n#include <map>\n#include <string>\n#include <unordered_map>\n#include <vector>\n\n";
453 for (
const entry& e : es)
455 out +=
"WELDER_OPAQUE(" + e.spelling +
")\n";
456 out +=
"\nnamespace " + ns +
" {\n";
457 for (
const entry& e : es)
459 out +=
"using " + e.name +
460 " [[=welder::weld(welder::lang::py)]] = " + e.spelling +
";\n";
461 out +=
"} // namespace " + ns +
"\n";
The reference-semantic container table: which STL containers welder can bind opaquely* (by reference)...
consteval std::string restyle(std::string_view id, case_kind kind)
Re-spell identifier id in convention kind, preserving any leading and trailing underscore run (_priva...
consteval std::string qualified_ident(std::meta::info entity)
The collision-free qualified identifier of entity: its own identifier (or, for an unnameable entity,...
consteval bool has_opaque_hook(std::meta::info style_type)
Does name style style_type (or any of its bases) declare the optional transform_opaque_container hook...
consteval std::string namespace_name(std::meta::info ns)
The fully-qualified spelling of namespace ns for a namespace X { … } header block (no leading :: — ge...
consteval std::string derive_name(std::meta::info arg)
A readable, valid, collision-free PascalCase identifier for container/element arg — the template name...
consteval void collect_into(std::vector< std::meta::info > &out, std::meta::info type)
Append type's directly-named reference container when it is one and eligible (see opaque_eligible),...
consteval std::string opaque_name()
The opaque-wrapper name for container Container found on member/site Member within Enclosing — the cu...
consteval std::size_t container_depth(std::meta::info type)
How deeply container type nests further reference containers: 1 for vector<int>, 2 for vector<vector<...
consteval bool scalar_leaf(std::meta::info t)
Is t a scalar leaf — a fundamental type or a std::basic_string — i.e.
consteval std::string decimal_string(std::size_t n)
Decimal render of n (constexpr std::to_string is unavailable on gcc-16) — the extent token an std::ar...
consteval std::string container_spelling(std::meta::info type)
The C++ text of container type, infrastructure args (allocator/comparator/ hasher) dropped — the refl...
consteval std::size_t value_arg_count(std::meta::info type)
How many leading (value) template arguments of type name its element/key/value types — a sequence exp...
consteval std::vector< std::meta::info > containers_in()
The reference containers within surface type Type (a splice-ready static list for a template for).
consteval bool opaque_eligible(std::meta::info type)
Is container type eligible for the generator — will every element/key/value type's name exist when it...
consteval std::string sanitize_ident(std::string s)
Reduce s to a valid C++ identifier: keep [A-Za-z0-9_], collapse every other run to a single _ (droppi...
consteval bool element_ok(std::meta::info t)
Can element/key/value type t appear inside an opaque container — i.e.
consteval bool welded_for(std::meta::info type, lang L)
Is type welded for language L — i.e.
@ py
Python (via the pybind11 and nanobind backends).
@ map
A bind_map container: std::map, std::unordered_map.
consteval bool is_reference_container(std::meta::info type)
Is type one of the containers welder can bind by reference (opaquely)?
Language-agnostic name styling: reshape a C++ identifier into a target language's naming convention,...
Language-agnostic resolution: given a reflected type/member and a target language,...
The accumulator threaded through the rod's emission hooks: the deduped set of reference containers th...
void collect(bool excluded, bool styled_site)
Collect every reference container within surface type SurfaceType (a data member / parameter / return...
void collect_callable(bool styled_site)
Collect from callable Fn's parameter types and (unless a constructor) its return type — never by_valu...
std::string render(const std::string &ns) const
The finished, self-contained header text — WELDER_OPAQUE(...) at global scope, the welded aliases ins...
std::vector< entry > entries
Deduped by C++ spelling.
void add_one(bool excluded, bool styled_site)
Record container C found on member/site Site within Enclosing (deduped by spelling; excluded OR-merge...
One container to open opaque: its C++ spelling, its derived target name, and whether a by_value mark ...
bool styled
name came from a Style-aware site (a data member / method / free function / variable),...
bool excluded
a by_value mark opted this container type out.
std::size_t depth
container nesting depth (see container_depth); shallower aliases render (and therefore weld) first,...