Re: sdl2 and ffi
- Posted by ghaberek (admin) Nov 14, 2022
- 2842 views
Hmm, that'll take some digesting, but my initial thought is that it needs to be as simple as possible to fit the eu ethos, so that someone like me can make stuff with the simpler stuff, and someone like you can do the more brain strangling spaghetti stuff.
so,
rect = allocate(16) allocates a block of memory of 16 bytes poke4(rect,{50,50,100,100}) - poke 4 4-byte integers into memory whose location begins at rect
replace by
create a structure containing the following memory elements
constant C_RECT = define_c_type({ C_LONG, -- left C_LONG, -- top C_LONG, -- right C_LONG -- bottom })\\
then
atom rect = allocate_struct( C_RECT ) --allocate a memory block of the size required to hold the c_type C_RECT poke_type( rect, C_RECT, {50,50,100,100} ) poke type( rect - pointer to where the memory is located C_RECT - the definition of the structure elements {50,50,100,100} - what to poke into each of those memory elements.
Yes that's what I'm going for. I originally called it define_c_type() because that's basically what I want: to define additional C types, be they "int" or "float" or structures and unions. That way we're extending the existing design of define_c_func/proc() and the new structure/union "types" will work there as well, almost transparently.
and you could access that structure in the same way with peek as before
peek4u(rect) (= 50) peek4u(rect + 12) (= 100) peek4u({rect,4}) (= {50,50,100,100} )
You're not wrong; you can certainly do that. But there's a lot of potential for error here, especially with the addition of 64-bit Euphoria and many more peek/poke routines like peek8u() and peek_pointer(). IMHO the ethos of Euphoria is to help reduce this kind of confusion. Why should you have to worry about the size of those structure members?
or is there a newer way to do that too?
That's where peek_type() and poke_type() come in: these routines will handle the nonsense of "is it four or eight bytes? signed? floating-point?" and just dispatch to the correct peek/poke for you, and it will do so correctly based on the platform (not all C_LONG are four bytes).
Then you add define_c_struct to short circuit the above process
constant C_RECT = define_c_struct({ {C_LONG,"left"}, {C_LONG,"top"}, {C_LONG,"right"}, {C_LONG,"bottom"} }, "RECT")
Now we are going to create a block of memory that will allow the above structure to live in it
atom rect = allocate_struct( C_RECT, {50,50,100,100} )which we could still access with
peek4u(rect + 12) (= 100) peek4u({rect,4}) (= {50,50,100,100} )
That's the gist of it. Although minding all of those "+ 12" offsets gets very messy when we have to support 32-bit and 64-bit Intel/AMD architecture, let alone that ARM processors are more common and those could introduce differences as well. Using libffi to help do some of this heavy lifting means we're building on literal decades of experience.
or
? peek_member( rect, "RECT.left" ) -- prints 50 ? peek_member( rect, "RECT" ) -- prints {50,50,100,100}
I can see the advantages, even though it looks more messy to me, and may not be intermediate level concept wise. However, I also like the simpler version, so
define_c_type
allocate structure
is simpler than
define_c_struct
allocate_struct
Both methods produce the same end results, the second method has more frills, which IMHO increase the complexity. It's a shame you have to wrap the definitions in quotes.
This is where feedback helps the most. I'm trying to reduce complexity, not add to it. Is peek_type( ptr, C_TYPE ) or peek_member( ptr, "TYPE.name" ) really more complex than peek4u( ptr + 12 )? and what does 12 mean? it might have to be 16 or 20 on 64-bit, right? who knows! So I'm basically going back to the drawing board on what Matt had original mostly-built for memstruct. He was doing all of these sizes-and-offsets by hand. Plus it seems a bit out of order to implement memstruct now with out a better plan for how classes will work later, since they might utilize a lot of the same type-sniffing code.
If a union is an amalgamation of single items and structures, I take it it would look something like this (in simple form)
C_RECT already defined as above constant C_THING = define_c_union { C_LONG, C_LONG, C_POINTER, C_RECT, --pointer to the C_RECT structure } thing = allocate_union(C_THING)
This is probably where having named members helps the most. Otherwise you're really shooting in the dark with magic numbers. Basically a union lets you perform bit-twiddling by converting a chunk of memory into different types. I don't know about you but to me, remembering what something like peek_type( ptr, C_THING, 1 ) does is going to be hard if not impossible.
Just my confused thoughts.
I think you're doing great, Chris.
-Greg