Program Listing for File CheckedInt.hpp

Return to documentation for file (src/rdf4cpp/util/CheckedInt.hpp)

#ifndef RDF4CPP_CHECKEDINT_HPP
#define RDF4CPP_CHECKEDINT_HPP

namespace rdf4cpp::util {
template<std::integral I>
struct CheckedIntegral {
private:
    I value;
    bool invalid = false;

public:
    constexpr CheckedIntegral(I value, bool invalid = false) noexcept : value(value), invalid(invalid) {}

    [[nodiscard]]constexpr  bool is_invalid() const noexcept {
        return invalid;
    }
    [[nodiscard]]constexpr  I get_value() const noexcept {
        return value;
    }

    constexpr std::partial_ordering operator<=>(const CheckedIntegral &other) const noexcept {
        if (this->invalid && other.invalid)
            return std::partial_ordering::equivalent;
        if (this->invalid != other.invalid)
            return std::partial_ordering::unordered;
        return this->value <=> other.value;
    }

    constexpr CheckedIntegral &operator+=(const CheckedIntegral &other) noexcept {
        this->invalid |= other.invalid;
        this->invalid |= __builtin_add_overflow(this->value, other.value, &this->value);
        return *this;
    }
    constexpr CheckedIntegral operator+(const CheckedIntegral &other) const noexcept {
        CheckedIntegral r = *this;
        r += other;
        return r;
    }
    constexpr CheckedIntegral &operator-=(const CheckedIntegral &other) noexcept {
        this->invalid |= other.invalid;
        this->invalid |= __builtin_sub_overflow(this->value, other.value, &this->value);
        return *this;
    }
    constexpr CheckedIntegral operator-(const CheckedIntegral &other) const noexcept {
        CheckedIntegral r = *this;
        r -= other;
        return r;
    }
    constexpr CheckedIntegral &operator*=(const CheckedIntegral &other) noexcept {
        this->invalid |= other.invalid;
        this->invalid |= __builtin_mul_overflow(this->value, other.value, &this->value);
        return *this;
    }
    constexpr CheckedIntegral operator*(const CheckedIntegral &other) const noexcept {
        CheckedIntegral r = *this;
        r *= other;
        return r;
    }
    constexpr CheckedIntegral &operator/=(const CheckedIntegral &other) noexcept {
        if (this->invalid || other.invalid || other.value == 0) {
            this->invalid = true;
            return *this;
        }
        this->value = this->value / other.value;
        return *this;
    }
    constexpr CheckedIntegral operator/(const CheckedIntegral &other) const noexcept {
        CheckedIntegral r = *this;
        r /= other;
        return r;
    }

    friend constexpr CheckedIntegral abs(CheckedIntegral const &val) noexcept {
        if constexpr (std::is_unsigned_v<I>) {
            return val;
        } else {
            if (val.value >= 0) {
                return val;
            }

            CheckedIntegral ret{0, val.invalid};
            ret.invalid |= __builtin_sub_overflow(0, val.value, &ret.value);
            return ret;
        }
    }
};

}  // namespace rdf4cpp::util

#endif  //RDF4CPP_CHECKEDINT_HPP