#Cast `[]?T` to `[]T`?

1 messages · Page 1 of 1 (latest)

polar belfry
#

Is it possible cast (or otherwise easily convert) []?T to []T? Or do I need to create a new slice of type []T and manually copy all values from the []?T slice while unpacking each one individually?

#

When I know all values are non-null ofc

rustic wagon
#

You need to create a new slice, think of ?T as stuct { null: bool, data: T}
if you cast you roughly half of the data will actually be the null field (plus padding) not the actual data that you want.

polar belfry
#

Yeah you're right, casting wouldn't make sense. But maybe there is a built in function or something for this purpose? If there is not, would this be the "proper" way?

const array = try allocator.alloc(?usize, size);
// some logic ...
const array_concrete = try allocator.alloc(usize, size);
for (array, array_concrete) |v, *v_conc| v_conc.* = v.?;
rustic wagon
#

no buitin for this, the for loop is the solution.
However it is questionable that you have a []?T in the firstplace, depending on what you are doing there might be a better solution.

brittle flare
#

If T happens to be a pointer, casting would be possible

polar belfry
# rustic wagon no buitin for this, the for loop is the solution. However it is questionable tha...

Hmm, this is the actual function I made:

    fn findLargestBatteryPackIndexes(self: *const Self, allocator: std.mem.Allocator) ![]usize {
        const pack_indexes = try allocator.alloc(?usize, self.pack_size);
        @memset(pack_indexes, null);
        defer allocator.free(pack_indexes);

        var bank_idx: usize = 1;
        while (bank_idx < self.bank.len) : (bank_idx += 1) {
            var pack_idx: usize = @max(
                0,
                @as(isize, @intCast(self.pack_size)) - (@as(isize, @intCast(self.bank.len)) - @as(isize, @intCast(bank_idx))),
            );
            while (pack_idx < pack_indexes.len) : (pack_idx += 1) {
                if (pack_indexes[pack_idx]) |idx| {
                    if (self.bank[bank_idx] > self.bank[idx]) {
                        pack_indexes[pack_idx] = bank_idx;
                        if (pack_idx < pack_indexes.len - 1) @memset(pack_indexes[pack_idx + 1 ..], null);
                        break;
                    }
                } else {
                    pack_indexes[pack_idx] = bank_idx;
                    break;
                }
            }
        }

        const pack_indexes_concrete = try allocator.alloc(usize, self.pack_size);
        for (pack_indexes, pack_indexes_concrete) |idx, *idx_conc| idx_conc.* = idx.?;

        return pack_indexes_concrete;
    }

I'm using null values to check for unassigned indexes. But at the end of the processing I know there should be no null values and want to return a non-optional slice. I'd love to hear suggestions tho

brittle flare
#

Is this aoc? I haven't made it past day 2 yet 💀

polar belfry
brittle flare
#

Just lack of time during the week

rustic wagon
#

I would have a second slice of bools []bool instead of a single []?usize, call it something like active_indexes.
it uses less memory, and avoids having to copy all the usize into a new slice.
just add a defer for (active_indexes) |active| std.debug.assert(active); to ensure you dont miss any