https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109249

--- Comment #2 from Andre Schackier <andre.schackier at gmail dot com> ---
I'm soryy will keep that in mind for the future :)

Example #1:
#include <array>
#include <cstdint>

enum class Type {
    None,

    Bug,
    Dark,
    Dragon,
    Electric,
    Fighting,
    Fire,
    Flying,
    Ghost,
    Grass,
    Ground,
    Ice,
    Normal,
    Poison,
    Psychic,
    Rock,
    Steel,
    Water,

    Count,
};

static constexpr const std::size_t NumberOfTypes =
    static_cast<std::size_t>(Type::Count);

namespace detail {
constexpr float GetTypeDamageMultiplierImpl(Type defending_type,
                                            Type attacking_type) noexcept {
    switch (defending_type) {
        case Type::None:
            return 1.0f;

        case Type::Bug:
            switch (attacking_type) {
                case Type::Fighting:
                case Type::Grass:
                case Type::Ground:
                    return 0.5f;

                case Type::Fire:
                case Type::Flying:
                case Type::Rock:
                    return 2.0f;

                default:
                    return 1.0f;
            }

        case Type::Dark:
            switch (attacking_type) {
                case Type::Psychic:
                    return 0.0f;

                case Type::Dark:
                case Type::Ghost:
                    return 0.5f;

                case Type::Bug:
                case Type::Fighting:
                    return 2.0f;

                default:
                    return 1.0f;
            }

        case Type::Dragon:
            switch (attacking_type) {
                case Type::Electric:
                case Type::Fire:
                case Type::Grass:
                case Type::Water:
                    return 0.5f;

                case Type::Dragon:
                case Type::Ice:
                    return 2.0f;

                default:
                    return 1.0f;
            }

        case Type::Electric:
            switch (attacking_type) {
                case Type::Electric:
                case Type::Flying:
                case Type::Steel:
                    return 0.5f;

                case Type::Ground:
                    return 2.0f;

                default:
                    return 1.0f;
            }

        case Type::Fighting:
            switch (attacking_type) {
                case Type::Bug:
                case Type::Dark:
                case Type::Rock:
                    return 0.5f;

                case Type::Flying:
                case Type::Psychic:
                    return 2.0f;

                default:
                    return 1.0f;
            }

        case Type::Fire:
            switch (attacking_type) {
                case Type::Bug:
                case Type::Fire:
                case Type::Grass:
                case Type::Ice:
                case Type::Steel:
                    return 0.5f;

                case Type::Ground:
                case Type::Rock:
                case Type::Water:
                    return 2.0f;

                default:
                    return 1.0f;
            }

        case Type::Flying:
            switch (attacking_type) {
                case Type::Ground:
                    return 0.0f;

                case Type::Bug:
                case Type::Fighting:
                case Type::Grass:
                    return 0.5f;

                case Type::Electric:
                case Type::Ice:
                case Type::Rock:
                    return 2.0f;

                default:
                    return 1.0f;
            }

        case Type::Ghost:
            switch (attacking_type) {
                case Type::Normal:
                case Type::Fighting:
                    return 0.0f;

                case Type::Bug:
                case Type::Poison:
                    return 0.5f;

                case Type::Dark:
                case Type::Ghost:
                    return 2.0f;

                default:
                    return 1.0f;
            }

        case Type::Grass:
            switch (attacking_type) {
                case Type::Electric:
                case Type::Grass:
                case Type::Ground:
                case Type::Water:
                    return 0.5f;

                case Type::Bug:
                case Type::Fire:
                case Type::Flying:
                case Type::Ice:
                case Type::Poison:
                    return 2.0f;

                default:
                    return 1.0f;
            }

        case Type::Ground:
            switch (attacking_type) {
                case Type::Electric:
                    return 0.0f;

                case Type::Poison:
                case Type::Rock:
                    return 0.5f;

                case Type::Grass:
                case Type::Ice:
                case Type::Water:
                    return 2.0f;

                default:
                    return 1.0f;
            }

        case Type::Ice:
            switch (attacking_type) {
                case Type::Ice:
                    return 0.5f;

                case Type::Fighting:
                case Type::Fire:
                case Type::Rock:
                case Type::Steel:
                    return 2.0f;

                default:
                    return 1.0f;
            }

        case Type::Normal:
            switch (attacking_type) {
                case Type::Ghost:
                    return 0.0f;

                case Type::Fighting:
                    return 2.0f;

                default:
                    return 1.0f;
            }

        case Type::Poison:
            switch (attacking_type) {
                case Type::Fighting:
                case Type::Poison:
                case Type::Bug:
                case Type::Grass:
                    return 0.5f;

                case Type::Ground:
                case Type::Psychic:
                    return 2.0f;

                default:
                    return 1.0f;
            }

        case Type::Psychic:
            switch (attacking_type) {
                case Type::Fighting:
                case Type::Psychic:
                    return 0.5f;

                case Type::Bug:
                case Type::Dark:
                case Type::Ghost:
                    return 2.0f;

                default:
                    return 1.0f;
            }

        case Type::Rock:
            switch (attacking_type) {
                case Type::Fire:
                case Type::Flying:
                case Type::Normal:
                case Type::Poison:
                    return 0.5f;

                case Type::Fighting:
                case Type::Grass:
                case Type::Ground:
                case Type::Steel:
                case Type::Water:
                    return 2.0f;

                default:
                    return 1.0f;
            }

        case Type::Steel:
            switch (attacking_type) {
                case Type::Poison:
                    return 0.0f;

                case Type::Bug:
                case Type::Dark:
                case Type::Dragon:
                case Type::Flying:
                case Type::Ghost:
                case Type::Grass:
                case Type::Ice:
                case Type::Normal:
                case Type::Psychic:
                case Type::Rock:
                case Type::Steel:
                    return 0.5f;

                case Type::Fighting:
                case Type::Fire:
                case Type::Ground:
                    return 2.0f;

                default:
                    return 1.0f;
            }

        case Type::Water:
            switch (attacking_type) {
                case Type::Fire:
                case Type::Ice:
                case Type::Steel:
                case Type::Water:
                    return 0.5f;

                case Type::Electric:
                case Type::Grass:
                    return 2.0f;

                default:
                    return 1.0f;
            }

        default:
            __builtin_unreachable();
    }
}

constexpr std::array<float, NumberOfTypes * NumberOfTypes>
GenerateTypeDamageTable() noexcept {
    std::array<float, NumberOfTypes * NumberOfTypes> table{};

    for (std::uint32_t defending_type{0u}; defending_type < NumberOfTypes;
         ++defending_type) {
        for (std::uint32_t attacking_type{0u}; attacking_type < NumberOfTypes;
             ++attacking_type) {
            table[defending_type * NumberOfTypes + attacking_type] =
                GetTypeDamageMultiplierImpl(static_cast<Type>(defending_type),
                                            static_cast<Type>(attacking_type));
        }
    }

    return std::move(table);
}
}  // namespace detail

float GetTypeDamageMultiplier(Type defending_type,
                              Type attacking_type) noexcept {
    constexpr const auto table = detail::GenerateTypeDamageTable();

    return table[static_cast<std::size_t>(defending_type) * NumberOfTypes +
                 static_cast<std::size_t>(attacking_type)];
}

Example #2:
#include <array>
#include <cstdint>

enum class Type {
    None,

    Bug,
    Dark,
    Dragon,
    Electric,
    Fighting,
    Fire,
    Flying,

    Count,
};

static constexpr const std::size_t NumberOfTypes =
    static_cast<std::size_t>(Type::Count);

namespace detail {
constexpr float GetTypeDamageMultiplierImpl(
    const Type defending_type, const Type attacking_type) noexcept {
    switch (defending_type) {
        case Type::None:
            return 1.0f;

        case Type::Bug:
            switch (attacking_type) {
                case Type::Fighting:
                    return 0.5f;

                case Type::Fire:
                case Type::Flying:
                    return 2.0f;

                default:
                    return 1.0f;
            }

        case Type::Dark:
            switch (attacking_type) {
                case Type::Dark:
                    return 0.5f;

                case Type::Bug:
                case Type::Fighting:
                    return 2.0f;

                default:
                    return 1.0f;
            }

        case Type::Dragon:
            switch (attacking_type) {
                case Type::Electric:
                case Type::Fire:
                    return 0.5f;

                case Type::Dragon:
                    return 2.0f;

                default:
                    return 1.0f;
            }

        case Type::Electric:
            switch (attacking_type) {
                case Type::Electric:
                case Type::Flying:
                    return 0.5f;

                default:
                    return 1.0f;
            }

        case Type::Fighting:
            switch (attacking_type) {
                case Type::Bug:
                case Type::Dark:
                    return 0.5f;

                case Type::Flying:
                    return 2.0f;

                default:
                    return 1.0f;
            }

        case Type::Fire:
            switch (attacking_type) {
                case Type::Bug:
                case Type::Fire:
                    return 0.5f;

                default:
                    return 1.0f;
            }

        case Type::Flying:
            switch (attacking_type) {
                case Type::Bug:
                case Type::Fighting:
                    return 0.5f;

                case Type::Electric:
                    return 2.0f;

                default:
                    return 1.0f;
            }

        default:
            __builtin_unreachable();
    }
}

constexpr std::array<float, NumberOfTypes * NumberOfTypes>
GenerateTypeDamageTable() noexcept {
    std::array<float, NumberOfTypes * NumberOfTypes> table{};

    for (std::uint32_t defending_type{0u}; defending_type < NumberOfTypes;
         ++defending_type) {
        for (std::uint32_t attacking_type{0u}; attacking_type < NumberOfTypes;
             ++attacking_type) {
            table[defending_type * NumberOfTypes + attacking_type] =
                GetTypeDamageMultiplierImpl(static_cast<Type>(defending_type),
                                            static_cast<Type>(attacking_type));
        }
    }

    return std::move(table);
}
}  // namespace detail

float GetTypeDamageMultiplier(const Type defending_type,
                              const Type attacking_type) noexcept {
    constexpr const auto table = detail::GenerateTypeDamageTable();

    return table[static_cast<std::size_t>(defending_type) * NumberOfTypes +
                 static_cast<std::size_t>(attacking_type)];
}

Reply via email to