排序规则资源束

ICU数据的很大一部分位于整理资源包中。在一个几乎是ICU 4.2的构建中,它们大约占15.2MB总数据大小的四分之一。

genrb识别一个排序规则裁剪规则,从中创建一个Collator,并将其二进制数据添加到资源包中。

缩小尺寸的想法

二进制排序数据

我们有几十个文件产生14kB或更大二进制文件的非常简单的规则。可以省略这些二进制文件,如果运行时代码具有构建器代码和必要的数据文件(尤其是invuca.icu)。这可以使用现有的genrb命令行选项在makefile中手动完成,或者可以根据规则字符串的长度或复杂性决定是否存储二进制文件。构建(makefile)总是可以提供这个新选项,而genrb管理何时包含二进制文件。这会节省约800kB。成本:运行时代码需要包括collation builder和invuca.icu,collator加载速度较慢,堆内存使用率较高。

我们可以检查和修改排序二进制文件的数据格式。

拉丁语-1

使用拉丁语-1的数据,但其他字符很少,二进制数据的大小应该更接近6或7kB非14kB

我相信,我们将拉丁语-1的数据从UCA表复制到裁剪表中,用于将回退到UCA的拉丁语-1字符。

我相信排序运行时代码已经分配并填充了一个拉丁语-1 CE表,该表会根据运行时属性进行更改。如果是这样,那么从UCA表复制拉丁语-1数据可能是不必要的

如果没有拉丁语-1范围之外的数据,那么我们可能不需要UTrie完全。或者,我们可以有一个固定的UTrie/UTrie2索引数组,在只定制特定字符集时使用,在这种情况下,我们不存储完整的UTrie(2),而只存储其data32数组。问题:如果我们采用欧洲排序规则(EOR),并且他们裁剪了许多非拉丁语-1字符,那么许多裁剪将不适合这些优化。

中日韩

调查CJK数据在UTrie中的密度或稀疏程度。是否有机会使用不同的、特定于CJK的数据结构?例如,仅存储16位主权重用于汉字?(对于适合的字符,使用单独的16位UTrie;对于Unihan和/或Hangul,使用平面表?)

我们也许能够总是将CE的顶部和底部16位存储在两次单独的16位值尝试。这将消除对大小优化的字符范围以及是否有特殊trie的特殊检查,并且在由主要差异决定的字符串比较中不应影响性能。如果大多数CE都有二级和三级权重的默认值,那么底部-16 trie将非常小。成本:生成排序键会慢一点,但我们可能更关心排序键长度(不会改变)。我们必须始终存储两次试穿,这会增加开销,可能会抵消小裁缝的节省。

注:CLDR 1.9/ICU 4.6在多个CJK裁剪中裁剪了更多角色。虽然上一个规则的范围再次变大,但一些裁剪仍然需要3字节的主权重。

概述

除了CE映射(主trie、收缩和扩展表),我们还有用于某些操作的额外数据,如用于优化向后迭代的位集。我们可以省略这些并在加载时构建它们。或者我们可以仅当它们与UCA数据中的相同时才省略它们,运行时可以指向那里。

也许我们可以将小而稀疏的二进制结果(排序规则生成器的输出)存储在简单数据格式这比完整形式小得多,例如从字符串到CE序列的映射列表。在运行时,我们需要UTrie2构建器和足够的代码来从预计算数据构建扩展和收缩表,但不是完整的排序规则构建器,也不是invuca.icu数据、规范等价代码等。我们可以将此数据存储在单独的束键下,以避免格式版本控制。我们甚至可以将这些数据存储在资源项树(与CE intvector并行的字符串数组等)中,而不是存储在自定义二进制文件中。这可能会保存大量数据。成本:运行时代码需要UTrie和收缩/扩展表构建器,collator的加载速度较慢,堆内存使用率更高。

弗拉基米尔的想法:对于使用小字体的语言(例如西里尔文或泰语),我们可以使用短的线性表格将单个范围的代码点映射到CE,以避免trie。或者可以使用两个或三个范围,尤其是其中一个位于冗余拉丁语-1中,并且仅在加载时用于构建特殊拉丁语-1表时。在运行时直接使用线性表,而不是在加载时构建trie。成本:尽管如此,以规模换取性能它实际上可能更快如果collator在线性范围内看到字符,则比trie更重要。它只是在这个字符的where-is-the-data链中添加了另一个测试。探索使用函数指针或带有虚拟函数的C++子类在如何存储和访问CE的变量之间切换?

注释

我们应该在从旧UTrie切换到新UTrie2的同时进行不兼容的更改,这无论如何都需要主版本更改

定制规则字符串

对于某些规则字符串,ICU可以采用CLDR的新语法,用于更紧凑地表示字符序列,其中主要差异来自重置点。这将大大减少CJK规则字符串-减少50%以上!我们必须试一试才能得到准确的数字。

  • 在ICU完成4.6

    • 我们甚至可以在这个语法中使用特殊字符来进一步连续字符的缩写序列; 例如,我们可以将<2000020001200220003>缩写为<20000F802>,其中U+F802表示“前一个之后有3个连续的代码点”。(非字符或PUA可能合适。)

我们有三个几乎相同的Unihan排序规则,在ja/ko/zh排序规则包中。genrb可以自动检测它们的大型通用后缀(以“&[last regular]”开头),将其存储在一个单独的coll/unihan.res捆绑包中,并用类似“[unihan]”的东西替换CJK捆绑包中的后缀。成本:在运行时,当有人请求unihan规则字符串(这种情况很少见)时,需要从不同的部分和公共后缀中分配/连接该字符串。

    • Mark有一个更好的主意:CLDR和ICU都应该将规则内语法添加到导入另一个规则字符串。它应该能够引用另一个捆绑包中的字符串。这应该用于欧洲排序规则(EOR)和大型Unihan规则字符串。ICU API应该返回包括该导入语法的规则字符串,而不将其替换为引用的字符串值。旧代码将无法解析此内容,但我们不保证不添加语法。因为规则字符串仍然是内存映射的,所以没有运行时开销。排序规则解析器可以临时构建完整的字符串,或者更好的方法是只加载子字符串并临时分支到其中。

  • 在ICU完成4.6

我们可以使用ICU 1.8之前的语法共';'和',',而不是“<<”和“<<<”。(请参见http://userguide.icu-project.org/collation/customization)

是否可行省略规则字符串并在运行时生成它们,按需提供?这将删除ICU数据中所有非常大的字符串。(马克对如何做到这一点有一些想法。我们至少必须为重置点存储一些数据。可能只值得为大型规则进行操作。)

我们可以分开存放,平行树排序规则资源包:一个只包含二进制文件,另一个仅包含规则字符串。很容易不包括其中之一。

    • 大型规则字符串可以是拉链压缩它可能比 页面;一个文件用于所有zip压缩的规则字符串,或zip压缩整个绑定内容,或zip-compress单个大字符串值(后者可能是最简单的)。

    • 使用ICU 4.2的coll/zh.txt进行的实验结果,其中主要包含裁剪规则。

      • 使用原始UTF-16字符串存储和重复消除,字符串值为577kB。

      • 用简单的 压缩,这些被减少到412kB。

      • txt文件的通用压缩将其压缩为:zip/gzip:224kB,bz2:211kB,7zip-fast:175kB,7 zip-normal:126kB

      • 更复杂的压缩方法需要数MB的堆内存进行解压缩。

其他

这个统汉字排序规则数据很大,在三个CJK排序资源包有没有办法共享公共数据?

我们有超过180个空文件“所以genrb不会发出警告”(就像回退警告一样)。删除这些将节省约10kB。我们必须重新设计如何确定在排序中是否支持语言/地区。