example.cpp
1 // example.cpp 2 // nanobind example: C++ functions callable from Python 3 // 4 // This demonstrates the pattern for Python/C++ interop: 5 // - Write performance-critical code in C++ 6 // - Expose via nanobind bindings 7 // - Call from Python with zero-copy where possible 8 9 #include <nanobind/nanobind.h> 10 #include <nanobind/stl/string.h> 11 #include <nanobind/stl/vector.h> 12 13 #include <cmath> 14 #include <numeric> 15 #include <string> 16 #include <vector> 17 18 namespace nb = nanobind; 19 20 // ============================================================================= 21 // Pure C++ functions (the actual implementation) 22 // ============================================================================= 23 24 namespace aleph { 25 26 // Simple function: add two numbers 27 int add(int a, int b) { return a + b; } 28 29 // String manipulation 30 std::string greet(const std::string &name) { 31 return "Hello from aleph, " + name + "!"; 32 } 33 34 // Vector operations (demonstrates zero-copy potential) 35 double dot_product(const std::vector<double> &a, const std::vector<double> &b) { 36 if (a.size() != b.size()) { 37 throw std::runtime_error("Vector sizes must match"); 38 } 39 return std::inner_product(a.begin(), a.end(), b.begin(), 0.0); 40 } 41 42 // Compute norm 43 double norm(const std::vector<double> &v) { 44 return std::sqrt(dot_product(v, v)); 45 } 46 47 // A simple class 48 class Counter { 49 public: 50 Counter(int initial = 0) : value_(initial) {} 51 52 void increment() { ++value_; } 53 void decrement() { --value_; } 54 void add(int n) { value_ += n; } 55 int get() const { return value_; } 56 void reset() { value_ = 0; } 57 58 std::string repr() const { return "Counter(" + std::to_string(value_) + ")"; } 59 60 private: 61 int value_; 62 }; 63 64 } // namespace aleph 65 66 // ============================================================================= 67 // nanobind module definition 68 // ============================================================================= 69 70 NB_MODULE(example, m) { 71 m.doc() = "aleph example module: C++ called from Python via nanobind"; 72 73 // Simple functions 74 m.def("add", &aleph::add, "Add two integers", nb::arg("a"), nb::arg("b")); 75 76 m.def("greet", &aleph::greet, "Generate a greeting", nb::arg("name")); 77 78 // Vector functions 79 m.def("dot_product", &aleph::dot_product, 80 "Compute dot product of two vectors", nb::arg("a"), nb::arg("b")); 81 82 m.def("norm", &aleph::norm, "Compute Euclidean norm of a vector", 83 nb::arg("v")); 84 85 // Class binding 86 nb::class_<aleph::Counter>(m, "Counter") 87 .def(nb::init<int>(), nb::arg("initial") = 0) 88 .def("increment", &aleph::Counter::increment) 89 .def("decrement", &aleph::Counter::decrement) 90 .def("add", &aleph::Counter::add, nb::arg("n")) 91 .def("get", &aleph::Counter::get) 92 .def("reset", &aleph::Counter::reset) 93 .def("__repr__", &aleph::Counter::repr); 94 95 // Module-level test function (called by buck2 run) 96 m.def("test", []() { 97 // Run some basic tests 98 bool ok = true; 99 100 // Test add 101 if (aleph::add(2, 3) != 5) { 102 ok = false; 103 } 104 105 // Test dot product 106 std::vector<double> a = {1.0, 2.0, 3.0}; 107 std::vector<double> b = {4.0, 5.0, 6.0}; 108 double expected = 32.0; // 1*4 + 2*5 + 3*6 109 if (std::abs(aleph::dot_product(a, b) - expected) > 1e-10) { 110 ok = false; 111 } 112 113 // Test Counter 114 aleph::Counter c(10); 115 c.increment(); 116 if (c.get() != 11) { 117 ok = false; 118 } 119 120 if (ok) { 121 nb::print("example module: all tests passed"); 122 } else { 123 nb::print("example module: TESTS FAILED"); 124 } 125 }); 126 }