Skip to content
Snippets Groups Projects
Unverified Commit 7a49c650 authored by Alexander Peyser's avatar Alexander Peyser Committed by GitHub
Browse files

Make `label_dict` conform (more) to Python's `dict` contract

Add methods to `label_dict`
- iterators `keys`, `values`, `items`
- `update(dict)`
- `label_dict(iter[k, v])`, `label_dict(label_dict)`
- `__contains__`

Also bump `pybind11` to latest and clean up `label_dict` implementation.

Addresses #1535 (in so far as possible) 
parent dfd077b2
No related branches found
No related tags found
No related merge requests found
...@@ -228,33 +228,65 @@ void register_cells(pybind11::module& m) { ...@@ -228,33 +228,65 @@ void register_cells(pybind11::module& m) {
pybind11::class_<label_dict_proxy> label_dict(m, "label_dict", pybind11::class_<label_dict_proxy> label_dict(m, "label_dict",
"A dictionary of labelled region and locset definitions, with a\n" "A dictionary of labelled region and locset definitions, with a\n"
"unique label is assigned to each definition."); "unique label assigned to each definition.");
label_dict label_dict
.def(pybind11::init<>(), "Create an empty label dictionary.") .def(pybind11::init<>(), "Create an empty label dictionary.")
.def(pybind11::init<const std::unordered_map<std::string, std::string>&>(), .def(pybind11::init<const std::unordered_map<std::string, std::string>&>(),
"Initialize a label dictionary from a dictionary with string labels as keys," "Initialize a label dictionary from a dictionary with string labels as keys,"
" and corresponding definitions as strings.") " and corresponding definitions as strings.")
.def(pybind11::init<const label_dict_proxy&>(),
"Initialize a label dictionary from another one")
.def(pybind11::init([](pybind11::iterator& it) {
label_dict_proxy ld;
for (; it != pybind11::iterator::sentinel(); ++it) {
const auto tuple = it->cast<pybind11::sequence>();
const auto key = tuple[0].cast<std::string>();
const auto value = tuple[1].cast<std::string>();
ld.set(key, value);
}
return ld;
}),
"Initialize a label dictionary from an iterable of key, definition pairs")
.def("__setitem__", .def("__setitem__",
[](label_dict_proxy& l, const char* name, const char* desc) { [](label_dict_proxy& l, const char* name, const char* desc) {
l.set(name, desc);}) l.set(name, desc);})
.def("__getitem__", .def("__getitem__",
[](label_dict_proxy& l, const char* name) { [](label_dict_proxy& l, const char* name) {
if (!l.cache.count(name)) { if (auto v = l.getitem(name)) return v.value();
throw pybind11::key_error(name); throw pybind11::key_error(name);
}
return l.cache.at(name);
}) })
.def("__len__", &label_dict_proxy::size) .def("__len__", &label_dict_proxy::size)
.def("__iter__", .def("__iter__",
[](const label_dict_proxy &ld) { [](const label_dict_proxy &ld) {
return pybind11::make_key_iterator(ld.cache.begin(), ld.cache.end());}, return pybind11::make_key_iterator(ld.cache.begin(), ld.cache.end());},
pybind11::keep_alive<0, 1>()) pybind11::keep_alive<0, 1>())
.def("__contains__",
[](const label_dict_proxy &ld, const char* name) {
return ld.contains(name);})
.def("keys",
[](const label_dict_proxy &ld) {
return pybind11::make_key_iterator(ld.cache.begin(), ld.cache.end());},
pybind11::keep_alive<0, 1>())
.def("items",
[](const label_dict_proxy &ld) {
return pybind11::make_iterator(ld.cache.begin(), ld.cache.end());},
pybind11::keep_alive<0, 1>())
.def("values",
[](const label_dict_proxy &ld) {
return pybind11::make_value_iterator(ld.cache.begin(), ld.cache.end());
},
pybind11::keep_alive<0, 1>())
.def("append", [](label_dict_proxy& l, const label_dict_proxy& other, const char* prefix) { .def("append", [](label_dict_proxy& l, const label_dict_proxy& other, const char* prefix) {
l.import(other, prefix); l.import(other, prefix);
}, },
"other"_a, "The label_dict to be imported" "other"_a, "The label_dict to be imported"
"prefix"_a="", "optional prefix appended to the region and locset labels", "prefix"_a="", "optional prefix appended to the region and locset labels",
"Import the entries of a another label dictionary with an optional prefix.") "Import the entries of a another label dictionary with an optional prefix.")
.def("update", [](label_dict_proxy& l, const label_dict_proxy& other) {
l.import(other);
},
"other"_a, "The label_dict to be imported"
"Import the entries of a another label dictionary.")
.def_readonly("regions", &label_dict_proxy::regions, .def_readonly("regions", &label_dict_proxy::regions,
"The region definitions.") "The region definitions.")
.def_readonly("locsets", &label_dict_proxy::locsets, .def_readonly("locsets", &label_dict_proxy::locsets,
......
...@@ -20,7 +20,7 @@ struct label_dict_proxy { ...@@ -20,7 +20,7 @@ struct label_dict_proxy {
label_dict_proxy(const str_map& in) { label_dict_proxy(const str_map& in) {
for (auto& i: in) { for (auto& i: in) {
set(i.first.c_str(), i.second.c_str()); set(i.first, i.second);
} }
} }
...@@ -28,18 +28,20 @@ struct label_dict_proxy { ...@@ -28,18 +28,20 @@ struct label_dict_proxy {
update_cache(); update_cache();
} }
label_dict_proxy(const label_dict_proxy&) = default;
std::size_t size() const { std::size_t size() const {
return locsets.size() + regions.size(); return locsets.size() + regions.size();
} }
void import(const label_dict_proxy& other, std::string prefix) { void import(const label_dict_proxy& other, std::string prefix = "") {
dict.import(other.dict, prefix); dict.import(other.dict, prefix);
clear_cache(); clear_cache();
update_cache(); update_cache();
} }
void set(const char* name, const char* desc) { void set(const std::string& name, const std::string& desc) {
using namespace std::string_literals; using namespace std::string_literals;
// The following code takes an input name and a region or locset // The following code takes an input name and a region or locset
// description, e.g.: // description, e.g.:
...@@ -81,7 +83,7 @@ struct label_dict_proxy { ...@@ -81,7 +83,7 @@ struct label_dict_proxy {
throw std::runtime_error(util::pprintf(base, name, desc, msg)); throw std::runtime_error(util::pprintf(base, name, desc, msg));
} }
// Exceptions are thrown in parse or eval if an unexpected error occured. // Exceptions are thrown in parse or eval if an unexpected error occured.
catch (std::exception& e) { catch (std::exception& e) {
const char* msg = const char* msg =
"\n----- internal error -------------------------------------------" "\n----- internal error -------------------------------------------"
...@@ -108,6 +110,17 @@ struct label_dict_proxy { ...@@ -108,6 +110,17 @@ struct label_dict_proxy {
s += ")"; s += ")";
return s; return s;
} }
bool contains(const std::string& name) const {
return cache.find(name) != cache.end();
}
std::optional<std::string> getitem(const std::string& name) const {
if (auto kv = cache.find(name); kv != cache.end()) {
return kv->second;
}
return {};
}
private: private:
......
Subproject commit 8de7772cc72daca8e947b79b83fea46214931604 Subproject commit 750e38dcfdac59231a615580d4e6cb3647b31779
...@@ -49,7 +49,7 @@ class Arbor(CMakePackage, CudaPackage): ...@@ -49,7 +49,7 @@ class Arbor(CMakePackage, CudaPackage):
extends('python', when='+python') extends('python', when='+python')
depends_on('python@3.6:', when="+python", type=('build', 'run')) depends_on('python@3.6:', when="+python", type=('build', 'run'))
depends_on('py-numpy', when='+python', type=('build', 'run')) depends_on('py-numpy', when='+python', type=('build', 'run'))
depends_on('py-pybind11@2.6:', when='+python', type=('build', 'run')) depends_on('py-pybind11@2.8:', when='+python', type=('build', 'run'))
# sphinx based documentation # sphinx based documentation
depends_on('python@3.6:', when="+doc", type='build') depends_on('python@3.6:', when="+doc", type='build')
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment