I’ve recently stumbled upon a code responsible for checking if user selected all days of the week, e.g. 1, 2, 3, 4, 5, 6, 7. There are certainly many ways to approach this, but we’ll go stick to the approach proposed by the author - comparing canonical (sorted) representation of the days with predefined vectors. The gist of this idea can be illustrated below
Again, there are certainly many faster ways to perform this check, including simple for loop, but imagine this snippet being part of a complex workflow with all sorts of other checks where using comparison with vectors reduces code complexity.
Creation of one-off vectors for these checks already suggests certain level of inefficiency, but making it a global constant has a downside of pre-main overhead for its construction. Recent C++ standards bring ability to perform compile-time initialization for many data structures, including vector, but sadly I still have to deal with code that can use at most C++17.
But even in C++17 std::array can be initialized at compile-time, so we just need to find a way to compare arrays with vectors. Fortunately, standard library makes this trivial
Note, that because kEveryDays is constexpr, it’s initialized at compile-time with no runtime overhead. Well, this doesn’t look too bad and we can come up with a convenience array wrapper to make this comparison nicer, but is it worth it?
Let’s see. For comparison we’ll use 3 use-cases:
full match
mismatch at the last day
size mismatch
Intuitively, size mismatch should show largest win for the array check, since in this case vector construction adds pure overhead, but what about the rest?
The difference is huge! We’re talking about 30X speedup over vector based size mismatch but the rest of array-based functions are also many times faster than their vector-based colleagues.
Again, there are other ways to deal with this specific check, including those that are based on the idea of ranges. For example, something like std::array {1,2,3,4,5,6,7} can be represented even more efficiently by a range(1,8), but it becomes trickier to represent other use-cases that do not follow any step-based pattern and, possibly more importantly, we may not be able to leverage vectorized instructions.
std::array is a very versatile data structure, so every time you know the size at compile-time, consider using it instead of std::vector.