111986Sandreas.sandberg@arm.com/*
211986Sandreas.sandberg@arm.com    tests/pybind11_tests.cpp -- pybind example plugin
311986Sandreas.sandberg@arm.com
411986Sandreas.sandberg@arm.com    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
511986Sandreas.sandberg@arm.com
611986Sandreas.sandberg@arm.com    All rights reserved. Use of this source code is governed by a
711986Sandreas.sandberg@arm.com    BSD-style license that can be found in the LICENSE file.
811986Sandreas.sandberg@arm.com*/
911986Sandreas.sandberg@arm.com
1011986Sandreas.sandberg@arm.com#include "pybind11_tests.h"
1111986Sandreas.sandberg@arm.com#include "constructor_stats.h"
1211986Sandreas.sandberg@arm.com
1312391Sjason@lowepower.com#include <functional>
1412391Sjason@lowepower.com#include <list>
1512391Sjason@lowepower.com
1612037Sandreas.sandberg@arm.com/*
1712037Sandreas.sandberg@arm.comFor testing purposes, we define a static global variable here in a function that each individual
1812037Sandreas.sandberg@arm.comtest .cpp calls with its initialization lambda.  It's convenient here because we can just not
1912037Sandreas.sandberg@arm.comcompile some test files to disable/ignore some of the test code.
2012037Sandreas.sandberg@arm.com
2112037Sandreas.sandberg@arm.comIt is NOT recommended as a way to use pybind11 in practice, however: the initialization order will
2212037Sandreas.sandberg@arm.combe essentially random, which is okay for our test scripts (there are no dependencies between the
2312037Sandreas.sandberg@arm.comindividual pybind11 test .cpp files), but most likely not what you want when using pybind11
2412037Sandreas.sandberg@arm.comproductively.
2512037Sandreas.sandberg@arm.com
2612037Sandreas.sandberg@arm.comInstead, see the "How can I reduce the build time?" question in the "Frequently asked questions"
2712037Sandreas.sandberg@arm.comsection of the documentation for good practice on splitting binding code over multiple files.
2812037Sandreas.sandberg@arm.com*/
2911986Sandreas.sandberg@arm.comstd::list<std::function<void(py::module &)>> &initializers() {
3011986Sandreas.sandberg@arm.com    static std::list<std::function<void(py::module &)>> inits;
3111986Sandreas.sandberg@arm.com    return inits;
3211986Sandreas.sandberg@arm.com}
3311986Sandreas.sandberg@arm.com
3412391Sjason@lowepower.comtest_initializer::test_initializer(Initializer init) {
3512391Sjason@lowepower.com    initializers().push_back(init);
3612391Sjason@lowepower.com}
3712391Sjason@lowepower.com
3812391Sjason@lowepower.comtest_initializer::test_initializer(const char *submodule_name, Initializer init) {
3912391Sjason@lowepower.com    initializers().push_back([=](py::module &parent) {
4012391Sjason@lowepower.com        auto m = parent.def_submodule(submodule_name);
4112391Sjason@lowepower.com        init(m);
4212391Sjason@lowepower.com    });
4311986Sandreas.sandberg@arm.com}
4411986Sandreas.sandberg@arm.com
4511986Sandreas.sandberg@arm.comvoid bind_ConstructorStats(py::module &m) {
4611986Sandreas.sandberg@arm.com    py::class_<ConstructorStats>(m, "ConstructorStats")
4711986Sandreas.sandberg@arm.com        .def("alive", &ConstructorStats::alive)
4811986Sandreas.sandberg@arm.com        .def("values", &ConstructorStats::values)
4911986Sandreas.sandberg@arm.com        .def_readwrite("default_constructions", &ConstructorStats::default_constructions)
5011986Sandreas.sandberg@arm.com        .def_readwrite("copy_assignments", &ConstructorStats::copy_assignments)
5111986Sandreas.sandberg@arm.com        .def_readwrite("move_assignments", &ConstructorStats::move_assignments)
5211986Sandreas.sandberg@arm.com        .def_readwrite("copy_constructions", &ConstructorStats::copy_constructions)
5311986Sandreas.sandberg@arm.com        .def_readwrite("move_constructions", &ConstructorStats::move_constructions)
5412391Sjason@lowepower.com        .def_static("get", (ConstructorStats &(*)(py::object)) &ConstructorStats::get, py::return_value_policy::reference_internal)
5512391Sjason@lowepower.com
5612391Sjason@lowepower.com        // Not exactly ConstructorStats, but related: expose the internal pybind number of registered instances
5712391Sjason@lowepower.com        // to allow instance cleanup checks (invokes a GC first)
5812391Sjason@lowepower.com        .def_static("detail_reg_inst", []() {
5912391Sjason@lowepower.com            ConstructorStats::gc();
6012391Sjason@lowepower.com            return py::detail::get_internals().registered_instances.size();
6112391Sjason@lowepower.com        })
6212391Sjason@lowepower.com        ;
6311986Sandreas.sandberg@arm.com}
6411986Sandreas.sandberg@arm.com
6512391Sjason@lowepower.comPYBIND11_MODULE(pybind11_tests, m) {
6612391Sjason@lowepower.com    m.doc() = "pybind11 test module";
6711986Sandreas.sandberg@arm.com
6811986Sandreas.sandberg@arm.com    bind_ConstructorStats(m);
6911986Sandreas.sandberg@arm.com
7012391Sjason@lowepower.com#if !defined(NDEBUG)
7112391Sjason@lowepower.com    m.attr("debug_enabled") = true;
7212391Sjason@lowepower.com#else
7312391Sjason@lowepower.com    m.attr("debug_enabled") = false;
7412391Sjason@lowepower.com#endif
7512391Sjason@lowepower.com
7612391Sjason@lowepower.com    py::class_<UserType>(m, "UserType", "A `py::class_` type for testing")
7712391Sjason@lowepower.com        .def(py::init<>())
7812391Sjason@lowepower.com        .def(py::init<int>())
7912391Sjason@lowepower.com        .def("get_value", &UserType::value, "Get value using a method")
8012391Sjason@lowepower.com        .def("set_value", &UserType::set, "Set value using a method")
8112391Sjason@lowepower.com        .def_property("value", &UserType::value, &UserType::set, "Get/set value using a property")
8212391Sjason@lowepower.com        .def("__repr__", [](const UserType& u) { return "UserType({})"_s.format(u.value()); });
8312391Sjason@lowepower.com
8412391Sjason@lowepower.com    py::class_<IncType, UserType>(m, "IncType")
8512391Sjason@lowepower.com        .def(py::init<>())
8612391Sjason@lowepower.com        .def(py::init<int>())
8712391Sjason@lowepower.com        .def("__repr__", [](const IncType& u) { return "IncType({})"_s.format(u.value()); });
8812391Sjason@lowepower.com
8911986Sandreas.sandberg@arm.com    for (const auto &initializer : initializers())
9011986Sandreas.sandberg@arm.com        initializer(m);
9111986Sandreas.sandberg@arm.com
9211986Sandreas.sandberg@arm.com    if (!py::hasattr(m, "have_eigen")) m.attr("have_eigen") = false;
9311986Sandreas.sandberg@arm.com}
94