资源捆绑键

我们用来存储密钥的字节数实际上是数据的重要组成部分,正如您可以从右侧的信息中看到的那样。因此,瘦身是值得的。马库斯和我对此进行了头脑风暴,并有以下想法。

状态:大部分在ICU 4.4中实施。

缩小尺寸的想法

公用密钥存储

我们使用最常用的密钥创建一个通用的KEY res文件。

我们可以引入一个新的TABLE类型,或者只需增加formatVersion,并使用两个现有表类型中的每一个表类型的顶部位来区分本地键和池键。(最好能够尽可能多地使用16位密钥偏移量;测试表明,此偏移量的大小有显著差异。)✓(4.4:用于区分本地密钥与池密钥的阈值)

此表类型中的键偏移量可以来自文件,也可以来自公共key res文件。如果偏移量小于MAX_KEY,则从KEY文件中取出;如果不是,则使用offset-MAX_KEY从当前文件中获取密钥。MAX_KEY位于KEY文件中。

运行genrb两次。我们第一次提供一个特殊参数来构建KEY文件。我们收集所有密钥数据,并构建key res文件,其中只包含唯一的密钥。KEY res文件还包含MAX_KEY值。(池.res)

    • 我们可以通过只运行公共文件或不存储只出现在单个文件中的密钥来限制这一点。但我不认为我们真的需要担心这个。

第二次运行genrb时,我们提供KEY res文件作为输入参数。每当TABLE中的键出现在key文件中时,我们都会使用新的TABLE类型。

KEY res文件可以是root.res本身,也可以是单独的新文件。使用root.res,我们不需要再加载另一个文件,但如果不更新语言环境层次结构中的所有其他包,就无法更新根包。(pool.res与root.res分开)

请注意,只要优化了任何其他res文件以使用它,KEY文件就必须是ICU的一部分。旧res文件或未使用它优化的res文件仍会像以前一样工作。

从原型来看,这将节省约420kB使用两个pool.res文件时(在后缀共享之上,请参阅下文),一个用于区域设置数据,另一个用于排序规则数据。

问题

在ASCII和EBCDIC之间交换资源束数据时,KEY文件必须存在,因为表中的键按二进制字符串顺序排序,在ASCII和EBCDIC之间变化。这可能是个问题。

一种解决方法是始终按ASCII顺序对字符串进行排序。在EBCDIC平台上,查找可以在执行二进制搜索之前将密钥交换到堆栈缓冲区中。对于病态的长密钥,有几个选项:

    • 这可能需要堆分配,或者

    • 在每次字符串比较期间进行逐字符交换,或

    • 将最大密钥长度(在genrb和运行时代码中)限制为一些合理的数字,如63或127个字符。如果密钥太大,它可能只返回找不到; 如果有人试图编译过长的密钥,genrb可能会生成错误。

(4.4:ASCII顺序,在EBCDIC上,在字符串比较期间进行逐字符交换)

理论上,我们可以对所有平台强制使用charset-independent密钥排序顺序,但可能不值得使用与ASCII不同的顺序。

从理论上讲,我们可以要求运行时代码读取表中的所有键并进行复制和排序,或者构建一个哈希表,而根本不需要对二进制数据中的键进行排序。这总是需要一些开销和堆分配,类似于字符串值压缩。

对所有平台使用相同的排序顺序(或不使用)将大大简化资源包的交换,因为这样可以避免对表进行重新排序。

选项

密钥文件应该已经很小了(17Kish-见右栏),不值得花大力气来减少它。但这里有一些想法,以备我们考虑。

    1. 当我们构建Key文件时,我们可以有后缀字符串共享。也就是说,如果“abc<null>”位于偏移量57,我们不需要同时存储“bc<null>>”;我们可以使用偏移量58。这样可以节省大约7.5%的文件大小:1.3Kb。

    2. 。。。

单文件密钥存储

或者,尝试在单个文件中进行压缩。

    1. 避免重复键✓

    2. 使用后缀共享(见上文)(包括重复消除)。

      • 已实施,节省约220亿字节超过660束!

    3. 将短字符串压缩到偏移量中。想法是使偏移量为32位,并将最多5个6位字符打包到其中。顶部位=1表示打包格式。

      • 原型,增加660包中的数据量增加了33kB,因为所有表都从16位偏移量增加到32位偏移量,这比节省的数据量还要多。

      • 已拒绝

    4. 使用较短的键,以便大多数键适合打包形式。这意味着在运行时代码中更改LDML2ICUConverter和硬编码键。(截至ICU 4.4尚未实施)

在压缩形式中,我们可以有a-zA-Z0-9和两个标点符号。我们应该将冒号“:”编码为0,因为前导字符或尾随字符的6位代码中不能有0(否则我们必须显式编码长度),并且冒号不会以键首字符或键尾字符的形式出现。我们可以将下划线“_”编码为1,后跟字母和数字。

注意:ICU API可以返回键字符串指针(尽管更常见的是仅使用键进行查找)。对于压缩密钥,我们必须编写一个与 “字符串”页面.

非alnum关键字符的统计信息,来自genrb在几乎所有的ICU-4.2版本中处理所有660个资源包:

***非alnum密钥字符(密钥中的任何位置):

“:”=0x3a:12047

'_'=0x5f:4595

“-”=0x2d:543

“%”=0x25:248

“”=0x20:208

“/”=0x2f:25

“+”=0x2b:24

'.' = 0x2e:9

“)”=0x29:3

'('=0x28:3

***非alnum密钥字符作为第一个密钥字符:

“_”=0x5f:154

“-”=0x2d:134

“%”=0x25:124

***非alnum密钥字符作为最后一个密钥字符:

“_”=0x5f:154

“)”=0x29:3

背景信息

键用于TABLE类型。实际值有一个16位偏移量,以null结尾。它们当前未共享。

数据很重要。例如,在ICU4J中,快速测试显示以下内容:

总数:2409

总大小:728764字节

唯一大小总计:17187字节

在每种情况下都有一个终止null。

以下是顶级竞争者:

计数键

13780 0

13648 1

6910秒

5551其他

4507个

2698升

1676拉德

1324 2

1280 3

1251个

953 4

951 5

951 6

921多个

871磅

7.32亿

695 7

695 8

693 9

693 10

692 11

563 dn

539铜

531天

508版本

471年

399宽

385缩写

356不锈钢

317格式

313日历

294标准差

263格雷戈里亚人

以下是关键帧中字符的频率:

1 43655电子

2 40497页

3 28254转

425287欧

524928牛顿

6 23643吨

7 21948英寸

8 21939 1

9 19295 c

10 18541秒

11 17717 0

1216004米

13 15452升

14 13024小时

15 12617个

1611.12亿

17 10813天

18 10215 : !阿尔法努姆

19 10140 u

20 7780秒

21 7401年

22 7161克

东经23 6720

24 6498像素

25 6273天

26 6170亿

27 6105卢比

28 6104摄氏度

29 5717千

30 5662吨

31 5418亿

32 5374升

北纬33 5284

34 5201克

35 4908便士

36 4891 2

37 4827页

38 4638千

39 4007瓦

40 3997 3

库存41 3712件

42 3495升

43 3428 5

44 3383高

45 3298 4

46 3285华氏度

47 3223 _ !阿尔法努姆

48 3128欧

49 2853 6

50 2801伏

51 2702赫兹

52 2682 9

53 2534伏

54 2467 7

55 2350年

56 2318 8

57 1891瓦

58 1876赫兹

59 1817倍

60 1519焦耳

61 1197问

62 1126焦耳

63 978 x

64 700平方米

65 421 - !阿尔法努姆

66 164 % !阿尔法努姆