mirror of
https://github.com/YosysHQ/yosys
synced 2025-10-09 17:31:59 +00:00
pyosys/hashlib: equivalence operators
This commit is contained in:
parent
447a6cb3f0
commit
c8404bf86b
4 changed files with 62 additions and 18 deletions
|
@ -51,10 +51,11 @@
|
||||||
namespace pybind11 {
|
namespace pybind11 {
|
||||||
namespace hashlib {
|
namespace hashlib {
|
||||||
|
|
||||||
template<typename T>
|
// "traits"
|
||||||
struct is_pointer { static const bool value = false; };
|
template <typename T> struct is_pointer: std::false_type {};
|
||||||
template<typename T>
|
template <typename T> struct is_pointer<T*>: std::true_type {};
|
||||||
struct is_pointer<T*> { static const bool value = true; };
|
template <typename T> struct is_optional: std::false_type {};
|
||||||
|
template <typename T> struct is_optional< std::optional<T> >: std::true_type {};
|
||||||
|
|
||||||
bool is_mapping(object obj) {
|
bool is_mapping(object obj) {
|
||||||
object mapping = module_::import("collections.abc").attr("Mapping");
|
object mapping = module_::import("collections.abc").attr("Mapping");
|
||||||
|
@ -270,6 +271,12 @@ void bind_set(module &m, const char *name_cstr) {
|
||||||
.def("__iter__", [](const C &s){
|
.def("__iter__", [](const C &s){
|
||||||
return make_iterator(s.begin(), s.end());
|
return make_iterator(s.begin(), s.end());
|
||||||
}, keep_alive<0,1>())
|
}, keep_alive<0,1>())
|
||||||
|
.def("__eq__", [](const C &s, const C &other) { return s == other; })
|
||||||
|
.def("__eq__", [](const C &s, const iterable &other) {
|
||||||
|
C other_cast;
|
||||||
|
unionize<C, T>(other_cast, other);
|
||||||
|
return s == other_cast;
|
||||||
|
})
|
||||||
.def("__repr__", [name_cstr](const iterable &s){
|
.def("__repr__", [name_cstr](const iterable &s){
|
||||||
// repr(set(s)) where s is iterable would be more terse/robust
|
// repr(set(s)) where s is iterable would be more terse/robust
|
||||||
// but are there concerns with copying?
|
// but are there concerns with copying?
|
||||||
|
@ -292,17 +299,17 @@ void bind_pool(module &m, const char *name_cstr) {
|
||||||
|
|
||||||
|
|
||||||
template <typename C, typename K, typename V>
|
template <typename C, typename K, typename V>
|
||||||
void update_dict(C *target, const iterable &iterable_or_mapping) {
|
void update_dict(C &target, const iterable &iterable_or_mapping) {
|
||||||
if (is_mapping(iterable_or_mapping)) {
|
if (is_mapping(iterable_or_mapping)) {
|
||||||
for (const auto &key: iterable_or_mapping) {
|
for (const auto &key: iterable_or_mapping) {
|
||||||
(*target)[cast<K>(key)] = cast<V>(iterable_or_mapping[key]);
|
target[cast<K>(key)] = cast<V>(iterable_or_mapping[key]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (const auto &pair: iterable_or_mapping) {
|
for (const auto &pair: iterable_or_mapping) {
|
||||||
if (len(pair) != 2) {
|
if (len(pair) != 2) {
|
||||||
throw value_error(str("iterable element %s has more than two elements").format(str(pair)));
|
throw value_error(str("iterable element %s has more than two elements").format(str(pair)));
|
||||||
}
|
}
|
||||||
(*target)[cast<K>(pair[cast(0)])] = cast<V>(pair[cast(1)]);
|
target[cast<K>(pair[cast(0)])] = cast<V>(pair[cast(1)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -314,7 +321,7 @@ void bind_dict(module &m, const char *name_cstr) {
|
||||||
.def(init<const C &>()) // copy constructor
|
.def(init<const C &>()) // copy constructor
|
||||||
.def(init([](const iterable &other){ // copy instructor from arbitrary iterables and mappings
|
.def(init([](const iterable &other){ // copy instructor from arbitrary iterables and mappings
|
||||||
auto s = new C();
|
auto s = new C();
|
||||||
update_dict<C, K, V>(s, other);
|
update_dict<C, K, V>(*s, other);
|
||||||
return s;
|
return s;
|
||||||
}))
|
}))
|
||||||
.def("__len__", [](const C &s){ return (size_t)s.size(); })
|
.def("__len__", [](const C &s){ return (size_t)s.size(); })
|
||||||
|
@ -352,7 +359,15 @@ void bind_dict(module &m, const char *name_cstr) {
|
||||||
return s.at(k);
|
return s.at(k);
|
||||||
}
|
}
|
||||||
}, arg("key"), arg("default") = std::nullopt)
|
}, arg("key"), arg("default") = std::nullopt)
|
||||||
.def("popitem", [name_cstr](args _) { throw std::runtime_error(std::string(name_cstr) + " is not an ordered dictionary"); })
|
.def("popitem", [](C &s) {
|
||||||
|
auto it = s.begin();
|
||||||
|
if (it == s.end()) {
|
||||||
|
throw key_error("dict is empty");
|
||||||
|
}
|
||||||
|
auto copy = *it;
|
||||||
|
s.erase(it);
|
||||||
|
return copy;
|
||||||
|
})
|
||||||
.def("setdefault", [name_cstr](C &s, const K& k, std::optional<const V> &default_) {
|
.def("setdefault", [name_cstr](C &s, const K& k, std::optional<const V> &default_) {
|
||||||
auto it = s.find(k);
|
auto it = s.find(k);
|
||||||
if (it != s.end()) {
|
if (it != s.end()) {
|
||||||
|
@ -367,22 +382,25 @@ void bind_dict(module &m, const char *name_cstr) {
|
||||||
s[k] = nullptr;
|
s[k] = nullptr;
|
||||||
return (V)nullptr;
|
return (V)nullptr;
|
||||||
}
|
}
|
||||||
// TODO: std::optional? do we care?
|
if constexpr (is_optional<V>::value) {
|
||||||
|
s[k] = std::nullopt;
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
throw type_error(std::string("the value type of ") + name_cstr + " is not nullable");
|
throw type_error(std::string("the value type of ") + name_cstr + " is not nullable");
|
||||||
}, arg("key"), arg("default") = std::nullopt)
|
}, arg("key"), arg("default") = std::nullopt)
|
||||||
.def("update", [](C &s, iterable iterable_or_mapping) {
|
.def("update", [](C &s, iterable iterable_or_mapping) {
|
||||||
update_dict<C, K, V>(&s, iterable_or_mapping);
|
update_dict<C, K, V>(s, iterable_or_mapping);
|
||||||
}, arg("iterable_or_mapping"))
|
}, arg("iterable_or_mapping"))
|
||||||
.def("values", [](const C &s){
|
.def("values", [](const C &s){
|
||||||
return make_value_iterator(s.begin(), s.end());
|
return make_value_iterator(s.begin(), s.end());
|
||||||
}, keep_alive<0,1>())
|
}, keep_alive<0,1>())
|
||||||
.def("__or__", [](const C &s, iterable iterable_or_mapping) {
|
.def("__or__", [](const C &s, iterable iterable_or_mapping) {
|
||||||
auto result = new C(s);
|
auto result = new C(s);
|
||||||
update_dict<C, K, V>(result, iterable_or_mapping);
|
update_dict<C, K, V>(*result, iterable_or_mapping);
|
||||||
return result;
|
return result;
|
||||||
})
|
})
|
||||||
.def("__ior__", [](C &s, iterable iterable_or_mapping) {
|
.def("__ior__", [](C &s, iterable iterable_or_mapping) {
|
||||||
update_dict<C, K, V>(&s, iterable_or_mapping);
|
update_dict<C, K, V>(s, iterable_or_mapping);
|
||||||
return s;
|
return s;
|
||||||
})
|
})
|
||||||
.def("__bool__", [](const C &s) { return s.size() != 0; })
|
.def("__bool__", [](const C &s) { return s.size() != 0; })
|
||||||
|
@ -402,6 +420,17 @@ void bind_dict(module &m, const char *name_cstr) {
|
||||||
return representation;
|
return representation;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// K is always comparable
|
||||||
|
// Python implements `is` as a fallback to check if it's the same object
|
||||||
|
if constexpr (detail::is_comparable<V>::value) {
|
||||||
|
cls.def("__eq__", [](const C &s, const C &other) { return s == other; });
|
||||||
|
cls.def("__eq__", [](const C &s, const iterable &other) {
|
||||||
|
C other_cast;
|
||||||
|
update_dict<C, K, V>(other_cast, other);
|
||||||
|
return s == other_cast;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Inherit from collections.abc.Mapping so update operators (and a bunch
|
// Inherit from collections.abc.Mapping so update operators (and a bunch
|
||||||
// of other things) work.
|
// of other things) work.
|
||||||
auto collections_abc = module_::import("collections.abc");
|
auto collections_abc = module_::import("collections.abc");
|
||||||
|
|
|
@ -36,7 +36,7 @@ using namespace RTLIL;
|
||||||
#include "wrappers.inc.cc"
|
#include "wrappers.inc.cc"
|
||||||
|
|
||||||
namespace YOSYS_PYTHON {
|
namespace YOSYS_PYTHON {
|
||||||
struct YosysStatics{};
|
struct Globals {};
|
||||||
|
|
||||||
// Trampolines for Classes with Python-Overridable Virtual Methods
|
// Trampolines for Classes with Python-Overridable Virtual Methods
|
||||||
// https://pybind11.readthedocs.io/en/stable/advanced/classes.html#overriding-virtual-functions-in-python
|
// https://pybind11.readthedocs.io/en/stable/advanced/classes.html#overriding-virtual-functions-in-python
|
||||||
|
@ -192,7 +192,7 @@ namespace YOSYS_PYTHON {
|
||||||
m.def("log_file_error", [](std::string_view file, int line, std::string s) { log_formatted_file_error(file, line, s); });
|
m.def("log_file_error", [](std::string_view file, int line, std::string s) { log_formatted_file_error(file, line, s); });
|
||||||
|
|
||||||
// Namespace to host global objects
|
// Namespace to host global objects
|
||||||
auto global_variables = py::class_<YosysStatics>(m, "Yosys");
|
auto global_variables = py::class_<Globals>(m, "Globals");
|
||||||
|
|
||||||
// Trampoline Classes
|
// Trampoline Classes
|
||||||
py::class_<Pass, YOSYS_PYTHON::PassTrampoline, std::unique_ptr<Pass, py::nodelete>>(m, "Pass")
|
py::class_<Pass, YOSYS_PYTHON::PassTrampoline, std::unique_ptr<Pass, py::nodelete>>(m, "Pass")
|
||||||
|
|
|
@ -26,4 +26,19 @@ the_great_or = constructor_test_1 | constructor_test_2 | constructor_test_3
|
||||||
|
|
||||||
assert set(the_great_or) == {"first", "key", "tomato", "im running"}
|
assert set(the_great_or) == {"first", "key", "tomato", "im running"}
|
||||||
repr_test = eval(repr(the_great_or))
|
repr_test = eval(repr(the_great_or))
|
||||||
assert repr_test == the_great_or
|
|
||||||
|
assert repr_test == the_great_or # compare dicts
|
||||||
|
assert repr_test == {'tomato': 'tomato', 'first': 'second', 'key': 'value', 'im running': 'out of string ideas', } # compare dict with mapping
|
||||||
|
|
||||||
|
before = len(repr_test)
|
||||||
|
print(repr_test.popitem())
|
||||||
|
assert before - 1 == len(repr_test)
|
||||||
|
|
||||||
|
# test noncomparable
|
||||||
|
## if ys.CellType ever gets an == operator just disable this section
|
||||||
|
uncomparable_value = ys.Globals.yosys_celltypes.cell_types[ys.IdString("$not")]
|
||||||
|
|
||||||
|
x = ys.IdstringToCelltypeDict({ ys.IdString("\\a"): uncomparable_value})
|
||||||
|
y = ys.IdstringToCelltypeDict({ ys.IdString("\\a"): uncomparable_value})
|
||||||
|
|
||||||
|
assert x != y # not comparable
|
||||||
|
|
|
@ -33,10 +33,10 @@ for cls in [StringSet, StringPool]:
|
||||||
C |= {"A", "B", "C"}
|
C |= {"A", "B", "C"}
|
||||||
D |= {"C", "D", "E"}
|
D |= {"C", "D", "E"}
|
||||||
c_symdiff_d = (C ^ D)
|
c_symdiff_d = (C ^ D)
|
||||||
assert (c_symdiff_d) == {"A", "B", "D", "E"}
|
assert c_symdiff_d == {"A", "B", "D", "E"} # compare against iterable
|
||||||
|
|
||||||
repr_test = eval(repr(c_symdiff_d))
|
repr_test = eval(repr(c_symdiff_d))
|
||||||
c_symdiff_d == repr_test
|
assert c_symdiff_d == repr_test # compare against self
|
||||||
|
|
||||||
|
|
||||||
print("Done.")
|
print("Done.")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue