Revert^2 "Replace usage of ICU4C in bionic with ICU4X"
889f6585d824098854ed3157f60444606f49fa7a
Change-Id: Ic16a9518483d80d6de6ac1f9176606a503a7e72c
diff --git a/libc/Android.bp b/libc/Android.bp
index b5ff680..e6f69c2 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -790,6 +790,53 @@
}
// ========================================================
+// icu4x_bionic.a - Thin Rust wrapper around ICU4X
+// ========================================================
+
+rust_ffi_static {
+ name: "libicu4x_bionic",
+ crate_name: "icu4x_bionic",
+ crate_root: "bionic/icu4x.rs",
+ edition: "2021",
+ features: [],
+ rustlibs: [
+ "//external/rust/android-crates-io/crates/icu_casemap:libicu_casemap",
+ "//external/rust/android-crates-io/crates/icu_collections:libicu_collections",
+ "//external/rust/android-crates-io/crates/icu_properties:libicu_properties",
+ ],
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
+ vendor_available: true,
+ product_available: true,
+ ramdisk_available: true,
+ vendor_ramdisk_available: true,
+ recovery_available: true,
+ native_bridge_supported: true,
+ sdk_version: "minimum",
+ defaults: ["linux_bionic_supported"],
+}
+
+// current rust implementation detail; will be removed as part of a larger cleanup later
+// go/android-mto-staticlibs-in-make
+cc_rustlibs_for_make {
+ name: "libstatic_rustlibs_for_make",
+ whole_static_libs: ["libicu4x_bionic"],
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
+ vendor_available: true,
+ product_available: true,
+ ramdisk_available: true,
+ vendor_ramdisk_available: true,
+ recovery_available: true,
+ native_bridge_supported: true,
+ defaults: ["linux_bionic_supported"],
+}
+
+// ========================================================
// libc_bionic.a - home-grown C library code
// ========================================================
@@ -870,7 +917,6 @@
"bionic/grp_pwd_file.cpp",
"bionic/heap_zero_init.cpp",
"bionic/iconv.cpp",
- "bionic/icu_wrappers.cpp",
"bionic/ifaddrs.cpp",
"bionic/inotify_init.cpp",
"bionic/ioctl.cpp",
@@ -1182,6 +1228,7 @@
whole_static_libs: [
"//external/llvm-libc:llvmlibc",
"libsystemproperties",
+ "libicu4x_bionic",
],
cppflags: ["-Wold-style-cast"],
@@ -1433,7 +1480,6 @@
"bionic/android_mallopt.cpp",
"bionic/gwp_asan_wrappers.cpp",
"bionic/heap_tagging.cpp",
- "bionic/icu.cpp",
"bionic/malloc_common.cpp",
"bionic/malloc_common_dynamic.cpp",
"bionic/android_profiling_dynamic.cpp",
@@ -1452,7 +1498,6 @@
"bionic/android_mallopt.cpp",
"bionic/gwp_asan_wrappers.cpp",
"bionic/heap_tagging.cpp",
- "bionic/icu_static.cpp",
"bionic/malloc_common.cpp",
"bionic/malloc_limit.cpp",
],
diff --git a/libc/bionic/icu.cpp b/libc/bionic/icu.cpp
deleted file mode 100644
index c11b9d6..0000000
--- a/libc/bionic/icu.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "private/icu.h"
-
-#include <dirent.h>
-#include <dlfcn.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <async_safe/log.h>
-
-static void* g_libicu_handle = nullptr;
-
-static bool __find_icu() {
- g_libicu_handle = dlopen("libicu.so", RTLD_LOCAL);
- if (g_libicu_handle == nullptr) {
- async_safe_format_log(ANDROID_LOG_ERROR, "bionic-icu", "couldn't open libicu.so: %s",
- dlerror());
- return false;
- }
-
- return true;
-}
-
-void* __find_icu_symbol(const char* symbol_name) {
- static bool found_icu = __find_icu();
- if (!found_icu) return nullptr;
-
- void* symbol = dlsym(g_libicu_handle, symbol_name);
- if (symbol == nullptr) {
- async_safe_format_log(ANDROID_LOG_ERROR, "bionic-icu", "couldn't find %s", symbol_name);
- }
- return symbol;
-}
diff --git a/libc/bionic/icu4x.rs b/libc/bionic/icu4x.rs
new file mode 100644
index 0000000..939ba2f
--- /dev/null
+++ b/libc/bionic/icu4x.rs
@@ -0,0 +1,98 @@
+// Copyright (C) 2025 The Android Open Source Project
+// SPDX-License-Identifier: Apache-2.0
+
+#![allow(missing_docs)] // Not particularly useful to document these thin wrappers
+
+//! This is a thin wrapper around ICU4X for use in Bionic
+
+use icu_casemap::CaseMapper;
+use icu_collections::codepointtrie::TrieValue;
+use icu_properties::props::*;
+use icu_properties::{CodePointMapData, CodePointSetData};
+
+#[no_mangle]
+pub extern "C" fn __icu4x_bionic_general_category(ch: u32) -> u8 {
+ CodePointMapData::<GeneralCategory>::new().get32(ch) as u8
+}
+
+#[no_mangle]
+pub extern "C" fn __icu4x_bionic_east_asian_width(ch: u32) -> u8 {
+ CodePointMapData::<EastAsianWidth>::new().get32(ch).to_u32() as u8
+}
+
+#[no_mangle]
+pub extern "C" fn __icu4x_bionic_hangul_syllable_type(ch: u32) -> u8 {
+ CodePointMapData::<HangulSyllableType>::new().get32(ch).to_u32() as u8
+}
+
+#[no_mangle]
+pub extern "C" fn __icu4x_bionic_is_alphabetic(ch: u32) -> bool {
+ CodePointSetData::new::<Alphabetic>().contains32(ch)
+}
+
+#[no_mangle]
+pub extern "C" fn __icu4x_bionic_is_default_ignorable_code_point(ch: u32) -> bool {
+ CodePointSetData::new::<DefaultIgnorableCodePoint>().contains32(ch)
+}
+
+#[no_mangle]
+pub extern "C" fn __icu4x_bionic_is_lowercase(ch: u32) -> bool {
+ CodePointSetData::new::<Lowercase>().contains32(ch)
+}
+
+#[no_mangle]
+pub extern "C" fn __icu4x_bionic_is_alnum(ch: u32) -> bool {
+ CodePointSetData::new::<Alnum>().contains32(ch)
+}
+
+#[no_mangle]
+pub extern "C" fn __icu4x_bionic_is_blank(ch: u32) -> bool {
+ CodePointSetData::new::<Blank>().contains32(ch)
+}
+
+#[no_mangle]
+pub extern "C" fn __icu4x_bionic_is_graph(ch: u32) -> bool {
+ CodePointSetData::new::<Graph>().contains32(ch)
+}
+
+#[no_mangle]
+pub extern "C" fn __icu4x_bionic_is_print(ch: u32) -> bool {
+ CodePointSetData::new::<Print>().contains32(ch)
+}
+
+#[no_mangle]
+pub extern "C" fn __icu4x_bionic_is_xdigit(ch: u32) -> bool {
+ CodePointSetData::new::<Xdigit>().contains32(ch)
+}
+
+#[no_mangle]
+pub extern "C" fn __icu4x_bionic_is_white_space(ch: u32) -> bool {
+ CodePointSetData::new::<WhiteSpace>().contains32(ch)
+}
+
+#[no_mangle]
+pub extern "C" fn __icu4x_bionic_is_uppercase(ch: u32) -> bool {
+ CodePointSetData::new::<Uppercase>().contains32(ch)
+}
+
+/// Convert a code point to uppercase
+#[no_mangle]
+pub extern "C" fn __icu4x_bionic_to_upper(ch: u32) -> u32 {
+ let Ok(ch) = char::try_from(ch) else {
+ return ch;
+ };
+ let cm = CaseMapper::new();
+
+ cm.simple_uppercase(ch) as u32
+}
+
+/// Convert a code point to lowercase
+#[no_mangle]
+pub extern "C" fn __icu4x_bionic_to_lower(ch: u32) -> u32 {
+ let Ok(ch) = char::try_from(ch) else {
+ return ch;
+ };
+ let cm = CaseMapper::new();
+
+ cm.simple_lowercase(ch) as u32
+}
diff --git a/libc/bionic/icu_static.cpp b/libc/bionic/icu_static.cpp
deleted file mode 100644
index cf24a38..0000000
--- a/libc/bionic/icu_static.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "private/icu.h"
-
-// We don't have dlopen/dlsym for static binaries yet.
-void* __find_icu_symbol(const char*) {
- return nullptr;
-}
diff --git a/libc/bionic/icu_wrappers.cpp b/libc/bionic/icu_wrappers.cpp
deleted file mode 100644
index 523f5a6..0000000
--- a/libc/bionic/icu_wrappers.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "private/icu.h"
-
-int8_t __icu_charType(wint_t wc) {
- typedef int8_t (*u_charType_t)(UChar32);
- static auto u_charType = reinterpret_cast<u_charType_t>(__find_icu_symbol("u_charType"));
- return u_charType ? u_charType(wc) : -1;
-}
-
-int32_t __icu_getIntPropertyValue(wint_t wc, UProperty property) {
- typedef int32_t (*u_getIntPropertyValue_t)(UChar32, UProperty);
- static auto u_getIntPropertyValue =
- reinterpret_cast<u_getIntPropertyValue_t>(__find_icu_symbol("u_getIntPropertyValue"));
- return u_getIntPropertyValue ? u_getIntPropertyValue(wc, property) : 0;
-}
diff --git a/libc/bionic/wctype.cpp b/libc/bionic/wctype.cpp
index 94597d9..8d0733d 100644
--- a/libc/bionic/wctype.cpp
+++ b/libc/bionic/wctype.cpp
@@ -35,7 +35,7 @@
#include <wchar.h>
#include "bionic/macros.h"
-#include "private/icu.h"
+#include "private/icu4x.h"
enum {
WC_TYPE_INVALID = 0,
@@ -54,60 +54,65 @@
WC_TYPE_MAX
};
-static u_hasBinaryProperty_t __find_u_hasBinaryProperty() {
- static auto u_hasBinaryProperty =
- reinterpret_cast<u_hasBinaryProperty_t>(__find_icu_symbol("u_hasBinaryProperty"));
- return u_hasBinaryProperty;
+#define DO_ISW(prop_name, narrow_fn) \
+ if (__predict_true(wc < 0x80)) { \
+ return narrow_fn(wc); \
+ } \
+ return __icu4x_bionic_is_##prop_name(wc);
+
+int iswalnum(wint_t wc) {
+ DO_ISW(alnum, isalnum);
}
-
-#define DO_ISW(icu_constant, narrow_fn) \
- u_hasBinaryProperty_t u_hasBinaryProperty; \
- if (__predict_true(wc < 0x80) || \
- !(u_hasBinaryProperty = __find_u_hasBinaryProperty())) { \
- return narrow_fn(wc); \
- } \
- return u_hasBinaryProperty(wc, icu_constant); \
-
-int iswalnum(wint_t wc) { DO_ISW(UCHAR_POSIX_ALNUM, isalnum); }
__strong_alias(iswalnum_l, iswalnum);
-int iswalpha(wint_t wc) { DO_ISW(UCHAR_ALPHABETIC, isalpha); }
+int iswalpha(wint_t wc) {
+ DO_ISW(alphabetic, isalpha);
+}
__strong_alias(iswalpha_l, iswalpha);
-int iswblank(wint_t wc) { DO_ISW(UCHAR_POSIX_BLANK, isblank); }
+int iswblank(wint_t wc) {
+ DO_ISW(blank, isblank);
+}
__strong_alias(iswblank_l, iswblank);
-int iswgraph(wint_t wc) { DO_ISW(UCHAR_POSIX_GRAPH, isgraph); }
+int iswgraph(wint_t wc) {
+ DO_ISW(graph, isgraph);
+}
__strong_alias(iswgraph_l, iswgraph);
-int iswlower(wint_t wc) { DO_ISW(UCHAR_LOWERCASE, islower); }
+int iswlower(wint_t wc) {
+ DO_ISW(lowercase, islower);
+}
__strong_alias(iswlower_l, iswlower);
-int iswprint(wint_t wc) { DO_ISW(UCHAR_POSIX_PRINT, isprint); }
+int iswprint(wint_t wc) {
+ DO_ISW(print, isprint);
+}
__strong_alias(iswprint_l, iswprint);
-int iswspace(wint_t wc) { DO_ISW(UCHAR_WHITE_SPACE, isspace); }
+int iswspace(wint_t wc) {
+ DO_ISW(white_space, isspace);
+}
__strong_alias(iswspace_l, iswspace);
-int iswupper(wint_t wc) { DO_ISW(UCHAR_UPPERCASE, isupper); }
+int iswupper(wint_t wc) {
+ DO_ISW(uppercase, isupper);
+}
__strong_alias(iswupper_l, iswupper);
-int iswxdigit(wint_t wc) { DO_ISW(UCHAR_POSIX_XDIGIT, isxdigit); }
+int iswxdigit(wint_t wc) {
+ DO_ISW(xdigit, isxdigit);
+}
__strong_alias(iswxdigit_l, iswxdigit);
int iswcntrl(wint_t wc) {
if (wc < 0x80) return iscntrl(wc);
- typedef int8_t (*FnT)(UChar32);
- static auto u_charType = reinterpret_cast<FnT>(__find_icu_symbol("u_charType"));
- return u_charType ? (u_charType(wc) == U_CONTROL_CHAR) : iscntrl(wc);
+ return __icu4x_bionic_general_category(wc) == U_CONTROL_CHAR;
}
__strong_alias(iswcntrl_l, iswcntrl);
int iswdigit(wint_t wc) {
if (wc < 0x80) return isdigit(wc);
- typedef UBool (*FnT)(UChar32);
- static auto u_isdigit = reinterpret_cast<FnT>(__find_icu_symbol("u_isdigit"));
- return u_isdigit ? u_isdigit(wc) : isdigit(wc);
+ return __icu4x_bionic_general_category(wc) == U_DECIMAL_NUMBER;
}
__strong_alias(iswdigit_l, iswdigit);
int iswpunct(wint_t wc) {
if (wc < 0x80) return ispunct(wc);
- typedef UBool (*FnT)(UChar32);
- static auto u_ispunct = reinterpret_cast<FnT>(__find_icu_symbol("u_ispunct"));
- return u_ispunct ? u_ispunct(wc) : ispunct(wc);
+ int8_t chartype = __icu4x_bionic_general_category(wc);
+ return chartype >= U_DASH_PUNCTUATION && chartype <= U_OTHER_PUNCTUATION;
}
__strong_alias(iswpunct_l, iswpunct);
@@ -124,18 +129,14 @@
wint_t towlower(wint_t wc) {
if (wc < 0x80) return tolower(wc);
- typedef UChar32 (*FnT)(UChar32);
- static auto u_tolower = reinterpret_cast<FnT>(__find_icu_symbol("u_tolower"));
- return u_tolower ? u_tolower(wc) : tolower(wc);
+ return __icu4x_bionic_to_lower(wc);
}
__strong_alias(towlower_l, towlower);
wint_t towupper(wint_t wc) {
if (wc < 0x80) return toupper(wc);
- typedef UChar32 (*FnT)(UChar32);
- static auto u_toupper = reinterpret_cast<FnT>(__find_icu_symbol("u_toupper"));
- return u_toupper ? u_toupper(wc) : toupper(wc);
+ return __icu4x_bionic_to_upper(wc);
}
__strong_alias(towupper_l, towupper);
diff --git a/libc/bionic/wcwidth.cpp b/libc/bionic/wcwidth.cpp
index 776321f..633d83e 100644
--- a/libc/bionic/wcwidth.cpp
+++ b/libc/bionic/wcwidth.cpp
@@ -28,7 +28,7 @@
#include <wchar.h>
-#include "private/icu.h"
+#include "private/icu4x.h"
int wcwidth(wchar_t wc) {
// Fast-path ASCII.
@@ -44,38 +44,33 @@
// pretty arbitrary. See https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c for more details.
// Fancy unicode control characters?
- switch (__icu_charType(wc)) {
- case -1:
- // No icu4c available; give up.
- return -1;
- case U_CONTROL_CHAR:
- return -1;
- case U_NON_SPACING_MARK:
- case U_ENCLOSING_MARK:
- return 0;
- case U_FORMAT_CHAR:
- // A special case for soft hyphen (U+00AD) to match historical practice.
- // See the tests for more commentary.
- return (wc == 0x00ad) ? 1 : 0;
+ switch (__icu4x_bionic_general_category(wc)) {
+ case U_CONTROL_CHAR:
+ return -1;
+ case U_NON_SPACING_MARK:
+ case U_ENCLOSING_MARK:
+ return 0;
+ case U_FORMAT_CHAR:
+ // A special case for soft hyphen (U+00AD) to match historical practice.
+ // See the tests for more commentary.
+ return (wc == 0x00ad) ? 1 : 0;
}
// Medial and final jamo render as zero width when used correctly,
// so we handle them specially rather than relying on East Asian Width.
- switch (__icu_getIntPropertyValue(wc, UCHAR_HANGUL_SYLLABLE_TYPE)) {
- case U_HST_VOWEL_JAMO:
- case U_HST_TRAILING_JAMO:
- return 0;
- case U_HST_LEADING_JAMO:
- case U_HST_LV_SYLLABLE:
- case U_HST_LVT_SYLLABLE:
- return 2;
+ switch (__icu4x_bionic_hangul_syllable_type(wc)) {
+ case U_HST_VOWEL_JAMO:
+ case U_HST_TRAILING_JAMO:
+ return 0;
+ case U_HST_LEADING_JAMO:
+ case U_HST_LV_SYLLABLE:
+ case U_HST_LVT_SYLLABLE:
+ return 2;
}
// Hangeul choseong filler U+115F is default ignorable, so we check default
// ignorability only after we've already handled Hangeul jamo above.
- static auto u_hasBinaryProperty =
- reinterpret_cast<u_hasBinaryProperty_t>(__find_icu_symbol("u_hasBinaryProperty"));
- if (u_hasBinaryProperty && u_hasBinaryProperty(wc, UCHAR_DEFAULT_IGNORABLE_CODE_POINT)) return 0;
+ if (__icu4x_bionic_is_default_ignorable_code_point(wc)) return 0;
// A few weird special cases where EastAsianWidth is not helpful for us.
if (wc >= 0x3248 && wc <= 0x4dff) {
@@ -88,15 +83,15 @@
// The EastAsianWidth property is at least defined by the Unicode standard!
// https://www.unicode.org/reports/tr11/
- switch (__icu_getIntPropertyValue(wc, UCHAR_EAST_ASIAN_WIDTH)) {
- case U_EA_AMBIGUOUS:
- case U_EA_HALFWIDTH:
- case U_EA_NARROW:
- case U_EA_NEUTRAL:
- return 1;
- case U_EA_FULLWIDTH:
- case U_EA_WIDE:
- return 2;
+ switch (__icu4x_bionic_east_asian_width(wc)) {
+ case U_EA_AMBIGUOUS:
+ case U_EA_HALFWIDTH:
+ case U_EA_NARROW:
+ case U_EA_NEUTRAL:
+ return 1;
+ case U_EA_FULLWIDTH:
+ case U_EA_WIDE:
+ return 2;
}
return 0;
diff --git a/libc/private/icu.h b/libc/private/icu4x.h
similarity index 68%
rename from libc/private/icu.h
rename to libc/private/icu4x.h
index 8e4aa80..8b7e1d0 100644
--- a/libc/private/icu.h
+++ b/libc/private/icu4x.h
@@ -26,38 +26,20 @@
* SUCH DAMAGE.
*/
-#ifndef _PRIVATE_ICU_H
-#define _PRIVATE_ICU_H
+#pragma once
+#include <ctype.h>
#include <stdint.h>
#include <wchar.h>
-typedef int8_t UBool;
-#define FALSE 0
-#define TRUE 1
-
-typedef int32_t UChar32;
-
-enum UProperty {
- UCHAR_ALPHABETIC = 0,
- UCHAR_DEFAULT_IGNORABLE_CODE_POINT = 5,
- UCHAR_LOWERCASE = 22,
- UCHAR_POSIX_ALNUM = 44,
- UCHAR_POSIX_BLANK = 45,
- UCHAR_POSIX_GRAPH = 46,
- UCHAR_POSIX_PRINT = 47,
- UCHAR_POSIX_XDIGIT = 48,
- UCHAR_UPPERCASE = 30,
- UCHAR_WHITE_SPACE = 31,
- UCHAR_EAST_ASIAN_WIDTH = 0x1004,
- UCHAR_HANGUL_SYLLABLE_TYPE = 0x100b,
-};
-
enum UCharCategory {
U_NON_SPACING_MARK = 6,
U_ENCLOSING_MARK = 7,
+ U_DECIMAL_NUMBER = 9,
U_CONTROL_CHAR = 15,
U_FORMAT_CHAR = 16,
+ U_DASH_PUNCTUATION = 19,
+ U_OTHER_PUNCTUATION = 23,
};
enum UEastAsianWidth {
@@ -78,11 +60,24 @@
U_HST_LVT_SYLLABLE,
};
-int8_t __icu_charType(wint_t wc);
-int32_t __icu_getIntPropertyValue(wint_t wc, UProperty property);
+__BEGIN_DECLS
-typedef UBool (*u_hasBinaryProperty_t)(UChar32, UProperty);
+uint8_t __icu4x_bionic_general_category(uint32_t cp);
+uint8_t __icu4x_bionic_east_asian_width(uint32_t cp);
+uint8_t __icu4x_bionic_hangul_syllable_type(uint32_t cp);
-void* __find_icu_symbol(const char* symbol_name);
+bool __icu4x_bionic_is_alphabetic(uint32_t cp);
+bool __icu4x_bionic_is_default_ignorable_code_point(uint32_t cp);
+bool __icu4x_bionic_is_lowercase(uint32_t cp);
+bool __icu4x_bionic_is_alnum(uint32_t cp);
+bool __icu4x_bionic_is_blank(uint32_t cp);
+bool __icu4x_bionic_is_graph(uint32_t cp);
+bool __icu4x_bionic_is_print(uint32_t cp);
+bool __icu4x_bionic_is_xdigit(uint32_t cp);
+bool __icu4x_bionic_is_white_space(uint32_t cp);
+bool __icu4x_bionic_is_uppercase(uint32_t cp);
-#endif // _PRIVATE_ICU_H
+uint32_t __icu4x_bionic_to_upper(uint32_t ch);
+uint32_t __icu4x_bionic_to_lower(uint32_t ch);
+
+__END_DECLS
diff --git a/tests/utils.h b/tests/utils.h
index 4740e59..3b4f2a9 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -65,12 +65,6 @@
#define KNOWN_FAILURE_ON_BIONIC(x) x
#endif
-// bionic's dlsym doesn't work in static binaries, so we can't access icu,
-// so any unicode test case will fail.
-static inline bool have_dl() {
- return (dlopen("libc.so", 0) != nullptr);
-}
-
static inline bool running_with_native_bridge() {
#if defined(__BIONIC__)
static const prop_info* pi = __system_property_find("ro.dalvik.vm.isa." ABI_STRING);
diff --git a/tests/wchar_test.cpp b/tests/wchar_test.cpp
index ba2a4d8..c76f800 100644
--- a/tests/wchar_test.cpp
+++ b/tests/wchar_test.cpp
@@ -1062,16 +1062,12 @@
}
TEST(wchar, wcwidth_non_spacing_and_enclosing_marks_and_format) {
- if (!have_dl()) return;
-
EXPECT_EQ(0, wcwidth(0x0300)); // Combining grave.
EXPECT_EQ(0, wcwidth(0x20dd)); // Combining enclosing circle.
EXPECT_EQ(0, wcwidth(0x200b)); // Zero width space.
}
TEST(wchar, wcwidth_non_spacing_special_cases) {
- if (!have_dl()) return;
-
// U+00AD is a soft hyphen, which normally shouldn't be rendered at all.
// I think the assumption here is that you elide the soft hyphen character
// completely in that case, and never call wcwidth() if you don't want to
@@ -1100,8 +1096,6 @@
}
TEST(wchar, wcwidth_cjk) {
- if (!have_dl()) return;
-
EXPECT_EQ(2, wcwidth(0x4e00)); // Start of CJK unified block.
EXPECT_EQ(2, wcwidth(0x9fff)); // End of CJK unified block.
EXPECT_EQ(2, wcwidth(0x3400)); // Start of CJK extension A block.
@@ -1111,16 +1105,12 @@
}
TEST(wchar, wcwidth_korean_combining_jamo) {
- if (!have_dl()) return;
-
AssertWcwidthRange(0x1160, 0x1200, 0); // Original range.
EXPECT_EQ(0, wcwidth(0xd7b0)); // Newer.
EXPECT_EQ(0, wcwidth(0xd7cb));
}
TEST(wchar, wcwidth_korean_jeongeul_syllables) {
- if (!have_dl()) return;
-
EXPECT_EQ(2, wcwidth(0xac00)); // Start of block.
EXPECT_EQ(2, wcwidth(0xd7a3)); // End of defined code points as of Unicode 15.
@@ -1129,8 +1119,6 @@
}
TEST(wchar, wcwidth_kana) {
- if (!have_dl()) return;
-
// Hiragana (most, not undefined).
AssertWcwidthRange(0x3041, 0x3097, 2);
// Katakana.
@@ -1138,30 +1126,22 @@
}
TEST(wchar, wcwidth_circled_two_digit_cjk) {
- if (!have_dl()) return;
-
// Circled two-digit CJK "speed sign" numbers are wide,
// though EastAsianWidth is ambiguous.
AssertWcwidthRange(0x3248, 0x3250, 2);
}
TEST(wchar, wcwidth_hexagrams) {
- if (!have_dl()) return;
-
// Hexagrams are wide, though EastAsianWidth is neutral.
AssertWcwidthRange(0x4dc0, 0x4e00, 2);
}
TEST(wchar, wcwidth_default_ignorables) {
- if (!have_dl()) return;
-
AssertWcwidthRange(0xfff0, 0xfff8, 0); // Unassigned by default ignorable.
EXPECT_EQ(0, wcwidth(0xe0000)); // ...through 0xe0fff.
}
TEST(wchar, wcwidth_hangeul_compatibility_jamo) {
- if (!have_dl()) return;
-
// These are actually the *compatibility* jamo code points, *not* the regular
// jamo code points (U+1100-U+11FF) using a jungseong filler. If you use the
// Android IME to type any of these, you get these code points.
diff --git a/tests/wctype_test.cpp b/tests/wctype_test.cpp
index f4b7a8f..1a2bbc1 100644
--- a/tests/wctype_test.cpp
+++ b/tests/wctype_test.cpp
@@ -37,20 +37,14 @@
for (const wchar_t* p = trues; *p; ++p) {
const wchar_t val_ch = *p;
const int val_int = static_cast<int>(val_ch);
- if (!have_dl() && val_ch > 0x7f) {
- GTEST_LOG_(INFO) << "skipping unicode test " << val_int;
- continue;
- }
+
EXPECT_TRUE(fn(val_ch)) << val_int;
EXPECT_TRUE(fn_l(val_ch, l.l)) << val_int;
}
for (const wchar_t* p = falses; *p; ++p) {
const wchar_t val_ch = *p;
const int val_int = static_cast<int>(val_ch);
- if (!have_dl() && val_ch > 0x7f) {
- GTEST_LOG_(INFO) << "skipping unicode test " << val_int;
- continue;
- }
+
EXPECT_FALSE(fn(val_ch)) << val_int;
EXPECT_FALSE(fn_l(val_ch, l.l)) << val_int;
}
@@ -111,14 +105,10 @@
EXPECT_EQ(wint_t('a'), towlower(L'A'));
EXPECT_EQ(wint_t('z'), towlower(L'z'));
EXPECT_EQ(wint_t('z'), towlower(L'Z'));
- if (have_dl()) {
- EXPECT_EQ(wint_t(L'ç'), towlower(L'ç'));
- EXPECT_EQ(wint_t(L'ç'), towlower(L'Ç'));
- EXPECT_EQ(wint_t(L'δ'), towlower(L'δ'));
- EXPECT_EQ(wint_t(L'δ'), towlower(L'Δ'));
- } else {
- GTEST_SKIP() << "icu not available";
- }
+ EXPECT_EQ(wint_t(L'ç'), towlower(L'ç'));
+ EXPECT_EQ(wint_t(L'ç'), towlower(L'Ç'));
+ EXPECT_EQ(wint_t(L'δ'), towlower(L'δ'));
+ EXPECT_EQ(wint_t(L'δ'), towlower(L'Δ'));
}
TEST(wctype, towlower_l) {
@@ -129,14 +119,10 @@
EXPECT_EQ(wint_t('a'), towlower_l(L'A', l.l));
EXPECT_EQ(wint_t('z'), towlower_l(L'z', l.l));
EXPECT_EQ(wint_t('z'), towlower_l(L'Z', l.l));
- if (have_dl()) {
- EXPECT_EQ(wint_t(L'ç'), towlower_l(L'ç', l.l));
- EXPECT_EQ(wint_t(L'ç'), towlower_l(L'Ç', l.l));
- EXPECT_EQ(wint_t(L'δ'), towlower_l(L'δ', l.l));
- EXPECT_EQ(wint_t(L'δ'), towlower_l(L'Δ', l.l));
- } else {
- GTEST_SKIP() << "icu not available";
- }
+ EXPECT_EQ(wint_t(L'ç'), towlower_l(L'ç', l.l));
+ EXPECT_EQ(wint_t(L'ç'), towlower_l(L'Ç', l.l));
+ EXPECT_EQ(wint_t(L'δ'), towlower_l(L'δ', l.l));
+ EXPECT_EQ(wint_t(L'δ'), towlower_l(L'Δ', l.l));
}
TEST(wctype, towupper) {
@@ -146,14 +132,10 @@
EXPECT_EQ(wint_t('A'), towupper(L'A'));
EXPECT_EQ(wint_t('Z'), towupper(L'z'));
EXPECT_EQ(wint_t('Z'), towupper(L'Z'));
- if (have_dl()) {
- EXPECT_EQ(wint_t(L'Ç'), towupper(L'ç'));
- EXPECT_EQ(wint_t(L'Ç'), towupper(L'Ç'));
- EXPECT_EQ(wint_t(L'Δ'), towupper(L'δ'));
- EXPECT_EQ(wint_t(L'Δ'), towupper(L'Δ'));
- } else {
- GTEST_SKIP() << "icu not available";
- }
+ EXPECT_EQ(wint_t(L'Ç'), towupper(L'ç'));
+ EXPECT_EQ(wint_t(L'Ç'), towupper(L'Ç'));
+ EXPECT_EQ(wint_t(L'Δ'), towupper(L'δ'));
+ EXPECT_EQ(wint_t(L'Δ'), towupper(L'Δ'));
}
TEST(wctype, towupper_l) {
@@ -164,14 +146,10 @@
EXPECT_EQ(wint_t('A'), towupper_l(L'A', l.l));
EXPECT_EQ(wint_t('Z'), towupper_l(L'z', l.l));
EXPECT_EQ(wint_t('Z'), towupper_l(L'Z', l.l));
- if (have_dl()) {
- EXPECT_EQ(wint_t(L'Ç'), towupper_l(L'ç', l.l));
- EXPECT_EQ(wint_t(L'Ç'), towupper_l(L'Ç', l.l));
- EXPECT_EQ(wint_t(L'Δ'), towupper_l(L'δ', l.l));
- EXPECT_EQ(wint_t(L'Δ'), towupper_l(L'Δ', l.l));
- } else {
- GTEST_SKIP() << "icu not available";
- }
+ EXPECT_EQ(wint_t(L'Ç'), towupper_l(L'ç', l.l));
+ EXPECT_EQ(wint_t(L'Ç'), towupper_l(L'Ç', l.l));
+ EXPECT_EQ(wint_t(L'Δ'), towupper_l(L'δ', l.l));
+ EXPECT_EQ(wint_t(L'Δ'), towupper_l(L'Δ', l.l));
}
TEST(wctype, wctype) {