240 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			240 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2015 The Go Authors. All rights reserved.
 | 
						|
// Use of this source code is governed by a BSD-style
 | 
						|
// license that can be found in the LICENSE file.
 | 
						|
 | 
						|
package width
 | 
						|
 | 
						|
import (
 | 
						|
	"unicode/utf8"
 | 
						|
 | 
						|
	"golang.org/x/text/transform"
 | 
						|
)
 | 
						|
 | 
						|
type foldTransform struct {
 | 
						|
	transform.NopResetter
 | 
						|
}
 | 
						|
 | 
						|
func (foldTransform) Span(src []byte, atEOF bool) (n int, err error) {
 | 
						|
	for n < len(src) {
 | 
						|
		if src[n] < utf8.RuneSelf {
 | 
						|
			// ASCII fast path.
 | 
						|
			for n++; n < len(src) && src[n] < utf8.RuneSelf; n++ {
 | 
						|
			}
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		v, size := trie.lookup(src[n:])
 | 
						|
		if size == 0 { // incomplete UTF-8 encoding
 | 
						|
			if !atEOF {
 | 
						|
				err = transform.ErrShortSrc
 | 
						|
			} else {
 | 
						|
				n = len(src)
 | 
						|
			}
 | 
						|
			break
 | 
						|
		}
 | 
						|
		if elem(v)&tagNeedsFold != 0 {
 | 
						|
			err = transform.ErrEndOfSpan
 | 
						|
			break
 | 
						|
		}
 | 
						|
		n += size
 | 
						|
	}
 | 
						|
	return n, err
 | 
						|
}
 | 
						|
 | 
						|
func (foldTransform) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
 | 
						|
	for nSrc < len(src) {
 | 
						|
		if src[nSrc] < utf8.RuneSelf {
 | 
						|
			// ASCII fast path.
 | 
						|
			start, end := nSrc, len(src)
 | 
						|
			if d := len(dst) - nDst; d < end-start {
 | 
						|
				end = nSrc + d
 | 
						|
			}
 | 
						|
			for nSrc++; nSrc < end && src[nSrc] < utf8.RuneSelf; nSrc++ {
 | 
						|
			}
 | 
						|
			n := copy(dst[nDst:], src[start:nSrc])
 | 
						|
			if nDst += n; nDst == len(dst) {
 | 
						|
				nSrc = start + n
 | 
						|
				if nSrc == len(src) {
 | 
						|
					return nDst, nSrc, nil
 | 
						|
				}
 | 
						|
				if src[nSrc] < utf8.RuneSelf {
 | 
						|
					return nDst, nSrc, transform.ErrShortDst
 | 
						|
				}
 | 
						|
			}
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		v, size := trie.lookup(src[nSrc:])
 | 
						|
		if size == 0 { // incomplete UTF-8 encoding
 | 
						|
			if !atEOF {
 | 
						|
				return nDst, nSrc, transform.ErrShortSrc
 | 
						|
			}
 | 
						|
			size = 1 // gobble 1 byte
 | 
						|
		}
 | 
						|
		if elem(v)&tagNeedsFold == 0 {
 | 
						|
			if size != copy(dst[nDst:], src[nSrc:nSrc+size]) {
 | 
						|
				return nDst, nSrc, transform.ErrShortDst
 | 
						|
			}
 | 
						|
			nDst += size
 | 
						|
		} else {
 | 
						|
			data := inverseData[byte(v)]
 | 
						|
			if len(dst)-nDst < int(data[0]) {
 | 
						|
				return nDst, nSrc, transform.ErrShortDst
 | 
						|
			}
 | 
						|
			i := 1
 | 
						|
			for end := int(data[0]); i < end; i++ {
 | 
						|
				dst[nDst] = data[i]
 | 
						|
				nDst++
 | 
						|
			}
 | 
						|
			dst[nDst] = data[i] ^ src[nSrc+size-1]
 | 
						|
			nDst++
 | 
						|
		}
 | 
						|
		nSrc += size
 | 
						|
	}
 | 
						|
	return nDst, nSrc, nil
 | 
						|
}
 | 
						|
 | 
						|
type narrowTransform struct {
 | 
						|
	transform.NopResetter
 | 
						|
}
 | 
						|
 | 
						|
func (narrowTransform) Span(src []byte, atEOF bool) (n int, err error) {
 | 
						|
	for n < len(src) {
 | 
						|
		if src[n] < utf8.RuneSelf {
 | 
						|
			// ASCII fast path.
 | 
						|
			for n++; n < len(src) && src[n] < utf8.RuneSelf; n++ {
 | 
						|
			}
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		v, size := trie.lookup(src[n:])
 | 
						|
		if size == 0 { // incomplete UTF-8 encoding
 | 
						|
			if !atEOF {
 | 
						|
				err = transform.ErrShortSrc
 | 
						|
			} else {
 | 
						|
				n = len(src)
 | 
						|
			}
 | 
						|
			break
 | 
						|
		}
 | 
						|
		if k := elem(v).kind(); byte(v) == 0 || k != EastAsianFullwidth && k != EastAsianWide && k != EastAsianAmbiguous {
 | 
						|
		} else {
 | 
						|
			err = transform.ErrEndOfSpan
 | 
						|
			break
 | 
						|
		}
 | 
						|
		n += size
 | 
						|
	}
 | 
						|
	return n, err
 | 
						|
}
 | 
						|
 | 
						|
func (narrowTransform) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
 | 
						|
	for nSrc < len(src) {
 | 
						|
		if src[nSrc] < utf8.RuneSelf {
 | 
						|
			// ASCII fast path.
 | 
						|
			start, end := nSrc, len(src)
 | 
						|
			if d := len(dst) - nDst; d < end-start {
 | 
						|
				end = nSrc + d
 | 
						|
			}
 | 
						|
			for nSrc++; nSrc < end && src[nSrc] < utf8.RuneSelf; nSrc++ {
 | 
						|
			}
 | 
						|
			n := copy(dst[nDst:], src[start:nSrc])
 | 
						|
			if nDst += n; nDst == len(dst) {
 | 
						|
				nSrc = start + n
 | 
						|
				if nSrc == len(src) {
 | 
						|
					return nDst, nSrc, nil
 | 
						|
				}
 | 
						|
				if src[nSrc] < utf8.RuneSelf {
 | 
						|
					return nDst, nSrc, transform.ErrShortDst
 | 
						|
				}
 | 
						|
			}
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		v, size := trie.lookup(src[nSrc:])
 | 
						|
		if size == 0 { // incomplete UTF-8 encoding
 | 
						|
			if !atEOF {
 | 
						|
				return nDst, nSrc, transform.ErrShortSrc
 | 
						|
			}
 | 
						|
			size = 1 // gobble 1 byte
 | 
						|
		}
 | 
						|
		if k := elem(v).kind(); byte(v) == 0 || k != EastAsianFullwidth && k != EastAsianWide && k != EastAsianAmbiguous {
 | 
						|
			if size != copy(dst[nDst:], src[nSrc:nSrc+size]) {
 | 
						|
				return nDst, nSrc, transform.ErrShortDst
 | 
						|
			}
 | 
						|
			nDst += size
 | 
						|
		} else {
 | 
						|
			data := inverseData[byte(v)]
 | 
						|
			if len(dst)-nDst < int(data[0]) {
 | 
						|
				return nDst, nSrc, transform.ErrShortDst
 | 
						|
			}
 | 
						|
			i := 1
 | 
						|
			for end := int(data[0]); i < end; i++ {
 | 
						|
				dst[nDst] = data[i]
 | 
						|
				nDst++
 | 
						|
			}
 | 
						|
			dst[nDst] = data[i] ^ src[nSrc+size-1]
 | 
						|
			nDst++
 | 
						|
		}
 | 
						|
		nSrc += size
 | 
						|
	}
 | 
						|
	return nDst, nSrc, nil
 | 
						|
}
 | 
						|
 | 
						|
type wideTransform struct {
 | 
						|
	transform.NopResetter
 | 
						|
}
 | 
						|
 | 
						|
func (wideTransform) Span(src []byte, atEOF bool) (n int, err error) {
 | 
						|
	for n < len(src) {
 | 
						|
		// TODO: Consider ASCII fast path. Special-casing ASCII handling can
 | 
						|
		// reduce the ns/op of BenchmarkWideASCII by about 30%. This is probably
 | 
						|
		// not enough to warrant the extra code and complexity.
 | 
						|
		v, size := trie.lookup(src[n:])
 | 
						|
		if size == 0 { // incomplete UTF-8 encoding
 | 
						|
			if !atEOF {
 | 
						|
				err = transform.ErrShortSrc
 | 
						|
			} else {
 | 
						|
				n = len(src)
 | 
						|
			}
 | 
						|
			break
 | 
						|
		}
 | 
						|
		if k := elem(v).kind(); byte(v) == 0 || k != EastAsianHalfwidth && k != EastAsianNarrow {
 | 
						|
		} else {
 | 
						|
			err = transform.ErrEndOfSpan
 | 
						|
			break
 | 
						|
		}
 | 
						|
		n += size
 | 
						|
	}
 | 
						|
	return n, err
 | 
						|
}
 | 
						|
 | 
						|
func (wideTransform) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
 | 
						|
	for nSrc < len(src) {
 | 
						|
		// TODO: Consider ASCII fast path. Special-casing ASCII handling can
 | 
						|
		// reduce the ns/op of BenchmarkWideASCII by about 30%. This is probably
 | 
						|
		// not enough to warrant the extra code and complexity.
 | 
						|
		v, size := trie.lookup(src[nSrc:])
 | 
						|
		if size == 0 { // incomplete UTF-8 encoding
 | 
						|
			if !atEOF {
 | 
						|
				return nDst, nSrc, transform.ErrShortSrc
 | 
						|
			}
 | 
						|
			size = 1 // gobble 1 byte
 | 
						|
		}
 | 
						|
		if k := elem(v).kind(); byte(v) == 0 || k != EastAsianHalfwidth && k != EastAsianNarrow {
 | 
						|
			if size != copy(dst[nDst:], src[nSrc:nSrc+size]) {
 | 
						|
				return nDst, nSrc, transform.ErrShortDst
 | 
						|
			}
 | 
						|
			nDst += size
 | 
						|
		} else {
 | 
						|
			data := inverseData[byte(v)]
 | 
						|
			if len(dst)-nDst < int(data[0]) {
 | 
						|
				return nDst, nSrc, transform.ErrShortDst
 | 
						|
			}
 | 
						|
			i := 1
 | 
						|
			for end := int(data[0]); i < end; i++ {
 | 
						|
				dst[nDst] = data[i]
 | 
						|
				nDst++
 | 
						|
			}
 | 
						|
			dst[nDst] = data[i] ^ src[nSrc+size-1]
 | 
						|
			nDst++
 | 
						|
		}
 | 
						|
		nSrc += size
 | 
						|
	}
 | 
						|
	return nDst, nSrc, nil
 | 
						|
}
 |