| 732 | |
| 733 | template <typename Map, typename holder_type = default_holder_type<Map>, typename... Args> |
| 734 | class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&...args) { |
| 735 | using KeyType = typename Map::key_type; |
| 736 | using MappedType = typename Map::mapped_type; |
| 737 | using KeysView = detail::keys_view; |
| 738 | using ValuesView = detail::values_view; |
| 739 | using ItemsView = detail::items_view; |
| 740 | using Class_ = class_<Map, holder_type>; |
| 741 | |
| 742 | // If either type is a non-module-local bound type then make the map binding non-local as well; |
| 743 | // otherwise (e.g. both types are either module-local or converting) the map will be |
| 744 | // module-local. |
| 745 | auto *tinfo = detail::get_type_info(typeid(MappedType)); |
| 746 | bool local = !tinfo || tinfo->module_local; |
| 747 | if (local) { |
| 748 | tinfo = detail::get_type_info(typeid(KeyType)); |
| 749 | local = !tinfo || tinfo->module_local; |
| 750 | } |
| 751 | |
| 752 | Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...); |
| 753 | |
| 754 | // Wrap KeysView if it wasn't already wrapped |
| 755 | if (!detail::get_type_info(typeid(KeysView))) { |
| 756 | class_<KeysView> keys_view(scope, "KeysView", pybind11::module_local(local)); |
| 757 | keys_view.def("__len__", &KeysView::len); |
| 758 | keys_view.def("__iter__", |
| 759 | &KeysView::iter, |
| 760 | keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */ |
| 761 | ); |
| 762 | keys_view.def("__contains__", &KeysView::contains); |
| 763 | } |
| 764 | // Similarly for ValuesView: |
| 765 | if (!detail::get_type_info(typeid(ValuesView))) { |
| 766 | class_<ValuesView> values_view(scope, "ValuesView", pybind11::module_local(local)); |
| 767 | values_view.def("__len__", &ValuesView::len); |
| 768 | values_view.def("__iter__", |
| 769 | &ValuesView::iter, |
| 770 | keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */ |
| 771 | ); |
| 772 | } |
| 773 | // Similarly for ItemsView: |
| 774 | if (!detail::get_type_info(typeid(ItemsView))) { |
| 775 | class_<ItemsView> items_view(scope, "ItemsView", pybind11::module_local(local)); |
| 776 | items_view.def("__len__", &ItemsView::len); |
| 777 | items_view.def("__iter__", |
| 778 | &ItemsView::iter, |
| 779 | keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */ |
| 780 | ); |
| 781 | } |
| 782 | |
| 783 | cl.def(init<>()); |
| 784 | |
| 785 | // Register stream insertion operator (if possible) |
| 786 | detail::map_if_insertion_operator<Map, Class_>(cl, name); |
| 787 | |
| 788 | cl.def( |
| 789 | "__bool__", |
| 790 | [](const Map &m) -> bool { return !m.empty(); }, |
| 791 | "Check whether the map is nonempty"); |
nothing calls this directly
no test coverage detected