package norm
import
const (
maxNonStarters = 30
maxBufferSize = maxNonStarters + 2
maxNFCExpansion = 3
maxNFKCExpansion = 18
maxByteBufferSize = utf8.UTFMax * maxBufferSize
)
type ssState int
const (
ssSuccess ssState = iota
ssStarter
ssOverflow
)
type streamSafe uint8
func ( *streamSafe) ( Properties) {
* = streamSafe(.nTrailingNonStarters())
}
func ( *streamSafe) ( Properties) ssState {
if * > maxNonStarters {
panic("streamSafe was not reset")
}
:= .nLeadingNonStarters()
if * += streamSafe(); * > maxNonStarters {
* = 0
return ssOverflow
}
if == 0 {
* = streamSafe(.nTrailingNonStarters())
return ssStarter
}
return ssSuccess
}
func ( *streamSafe) ( Properties) ssState {
if * > maxNonStarters {
panic("streamSafe was not reset")
}
:= * + streamSafe(.nTrailingNonStarters())
if > maxNonStarters {
return ssOverflow
}
* =
if .nLeadingNonStarters() == 0 {
return ssStarter
}
return ssSuccess
}
func ( streamSafe) () bool {
return == maxNonStarters
}
const GraphemeJoiner = "\u034F"
type reorderBuffer struct {
rune [maxBufferSize]Properties
byte [maxByteBufferSize]byte
nbyte uint8
ss streamSafe
nrune int
f formInfo
src input
nsrc int
tmpBytes input
out []byte
flushF func(*reorderBuffer) bool
}
func ( *reorderBuffer) ( Form, []byte) {
.f = *formTable[]
.src.setBytes()
.nsrc = len()
.ss = 0
}
func ( *reorderBuffer) ( Form, string) {
.f = *formTable[]
.src.setString()
.nsrc = len()
.ss = 0
}
func ( *reorderBuffer) ( []byte, func(*reorderBuffer) bool) {
.out =
.flushF =
}
func ( *reorderBuffer) () {
.nrune = 0
.nbyte = 0
}
func ( *reorderBuffer) () bool {
if .f.composing {
.compose()
}
:= .flushF()
.reset()
return
}
func ( *reorderBuffer) bool {
for := 0; < .nrune; ++ {
:= .rune[].pos
:= + .rune[].size
.out = append(.out, .byte[:]...)
}
return true
}
func ( *reorderBuffer) ( []byte) []byte {
for := 0; < .nrune; ++ {
:= .rune[].pos
:= + .rune[].size
= append(, .byte[:]...)
}
.reset()
return
}
func ( *reorderBuffer) ( []byte) int {
:= 0
for := 0; < .nrune; ++ {
:= .rune[]
+= copy([:], .byte[.pos:.pos+.size])
}
.reset()
return
}
func ( *reorderBuffer) ( Properties) {
:= .nrune
:= .rune[:]
:= .ccc
if > 0 {
for ; > 0; -- {
if [-1].ccc <= {
break
}
[] = [-1]
}
}
.nrune += 1
:= uint8(.nbyte)
.nbyte += utf8.UTFMax
.pos =
[] =
}
type insertErr int
const (
iSuccess insertErr = -iota
iShortDst
iShortSrc
)
func ( *reorderBuffer) ( input, int, Properties) insertErr {
if := .hangul(); != 0 {
.decomposeHangul()
return iSuccess
}
if .hasDecomposition() {
return .insertDecomposed(.Decomposition())
}
.insertSingle(, , )
return iSuccess
}
func ( *reorderBuffer) ( input, int, Properties) {
if := .hangul(); != 0 {
.decomposeHangul()
}
if .hasDecomposition() {
.insertDecomposed(.Decomposition())
} else {
.insertSingle(, , )
}
}
func ( *reorderBuffer) ( []byte) insertErr {
.tmpBytes.setBytes()
for := 0; < len(); {
:= .f.info(.tmpBytes, )
if .BoundaryBefore() && .nrune > 0 && !.doFlush() {
return iShortDst
}
+= copy(.byte[.nbyte:], [:+int(.size)])
.insertOrdered()
}
return iSuccess
}
func ( *reorderBuffer) ( input, int, Properties) {
.copySlice(.byte[.nbyte:], , +int(.size))
.insertOrdered()
}
func ( *reorderBuffer) () {
.insertSingle(input{str: GraphemeJoiner}, 0, Properties{size: uint8(len(GraphemeJoiner))})
}
func ( *reorderBuffer) ( rune) {
:= .nbyte
:= utf8.EncodeRune(.byte[:], rune())
.nbyte += utf8.UTFMax
.rune[.nrune] = Properties{pos: , size: uint8()}
.nrune++
}
func ( *reorderBuffer) ( int, rune) {
:= .rune[].pos
:= utf8.EncodeRune(.byte[:], rune())
.rune[] = Properties{pos: , size: uint8()}
}
func ( *reorderBuffer) ( int) rune {
:= .rune[]
, := utf8.DecodeRune(.byte[.pos : .pos+.size])
return
}
func ( *reorderBuffer) ( int) []byte {
:= .rune[]
return .byte[.pos : int(.pos)+int(.size)]
}
const (
hangulBase = 0xAC00
hangulBase0 = 0xEA
hangulBase1 = 0xB0
hangulBase2 = 0x80
hangulEnd = hangulBase + jamoLVTCount
hangulEnd0 = 0xED
hangulEnd1 = 0x9E
hangulEnd2 = 0xA4
jamoLBase = 0x1100
jamoLBase0 = 0xE1
jamoLBase1 = 0x84
jamoLEnd = 0x1113
jamoVBase = 0x1161
jamoVEnd = 0x1176
jamoTBase = 0x11A7
jamoTEnd = 0x11C3
jamoTCount = 28
jamoVCount = 21
jamoVTCount = 21 * 28
jamoLVTCount = 19 * 21 * 28
)
const hangulUTF8Size = 3
func ( []byte) bool {
if len() < hangulUTF8Size {
return false
}
:= [0]
if < hangulBase0 {
return false
}
:= [1]
switch {
case == hangulBase0:
return >= hangulBase1
case < hangulEnd0:
return true
case > hangulEnd0:
return false
case < hangulEnd1:
return true
}
return == hangulEnd1 && [2] < hangulEnd2
}
func ( string) bool {
if len() < hangulUTF8Size {
return false
}
:= [0]
if < hangulBase0 {
return false
}
:= [1]
switch {
case == hangulBase0:
return >= hangulBase1
case < hangulEnd0:
return true
case > hangulEnd0:
return false
case < hangulEnd1:
return true
}
return == hangulEnd1 && [2] < hangulEnd2
}
func ( []byte) bool {
return [0] == jamoLBase0 && ([1]&0xFC) == jamoLBase1
}
func ( []byte) bool {
, := utf8.DecodeRune()
-= hangulBase
return < jamoLVTCount && %jamoTCount == 0
}
func ( []byte, rune) int {
const = 3
-= hangulBase
:= % jamoTCount
/= jamoTCount
utf8.EncodeRune(, jamoLBase+/jamoVCount)
utf8.EncodeRune([:], jamoVBase+%jamoVCount)
if != 0 {
utf8.EncodeRune([2*:], jamoTBase+)
return 3 *
}
return 2 *
}
func ( *reorderBuffer) ( rune) {
-= hangulBase
:= % jamoTCount
/= jamoTCount
.appendRune(jamoLBase + /jamoVCount)
.appendRune(jamoVBase + %jamoVCount)
if != 0 {
.appendRune(jamoTBase + )
}
}
func ( *reorderBuffer) (, , int) {
:= .rune[:]
:= .nrune
for ; < ; ++ {
:= [-1].ccc
:= [].ccc
if == 0 {
= - 1
}
if != -1 && >= {
[] = []
++
} else {
:= .runeAt()
:= .runeAt()
switch {
case jamoLBase <= && < jamoLEnd &&
jamoVBase <= && < jamoVEnd:
.assignRune(, hangulBase+
(-jamoLBase)*jamoVTCount+(-jamoVBase)*jamoTCount)
case hangulBase <= && < hangulEnd &&
jamoTBase < && < jamoTEnd &&
((-hangulBase)%jamoTCount) == 0:
.assignRune(, +-jamoTBase)
default:
[] = []
++
}
}
}
.nrune =
}
func ( *reorderBuffer) () {
recompMapOnce.Do(buildRecompMap)
:= .nrune
if == 0 {
return
}
:= 1
:= .rune[:]
for , := 0, 1; < ; ++ {
if isJamoVT(.bytesAt()) {
.combineHangul(, , )
return
}
:= []
if .combinesBackward() {
:= [-1].ccc
:= .ccc
:= false
if == 0 {
= - 1
} else {
= != -1 && >=
}
if ! {
:= combine(.runeAt(), .runeAt())
if != 0 {
.assignRune(, )
continue
}
}
}
[] = []
++
}
.nrune =
}