From 9f3faaf3c4825f13da91f985502d8625ce3ea848 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 15 Nov 2022 00:55:39 +0100 Subject: [PATCH] lib/icu/Transliterator: wrapper for UTransliterator --- src/lib/icu/Transliterator.cxx | 64 ++++++++++++++++++++++++++++++++++ src/lib/icu/Transliterator.hxx | 64 ++++++++++++++++++++++++++++++++++ src/lib/icu/meson.build | 1 + 3 files changed, 129 insertions(+) create mode 100644 src/lib/icu/Transliterator.cxx create mode 100644 src/lib/icu/Transliterator.hxx diff --git a/src/lib/icu/Transliterator.cxx b/src/lib/icu/Transliterator.cxx new file mode 100644 index 000000000..b1470d609 --- /dev/null +++ b/src/lib/icu/Transliterator.cxx @@ -0,0 +1,64 @@ +/* + * Copyright 2003-2022 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "Transliterator.hxx" +#include "util/AllocatedArray.hxx" + +#include // for std::copy() +#include + +static UTransliterator * +OpenTransliterator(const UChar *id, const UChar *rules) +{ + UErrorCode error_code = U_ZERO_ERROR; + + UTransliterator *t = utrans_openU(id, -1, UTRANS_FORWARD, + rules, -1, + nullptr, &error_code); + if (t == nullptr) + throw std::runtime_error(u_errorName(error_code)); + + return t; +} + +IcuTransliterator::IcuTransliterator(const UChar *id, const UChar *rules) + :transliterator(OpenTransliterator(id, rules)) +{ +} + +AllocatedArray +IcuTransliterator::Transliterate(std::basic_string_view src) noexcept +{ + AllocatedArray dest(src.size() * 2U); + std::copy(src.begin(), src.end(), dest.begin()); + + int32_t length = src.size(); + int32_t limit = length; + + UErrorCode status = U_ZERO_ERROR; + utrans_transUChars(transliterator, + dest.data(), &length, dest.size(), + 0, &limit, + &status); + if (U_FAILURE(status)) + return nullptr; + + dest.SetSize(length); + return dest; +} diff --git a/src/lib/icu/Transliterator.hxx b/src/lib/icu/Transliterator.hxx new file mode 100644 index 000000000..38ab86e9d --- /dev/null +++ b/src/lib/icu/Transliterator.hxx @@ -0,0 +1,64 @@ +/* + * Copyright 2003-2022 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#pragma once + +#include + +#include // for std::exchange() + +template class AllocatedArray; + +/** + * Wrapper for an ICU #UTransliterator instance. + */ +class IcuTransliterator { + UTransliterator *transliterator = nullptr; + + IcuTransliterator(UTransliterator *_transliterator) noexcept + :transliterator(_transliterator) {} + +public: + IcuTransliterator() noexcept = default; + + /** + * Throws on error. + */ + IcuTransliterator(const UChar *id, const UChar *rules); + + ~IcuTransliterator() noexcept { + if (transliterator != nullptr) + utrans_close(transliterator); + } + + IcuTransliterator(IcuTransliterator &&src) noexcept + :transliterator(std::exchange(src.transliterator, nullptr)) {} + + IcuTransliterator &operator=(IcuTransliterator &&src) noexcept { + using std::swap; + swap(transliterator, src.transliterator); + return *this; + } + + /** + * @return the transliterated string (or nullptr on error) + */ + [[gnu::pure]] + AllocatedArray Transliterate(std::basic_string_view src) noexcept; +}; diff --git a/src/lib/icu/meson.build b/src/lib/icu/meson.build index 57b816946..65d90b199 100644 --- a/src/lib/icu/meson.build +++ b/src/lib/icu/meson.build @@ -19,6 +19,7 @@ if icu_dep.found() 'Util.cxx', 'FoldCase.cxx', 'Normalize.cxx', + 'Transliterator.cxx', ] else if meson.version().version_compare('>= 0.60')