Now you support me, now you don't

Now you support me, now you don't

This blog has a pretty ugly title. So you can imagine files of this exact pattern repeated hundreds of times will be worse than ugly. The problem is rather simple, some hardware may offer features that other hardware does not. Naturally, you do not want to enable these features if it's not even supported as

The thing is this is so commonly needed that there are many many ways of defining these types of blocks. We'll look at a few approaches to this today but first let's establish an example method, which I've had to implement myself.

Consider a simple API that returns the CPU utilisation when requested:

grpc::Status GetCpuUtilization( grpc::ServerContext* ctx,
                                const cpu::CpuRequest* req,
                                cpu::CpuResponse* resp) {
  resp->set_utilization(GetCpuUtilization());
  // set_utilization would be defined in the corresponding auto-generated proto
  return grpc::Status::OK;
}

Now let's assume that our targetted hardware fleet has both x86 and aarch64 style CPUs so the implementatation for fetching CPU utilisation is different. So let us say our codebase now also has functions

Classic C-Style Macros

In my limited experience with C, I've found macros and macro methods are good enough to get the job done. As a simple example, let's say we have something like this.

old cpp way

This is where compile-time programming actually begins to formalise a bit. So you could do something like constexpr

Modern cpp way

Extending comptime stuff

Quick spoiler, this one's my favourite.

One of the things I enjoyed most about Zig was being prompted to think in the so called "comptime metaprogramming" dimension. For those unfamiliar, it's pretty straightforward - the idea is to perform as many operations (mostly deciding how much memory to allocate) at compile time rather than at runtime.