diff --git a/source/context.cpp b/source/context.cpp index 901750a0..3ccd5151 100644 --- a/source/context.cpp +++ b/source/context.cpp @@ -93,30 +93,48 @@ using ModuleGetter = std::function< pybind11::module & (std::string const &) >; {1} +static std::vector const reserved_python_words{{ + "nonlocal", + "global", +}}; +std::string mangle_namespace_name(std::string const &ns) {{ + if( std::find(reserved_python_words.begin(), reserved_python_words.end(), ns) == reserved_python_words.end() ) return ns; + return ns + '_'; +}} + +void makeSubmodules(const std::vector &moduleNames, std::map &modules) {{ + std::string prevNamespace = ""; + std::string curNamespace = ""; + for (const auto &curMod : moduleNames) {{ + if (curNamespace.size() > 0) + curNamespace += "::"; // don't add :: to the start + const auto mangledMod = mangle_namespace_name(curMod); + curNamespace += mangledMod; + if (modules.count(curNamespace) == 0) {{ + modules[curNamespace] = modules[prevNamespace].def_submodule(mangledMod.c_str(), ("Bindings for " + curNamespace + " namespace").c_str()); + }} + prevNamespace = curNamespace; + }} +}} + + PYBIND11_MODULE({2}, root_module) {{ root_module.doc() = "{2} module"; std::map modules; ModuleGetter M = [&](std::string const &namespace_) -> pybind11::module & {{ - auto it = modules.find(namespace_); + auto it = modules.find(mangle_namespace_name(namespace_)); if( it == modules.end() ) throw std::runtime_error("Attempt to access pybind11::module for namespace " + namespace_ + " before it was created!!!"); return it->second; }}; modules[""] = root_module; - static std::vector const reserved_python_words {{"nonlocal", "global", }}; - - auto mangle_namespace_name( - [](std::string const &ns) -> std::string {{ - if ( std::find(reserved_python_words.begin(), reserved_python_words.end(), ns) == reserved_python_words.end() ) return ns; - return ns+'_'; - }} - ); - - std::vector< std::pair > sub_modules {{ + std::vector< std::vector > sub_modules {{ {3} }}; - for(auto &p : sub_modules ) modules[ p.first.empty() ? p.second : p.first+"::"+p.second ] = modules[p.first].def_submodule( mangle_namespace_name(p.second).c_str(), ("Bindings for " + p.first + "::" + p.second + " namespace").c_str() ); + for(auto &p : sub_modules ) {{ + makeSubmodules(p, modules); + }} //pybind11::class_>(M(""), "_encapsulated_data_"); @@ -213,22 +231,20 @@ void Context::add_to_binded(CXXRecordDecl const *C) /// examine binded objects and recursivly create all nested namespaces std::set Context::create_all_nested_namespaces() { - vector namespaces; + std::set namespaces; for( auto &b : binders ) { if( b->code().size() ) { string ns = namespace_from_named_decl(b->named_decl()); while( ns.size() ) { - namespaces.push_back(ns); + namespaces.insert(ns); ns = base_namespace(ns); } } } - std::set s(namespaces.begin(), namespaces.end()); - - return s; + return namespaces; } std::string Context::module_variable_name(std::string const &namespace_) @@ -454,9 +470,15 @@ void Context::generate(Config const &config) string namespace_pairs; std::set namespaces = create_all_nested_namespaces(); for( auto &n : namespaces ) { - if( n.size() ) namespace_pairs += "\t\t{{\"{}\", \"{}\"}},\n"_format(base_namespace(n), last_namespace(n)); - modules += n; - modules += ' '; + if( n.size() ) { + const auto curMods = split(n, "::"); + namespace_pairs += "\t\t{"; + for( size_t i = 0; i < curMods.size(); i++ ) { + namespace_pairs += "\"" + curMods[i] + "\""; + if( i != curMods.size() - 1 ) namespace_pairs += ", "; + } + namespace_pairs += "},\n"; + } } replace(modules, "::", "."); diff --git a/source/util.cpp b/source/util.cpp index 2b425a52..306228cd 100644 --- a/source/util.cpp +++ b/source/util.cpp @@ -36,25 +36,21 @@ namespace binder { /// Split string using given separator -vector split(string const &buffer, string const &separator) -{ - string line; - vector lines; - - for( uint i = 0; i < buffer.size(); ++i ) { - if( buffer.compare(i, separator.size(), separator) ) line.push_back(buffer[i]); - else { - lines.push_back(line); - line.resize(0); - } - } - - if( line.size() ) lines.push_back(line); - - return lines; +std::vector split(const std::string &s, const std::string &delimiter) { + size_t pos_start = 0, pos_end, delim_len = delimiter.length(); + std::string token; + std::vector res; + + while ((pos_end = s.find(delimiter, pos_start)) != std::string::npos) { + token = s.substr (pos_start, pos_end - pos_start); + pos_start = pos_end + delim_len; + res.push_back (token); + } + + res.push_back (s.substr (pos_start)); + return res; } - /// Replace all occurrences of string void replace_reverse(string &r, string const &from, string const &to) { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4c356de1..88f2e389 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -141,6 +141,7 @@ set( binder_tests T42.stl.names.multiset T43.stl.pybind11_include_stl T50.namespace_binder + T51.nested_namespace T60.custom_shared ) if (pybind11_VERSION VERSION_LESS 2.5.99) diff --git a/test/T51.nested_namespace.hpp b/test/T51.nested_namespace.hpp new file mode 100644 index 00000000..1d623742 --- /dev/null +++ b/test/T51.nested_namespace.hpp @@ -0,0 +1,15 @@ + +#ifndef _INCLUDED_T51_NESTED_NAMESPACES_ +#define _INCLUDED_T51_NESTED_NAMESPACES_ + +namespace aaaa::bbbb::cccc { +void foo_aaaa_bbbb_cccc() {} +namespace dddd{ + void bar_aaaa_bbbb_cccc_dddd() {} +} +namespace eeee { + void baz_aaaa_bbbb_cccc_eeee() {} +} +} + +#endif // _INCLUDED_T51_NESTED_NAMESPACES_ diff --git a/test/T51.nested_namespace.ref.cpp b/test/T51.nested_namespace.ref.cpp new file mode 100644 index 00000000..b7535684 --- /dev/null +++ b/test/T51.nested_namespace.ref.cpp @@ -0,0 +1,150 @@ +// File: T51_nested_namespace.cpp +#include // aaaa::bbbb::cccc::foo_aaaa_bbbb_cccc + +#include +#include +#include + +#ifndef BINDER_PYBIND11_TYPE_CASTER + #define BINDER_PYBIND11_TYPE_CASTER + PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr, false) + PYBIND11_DECLARE_HOLDER_TYPE(T, T*, false) + PYBIND11_MAKE_OPAQUE(std::shared_ptr) +#endif + +void bind_T51_nested_namespace(std::function< pybind11::module &(std::string const &namespace_) > &M) +{ + // aaaa::bbbb::cccc::foo_aaaa_bbbb_cccc() file:T51.nested_namespace.hpp line:6 + M("aaaa::bbbb::cccc").def("foo_aaaa_bbbb_cccc", (void (*)()) &aaaa::bbbb::cccc::foo_aaaa_bbbb_cccc, "C++: aaaa::bbbb::cccc::foo_aaaa_bbbb_cccc() --> void"); + +} + + +// File: T51_nested_namespace_1.cpp +#include // aaaa::bbbb::cccc::dddd::bar_aaaa_bbbb_cccc_dddd + +#include +#include +#include + +#ifndef BINDER_PYBIND11_TYPE_CASTER + #define BINDER_PYBIND11_TYPE_CASTER + PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr, false) + PYBIND11_DECLARE_HOLDER_TYPE(T, T*, false) + PYBIND11_MAKE_OPAQUE(std::shared_ptr) +#endif + +void bind_T51_nested_namespace_1(std::function< pybind11::module &(std::string const &namespace_) > &M) +{ + // aaaa::bbbb::cccc::dddd::bar_aaaa_bbbb_cccc_dddd() file:T51.nested_namespace.hpp line:8 + M("aaaa::bbbb::cccc::dddd").def("bar_aaaa_bbbb_cccc_dddd", (void (*)()) &aaaa::bbbb::cccc::dddd::bar_aaaa_bbbb_cccc_dddd, "C++: aaaa::bbbb::cccc::dddd::bar_aaaa_bbbb_cccc_dddd() --> void"); + +} + + +// File: T51_nested_namespace_2.cpp +#include // aaaa::bbbb::cccc::eeee::baz_aaaa_bbbb_cccc_eeee + +#include +#include +#include + +#ifndef BINDER_PYBIND11_TYPE_CASTER + #define BINDER_PYBIND11_TYPE_CASTER + PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr, false) + PYBIND11_DECLARE_HOLDER_TYPE(T, T*, false) + PYBIND11_MAKE_OPAQUE(std::shared_ptr) +#endif + +void bind_T51_nested_namespace_2(std::function< pybind11::module &(std::string const &namespace_) > &M) +{ + // aaaa::bbbb::cccc::eeee::baz_aaaa_bbbb_cccc_eeee() file:T51.nested_namespace.hpp line:11 + M("aaaa::bbbb::cccc::eeee").def("baz_aaaa_bbbb_cccc_eeee", (void (*)()) &aaaa::bbbb::cccc::eeee::baz_aaaa_bbbb_cccc_eeee, "C++: aaaa::bbbb::cccc::eeee::baz_aaaa_bbbb_cccc_eeee() --> void"); + +} + + +#include +#include +#include +#include +#include +#include +#include + +#include + +using ModuleGetter = std::function< pybind11::module & (std::string const &) >; + +void bind_T51_nested_namespace(std::function< pybind11::module &(std::string const &namespace_) > &M); +void bind_T51_nested_namespace_1(std::function< pybind11::module &(std::string const &namespace_) > &M); +void bind_T51_nested_namespace_2(std::function< pybind11::module &(std::string const &namespace_) > &M); + + +static std::vector const reserved_python_words{ + "nonlocal", + "global", +}; +std::string mangle_namespace_name(std::string const &ns) { + if( std::find(reserved_python_words.begin(), reserved_python_words.end(), ns) == reserved_python_words.end() ) return ns; + return ns + '_'; +} + +void makeSubmodules(const std::vector &moduleNames, std::map &modules) { + std::string prevNamespace = ""; + std::string curNamespace = ""; + for (const auto &curMod : moduleNames) { + std::cout << "making: " << curMod << std::endl; + if (curNamespace.size() > 0) + curNamespace += "::"; // don't add :: to the start + const auto mangledMod = mangle_namespace_name(curMod); + std::cout << "mangled: " << mangledMod << std::endl; + curNamespace += mangledMod; + if (modules.count(curNamespace) == 0) { + std::cout << "defining namespace " << curNamespace << " in " << prevNamespace << std::endl; + modules[curNamespace] = modules[prevNamespace].def_submodule(mangledMod.c_str(), ("Bindings for " + curNamespace + " namespace").c_str()); + } + prevNamespace = curNamespace; + } +} + + +PYBIND11_MODULE(T51_nested_namespace, root_module) { + root_module.doc() = "T51_nested_namespace module"; + + std::map modules; + ModuleGetter M = [&](std::string const &namespace_) -> pybind11::module & { + auto it = modules.find(mangle_namespace_name(namespace_)); + if( it == modules.end() ) throw std::runtime_error("Attempt to access pybind11::module for namespace " + namespace_ + " before it was created!!!"); + return it->second; + }; + + modules[""] = root_module; + + std::vector< std::vector > sub_modules { + {"aaaa"}, + {"aaaa", "bbbb"}, + {"aaaa", "bbbb", "cccc"}, + {"aaaa", "bbbb", "cccc", "dddd"}, + {"aaaa", "bbbb", "cccc", "eeee"}, + }; + for(auto &p : sub_modules ) { + makeSubmodules(p, modules); + } + + //pybind11::class_>(M(""), "_encapsulated_data_"); + + bind_T51_nested_namespace(M); + bind_T51_nested_namespace_1(M); + bind_T51_nested_namespace_2(M); + +} + +// Source list file: /home/matt/workspace/binder/build/test//T51_nested_namespace.sources +// T51_nested_namespace.cpp +// T51_nested_namespace.cpp +// T51_nested_namespace_1.cpp +// T51_nested_namespace_2.cpp + +// Modules list file: /home/matt/workspace/binder/build/test//T51_nested_namespace.modules +//