UNICODE

The shared code-point classification predicates (isBmpCodePoint, isValidCodePoint, isTextCodePoint, …) live in code_point — see code_point/README.md. So does the CodePoint type both codecs decode to and encode from, code_point/types.ts: a scalar value, an untagged surrogate or above-0x10FFFF value the UTF-8 decoder passes through unchecked (gate on isValidCodePoint for a scalar), or an errorMask-tagged error value laid out by the error tables below.

Text that says what its words are — keywords, strings, numbers — beside the text itself, for a page or a terminal to colour without reading it again, is marked: marked/README.md.

Which function to call for each encoding is on its own page: utf8, utf16 and ascii. The rest of this page is the bit-level design.

UTF-8

Requirement: no loss for UTF8 => codepoint => UTF8

utf8utf8 codesizecodepoint
[a]0xxx_xxxx7 bit0_0000_0000_0000_0xxx_xxxx
[b,a]110x_xxxx 10xx_xxxx11 bit0_0000_0000_0xxx_xxxx_xxxx + 0_0000_0000_1000_0000
[c,b,a]1110_xxxx 10xx_xxxx 10xx_xxxx16 bit0_0000_xxxx_xxxx_xxxx_xxxx + 0_0000_1000_0000_0000
[d,c,b,a]1111_0xxx 10xx_xxxx 10xx_xxxx 10xx_xxxx21 bitx_xxxx_xxxx_xxxx_xxxx_xxxx + 1_0000_0000_0000_0000
utf8 errorutf8 codesizecodepointflag
[e]1111_1xxx3 biterrorByteFlag
[d,]1111_0xxx3 biterrorByteFlag
[c,]1110_xxxx4 biterrorByteFlag
[b,]110x_xxxx5 biterrorByteFlag
[e]10xx_xxxx6 bit0000_0000 1xxx_xxxxerrorByteFlag
[d,c,]1111_0xxx 10xx_xxxx9 bit0000_001x xxxx_xxxxerrorLead4ContFlag
[c,b,]1110_xxxx 10xx_xxxx10 bit0000_01xx xxxx_xxxxerrorLead3ContFlag
[d,c,b,]1111_0xxx 10xx_xxxx 10xx_xxxx15 bit1xxx_xxxx xxxx_xxxxerrorLead4Cont2Flag

Each code point is also tagged with errorMask. The flags are named once, in utf8/module.f.mjs, and both the encoder and the decoder read them from there.

Total error states:

2^6 + 2^3 + 2^5 + 2^4 + 2^10 + 2^3 + + 2^9 + 2^15
2^4 + 2^6 + 2^5 + 2^4 + 2^10 + 2^9 + 2^15
2^5 + 2^6 + 2^5 + 2^10 + 2^9 + 2^15
2^6 + 2^6 + 2^10 + 2^9 + 2^15
2^7 + 2^9 + 2^10 + 2^15
0b1000_0110_1000_000
128 + 512 + 1024 + 32_768
34_432
< 2^16

utf8/module.f.mjs

const toCodePointList: (input: List<u8|null>) => List<CodePoint>
const fromCodePointList: (input: List<CodePoint>) => List<u8>

UTF-16

Requirement: no loss for UTF16 => codepoint => UTF16

0xD800..0xDFFF
0b_1101_1000_0000_0000
0b_1101_1111_1111_1111

0b_1101_1xxx_xxxx_xxxx : 11 bits

- first : 0xD800: 0b_1101_10xx_xxxx_xxxx : 10 bit
- second: 0xDC00: 0b_1101_11xx_xxxx_xxxx : 10 bit
utf16utf16 codesizecodepoint
[a]xxxx_xxxx_xxxx_xxxx16 bit0000_xxxx_xxxx_xxxx_xxxx
[b,a]1101_10xx_xxxx_xxxx 1101_11xx_xxxx_xxxx20 bitxxxx_xxxx_xxxx_xxxx_xxxx + 1_0000_0000_0000_0000
utf16 errorutf16 codesizecodepoint
[e]1101_11xx_xxxx_xxxx10 bit1101_11xx_xxxx_xxxx
[b,]1101_10xx_xxxx_xxxx10 bit1101_10xx_xxxx_xxxx

Total error states: 11 bit

utf16/module.f.mjs

const toCodePointList : List<u16|null>) => List<CodePoint>
const fromCodePointList: (input: List<CodePoint>) => List<u16>
const stringToList: (input: string) => List<u16>
const listToString: (input: List<u16>) => string

UTF-16 => CP => UTF-8 => CP = UTF-16

Example

UTF-16:
  1101_11xx_xxxx_xxxx
  1101_11xx_xxxx_xxxx
CP:
  1000_0000_0000_0000_1101_11xx_xxxx_xxxx
  1000_0000_0000_0000_1101_11xx_xxxx_xxxx
UTF-8:
  1111_0.101
  10.11_xxxx
  10xx_xxxx
  1111_0.101
  10.11_xxxx
  10xx_xxxx
CP:
  1000_0000_0000_0000_1101_11xx_xxxx_xxxx
  1000_0000_0000_0000_1101_11xx_xxxx_xxxx
UTF-16:
  1101_11xx_xxxx_xxxx
  1101_11xx_xxxx_xxxx

Emergent Testing

Idle. Press Run to start the suite.

  • ./ascii/proof.f.mjs
  • ./code_point/proof.f.mjs
  • ./marked/proof.f.mjs
  • ./percent/proof.f.mjs
  • ./proof.f.mjs
  • ./sgr/proof.f.mjs
  • ./shell/proof.f.mjs
  • ./utf16/proof.f.mjs
  • ./utf8/proof.f.mjs