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