#ifndef NETGEN_CORE_PYTHON_NGCORE_HPP #define NETGEN_CORE_PYTHON_NGCORE_HPP #include #include "array.hpp" #include "archive.hpp" #include "flags.hpp" #include "ngcore_api.hpp" namespace py = pybind11; namespace ngcore { template Array makeCArray(const py::object& obj) { Array arr; arr.SetAllocSize(py::len(obj)); if(py::isinstance(obj)) for(auto& val : py::cast(obj)) arr.Append(py::cast(val)); else if(py::isinstance(obj)) for(auto& val : py::cast(obj)) arr.Append(py::cast(val)); else throw py::type_error("Cannot convert Python object to C Array"); return arr; } void NGCORE_API SetFlag(Flags &flags, std::string s, py::object value); // Parse python kwargs to flags Flags NGCORE_API CreateFlagsFromKwArgs(py::object pyclass, const py::kwargs& kwargs, py::list info = py::list()); // *************** Archiving functionality ************** template Archive& Archive :: Shallow(T& val) { static_assert(detail::is_any_pointer, "ShallowArchive must be given pointer type!"); #ifdef NETGEN_PYTHON if(shallow_to_python) { if(is_output) ShallowOutPython(pybind11::cast(val)); else { pybind11::object obj; ShallowInPython(obj); val = pybind11::cast(obj); } } else #endif // NETGEN_PYTHON *this & val; return *this; } template class PyArchive : public ARCHIVE { private: pybind11::list lst; size_t index = 0; std::map version_needed; protected: using ARCHIVE::stream; using ARCHIVE::version_map; using ARCHIVE::logger; using ARCHIVE::GetLibraryVersions; public: PyArchive(const pybind11::object& alst = pybind11::none()) : ARCHIVE(std::make_shared()), lst(alst.is_none() ? pybind11::list() : pybind11::cast(alst)) { ARCHIVE::shallow_to_python = true; if(Input()) { stream = std::make_shared (pybind11::cast(lst[pybind11::len(lst)-1])); *this & version_needed; logger->debug("versions needed for unpickling = {}", version_needed); for(auto& libversion : version_needed) if(libversion.second > GetLibraryVersion(libversion.first)) throw Exception("Error in unpickling data:\nLibrary " + libversion.first + " must be at least " + libversion.second.to_string()); stream = std::make_shared (pybind11::cast(lst[pybind11::len(lst)-2])); *this & version_map; stream = std::make_shared (pybind11::cast(lst[pybind11::len(lst)-3])); } } void NeedsVersion(const std::string& library, const std::string& version) override { if(Output()) { logger->debug("Need version {} of library {}.", version, library); version_needed[library] = version_needed[library] > version ? version_needed[library] : version; } } using ARCHIVE::Output; using ARCHIVE::Input; using ARCHIVE::FlushBuffer; using ARCHIVE::operator&; using ARCHIVE::operator<<; using ARCHIVE::GetVersion; void ShallowOutPython(const pybind11::object& val) override { lst.append(val); } void ShallowInPython(pybind11::object& val) override { val = lst[index++]; } pybind11::list WriteOut() { FlushBuffer(); lst.append(pybind11::bytes(std::static_pointer_cast(stream)->str())); stream = std::make_shared(); *this & GetLibraryVersions(); FlushBuffer(); lst.append(pybind11::bytes(std::static_pointer_cast(stream)->str())); stream = std::make_shared(); logger->debug("Writeout version needed = {}", version_needed); *this & version_needed; FlushBuffer(); lst.append(pybind11::bytes(std::static_pointer_cast(stream)->str())); return lst; } }; template auto NGSPickle() { return pybind11::pickle([](T* self) { PyArchive ar; ar & self; auto output = pybind11::make_tuple(ar.WriteOut()); GetLogger("Archive")->trace("Pickling output for object of type {} = {}", Demangle(typeid(T).name()), std::string(pybind11::str(output))); return output; }, [](const pybind11::tuple & state) { T* val = nullptr; GetLogger("Archive")->trace("State for unpickling of object of type {} = {}", Demangle(typeid(T).name()), std::string(pybind11::str(state[0]))); PyArchive ar(state[0]); ar & val; return val; }); } } // namespace ngcore #endif // NETGEN_CORE_PYTHON_NGCORE_HPP