I really need your feedback about one thing that I want to code. It requires a bit of work, and I would like to hear your opinions to avoid wasting some efforts.
I wanted to get rid of the C99 variable length syntax. I already wrote a stub and I know how to do it, but to do this correctly I need to change a bit the memory management of
obj_reader_t::load. In practice, I want to get rid of
manual allocations using
new, replacing them with RAII approaches like
std::unique_ptr. Obviously I am quite new with simutrans codebase, and it took me some attempts to find a valid and coherent approach, but I should be there.
Now, my point is that I wanted to perform the memory management change patch, and then the other one for VLAs. Unfortunately, it looks like that GCC stopped allowing me to use C99 VLAs after some C++11 changes, therefore I need to write a single bigger patch :(. I would like your feedback because it is a bit of work, and maybe there are different possible approaches for the problem. I will show my idea, so you can give me your feedbacks.
I want to write a templated class that is responsible for RAII allocation and construction, something like
std::unique_ptr. The main difference is that this will allow to have "tail" variable length array of data. Let's call the class "Vla", the idea was something like the following:
template</* gimme a sec about this */ T, typename Tail, typename TailSizeT = std::size_t>
class Vla {
template <typename... Args>
explicit Vla(TailSizeT tail_size, Args && ... args);
};
As I said,
Vla will be responsible of allocating our type... or a sort of. In practice, we need to access the data in the "tail", and I wanted to avoid useless boilerplate, and at the same time I want zero overhead. Therefore, my idea is to create a helper class to allow easy managing of the VLA-related data, and to use CRTP to have static inheritance. In the previous example,
T would be a
template <typename> class TThe following example struct
struct legacy_data_t {
double d;
int i;
unsigned short data_size;
char data[];
};
would become something like
template <typename V>
struct new_data_base_t {
double d;
int i;
};
using new_data_t = Vla<new_data_base_t, char, unsigned short>;
You can imagine that
Vla will have an API very similar to
std::unique_ptr, but instead of returning a pointer to a
new_data_base_t (it can't, it is a templated class!

), it will give back a pointer to a VlaWrapper, something like
template <template <typename> class T, typename Tail, typename SizeTailT>
struct VlaWrapper final : T<VlaWrapper<T, Tail, TailSizeT>> {
template <typename... Args>
VlaWrapper(TailSizeT tail_size, Args && ... args) :
T(std::forward<Args>(args)...), _tail_size(tail_size)
{}
private:
TailSizeT _tail_size;
};
Believe it or not, the implementation is a bit more complex than this, but the idea is that, using the wrapper, I can use my class (
new_data_base_t in this case) and I also have the features to access VLA data. Unfortunately, the struct I want to create must be changed, but on the other hand there is no need for manual memory management.
Going further,
Vla needs to be owned in order to work. I designed a way to create a collection of
Vlas inside
obj_reader_t::load, which is passed downstream in order to allocate new objects and point to them. This changes the concepts a bit, because new the allocations are performed on the children, with this approach the children will just point to the "arena" of allocations. I already studied how xrefs are handled (they are the major cause of my attempts

), I know how to handle the thing (if I looked wherever I needed to, hopefully

). This new approach will address the problem of "memory responsibility" (it will be based on RAII, storing the handlers inside a container), the only downside is that the container itself is an overhead. I was thinking about
std::deque, which preserves references validity and it has smaller memory overhead than
std::forward_list. I think that the impact of the container will be minimal, but I also want to hear your opinion.
At this point, I think that you understood why I am sharing this idea before diving into the code. I wanted to start smaller, but I started feeling itchy because of these VLAs, and I would really like to get rid of them. Maybe you guys disagree with my approach, maybe you have better ideas. In any case, I think that your opinion is very important in this case, I am not talking about "just smashing 'override's around" this time

. And I am really using C++11 features for this thing, so it is quite important in this case

Let me know what you think.
P.s.: there are a few things I want to discuss about
Vla and
VlaWrapper APIs, but for now it is better to talk about the general idea.