/* * This source code is released into the public domain. */ module; /* * flagset: a type-type flags type. */ #include #include #include #include #include export module nihil.flagset; namespace nihil { export template struct flagset final { using underlying_type = base_type; /* * Create an empty flags. */ flagset() noexcept = default; /* * Copyable. */ flagset(flagset const &other) noexcept : m_value(other.m_value) {} /* * Create flags from an integer mask. */ template [[nodiscard]] static constexpr auto mask() noexcept -> flagset { return flagset(flag); } /* * Create flags for a specific bit. */ template [[nodiscard]] static constexpr auto bit() noexcept -> flagset { static_assert(bitnr < std::numeric_limits::digits); return flagset(static_cast(1) << bitnr); } /* * Create flags from a runtime value. */ [[nodiscard]] static auto from_int(base_type value) noexcept -> flagset { return flagset(value); } /* * Assign this flagset. */ auto operator=(this flagset &lhs, flagset rhs) noexcept -> flagset & { if (&lhs != &rhs) lhs.m_value = rhs.m_value; return lhs; } /* * The integer value of this flagset. */ [[nodiscard]] constexpr auto value(this flagset self) noexcept -> base_type { return self.m_value; } /* * True if this flagset has any bits set. */ [[nodiscard]] explicit constexpr operator bool(this flagset self) noexcept { return self.m_value != 0; } /* * Set bits. */ constexpr auto operator|= (this flagset &lhs, flagset rhs) noexcept -> flagset & { lhs.m_value |= rhs.value(); return lhs; } /* * Mask bits. */ constexpr auto operator&= (this flagset &lhs, flagset rhs) noexcept -> flagset & { lhs.m_value &= rhs.value(); return lhs; } /* * Invert bits. */ [[nodiscard]] constexpr auto operator~ (this flagset self) noexcept -> flagset { return flagset(~self.m_value); } /* * xor bits. */ constexpr auto operator^= (this flagset &lhs, flagset rhs) noexcept -> flagset { lhs.m_value ^= rhs.value(); return lhs; } private: base_type m_value = 0; explicit constexpr flagset(base_type mask) noexcept : m_value(mask) {} }; export template [[nodiscard]] auto operator| (flagset lhs, flagset rhs) noexcept -> flagset { return (lhs |= rhs); } export template [[nodiscard]] auto operator& (flagset lhs, flagset rhs) noexcept -> flagset { return (lhs &= rhs); } export template [[nodiscard]] auto operator^ (flagset lhs, flagset rhs) noexcept -> flagset { return (lhs ^= rhs); } export template [[nodiscard]] auto operator== (flagset lhs, flagset rhs) noexcept -> bool { return lhs.value() == rhs.value(); } export template auto operator<<(std::ostream &strm, flagset flags) -> std::ostream & { std::print(strm, "{}", flags); return strm; } } // namespace nihil /* * Formatting for flagset. */ export template struct std::formatter, Char> { using flags_t = nihil::flagset; template constexpr auto parse(ParseContext &ctx) -> ParseContext::iterator { return ctx.begin(); } template auto format(flags_t flags, FmtContext& ctx) const -> FmtContext::iterator { auto constexpr digits = std::numeric_limits::digits; auto value = flags.value(); auto it = ctx.out(); *it++ = Char{'<'}; auto printed_any = false; for (unsigned i = 0; i < digits; ++i) { unsigned bit = (digits - 1) - i; auto this_bit = static_cast(1) << bit; if ((value & this_bit) == 0) continue; if (printed_any) *it++ = Char{','}; if (bit > 10) *it++ = Char{'0'} + (bit / 10); *it++ = Char{'0'} + (bit % 10); printed_any = true; } *it++ = Char{'>'}; return it; } };