Implementing a Struct of Arrays

https://news.ycombinator.com/rss Hits: 9
Summary

Recently, I watched Andrew Kelley’s talk on Practical Data Oriented Design. It goes into some of the architectural changes he’s been making to the Zig compiler, with pretty significant performance benefit. Would definitely recommend checking out the talk, even if you’re like me and have never written any Zig.About halfway through the talk, he shows a way to improve his memory usage by avoiding wasting memory. By turning this structure:const Monster = struct { anim : *Animation, kind : Kind, const Kind = enum { snake, bat, wolf, dingo, human }; }; var monsters : ArrayList(Monster) = .{}; into this one:var monsters : MultiArrayList(Monster) = .{}; ArrayList(Monster) is what we could call std::vector<Monster>, and MultiArrayList(Monster) now stores the anims and kinds in two separate arrays, instead of one. That is, a struct of arrays instead of an array of structs. But it’s a tiny code change.One of the interesting things about Zig to me is that types are first class. Rather than having a class template that takes a template type parameter (like std::vector taking T), you write a function that takes a function parameter that is a type. That function then returns a type.The implementation of MultiArrayList is literallypub fn MultiArrayList(comptime T: type) type { return struct { // lots of code }; } The goal of this blog post is to implement the same thing using C++26 Reflection. We’re going to write a SoaVector<T> that instead being a dynamic array of Ts has one dynamic array for each non-static data member of T.We Start with StorageFor the purposes of this post, we’re going to pick a simple type that has two members of different types. Let’s say… a chess coordinate:struct Point { char x; int y; }; If we were implementing a simple Vector<Point> our storage would look likestruct { Point* data; size_t size; size_t capacity; }; But we’re writing an SoaVector<Point>, which means we want to store the xs and ys separately. Now, we could be lazy and do this:struct { std::ve...

First seen: 2025-05-09 12:14

Last seen: 2025-05-09 20:16