func _next_boundary(storage: ByteStorage, offset: Int, end: Int) -> IntThe byte offset just past the extended grapheme cluster starting at offset, which must itself be a cluster boundary. Because scans start at true boundaries, all UAX #29 rule state (GB11's emoji sequence, GB9c's conjunct chain, GB12/13's regional-indicator parity) is local to this one scan — the iterator carries none.
View Source
pub func _next_boundary(storage: ByteStorage, offset: Int, end: Int) -> Int {
let head: Int = _utf8_decode(storage: storage, offset: offset, end: end)
let head_cat: Int = _grapheme_category(scalar: _packed_scalar(packed: head))
let pos: Int = offset + _packed_size(packed: head)
// GB3/GB4: CR joins only a following LF; controls stand alone.
if head_cat == _GC_CR {
if pos < end {
let after_cr: Int = _utf8_decode(storage: storage, offset: pos, end: end)
if _packed_scalar(packed: after_cr) == 10 { return pos + _packed_size(
packed: after_cr
) }
}
return pos
}
if head_cat == _GC_CONTROL { return pos }
if head_cat == _GC_LF { return pos }
let prev: Int = head_cat
// GB11 state: 0 none, 1 ExtPict (+ extends), 2 ExtPict + extends + ZWJ.
let emoji: Int = 0
if head_cat == _GC_EXT_PICT { emoji = 1 }
// GB9c state: 0 none, 1 consonant (+ InCB extends), 2 consonant + linker.
let incb: Int = 0
if head_cat == _GC_INCB_CONSONANT { incb = 1 }
// GB12/13 state: length of the trailing regional-indicator run.
let ri_run: Int = 0
if head_cat == _GC_REGIONAL_INDICATOR { ri_run = 1 }
loop pos < end {
let next_packed: Int = _utf8_decode(storage: storage, offset: pos, end: end)
let cat: Int = _grapheme_category(scalar: _packed_scalar(packed: next_packed))
if _joins(prev: prev, cat: cat, emoji: emoji, incb: incb, ri_run: ri_run) == false { return pos }
if cat == _GC_EXT_PICT {
emoji = 1
} else {
let emoji_extends: Bool = emoji == 1 && _extends_cluster(cat: cat)
if emoji_extends {
if cat == _GC_ZWJ { emoji = 2 }
} else {
emoji = 0
}
}
if cat == _GC_INCB_CONSONANT {
incb = 1
} else {
let links: Bool = incb >= 1 && cat == _GC_EXTEND_INCB_LINKER
let carries: Bool = incb >= 1 && (cat == _GC_EXTEND_INCB_EXTEND || cat == _GC_ZWJ)
if links {
incb = 2
} else {
if carries == false { incb = 0 }
}
}
if cat == _GC_REGIONAL_INDICATOR {
if prev == _GC_REGIONAL_INDICATOR {
ri_run = ri_run + 1
} else {
ri_run = 1
}
} else {
ri_run = 0
}
prev = cat
pos = pos + _packed_size(packed: next_packed)
}
pos
}