Sparse array initialization

Consider this C program:

#include <stdio.h>

struct some_struct {
    int a, b;
} structs[3] = {
    [0] = {.a = 1, .b = 1},
    [1] = {.a = 2, .b = 2},
    [2] = {.a = 3, .b = 3},
};

#define N 255
struct some_struct *array[N] = {
    ['z'] = &structs[0],
    ['i'] = &structs[1],
    ['g'] = &structs[2],
};

int main(void) {

    unsigned char k = 0;
    for (; k < N; k++) {
        struct some_struct *p = array[k];
        if (NULL == p)
            continue;
        printf("'%c' => {.a = %d, .b = %d}\n", k, p->a, p->b);
    }
}

Result:

$ gcc -Wall sa.c 
$ ./a.out 
'g' => {.a = 3, .b = 3}
'i' => {.a = 2, .b = 2}
'z' => {.a = 1, .b = 1}

Is it possible to do something similar in Zig? I mean:

  • initialize explicitly only some elements of an array
  • use chars (not numbers) for indexes in initializer
  • initialization is “out of order”

I would use optionals for this:

const std = @import("std");

const some_struct = struct {
   a: isize,
   b: isize,
};

const N = 255;

pub fn main() void {
   const structs: [3]some_struct = .{
      .{ .a = 1, .b = 1 },
      .{ .a = 2, .b = 2 },
      .{ .a = 3, .b = 3 },
   };

   var array: [N]?*const some_struct = [_]?*some_struct{null} ** N;
   array['z'] = &structs[0];
   array['i'] = &structs[1];
   array['g'] = &structs[2];

   for (array) |maybe_p, i| {
      if (maybe_p) |p| std.log.info("'{c}' => {{ .a = {}, .b = {} }}", .{ @intCast(u8, i), p.a, p.b });
   }
}

I believe that given the way Zig represents optional pointers in memory, this has no added overhead.

4 Likes

Ok, so the method is just to move “sparse initialization” out of the initializer itself. Looks pretty nice, thanks @dude_the_builder.

1 Like

Just two notes: it’s possible to initialize the array in a single expression, and it may be wise (since it is possible and ergonomic in Zig) to use optional values instead of optional pointers.

const array: [N]?some_struct = [_]?some_struct{
    structs[0],
    structs[1],
    structs[2],
} ++ [_]?some_struct{null} ** (N - 3);

Using optional values does come at the cost of padding out each element to about twice the original number of bytes, but that is often much less overhead than managing the lifetime of each individual pointer element if they have to be initiated dynamically.

2 Likes

Thanks for your notes @InKryption.
I’d like to use ascii symbols as indexes in initialization code.
Later I use XLookupKeysym() to get a symbol and use it as an index.

In my case, initialization happens in the very beginning.

1 Like