From 92416fb6e86614bef33c218bcb4ac146266964c5 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Fri, 21 Nov 2025 10:52:14 +0100 Subject: [PATCH] Use std::visit to exhaust std::variant possibilities This makes it unnecessary to silence impossible "unhandled" cases. --- src/ft2font_wrapper.cpp | 46 +++++++++++++++++------------------------ src/mplutils.h | 15 ++++++++------ 2 files changed, 28 insertions(+), 33 deletions(-) diff --git a/src/ft2font_wrapper.cpp b/src/ft2font_wrapper.cpp index 08bb27f024f2..f8360449ef77 100644 --- a/src/ft2font_wrapper.cpp +++ b/src/ft2font_wrapper.cpp @@ -8,6 +8,7 @@ #endif #include "ft2font.h" +#include "mplutils.h" #include #include @@ -617,20 +618,15 @@ PyFT2Font_set_text(PyFT2Font *self, std::u32string_view text, double angle = 0.0 std::variant languages_or_str = nullptr) { std::vector xys; - - FT2Font::LanguageType languages; - if (auto value = std::get_if(&languages_or_str)) { - languages = std::move(*value); - } else if (auto value = std::get_if(&languages_or_str)) { - languages = std::vector{ - FT2Font::LanguageRange{*value, 0, text.size()} - }; - } else { - // NOTE: this can never happen as pybind11 would have checked the type in the - // Python wrapper before calling this function, but we need to keep the - // std::get_if instead of std::get for macOS 10.12 compatibility. - throw py::type_error("languages must be str or list of tuple"); - } + FT2Font::LanguageType languages = std::visit(overloaded { + [](FT2Font::LanguageType languages) { + return languages; + }, + [&](std::string value) { + return FT2Font::LanguageType{{ + FT2Font::LanguageRange{value, 0, text.size()}}}; + } + }, languages_or_str); self->set_text(text, angle, static_cast(flags), features, languages, xys); @@ -1340,19 +1336,15 @@ PyFT2Font_layout(PyFT2Font *self, std::u32string text, LoadFlags flags, { const auto load_flags = static_cast(flags); - FT2Font::LanguageType languages; - if (auto value = std::get_if(&languages_or_str)) { - languages = std::move(*value); - } else if (auto value = std::get_if(&languages_or_str)) { - languages = std::vector{ - FT2Font::LanguageRange{*value, 0, text.size()} - }; - } else { - // NOTE: this can never happen as pybind11 would have checked the type in the - // Python wrapper before calling this function, but we need to keep the - // std::get_if instead of std::get for macOS 10.12 compatibility. - throw py::type_error("languages must be str or list of tuple"); - } + FT2Font::LanguageType languages = std::visit(overloaded { + [](FT2Font::LanguageType languages) { + return languages; + }, + [&](std::string value) { + return FT2Font::LanguageType{{ + FT2Font::LanguageRange{value, 0, text.size()}}}; + } + }, languages_or_str); std::set glyph_seen_fonts; auto glyphs = self->layout(text, load_flags, features, languages, glyph_seen_fonts); diff --git a/src/mplutils.h b/src/mplutils.h index 475530b3d880..2a7d63c871f5 100644 --- a/src/mplutils.h +++ b/src/mplutils.h @@ -49,8 +49,6 @@ enum { }; #ifdef __cplusplus // not for macosx.m -// Check that array has shape (N, d1) or (N, d1, d2). We cast d1, d2 to longs -// so that we don't need to access the NPY_INTP_FMT macro here. #include #include #include @@ -59,6 +57,12 @@ enum { namespace py = pybind11; using namespace pybind11::literals; +// Helper for std::visit. +template struct overloaded : Ts... { using Ts::operator()...; }; +template overloaded(Ts...) -> overloaded; + +// Check that array has shape (N, d1) or (N, d1, d2). We cast d1, d2 to longs +// so that we don't need to access the NPY_INTP_FMT macro here. template inline void check_trailing_shape(T array, char const* name, long d1) { @@ -97,11 +101,10 @@ inline void check_trailing_shape(T array, char const* name, long d1, long d2) } } -/* In most cases, code should use safe_first_shape(obj) instead of obj.shape(0), since - safe_first_shape(obj) == 0 when any dimension is 0. */ +// In most cases, code should use safe_first_shape(obj) instead of +// obj.shape(0), since safe_first_shape(obj) == 0 when any dimension is 0. template -py::ssize_t -safe_first_shape(const py::detail::unchecked_reference &a) +py::ssize_t safe_first_shape(const py::detail::unchecked_reference &a) { bool empty = (ND == 0); for (py::ssize_t i = 0; i < ND; i++) {