Skip to content

Instantly share code, notes, and snippets.

@withs
Created May 10, 2022 19:57
Show Gist options
  • Save withs/d1acf170065719924feb37005a21f83b to your computer and use it in GitHub Desktop.
Save withs/d1acf170065719924feb37005a21f83b to your computer and use it in GitHub Desktop.
Create Cxx classes with methods and members In V (poc)
// I have a special case where i need to create and give a c++ class with virtual methods,
// so i came up with this proof of concept.
// Known limitation:
// - accesing class member/methods from "this" is pertty impossible without storing the Cxx struct globaly
// - you can't pass struct methods since the struct ptr will overwrite the real "this" ptr
// use it:
// v -enable-globals -shared vxx.v (work well with autofree and prod)
// g++ vxx_class.cc
// utils fns (those aren't used in the project but they are pretty usefull when working with c++ classes free cool cool code :])
[inline]
pub fn get_virtual(in_this_class voidptr, at_index int) voidptr {
return unsafe { ((*(&&voidptr(in_this_class)))[at_index]) }
}
// v_fn_add := get_virtual(class_ptr, v_fn_idx)(class_ptr, args)
[inline]
fn call_vfunc<T>(from_class voidptr, at_idx int) T {
return T(get_virtual(from_class, at_idx))
}
// v_fn_ret_if_needed := call_vfunc<fn_proto>(class_ptr, v_fn_idx)(class_ptr, args)
// CXX Class implementation
struct CXXClass<T, Y> {
pub mut:
buff []u8 = []u8{len: int(sizeof(usize) + sizeof(Y))}
members &T = 0
methods Y
raw_class_ptr voidptr
}
pub fn new_cxx_class<T, Y>() &CXXClass<T, Y> {
mut cc := &CXXClass<T, Y>{}
unsafe {
*(&usize(cc.buff.data)) = &cc.methods
}
cc.members = &T(usize(cc.buff.data) + sizeof(usize))
cc.raw_class_ptr = cc.buff.data
return cc
}
// tests
[callconv: 'fastcall']
type P_hello = fn (ecx voidptr, edx usize)
[callconv: 'fastcall']
type P_cool = fn (ecx voidptr, edx usize, real_arg int) bool
[callconv: 'fastcall']
fn hello(ecx voidptr, edx usize) {
dump('hello')
}
[callconv: 'fastcall']
fn cool(ecx voidptr, edx usize, real_arg int) bool {
dump('cool -> $real_arg')
return true
}
[callconv: 'fastcall']
fn destructor() {
dump('deconstructed')
}
struct MyClassMethods {
hello P_hello = hello
cool P_cool = cool
pad voidptr = voidptr(0) // needed if destructor is present, and it must be before the destructor
destructor voidptr = destructor
}
struct MyClassMembers {
pub mut:
a int
ab [3]u8
abc &usize = 0
}
__global (
cc = new_cxx_class<MyClassMembers, MyClassMethods>()
)
[export: 'make_vxx']
pub fn make_vxx() voidptr {
cc = new_cxx_class<MyClassMembers, MyClassMethods>()
return cc.raw_class_ptr
}
[export: 'action']
pub fn action() {
cc.members.a = 123_670_667
cc.members.ab = [u8(123), 67, 66]!
cc.members.abc = voidptr(hello)
cc.methods.hello(cc.raw_class_ptr, 0)
}
#include "iostream"
#include <dlfcn.h>
class VxxClass {
public:
int a;
char ab[3];
void* abc;
virtual void hello() = 0;
virtual bool cool(int arg) = 0;
virtual ~VxxClass() = 0;
};
typedef void* (*Make_vxx)();
typedef void (*Action)();
int main(int argc, char const *argv[]) {
void* a = dlopen("vxx.dylib", RTLD_LAZY);
Make_vxx make_vxx = (Make_vxx) dlsym(a, "make_vxx");
Action action = (Action) dlsym(a, "action");
VxxClass* here = (VxxClass*)(make_vxx());
std::cout << here << std::endl;
here->hello();
std::cout << here->cool(123) << '\n';
std::cout << "here->a " << here->a << '\n';
std::cout << "here->ab " << here->ab[0] << " - "<< here->ab[1] << " - " << here->ab[2] << '\n';
std::cout << "here->abc " << here->abc << '\n';
action();
std::cout << "here->a " << here->a << '\n';
std::cout << "here->ab " << here->ab[0] << " - "<< here->ab[1] << " - " << here->ab[2] << '\n';
std::cout << "here->abc " << here->abc << '\n';
delete here;
return 0;
}
@withs
Copy link
Author

withs commented May 10, 2022

result:

fleur@air cpp_classes % g++ vxx_class.cc && ./a.out              
0x600003900030
[vxx.v:62] 'hello': hello
[vxx.v:67] 'cool -> $real_arg': cool -> 0
1
here->a 0
here->ab  -  - 
here->abc 0x0
[vxx.v:62] 'hello': hello
here->a 123670667
here->ab { - C - B
here->abc 0x104b36040
[vxx.v:73] 'deconstructed': deconstructed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment