99#include < AMReX_IntVect.H>
1010#include < AMReX_ParmParse.H>
1111
12+ #include < functional>
1213#include < iostream>
1314#include < string>
15+ #include < string_view>
1416#include < vector>
1517
1618
@@ -111,34 +113,61 @@ void init_ParmParse(py::module &m)
111113
112114 auto g_table = pp.table ();
113115
116+ // sort all keys
114117 std::vector<std::string> sorted_names;
115118 sorted_names.reserve (g_table.size ());
116119 for (auto const & [name, entry] : g_table) {
117120 sorted_names.push_back (name);
118121 }
119122 std::sort (sorted_names.begin (), sorted_names.end ());
120123
124+ // helper function to unroll any nested parameter.sub.options into dict of dict of value
125+ auto add_nested = [&d](auto && value, std::string_view s) {
126+ py::dict d_inner = d; // just hold a handle to the current dict
127+
128+ while (true ) {
129+ auto pos = s.find (' .' );
130+ bool last = pos == std::string_view::npos;
131+ py::str key (s.substr (0 , pos));
132+
133+ if (last) {
134+ d_inner[key] = value;
135+ break ;
136+ } else {
137+ // Create nested dict if missing or wrong type
138+ if (!d_inner.contains (key) ||
139+ !py::isinstance<py::dict>(d_inner[key])) {
140+ d_inner[key] = py::dict ();
141+ }
142+
143+ // Move one level deeper (safe, keeps reference alive)
144+ d_inner = d_inner[key].cast <py::dict>();
145+ }
146+ s.remove_prefix (pos + 1 );
147+ }
148+ };
149+
121150 for (auto const & name : sorted_names) {
122151 auto const & entry = g_table[name];
123152 for (auto const & vals : entry.m_vals ) {
124153 if (vals.size () == 1 ) {
125154 std::visit (
126- [&d,&name,&pp ](auto && arg) {
155+ [&](auto && arg) {
127156 using T = std::remove_pointer_t <std::decay_t <decltype (arg)>>;
128157 T v;
129158 pp.get (name.c_str (), v);
130- d[name. c_str ()] = v ;
159+ add_nested (v, name) ;
131160 },
132161 entry.m_typehint
133162 );
134163 } else {
135164 std::visit (
136- [&d,&name,&pp ](auto && arg) {
165+ [&](auto && arg) {
137166 using T = std::remove_pointer_t <std::decay_t <decltype (arg)>>;
138167 if constexpr (!std::is_same_v<T, bool >) {
139168 std::vector<T> valarr;
140169 pp.getarr (name.c_str (), valarr);
141- d[name. c_str ()] = valarr;
170+ add_nested ( valarr, name) ;
142171 }
143172 },
144173 entry.m_typehint
@@ -149,7 +178,18 @@ void init_ParmParse(py::module &m)
149178
150179 return d;
151180 },
152- " DOC GOES HERE TODO TODO"
181+ R"( Convert to a nested Python dictionary.
182+
183+ .. code-block:: python
184+
185+ # Example: dump all ParmParse entries to YAML or TOML
186+ import toml
187+ import yaml
188+
189+ pp = amr.ParmParse("").to_dict()
190+ yaml_string = yaml.dump(d)
191+ toml_string = toml.dumps(d)
192+ )"
153193 )
154194 ;
155195}
0 commit comments