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) { 19 return a + b; 20 } 21 22 extern "C" int32_t ffi_multiply(int32_t a, int32_t b) { 23 return a * b; 24 } 25 26 // ============================================================================= 27 // Vector operations 28 // ============================================================================= 29 30 extern "C" double ffi_dot_product(const double* a, const double* b, size_t len) { 31 double result = 0.0; 32 for (size_t i = 0; i < len; ++i) { 33 result += a[i] * b[i]; 34 } 35 return result; 36 } 37 38 extern "C" double ffi_norm(const double* v, size_t len) { 39 return std::sqrt(ffi_dot_product(v, v, len)); 40 } 41 42 extern "C" void ffi_scale(double* v, size_t len, double scalar) { 43 for (size_t i = 0; i < len; ++i) { 44 v[i] *= scalar; 45 } 46 } 47 48 // ============================================================================= 49 // String operations 50 // ============================================================================= 51 52 extern "C" char* ffi_greet(const char* name) { 53 std::string greeting = "Hello from C++, " + std::string(name) + "!"; 54 55 // Allocate with malloc so Haskell can free with ffi_free_string 56 char* result = static_cast<char*>(std::malloc(greeting.size() + 1)); 57 if (result) { 58 std::strcpy(result, greeting.c_str()); 59 } 60 return result; 61 } 62 63 extern "C" void ffi_free_string(char* str) { 64 std::free(str); 65 } 66 67 // ============================================================================= 68 // Counter (opaque handle pattern) 69 // ============================================================================= 70 71 // C++ class behind the opaque handle 72 class CounterImpl { 73 public: 74 explicit CounterImpl(int32_t initial) : value_(initial) {} 75 76 int32_t get() const { return value_; } 77 int32_t increment() { return ++value_; } 78 int32_t add(int32_t n) { 79 value_ += n; 80 return value_; 81 } 82 83 private: 84 int32_t value_; 85 }; 86 87 // The Counter struct is just an alias for the C++ class 88 struct Counter : public CounterImpl { 89 using CounterImpl::CounterImpl; 90 }; 91 92 extern "C" Counter* ffi_counter_new(int32_t initial) { 93 return new Counter(initial); // NOLINT(aleph-cpp-raw-new-delete) 94 } 95 96 // NOLINTNEXTLINE(aleph-cpp-raw-new-delete) 97 extern "C" void ffi_counter_free(Counter* counter) { 98 delete counter; 99 } 100 101 extern "C" int32_t ffi_counter_get(const Counter* counter) { 102 return counter->get(); 103 } 104 105 extern "C" int32_t ffi_counter_increment(Counter* counter) { 106 return counter->increment(); 107 } 108 109 extern "C" int32_t ffi_counter_add(Counter* counter, int32_t n) { 110 return counter->add(n); 111 }