Use an internal std::string to implement a ring buffer and provide an API producing std::string_view slices. Alternatively, use std::vector<char> and std::span<char>. Don't expose the internal collection type. You can convert to pointer + length slices for FFI.
Conversation
Replying to
You could use a pair of iterators to represent the slice, which is closer to how FFI has to do it anyway.
1
Replying to
right. but then the problem becomes sizing the ring buffer. the caller does not have enough information to make a well informed choice, neither does the callee
1
Replying to
It can produce in between 1 and N bytes of output until it reaches the end of the data though, right? So the caller's choice of size is a latency/memory vs. throughput choice, with diminishing returns for doing larger chunks at the same time.
1
You can make an API like read(stream) where it returns a slice of at least 1 byte and finally signals that it has come to an end. Choose some arbitrary buffer size and let the caller override it when they create the stream. If you really wanted you could do it in parallel.
1
Replying to
hmm. I kind of like the self-sizedness of std::string (the underlying buffer being as large or as small as your flush frequency) but this could make sense
1
Replying to
If you were going to use an interface like a C++ stream, I think you should *provide* one rather than taking one as an argument. It lets you decide to do it in a thread or even a separate process with the buffer in shared memory or even just an OS pipe.
1
Replying to
I mean giving them an input stream rather than taking an output stream. Taking output stream or writing to FILE provided by a caller will be way less efficient because essentially everything will still want buffering but you'll be doing indirect calls and maybe locking per byte.
1
1
It has to be buffered somewhere for efficiency. Seems like the only way to get good performance is doing the buffering yourself if you're going to be getting the output byte by byte.
Taking an output stream / FILE is just a fancy way of taking a function pointer with a write(ptr, size) method with interoperability issues and a lot of baggage. Look at git.musl-libc.org/cgit/musl/tree and git.musl-libc.org/cgit/musl/tree for example. It's not pretty and this is a clean impl.
1
1
Replying to
yeah this totally makes sense. I think I'm going to have the FFI provide a write(ptr,size) function which will be called at will by the simulation (at the beginning, simply after every simulation step) and treat the C++ interface as internal/unstable for now
1
Show replies

