37 return std::string{std::meta::display_string_of(std::meta::dealias(type))};
52 bool pending_sep{
false};
54 const bool ok{(c >=
'A' && c <=
'Z') || (c >=
'a' && c <=
'z') ||
55 (c >=
'0' && c <=
'9') || c ==
'_'};
57 if (pending_sep && !out.empty())
67 if (out[0] >=
'0' && out[0] <=
'9')
68 out.insert(out.begin(),
'_');
87 auto keep = [](std::meta::info p) {
88 if (!std::meta::has_identifier(p))
90 const std::string
id{std::meta::identifier_of(p)};
93 return !(
id.size() >= 2 &&
id[0] ==
'_' &&
id[1] ==
'_');
95 std::vector<std::string> parts{};
97 std::meta::has_identifier(entity)
98 ? std::string{std::meta::identifier_of(entity)}
99 : std::string{std::meta::display_string_of(entity)},
103 for (std::meta::info e{entity};
104 std::meta::has_parent(e) && std::meta::parent_of(e) != ^^::;) {
105 e = std::meta::parent_of(e);
106 if (!(std::meta::is_namespace(e) ||
107 (std::meta::is_type(e) && std::meta::is_class_type(e))))
111 std::string{std::meta::identifier_of(e)},
115 for (
auto it{parts.rbegin()}; it != parts.rend(); ++it)
137 if (!std::meta::is_type(arg))
138 return std::string{std::meta::display_string_of(arg)};
139 const std::meta::info type{std::meta::dealias(arg)};
141 if (std::meta::has_template_arguments(type) &&
142 std::meta::template_of(type) == ^^std::basic_string)
146 const auto args{std::meta::template_arguments_of(type)};
154 if (std::meta::has_template_arguments(type)) {
156 for (
const std::meta::info a : std::meta::template_arguments_of(type))
171 const std::meta::access_context ctx{std::meta::access_context::unprivileged()};
172 for (
const std::meta::info m : std::meta::members_of(style_type, ctx))
173 if (std::meta::is_function(m) && std::meta::has_identifier(m) &&
174 std::meta::identifier_of(m) ==
"transform_opaque_container")
176 for (
const std::meta::info b : std::meta::bases_of(style_type, ctx))
198template <
class Style, std::meta::info Enclosing, std::meta::info Container,
199 std::meta::info Member>
203 Style::transform_opaque_container(Enclosing, Container, Member)});
211 std::string tail{std::meta::identifier_of(ns)};
212 for (std::meta::info p{std::meta::parent_of(ns)};
213 p != std::meta::info{} && p != ^^:: && std::meta::has_identifier(p);
214 p = std::meta::parent_of(p))
215 tail = std::string{std::meta::identifier_of(p)} +
"::" + tail;
224 t = std::meta::dealias(t);
225 if (std::meta::is_fundamental_type(t))
227 return std::meta::has_template_arguments(t) &&
228 std::meta::template_of(t) == ^^std::basic_string;
242 t = std::meta::dealias(t);
247 if (std::meta::is_class_type(t) || std::meta::is_enum_type(t))
250 return std::meta::is_namespace(std::meta::parent_of(t)) &&
261 const auto args{std::meta::template_arguments_of(type)};
273consteval void collect_into(std::vector<std::meta::info>& out, std::meta::info type) {
274 const std::meta::info u{std::meta::dealias(std::meta::remove_cvref(type))};
281template <std::meta::info Type>
283 std::vector<std::meta::info> out{};
319 template <std::meta::info C,
class Style, std::meta::info Enclosing,
320 std::meta::info Site>
321 void add_one(
bool excluded,
bool styled_site) {
325 if (e.spelling == sp) {
326 e.excluded = e.excluded || excluded;
327 if (styled_site && !e.styled) {
333 entries.push_back({std::string{sp}, std::string{nm}, excluded, styled_site});
340 template <std::meta::info SurfaceType,
class Style, std::meta::info Enclosing,
341 std::meta::info Site>
342 void collect([[maybe_unused]]
bool excluded, [[maybe_unused]]
bool styled_site) {
345 template for (
constexpr auto c :
355 template <std::meta::info Fn,
class Style>
357 template for (
constexpr auto p :
358 std::define_static_array(std::meta::parameters_of(Fn)))
361 if constexpr (!std::meta::is_constructor(Fn)) {
362 using R = [:std::meta::return_type_of(Fn):];
363 if constexpr (!std::is_void_v<R>)
364 collect<std::meta::return_type_of(Fn), Style, std::meta::parent_of(Fn),
365 Fn>(
false, styled_site);
373 std::string
render(
const std::string& ns)
const {
374 std::vector<entry> es{
entries};
375 std::sort(es.begin(), es.end(),
376 [](
const entry& a,
const entry& b) { return a.name < b.name; });
377 for (std::size_t i{1}; i < es.size(); ++i)
378 if (!es[i].excluded && !es[i - 1].excluded &&
379 es[i].name == es[i - 1].name &&
380 es[i].spelling != es[i - 1].spelling)
381 return "#error welder: two distinct opaque containers derive the "
383 es[i].name +
"' (" + es[i - 1].spelling +
" vs " +
385 "); this generator cannot rename them automatically.\n";
387 out +=
"#pragma once\n";
388 out +=
"// AUTO-GENERATED by welder (welder::rods::opaque_containers). Do not edit.\n";
390 out +=
"// Include AFTER your welded type headers and the active backend's\n";
391 out +=
"// <welder/rods/python/{pybind11,nanobind}/rod.hpp>, before the module.\n";
392 out +=
"#include <map>\n#include <string>\n#include <unordered_map>\n#include <vector>\n\n";
393 for (
const entry& e : es)
395 out +=
"WELDER_OPAQUE(" + e.spelling +
")\n";
396 out +=
"\nnamespace " + ns +
" {\n";
397 for (
const entry& e : es)
399 out +=
"using " + e.name +
400 " [[=welder::weld(welder::lang::py)]] = " + e.spelling +
";\n";
401 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 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 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 PHASE 1 register every element/key/value type's n...
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 the driver's PHASE 1 (name pre-registration) register t's name before PHASE 2 binds the container...
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.