Skip to content

Commit

Permalink
Support read/write to structs originating in C
Browse files Browse the repository at this point in the history
  • Loading branch information
czgdp1807 committed Jan 19, 2023
1 parent 23311c7 commit 701716f
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 1 deletion.
2 changes: 2 additions & 0 deletions integration_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,8 @@ RUN(NAME structs_16 LABELS cpython llvm c)
RUN(NAME structs_17 LABELS cpython llvm c)
RUN(NAME structs_18 LABELS llvm c
EXTRAFILES structs_18b.c)
RUN(NAME structs_19 LABELS cpython llvm c
EXTRAFILES structs_19b.c)
RUN(NAME sizeof_01 LABELS llvm c
EXTRAFILES sizeof_01b.c)
RUN(NAME enum_01 LABELS cpython llvm c)
Expand Down
70 changes: 70 additions & 0 deletions integration_tests/structs_19.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
from ltypes import (i8, dataclass, i32, f32, c32, f64, i16, i64, c64,
ccall, CPtr, c_p_pointer, Pointer)

@dataclass
class buffer_struct:
buffer8: i8
buffer1: i32
buffer2: f32
buffer3: c32
buffer4: f64
buffer5: i16
buffer6: i64
buffer7: c64

@ccall
def get_buffer() -> CPtr:
pass

@ccall
def fill_buffer(buffer_cptr: CPtr):
pass

def f():
b: CPtr = get_buffer()
pb: Pointer[buffer_struct] = c_p_pointer(b, buffer_struct)
pb.buffer8 = i8(3)
pb.buffer1 = i32(4)
pb.buffer2 = f32(5)
pb.buffer3 = c32(9)
pb.buffer4 = f64(6)
pb.buffer5 = i16(7)
pb.buffer6 = i64(8)
pb.buffer7 = c64(10)
print(pb.buffer8)
print(pb.buffer1)
print(pb.buffer2)
print(pb.buffer3)
print(pb.buffer4)
print(pb.buffer5)
print(pb.buffer6)
print(pb.buffer7)
assert pb.buffer8 == i8(3)
assert pb.buffer1 == i32(4)
assert pb.buffer2 == f32(5)
assert pb.buffer3 == c32(9)
assert pb.buffer4 == f64(6)
assert pb.buffer5 == i16(7)
assert pb.buffer6 == i64(8)
assert pb.buffer7 == c64(10)

fill_buffer(b)
print(pb.buffer8)
print(pb.buffer1)
print(pb.buffer2)
print(pb.buffer3)
print(pb.buffer4)
print(pb.buffer5)
print(pb.buffer6)
print(pb.buffer7)
assert pb.buffer8 == i8(8)
assert pb.buffer1 == i32(9)
assert pb.buffer2 == f32(10)
assert pb.buffer3 == c32(14) + c32(15j)
assert pb.buffer4 == f64(11)
assert pb.buffer5 == i16(12)
assert pb.buffer6 == i64(13)
assert pb.buffer7 == c64(16) + c64(17j)


f()
31 changes: 31 additions & 0 deletions integration_tests/structs_19b.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include <stdlib.h>
#include <complex.h>
#include "structs_19b.h"


struct buffer_c {
int8_t buffer8;
int32_t buffer1;
float buffer2;
float complex buffer3;
double buffer4;
int16_t buffer5;
int64_t buffer6;
double complex buffer7;
};

void fill_buffer(void* buffer_cptr) {
struct buffer_c* buffer_clink_ = (struct buffer_c*) buffer_cptr;
buffer_clink_->buffer8 = 8;
buffer_clink_->buffer1 = 9;
buffer_clink_->buffer2 = 10.0;
buffer_clink_->buffer3 = CMPLXF(14.0, 15.0);
buffer_clink_->buffer4 = 11.0;
buffer_clink_->buffer5 = 12;
buffer_clink_->buffer6 = 13;
buffer_clink_->buffer7 = CMPLXL(16.0, 17.0);
}

void* get_buffer() {
return malloc(sizeof(struct buffer_c));
}
4 changes: 4 additions & 0 deletions integration_tests/structs_19b.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#include <inttypes.h>

void fill_buffer(void* buffer_cptr);
void* get_buffer();
26 changes: 25 additions & 1 deletion src/runtime/ltypes/ltypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ def inner_func():

# C interoperation support

class c_float_complex(ctypes.Structure):
_fields_ = [("real", ctypes.c_float), ("imag", ctypes.c_float)]

class c_double_complex(ctypes.Structure):
_fields_ = [("real", ctypes.c_double), ("imag", ctypes.c_double)]

def convert_type_to_ctype(arg):
if arg == f64:
return ctypes.c_double
Expand All @@ -172,6 +178,10 @@ def convert_type_to_ctype(arg):
return ctypes.c_void_p
elif arg == str:
return ctypes.c_char_p
elif arg == c32:
return c_float_complex
elif arg == c64:
return c_double_complex
elif arg is None:
raise NotImplementedError("Type cannot be None")
elif isinstance(arg, Array):
Expand Down Expand Up @@ -328,9 +338,23 @@ def __init__(self, ctypes_ptr_):
def __getattr__(self, name: str):
if name == "ctypes_ptr":
return self.__dict__[name]
return self.ctypes_ptr.contents.__getattribute__(name)
value = self.ctypes_ptr.contents.__getattribute__(name)
if isinstance(value, (c_float_complex, c_double_complex)):
value = complex(value.real, value.imag)
return value

def __setattr__(self, name: str, value):
name_ = self.ctypes_ptr.contents.__getattribute__(name)
if isinstance(value, complex):
if isinstance(name_, c_float_complex):
value = c_float_complex(value.real, value.imag)
elif isinstance(name_, c_double_complex):
value = c_double_complex(value.real, value.imag)
else:
if isinstance(name_, c_float_complex):
value = c_float_complex(value.real, 0.0)
elif isinstance(name_, c_double_complex):
value = c_double_complex(value.real, 0.0)
self.ctypes_ptr.contents.__setattr__(name, value)

def c_p_pointer(cptr, targettype):
Expand Down

0 comments on commit 701716f

Please sign in to comment.