dvidelabs / flatcc

FlatBuffers Compiler and Library in C for C
Apache License 2.0
646 stars 182 forks source link

Any docs regarding usage of bool and bool vectors? #279

Closed non-descriptive closed 3 months ago

non-descriptive commented 4 months ago

I didn't find any examples or docs how to use boolean values and push them into boolean vectors. Orc example has deprecated field as bool, but no other kinds. I have a field in my struct of bool vector:

table MyStruct {
  bools: [bool];
  ints: [int];
}

and I tried different kinds of pushing values into it

flatcc_builder_t builder;
flatcc_builder_t* B = &builder;
flatcc_builder_init(B);

ns(MyStruct_start_as_root(B));
ns(MyStruct_bools_start(B));
ns(MyStruct_ints_start(B));

 // Warning from compiler:  makes pointer from integer without a cast
ns(MyStruct_bools_push(B, true));

// Warning: incompatible pointers 'const flatbuffers_bool_t*' and 'const _Bool*'
const bool data = true;
ns(MyStruct_bools_push(B, &data));  

// this compiles silently
const flatbuffers_bool_t data = flatbuffers_true;
ns(MyStruct_bools_push(B, &data)); 

ns(MyStruct_bools_end(B));
ns(MyStruct_ints_end(B));
ns(MyStruct_end_as_root(B));

size_t size;
void  *data = flatcc_builder_finalize_buffer(B, &size);
// the rest

And none of those methods affect final buffer at all. So how to work with booleans. Are they broken and I should use short integer types instead?

mikkelfj commented 4 months ago

So I don't recall all details and therefore my reply might not be 100% accurate, but I can dig into it more if necessary.

Booleans are just single byte integers as I recall, valued 0 or 1. const bool is not a valid type for flatcc. It is also documented. The reason is that bool has not well defined size. flatbuffers_bool_t or flatbuffers_boolean_t or something like that is the correct type and it is probably a typedef to uint8_t.

I think you are tripping over the interface moire than specifically booleans. I suggest getting it to work with regular ints first.

In your example you start the ints vector instead of the bools vector, so you should not be using MyStruct_bools_push. You do start bools, but you can only operate on the most recently opened vector so either close ints first or push before starting ints. Note that flatcc is unique in this respect, other languages would required you to create the vector before even starting the table.

It is likely that you do not get an error for the above, possibly unless running in debug mode.

The next problem is that you push an array using &data, so not only are you referring to the wrong fundamental type, but you are also specifying a pointer instead of an integer value. This is likely the error that you get, but not the first that you make.

Push operates on single elements (generally, but there are many options). The good thing is that if you have a native bool array in C, e.g. data as in your example, and you can largely rely on C's type coercion using Mystructs_bools_push(data[0]), or Mystucts_bools_push((flatbutters_bool_t)data[0]).

You can also create the entire vector at once, and it is often more efficient. Something like MyStruct_bools_create(&data, count), but this requires data to have the correct type, and it cannot be while the ints array or the bools array has been started. Crate replaces a start, multiple push, and end operations, and can often bypass temporary storage.

Hope this helps

non-descriptive commented 4 months ago

so if I want to put something out of order I can open vector (start) push things, close it and and open again later? the docs were kinda poor and examples are too simple, it's hard to understand how to use api correctly, what methods are generated and when to use them. if there is more info about those things would be glad to receive directions.

mikkelfj commented 4 months ago

I suggest trying out the monster example from the google flatbuffer project. It is also in flatcc samples, but it is documented on googles site. Note however, that each language has its own way an there is C specific documentation there.

As to your question: Once you have ended a vector you cannot start it again, but you can start it, push to it, then start something else that is relevant in that context, such as creating things you would push onto that vector, like strings or sub tables, you can then resume pushing once the child elements are done.

You might also be able to start another vector at the same level like you did, with ints and bools, but that is not guaranteed. You can create the vectors alright, but when you start a vector that is a started as a member of table, extra information is stored to keep record, and this might get confused, not sure. Addibng a vector to a table is multiple steps: start the vector, push elements, end the vector, get the vectors "handle" or buffer offset, then add that handle as a member of a table. An operation like Mystruct_bools_start/end combines multiple such steps into fewer operations, but that is just for convenience. BTW Mystructs is not a good name here because structs are different from tables.

As to documentation, it is a huge effort, and contrubutions would be welcome, but most people seem to find their way around regardless. It is worth noting that not matter what, the first two days are difficult because the concepts need to click, and after that there is a system to it that makes it relatively easy.

mikkelfj commented 4 months ago

https://flatbuffers.dev/flatbuffers_guide_tutorial.html click in the C option at the top.

https://github.com/dvidelabs/flatcc/tree/master/samples/monster