Skip to content

Commit 28a5602

Browse files
committed
Mega-commit for cherry-picking ease. Fix joint C++/python object handling, ensure __str__ takes no parameters, test to_string methods
1 parent 72ba84f commit 28a5602

30 files changed

+117
-49
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ execute_process(
7474
list(APPEND CMAKE_PREFIX_PATH "${NB_DIR}")
7575
find_package(nanobind CONFIG REQUIRED)
7676

77-
nanobind_add_module(python MODULE LTO STABLE_ABI NB_STATIC)
77+
nanobind_add_module(python MODULE LTO NOMINSIZE STABLE_ABI NB_STATIC)
7878

7979
set_target_properties(python PROPERTIES
8080
PREFIX ""

include/kernel_function.hpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
#include <nanobind/nanobind.h>
2121
#include <nanobind/trampoline.h>
2222
#include <nanobind/ndarray.h>
23-
#include <nanobind/stl/shared_ptr.h>
23+
#include <nanobind/intrusive/counter.h>
24+
#include <nanobind/intrusive/ref.h>
2425
#include <nanobind/stl/vector.h>
2526

2627
#include <numpy/arrayobject.h>
@@ -37,7 +38,7 @@ namespace datasketches {
3738
* which native Python kernels ultimately inherit. The actual
3839
* kernels implement KernelFunction, as shown in KernelFunction.py
3940
*/
40-
struct kernel_function {
41+
struct kernel_function : public nb::intrusive_base {
4142
virtual double operator()(nb::handle& a, nb::handle& b) const = 0;
4243
virtual ~kernel_function() = default;
4344
};
@@ -71,7 +72,7 @@ struct KernelFunction : public kernel_function {
7172
* never need to use this directly.
7273
*/
7374
struct kernel_function_holder {
74-
explicit kernel_function_holder(std::shared_ptr<kernel_function> kernel) : _kernel(kernel) {}
75+
explicit kernel_function_holder(kernel_function* kernel) : _kernel(kernel) {}
7576
kernel_function_holder(const kernel_function_holder& other) : _kernel(other._kernel) {}
7677
kernel_function_holder(kernel_function_holder&& other) : _kernel(std::move(other._kernel)) {}
7778
kernel_function_holder& operator=(const kernel_function_holder& other) { _kernel = other._kernel; return *this; }
@@ -99,7 +100,7 @@ struct kernel_function_holder {
99100
}
100101

101102
private:
102-
std::shared_ptr<kernel_function> _kernel;
103+
nb::ref<kernel_function> _kernel;
103104
};
104105

105106
}

include/tuple_policy.hpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#include <memory>
2121
#include <nanobind/nanobind.h>
2222
#include <nanobind/trampoline.h>
23+
#include <nanobind/intrusive/counter.h>
24+
#include <nanobind/intrusive/ref.h>
2325

2426
#ifndef _TUPLE_POLICY_HPP_
2527
#define _TUPLE_POLICY_HPP_
@@ -33,10 +35,10 @@ namespace datasketches {
3335
* which native Python policies ultimately inherit. The actual
3436
* policies implement TuplePolicy, as shown in TuplePolicy.py
3537
*/
36-
struct tuple_policy {
37-
virtual nb::object create_summary() = 0;
38-
virtual nb::object update_summary(nb::object& summary, const nb::object& update) = 0;
39-
virtual nb::object operator()(nb::object& summary, const nb::object& update) = 0;
38+
struct tuple_policy : public nb::intrusive_base {
39+
virtual nb::object create_summary() const = 0;
40+
virtual nb::object update_summary(nb::object& summary, const nb::object& update) const = 0;
41+
virtual nb::object operator()(nb::object& summary, const nb::object& update) const = 0;
4042
virtual ~tuple_policy() = default;
4143
};
4244

@@ -53,7 +55,7 @@ struct TuplePolicy : public tuple_policy {
5355
*
5456
* @return nb::object representing a new summary
5557
*/
56-
nb::object create_summary() override {
58+
nb::object create_summary() const override {
5759
NB_OVERRIDE_PURE(
5860
create_summary, // Name of function in C++ (must match Python name)
5961
// Argument(s) -- if any
@@ -67,7 +69,7 @@ struct TuplePolicy : public tuple_policy {
6769
* @param update The new value with which to update the summary
6870
* @return nb::object The updated summary
6971
*/
70-
nb::object update_summary(nb::object& summary, const nb::object& update) override {
72+
nb::object update_summary(nb::object& summary, const nb::object& update) const override {
7173
NB_OVERRIDE_PURE(
7274
update_summary, // Name of function in C++ (must match Python name)
7375
summary, update // Arguments
@@ -81,7 +83,7 @@ struct TuplePolicy : public tuple_policy {
8183
* @param update An update to apply to the current summary
8284
* @return nb::object The potentially modified summary
8385
*/
84-
nb::object operator()(nb::object& summary, const nb::object& update) override {
86+
nb::object operator()(nb::object& summary, const nb::object& update) const override {
8587
NB_OVERRIDE_PURE_NAME(
8688
"__call__", // Name of function in python
8789
operator(), // Name of function in C++
@@ -96,7 +98,7 @@ struct TuplePolicy : public tuple_policy {
9698
* never need to use this directly.
9799
*/
98100
struct tuple_policy_holder {
99-
explicit tuple_policy_holder(std::shared_ptr<tuple_policy> policy) : _policy(policy) {}
101+
explicit tuple_policy_holder(tuple_policy* policy) : _policy(policy) {}
100102
tuple_policy_holder(const tuple_policy_holder& other) : _policy(other._policy) {}
101103
tuple_policy_holder(tuple_policy_holder&& other) : _policy(std::move(other._policy)) {}
102104
tuple_policy_holder& operator=(const tuple_policy_holder& other) { _policy = other._policy; return *this; }
@@ -113,7 +115,7 @@ struct tuple_policy_holder {
113115
}
114116

115117
private:
116-
std::shared_ptr<tuple_policy> _policy;
118+
nb::ref<tuple_policy> _policy;
117119
};
118120

119121
/* A degenerate policy used to enable Jaccard Similarity on tuple sketches,

src/count_wrapper.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ void bind_count_min_sketch(nb::module_ &m, const char* name) {
5050
"with 95% confidence, frequency estimates satisfy the 'relative_error' guarantee. "
5151
"Returns the number of hash functions that are required in order to achieve the specified "
5252
"confidence of the sketch. confidence = 1 - delta, with delta denoting the sketch failure probability.")
53-
.def("__str__", &count_min_sketch<W>::to_string,
53+
.def("__str__", [](const count_min_sketch<W>& sk) { return sk.to_string(); },
5454
"Produces a string summary of the sketch")
5555
.def("to_string", &count_min_sketch<W>::to_string,
5656
"Produces a string summary of the sketch")

src/cpc_wrapper.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ void init_cpc(nb::module_ &m) {
3939
":type seed: int, optional"
4040
)
4141
.def("__copy__", [](const cpc_sketch& sk){ return cpc_sketch(sk); })
42-
.def("__str__", &cpc_sketch::to_string,
42+
.def("__str__", [](const cpc_sketch& sk) { return sk.to_string(); },
4343
"Produces a string summary of the sketch")
4444
.def("to_string", &cpc_sketch::to_string,
4545
"Produces a string summary of the sketch")

src/datasketches.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@
1818
*/
1919

2020
#include <nanobind/nanobind.h>
21+
#include <nanobind/intrusive/counter.h>
22+
23+
// needed for sketches such as Density and Tuple which rely
24+
// on a joint C++/Python object
25+
#include <nanobind/intrusive/counter.inl>
2126

2227
namespace nb = nanobind;
2328

@@ -41,6 +46,18 @@ void init_kolmogorov_smirnov(nb::module_& m);
4146
void init_serde(nb::module_& m);
4247

4348
NB_MODULE(_datasketches, m) {
49+
// needed in conjunction with the counter.inl include above
50+
nb::intrusive_init(
51+
[](PyObject *o) noexcept {
52+
nb::gil_scoped_acquire guard;
53+
Py_INCREF(o);
54+
},
55+
[](PyObject *o) noexcept {
56+
nb::gil_scoped_acquire guard;
57+
Py_DECREF(o);
58+
}
59+
);
60+
4461
init_hll(m);
4562
init_kll(m);
4663
init_fi(m);

src/density_wrapper.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
#include <vector>
2121
#include <memory>
2222
#include <nanobind/nanobind.h>
23-
#include <nanobind/stl/shared_ptr.h>
23+
#include <nanobind/intrusive/counter.h>
24+
#include <nanobind/stl/string.h>
2425
#include <nanobind/stl/vector.h>
2526
#include <nanobind/make_iterator.h>
2627

@@ -38,7 +39,7 @@ void bind_density_sketch(nb::module_ &m, const char* name) {
3839
using namespace datasketches;
3940

4041
nb::class_<density_sketch<T, K>>(m, name)
41-
.def("__init__", [](density_sketch<T, K>* sk, uint16_t k, uint32_t dim, std::shared_ptr<kernel_function> kernel)
42+
.def("__init__", [](density_sketch<T, K>* sk, uint16_t k, uint32_t dim, kernel_function* kernel)
4243
{ K holder(kernel);
4344
new (sk) density_sketch<T, K>(k, dim, holder);
4445
},
@@ -67,7 +68,7 @@ void bind_density_sketch(nb::module_ &m, const char* name) {
6768
"Returns True if the sketch is in estimation mode, otherwise False")
6869
.def("get_estimate", &density_sketch<T, K>::get_estimate, nb::arg("point"),
6970
"Returns an approximate density at the given point")
70-
.def("__str__", &density_sketch<T, K>::to_string, nb::arg("print_levels")=false, nb::arg("print_items")=false,
71+
.def("__str__", [](const density_sketch<T, K>& sk) { return sk.to_string(); },
7172
"Produces a string summary of the sketch")
7273
.def("to_string", &density_sketch<T, K>::to_string, nb::arg("print_levels")=false, nb::arg("print_items")=false,
7374
"Produces a string summary of the sketch")
@@ -87,7 +88,7 @@ void bind_density_sketch(nb::module_ &m, const char* name) {
8788
)
8889
.def_static(
8990
"deserialize",
90-
[](const nb::bytes& bytes, std::shared_ptr<kernel_function> kernel) {
91+
[](const nb::bytes& bytes, kernel_function* kernel) {
9192
K holder(kernel);
9293
return density_sketch<T, K>::deserialize(bytes.c_str(), bytes.size(), holder);
9394
},
@@ -108,6 +109,8 @@ void init_density(nb::module_ &m) {
108109

109110
// generic kernel function
110111
nb::class_<kernel_function, KernelFunction>(m, "KernelFunction",
112+
nb::intrusive_ptr<kernel_function>(
113+
[](kernel_function *kf, PyObject *po) noexcept { kf->set_self_py(po); }),
111114
"A generic base class from which user-defined kernels must inherit.")
112115
.def(nb::init())
113116
.def("__call__", &kernel_function::operator(), nb::arg("a"), nb::arg("b"),

src/ebpps_wrapper.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ void bind_ebpps_sketch(nb::module_ &m, const char* name) {
3939
":param k: Maximum number of samples in the sketch\n:type k: int\n"
4040
)
4141
.def("__copy__", [](const ebpps_sketch<T>& sk){ return ebpps_sketch<T>(sk); })
42-
.def("__str__", &ebpps_sketch<T>::to_string,
42+
.def("__str__", [](const ebpps_sketch<T>& sk) { return sk.to_string(); },
4343
"Produces a string summary of the sketch")
4444
.def("to_string",
4545
[](const ebpps_sketch<T>& sk, bool print_items) {

src/fi_wrapper.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ void bind_fi_sketch(nb::module_ &m, const char* name) {
5252
":type lg_max_k: int\n"
5353
)
5454
.def("__copy__", [](const frequent_items_sketch<T, W, H, E>& sk){ return frequent_items_sketch<T,W,H,E>(sk); })
55-
.def("__str__", &frequent_items_sketch<T, W, H, E>::to_string, nb::arg("print_items")=false,
55+
.def("__str__", [](const frequent_items_sketch<T, W, H, E>& sk) { return sk.to_string(); },
5656
"Produces a string summary of the sketch")
5757
.def("to_string", &frequent_items_sketch<T, W, H, E>::to_string, nb::arg("print_items")=false,
5858
"Produces a string summary of the sketch")

src/hll_wrapper.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ void init_hll(nb::module_ &m) {
4444
"HLL_8) at the cost of much higher initial memory use. Default (and recommended) is False.\n"
4545
":type start_full_size: bool"
4646
)
47-
.def("__str__", (std::string (hll_sketch::*)(bool,bool,bool,bool) const) &hll_sketch::to_string,
47+
.def("__str__", [](const hll_sketch& sk) { return sk.to_string(); },
4848
"Produces a string summary of the sketch")
4949
.def("to_string", (std::string (hll_sketch::*)(bool,bool,bool,bool) const) &hll_sketch::to_string,
5050
nb::arg("summary")=true, nb::arg("detail")=false, nb::arg("aux_detail")=false, nb::arg("all")=false,

0 commit comments

Comments
 (0)