#Please help shorten this piece of stupid comptime code

1 messages · Page 1 of 1 (latest)

steel berry
#

I have some comptime code that seems way longer than it needs to be. Comments are included about why each piece exists, and what errors I ran into that led me to put it there. I feel like there must be a better way to do this.

fn getBaseQuantities(comptime bases: []const TypeValuePair) []const TypeValuePair {
    comptime {
        var basesReduced: []const TypeValuePair = &.{};
        for (0..bases.len) |i| {
            switch (interface.satisfiesInterface(CompositeQuantity, bases[i].t)) {
                .Satisfies => {
                    for (getBaseQuantities(bases[i].t.bases)) |baseToAdd| {
                        basesReduced = basesReduced ++ [_]TypeValuePair{.{ .t = baseToAdd.t, .v = baseToAdd.v * bases[i].v }};
                    }
                    continue;
                },
                .Fails => {},
            }
            switch (interface.satisfiesInterface(BaseQuantity, bases[i].t)) {
                .Satisfies => {
                    basesReduced = basesReduced ++ [_]TypeValuePair{bases[i]};
                },
                .Fails => {
                    @compileError(std.fmt.comptimePrint("{} is not a base or composite quality.", .{bases[i].t}));
                },
            }
        }

        const sortFunc: fn (void, TypeValuePair, TypeValuePair) bool = struct {
            pub fn inner(_: void, a: TypeValuePair, b: TypeValuePair) bool {
                return std.mem.order(u8, @typeName(a.t), @typeName(b.t)) == std.math.Order.gt;
            }
        }.inner;

snippet continued in next message

#
        //I can't sort basesReduced, because it's const, so I make a copy.
        //However, if I make it not const, then the array concatenation above fails with "error: expected type '[]main.TypeValuePair', found '*const [1]main.TypeValuePair'"
        var basesSorted: [basesReduced.len]TypeValuePair = undefined;
        @memcpy(&basesSorted, basesReduced);
        std.mem.sort(TypeValuePair, &basesSorted, {}, sortFunc);

        //I can't remove duplicate elements from basesSorted directly, because i can't seem to perform array concatenation on a non-const slice (same error as above)
        //I also can't make this a const slice, because then I can't assign to its elements
        var basesNoRepeats: [basesReduced.len]TypeValuePair = .{TypeValuePair{ .t = undefined, .v = 0 }} ** basesReduced.len;
        var j = 0;
        for (0..basesSorted.len) |i| {
            if (i > 0 and basesSorted[i].t == basesSorted[i - 1].t) {
                basesNoRepeats[j - 1].v += basesSorted[i].v;
            } else {
                basesNoRepeats[j] = basesSorted[i];
                j += 1;
            }
        }

        //I can't directly slice basesNoRepeats and return it, because then I get "error: type capture contains reference to comptime var" later when I use the return value in a struct definition
        var basesConstSlice: []const TypeValuePair = &.{};
        for (0..j) |i| {
            basesConstSlice = basesConstSlice ++ [_]TypeValuePair{basesNoRepeats[i]};
        }

        return basesConstSlice;
    }
}
#

i feel like i'm just converting a slice back and forth for no reason, but trying to do anything else leads to a compiler error. what do

ornate geyser
# steel berry ```rs //I can't sort basesReduced, because it's const, so I make a copy....

try this:

fn getBaseQuantities(comptime bases: []const TypeValuePair) []const TypeValuePair {
    comptime {
        var basesReduced: []TypeValuePair = &.{};
        for (0..bases.len) |i| {
            switch (interface.satisfiesInterface(CompositeQuantity, bases[i].t)) {
                .Satisfies => {
                    for (getBaseQuantities(bases[i].t.bases)) |baseToAdd| {
                        basesReduced = basesReduced ++ @as([]TypeValuePair, &.{.{ .t = baseToAdd.t, .v = baseToAdd.v * bases[i].v }});
                    }
                    continue;
                },
                .Fails => {},
            }
            switch (interface.satisfiesInterface(BaseQuantity, bases[i].t)) {
                .Satisfies => basesReduced = basesReduced ++ @as([]TypeValuePair, &.{bases[i]});
                .Fails => @compileError(std.fmt.comptimePrint("{} is not a base or composite quality.", .{bases[i].t}));
            }
        }

        const sortFunc = struct {
            pub fn inner(_: void, a: TypeValuePair, b: TypeValuePair) bool {
                return std.mem.order(u8, @typeName(a.t), @typeName(b.t)) == std.math.Order.gt;
            }
        }.inner;

        std.mem.sort(TypeValuePair, basesReduced, {}, sortFunc);

        var basesNoRepeats: []TypeValuePair = &[_]TypeValuePair{.{ .t = undefined, .v = 0 }} ** basesReduced.len;
        var j = 0;
        for (0..basesReduced.len) |i| {
            if (i > 0 and basesReduced[i].t == basesReduced[i - 1].t) {
                basesNoRepeats[basesNoRepeats.len - 1].v += basesReduced[i].v;
            } else {
                basesNoRepeats[j] = basesReduced[i];
                j += 1;
            }
        }

        return basesNoRepeats;
    }
}
#

I cant test it so idk if its right

steel berry
#

i tried it after fixing a couple syntax errors in a switch statement

#

and got this

                .Satisfies => basesReduced = basesReduced ++ @as([]TypeValuePair, &.{bases[i]}),```
#

even explicitly casting it doesn't work? really not sure what's going on here

ornate geyser
steel berry
#

i'm trying to make a lil library for unit conversion/dimensional analysis. right now it does very little LOL

ornate geyser
steel berry
#

yes

ornate geyser
#

why not 0.14.0?

steel berry
#

oh is 0.14.0 out now? i don't think it was fully released when I started making this

#

i started a while ago then came back to it today

ornate geyser
#

yeah its released, not many breaking changes though

steel berry
#

alright i'll download that

#

dunno if it will make anything easier here tho

ornate geyser
#

no not really

#

well in the end couldnt do much better lol, code is code ig

fn getBaseQuantities(comptime bases: []const TypeValuePair) []const TypeValuePair {
    var basesReduced: []const TypeValuePair = &.{};
    for (0..bases.len) |i| {
        switch (interface.satisfiesInterface(CompositeQuantity, bases[i].t)) {
            .Satisfies => {
                for (getBaseQuantities(bases[i].t.bases)) |baseToAdd| {
                    basesReduced = basesReduced ++ [_]TypeValuePair{.{ .t = baseToAdd.t, .v = baseToAdd.v * bases[i].v }};
                }
                continue;
            },
            .Fails => {},
        }
        switch (interface.satisfiesInterface(BaseQuantity, bases[i].t)) {
            .Satisfies => basesReduced = basesReduced ++ [_]TypeValuePair{bases[i]},
            .Fails => @compileError(std.fmt.comptimePrint("{} is not a base or composite quality.", .{bases[i].t})),
        }
    }

    const sortFunc: fn (void, TypeValuePair, TypeValuePair) bool = struct {
        pub fn inner(_: void, a: TypeValuePair, b: TypeValuePair) bool {
            return std.mem.order(u8, @typeName(a.t), @typeName(b.t)) == std.math.Order.gt;
        }
    }.inner;

    var basesSorted: [basesReduced.len]TypeValuePair = basesReduced[0..].*;
    std.mem.sort(TypeValuePair, &basesSorted, {}, sortFunc);

    var basesNoRepeats = [_]TypeValuePair{TypeValuePair{ .t = undefined, .v = 0 }} ** basesReduced.len;
    var j = 0;
    for (0..basesSorted.len) |i| {
        if (i > 0 and basesSorted[i].t == basesSorted[i - 1].t) {
            basesNoRepeats[j - 1].v += basesSorted[i].v;
        } else {
            basesNoRepeats[j] = basesSorted[i];
            j += 1;
        }
    }

    const basesConstSlice = basesNoRepeats[0..].*;
    return &basesConstSlice;
}
steel berry
#

alright, at least it's a bit better

#

fits in one message LOL