| * revise data structures for lookup | |
| See "5.1.2 Multi-stage tables" in Unicode standard for some hints | |
| https://www.unicode.org/versions/Unicode17.0.0/core-spec/chapter-5/ | |
| * look at how it is done in gnulib/libunistring. e.g. bitmap_lookup | |
| in unictype/bitmap.h or combining_class in unictype/combining_class.c. | |
| gnulib/lib/gen-uni-tables.c (in gnulib git repo) for generating C source | |
| code with data literals, and especially gnulib/lib/unictype/3level.h. | |
| * most codepoints only translate to a single collation unit, which | |
| takes 32 bits (16 + 8 + 8) to store. currently we store a number of | |
| collation units, as well as an offset into the array of collation units. | |
| what if we stored the 32 bit collation unit info directly where the offset | |
| currently is, and make it only one unit by default. overload the value | |
| (perhaps use high tertiary weights) to mark multi-unit results and reference | |
| an offset in another lookup table for the sequence of collation units. this | |
| could cut the size of the data by a factor of two. | |
| * optimise sequence lookup or lookup for ASCII chars | |
| * Unicode normalisation issues. The table by default contains entries | |
| for many "canonically decomposable characters". This uses more storage | |
| space, but saves on time. | |
| libunistring has a "stream normalization" feature - see documentation | |
| of "struct uninorm_filter". We could see how efficient this was. | |
| Consider combining the "normalization" step with searching for discontiguous | |
| matches. The Unicode documentation often uses the example of å with a cedilla, | |
| in tailoring for Danish. | |
| If we normalise this to NFD, we get "a <cedilla> <ring>". Then a discontiguous | |
| match has to be found for "a <ring>". We have two rather slow processes | |
| (normalization, and discontiguous matching) that cancel each other out. It | |
| might be possible to combine them to get a "collation-dependent normalization | |
| form" (no such form is defined to my knowledge). | |
| The Unicode Collation Algorithm describes "blocking context" for non-contiguous | |
| matches: | |
| UTS10-D34. Blocking Context: The presence of a character B between two | |
| characters C1 and C2, where ccc(B) = 0 or ccc(B) ≥ ccc(C2). | |
| The notation ccc(B) is an abbreviation for "the Canonical_Combining_Class | |
| value of B". | |
| https://www.unicode.org/reports/tr10/#UTS10-D34 | |
| My understanding is, that due to the previous normalization step (to NFD), | |
| that the case ccc(B) > ccc(C2) should not occur. For example, if "a <ring>" | |
| is a contraction, after normalization it is only characters with | |
| Canonical_Combining_Class equal to that of <ring> which could block the | |
| contraction before a following character with Canonical_Combining_Class zero, | |
| as NFD produces combining characters with non-decreasing | |
| Canonical_Combining_Class. It's described in the Unicode standard proper: | |
| "3.11.5 Canonical Ordering Algorithm" | |
| https://www.unicode.org/versions/Unicode17.0.0/core-spec/chapter-3/#G49591 | |
| "CLDR" adds the concept of "prefix mapping", which stops a time penalty | |
| whenever a letter L appears: | |
| For example, the DUCET contains contractions for several variants of | |
| L· (L followed by middle dot). Collating ASCII text is slowed down by | |
| contraction matching starting with L/l. In the CLDR root collation, | |
| these contractions are replaced by prefix mappings (L|·) which are | |
| triggered only when the middle dot is encountered. | |
| ... | |
| The mapping is conditional on the prefix match but does not change the | |
| mappings for the preceding text. As a result, a contraction mapping | |
| for "px" can be replaced by a prefix rule "p|x" only if px maps to | |
| the collation elements for p followed by the collation elements for | |
| "x if after p". In the DUCET, L· maps to CE(L) followed by a special | |
| secondary CE (which differs from CE(·) when · is not preceded by | |
| L). In the CLDR root collation, L has no context-sensitive mappings, | |
| but · maps to that special secondary CE if preceded by L. | |
| https://www.unicode.org/reports/tr35/tr35-collation.html#Context_Sensitive_Mappings | |
| However, it's rather vague how to implement this correctly: | |
| Note: Matching of discontiguous contractions should be implemented without | |
| rewriting the text (unlike in the [UCA] algorithm specification), so that | |
| prefix matching is predictable. (It should also help with contraction | |
| matching performance.) An implementation that does rewrite the text, as | |
| in the UCA, will get different results for some (unusual) combinations | |
| of contractions, prefix rules, and input text. | |
| * could use "compatibility decompositions" to save space | |
| (UTS #10 9.3.2). | |
| notes: | |
| # print all contractions | |
| perl -wnle '/^[[:xdigit:]]{4,5} [[:xdigit:]]/ && print' <allkeys.txt | |
| # list secondary weights | |
| perl -wnle '/\[[\.\*][[:xdigit:]]{4}\.([[:xdigit:]]{4})/ && print $1 ; ' <allkeys.txt | sort | uniq | |
| # list tertiary weights | |
| perl -wnle '/\[[\.\*][[:xdigit:]]{4}\.[[:xdigit:]]{4}.([[:xdigit:]]{4})/ && print $1 ; ' <allkeys.txt | sort | uniq | |
| In allkeys-17.0.0 | |
| 256 possible secondary weights (0x0000 and 0x0020 - 0x011E) | |
| extra secondary collation weights 011F - 0127 | |
| 29 possible tertiary weights | |