ffi.cpp
1 // ffi.cpp 2 // C++ implementation of FFI functions for Haskell 3 // 4 // This demonstrates calling C++ from Haskell via the FFI. 5 // All exported functions use extern "C" linkage for ABI compatibility. 6 7 #include "ffi.h" 8 9 #include <cmath> 10 #include <cstring> 11 #include <numeric> 12 #include <string> 13 14 // ============================================================================= 15 // Simple arithmetic 16 // ============================================================================= 17 18 extern "C" int32_t ffi_add(int32_t a, int32_t b) { return a + b; } 19 20 extern "C" int32_t ffi_multiply(int32_t a, int32_t b) { return a * b; } 21 22 // ============================================================================= 23 // Vector operations 24 // ============================================================================= 25 26 extern "C" double ffi_dot_product(const double *a, const double *b, 27 size_t len) { 28 double result = 0.0; 29 for (size_t i = 0; i < len; ++i) { 30 result += a[i] * b[i]; 31 } 32 return result; 33 } 34 35 extern "C" double ffi_norm(const double *v, size_t len) { 36 return std::sqrt(ffi_dot_product(v, v, len)); 37 } 38 39 extern "C" void ffi_scale(double *v, size_t len, double scalar) { 40 for (size_t i = 0; i < len; ++i) { 41 v[i] *= scalar; 42 } 43 } 44 45 // ============================================================================= 46 // String operations 47 // ============================================================================= 48 49 extern "C" char *ffi_greet(const char *name) { 50 std::string greeting = "Hello from C++, " + std::string(name) + "!"; 51 52 // Allocate with malloc so Haskell can free with ffi_free_string 53 char *result = static_cast<char *>(std::malloc(greeting.size() + 1)); 54 if (result) { 55 std::strcpy(result, greeting.c_str()); 56 } 57 return result; 58 } 59 60 extern "C" void ffi_free_string(char *str) { std::free(str); } 61 62 // ============================================================================= 63 // Counter (opaque handle pattern) 64 // ============================================================================= 65 66 // C++ class behind the opaque handle 67 class CounterImpl { 68 public: 69 explicit CounterImpl(int32_t initial) : value_(initial) {} 70 71 int32_t get() const { return value_; } 72 int32_t increment() { return ++value_; } 73 int32_t add(int32_t n) { 74 value_ += n; 75 return value_; 76 } 77 78 private: 79 int32_t value_; 80 }; 81 82 // The Counter struct is just an alias for the C++ class 83 struct Counter : public CounterImpl { 84 using CounterImpl::CounterImpl; 85 }; 86 87 extern "C" Counter *ffi_counter_new(int32_t initial) { 88 return new Counter(initial); // NOLINT(aleph-cpp-raw-new-delete) 89 } 90 91 // NOLINTNEXTLINE(aleph-cpp-raw-new-delete) 92 extern "C" void ffi_counter_free(Counter *counter) { delete counter; } 93 94 extern "C" int32_t ffi_counter_get(const Counter *counter) { 95 return counter->get(); 96 } 97 98 extern "C" int32_t ffi_counter_increment(Counter *counter) { 99 return counter->increment(); 100 } 101 102 extern "C" int32_t ffi_counter_add(Counter *counter, int32_t n) { 103 return counter->add(n); 104 }