vendor: update all dependencies
This commit is contained in:
+366
@@ -0,0 +1,366 @@
|
||||
// Copyright 2017 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 catmsg contains support types for package x/text/message/catalog.
|
||||
//
|
||||
// This package contains the low-level implementations of Message used by the
|
||||
// catalog package and provides primitives for other packages to implement their
|
||||
// own. For instance, the plural package provides functionality for selecting
|
||||
// translation strings based on the plural category of substitution arguments.
|
||||
//
|
||||
//
|
||||
// Encoding and Decoding
|
||||
//
|
||||
// Catalogs store Messages encoded as a single string. Compiling a message into
|
||||
// a string both results in compacter representation and speeds up evaluation.
|
||||
//
|
||||
// A Message must implement a Compile method to convert its arbitrary
|
||||
// representation to a string. The Compile method takes an Encoder which
|
||||
// facilitates serializing the message. Encoders also provide more context of
|
||||
// the messages's creation (such as for which language the message is intended),
|
||||
// which may not be known at the time of the creation of the message.
|
||||
//
|
||||
// Each message type must also have an accompanying decoder registered to decode
|
||||
// the message. This decoder takes a Decoder argument which provides the
|
||||
// counterparts for the decoding.
|
||||
//
|
||||
//
|
||||
// Renderers
|
||||
//
|
||||
// A Decoder must be initialized with a Renderer implementation. These
|
||||
// implementations must be provided by packages that use Catalogs, typically
|
||||
// formatting packages such as x/text/message. A typical user will not need to
|
||||
// worry about this type; it is only relevant to packages that do string
|
||||
// formatting and want to use the catalog package to handle localized strings.
|
||||
//
|
||||
// A package that uses catalogs for selecting strings receives selection results
|
||||
// as sequence of substrings passed to the Renderer. The following snippet shows
|
||||
// how to express the above example using the message package.
|
||||
//
|
||||
// message.Set(language.English, "You are %d minute(s) late.",
|
||||
// catalog.Var("minutes", plural.Select(1, "one", "minute")),
|
||||
// catalog.String("You are %[1]d ${minutes} late."))
|
||||
//
|
||||
// p := message.NewPrinter(language.English)
|
||||
// p.Printf("You are %d minute(s) late.", 5) // always 5 minutes late.
|
||||
//
|
||||
// To evaluate the Printf, package message wraps the arguments in a Renderer
|
||||
// that is passed to the catalog for message decoding. The call sequence that
|
||||
// results from evaluating the above message, assuming the person is rather
|
||||
// tardy, is:
|
||||
//
|
||||
// Render("You are %[1]d ")
|
||||
// Arg(1)
|
||||
// Render("minutes")
|
||||
// Render(" late.")
|
||||
//
|
||||
// The calls to Arg is caused by the plural.Select execution, which evaluates
|
||||
// the argument to determine whether the singular or plural message form should
|
||||
// be selected. The calls to Render reports the partial results to the message
|
||||
// package for further evaluation.
|
||||
package catmsg
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
// A Handle refers to a registered message type.
|
||||
type Handle int
|
||||
|
||||
// First is used as a Handle to EncodeMessageType, followed by a series of calls
|
||||
// to EncodeMessage, to implement selecting the first matching Message.
|
||||
//
|
||||
// TODO: this can be removed once we either can use type aliases or if the
|
||||
// internals of this package are merged with the catalog package.
|
||||
var First Handle = msgFirst
|
||||
|
||||
// A Handler decodes and evaluates data compiled by a Message and sends the
|
||||
// result to the Decoder. The output may depend on the value of the substitution
|
||||
// arguments, accessible by the Decoder's Arg method. The Handler returns false
|
||||
// if there is no translation for the given substitution arguments.
|
||||
type Handler func(d *Decoder) bool
|
||||
|
||||
// Register records the existence of a message type and returns a Handle that
|
||||
// can be used in the Encoder's EncodeMessageType method to create such
|
||||
// messages. The prefix of the name should be the package path followed by
|
||||
// an optional disambiguating string.
|
||||
// Register will panic if a handle for the same name was already registered.
|
||||
func Register(name string, handler Handler) Handle {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
if _, ok := names[name]; ok {
|
||||
panic(fmt.Errorf("catmsg: handler for %q already exists", name))
|
||||
}
|
||||
h := Handle(len(handlers))
|
||||
names[name] = h
|
||||
handlers = append(handlers, handler)
|
||||
return h
|
||||
}
|
||||
|
||||
// These handlers require fixed positions in the handlers slice.
|
||||
const (
|
||||
msgVars Handle = iota
|
||||
msgFirst
|
||||
msgRaw
|
||||
msgString
|
||||
numFixed
|
||||
)
|
||||
|
||||
const prefix = "golang.org/x/text/internal/catmsg."
|
||||
|
||||
var (
|
||||
mutex sync.Mutex
|
||||
names = map[string]Handle{
|
||||
prefix + "Vars": msgVars,
|
||||
prefix + "First": msgFirst,
|
||||
prefix + "Raw": msgRaw,
|
||||
prefix + "String": msgString,
|
||||
}
|
||||
handlers = make([]Handler, numFixed)
|
||||
)
|
||||
|
||||
func init() {
|
||||
// This handler is a message type wrapper that initializes a decoder
|
||||
// with a variable block. This message type, if present, is always at the
|
||||
// start of an encoded message.
|
||||
handlers[msgVars] = func(d *Decoder) bool {
|
||||
blockSize := int(d.DecodeUint())
|
||||
d.vars = d.data[:blockSize]
|
||||
d.data = d.data[blockSize:]
|
||||
return d.executeMessage()
|
||||
}
|
||||
|
||||
// First takes the first message in a sequence that results in a match for
|
||||
// the given substitution arguments.
|
||||
handlers[msgFirst] = func(d *Decoder) bool {
|
||||
for !d.Done() {
|
||||
if d.ExecuteMessage() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
handlers[msgRaw] = func(d *Decoder) bool {
|
||||
d.Render(d.data)
|
||||
return true
|
||||
}
|
||||
|
||||
// A String message alternates between a string constant and a variable
|
||||
// substitution.
|
||||
handlers[msgString] = func(d *Decoder) bool {
|
||||
for !d.Done() {
|
||||
if str := d.DecodeString(); str != "" {
|
||||
d.Render(str)
|
||||
}
|
||||
if d.Done() {
|
||||
break
|
||||
}
|
||||
d.ExecuteSubstitution()
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrIncomplete indicates a compiled message does not define translations
|
||||
// for all possible argument values. If this message is returned, evaluating
|
||||
// a message may result in the ErrNoMatch error.
|
||||
ErrIncomplete = errors.New("catmsg: incomplete message; may not give result for all inputs")
|
||||
|
||||
// ErrNoMatch indicates no translation message matched the given input
|
||||
// parameters when evaluating a message.
|
||||
ErrNoMatch = errors.New("catmsg: no translation for inputs")
|
||||
)
|
||||
|
||||
// A Message holds a collection of translations for the same phrase that may
|
||||
// vary based on the values of substitution arguments.
|
||||
type Message interface {
|
||||
// Compile encodes the format string(s) of the message as a string for later
|
||||
// evaluation.
|
||||
//
|
||||
// The first call Compile makes on the encoder must be EncodeMessageType.
|
||||
// The handle passed to this call may either be a handle returned by
|
||||
// Register to encode a single custom message, or HandleFirst followed by
|
||||
// a sequence of calls to EncodeMessage.
|
||||
//
|
||||
// Compile must return ErrIncomplete if it is possible for evaluation to
|
||||
// not match any translation for a given set of formatting parameters.
|
||||
// For example, selecting a translation based on plural form may not yield
|
||||
// a match if the form "Other" is not one of the selectors.
|
||||
//
|
||||
// Compile may return any other application-specific error. For backwards
|
||||
// compatibility with package like fmt, which often do not do sanity
|
||||
// checking of format strings ahead of time, Compile should still make an
|
||||
// effort to have some sensible fallback in case of an error.
|
||||
Compile(e *Encoder) error
|
||||
}
|
||||
|
||||
// Compile converts a Message to a data string that can be stored in a Catalog.
|
||||
// The resulting string can subsequently be decoded by passing to the Execute
|
||||
// method of a Decoder.
|
||||
func Compile(tag language.Tag, macros Dictionary, m Message) (data string, err error) {
|
||||
// TODO: pass macros so they can be used for validation.
|
||||
v := &Encoder{inBody: true} // encoder for variables
|
||||
v.root = v
|
||||
e := &Encoder{root: v, parent: v, tag: tag} // encoder for messages
|
||||
err = m.Compile(e)
|
||||
// This package serves te message package, which in turn is meant to be a
|
||||
// drop-in replacement for fmt. With the fmt package, format strings are
|
||||
// evaluated lazily and errors are handled by substituting strings in the
|
||||
// result, rather then returning an error. Dealing with multiple languages
|
||||
// makes it more important to check errors ahead of time. We chose to be
|
||||
// consistent and compatible and allow graceful degradation in case of
|
||||
// errors.
|
||||
buf := e.buf[stripPrefix(e.buf):]
|
||||
if len(v.buf) > 0 {
|
||||
// Prepend variable block.
|
||||
b := make([]byte, 1+maxVarintBytes+len(v.buf)+len(buf))
|
||||
b[0] = byte(msgVars)
|
||||
b = b[:1+encodeUint(b[1:], uint64(len(v.buf)))]
|
||||
b = append(b, v.buf...)
|
||||
b = append(b, buf...)
|
||||
buf = b
|
||||
}
|
||||
if err == nil {
|
||||
err = v.err
|
||||
}
|
||||
return string(buf), err
|
||||
}
|
||||
|
||||
// Var defines a message that can be substituted for a placeholder of the same
|
||||
// name. If an expression does not result in a string after evaluation, Name is
|
||||
// used as the substitution. For example:
|
||||
// Var{
|
||||
// Name: "minutes",
|
||||
// Message: plural.Select(1, "one", "minute"),
|
||||
// }
|
||||
// will resolve to minute for singular and minutes for plural forms.
|
||||
type Var struct {
|
||||
Name string
|
||||
Message Message
|
||||
}
|
||||
|
||||
var errIsVar = errors.New("catmsg: variable used as message")
|
||||
|
||||
// Compile implements Message.
|
||||
//
|
||||
// Note that this method merely registers a variable; it does not create an
|
||||
// encoded message.
|
||||
func (v *Var) Compile(e *Encoder) error {
|
||||
if err := e.addVar(v.Name, v.Message); err != nil {
|
||||
return err
|
||||
}
|
||||
// Using a Var by itself is an error. If it is in a sequence followed by
|
||||
// other messages referring to it, this error will be ignored.
|
||||
return errIsVar
|
||||
}
|
||||
|
||||
// Raw is a message consisting of a single format string that is passed as is
|
||||
// to the Renderer.
|
||||
//
|
||||
// Note that a Renderer may still do its own variable substitution.
|
||||
type Raw string
|
||||
|
||||
// Compile implements Message.
|
||||
func (r Raw) Compile(e *Encoder) (err error) {
|
||||
e.EncodeMessageType(msgRaw)
|
||||
// Special case: raw strings don't have a size encoding and so don't use
|
||||
// EncodeString.
|
||||
e.buf = append(e.buf, r...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// String is a message consisting of a single format string which contains
|
||||
// placeholders that may be substituted with variables.
|
||||
//
|
||||
// Variable substitutions are marked with placeholders and a variable name of
|
||||
// the form ${name}. Any other substitutions such as Go templates or
|
||||
// printf-style substitutions are left to be done by the Renderer.
|
||||
//
|
||||
// When evaluation a string interpolation, a Renderer will receive separate
|
||||
// calls for each placeholder and interstitial string. For example, for the
|
||||
// message: "%[1]v ${invites} %[2]v to ${their} party." The sequence of calls
|
||||
// is:
|
||||
// d.Render("%[1]v ")
|
||||
// d.Arg(1)
|
||||
// d.Render(resultOfInvites)
|
||||
// d.Render(" %[2]v to ")
|
||||
// d.Arg(1)
|
||||
// d.Render(resultOfTheir)
|
||||
// d.Render(" party.")
|
||||
// where the messages for "invites" and "their" both use a plural.Select
|
||||
// referring to the first argument.
|
||||
//
|
||||
// Strings may also invoke macros. Macros are essentially variables that can be
|
||||
// reused. Macros may, for instance, be used to make selections between
|
||||
// different conjugations of a verb. See the catalog package description for an
|
||||
// overview of macros.
|
||||
type String string
|
||||
|
||||
// Compile implements Message. It parses the placeholder formats and returns
|
||||
// any error.
|
||||
func (s String) Compile(e *Encoder) (err error) {
|
||||
msg := string(s)
|
||||
const subStart = "${"
|
||||
hasHeader := false
|
||||
p := 0
|
||||
b := []byte{}
|
||||
for {
|
||||
i := strings.Index(msg[p:], subStart)
|
||||
if i == -1 {
|
||||
break
|
||||
}
|
||||
b = append(b, msg[p:p+i]...)
|
||||
p += i + len(subStart)
|
||||
if i = strings.IndexByte(msg[p:], '}'); i == -1 {
|
||||
b = append(b, "$!(MISSINGBRACE)"...)
|
||||
err = fmt.Errorf("catmsg: missing '}'")
|
||||
p = len(msg)
|
||||
break
|
||||
}
|
||||
name := strings.TrimSpace(msg[p : p+i])
|
||||
if q := strings.IndexByte(name, '('); q == -1 {
|
||||
if !hasHeader {
|
||||
hasHeader = true
|
||||
e.EncodeMessageType(msgString)
|
||||
}
|
||||
e.EncodeString(string(b))
|
||||
e.EncodeSubstitution(name)
|
||||
b = b[:0]
|
||||
} else if j := strings.IndexByte(name[q:], ')'); j == -1 {
|
||||
// TODO: what should the error be?
|
||||
b = append(b, "$!(MISSINGPAREN)"...)
|
||||
err = fmt.Errorf("catmsg: missing ')'")
|
||||
} else if x, sErr := strconv.ParseUint(strings.TrimSpace(name[q+1:q+j]), 10, 32); sErr != nil {
|
||||
// TODO: handle more than one argument
|
||||
b = append(b, "$!(BADNUM)"...)
|
||||
err = fmt.Errorf("catmsg: invalid number %q", strings.TrimSpace(name[q+1:q+j]))
|
||||
} else {
|
||||
if !hasHeader {
|
||||
hasHeader = true
|
||||
e.EncodeMessageType(msgString)
|
||||
}
|
||||
e.EncodeString(string(b))
|
||||
e.EncodeSubstitution(name[:q], int(x))
|
||||
b = b[:0]
|
||||
}
|
||||
p += i + 1
|
||||
}
|
||||
b = append(b, msg[p:]...)
|
||||
if !hasHeader {
|
||||
// Simplify string to a raw string.
|
||||
Raw(string(b)).Compile(e)
|
||||
} else if len(b) > 0 {
|
||||
e.EncodeString(string(b))
|
||||
}
|
||||
return err
|
||||
}
|
||||
+294
@@ -0,0 +1,294 @@
|
||||
// Copyright 2017 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 catmsg
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
type renderer struct {
|
||||
args []int
|
||||
result string
|
||||
}
|
||||
|
||||
func (r *renderer) Arg(i int) interface{} {
|
||||
if i >= len(r.args) {
|
||||
return nil
|
||||
}
|
||||
return r.args[i]
|
||||
}
|
||||
|
||||
func (r *renderer) Render(s string) {
|
||||
if r.result != "" {
|
||||
r.result += "|"
|
||||
}
|
||||
r.result += s
|
||||
}
|
||||
|
||||
func TestCodec(t *testing.T) {
|
||||
type test struct {
|
||||
args []int
|
||||
out string
|
||||
decErr string
|
||||
}
|
||||
single := func(out, err string) []test { return []test{{out: out, decErr: err}} }
|
||||
testCases := []struct {
|
||||
desc string
|
||||
m Message
|
||||
enc string
|
||||
encErr string
|
||||
tests []test
|
||||
}{{
|
||||
desc: "unused variable",
|
||||
m: &Var{"name", String("foo")},
|
||||
encErr: errIsVar.Error(),
|
||||
tests: single("", ""),
|
||||
}, {
|
||||
desc: "empty",
|
||||
m: empty{},
|
||||
tests: single("", ""),
|
||||
}, {
|
||||
desc: "sequence with empty",
|
||||
m: seq{empty{}},
|
||||
tests: single("", ""),
|
||||
}, {
|
||||
desc: "raw string",
|
||||
m: Raw("foo"),
|
||||
tests: single("foo", ""),
|
||||
}, {
|
||||
desc: "raw string no sub",
|
||||
m: Raw("${foo}"),
|
||||
enc: "\x02${foo}",
|
||||
tests: single("${foo}", ""),
|
||||
}, {
|
||||
desc: "simple string",
|
||||
m: String("foo"),
|
||||
tests: single("foo", ""),
|
||||
}, {
|
||||
desc: "missing var",
|
||||
m: String("foo${bar}"),
|
||||
enc: "\x03\x03foo\x02\x03bar",
|
||||
encErr: `unknown var "bar"`,
|
||||
tests: single("foo|bar", ""),
|
||||
}, {
|
||||
desc: "empty var",
|
||||
m: seq{
|
||||
&Var{"bar", seq{}},
|
||||
String("foo${bar}"),
|
||||
},
|
||||
enc: "\x00\x05\x04\x02bar\x03\x03foo\x00\x00",
|
||||
// TODO: recognize that it is cheaper to substitute bar.
|
||||
tests: single("foo|bar", ""),
|
||||
}, {
|
||||
desc: "var after value",
|
||||
m: seq{
|
||||
String("foo${bar}"),
|
||||
&Var{"bar", String("baz")},
|
||||
},
|
||||
encErr: errIsVar.Error(),
|
||||
tests: single("foo|bar", ""),
|
||||
}, {
|
||||
desc: "substitution",
|
||||
m: seq{
|
||||
&Var{"bar", String("baz")},
|
||||
String("foo${bar}"),
|
||||
},
|
||||
tests: single("foo|baz", ""),
|
||||
}, {
|
||||
desc: "shadowed variable",
|
||||
m: seq{
|
||||
&Var{"bar", String("baz")},
|
||||
seq{
|
||||
&Var{"bar", String("BAZ")},
|
||||
String("foo${bar}"),
|
||||
},
|
||||
},
|
||||
tests: single("foo|BAZ", ""),
|
||||
}, {
|
||||
desc: "not shadowed variable",
|
||||
m: seq{
|
||||
&Var{"bar", String("baz")},
|
||||
seq{
|
||||
String("foo${bar}"),
|
||||
&Var{"bar", String("BAZ")},
|
||||
},
|
||||
},
|
||||
encErr: errIsVar.Error(),
|
||||
tests: single("foo|baz", ""),
|
||||
}, {
|
||||
desc: "duplicate variable",
|
||||
m: seq{
|
||||
&Var{"bar", String("baz")},
|
||||
&Var{"bar", String("BAZ")},
|
||||
String("${bar}"),
|
||||
},
|
||||
encErr: "catmsg: duplicate variable \"bar\"",
|
||||
tests: single("baz", ""),
|
||||
}, {
|
||||
desc: "complete incomplete variable",
|
||||
m: seq{
|
||||
&Var{"bar", incomplete{}},
|
||||
String("${bar}"),
|
||||
},
|
||||
enc: "\x00\t\b\x01\x01\x04\x04\x02bar\x03\x00\x00\x00",
|
||||
// TODO: recognize that it is cheaper to substitute bar.
|
||||
tests: single("bar", ""),
|
||||
}, {
|
||||
desc: "incomplete sequence",
|
||||
m: seq{
|
||||
incomplete{},
|
||||
incomplete{},
|
||||
},
|
||||
encErr: ErrIncomplete.Error(),
|
||||
tests: single("", ErrNoMatch.Error()),
|
||||
}, {
|
||||
desc: "compile error variable",
|
||||
m: seq{
|
||||
&Var{"bar", errorCompileMsg{}},
|
||||
String("${bar}"),
|
||||
},
|
||||
encErr: errCompileTest.Error(),
|
||||
tests: single("bar", ""),
|
||||
}, {
|
||||
desc: "compile error message",
|
||||
m: errorCompileMsg{},
|
||||
encErr: errCompileTest.Error(),
|
||||
tests: single("", ""),
|
||||
}, {
|
||||
desc: "compile error sequence",
|
||||
m: seq{
|
||||
errorCompileMsg{},
|
||||
errorCompileMsg{},
|
||||
},
|
||||
encErr: errCompileTest.Error(),
|
||||
tests: single("", ""),
|
||||
}, {
|
||||
desc: "macro",
|
||||
m: String("${exists(1)}"),
|
||||
tests: single("you betya!", ""),
|
||||
}, {
|
||||
desc: "macro incomplete",
|
||||
m: String("${incomplete(1)}"),
|
||||
enc: "\x03\x00\x01\nincomplete\x01",
|
||||
tests: single("incomplete", ""),
|
||||
}, {
|
||||
desc: "macro undefined at end",
|
||||
m: String("${undefined(1)}"),
|
||||
enc: "\x03\x00\x01\tundefined\x01",
|
||||
tests: single("undefined", "catmsg: undefined macro \"undefined\""),
|
||||
}, {
|
||||
desc: "macro undefined with more text following",
|
||||
m: String("${undefined(1)}."),
|
||||
enc: "\x03\x00\x01\tundefined\x01\x01.",
|
||||
tests: single("undefined|.", "catmsg: undefined macro \"undefined\""),
|
||||
}, {
|
||||
desc: "macro missing paren",
|
||||
m: String("${missing(1}"),
|
||||
encErr: "catmsg: missing ')'",
|
||||
tests: single("$!(MISSINGPAREN)", ""),
|
||||
}, {
|
||||
desc: "macro bad num",
|
||||
m: String("aa${bad(a)}"),
|
||||
encErr: "catmsg: invalid number \"a\"",
|
||||
tests: single("aa$!(BADNUM)", ""),
|
||||
}, {
|
||||
desc: "var missing brace",
|
||||
m: String("a${missing"),
|
||||
encErr: "catmsg: missing '}'",
|
||||
tests: single("a$!(MISSINGBRACE)", ""),
|
||||
}}
|
||||
r := &renderer{}
|
||||
dec := NewDecoder(language.Und, r, macros)
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
|
||||
data, err := Compile(language.Und, macros, tc.m)
|
||||
if failErr(err, tc.encErr) {
|
||||
t.Errorf("encoding error: got %+q; want %+q", err, tc.encErr)
|
||||
}
|
||||
if tc.enc != "" && data != tc.enc {
|
||||
t.Errorf("encoding: got %+q; want %+q", data, tc.enc)
|
||||
}
|
||||
for _, st := range tc.tests {
|
||||
t.Run("", func(t *testing.T) {
|
||||
*r = renderer{args: st.args}
|
||||
if err = dec.Execute(data); failErr(err, st.decErr) {
|
||||
t.Errorf("decoding error: got %+q; want %+q", err, st.decErr)
|
||||
}
|
||||
if r.result != st.out {
|
||||
t.Errorf("decode: got %+q; want %+q", r.result, st.out)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func failErr(got error, want string) bool {
|
||||
if got == nil {
|
||||
return want != ""
|
||||
}
|
||||
return want == "" || !strings.Contains(got.Error(), want)
|
||||
}
|
||||
|
||||
type seq []Message
|
||||
|
||||
func (s seq) Compile(e *Encoder) (err error) {
|
||||
err = ErrIncomplete
|
||||
e.EncodeMessageType(First)
|
||||
for _, m := range s {
|
||||
// Pass only the last error, but allow erroneous or complete messages
|
||||
// here to allow testing different scenarios.
|
||||
err = e.EncodeMessage(m)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type empty struct{}
|
||||
|
||||
func (empty) Compile(e *Encoder) (err error) { return nil }
|
||||
|
||||
var msgIncomplete = Register(
|
||||
"golang.org/x/text/internal/catmsg.incomplete",
|
||||
func(d *Decoder) bool { return false })
|
||||
|
||||
type incomplete struct{}
|
||||
|
||||
func (incomplete) Compile(e *Encoder) (err error) {
|
||||
e.EncodeMessageType(msgIncomplete)
|
||||
return ErrIncomplete
|
||||
}
|
||||
|
||||
type errorCompileMsg struct{}
|
||||
|
||||
var errCompileTest = errors.New("catmsg: compile error test")
|
||||
|
||||
func (errorCompileMsg) Compile(e *Encoder) (err error) {
|
||||
return errCompileTest
|
||||
}
|
||||
|
||||
type dictionary struct{}
|
||||
|
||||
var (
|
||||
macros = dictionary{}
|
||||
dictMessages = map[string]string{
|
||||
"exists": compile(String("you betya!")),
|
||||
"incomplete": compile(incomplete{}),
|
||||
}
|
||||
)
|
||||
|
||||
func (d dictionary) Lookup(key string) (data string, ok bool) {
|
||||
data, ok = dictMessages[key]
|
||||
return
|
||||
}
|
||||
|
||||
func compile(m Message) (data string) {
|
||||
data, _ = Compile(language.Und, macros, m)
|
||||
return data
|
||||
}
|
||||
+407
@@ -0,0 +1,407 @@
|
||||
// Copyright 2017 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 catmsg
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
// A Renderer renders a Message.
|
||||
type Renderer interface {
|
||||
// Render renders the given string. The given string may be interpreted as a
|
||||
// format string, such as the one used by the fmt package or a template.
|
||||
Render(s string)
|
||||
|
||||
// Arg returns the i-th argument passed to format a message. This method
|
||||
// should return nil if there is no such argument. Messages need access to
|
||||
// arguments to allow selecting a message based on linguistic features of
|
||||
// those arguments.
|
||||
Arg(i int) interface{}
|
||||
}
|
||||
|
||||
// A Dictionary specifies a source of messages, including variables or macros.
|
||||
type Dictionary interface {
|
||||
// Lookup returns the message for the given key. It returns false for ok if
|
||||
// such a message could not be found.
|
||||
Lookup(key string) (data string, ok bool)
|
||||
|
||||
// TODO: consider returning an interface, instead of a string. This will
|
||||
// allow implementations to do their own message type decoding.
|
||||
}
|
||||
|
||||
// An Encoder serializes a Message to a string.
|
||||
type Encoder struct {
|
||||
// The root encoder is used for storing encoded variables.
|
||||
root *Encoder
|
||||
// The parent encoder provides the surrounding scopes for resolving variable
|
||||
// names.
|
||||
parent *Encoder
|
||||
|
||||
tag language.Tag
|
||||
|
||||
// buf holds the encoded message so far. After a message completes encoding,
|
||||
// the contents of buf, prefixed by the encoded length, are flushed to the
|
||||
// parent buffer.
|
||||
buf []byte
|
||||
|
||||
// vars is the lookup table of variables in the current scope.
|
||||
vars []keyVal
|
||||
|
||||
err error
|
||||
inBody bool // if false next call must be EncodeMessageType
|
||||
}
|
||||
|
||||
type keyVal struct {
|
||||
key string
|
||||
offset int
|
||||
}
|
||||
|
||||
// Language reports the language for which the encoded message will be stored
|
||||
// in the Catalog.
|
||||
func (e *Encoder) Language() language.Tag { return e.tag }
|
||||
|
||||
func (e *Encoder) setError(err error) {
|
||||
if e.root.err == nil {
|
||||
e.root.err = err
|
||||
}
|
||||
}
|
||||
|
||||
// EncodeUint encodes x.
|
||||
func (e *Encoder) EncodeUint(x uint64) {
|
||||
e.checkInBody()
|
||||
var buf [maxVarintBytes]byte
|
||||
n := encodeUint(buf[:], x)
|
||||
e.buf = append(e.buf, buf[:n]...)
|
||||
}
|
||||
|
||||
// EncodeString encodes s.
|
||||
func (e *Encoder) EncodeString(s string) {
|
||||
e.checkInBody()
|
||||
e.EncodeUint(uint64(len(s)))
|
||||
e.buf = append(e.buf, s...)
|
||||
}
|
||||
|
||||
// EncodeMessageType marks the current message to be of type h.
|
||||
//
|
||||
// It must be the first call of a Message's Compile method.
|
||||
func (e *Encoder) EncodeMessageType(h Handle) {
|
||||
if e.inBody {
|
||||
panic("catmsg: EncodeMessageType not the first method called")
|
||||
}
|
||||
e.inBody = true
|
||||
e.EncodeUint(uint64(h))
|
||||
}
|
||||
|
||||
// EncodeMessage serializes the given message inline at the current position.
|
||||
func (e *Encoder) EncodeMessage(m Message) error {
|
||||
e = &Encoder{root: e.root, parent: e}
|
||||
err := m.Compile(e)
|
||||
if _, ok := m.(*Var); !ok {
|
||||
e.flushTo(e.parent)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (e *Encoder) checkInBody() {
|
||||
if !e.inBody {
|
||||
panic("catmsg: expected prior call to EncodeMessageType")
|
||||
}
|
||||
}
|
||||
|
||||
// stripPrefix indicates the number of prefix bytes that must be stripped to
|
||||
// turn a single-element sequence into a message that is just this single member
|
||||
// without its size prefix. If the message can be stripped, b[1:n] contains the
|
||||
// size prefix.
|
||||
func stripPrefix(b []byte) (n int) {
|
||||
if len(b) > 0 && Handle(b[0]) == msgFirst {
|
||||
x, n, _ := decodeUint(b[1:])
|
||||
if 1+n+int(x) == len(b) {
|
||||
return 1 + n
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (e *Encoder) flushTo(dst *Encoder) {
|
||||
data := e.buf
|
||||
p := stripPrefix(data)
|
||||
if p > 0 {
|
||||
data = data[1:]
|
||||
} else {
|
||||
// Prefix the size.
|
||||
dst.EncodeUint(uint64(len(data)))
|
||||
}
|
||||
dst.buf = append(dst.buf, data...)
|
||||
}
|
||||
|
||||
func (e *Encoder) addVar(key string, m Message) error {
|
||||
for _, v := range e.parent.vars {
|
||||
if v.key == key {
|
||||
err := fmt.Errorf("catmsg: duplicate variable %q", key)
|
||||
e.setError(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
scope := e.parent
|
||||
// If a variable message is Incomplete, and does not evaluate to a message
|
||||
// during execution, we fall back to the variable name. We encode this by
|
||||
// appending the variable name if the message reports it's incomplete.
|
||||
|
||||
err := m.Compile(e)
|
||||
if err != ErrIncomplete {
|
||||
e.setError(err)
|
||||
}
|
||||
switch {
|
||||
case len(e.buf) == 1 && Handle(e.buf[0]) == msgFirst: // empty sequence
|
||||
e.buf = e.buf[:0]
|
||||
e.inBody = false
|
||||
fallthrough
|
||||
case len(e.buf) == 0:
|
||||
// Empty message.
|
||||
if err := String(key).Compile(e); err != nil {
|
||||
e.setError(err)
|
||||
}
|
||||
case err == ErrIncomplete:
|
||||
if Handle(e.buf[0]) != msgFirst {
|
||||
seq := &Encoder{root: e.root, parent: e}
|
||||
seq.EncodeMessageType(First)
|
||||
e.flushTo(seq)
|
||||
e = seq
|
||||
}
|
||||
// e contains a sequence; append the fallback string.
|
||||
e.EncodeMessage(String(key))
|
||||
}
|
||||
|
||||
// Flush result to variable heap.
|
||||
offset := len(e.root.buf)
|
||||
e.flushTo(e.root)
|
||||
e.buf = e.buf[:0]
|
||||
|
||||
// Record variable offset in current scope.
|
||||
scope.vars = append(scope.vars, keyVal{key: key, offset: offset})
|
||||
return err
|
||||
}
|
||||
|
||||
const (
|
||||
substituteVar = iota
|
||||
substituteMacro
|
||||
substituteError
|
||||
)
|
||||
|
||||
// EncodeSubstitution inserts a resolved reference to a variable or macro.
|
||||
//
|
||||
// This call must be matched with a call to ExecuteSubstitution at decoding
|
||||
// time.
|
||||
func (e *Encoder) EncodeSubstitution(name string, arguments ...int) {
|
||||
if arity := len(arguments); arity > 0 {
|
||||
// TODO: also resolve macros.
|
||||
e.EncodeUint(substituteMacro)
|
||||
e.EncodeString(name)
|
||||
for _, a := range arguments {
|
||||
e.EncodeUint(uint64(a))
|
||||
}
|
||||
return
|
||||
}
|
||||
for scope := e; scope != nil; scope = scope.parent {
|
||||
for _, v := range scope.vars {
|
||||
if v.key != name {
|
||||
continue
|
||||
}
|
||||
e.EncodeUint(substituteVar) // TODO: support arity > 0
|
||||
e.EncodeUint(uint64(v.offset))
|
||||
return
|
||||
}
|
||||
}
|
||||
// TODO: refer to dictionary-wide scoped variables.
|
||||
e.EncodeUint(substituteError)
|
||||
e.EncodeString(name)
|
||||
e.setError(fmt.Errorf("catmsg: unknown var %q", name))
|
||||
}
|
||||
|
||||
// A Decoder deserializes and evaluates messages that are encoded by an encoder.
|
||||
type Decoder struct {
|
||||
tag language.Tag
|
||||
dst Renderer
|
||||
macros Dictionary
|
||||
|
||||
err error
|
||||
vars string
|
||||
data string
|
||||
|
||||
macroArg int // TODO: allow more than one argument
|
||||
}
|
||||
|
||||
// NewDecoder returns a new Decoder.
|
||||
//
|
||||
// Decoders are designed to be reused for multiple invocations of Execute.
|
||||
// Only one goroutine may call Execute concurrently.
|
||||
func NewDecoder(tag language.Tag, r Renderer, macros Dictionary) *Decoder {
|
||||
return &Decoder{
|
||||
tag: tag,
|
||||
dst: r,
|
||||
macros: macros,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Decoder) setError(err error) {
|
||||
if d.err == nil {
|
||||
d.err = err
|
||||
}
|
||||
}
|
||||
|
||||
// Language returns the language in which the message is being rendered.
|
||||
//
|
||||
// The destination language may be a child language of the language used for
|
||||
// encoding. For instance, a decoding language of "pt-PT"" is consistent with an
|
||||
// encoding language of "pt".
|
||||
func (d *Decoder) Language() language.Tag { return d.tag }
|
||||
|
||||
// Done reports whether there are more bytes to process in this message.
|
||||
func (d *Decoder) Done() bool { return len(d.data) == 0 }
|
||||
|
||||
// Render implements Renderer.
|
||||
func (d *Decoder) Render(s string) { d.dst.Render(s) }
|
||||
|
||||
// Arg implements Renderer.
|
||||
//
|
||||
// During evaluation of macros, the argument positions may be mapped to
|
||||
// arguments that differ from the original call.
|
||||
func (d *Decoder) Arg(i int) interface{} {
|
||||
if d.macroArg != 0 {
|
||||
if i != 1 {
|
||||
panic("catmsg: only macros with single argument supported")
|
||||
}
|
||||
i = d.macroArg
|
||||
}
|
||||
return d.dst.Arg(i)
|
||||
}
|
||||
|
||||
// DecodeUint decodes a number that was encoded with EncodeUint and advances the
|
||||
// position.
|
||||
func (d *Decoder) DecodeUint() uint64 {
|
||||
x, n, err := decodeUintString(d.data)
|
||||
d.data = d.data[n:]
|
||||
if err != nil {
|
||||
d.setError(err)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// DecodeString decodes a string that was encoded with EncodeString and advances
|
||||
// the position.
|
||||
func (d *Decoder) DecodeString() string {
|
||||
size := d.DecodeUint()
|
||||
s := d.data[:size]
|
||||
d.data = d.data[size:]
|
||||
return s
|
||||
}
|
||||
|
||||
// SkipMessage skips the message at the current location and advances the
|
||||
// position.
|
||||
func (d *Decoder) SkipMessage() {
|
||||
n := int(d.DecodeUint())
|
||||
d.data = d.data[n:]
|
||||
}
|
||||
|
||||
// Execute decodes and evaluates msg.
|
||||
//
|
||||
// Only one goroutine may call execute.
|
||||
func (d *Decoder) Execute(msg string) error {
|
||||
d.err = nil
|
||||
if !d.execute(msg) {
|
||||
return ErrNoMatch
|
||||
}
|
||||
return d.err
|
||||
}
|
||||
|
||||
func (d *Decoder) execute(msg string) bool {
|
||||
saved := d.data
|
||||
d.data = msg
|
||||
ok := d.executeMessage()
|
||||
d.data = saved
|
||||
return ok
|
||||
}
|
||||
|
||||
// executeMessageFromData is like execute, but also decodes a leading message
|
||||
// size and clips the given string accordingly.
|
||||
//
|
||||
// It reports the number of bytes consumed and whether a message was selected.
|
||||
func (d *Decoder) executeMessageFromData(s string) (n int, ok bool) {
|
||||
saved := d.data
|
||||
d.data = s
|
||||
size := int(d.DecodeUint())
|
||||
n = len(s) - len(d.data)
|
||||
// Sanitize the setting. This allows skipping a size argument for
|
||||
// RawString and method Done.
|
||||
d.data = d.data[:size]
|
||||
ok = d.executeMessage()
|
||||
n += size - len(d.data)
|
||||
d.data = saved
|
||||
return n, ok
|
||||
}
|
||||
|
||||
var errUnknownHandler = errors.New("catmsg: string contains unsupported handler")
|
||||
|
||||
// executeMessage reads the handle id, initializes the decoder and executes the
|
||||
// message. It is assumed that all of d.data[d.p:] is the single message.
|
||||
func (d *Decoder) executeMessage() bool {
|
||||
if d.Done() {
|
||||
// We interpret no data as a valid empty message.
|
||||
return true
|
||||
}
|
||||
handle := d.DecodeUint()
|
||||
|
||||
var fn Handler
|
||||
mutex.Lock()
|
||||
if int(handle) < len(handlers) {
|
||||
fn = handlers[handle]
|
||||
}
|
||||
mutex.Unlock()
|
||||
if fn == nil {
|
||||
d.setError(errUnknownHandler)
|
||||
d.execute(fmt.Sprintf("\x02$!(UNKNOWNMSGHANDLER=%#x)", handle))
|
||||
return true
|
||||
}
|
||||
return fn(d)
|
||||
}
|
||||
|
||||
// ExecuteMessage decodes and executes the message at the current position.
|
||||
func (d *Decoder) ExecuteMessage() bool {
|
||||
n, ok := d.executeMessageFromData(d.data)
|
||||
d.data = d.data[n:]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ExecuteSubstitution executes the message corresponding to the substitution
|
||||
// as encoded by EncodeSubstitution.
|
||||
func (d *Decoder) ExecuteSubstitution() {
|
||||
switch x := d.DecodeUint(); x {
|
||||
case substituteVar:
|
||||
offset := d.DecodeUint()
|
||||
d.executeMessageFromData(d.vars[offset:])
|
||||
case substituteMacro:
|
||||
name := d.DecodeString()
|
||||
data, ok := d.macros.Lookup(name)
|
||||
old := d.macroArg
|
||||
// TODO: support macros of arity other than 1.
|
||||
d.macroArg = int(d.DecodeUint())
|
||||
switch {
|
||||
case !ok:
|
||||
// TODO: detect this at creation time.
|
||||
d.setError(fmt.Errorf("catmsg: undefined macro %q", name))
|
||||
fallthrough
|
||||
case !d.execute(data):
|
||||
d.dst.Render(name) // fall back to macro name.
|
||||
}
|
||||
d.macroArg = old
|
||||
case substituteError:
|
||||
d.dst.Render(d.DecodeString())
|
||||
default:
|
||||
panic("catmsg: unreachable")
|
||||
}
|
||||
}
|
||||
+33
-18
@@ -67,6 +67,15 @@ func VerifyDNSLength(verify bool) Option {
|
||||
return func(o *options) { o.verifyDNSLength = verify }
|
||||
}
|
||||
|
||||
// RemoveLeadingDots removes leading label separators. Leading runes that map to
|
||||
// dots, such as U+3002 IDEOGRAPHIC FULL STOP, are removed as well.
|
||||
//
|
||||
// This is the behavior suggested by the UTS #46 and is adopted by some
|
||||
// browsers.
|
||||
func RemoveLeadingDots(remove bool) Option {
|
||||
return func(o *options) { o.removeLeadingDots = remove }
|
||||
}
|
||||
|
||||
// ValidateLabels sets whether to check the mandatory label validation criteria
|
||||
// as defined in Section 5.4 of RFC 5891. This includes testing for correct use
|
||||
// of hyphens ('-'), normalization, validity of runes, and the context rules.
|
||||
@@ -133,14 +142,16 @@ func MapForLookup() Option {
|
||||
o.mapping = validateAndMap
|
||||
StrictDomainName(true)(o)
|
||||
ValidateLabels(true)(o)
|
||||
RemoveLeadingDots(true)(o)
|
||||
}
|
||||
}
|
||||
|
||||
type options struct {
|
||||
transitional bool
|
||||
useSTD3Rules bool
|
||||
validateLabels bool
|
||||
verifyDNSLength bool
|
||||
transitional bool
|
||||
useSTD3Rules bool
|
||||
validateLabels bool
|
||||
verifyDNSLength bool
|
||||
removeLeadingDots bool
|
||||
|
||||
trie *idnaTrie
|
||||
|
||||
@@ -240,21 +251,23 @@ var (
|
||||
|
||||
punycode = &Profile{}
|
||||
lookup = &Profile{options{
|
||||
transitional: true,
|
||||
useSTD3Rules: true,
|
||||
validateLabels: true,
|
||||
trie: trie,
|
||||
fromPuny: validateFromPunycode,
|
||||
mapping: validateAndMap,
|
||||
bidirule: bidirule.ValidString,
|
||||
transitional: true,
|
||||
useSTD3Rules: true,
|
||||
validateLabels: true,
|
||||
removeLeadingDots: true,
|
||||
trie: trie,
|
||||
fromPuny: validateFromPunycode,
|
||||
mapping: validateAndMap,
|
||||
bidirule: bidirule.ValidString,
|
||||
}}
|
||||
display = &Profile{options{
|
||||
useSTD3Rules: true,
|
||||
validateLabels: true,
|
||||
trie: trie,
|
||||
fromPuny: validateFromPunycode,
|
||||
mapping: validateAndMap,
|
||||
bidirule: bidirule.ValidString,
|
||||
useSTD3Rules: true,
|
||||
validateLabels: true,
|
||||
removeLeadingDots: true,
|
||||
trie: trie,
|
||||
fromPuny: validateFromPunycode,
|
||||
mapping: validateAndMap,
|
||||
bidirule: bidirule.ValidString,
|
||||
}}
|
||||
registration = &Profile{options{
|
||||
useSTD3Rules: true,
|
||||
@@ -293,7 +306,9 @@ func (p *Profile) process(s string, toASCII bool) (string, error) {
|
||||
s, err = p.mapping(p, s)
|
||||
}
|
||||
// Remove leading empty labels.
|
||||
for ; len(s) > 0 && s[0] == '.'; s = s[1:] {
|
||||
if p.removeLeadingDots {
|
||||
for ; len(s) > 0 && s[0] == '.'; s = s[1:] {
|
||||
}
|
||||
}
|
||||
// It seems like we should only create this error on ToASCII, but the
|
||||
// UTS 46 conformance tests suggests we should always check this.
|
||||
|
||||
+16
-7
@@ -117,7 +117,7 @@ func TestLabelErrors(t *testing.T) {
|
||||
f func(string) (string, error)
|
||||
}
|
||||
punyA := kind{"PunycodeA", punycode.ToASCII}
|
||||
resolve := kind{"ToASCII", Lookup.ToASCII}
|
||||
resolve := kind{"ResolveA", Lookup.ToASCII}
|
||||
display := kind{"ToUnicode", Display.ToUnicode}
|
||||
p := New(VerifyDNSLength(true), MapForLookup(), BidiRule())
|
||||
lengthU := kind{"CheckLengthU", p.ToUnicode}
|
||||
@@ -145,16 +145,25 @@ func TestLabelErrors(t *testing.T) {
|
||||
{display, "foo.xn--.bar", "foo..bar", ""},
|
||||
|
||||
{lengthA, "a..b", "a..b", "A4"},
|
||||
// Stripping leading empty labels here but not for "empty" punycode
|
||||
// above seems inconsistent, but seems to be applied by both the
|
||||
// conformance test and Chrome. Different interpretations would be
|
||||
// possible, though.
|
||||
{punyA, ".b", ".b", ""},
|
||||
// For backwards compatibility, the Punycode profile does not map runes.
|
||||
{punyA, "\u3002b", "xn--b-83t", ""},
|
||||
{punyA, "..b", "..b", ""},
|
||||
// Only strip leading empty labels for certain profiles. Stripping
|
||||
// leading empty labels here but not for "empty" punycode above seems
|
||||
// inconsistent, but seems to be applied by both the conformance test
|
||||
// and Chrome. So we turn it off by default, support it as an option,
|
||||
// and enable it in profiles where it seems commonplace.
|
||||
{lengthA, ".b", "b", ""},
|
||||
{lengthA, "\u3002b", "b", ""},
|
||||
{lengthA, "..b", "b", ""},
|
||||
{lengthA, "b..", "b..", ""}, // TODO: remove trailing dots?
|
||||
{lengthA, "b..", "b..", ""},
|
||||
|
||||
{resolve, "a..b", "a..b", ""},
|
||||
{resolve, ".b", "b", ""},
|
||||
{resolve, "\u3002b", "b", ""},
|
||||
{resolve, "..b", "b", ""},
|
||||
{resolve, "b..", "b..", ""}, // TODO: remove trailing dots?
|
||||
{resolve, "b..", "b..", ""},
|
||||
|
||||
// Raw punycode
|
||||
{punyA, "", "", ""},
|
||||
|
||||
+433
@@ -0,0 +1,433 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
//go:generate stringer -type RoundingMode
|
||||
|
||||
package number
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// RoundingMode determines how a number is rounded to the desired precision.
|
||||
type RoundingMode byte
|
||||
|
||||
const (
|
||||
ToNearestEven RoundingMode = iota // towards the nearest integer, or towards an even number if equidistant.
|
||||
ToNearestZero // towards the nearest integer, or towards zero if equidistant.
|
||||
ToNearestAway // towards the nearest integer, or away from zero if equidistant.
|
||||
ToPositiveInf // towards infinity
|
||||
ToNegativeInf // towards negative infinity
|
||||
ToZero // towards zero
|
||||
AwayFromZero // away from zero
|
||||
numModes
|
||||
)
|
||||
|
||||
// A RoundingContext indicates how a number should be converted to digits.
|
||||
type RoundingContext struct {
|
||||
Mode RoundingMode
|
||||
Increment int32 // if > 0, round to Increment * 10^-Scale
|
||||
|
||||
Precision int32 // maximum number of significant digits.
|
||||
Scale int32 // maximum number of decimals after the dot.
|
||||
}
|
||||
|
||||
const maxIntDigits = 20
|
||||
|
||||
// A Decimal represents floating point number represented in digits of the base
|
||||
// in which a number is to be displayed. Digits represents a number [0, 1.0),
|
||||
// and the absolute value represented by Decimal is Digits * 10^Exp.
|
||||
// Leading and trailing zeros may be omitted and Exp may point outside a valid
|
||||
// position in Digits.
|
||||
//
|
||||
// Examples:
|
||||
// Number Decimal
|
||||
// 12345 Digits: [1, 2, 3, 4, 5], Exp: 5
|
||||
// 12.345 Digits: [1, 2, 3, 4, 5], Exp: 2
|
||||
// 12000 Digits: [1, 2], Exp: 5
|
||||
// 0.00123 Digits: [1, 2, 3], Exp: -2
|
||||
type Decimal struct {
|
||||
Digits []byte // mantissa digits, big-endian
|
||||
Exp int32 // exponent
|
||||
Neg bool
|
||||
Inf bool // Takes precedence over Digits and Exp.
|
||||
NaN bool // Takes precedence over Inf.
|
||||
|
||||
buf [maxIntDigits]byte
|
||||
}
|
||||
|
||||
// normalize retuns a new Decimal with leading and trailing zeros removed.
|
||||
func (d *Decimal) normalize() (n Decimal) {
|
||||
n = *d
|
||||
b := n.Digits
|
||||
// Strip leading zeros. Resulting number of digits is significant digits.
|
||||
for len(b) > 0 && b[0] == 0 {
|
||||
b = b[1:]
|
||||
n.Exp--
|
||||
}
|
||||
// Strip trailing zeros
|
||||
for len(b) > 0 && b[len(b)-1] == 0 {
|
||||
b = b[:len(b)-1]
|
||||
}
|
||||
if len(b) == 0 {
|
||||
n.Exp = 0
|
||||
}
|
||||
n.Digits = b
|
||||
return n
|
||||
}
|
||||
|
||||
func (d *Decimal) clear() {
|
||||
b := d.Digits
|
||||
if b == nil {
|
||||
b = d.buf[:0]
|
||||
}
|
||||
*d = Decimal{}
|
||||
d.Digits = b[:0]
|
||||
}
|
||||
|
||||
func (x *Decimal) String() string {
|
||||
if x.NaN {
|
||||
return "NaN"
|
||||
}
|
||||
var buf []byte
|
||||
if x.Neg {
|
||||
buf = append(buf, '-')
|
||||
}
|
||||
if x.Inf {
|
||||
buf = append(buf, "Inf"...)
|
||||
return string(buf)
|
||||
}
|
||||
switch {
|
||||
case len(x.Digits) == 0:
|
||||
buf = append(buf, '0')
|
||||
case x.Exp <= 0:
|
||||
// 0.00ddd
|
||||
buf = append(buf, "0."...)
|
||||
buf = appendZeros(buf, -int(x.Exp))
|
||||
buf = appendDigits(buf, x.Digits)
|
||||
|
||||
case /* 0 < */ int(x.Exp) < len(x.Digits):
|
||||
// dd.ddd
|
||||
buf = appendDigits(buf, x.Digits[:x.Exp])
|
||||
buf = append(buf, '.')
|
||||
buf = appendDigits(buf, x.Digits[x.Exp:])
|
||||
|
||||
default: // len(x.Digits) <= x.Exp
|
||||
// ddd00
|
||||
buf = appendDigits(buf, x.Digits)
|
||||
buf = appendZeros(buf, int(x.Exp)-len(x.Digits))
|
||||
}
|
||||
return string(buf)
|
||||
}
|
||||
|
||||
func appendDigits(buf []byte, digits []byte) []byte {
|
||||
for _, c := range digits {
|
||||
buf = append(buf, c+'0')
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
// appendZeros appends n 0 digits to buf and returns buf.
|
||||
func appendZeros(buf []byte, n int) []byte {
|
||||
for ; n > 0; n-- {
|
||||
buf = append(buf, '0')
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
func (d *Decimal) round(mode RoundingMode, n int) {
|
||||
if n >= len(d.Digits) {
|
||||
return
|
||||
}
|
||||
// Make rounding decision: The result mantissa is truncated ("rounded down")
|
||||
// by default. Decide if we need to increment, or "round up", the (unsigned)
|
||||
// mantissa.
|
||||
inc := false
|
||||
switch mode {
|
||||
case ToNegativeInf:
|
||||
inc = d.Neg
|
||||
case ToPositiveInf:
|
||||
inc = !d.Neg
|
||||
case ToZero:
|
||||
// nothing to do
|
||||
case AwayFromZero:
|
||||
inc = true
|
||||
case ToNearestEven:
|
||||
inc = d.Digits[n] > 5 || d.Digits[n] == 5 &&
|
||||
(len(d.Digits) > n+1 || n == 0 || d.Digits[n-1]&1 != 0)
|
||||
case ToNearestAway:
|
||||
inc = d.Digits[n] >= 5
|
||||
case ToNearestZero:
|
||||
inc = d.Digits[n] > 5 || d.Digits[n] == 5 && len(d.Digits) > n+1
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
if inc {
|
||||
d.roundUp(n)
|
||||
} else {
|
||||
d.roundDown(n)
|
||||
}
|
||||
}
|
||||
|
||||
// roundFloat rounds a floating point number.
|
||||
func (r RoundingMode) roundFloat(x float64) float64 {
|
||||
// Make rounding decision: The result mantissa is truncated ("rounded down")
|
||||
// by default. Decide if we need to increment, or "round up", the (unsigned)
|
||||
// mantissa.
|
||||
abs := x
|
||||
if x < 0 {
|
||||
abs = -x
|
||||
}
|
||||
i, f := math.Modf(abs)
|
||||
if f == 0.0 {
|
||||
return x
|
||||
}
|
||||
inc := false
|
||||
switch r {
|
||||
case ToNegativeInf:
|
||||
inc = x < 0
|
||||
case ToPositiveInf:
|
||||
inc = x >= 0
|
||||
case ToZero:
|
||||
// nothing to do
|
||||
case AwayFromZero:
|
||||
inc = true
|
||||
case ToNearestEven:
|
||||
// TODO: check overflow
|
||||
inc = f > 0.5 || f == 0.5 && int64(i)&1 != 0
|
||||
case ToNearestAway:
|
||||
inc = f >= 0.5
|
||||
case ToNearestZero:
|
||||
inc = f > 0.5
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
if inc {
|
||||
i += 1
|
||||
}
|
||||
if abs != x {
|
||||
i = -i
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func (x *Decimal) roundUp(n int) {
|
||||
if n < 0 || n >= len(x.Digits) {
|
||||
return // nothing to do
|
||||
}
|
||||
// find first digit < 9
|
||||
for n > 0 && x.Digits[n-1] >= 9 {
|
||||
n--
|
||||
}
|
||||
|
||||
if n == 0 {
|
||||
// all digits are 9s => round up to 1 and update exponent
|
||||
x.Digits[0] = 1 // ok since len(x.Digits) > n
|
||||
x.Digits = x.Digits[:1]
|
||||
x.Exp++
|
||||
return
|
||||
}
|
||||
x.Digits[n-1]++
|
||||
x.Digits = x.Digits[:n]
|
||||
// x already trimmed
|
||||
}
|
||||
|
||||
func (x *Decimal) roundDown(n int) {
|
||||
if n < 0 || n >= len(x.Digits) {
|
||||
return // nothing to do
|
||||
}
|
||||
x.Digits = x.Digits[:n]
|
||||
trim(x)
|
||||
}
|
||||
|
||||
// trim cuts off any trailing zeros from x's mantissa;
|
||||
// they are meaningless for the value of x.
|
||||
func trim(x *Decimal) {
|
||||
i := len(x.Digits)
|
||||
for i > 0 && x.Digits[i-1] == 0 {
|
||||
i--
|
||||
}
|
||||
x.Digits = x.Digits[:i]
|
||||
if i == 0 {
|
||||
x.Exp = 0
|
||||
}
|
||||
}
|
||||
|
||||
// A Converter converts a number into decimals according to the given rounding
|
||||
// criteria.
|
||||
type Converter interface {
|
||||
Convert(d *Decimal, r *RoundingContext)
|
||||
}
|
||||
|
||||
const (
|
||||
signed = true
|
||||
unsigned = false
|
||||
)
|
||||
|
||||
// Convert converts the given number to the decimal representation using the
|
||||
// supplied RoundingContext.
|
||||
func (d *Decimal) Convert(r *RoundingContext, number interface{}) {
|
||||
switch f := number.(type) {
|
||||
case Converter:
|
||||
d.clear()
|
||||
f.Convert(d, r)
|
||||
case float32:
|
||||
d.ConvertFloat(r, float64(f), 32)
|
||||
case float64:
|
||||
d.ConvertFloat(r, f, 64)
|
||||
case int:
|
||||
d.ConvertInt(r, signed, uint64(f))
|
||||
case int8:
|
||||
d.ConvertInt(r, signed, uint64(f))
|
||||
case int16:
|
||||
d.ConvertInt(r, signed, uint64(f))
|
||||
case int32:
|
||||
d.ConvertInt(r, signed, uint64(f))
|
||||
case int64:
|
||||
d.ConvertInt(r, signed, uint64(f))
|
||||
case uint:
|
||||
d.ConvertInt(r, unsigned, uint64(f))
|
||||
case uint8:
|
||||
d.ConvertInt(r, unsigned, uint64(f))
|
||||
case uint16:
|
||||
d.ConvertInt(r, unsigned, uint64(f))
|
||||
case uint32:
|
||||
d.ConvertInt(r, unsigned, uint64(f))
|
||||
case uint64:
|
||||
d.ConvertInt(r, unsigned, f)
|
||||
|
||||
// TODO:
|
||||
// case string: if produced by strconv, allows for easy arbitrary pos.
|
||||
// case reflect.Value:
|
||||
// case big.Float
|
||||
// case big.Int
|
||||
// case big.Rat?
|
||||
// catch underlyings using reflect or will this already be done by the
|
||||
// message package?
|
||||
}
|
||||
}
|
||||
|
||||
// ConvertInt converts an integer to decimals.
|
||||
func (d *Decimal) ConvertInt(r *RoundingContext, signed bool, x uint64) {
|
||||
if r.Increment > 0 {
|
||||
// TODO: if uint64 is too large, fall back to float64
|
||||
if signed {
|
||||
d.ConvertFloat(r, float64(int64(x)), 64)
|
||||
} else {
|
||||
d.ConvertFloat(r, float64(x), 64)
|
||||
}
|
||||
return
|
||||
}
|
||||
d.clear()
|
||||
if signed && int64(x) < 0 {
|
||||
x = uint64(-int64(x))
|
||||
d.Neg = true
|
||||
}
|
||||
d.fillIntDigits(x)
|
||||
d.Exp = int32(len(d.Digits))
|
||||
}
|
||||
|
||||
// ConvertFloat converts a floating point number to decimals.
|
||||
func (d *Decimal) ConvertFloat(r *RoundingContext, x float64, size int) {
|
||||
d.clear()
|
||||
if math.IsNaN(x) {
|
||||
d.NaN = true
|
||||
return
|
||||
}
|
||||
abs := x
|
||||
if x < 0 {
|
||||
d.Neg = true
|
||||
abs = -x
|
||||
}
|
||||
if math.IsInf(abs, 1) {
|
||||
d.Inf = true
|
||||
return
|
||||
}
|
||||
// Simple case: decimal notation
|
||||
if r.Scale > 0 || r.Increment > 0 || r.Precision == 0 {
|
||||
if int(r.Scale) > len(scales) {
|
||||
x *= math.Pow(10, float64(r.Scale))
|
||||
} else {
|
||||
x *= scales[r.Scale]
|
||||
}
|
||||
if r.Increment > 0 {
|
||||
inc := float64(r.Increment)
|
||||
x /= float64(inc)
|
||||
x = r.Mode.roundFloat(x)
|
||||
x *= inc
|
||||
} else {
|
||||
x = r.Mode.roundFloat(x)
|
||||
}
|
||||
d.fillIntDigits(uint64(math.Abs(x)))
|
||||
d.Exp = int32(len(d.Digits)) - r.Scale
|
||||
return
|
||||
}
|
||||
|
||||
// Nasty case (for non-decimal notation).
|
||||
// Asides from being inefficient, this result is also wrong as it will
|
||||
// apply ToNearestEven rounding regardless of the user setting.
|
||||
// TODO: expose functionality in strconv so we can avoid this hack.
|
||||
// Something like this would work:
|
||||
// AppendDigits(dst []byte, x float64, base, size, prec int) (digits []byte, exp, accuracy int)
|
||||
// TODO: This only supports the nearest even rounding mode.
|
||||
|
||||
prec := int(r.Precision)
|
||||
if prec > 0 {
|
||||
prec--
|
||||
}
|
||||
b := strconv.AppendFloat(d.Digits, abs, 'e', prec, size)
|
||||
i := 0
|
||||
k := 0
|
||||
// No need to check i < len(b) as we always have an 'e'.
|
||||
for {
|
||||
if c := b[i]; '0' <= c && c <= '9' {
|
||||
b[k] = c - '0'
|
||||
k++
|
||||
} else if c != '.' {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
d.Digits = b[:k]
|
||||
i += len("e")
|
||||
pSign := i
|
||||
exp := 0
|
||||
for i++; i < len(b); i++ {
|
||||
exp *= 10
|
||||
exp += int(b[i] - '0')
|
||||
}
|
||||
if b[pSign] == '-' {
|
||||
exp = -exp
|
||||
}
|
||||
d.Exp = int32(exp) + 1
|
||||
}
|
||||
|
||||
func (d *Decimal) fillIntDigits(x uint64) {
|
||||
if cap(d.Digits) < maxIntDigits {
|
||||
d.Digits = d.buf[:]
|
||||
} else {
|
||||
d.Digits = d.buf[:maxIntDigits]
|
||||
}
|
||||
i := 0
|
||||
for ; x > 0; x /= 10 {
|
||||
d.Digits[i] = byte(x % 10)
|
||||
i++
|
||||
}
|
||||
d.Digits = d.Digits[:i]
|
||||
for p := 0; p < i; p++ {
|
||||
i--
|
||||
d.Digits[p], d.Digits[i] = d.Digits[i], d.Digits[p]
|
||||
}
|
||||
}
|
||||
|
||||
var scales [70]float64
|
||||
|
||||
func init() {
|
||||
x := 1.0
|
||||
for i := range scales {
|
||||
scales[i] = x
|
||||
x *= 10
|
||||
}
|
||||
}
|
||||
+291
@@ -0,0 +1,291 @@
|
||||
// Copyright 2017 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 number
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func mkfloat(num string) float64 {
|
||||
u, _ := strconv.ParseUint(num, 10, 32)
|
||||
return float64(u)
|
||||
}
|
||||
|
||||
// mkdec creates a decimal from a string. All ASCII digits are converted to
|
||||
// digits in the decimal. The dot is used to indicate the scale by which the
|
||||
// digits are shifted. Numbers may have an additional exponent or be the special
|
||||
// value NaN, Inf, or -Inf.
|
||||
func mkdec(num string) (d Decimal) {
|
||||
if num[0] == '-' {
|
||||
d.Neg = true
|
||||
num = num[1:]
|
||||
}
|
||||
switch num {
|
||||
case "NaN":
|
||||
d.NaN = true
|
||||
return
|
||||
case "Inf":
|
||||
d.Inf = true
|
||||
return
|
||||
}
|
||||
if p := strings.IndexAny(num, "eE"); p != -1 {
|
||||
i64, err := strconv.ParseInt(num[p+1:], 10, 32)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
d.Exp = int32(i64)
|
||||
num = num[:p]
|
||||
}
|
||||
if p := strings.IndexByte(num, '.'); p != -1 {
|
||||
d.Exp += int32(p)
|
||||
num = num[:p] + num[p+1:]
|
||||
} else {
|
||||
d.Exp += int32(len(num))
|
||||
}
|
||||
d.Digits = []byte(num)
|
||||
for i := range d.Digits {
|
||||
d.Digits[i] -= '0'
|
||||
}
|
||||
return d.normalize()
|
||||
}
|
||||
|
||||
func byteNum(s string) []byte {
|
||||
b := make([]byte, len(s))
|
||||
for i := 0; i < len(s); i++ {
|
||||
if c := s[i]; '0' <= c && c <= '9' {
|
||||
b[i] = s[i] - '0'
|
||||
} else {
|
||||
b[i] = s[i] - 'a' + 10
|
||||
}
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func strNum(s string) string {
|
||||
return string(byteNum(s))
|
||||
}
|
||||
|
||||
func TestDecimalString(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
x Decimal
|
||||
want string
|
||||
}{
|
||||
{want: "0"},
|
||||
{Decimal{Digits: nil, Exp: 1000}, "0"}, // exponent of 1000 is ignored
|
||||
{Decimal{Digits: byteNum("12345"), Exp: 0}, "0.12345"},
|
||||
{Decimal{Digits: byteNum("12345"), Exp: -3}, "0.00012345"},
|
||||
{Decimal{Digits: byteNum("12345"), Exp: +3}, "123.45"},
|
||||
{Decimal{Digits: byteNum("12345"), Exp: +10}, "1234500000"},
|
||||
} {
|
||||
if got := test.x.String(); got != test.want {
|
||||
t.Errorf("%v == %q; want %q", test.x, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRounding(t *testing.T) {
|
||||
testCases := []struct {
|
||||
x string
|
||||
n int
|
||||
// modes is the result for modes. Signs are left out of the result.
|
||||
// The results are stored in the following order:
|
||||
// zero, negInf
|
||||
// nearZero, nearEven, nearAway
|
||||
// away, posInf
|
||||
modes [numModes]string
|
||||
}{
|
||||
{"0", 1, [numModes]string{
|
||||
"0", "0",
|
||||
"0", "0", "0",
|
||||
"0", "0"}},
|
||||
{"1", 1, [numModes]string{
|
||||
"1", "1",
|
||||
"1", "1", "1",
|
||||
"1", "1"}},
|
||||
{"5", 1, [numModes]string{
|
||||
"5", "5",
|
||||
"5", "5", "5",
|
||||
"5", "5"}},
|
||||
{"15", 1, [numModes]string{
|
||||
"10", "10",
|
||||
"10", "20", "20",
|
||||
"20", "20"}},
|
||||
{"45", 1, [numModes]string{
|
||||
"40", "40",
|
||||
"40", "40", "50",
|
||||
"50", "50"}},
|
||||
{"95", 1, [numModes]string{
|
||||
"90", "90",
|
||||
"90", "100", "100",
|
||||
"100", "100"}},
|
||||
|
||||
{"12344999", 4, [numModes]string{
|
||||
"12340000", "12340000",
|
||||
"12340000", "12340000", "12340000",
|
||||
"12350000", "12350000"}},
|
||||
{"12345000", 4, [numModes]string{
|
||||
"12340000", "12340000",
|
||||
"12340000", "12340000", "12350000",
|
||||
"12350000", "12350000"}},
|
||||
{"12345001", 4, [numModes]string{
|
||||
"12340000", "12340000",
|
||||
"12350000", "12350000", "12350000",
|
||||
"12350000", "12350000"}},
|
||||
{"12345100", 4, [numModes]string{
|
||||
"12340000", "12340000",
|
||||
"12350000", "12350000", "12350000",
|
||||
"12350000", "12350000"}},
|
||||
{"23454999", 4, [numModes]string{
|
||||
"23450000", "23450000",
|
||||
"23450000", "23450000", "23450000",
|
||||
"23460000", "23460000"}},
|
||||
{"23455000", 4, [numModes]string{
|
||||
"23450000", "23450000",
|
||||
"23450000", "23460000", "23460000",
|
||||
"23460000", "23460000"}},
|
||||
{"23455001", 4, [numModes]string{
|
||||
"23450000", "23450000",
|
||||
"23460000", "23460000", "23460000",
|
||||
"23460000", "23460000"}},
|
||||
{"23455100", 4, [numModes]string{
|
||||
"23450000", "23450000",
|
||||
"23460000", "23460000", "23460000",
|
||||
"23460000", "23460000"}},
|
||||
|
||||
{"99994999", 4, [numModes]string{
|
||||
"99990000", "99990000",
|
||||
"99990000", "99990000", "99990000",
|
||||
"100000000", "100000000"}},
|
||||
{"99995000", 4, [numModes]string{
|
||||
"99990000", "99990000",
|
||||
"99990000", "100000000", "100000000",
|
||||
"100000000", "100000000"}},
|
||||
{"99999999", 4, [numModes]string{
|
||||
"99990000", "99990000",
|
||||
"100000000", "100000000", "100000000",
|
||||
"100000000", "100000000"}},
|
||||
|
||||
{"12994999", 4, [numModes]string{
|
||||
"12990000", "12990000",
|
||||
"12990000", "12990000", "12990000",
|
||||
"13000000", "13000000"}},
|
||||
{"12995000", 4, [numModes]string{
|
||||
"12990000", "12990000",
|
||||
"12990000", "13000000", "13000000",
|
||||
"13000000", "13000000"}},
|
||||
{"12999999", 4, [numModes]string{
|
||||
"12990000", "12990000",
|
||||
"13000000", "13000000", "13000000",
|
||||
"13000000", "13000000"}},
|
||||
}
|
||||
modes := []RoundingMode{
|
||||
ToZero, ToNegativeInf,
|
||||
ToNearestZero, ToNearestEven, ToNearestAway,
|
||||
AwayFromZero, ToPositiveInf,
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
// Create negative counterpart tests: the sign is reversed and
|
||||
// ToPositiveInf and ToNegativeInf swapped.
|
||||
negModes := tc.modes
|
||||
negModes[1], negModes[6] = negModes[6], negModes[1]
|
||||
for i, res := range negModes {
|
||||
negModes[i] = "-" + res
|
||||
}
|
||||
for i, m := range modes {
|
||||
t.Run(fmt.Sprintf("x:%s/n:%d/%s", tc.x, tc.n, m), func(t *testing.T) {
|
||||
d := mkdec(tc.x)
|
||||
d.round(m, tc.n)
|
||||
if got := d.String(); got != tc.modes[i] {
|
||||
t.Errorf("pos decimal: got %q; want %q", d.String(), tc.modes[i])
|
||||
}
|
||||
|
||||
mult := math.Pow(10, float64(len(tc.x)-tc.n))
|
||||
f := mkfloat(tc.x)
|
||||
f = m.roundFloat(f/mult) * mult
|
||||
if got := fmt.Sprintf("%.0f", f); got != tc.modes[i] {
|
||||
t.Errorf("pos float: got %q; want %q", got, tc.modes[i])
|
||||
}
|
||||
|
||||
// Test the negative case. This is the same as the positive
|
||||
// case, but with ToPositiveInf and ToNegativeInf swapped.
|
||||
d = mkdec(tc.x)
|
||||
d.Neg = true
|
||||
d.round(m, tc.n)
|
||||
if got, want := d.String(), negModes[i]; got != want {
|
||||
t.Errorf("neg decimal: got %q; want %q", d.String(), want)
|
||||
}
|
||||
|
||||
f = -mkfloat(tc.x)
|
||||
f = m.roundFloat(f/mult) * mult
|
||||
if got := fmt.Sprintf("%.0f", f); got != negModes[i] {
|
||||
t.Errorf("neg float: got %q; want %q", got, negModes[i])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvert(t *testing.T) {
|
||||
scale2 := &RoundingContext{Scale: 2}
|
||||
scale2away := &RoundingContext{Scale: 2, Mode: AwayFromZero}
|
||||
inc0_05 := &RoundingContext{Increment: 5, Scale: 2}
|
||||
inc50 := &RoundingContext{Increment: 50}
|
||||
prec3 := &RoundingContext{Precision: 3}
|
||||
testCases := []struct {
|
||||
x interface{}
|
||||
rc *RoundingContext
|
||||
out string
|
||||
}{
|
||||
{int8(-34), scale2, "-34"},
|
||||
{int16(-234), scale2, "-234"},
|
||||
{int32(-234), scale2, "-234"},
|
||||
{int64(-234), scale2, "-234"},
|
||||
{int(-234), scale2, "-234"},
|
||||
{uint8(234), scale2, "234"},
|
||||
{uint16(234), scale2, "234"},
|
||||
{uint32(234), scale2, "234"},
|
||||
{uint64(234), scale2, "234"},
|
||||
{uint(234), scale2, "234"},
|
||||
{-0.001, scale2, "-0"},
|
||||
{-1e9, scale2, "-1000000000.00"},
|
||||
{0.234, scale2, "0.23"},
|
||||
{0.234, scale2away, "0.24"},
|
||||
{0.1234, prec3, "0.123"},
|
||||
{1234.0, prec3, "1230"},
|
||||
{1.2345e10, prec3, "12300000000"},
|
||||
|
||||
{0.03, inc0_05, "0.05"},
|
||||
{0.025, inc0_05, "0"},
|
||||
{0.075, inc0_05, "0.10"},
|
||||
{325, inc50, "300"},
|
||||
{375, inc50, "400"},
|
||||
|
||||
{converter(3), scale2, "100"},
|
||||
|
||||
{math.Inf(1), inc50, "Inf"},
|
||||
{math.Inf(-1), inc50, "-Inf"},
|
||||
{math.NaN(), inc50, "NaN"},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
var d Decimal
|
||||
t.Run(fmt.Sprintf("%T:%v-%v", tc.x, tc.x, tc.rc), func(t *testing.T) {
|
||||
d.Convert(tc.rc, tc.x)
|
||||
if got := d.String(); got != tc.out {
|
||||
t.Errorf("got %q; want %q", got, tc.out)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type converter int
|
||||
|
||||
func (c converter) Convert(d *Decimal, r *RoundingContext) {
|
||||
d.Digits = append(d.Digits, 1, 0, 0)
|
||||
d.Exp = 3
|
||||
}
|
||||
+467
@@ -0,0 +1,467 @@
|
||||
// Copyright 2017 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 number
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
// TODO:
|
||||
// - grouping of fractions
|
||||
// - allow user-defined superscript notation (such as <sup>4</sup>)
|
||||
// - same for non-breaking spaces, like
|
||||
|
||||
// Formatting proceeds along the following lines:
|
||||
// 0) Compose rounding information from format and context.
|
||||
// 1) Convert a number into a Decimal.
|
||||
// 2) Sanitize Decimal by adding trailing zeros, removing leading digits, and
|
||||
// (non-increment) rounding. The Decimal that results from this is suitable
|
||||
// for determining the plural form.
|
||||
// 3) Render the Decimal in the localized form.
|
||||
|
||||
// Formatter contains all the information needed to render a number.
|
||||
type Formatter struct {
|
||||
Pattern
|
||||
Info
|
||||
RoundingContext
|
||||
}
|
||||
|
||||
func (f *Formatter) init(t language.Tag, index []uint8) {
|
||||
f.Info = InfoFromTag(t)
|
||||
for ; ; t = t.Parent() {
|
||||
if ci, ok := language.CompactIndex(t); ok {
|
||||
f.Pattern = formats[index[ci]]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// InitPattern initializes a Formatter for the given Pattern.
|
||||
func (f *Formatter) InitPattern(t language.Tag, pat *Pattern) {
|
||||
f.Info = InfoFromTag(t)
|
||||
f.Pattern = *pat
|
||||
}
|
||||
|
||||
// InitDecimal initializes a Formatter using the default Pattern for the given
|
||||
// language.
|
||||
func (f *Formatter) InitDecimal(t language.Tag) {
|
||||
f.init(t, tagToDecimal)
|
||||
}
|
||||
|
||||
// InitScientific initializes a Formatter using the default Pattern for the
|
||||
// given language.
|
||||
func (f *Formatter) InitScientific(t language.Tag) {
|
||||
f.init(t, tagToScientific)
|
||||
}
|
||||
|
||||
// InitEngineering initializes a Formatter using the default Pattern for the
|
||||
// given language.
|
||||
func (f *Formatter) InitEngineering(t language.Tag) {
|
||||
f.init(t, tagToScientific)
|
||||
f.Pattern.MaxIntegerDigits = 3
|
||||
f.Pattern.MinIntegerDigits = 1
|
||||
}
|
||||
|
||||
// InitPercent initializes a Formatter using the default Pattern for the given
|
||||
// language.
|
||||
func (f *Formatter) InitPercent(t language.Tag) {
|
||||
f.init(t, tagToPercent)
|
||||
}
|
||||
|
||||
// InitPerMille initializes a Formatter using the default Pattern for the given
|
||||
// language.
|
||||
func (f *Formatter) InitPerMille(t language.Tag) {
|
||||
f.init(t, tagToPercent)
|
||||
f.Pattern.DigitShift = 3
|
||||
}
|
||||
|
||||
func (f *Formatter) Append(dst []byte, x interface{}) []byte {
|
||||
var d Decimal
|
||||
d.Convert(&f.RoundingContext, x)
|
||||
return f.Format(dst, &d)
|
||||
}
|
||||
|
||||
func (f *Formatter) Format(dst []byte, d *Decimal) []byte {
|
||||
var result []byte
|
||||
var postPrefix, preSuffix int
|
||||
if f.MinExponentDigits > 0 {
|
||||
result, postPrefix, preSuffix = appendScientific(dst, f, d)
|
||||
} else {
|
||||
result, postPrefix, preSuffix = appendDecimal(dst, f, d)
|
||||
}
|
||||
if f.PadRune == 0 {
|
||||
return result
|
||||
}
|
||||
width := int(f.FormatWidth)
|
||||
if count := utf8.RuneCount(result); count < width {
|
||||
insertPos := 0
|
||||
switch f.Flags & PadMask {
|
||||
case PadAfterPrefix:
|
||||
insertPos = postPrefix
|
||||
case PadBeforeSuffix:
|
||||
insertPos = preSuffix
|
||||
case PadAfterSuffix:
|
||||
insertPos = len(result)
|
||||
}
|
||||
num := width - count
|
||||
pad := [utf8.UTFMax]byte{' '}
|
||||
sz := 1
|
||||
if r := f.PadRune; r != 0 {
|
||||
sz = utf8.EncodeRune(pad[:], r)
|
||||
}
|
||||
extra := sz * num
|
||||
if n := len(result) + extra; n < cap(result) {
|
||||
result = result[:n]
|
||||
copy(result[insertPos+extra:], result[insertPos:])
|
||||
} else {
|
||||
buf := make([]byte, n)
|
||||
copy(buf, result[:insertPos])
|
||||
copy(buf[insertPos+extra:], result[insertPos:])
|
||||
result = buf
|
||||
}
|
||||
for ; num > 0; num-- {
|
||||
insertPos += copy(result[insertPos:], pad[:sz])
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// appendDecimal appends a formatted number to dst. It returns two possible
|
||||
// insertion points for padding.
|
||||
func appendDecimal(dst []byte, f *Formatter, d *Decimal) (b []byte, postPre, preSuf int) {
|
||||
if dst, ok := f.renderSpecial(dst, d); ok {
|
||||
return dst, 0, len(dst)
|
||||
}
|
||||
n := d.normalize()
|
||||
if maxSig := int(f.MaxSignificantDigits); maxSig > 0 {
|
||||
n.round(ToZero, maxSig)
|
||||
}
|
||||
digits := n.Digits
|
||||
exp := n.Exp
|
||||
exp += int32(f.Pattern.DigitShift)
|
||||
|
||||
// Split in integer and fraction part.
|
||||
var intDigits, fracDigits []byte
|
||||
var numInt, numFrac int
|
||||
if exp > 0 {
|
||||
numInt = int(exp)
|
||||
if int(exp) >= len(digits) { // ddddd | ddddd00
|
||||
intDigits = digits
|
||||
} else { // ddd.dd
|
||||
intDigits = digits[:exp]
|
||||
fracDigits = digits[exp:]
|
||||
numFrac = len(fracDigits)
|
||||
}
|
||||
} else {
|
||||
fracDigits = digits
|
||||
numFrac = -int(exp) + len(digits)
|
||||
}
|
||||
// Cap integer digits. Remove *most-significant* digits.
|
||||
if f.MaxIntegerDigits > 0 && numInt > int(f.MaxIntegerDigits) {
|
||||
offset := numInt - int(f.MaxIntegerDigits)
|
||||
if offset > len(intDigits) {
|
||||
numInt = 0
|
||||
intDigits = nil
|
||||
} else {
|
||||
numInt = int(f.MaxIntegerDigits)
|
||||
intDigits = intDigits[offset:]
|
||||
// for keeping track of significant digits
|
||||
digits = digits[offset:]
|
||||
}
|
||||
// Strip leading zeros. Resulting number of digits is significant digits.
|
||||
for len(intDigits) > 0 && intDigits[0] == 0 {
|
||||
intDigits = intDigits[1:]
|
||||
digits = digits[1:]
|
||||
numInt--
|
||||
}
|
||||
}
|
||||
if f.MaxSignificantDigits == 0 && int(f.MaxFractionDigits) < numFrac {
|
||||
if extra := numFrac - int(f.MaxFractionDigits); extra > len(fracDigits) {
|
||||
numFrac = 0
|
||||
fracDigits = nil
|
||||
} else {
|
||||
numFrac = int(f.MaxFractionDigits)
|
||||
fracDigits = fracDigits[:len(fracDigits)-extra]
|
||||
}
|
||||
}
|
||||
|
||||
neg := d.Neg
|
||||
affix, suffix := f.getAffixes(neg)
|
||||
dst = appendAffix(dst, f, affix, neg)
|
||||
savedLen := len(dst)
|
||||
|
||||
minInt := int(f.MinIntegerDigits)
|
||||
if minInt == 0 && f.MinSignificantDigits > 0 {
|
||||
minInt = 1
|
||||
}
|
||||
// add leading zeros
|
||||
for i := minInt; i > numInt; i-- {
|
||||
dst = f.AppendDigit(dst, 0)
|
||||
if f.needsSep(i) {
|
||||
dst = append(dst, f.Symbol(SymGroup)...)
|
||||
}
|
||||
}
|
||||
i := 0
|
||||
for ; i < len(intDigits); i++ {
|
||||
dst = f.AppendDigit(dst, intDigits[i])
|
||||
if f.needsSep(numInt - i) {
|
||||
dst = append(dst, f.Symbol(SymGroup)...)
|
||||
}
|
||||
}
|
||||
for ; i < numInt; i++ {
|
||||
dst = f.AppendDigit(dst, 0)
|
||||
if f.needsSep(numInt - i) {
|
||||
dst = append(dst, f.Symbol(SymGroup)...)
|
||||
}
|
||||
}
|
||||
|
||||
trailZero := int(f.MinFractionDigits) - numFrac
|
||||
if d := int(f.MinSignificantDigits) - len(digits); d > 0 && d > trailZero {
|
||||
trailZero = d
|
||||
}
|
||||
if numFrac > 0 || trailZero > 0 || f.Flags&AlwaysDecimalSeparator != 0 {
|
||||
dst = append(dst, f.Symbol(SymDecimal)...)
|
||||
}
|
||||
// Add leading zeros
|
||||
for i := numFrac - len(fracDigits); i > 0; i-- {
|
||||
dst = f.AppendDigit(dst, 0)
|
||||
}
|
||||
i = 0
|
||||
for ; i < len(fracDigits); i++ {
|
||||
dst = f.AppendDigit(dst, fracDigits[i])
|
||||
}
|
||||
for ; trailZero > 0; trailZero-- {
|
||||
dst = f.AppendDigit(dst, 0)
|
||||
}
|
||||
return appendAffix(dst, f, suffix, neg), savedLen, len(dst)
|
||||
}
|
||||
|
||||
// appendScientific appends a formatted number to dst. It returns two possible
|
||||
// insertion points for padding.
|
||||
func appendScientific(dst []byte, f *Formatter, d *Decimal) (b []byte, postPre, preSuf int) {
|
||||
if dst, ok := f.renderSpecial(dst, d); ok {
|
||||
return dst, 0, 0
|
||||
}
|
||||
// Significant digits are transformed by parser for scientific notation and
|
||||
// do not need to be handled here.
|
||||
maxInt, numInt := int(f.MaxIntegerDigits), int(f.MinIntegerDigits)
|
||||
if numInt == 0 {
|
||||
numInt = 1
|
||||
}
|
||||
maxSig := int(f.MaxFractionDigits) + numInt
|
||||
minSig := int(f.MinFractionDigits) + numInt
|
||||
n := d.normalize()
|
||||
if maxSig > 0 {
|
||||
n.round(ToZero, maxSig)
|
||||
}
|
||||
digits := n.Digits
|
||||
exp := n.Exp
|
||||
|
||||
// If a maximum number of integers is specified, the minimum must be 1
|
||||
// and the exponent is grouped by this number (e.g. for engineering)
|
||||
if len(digits) == 0 {
|
||||
exp = 0
|
||||
} else if maxInt > numInt {
|
||||
// Correct the exponent to reflect a single integer digit.
|
||||
exp--
|
||||
numInt = 1
|
||||
// engineering
|
||||
// 0.01234 ([12345]e-1) -> 1.2345e-2 12.345e-3
|
||||
// 12345 ([12345]e+5) -> 1.2345e4 12.345e3
|
||||
d := int(exp) % maxInt
|
||||
if d < 0 {
|
||||
d += maxInt
|
||||
}
|
||||
exp -= int32(d)
|
||||
numInt += d
|
||||
} else {
|
||||
exp -= int32(numInt)
|
||||
}
|
||||
var intDigits, fracDigits []byte
|
||||
if numInt <= len(digits) {
|
||||
intDigits = digits[:numInt]
|
||||
fracDigits = digits[numInt:]
|
||||
} else {
|
||||
intDigits = digits
|
||||
}
|
||||
neg := d.Neg
|
||||
affix, suffix := f.getAffixes(neg)
|
||||
dst = appendAffix(dst, f, affix, neg)
|
||||
savedLen := len(dst)
|
||||
|
||||
i := 0
|
||||
for ; i < len(intDigits); i++ {
|
||||
dst = f.AppendDigit(dst, intDigits[i])
|
||||
if f.needsSep(numInt - i) {
|
||||
dst = append(dst, f.Symbol(SymGroup)...)
|
||||
}
|
||||
}
|
||||
for ; i < numInt; i++ {
|
||||
dst = f.AppendDigit(dst, 0)
|
||||
if f.needsSep(numInt - i) {
|
||||
dst = append(dst, f.Symbol(SymGroup)...)
|
||||
}
|
||||
}
|
||||
|
||||
trailZero := minSig - numInt - len(fracDigits)
|
||||
if len(fracDigits) > 0 || trailZero > 0 || f.Flags&AlwaysDecimalSeparator != 0 {
|
||||
dst = append(dst, f.Symbol(SymDecimal)...)
|
||||
}
|
||||
i = 0
|
||||
for ; i < len(fracDigits); i++ {
|
||||
dst = f.AppendDigit(dst, fracDigits[i])
|
||||
}
|
||||
for ; trailZero > 0; trailZero-- {
|
||||
dst = f.AppendDigit(dst, 0)
|
||||
}
|
||||
|
||||
// exp
|
||||
buf := [12]byte{}
|
||||
// TODO: use exponential if superscripting is not available (no Latin
|
||||
// numbers or no tags) and use exponential in all other cases.
|
||||
exponential := f.Symbol(SymExponential)
|
||||
if exponential == "E" {
|
||||
dst = append(dst, "\u202f"...) // NARROW NO-BREAK SPACE
|
||||
dst = append(dst, f.Symbol(SymSuperscriptingExponent)...)
|
||||
dst = append(dst, "\u202f"...) // NARROW NO-BREAK SPACE
|
||||
dst = f.AppendDigit(dst, 1)
|
||||
dst = f.AppendDigit(dst, 0)
|
||||
switch {
|
||||
case exp < 0:
|
||||
dst = append(dst, superMinus...)
|
||||
exp = -exp
|
||||
case f.Flags&AlwaysExpSign != 0:
|
||||
dst = append(dst, superPlus...)
|
||||
}
|
||||
b = strconv.AppendUint(buf[:0], uint64(exp), 10)
|
||||
for i := len(b); i < int(f.MinExponentDigits); i++ {
|
||||
dst = append(dst, superDigits[0]...)
|
||||
}
|
||||
for _, c := range b {
|
||||
dst = append(dst, superDigits[c-'0']...)
|
||||
}
|
||||
} else {
|
||||
dst = append(dst, exponential...)
|
||||
switch {
|
||||
case exp < 0:
|
||||
dst = append(dst, f.Symbol(SymMinusSign)...)
|
||||
exp = -exp
|
||||
case f.Flags&AlwaysExpSign != 0:
|
||||
dst = append(dst, f.Symbol(SymPlusSign)...)
|
||||
}
|
||||
b = strconv.AppendUint(buf[:0], uint64(exp), 10)
|
||||
for i := len(b); i < int(f.MinExponentDigits); i++ {
|
||||
dst = f.AppendDigit(dst, 0)
|
||||
}
|
||||
for _, c := range b {
|
||||
dst = f.AppendDigit(dst, c-'0')
|
||||
}
|
||||
}
|
||||
return appendAffix(dst, f, suffix, neg), savedLen, len(dst)
|
||||
}
|
||||
|
||||
const (
|
||||
superMinus = "\u207B" // SUPERSCRIPT HYPHEN-MINUS
|
||||
superPlus = "\u207A" // SUPERSCRIPT PLUS SIGN
|
||||
)
|
||||
|
||||
var (
|
||||
// Note: the digits are not sequential!!!
|
||||
superDigits = []string{
|
||||
"\u2070", // SUPERSCRIPT DIGIT ZERO
|
||||
"\u00B9", // SUPERSCRIPT DIGIT ONE
|
||||
"\u00B2", // SUPERSCRIPT DIGIT TWO
|
||||
"\u00B3", // SUPERSCRIPT DIGIT THREE
|
||||
"\u2074", // SUPERSCRIPT DIGIT FOUR
|
||||
"\u2075", // SUPERSCRIPT DIGIT FIVE
|
||||
"\u2076", // SUPERSCRIPT DIGIT SIX
|
||||
"\u2077", // SUPERSCRIPT DIGIT SEVEN
|
||||
"\u2078", // SUPERSCRIPT DIGIT EIGHT
|
||||
"\u2079", // SUPERSCRIPT DIGIT NINE
|
||||
}
|
||||
)
|
||||
|
||||
func (f *Formatter) getAffixes(neg bool) (affix, suffix string) {
|
||||
str := f.Affix
|
||||
if str != "" {
|
||||
if f.NegOffset > 0 {
|
||||
if neg {
|
||||
str = str[f.NegOffset:]
|
||||
} else {
|
||||
str = str[:f.NegOffset]
|
||||
}
|
||||
}
|
||||
sufStart := 1 + str[0]
|
||||
affix = str[1:sufStart]
|
||||
suffix = str[sufStart+1:]
|
||||
}
|
||||
// TODO: introduce a NeedNeg sign to indicate if the left pattern already
|
||||
// has a sign marked?
|
||||
if f.NegOffset == 0 && (neg || f.Flags&AlwaysSign != 0) {
|
||||
affix = "-" + affix
|
||||
}
|
||||
return affix, suffix
|
||||
}
|
||||
|
||||
func (f *Formatter) renderSpecial(dst []byte, d *Decimal) (b []byte, ok bool) {
|
||||
if d.NaN {
|
||||
return fmtNaN(dst, f), true
|
||||
}
|
||||
if d.Inf {
|
||||
return fmtInfinite(dst, f, d), true
|
||||
}
|
||||
return dst, false
|
||||
}
|
||||
|
||||
func fmtNaN(dst []byte, f *Formatter) []byte {
|
||||
return append(dst, f.Symbol(SymNan)...)
|
||||
}
|
||||
|
||||
func fmtInfinite(dst []byte, f *Formatter, d *Decimal) []byte {
|
||||
affix, suffix := f.getAffixes(d.Neg)
|
||||
dst = appendAffix(dst, f, affix, d.Neg)
|
||||
dst = append(dst, f.Symbol(SymInfinity)...)
|
||||
dst = appendAffix(dst, f, suffix, d.Neg)
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendAffix(dst []byte, f *Formatter, affix string, neg bool) []byte {
|
||||
quoting := false
|
||||
escaping := false
|
||||
for _, r := range affix {
|
||||
switch {
|
||||
case escaping:
|
||||
// escaping occurs both inside and outside of quotes
|
||||
dst = append(dst, string(r)...)
|
||||
escaping = false
|
||||
case r == '\\':
|
||||
escaping = true
|
||||
case r == '\'':
|
||||
quoting = !quoting
|
||||
case quoting:
|
||||
dst = append(dst, string(r)...)
|
||||
case r == '%':
|
||||
if f.DigitShift == 3 {
|
||||
dst = append(dst, f.Symbol(SymPerMille)...)
|
||||
} else {
|
||||
dst = append(dst, f.Symbol(SymPercentSign)...)
|
||||
}
|
||||
case r == '-' || r == '+':
|
||||
if neg {
|
||||
dst = append(dst, f.Symbol(SymMinusSign)...)
|
||||
} else if f.Flags&ElideSign == 0 {
|
||||
dst = append(dst, f.Symbol(SymPlusSign)...)
|
||||
} else {
|
||||
dst = append(dst, ' ')
|
||||
}
|
||||
default:
|
||||
dst = append(dst, string(r)...)
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
+508
@@ -0,0 +1,508 @@
|
||||
// Copyright 2017 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 number
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func TestAppendDecimal(t *testing.T) {
|
||||
type pairs map[string]string // alternates with decimal input and result
|
||||
|
||||
testCases := []struct {
|
||||
pattern string
|
||||
// We want to be able to test some forms of patterns that cannot be
|
||||
// represented as a string.
|
||||
pat *Pattern
|
||||
|
||||
test pairs
|
||||
}{{
|
||||
pattern: "0",
|
||||
test: pairs{
|
||||
"0": "0",
|
||||
"1": "1",
|
||||
"-1": "-1",
|
||||
".00": "0",
|
||||
"10.": "10",
|
||||
"12": "12",
|
||||
"1.2": "1",
|
||||
"NaN": "NaN",
|
||||
"-Inf": "-∞",
|
||||
},
|
||||
}, {
|
||||
pattern: "+0;+0",
|
||||
test: pairs{
|
||||
"0": "+0",
|
||||
"1": "+1",
|
||||
"-1": "-1",
|
||||
".00": "+0",
|
||||
"10.": "+10",
|
||||
"12": "+12",
|
||||
"1.2": "+1",
|
||||
"NaN": "NaN",
|
||||
"-Inf": "-∞",
|
||||
"Inf": "+∞",
|
||||
},
|
||||
}, {
|
||||
pattern: "0 +;0 +",
|
||||
test: pairs{
|
||||
"0": "0 +",
|
||||
"1": "1 +",
|
||||
"-1": "1 -",
|
||||
".00": "0 +",
|
||||
},
|
||||
}, {
|
||||
pattern: "0;0-",
|
||||
test: pairs{
|
||||
"-1": "1-",
|
||||
"NaN": "NaN",
|
||||
"-Inf": "∞-",
|
||||
"Inf": "∞",
|
||||
},
|
||||
}, {
|
||||
pattern: "0000",
|
||||
test: pairs{
|
||||
"0": "0000",
|
||||
"1": "0001",
|
||||
"12": "0012",
|
||||
"12345": "12345",
|
||||
},
|
||||
}, {
|
||||
pattern: ".0",
|
||||
test: pairs{
|
||||
"0": ".0",
|
||||
"1": "1.0",
|
||||
"1.2": "1.2",
|
||||
"1.2345": "1.2",
|
||||
},
|
||||
}, {
|
||||
pattern: "#.0",
|
||||
test: pairs{
|
||||
"0": ".0",
|
||||
},
|
||||
}, {
|
||||
pattern: "#.0#",
|
||||
test: pairs{
|
||||
"0": ".0",
|
||||
"1": "1.0",
|
||||
},
|
||||
}, {
|
||||
pattern: "0.0#",
|
||||
test: pairs{
|
||||
"0": "0.0",
|
||||
},
|
||||
}, {
|
||||
pattern: "#0.###",
|
||||
test: pairs{
|
||||
"0": "0",
|
||||
"1": "1",
|
||||
"1.2": "1.2",
|
||||
"1.2345": "1.234", // rounding should have been done earlier
|
||||
"1234.5": "1234.5",
|
||||
"1234.567": "1234.567",
|
||||
},
|
||||
}, {
|
||||
pattern: "#0.######",
|
||||
test: pairs{
|
||||
"0": "0",
|
||||
"1234.5678": "1234.5678",
|
||||
"0.123456789": "0.123456",
|
||||
"NaN": "NaN",
|
||||
"Inf": "∞",
|
||||
},
|
||||
|
||||
// Test separators.
|
||||
}, {
|
||||
pattern: "#,#.00",
|
||||
test: pairs{
|
||||
"100": "1,0,0.00",
|
||||
},
|
||||
}, {
|
||||
pattern: "#,0.##",
|
||||
test: pairs{
|
||||
"10": "1,0",
|
||||
},
|
||||
}, {
|
||||
pattern: "#,0",
|
||||
test: pairs{
|
||||
"10": "1,0",
|
||||
},
|
||||
}, {
|
||||
pattern: "#,##,#.00",
|
||||
test: pairs{
|
||||
"1000": "1,00,0.00",
|
||||
},
|
||||
}, {
|
||||
pattern: "#,##0.###",
|
||||
test: pairs{
|
||||
"0": "0",
|
||||
"1234.5678": "1,234.567",
|
||||
"0.123456789": "0.123",
|
||||
},
|
||||
}, {
|
||||
pattern: "#,##,##0.###",
|
||||
test: pairs{
|
||||
"0": "0",
|
||||
"123456789012": "1,23,45,67,89,012",
|
||||
"0.123456789": "0.123",
|
||||
},
|
||||
}, {
|
||||
pattern: "0,00,000.###",
|
||||
test: pairs{
|
||||
"0": "0,00,000",
|
||||
"123456789012": "1,23,45,67,89,012",
|
||||
"12.3456789": "0,00,012.345",
|
||||
"0.123456789": "0,00,000.123",
|
||||
},
|
||||
|
||||
// Support for ill-formed patterns.
|
||||
}, {
|
||||
pattern: "#",
|
||||
test: pairs{
|
||||
".00": "", // This is the behavior of fmt.
|
||||
"0": "", // This is the behavior of fmt.
|
||||
"1": "1",
|
||||
"10.": "10",
|
||||
},
|
||||
}, {
|
||||
pattern: ".#",
|
||||
test: pairs{
|
||||
"0": "", // This is the behavior of fmt.
|
||||
"1": "1",
|
||||
"1.2": "1.2",
|
||||
"1.2345": "1.2",
|
||||
},
|
||||
}, {
|
||||
pattern: "#,#.##",
|
||||
test: pairs{
|
||||
"10": "1,0",
|
||||
},
|
||||
}, {
|
||||
pattern: "#,#",
|
||||
test: pairs{
|
||||
"10": "1,0",
|
||||
},
|
||||
|
||||
// Special patterns
|
||||
}, {
|
||||
pattern: "#,max_int=2",
|
||||
pat: &Pattern{
|
||||
MaxIntegerDigits: 2,
|
||||
},
|
||||
test: pairs{
|
||||
"2017": "17",
|
||||
},
|
||||
}, {
|
||||
pattern: "0,max_int=2",
|
||||
pat: &Pattern{
|
||||
MaxIntegerDigits: 2,
|
||||
MinIntegerDigits: 1,
|
||||
},
|
||||
test: pairs{
|
||||
"2000": "0",
|
||||
"2001": "1",
|
||||
"2017": "17",
|
||||
},
|
||||
}, {
|
||||
pattern: "00,max_int=2",
|
||||
pat: &Pattern{
|
||||
MaxIntegerDigits: 2,
|
||||
MinIntegerDigits: 2,
|
||||
},
|
||||
test: pairs{
|
||||
"2000": "00",
|
||||
"2001": "01",
|
||||
"2017": "17",
|
||||
},
|
||||
}, {
|
||||
pattern: "@@@@,max_int=2",
|
||||
pat: &Pattern{
|
||||
MaxIntegerDigits: 2,
|
||||
MinSignificantDigits: 4,
|
||||
},
|
||||
test: pairs{
|
||||
"2017": "17.00",
|
||||
"2000": "0.000",
|
||||
"2001": "1.000",
|
||||
},
|
||||
|
||||
// Significant digits
|
||||
}, {
|
||||
pattern: "@@##",
|
||||
test: pairs{
|
||||
"1": "1.0",
|
||||
"0.1": "0.10",
|
||||
"123": "123",
|
||||
"1234": "1234",
|
||||
"12345": "12340",
|
||||
},
|
||||
}, {
|
||||
pattern: "@@@@",
|
||||
test: pairs{
|
||||
"1": "1.000",
|
||||
".1": "0.1000",
|
||||
".001": "0.001000",
|
||||
"123": "123.0",
|
||||
"1234": "1234",
|
||||
"12345": "12340", // rounding down
|
||||
"NaN": "NaN",
|
||||
"-Inf": "-∞",
|
||||
},
|
||||
|
||||
// TODO: rounding
|
||||
// {"@@@@": "23456": "23460"}, // rounding up
|
||||
// TODO: padding
|
||||
|
||||
// Scientific and Engineering notation
|
||||
}, {
|
||||
pattern: "#E0",
|
||||
test: pairs{
|
||||
"0": "0\u202f×\u202f10⁰",
|
||||
"1": "1\u202f×\u202f10⁰",
|
||||
"123.456": "1\u202f×\u202f10²",
|
||||
},
|
||||
}, {
|
||||
pattern: "#E+0",
|
||||
test: pairs{
|
||||
"0": "0\u202f×\u202f10⁺⁰",
|
||||
"1000": "1\u202f×\u202f10⁺³",
|
||||
"1E100": "1\u202f×\u202f10⁺¹⁰⁰",
|
||||
"1E-100": "1\u202f×\u202f10⁻¹⁰⁰",
|
||||
"NaN": "NaN",
|
||||
"-Inf": "-∞",
|
||||
},
|
||||
}, {
|
||||
pattern: "##0E00",
|
||||
test: pairs{
|
||||
"100": "100\u202f×\u202f10⁰⁰",
|
||||
"12345": "10\u202f×\u202f10⁰³",
|
||||
"123.456": "100\u202f×\u202f10⁰⁰",
|
||||
},
|
||||
}, {
|
||||
pattern: "##0.###E00",
|
||||
test: pairs{
|
||||
"100": "100\u202f×\u202f10⁰⁰",
|
||||
"12345": "12.34\u202f×\u202f10⁰³",
|
||||
"123.456": "123.4\u202f×\u202f10⁰⁰",
|
||||
},
|
||||
}, {
|
||||
pattern: "##0.000E00",
|
||||
test: pairs{
|
||||
"100": "100.0\u202f×\u202f10⁰⁰",
|
||||
"12345": "12.34\u202f×\u202f10⁰³",
|
||||
"123.456": "123.4\u202f×\u202f10⁰⁰",
|
||||
},
|
||||
}, {
|
||||
pattern: "@@E0",
|
||||
test: pairs{
|
||||
"0": "0.0\u202f×\u202f10⁰",
|
||||
"99": "9.9\u202f×\u202f10¹",
|
||||
"0.99": "9.9\u202f×\u202f10⁻¹",
|
||||
},
|
||||
}, {
|
||||
pattern: "@###E00",
|
||||
test: pairs{
|
||||
"0": "0\u202f×\u202f10⁰⁰",
|
||||
"1": "1\u202f×\u202f10⁰⁰",
|
||||
"11": "1.1\u202f×\u202f10⁰¹",
|
||||
"111": "1.11\u202f×\u202f10⁰²",
|
||||
"1111": "1.111\u202f×\u202f10⁰³",
|
||||
"11111": "1.111\u202f×\u202f10⁰⁴",
|
||||
"0.1": "1\u202f×\u202f10⁻⁰¹",
|
||||
"0.11": "1.1\u202f×\u202f10⁻⁰¹",
|
||||
"0.001": "1\u202f×\u202f10⁻⁰³",
|
||||
},
|
||||
}, {
|
||||
pattern: "*x##0",
|
||||
test: pairs{
|
||||
"0": "xx0",
|
||||
"10": "x10",
|
||||
"100": "100",
|
||||
"1000": "1000",
|
||||
},
|
||||
}, {
|
||||
pattern: "##0*x",
|
||||
test: pairs{
|
||||
"0": "0xx",
|
||||
"10": "10x",
|
||||
"100": "100",
|
||||
"1000": "1000",
|
||||
},
|
||||
}, {
|
||||
pattern: "* ###0.000",
|
||||
test: pairs{
|
||||
"0": " 0.000",
|
||||
"123": " 123.000",
|
||||
"123.456": " 123.456",
|
||||
"1234.567": "1234.567",
|
||||
},
|
||||
}, {
|
||||
pattern: "**0.0#######E00",
|
||||
test: pairs{
|
||||
"0": "***0.0\u202f×\u202f10⁰⁰",
|
||||
"10": "***1.0\u202f×\u202f10⁰¹",
|
||||
"11": "***1.1\u202f×\u202f10⁰¹",
|
||||
"111": "**1.11\u202f×\u202f10⁰²",
|
||||
"1111": "*1.111\u202f×\u202f10⁰³",
|
||||
"11111": "1.1111\u202f×\u202f10⁰⁴",
|
||||
"11110": "*1.111\u202f×\u202f10⁰⁴",
|
||||
"11100": "**1.11\u202f×\u202f10⁰⁴",
|
||||
"11000": "***1.1\u202f×\u202f10⁰⁴",
|
||||
"10000": "***1.0\u202f×\u202f10⁰⁴",
|
||||
},
|
||||
}, {
|
||||
pattern: "*xpre0suf",
|
||||
test: pairs{
|
||||
"0": "pre0suf",
|
||||
"10": "pre10suf",
|
||||
},
|
||||
}, {
|
||||
pattern: "*∞ pre ###0 suf",
|
||||
test: pairs{
|
||||
"0": "∞∞∞ pre 0 suf",
|
||||
"10": "∞∞ pre 10 suf",
|
||||
"100": "∞ pre 100 suf",
|
||||
"1000": " pre 1000 suf",
|
||||
},
|
||||
}, {
|
||||
pattern: "pre *∞###0 suf",
|
||||
test: pairs{
|
||||
"0": "pre ∞∞∞0 suf",
|
||||
"10": "pre ∞∞10 suf",
|
||||
"100": "pre ∞100 suf",
|
||||
"1000": "pre 1000 suf",
|
||||
},
|
||||
}, {
|
||||
pattern: "pre ###0*∞ suf",
|
||||
test: pairs{
|
||||
"0": "pre 0∞∞∞ suf",
|
||||
"10": "pre 10∞∞ suf",
|
||||
"100": "pre 100∞ suf",
|
||||
"1000": "pre 1000 suf",
|
||||
},
|
||||
}, {
|
||||
pattern: "pre ###0 suf *∞",
|
||||
test: pairs{
|
||||
"0": "pre 0 suf ∞∞∞",
|
||||
"10": "pre 10 suf ∞∞",
|
||||
"100": "pre 100 suf ∞",
|
||||
"1000": "pre 1000 suf ",
|
||||
},
|
||||
}, {
|
||||
// Take width of positive pattern.
|
||||
pattern: "**###0;**-#####0x",
|
||||
test: pairs{
|
||||
"0": "***0",
|
||||
"-1": "*-1x",
|
||||
},
|
||||
}, {
|
||||
pattern: "0.00%",
|
||||
test: pairs{
|
||||
"0.1": "10.00%",
|
||||
},
|
||||
}, {
|
||||
pattern: "0.##%",
|
||||
test: pairs{
|
||||
"0.1": "10%",
|
||||
"0.11": "11%",
|
||||
"0.111": "11.1%",
|
||||
"0.1111": "11.11%",
|
||||
"0.11111": "11.11%",
|
||||
},
|
||||
}, {
|
||||
pattern: "‰ 0.0#",
|
||||
test: pairs{
|
||||
"0.1": "‰ 100.0",
|
||||
"0.11": "‰ 110.0",
|
||||
"0.111": "‰ 111.0",
|
||||
"0.1111": "‰ 111.1",
|
||||
"0.11111": "‰ 111.11",
|
||||
"0.111111": "‰ 111.11",
|
||||
},
|
||||
}}
|
||||
|
||||
// TODO:
|
||||
// "#,##0.00¤",
|
||||
// "#,##0.00 ¤;(#,##0.00 ¤)",
|
||||
|
||||
for _, tc := range testCases {
|
||||
pat := tc.pat
|
||||
if pat == nil {
|
||||
var err error
|
||||
if pat, err = ParsePattern(tc.pattern); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
var f Formatter
|
||||
f.InitPattern(language.English, pat)
|
||||
for dec, want := range tc.test {
|
||||
buf := make([]byte, 100)
|
||||
t.Run(tc.pattern+"/"+dec, func(t *testing.T) {
|
||||
dec := mkdec(dec)
|
||||
buf = f.Format(buf[:0], &dec)
|
||||
if got := string(buf); got != want {
|
||||
t.Errorf("\n got %[1]q (%[1]s)\nwant %[2]q (%[2]s)", got, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocales(t *testing.T) {
|
||||
testCases := []struct {
|
||||
tag language.Tag
|
||||
num string
|
||||
want string
|
||||
}{
|
||||
{language.Make("en"), "123456.78", "123,456.78"},
|
||||
{language.Make("de"), "123456.78", "123.456,78"},
|
||||
{language.Make("de-CH"), "123456.78", "123’456.78"},
|
||||
{language.Make("fr"), "123456.78", "123 456,78"},
|
||||
{language.Make("bn"), "123456.78", "১,২৩,৪৫৬.৭৮"},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(fmt.Sprint(tc.tag, "/", tc.num), func(t *testing.T) {
|
||||
var f Formatter
|
||||
f.InitDecimal(tc.tag)
|
||||
d := mkdec(tc.num)
|
||||
b := f.Format(nil, &d)
|
||||
if got := string(b); got != tc.want {
|
||||
t.Errorf("got %[1]q (%[1]s); want %[2]q (%[2]s)", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatters(t *testing.T) {
|
||||
var f Formatter
|
||||
testCases := []struct {
|
||||
init func(t language.Tag)
|
||||
num string
|
||||
want string
|
||||
}{
|
||||
{f.InitDecimal, "123456.78", "123,456.78"},
|
||||
{f.InitScientific, "123456.78", "1.23\u202f×\u202f10⁵"},
|
||||
{f.InitEngineering, "123456.78", "123\u202f×\u202f10³"},
|
||||
|
||||
{f.InitPercent, "0.1234", "12.34%"},
|
||||
{f.InitPerMille, "0.1234", "123.40‰"},
|
||||
}
|
||||
for i, tc := range testCases {
|
||||
t.Run(fmt.Sprint(i, "/", tc.num), func(t *testing.T) {
|
||||
tc.init(language.English)
|
||||
f.Pattern.MinFractionDigits = 2
|
||||
f.Pattern.MaxFractionDigits = 2
|
||||
d := mkdec(tc.num)
|
||||
b := f.Format(nil, &d)
|
||||
if got := string(b); got != tc.want {
|
||||
t.Errorf("got %[1]q (%[1]s); want %[2]q (%[2]s)", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+9
@@ -121,6 +121,15 @@ func (n Info) WriteDigit(dst []byte, asciiDigit rune) int {
|
||||
return int(n.system.digitSize)
|
||||
}
|
||||
|
||||
// AppendDigit appends the UTF-8 sequence for n corresponding to the given digit
|
||||
// to dst and reports the number of bytes written. dst must be large enough to
|
||||
// hold the rune (can be up to utf8.UTFMax bytes).
|
||||
func (n Info) AppendDigit(dst []byte, digit byte) []byte {
|
||||
dst = append(dst, n.system.zero[:n.system.digitSize]...)
|
||||
dst[len(dst)-1] += digit
|
||||
return dst
|
||||
}
|
||||
|
||||
// Digit returns the digit for the numbering system for the corresponding ASCII
|
||||
// value. For example, ni.Digit('3') could return '三'. Note that the argument
|
||||
// is the rune constant '3', which equals 51, not the integer constant 3.
|
||||
|
||||
+20
-10
@@ -5,6 +5,7 @@
|
||||
package number
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/text/internal/testtext"
|
||||
@@ -26,9 +27,9 @@ func TestInfo(t *testing.T) {
|
||||
// U+096F DEVANAGARI DIGIT NINE ('९')
|
||||
{"de-BE-u-nu-deva", SymGroup, ".", '\u096f'}, // miss -> latn -> de
|
||||
{"de-Cyrl-BE", SymGroup, ",", '9'}, // inherits from root
|
||||
{"de-CH", SymGroup, "'", '9'}, // overrides values in de
|
||||
{"de-CH-oxendict", SymGroup, "'", '9'}, // inherits from de-CH (no compact index)
|
||||
{"de-CH-u-nu-deva", SymGroup, "'", '\u096f'}, // miss -> latn -> de-CH
|
||||
{"de-CH", SymGroup, "’", '9'}, // overrides values in de
|
||||
{"de-CH-oxendict", SymGroup, "’", '9'}, // inherits from de-CH (no compact index)
|
||||
{"de-CH-u-nu-deva", SymGroup, "’", '\u096f'}, // miss -> latn -> de-CH
|
||||
|
||||
{"pa", SymExponential, "E", '9'},
|
||||
|
||||
@@ -51,13 +52,22 @@ func TestInfo(t *testing.T) {
|
||||
{"en-u-nu-roman", SymPlusSign, "+", '9'},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
info := InfoFromTag(language.MustParse(tc.lang))
|
||||
if got := info.Symbol(tc.sym); got != tc.wantSym {
|
||||
t.Errorf("%s:%v:sym: got %q; want %q", tc.lang, tc.sym, got, tc.wantSym)
|
||||
}
|
||||
if got := info.Digit('9'); got != tc.wantNine {
|
||||
t.Errorf("%s:%v:nine: got %q; want %q", tc.lang, tc.sym, got, tc.wantNine)
|
||||
}
|
||||
t.Run(fmt.Sprintf("%s:%v", tc.lang, tc.sym), func(t *testing.T) {
|
||||
info := InfoFromTag(language.MustParse(tc.lang))
|
||||
if got := info.Symbol(tc.sym); got != tc.wantSym {
|
||||
t.Errorf("sym: got %q; want %q", got, tc.wantSym)
|
||||
}
|
||||
if got := info.Digit('9'); got != tc.wantNine {
|
||||
t.Errorf("Digit(9): got %+q; want %+q", got, tc.wantNine)
|
||||
}
|
||||
var buf [4]byte
|
||||
if got := string(buf[:info.WriteDigit(buf[:], '9')]); got != string(tc.wantNine) {
|
||||
t.Errorf("WriteDigit(9): got %+q; want %+q", got, tc.wantNine)
|
||||
}
|
||||
if got := string(info.AppendDigit([]byte{}, 9)); got != string(tc.wantNine) {
|
||||
t.Errorf("AppendDigit(9): got %+q; want %+q", got, tc.wantNine)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+51
-10
@@ -46,16 +46,17 @@ type Pattern struct {
|
||||
Offset uint16 // Offset into Affix for prefix and suffix
|
||||
NegOffset uint16 // Offset into Affix for negative prefix and suffix or 0.
|
||||
|
||||
Multiplier uint32
|
||||
FormatWidth uint16
|
||||
|
||||
RoundIncrement uint32 // Use Min*Digits to determine scale
|
||||
PadRune rune
|
||||
|
||||
FormatWidth uint16
|
||||
DigitShift uint8 // Number of decimals to shift. Used for % and ‰.
|
||||
|
||||
GroupingSize [2]uint8
|
||||
Flags PatternFlag
|
||||
|
||||
// Number of digits.
|
||||
// TODO: consider using uint32
|
||||
MinIntegerDigits uint8
|
||||
MaxIntegerDigits uint8
|
||||
MinFractionDigits uint8
|
||||
@@ -65,11 +66,32 @@ type Pattern struct {
|
||||
MinExponentDigits uint8
|
||||
}
|
||||
|
||||
// A PatternFlag is a bit mask for the flag field of a Format.
|
||||
func (f *Pattern) needsSep(pos int) bool {
|
||||
p := pos - 1
|
||||
size := int(f.GroupingSize[0])
|
||||
if size == 0 || p == 0 {
|
||||
return false
|
||||
}
|
||||
if p == size {
|
||||
return true
|
||||
}
|
||||
if p -= size; p < 0 {
|
||||
return false
|
||||
}
|
||||
// TODO: make second groupingsize the same as first if 0 so that we can
|
||||
// avoid this check.
|
||||
if x := int(f.GroupingSize[1]); x != 0 {
|
||||
size = x
|
||||
}
|
||||
return p%size == 0
|
||||
}
|
||||
|
||||
// A PatternFlag is a bit mask for the flag field of a Pattern.
|
||||
type PatternFlag uint8
|
||||
|
||||
const (
|
||||
AlwaysSign PatternFlag = 1 << iota
|
||||
ElideSign // Use space instead of plus sign. AlwaysSign must be true.
|
||||
AlwaysExpSign
|
||||
AlwaysDecimalSeparator
|
||||
ParenthesisForNegative // Common pattern. Saves space.
|
||||
@@ -104,7 +126,8 @@ func (p *parser) setError(err error) {
|
||||
}
|
||||
|
||||
func (p *parser) updateGrouping() {
|
||||
if p.hasGroup && p.groupingCount < 255 {
|
||||
if p.hasGroup &&
|
||||
0 < p.groupingCount && p.groupingCount < 255 {
|
||||
p.GroupingSize[1] = p.GroupingSize[0]
|
||||
p.GroupingSize[0] = uint8(p.groupingCount)
|
||||
}
|
||||
@@ -163,6 +186,7 @@ func (p *parser) parseSubPattern(s string) string {
|
||||
s = p.parsePad(s, PadAfterPrefix)
|
||||
|
||||
s = p.parse(p.number, s)
|
||||
p.updateGrouping()
|
||||
|
||||
s = p.parsePad(s, PadBeforeSuffix)
|
||||
s = p.parseAffix(s)
|
||||
@@ -225,26 +249,41 @@ func (p *parser) affix(r rune) state {
|
||||
'#', '@', '.', '*', ',', ';':
|
||||
return nil
|
||||
case '\'':
|
||||
return p.escape
|
||||
p.FormatWidth--
|
||||
return p.escapeFirst
|
||||
case '%':
|
||||
if p.Multiplier != 0 {
|
||||
if p.DigitShift != 0 {
|
||||
p.setError(errDuplicatePercentSign)
|
||||
}
|
||||
p.Multiplier = 100
|
||||
p.DigitShift = 2
|
||||
case '\u2030': // ‰ Per mille
|
||||
if p.Multiplier != 0 {
|
||||
if p.DigitShift != 0 {
|
||||
p.setError(errDuplicatePermilleSign)
|
||||
}
|
||||
p.Multiplier = 1000
|
||||
p.DigitShift = 3
|
||||
// TODO: handle currency somehow: ¤, ¤¤, ¤¤¤, ¤¤¤¤
|
||||
}
|
||||
p.buf = append(p.buf, string(r)...)
|
||||
return p.affix
|
||||
}
|
||||
|
||||
func (p *parser) escapeFirst(r rune) state {
|
||||
switch r {
|
||||
case '\'':
|
||||
p.buf = append(p.buf, "\\'"...)
|
||||
return p.affix
|
||||
default:
|
||||
p.buf = append(p.buf, '\'')
|
||||
p.buf = append(p.buf, string(r)...)
|
||||
}
|
||||
return p.escape
|
||||
}
|
||||
|
||||
func (p *parser) escape(r rune) state {
|
||||
switch r {
|
||||
case '\'':
|
||||
p.FormatWidth--
|
||||
p.buf = append(p.buf, '\'')
|
||||
return p.affix
|
||||
default:
|
||||
p.buf = append(p.buf, string(r)...)
|
||||
@@ -294,6 +333,8 @@ func (p *parser) integer(r rune) state {
|
||||
next = p.exponent
|
||||
case '.':
|
||||
next = p.fraction
|
||||
case ',':
|
||||
next = p.integer
|
||||
}
|
||||
p.updateGrouping()
|
||||
return next
|
||||
|
||||
+73
-12
@@ -25,6 +25,20 @@ var testCases = []struct {
|
||||
FormatWidth: 1,
|
||||
MinIntegerDigits: 1,
|
||||
},
|
||||
}, {
|
||||
"+0",
|
||||
&Pattern{
|
||||
Affix: "\x01+\x00",
|
||||
FormatWidth: 2,
|
||||
MinIntegerDigits: 1,
|
||||
},
|
||||
}, {
|
||||
"0+",
|
||||
&Pattern{
|
||||
Affix: "\x00\x01+",
|
||||
FormatWidth: 2,
|
||||
MinIntegerDigits: 1,
|
||||
},
|
||||
}, {
|
||||
"0000",
|
||||
&Pattern{
|
||||
@@ -51,6 +65,22 @@ var testCases = []struct {
|
||||
MinIntegerDigits: 1,
|
||||
MaxFractionDigits: 6,
|
||||
},
|
||||
}, {
|
||||
"#,0",
|
||||
&Pattern{
|
||||
FormatWidth: 3,
|
||||
GroupingSize: [2]uint8{1, 0},
|
||||
MinIntegerDigits: 1,
|
||||
},
|
||||
}, {
|
||||
"#,0.00",
|
||||
&Pattern{
|
||||
FormatWidth: 6,
|
||||
GroupingSize: [2]uint8{1, 0},
|
||||
MinIntegerDigits: 1,
|
||||
MinFractionDigits: 2,
|
||||
MaxFractionDigits: 2,
|
||||
},
|
||||
}, {
|
||||
"#,##0.###",
|
||||
&Pattern{
|
||||
@@ -83,6 +113,11 @@ var testCases = []struct {
|
||||
MaxIntegerDigits: 1,
|
||||
MinExponentDigits: 1,
|
||||
},
|
||||
}, {
|
||||
// At least one exponent digit is required. As long as this is true, one can
|
||||
// determine that scientific rendering is needed if MinExponentDigits > 0.
|
||||
"#E#",
|
||||
nil,
|
||||
}, {
|
||||
"0E0",
|
||||
&Pattern{
|
||||
@@ -176,7 +211,7 @@ var testCases = []struct {
|
||||
MaxFractionDigits: 3,
|
||||
},
|
||||
}, {
|
||||
// Rounding increments
|
||||
// Rounding increment
|
||||
"1.05",
|
||||
&Pattern{
|
||||
RoundIncrement: 105,
|
||||
@@ -185,11 +220,22 @@ var testCases = []struct {
|
||||
MinFractionDigits: 2,
|
||||
MaxFractionDigits: 2,
|
||||
},
|
||||
}, {
|
||||
// Rounding increment with grouping
|
||||
"1,05",
|
||||
&Pattern{
|
||||
RoundIncrement: 105,
|
||||
FormatWidth: 4,
|
||||
GroupingSize: [2]uint8{2, 0},
|
||||
MinIntegerDigits: 3,
|
||||
MinFractionDigits: 0,
|
||||
MaxFractionDigits: 0,
|
||||
},
|
||||
}, {
|
||||
"0.0%",
|
||||
&Pattern{
|
||||
Affix: "\x00\x01%",
|
||||
Multiplier: 100,
|
||||
DigitShift: 2,
|
||||
FormatWidth: 4,
|
||||
MinIntegerDigits: 1,
|
||||
MinFractionDigits: 1,
|
||||
@@ -199,7 +245,7 @@ var testCases = []struct {
|
||||
"0.0‰",
|
||||
&Pattern{
|
||||
Affix: "\x00\x03‰",
|
||||
Multiplier: 1000,
|
||||
DigitShift: 3,
|
||||
FormatWidth: 4,
|
||||
MinIntegerDigits: 1,
|
||||
MinFractionDigits: 1,
|
||||
@@ -219,7 +265,7 @@ var testCases = []struct {
|
||||
"#,##0.00 ¤;(#,##0.00 ¤)",
|
||||
&Pattern{Affix: "\x00\x04\u00a0¤\x01(\x05\u00a0¤)",
|
||||
NegOffset: 6,
|
||||
Multiplier: 0,
|
||||
DigitShift: 0,
|
||||
FormatWidth: 10,
|
||||
GroupingSize: [2]uint8{3, 0},
|
||||
MinIntegerDigits: 1,
|
||||
@@ -272,6 +318,19 @@ var testCases = []struct {
|
||||
FormatWidth: 7,
|
||||
Flags: PadAfterSuffix,
|
||||
},
|
||||
}, {
|
||||
`* #0 o''clock`,
|
||||
&Pattern{Affix: "\x00\x09 o\\'clock",
|
||||
FormatWidth: 10,
|
||||
PadRune: 32,
|
||||
MinIntegerDigits: 0x1},
|
||||
}, {
|
||||
`'123'* #0'456'`,
|
||||
&Pattern{Affix: "\x05'123'\x05'456'",
|
||||
FormatWidth: 8,
|
||||
PadRune: 32,
|
||||
MinIntegerDigits: 0x1,
|
||||
Flags: PadAfterPrefix},
|
||||
}, {
|
||||
// no duplicate padding
|
||||
"*xpre#suf*x", nil,
|
||||
@@ -282,19 +341,21 @@ var testCases = []struct {
|
||||
|
||||
func TestParsePattern(t *testing.T) {
|
||||
for i, tc := range testCases {
|
||||
f, err := ParsePattern(tc.pat)
|
||||
if !reflect.DeepEqual(f, tc.want) {
|
||||
t.Errorf("%d:%s:\ngot %#v;\nwant %#v", i, tc.pat, f, tc.want)
|
||||
}
|
||||
if got, want := err != nil, tc.want == nil; got != want {
|
||||
t.Errorf("%d:%s:error: got %v; want %v", i, tc.pat, err, want)
|
||||
}
|
||||
t.Run(tc.pat, func(t *testing.T) {
|
||||
f, err := ParsePattern(tc.pat)
|
||||
if !reflect.DeepEqual(f, tc.want) {
|
||||
t.Errorf("%d:%s:\ngot %#v;\nwant %#v", i, tc.pat, f, tc.want)
|
||||
}
|
||||
if got, want := err != nil, tc.want == nil; got != want {
|
||||
t.Errorf("%d:%s:error: got %v; want %v", i, tc.pat, err, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPatternSize(t *testing.T) {
|
||||
if sz := unsafe.Sizeof(Pattern{}); sz > 48 {
|
||||
t.Errorf("got %d; want 48", sz)
|
||||
t.Errorf("got %d; want <= 48", sz)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// Code generated by "stringer -type RoundingMode"; DO NOT EDIT.
|
||||
|
||||
package number
|
||||
|
||||
import "fmt"
|
||||
|
||||
const _RoundingMode_name = "ToNearestEvenToNearestZeroToNearestAwayToPositiveInfToNegativeInfToZeroAwayFromZeronumModes"
|
||||
|
||||
var _RoundingMode_index = [...]uint8{0, 13, 26, 39, 52, 65, 71, 83, 91}
|
||||
|
||||
func (i RoundingMode) String() string {
|
||||
if i >= RoundingMode(len(_RoundingMode_index)-1) {
|
||||
return fmt.Sprintf("RoundingMode(%d)", i)
|
||||
}
|
||||
return _RoundingMode_name[_RoundingMode_index[i]:_RoundingMode_index[i+1]]
|
||||
}
|
||||
+283
-280
@@ -5,7 +5,7 @@ package number
|
||||
import "golang.org/x/text/internal/stringset"
|
||||
|
||||
// CLDRVersion is the CLDR version from which the tables in this package are derived.
|
||||
const CLDRVersion = "30"
|
||||
const CLDRVersion = "31"
|
||||
|
||||
var numSysData = []systemData{ // 58 elements
|
||||
0: {id: 0x0, digitSize: 0x1, zero: [4]uint8{0x30, 0x0, 0x0, 0x0}},
|
||||
@@ -255,82 +255,81 @@ var symIndex = [][12]uint8{ // 71 elements
|
||||
22: [12]uint8{0x0, 0x1, 0x2, 0x3, 0xe, 0x1c, 0x6, 0x7, 0x8, 0x9, 0x1d, 0xb},
|
||||
23: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x1b, 0x6, 0x7, 0x8, 0x9, 0x1e, 0x0},
|
||||
24: [12]uint8{0x1, 0x0, 0x2, 0x3, 0x4, 0x1b, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb},
|
||||
25: [12]uint8{0x0, 0x1f, 0x2, 0x3, 0x4, 0x1b, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb},
|
||||
25: [12]uint8{0x0, 0x15, 0x2, 0x3, 0x4, 0x1b, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb},
|
||||
26: [12]uint8{0x0, 0x1, 0x2, 0x3, 0xe, 0xf, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb},
|
||||
27: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x20, 0xb},
|
||||
27: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x1f, 0xb},
|
||||
28: [12]uint8{0x0, 0x15, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb},
|
||||
29: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x21, 0xb},
|
||||
30: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x22, 0xb},
|
||||
31: [12]uint8{0x1, 0x0, 0x2, 0x3, 0x4, 0x1b, 0x18, 0x13, 0x8, 0x9, 0x23, 0xb},
|
||||
32: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x1b, 0x18, 0x7, 0x8, 0x9, 0x23, 0xb},
|
||||
33: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x24, 0xb},
|
||||
34: [12]uint8{0x1, 0x0, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x25, 0xb},
|
||||
35: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x26, 0xb},
|
||||
36: [12]uint8{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x27, 0xb},
|
||||
37: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x28, 0xb},
|
||||
29: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x20, 0xb},
|
||||
30: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x21, 0xb},
|
||||
31: [12]uint8{0x1, 0x0, 0x2, 0x3, 0x4, 0x1b, 0x18, 0x13, 0x8, 0x9, 0x22, 0xb},
|
||||
32: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x1b, 0x18, 0x7, 0x8, 0x9, 0x22, 0xb},
|
||||
33: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x23, 0xb},
|
||||
34: [12]uint8{0x1, 0x0, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x24, 0xb},
|
||||
35: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x25, 0xb},
|
||||
36: [12]uint8{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x26, 0xb},
|
||||
37: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x27, 0xb},
|
||||
38: [12]uint8{0x1, 0x0, 0x2, 0x3, 0xe, 0x1c, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb},
|
||||
39: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x29, 0xb},
|
||||
40: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x2a, 0xb},
|
||||
41: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x1b, 0x2b, 0x13, 0x8, 0x9, 0x23, 0xb},
|
||||
39: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x28, 0xb},
|
||||
40: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x29, 0xb},
|
||||
41: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x1b, 0x2a, 0x13, 0x8, 0x9, 0x22, 0xb},
|
||||
42: [12]uint8{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0x0},
|
||||
43: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x17, 0x7, 0x8, 0x9, 0xa, 0xb},
|
||||
44: [12]uint8{0x1, 0x0, 0x2, 0x3, 0x4, 0x2c, 0x17, 0x7, 0x8, 0x9, 0xa, 0xb},
|
||||
45: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x2d, 0x0},
|
||||
46: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x2e, 0xb},
|
||||
47: [12]uint8{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x2f, 0xb},
|
||||
48: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x30, 0x7, 0x8, 0x9, 0xa, 0xb},
|
||||
49: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x31, 0xb},
|
||||
50: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x32, 0xb},
|
||||
51: [12]uint8{0x1, 0x1f, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb},
|
||||
52: [12]uint8{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x33, 0xb},
|
||||
53: [12]uint8{0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x7, 0x3b, 0x9, 0xa, 0xb},
|
||||
54: [12]uint8{0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x7, 0x3b, 0x9, 0x3c, 0xb},
|
||||
55: [12]uint8{0x34, 0x35, 0x36, 0x11, 0x38, 0x39, 0x3a, 0x7, 0x3b, 0x9, 0xa, 0xb},
|
||||
56: [12]uint8{0x34, 0x35, 0x36, 0x11, 0x38, 0x3d, 0x3a, 0x7, 0x3b, 0x9, 0xa, 0xb},
|
||||
57: [12]uint8{0x34, 0xc, 0x36, 0x37, 0x38, 0x3e, 0x3a, 0x7, 0x3b, 0x9, 0xa, 0x0},
|
||||
58: [12]uint8{0x34, 0x35, 0x36, 0x37, 0x38, 0x3e, 0x3a, 0x7, 0x3f, 0x9, 0x23, 0xb},
|
||||
59: [12]uint8{0x34, 0x35, 0x36, 0x11, 0x40, 0x41, 0x42, 0x7, 0x3b, 0x9, 0xa, 0x34},
|
||||
60: [12]uint8{0x34, 0x35, 0x36, 0x43, 0xe, 0x1c, 0x42, 0x7, 0x3b, 0x9, 0x1d, 0xb},
|
||||
61: [12]uint8{0x34, 0x35, 0x36, 0x11, 0xe, 0x1c, 0x42, 0x7, 0x3b, 0x9, 0xa, 0x34},
|
||||
62: [12]uint8{0x1, 0xc, 0x36, 0x11, 0x40, 0x44, 0x42, 0x7, 0x3b, 0x9, 0xa, 0x0},
|
||||
63: [12]uint8{0x34, 0x1, 0x36, 0x11, 0x4, 0x5, 0x42, 0x7, 0x3b, 0x9, 0xa, 0x34},
|
||||
64: [12]uint8{0x34, 0x35, 0x36, 0x11, 0x40, 0x44, 0x42, 0x7, 0x3b, 0x9, 0x23, 0xb},
|
||||
65: [12]uint8{0x0, 0x1, 0x2, 0x3, 0x40, 0x41, 0x42, 0x7, 0x8, 0x9, 0xa, 0x34},
|
||||
66: [12]uint8{0x34, 0x35, 0x36, 0x11, 0x4, 0x5, 0x42, 0x7, 0x3b, 0x9, 0x31, 0x34},
|
||||
67: [12]uint8{0x34, 0x35, 0x36, 0x11, 0x4, 0x5, 0x42, 0x7, 0x3b, 0x9, 0x32, 0x34},
|
||||
68: [12]uint8{0x0, 0x1, 0x45, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x27, 0xb},
|
||||
69: [12]uint8{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x46, 0xb},
|
||||
70: [12]uint8{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x47, 0x48, 0xb},
|
||||
44: [12]uint8{0x1, 0x0, 0x2, 0x3, 0x4, 0x1b, 0x17, 0x7, 0x8, 0x9, 0xa, 0xb},
|
||||
45: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x2b, 0x0},
|
||||
46: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x2c, 0xb},
|
||||
47: [12]uint8{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x2d, 0xb},
|
||||
48: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x2e, 0x7, 0x8, 0x9, 0xa, 0xb},
|
||||
49: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x2f, 0xb},
|
||||
50: [12]uint8{0x1, 0xc, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x30, 0xb},
|
||||
51: [12]uint8{0x1, 0x15, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb},
|
||||
52: [12]uint8{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x31, 0xb},
|
||||
53: [12]uint8{0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x7, 0x39, 0x9, 0xa, 0xb},
|
||||
54: [12]uint8{0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x7, 0x39, 0x9, 0x3a, 0xb},
|
||||
55: [12]uint8{0x32, 0x33, 0x34, 0x11, 0x36, 0x37, 0x38, 0x7, 0x39, 0x9, 0xa, 0xb},
|
||||
56: [12]uint8{0x32, 0x33, 0x34, 0x11, 0x36, 0x3b, 0x38, 0x7, 0x39, 0x9, 0xa, 0xb},
|
||||
57: [12]uint8{0x32, 0xc, 0x34, 0x35, 0x36, 0x3c, 0x38, 0x7, 0x39, 0x9, 0xa, 0x0},
|
||||
58: [12]uint8{0x32, 0x33, 0x34, 0x35, 0x36, 0x3c, 0x38, 0x7, 0x3d, 0x9, 0x22, 0xb},
|
||||
59: [12]uint8{0x32, 0x33, 0x34, 0x11, 0x3e, 0x3f, 0x40, 0x7, 0x39, 0x9, 0xa, 0x32},
|
||||
60: [12]uint8{0x32, 0x33, 0x34, 0x41, 0xe, 0x1c, 0x40, 0x7, 0x39, 0x9, 0x1d, 0xb},
|
||||
61: [12]uint8{0x32, 0x33, 0x34, 0x11, 0xe, 0x1c, 0x40, 0x7, 0x39, 0x9, 0xa, 0x32},
|
||||
62: [12]uint8{0x1, 0xc, 0x34, 0x11, 0x3e, 0x42, 0x40, 0x7, 0x39, 0x9, 0xa, 0x0},
|
||||
63: [12]uint8{0x32, 0x1, 0x34, 0x11, 0x4, 0x5, 0x40, 0x7, 0x39, 0x9, 0xa, 0x32},
|
||||
64: [12]uint8{0x32, 0x33, 0x34, 0x11, 0x3e, 0x42, 0x40, 0x7, 0x39, 0x9, 0x22, 0xb},
|
||||
65: [12]uint8{0x0, 0x1, 0x2, 0x3, 0x3e, 0x3f, 0x40, 0x7, 0x8, 0x9, 0xa, 0x32},
|
||||
66: [12]uint8{0x32, 0x33, 0x34, 0x11, 0x4, 0x5, 0x40, 0x7, 0x39, 0x9, 0x2f, 0x32},
|
||||
67: [12]uint8{0x32, 0x33, 0x34, 0x11, 0x4, 0x5, 0x40, 0x7, 0x39, 0x9, 0x30, 0x32},
|
||||
68: [12]uint8{0x0, 0x1, 0x43, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x26, 0xb},
|
||||
69: [12]uint8{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x44, 0xb},
|
||||
70: [12]uint8{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x45, 0x46, 0xb},
|
||||
} // Size: 876 bytes
|
||||
|
||||
var symData = stringset.Set{
|
||||
Data: "" + // Size: 584 bytes
|
||||
Data: "" + // Size: 580 bytes
|
||||
".,;%+-E׉∞NaN:\u00a0\u200e%\u200e\u200e+\u200e-ليس\u00a0رقمًا٪ND·Терхьаш" +
|
||||
"\u00a0дац'mnne×10^0/00INF−\u200e−ناعددepäluku’ՈչԹარ\u00a0არის\u00a0რიცხვ" +
|
||||
"იсан\u00a0емес¤¤¤сан\u00a0эмесບໍ່\u200bແມ່ນ\u200bໂຕ\u200bເລກNSဂဏန်းမဟု" +
|
||||
"တ်သောННне\u00a0числочыыһыла\u00a0буотах·10^–epilohosan\u00a0dälTFЕhaqi" +
|
||||
"qiy\u00a0son\u00a0emasҳақиқий\u00a0сон\u00a0эмас非數值٫٬؛٪\u061c\u061c+" +
|
||||
"\u061c-اس؉ليس\u00a0رقم\u200f−\u061c−؉\u200f\u200e+\u200e\u200e-\u200e×۱۰" +
|
||||
"^\u200e٪\u200e−\u200e၊ཨང་མེན་གྲངས་མེདཨང་མད",
|
||||
Index: []uint16{ // 74 elements
|
||||
"\u00a0дац’mnne×10^0/00INF−\u200e−ناعددepälukuՈչԹარ\u00a0არის\u00a0რიცხვი" +
|
||||
"сан\u00a0емес¤¤¤сан\u00a0эмесບໍ່\u200bແມ່ນ\u200bໂຕ\u200bເລກNSဂဏန်းမဟုတ်" +
|
||||
"သောННне\u00a0числочыыһыла\u00a0буотах·10^epilohosan\u00a0dälTFЕhaqiqiy" +
|
||||
"\u00a0son\u00a0emasҳақиқий\u00a0сон\u00a0эмас非數值٫٬؛٪\u061c\u061c+\u061c-" +
|
||||
"اس؉ليس\u00a0رقم\u200f−\u061c−؉\u200f\u200e+\u200e\u200e-\u200e×۱۰^" +
|
||||
"\u200e٪\u200e−\u200e၊ཨང་མེན་གྲངས་མེདཨང་མད",
|
||||
Index: []uint16{ // 72 elements
|
||||
// Entry 0 - 3F
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
|
||||
0x0009, 0x000c, 0x000f, 0x0012, 0x0013, 0x0015, 0x001c, 0x0020,
|
||||
0x0024, 0x0036, 0x0038, 0x003a, 0x003c, 0x0052, 0x0053, 0x0056,
|
||||
0x0057, 0x005c, 0x0060, 0x0063, 0x0066, 0x006c, 0x0076, 0x007e,
|
||||
0x0081, 0x0087, 0x00af, 0x00bf, 0x00c5, 0x00d5, 0x0102, 0x0104,
|
||||
0x012b, 0x012f, 0x013f, 0x015b, 0x0160, 0x0163, 0x016a, 0x0173,
|
||||
0x0175, 0x0177, 0x0189, 0x01a9, 0x01b2, 0x01b4, 0x01b6, 0x01b8,
|
||||
0x01bc, 0x01bf, 0x01c2, 0x01c6, 0x01c8, 0x01d6, 0x01dc, 0x01e1,
|
||||
0x0024, 0x0036, 0x0038, 0x003a, 0x003c, 0x0052, 0x0055, 0x0058,
|
||||
0x0059, 0x005e, 0x0062, 0x0065, 0x0068, 0x006e, 0x0078, 0x0080,
|
||||
0x0086, 0x00ae, 0x00be, 0x00c4, 0x00d4, 0x0101, 0x0103, 0x012a,
|
||||
0x012e, 0x013e, 0x015a, 0x015f, 0x0166, 0x016f, 0x0171, 0x0173,
|
||||
0x0185, 0x01a5, 0x01ae, 0x01b0, 0x01b2, 0x01b4, 0x01b8, 0x01bb,
|
||||
0x01be, 0x01c2, 0x01c4, 0x01d2, 0x01d8, 0x01dd, 0x01e2, 0x01e9,
|
||||
// Entry 40 - 7F
|
||||
0x01e6, 0x01ed, 0x01f4, 0x01fb, 0x0200, 0x0209, 0x020c, 0x0221,
|
||||
0x0239, 0x0248,
|
||||
0x01f0, 0x01f7, 0x01fc, 0x0205, 0x0208, 0x021d, 0x0235, 0x0244,
|
||||
},
|
||||
} // Size: 772 bytes
|
||||
} // Size: 764 bytes
|
||||
|
||||
// langToDefaults maps a compact language index to the default numbering system
|
||||
// and default symbol set
|
||||
var langToDefaults = [752]uint8{
|
||||
var langToDefaults = [754]uint8{
|
||||
// Entry 0 - 3F
|
||||
0x80, 0x06, 0x13, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x83, 0x02, 0x02, 0x02,
|
||||
@@ -365,79 +364,80 @@ var langToDefaults = [752]uint8{
|
||||
0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x14, 0x14,
|
||||
0x06, 0x00, 0x06, 0x06, 0x00, 0x06, 0x06, 0x01,
|
||||
0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00,
|
||||
0x06, 0x00, 0x06, 0x06, 0x00, 0x00, 0x06, 0x06,
|
||||
0x01, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x00,
|
||||
// Entry 100 - 13F
|
||||
0x06, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06,
|
||||
0x00, 0x00, 0x06, 0x06, 0x15, 0x15, 0x06, 0x06,
|
||||
0x01, 0x01, 0x97, 0x16, 0x16, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x17, 0x17, 0x00, 0x00, 0x18, 0x18,
|
||||
0x18, 0x9a, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x0d, 0x01, 0x01, 0x01, 0x01,
|
||||
0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
|
||||
0x06, 0x00, 0x00, 0x06, 0x06, 0x15, 0x15, 0x06,
|
||||
0x06, 0x01, 0x01, 0x97, 0x16, 0x16, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x17, 0x17, 0x00, 0x00, 0x18,
|
||||
0x18, 0x18, 0x9a, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x06, 0x06, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x06, 0x06, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
// Entry 140 - 17F
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x9d, 0x00,
|
||||
0x06, 0x06, 0x19, 0x19, 0x19, 0x19, 0xa0, 0x00,
|
||||
0x01, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x9d,
|
||||
0x00, 0x06, 0x06, 0x19, 0x19, 0x19, 0x19, 0xa0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1a, 0x1a, 0x00, 0x00, 0x06,
|
||||
0x06, 0x06, 0x0b, 0x0b, 0x01, 0x01, 0x1b, 0x1b,
|
||||
0x0a, 0x0a, 0xa2, 0x00, 0x00, 0x00, 0x06, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x1a, 0x1a, 0x00, 0x00,
|
||||
0x06, 0x06, 0x06, 0x0b, 0x0b, 0x01, 0x01, 0x1b,
|
||||
0x1b, 0x0a, 0x0a, 0xa2, 0x00, 0x00, 0x00, 0x06,
|
||||
// Entry 180 - 1BF
|
||||
0x06, 0x1c, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00,
|
||||
0x06, 0x06, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x01,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x01, 0x0d, 0x0d, 0x00, 0x00, 0x1e, 0x1e, 0x06,
|
||||
0x06, 0x1f, 0x1f, 0x00, 0x00, 0x06, 0x06, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x1a,
|
||||
0x00, 0x00, 0x01, 0x01, 0x20, 0x20, 0x00, 0x00,
|
||||
0x00, 0x21, 0x21, 0x00, 0x00, 0x06, 0x06, 0x00,
|
||||
0x06, 0x06, 0x1c, 0x06, 0x06, 0x06, 0x00, 0x00,
|
||||
0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x00, 0x1d,
|
||||
0x1d, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, 0x01, 0x0d, 0x0d, 0x00, 0x00, 0x1e,
|
||||
0x1e, 0x06, 0x06, 0x1f, 0x1f, 0x00, 0x00, 0x06,
|
||||
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xa5, 0x1a, 0x00, 0x00, 0x01, 0x01, 0x20, 0x20,
|
||||
0x00, 0x00, 0x00, 0x21, 0x21, 0x00, 0x00, 0x06,
|
||||
// Entry 1C0 - 1FF
|
||||
0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x22, 0x22, 0xa7, 0x00, 0x00, 0x15, 0x15, 0x06,
|
||||
0x06, 0x00, 0x00, 0x00, 0x00, 0x23, 0x23, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0d, 0x0d, 0x00, 0x00,
|
||||
0x06, 0x06, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00,
|
||||
0x00, 0x00, 0xa9, 0x00, 0x00, 0x06, 0x00, 0x00,
|
||||
0x00, 0x00, 0x06, 0x06, 0xaa, 0x24, 0xac, 0x00,
|
||||
0x00, 0x00, 0x00, 0xad, 0x14, 0x14, 0x00, 0x00,
|
||||
0x06, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x22, 0x22, 0xa7, 0x00, 0x00, 0x15,
|
||||
0x15, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x23,
|
||||
0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x0d,
|
||||
0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x06, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0xaa, 0x24,
|
||||
0xac, 0x00, 0x00, 0x00, 0x00, 0xad, 0x14, 0x14,
|
||||
// Entry 200 - 23F
|
||||
0x06, 0x06, 0x06, 0xb0, 0x00, 0x00, 0xb1, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x01, 0x01,
|
||||
0x14, 0x14, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x06, 0x06, 0x06, 0xb0, 0x00, 0x00,
|
||||
0xb1, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x01, 0x01, 0x14, 0x14, 0x06, 0x06, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x25, 0x25, 0x25, 0xb4, 0xb6, 0x1a,
|
||||
0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0xb8,
|
||||
0x26, 0x06, 0x01, 0x06, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x25, 0x25, 0x25, 0xb4,
|
||||
0xb6, 0x1a, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
|
||||
0x01, 0xb8, 0x26, 0x06, 0x01, 0x06, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
// Entry 240 - 27F
|
||||
0x00, 0x00, 0x19, 0x19, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x00, 0x00, 0x27, 0x27, 0x27, 0x27, 0x27,
|
||||
0x27, 0x27, 0x06, 0x06, 0x00, 0x00, 0x28, 0x28,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x29, 0x29,
|
||||
0x29, 0x06, 0x06, 0x0d, 0x0d, 0x06, 0x06, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x2a, 0x2a, 0x2b, 0x2b,
|
||||
0x2c, 0x2c, 0x00, 0x00, 0x00, 0x2d, 0x2d, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x06, 0x00, 0x00, 0x19, 0x19, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x00, 0x00, 0x27, 0x27, 0x27,
|
||||
0x27, 0x27, 0x27, 0x27, 0x06, 0x06, 0x00, 0x00,
|
||||
0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29,
|
||||
0x29, 0x29, 0x29, 0x06, 0x06, 0x0d, 0x0d, 0x06,
|
||||
0x06, 0x01, 0x01, 0x01, 0x01, 0x01, 0x2a, 0x2a,
|
||||
0x2b, 0x2b, 0x2c, 0x2c, 0x00, 0x00, 0x00, 0x2d,
|
||||
0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Entry 280 - 2BF
|
||||
0x01, 0x01, 0x01, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
|
||||
0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00,
|
||||
0x00, 0xba, 0x20, 0x20, 0x20, 0x00, 0x06, 0x00,
|
||||
0x00, 0x01, 0x01, 0x01, 0x01, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x00, 0x00, 0x00, 0xba, 0x20, 0x20, 0x20, 0x00,
|
||||
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x2e, 0x2e, 0x00, 0x2f, 0x2f,
|
||||
0x06, 0x06, 0x06, 0x00, 0x0d, 0x0d, 0x01, 0x01,
|
||||
0x00, 0x00, 0x30, 0x30, 0xbd, 0xbf, 0x1a, 0xc0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x2e, 0x00,
|
||||
0x2f, 0x2f, 0x06, 0x06, 0x06, 0x00, 0x0d, 0x0d,
|
||||
0x01, 0x01, 0x00, 0x00, 0x30, 0x30, 0xbd, 0xbf,
|
||||
// Entry 2C0 - 2FF
|
||||
0xc2, 0x26, 0xc4, 0x32, 0x31, 0x31, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x33, 0x33, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x34, 0x34, 0x01, 0x01, 0xc6, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x34, 0x34, 0x34, 0x34, 0x00, 0x00,
|
||||
} // Size: 752 bytes
|
||||
0x1a, 0xc0, 0xc2, 0x26, 0xc4, 0x32, 0x31, 0x31,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x34, 0x34, 0x01, 0x01, 0xc6, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x34, 0x34, 0x34, 0x34,
|
||||
0x00, 0x00,
|
||||
} // Size: 754 bytes
|
||||
|
||||
// langToAlt is a list of numbering system and symbol set pairs, sorted and
|
||||
// marked by compact language index.
|
||||
@@ -464,59 +464,59 @@ var langToAlt = []altSymData{ // 73 elements
|
||||
20: {compactTag: 0x63, system: 0x3, symIndex: 0x35},
|
||||
21: {compactTag: 0x7b, system: 0x36, symIndex: 0x46},
|
||||
22: {compactTag: 0x7b, system: 0x0, symIndex: 0x0},
|
||||
23: {compactTag: 0x112, system: 0x4, symIndex: 0x3c},
|
||||
24: {compactTag: 0x112, system: 0x0, symIndex: 0x16},
|
||||
25: {compactTag: 0x112, system: 0x3, symIndex: 0x37},
|
||||
26: {compactTag: 0x121, system: 0x0, symIndex: 0x1},
|
||||
27: {compactTag: 0x121, system: 0x3, symIndex: 0x38},
|
||||
28: {compactTag: 0x121, system: 0x4, symIndex: 0x3d},
|
||||
29: {compactTag: 0x156, system: 0x0, symIndex: 0x0},
|
||||
30: {compactTag: 0x156, system: 0x3, symIndex: 0x37},
|
||||
31: {compactTag: 0x156, system: 0x4, symIndex: 0x3b},
|
||||
32: {compactTag: 0x15e, system: 0x0, symIndex: 0x0},
|
||||
33: {compactTag: 0x15e, system: 0x3, symIndex: 0x35},
|
||||
34: {compactTag: 0x17a, system: 0x0, symIndex: 0x0},
|
||||
35: {compactTag: 0x17a, system: 0x3, symIndex: 0x35},
|
||||
36: {compactTag: 0x17a, system: 0x4, symIndex: 0x3b},
|
||||
37: {compactTag: 0x1ae, system: 0x4, symIndex: 0x3b},
|
||||
38: {compactTag: 0x1ae, system: 0x0, symIndex: 0x1a},
|
||||
39: {compactTag: 0x1ca, system: 0x4, symIndex: 0x3b},
|
||||
40: {compactTag: 0x1ca, system: 0x0, symIndex: 0x0},
|
||||
41: {compactTag: 0x1ea, system: 0xb, symIndex: 0x0},
|
||||
42: {compactTag: 0x1f4, system: 0x23, symIndex: 0x44},
|
||||
43: {compactTag: 0x1f4, system: 0x0, symIndex: 0x24},
|
||||
44: {compactTag: 0x1f6, system: 0x4, symIndex: 0x3b},
|
||||
45: {compactTag: 0x1fb, system: 0x0, symIndex: 0x14},
|
||||
46: {compactTag: 0x1fb, system: 0x3, symIndex: 0x39},
|
||||
47: {compactTag: 0x1fb, system: 0x4, symIndex: 0x3e},
|
||||
48: {compactTag: 0x203, system: 0xb, symIndex: 0x0},
|
||||
49: {compactTag: 0x206, system: 0x0, symIndex: 0x6},
|
||||
50: {compactTag: 0x206, system: 0x3, symIndex: 0x35},
|
||||
51: {compactTag: 0x206, system: 0x4, symIndex: 0x3b},
|
||||
52: {compactTag: 0x225, system: 0x0, symIndex: 0x0},
|
||||
53: {compactTag: 0x225, system: 0x4, symIndex: 0x3f},
|
||||
54: {compactTag: 0x226, system: 0x4, symIndex: 0x3b},
|
||||
55: {compactTag: 0x226, system: 0x0, symIndex: 0x1a},
|
||||
56: {compactTag: 0x22f, system: 0x4, symIndex: 0x3b},
|
||||
57: {compactTag: 0x22f, system: 0x0, symIndex: 0x26},
|
||||
58: {compactTag: 0x291, system: 0x0, symIndex: 0x20},
|
||||
59: {compactTag: 0x291, system: 0x3, symIndex: 0x3a},
|
||||
60: {compactTag: 0x291, system: 0x4, symIndex: 0x40},
|
||||
61: {compactTag: 0x2bc, system: 0x0, symIndex: 0x1a},
|
||||
62: {compactTag: 0x2bc, system: 0x4, symIndex: 0x41},
|
||||
63: {compactTag: 0x2bd, system: 0x4, symIndex: 0x41},
|
||||
64: {compactTag: 0x2bf, system: 0x0, symIndex: 0x31},
|
||||
65: {compactTag: 0x2bf, system: 0x4, symIndex: 0x42},
|
||||
66: {compactTag: 0x2c0, system: 0x4, symIndex: 0x3b},
|
||||
67: {compactTag: 0x2c0, system: 0x0, symIndex: 0x26},
|
||||
68: {compactTag: 0x2c2, system: 0x0, symIndex: 0x32},
|
||||
69: {compactTag: 0x2c2, system: 0x4, symIndex: 0x43},
|
||||
70: {compactTag: 0x2e4, system: 0x0, symIndex: 0x0},
|
||||
71: {compactTag: 0x2e4, system: 0x3, symIndex: 0x35},
|
||||
72: {compactTag: 0x2e4, system: 0x4, symIndex: 0x3b},
|
||||
23: {compactTag: 0x113, system: 0x4, symIndex: 0x3c},
|
||||
24: {compactTag: 0x113, system: 0x0, symIndex: 0x16},
|
||||
25: {compactTag: 0x113, system: 0x3, symIndex: 0x37},
|
||||
26: {compactTag: 0x122, system: 0x0, symIndex: 0x1},
|
||||
27: {compactTag: 0x122, system: 0x3, symIndex: 0x38},
|
||||
28: {compactTag: 0x122, system: 0x4, symIndex: 0x3d},
|
||||
29: {compactTag: 0x157, system: 0x0, symIndex: 0x0},
|
||||
30: {compactTag: 0x157, system: 0x3, symIndex: 0x37},
|
||||
31: {compactTag: 0x157, system: 0x4, symIndex: 0x3b},
|
||||
32: {compactTag: 0x15f, system: 0x0, symIndex: 0x0},
|
||||
33: {compactTag: 0x15f, system: 0x3, symIndex: 0x35},
|
||||
34: {compactTag: 0x17b, system: 0x0, symIndex: 0x0},
|
||||
35: {compactTag: 0x17b, system: 0x3, symIndex: 0x35},
|
||||
36: {compactTag: 0x17b, system: 0x4, symIndex: 0x3b},
|
||||
37: {compactTag: 0x1b0, system: 0x4, symIndex: 0x3b},
|
||||
38: {compactTag: 0x1b0, system: 0x0, symIndex: 0x1a},
|
||||
39: {compactTag: 0x1cc, system: 0x4, symIndex: 0x3b},
|
||||
40: {compactTag: 0x1cc, system: 0x0, symIndex: 0x0},
|
||||
41: {compactTag: 0x1ec, system: 0xb, symIndex: 0x0},
|
||||
42: {compactTag: 0x1f6, system: 0x23, symIndex: 0x44},
|
||||
43: {compactTag: 0x1f6, system: 0x0, symIndex: 0x24},
|
||||
44: {compactTag: 0x1f8, system: 0x4, symIndex: 0x3b},
|
||||
45: {compactTag: 0x1fd, system: 0x0, symIndex: 0x14},
|
||||
46: {compactTag: 0x1fd, system: 0x3, symIndex: 0x39},
|
||||
47: {compactTag: 0x1fd, system: 0x4, symIndex: 0x3e},
|
||||
48: {compactTag: 0x205, system: 0xb, symIndex: 0x0},
|
||||
49: {compactTag: 0x208, system: 0x0, symIndex: 0x6},
|
||||
50: {compactTag: 0x208, system: 0x3, symIndex: 0x35},
|
||||
51: {compactTag: 0x208, system: 0x4, symIndex: 0x3b},
|
||||
52: {compactTag: 0x227, system: 0x0, symIndex: 0x0},
|
||||
53: {compactTag: 0x227, system: 0x4, symIndex: 0x3f},
|
||||
54: {compactTag: 0x228, system: 0x4, symIndex: 0x3b},
|
||||
55: {compactTag: 0x228, system: 0x0, symIndex: 0x1a},
|
||||
56: {compactTag: 0x231, system: 0x4, symIndex: 0x3b},
|
||||
57: {compactTag: 0x231, system: 0x0, symIndex: 0x26},
|
||||
58: {compactTag: 0x293, system: 0x0, symIndex: 0x20},
|
||||
59: {compactTag: 0x293, system: 0x3, symIndex: 0x3a},
|
||||
60: {compactTag: 0x293, system: 0x4, symIndex: 0x40},
|
||||
61: {compactTag: 0x2be, system: 0x0, symIndex: 0x1a},
|
||||
62: {compactTag: 0x2be, system: 0x4, symIndex: 0x41},
|
||||
63: {compactTag: 0x2bf, system: 0x4, symIndex: 0x41},
|
||||
64: {compactTag: 0x2c1, system: 0x0, symIndex: 0x31},
|
||||
65: {compactTag: 0x2c1, system: 0x4, symIndex: 0x42},
|
||||
66: {compactTag: 0x2c2, system: 0x4, symIndex: 0x3b},
|
||||
67: {compactTag: 0x2c2, system: 0x0, symIndex: 0x26},
|
||||
68: {compactTag: 0x2c4, system: 0x0, symIndex: 0x32},
|
||||
69: {compactTag: 0x2c4, system: 0x4, symIndex: 0x43},
|
||||
70: {compactTag: 0x2e6, system: 0x0, symIndex: 0x0},
|
||||
71: {compactTag: 0x2e6, system: 0x3, symIndex: 0x35},
|
||||
72: {compactTag: 0x2e6, system: 0x4, symIndex: 0x3b},
|
||||
} // Size: 316 bytes
|
||||
|
||||
var tagToDecimal = []uint8{ // 752 elements
|
||||
var tagToDecimal = []uint8{ // 754 elements
|
||||
// Entry 0 - 3F
|
||||
0x01, 0x01, 0x08, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
@@ -566,10 +566,10 @@ var tagToDecimal = []uint8{ // 752 elements
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x05,
|
||||
0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x05, 0x05,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x05, 0x05, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
// Entry 180 - 1BF
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
@@ -577,16 +577,16 @@ var tagToDecimal = []uint8{ // 752 elements
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x05, 0x05, 0x05, 0x05,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x05, 0x05,
|
||||
0x05, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
// Entry 1C0 - 1FF
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x05, 0x05,
|
||||
0x01, 0x01, 0x05, 0x05, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x05, 0x05, 0x01, 0x01, 0x05, 0x05, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
// Entry 200 - 23F
|
||||
@@ -594,8 +594,8 @@ var tagToDecimal = []uint8{ // 752 elements
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x05, 0x05, 0x01, 0x01, 0x01, 0x05, 0x01, 0x01,
|
||||
0x05, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x05, 0x05, 0x01, 0x01, 0x01, 0x05,
|
||||
0x01, 0x01, 0x05, 0x05, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
// Entry 240 - 27F
|
||||
@@ -611,7 +611,7 @@ var tagToDecimal = []uint8{ // 752 elements
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x05, 0x05, 0x05, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x05, 0x05, 0x05,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
@@ -623,9 +623,10 @@ var tagToDecimal = []uint8{ // 752 elements
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
} // Size: 776 bytes
|
||||
0x01, 0x01,
|
||||
} // Size: 778 bytes
|
||||
|
||||
var tagToScientific = []uint8{ // 752 elements
|
||||
var tagToScientific = []uint8{ // 754 elements
|
||||
// Entry 0 - 3F
|
||||
0x02, 0x02, 0x09, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
@@ -675,10 +676,10 @@ var tagToScientific = []uint8{ // 752 elements
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0d,
|
||||
0x0d, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0d, 0x0d,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x0d, 0x0d, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
// Entry 180 - 1BF
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
@@ -691,11 +692,11 @@ var tagToScientific = []uint8{ // 752 elements
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
// Entry 1C0 - 1FF
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x0e, 0x0e, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x0e, 0x0e, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x0d, 0x0d, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x0d, 0x0d, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
// Entry 200 - 23F
|
||||
@@ -703,8 +704,8 @@ var tagToScientific = []uint8{ // 752 elements
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x0d, 0x02, 0x02,
|
||||
0x0d, 0x0d, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0d,
|
||||
0x02, 0x02, 0x0d, 0x0d, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
// Entry 240 - 27F
|
||||
@@ -713,7 +714,7 @@ var tagToScientific = []uint8{ // 752 elements
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x0e, 0x0e, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0e, 0x0e,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
// Entry 280 - 2BF
|
||||
@@ -732,9 +733,10 @@ var tagToScientific = []uint8{ // 752 elements
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
} // Size: 776 bytes
|
||||
0x02, 0x02,
|
||||
} // Size: 778 bytes
|
||||
|
||||
var tagToPercent = []uint8{ // 752 elements
|
||||
var tagToPercent = []uint8{ // 754 elements
|
||||
// Entry 0 - 3F
|
||||
0x04, 0x04, 0x0a, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
@@ -769,87 +771,88 @@ var tagToPercent = []uint8{ // 752 elements
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x03,
|
||||
0x03, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04,
|
||||
0x03, 0x03, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
// Entry 100 - 13F
|
||||
0x03, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x0b, 0x0b,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x03, 0x03, 0x04, 0x04, 0x03, 0x03,
|
||||
0x03, 0x03, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x0b,
|
||||
0x0b, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x03, 0x03, 0x04, 0x04, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
// Entry 140 - 17F
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x06, 0x06,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x06, 0x06, 0x04,
|
||||
0x04, 0x04, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04,
|
||||
0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x06,
|
||||
0x06, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x06, 0x06,
|
||||
0x04, 0x04, 0x04, 0x03, 0x03, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
// Entry 180 - 1BF
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06,
|
||||
0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x04,
|
||||
// Entry 1C0 - 1FF
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x04, 0x04,
|
||||
// Entry 200 - 23F
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x06, 0x06, 0x04, 0x04, 0x04, 0x06, 0x04, 0x04,
|
||||
0x06, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
|
||||
// Entry 240 - 27F
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03,
|
||||
0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
|
||||
0x03, 0x03, 0x04, 0x04, 0x04, 0x03, 0x03, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
// Entry 280 - 2BF
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x06, 0x06, 0x06, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x03, 0x03, 0x04, 0x04, 0x04,
|
||||
0x0f, 0x0f, 0x0f, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x06, 0x06, 0x06, 0x04,
|
||||
// Entry 2C0 - 2FF
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x06, 0x06,
|
||||
0x06, 0x06, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03,
|
||||
// Entry 1C0 - 1FF
|
||||
0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03,
|
||||
0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03,
|
||||
// Entry 200 - 23F
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
} // Size: 776 bytes
|
||||
0x04, 0x04, 0x06, 0x06, 0x04, 0x04, 0x04, 0x06,
|
||||
0x04, 0x04, 0x06, 0x06, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
// Entry 240 - 27F
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x04, 0x04, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03,
|
||||
0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x03,
|
||||
0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
// Entry 280 - 2BF
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x06, 0x06, 0x06,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x04,
|
||||
0x04, 0x04, 0x0f, 0x0f, 0x0f, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x06, 0x06,
|
||||
// Entry 2C0 - 2FF
|
||||
0x06, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x04,
|
||||
} // Size: 778 bytes
|
||||
|
||||
var formats = []Pattern{Pattern{Affix: "",
|
||||
Offset: 0x0,
|
||||
NegOffset: 0x0,
|
||||
Multiplier: 0x0,
|
||||
FormatWidth: 0x0,
|
||||
RoundIncrement: 0x0,
|
||||
PadRune: 0,
|
||||
FormatWidth: 0x0,
|
||||
DigitShift: 0x0,
|
||||
GroupingSize: [2]uint8{0x0,
|
||||
0x0},
|
||||
Flags: 0x0,
|
||||
@@ -863,10 +866,10 @@ var formats = []Pattern{Pattern{Affix: "",
|
||||
Pattern{Affix: "",
|
||||
Offset: 0x0,
|
||||
NegOffset: 0x0,
|
||||
Multiplier: 0x0,
|
||||
FormatWidth: 0x9,
|
||||
RoundIncrement: 0x0,
|
||||
PadRune: 0,
|
||||
FormatWidth: 0x9,
|
||||
DigitShift: 0x0,
|
||||
GroupingSize: [2]uint8{0x3,
|
||||
0x0},
|
||||
Flags: 0x0,
|
||||
@@ -880,10 +883,10 @@ var formats = []Pattern{Pattern{Affix: "",
|
||||
Pattern{Affix: "",
|
||||
Offset: 0x0,
|
||||
NegOffset: 0x0,
|
||||
Multiplier: 0x0,
|
||||
FormatWidth: 0x3,
|
||||
RoundIncrement: 0x0,
|
||||
PadRune: 0,
|
||||
FormatWidth: 0x3,
|
||||
DigitShift: 0x0,
|
||||
GroupingSize: [2]uint8{0x0,
|
||||
0x0},
|
||||
Flags: 0x0,
|
||||
@@ -897,10 +900,10 @@ var formats = []Pattern{Pattern{Affix: "",
|
||||
Pattern{Affix: "\x00\x03\u00a0%",
|
||||
Offset: 0x0,
|
||||
NegOffset: 0x0,
|
||||
Multiplier: 0x64,
|
||||
FormatWidth: 0x7,
|
||||
RoundIncrement: 0x0,
|
||||
PadRune: 0,
|
||||
FormatWidth: 0x7,
|
||||
DigitShift: 0x2,
|
||||
GroupingSize: [2]uint8{0x3,
|
||||
0x0},
|
||||
Flags: 0x0,
|
||||
@@ -914,10 +917,10 @@ var formats = []Pattern{Pattern{Affix: "",
|
||||
Pattern{Affix: "\x00\x01%",
|
||||
Offset: 0x0,
|
||||
NegOffset: 0x0,
|
||||
Multiplier: 0x64,
|
||||
FormatWidth: 0x6,
|
||||
RoundIncrement: 0x0,
|
||||
PadRune: 0,
|
||||
FormatWidth: 0x6,
|
||||
DigitShift: 0x2,
|
||||
GroupingSize: [2]uint8{0x3,
|
||||
0x0},
|
||||
Flags: 0x0,
|
||||
@@ -931,10 +934,10 @@ var formats = []Pattern{Pattern{Affix: "",
|
||||
Pattern{Affix: "",
|
||||
Offset: 0x0,
|
||||
NegOffset: 0x0,
|
||||
Multiplier: 0x0,
|
||||
FormatWidth: 0xc,
|
||||
RoundIncrement: 0x0,
|
||||
PadRune: 0,
|
||||
FormatWidth: 0xc,
|
||||
DigitShift: 0x0,
|
||||
GroupingSize: [2]uint8{0x3,
|
||||
0x2},
|
||||
Flags: 0x0,
|
||||
@@ -948,10 +951,10 @@ var formats = []Pattern{Pattern{Affix: "",
|
||||
Pattern{Affix: "\x00\x01%",
|
||||
Offset: 0x0,
|
||||
NegOffset: 0x0,
|
||||
Multiplier: 0x64,
|
||||
FormatWidth: 0x9,
|
||||
RoundIncrement: 0x0,
|
||||
PadRune: 0,
|
||||
FormatWidth: 0x9,
|
||||
DigitShift: 0x2,
|
||||
GroupingSize: [2]uint8{0x3,
|
||||
0x2},
|
||||
Flags: 0x0,
|
||||
@@ -965,10 +968,10 @@ var formats = []Pattern{Pattern{Affix: "",
|
||||
Pattern{Affix: "\x00\x03\u00a0%",
|
||||
Offset: 0x0,
|
||||
NegOffset: 0x0,
|
||||
Multiplier: 0x64,
|
||||
FormatWidth: 0xa,
|
||||
RoundIncrement: 0x0,
|
||||
PadRune: 0,
|
||||
FormatWidth: 0xa,
|
||||
DigitShift: 0x2,
|
||||
GroupingSize: [2]uint8{0x3,
|
||||
0x2},
|
||||
Flags: 0x0,
|
||||
@@ -982,10 +985,10 @@ var formats = []Pattern{Pattern{Affix: "",
|
||||
Pattern{Affix: "",
|
||||
Offset: 0x0,
|
||||
NegOffset: 0x0,
|
||||
Multiplier: 0x0,
|
||||
FormatWidth: 0x9,
|
||||
RoundIncrement: 0x0,
|
||||
PadRune: 0,
|
||||
FormatWidth: 0x9,
|
||||
DigitShift: 0x0,
|
||||
GroupingSize: [2]uint8{0x0,
|
||||
0x0},
|
||||
Flags: 0x0,
|
||||
@@ -999,13 +1002,13 @@ var formats = []Pattern{Pattern{Affix: "",
|
||||
Pattern{Affix: "",
|
||||
Offset: 0x0,
|
||||
NegOffset: 0x0,
|
||||
Multiplier: 0x0,
|
||||
FormatWidth: 0xd,
|
||||
RoundIncrement: 0x0,
|
||||
PadRune: 0,
|
||||
FormatWidth: 0xd,
|
||||
DigitShift: 0x0,
|
||||
GroupingSize: [2]uint8{0x0,
|
||||
0x0},
|
||||
Flags: 0x2,
|
||||
Flags: 0x4,
|
||||
MinIntegerDigits: 0x1,
|
||||
MaxIntegerDigits: 0x0,
|
||||
MinFractionDigits: 0x6,
|
||||
@@ -1016,10 +1019,10 @@ var formats = []Pattern{Pattern{Affix: "",
|
||||
Pattern{Affix: "\x00\x01%",
|
||||
Offset: 0x0,
|
||||
NegOffset: 0x0,
|
||||
Multiplier: 0x64,
|
||||
FormatWidth: 0x3,
|
||||
RoundIncrement: 0x0,
|
||||
PadRune: 0,
|
||||
FormatWidth: 0x3,
|
||||
DigitShift: 0x2,
|
||||
GroupingSize: [2]uint8{0x0,
|
||||
0x0},
|
||||
Flags: 0x0,
|
||||
@@ -1033,11 +1036,11 @@ var formats = []Pattern{Pattern{Affix: "",
|
||||
Pattern{Affix: "\x03%\u00a0\x00",
|
||||
Offset: 0x0,
|
||||
NegOffset: 0x0,
|
||||
Multiplier: 0x64,
|
||||
FormatWidth: 0x7,
|
||||
RoundIncrement: 0x0,
|
||||
PadRune: 0,
|
||||
FormatWidth: 0x7,
|
||||
GroupingSize: [2]uint8{0x0,
|
||||
DigitShift: 0x2,
|
||||
GroupingSize: [2]uint8{0x3,
|
||||
0x0},
|
||||
Flags: 0x0,
|
||||
MinIntegerDigits: 0x1,
|
||||
@@ -1050,10 +1053,10 @@ var formats = []Pattern{Pattern{Affix: "",
|
||||
Pattern{Affix: "\x03%\u00a0\x00\x04%\u00a0-\x00",
|
||||
Offset: 0x0,
|
||||
NegOffset: 0x5,
|
||||
Multiplier: 0x64,
|
||||
FormatWidth: 0x7,
|
||||
RoundIncrement: 0x0,
|
||||
PadRune: 0,
|
||||
FormatWidth: 0x7,
|
||||
DigitShift: 0x2,
|
||||
GroupingSize: [2]uint8{0x3,
|
||||
0x0},
|
||||
Flags: 0x0,
|
||||
@@ -1067,10 +1070,10 @@ var formats = []Pattern{Pattern{Affix: "",
|
||||
Pattern{Affix: "\x01[\x01]",
|
||||
Offset: 0x0,
|
||||
NegOffset: 0x0,
|
||||
Multiplier: 0x0,
|
||||
FormatWidth: 0x5,
|
||||
RoundIncrement: 0x0,
|
||||
PadRune: 0,
|
||||
FormatWidth: 0x5,
|
||||
DigitShift: 0x0,
|
||||
GroupingSize: [2]uint8{0x0,
|
||||
0x0},
|
||||
Flags: 0x0,
|
||||
@@ -1084,10 +1087,10 @@ var formats = []Pattern{Pattern{Affix: "",
|
||||
Pattern{Affix: "",
|
||||
Offset: 0x0,
|
||||
NegOffset: 0x0,
|
||||
Multiplier: 0x0,
|
||||
FormatWidth: 0x1,
|
||||
RoundIncrement: 0x0,
|
||||
PadRune: 0,
|
||||
FormatWidth: 0x1,
|
||||
DigitShift: 0x0,
|
||||
GroupingSize: [2]uint8{0x0,
|
||||
0x0},
|
||||
Flags: 0x0,
|
||||
@@ -1101,11 +1104,11 @@ var formats = []Pattern{Pattern{Affix: "",
|
||||
Pattern{Affix: "\x01%\x00",
|
||||
Offset: 0x0,
|
||||
NegOffset: 0x0,
|
||||
Multiplier: 0x64,
|
||||
FormatWidth: 0x6,
|
||||
RoundIncrement: 0x0,
|
||||
PadRune: 0,
|
||||
FormatWidth: 0x6,
|
||||
GroupingSize: [2]uint8{0x0,
|
||||
DigitShift: 0x2,
|
||||
GroupingSize: [2]uint8{0x3,
|
||||
0x0},
|
||||
Flags: 0x0,
|
||||
MinIntegerDigits: 0x1,
|
||||
@@ -1116,4 +1119,4 @@ var formats = []Pattern{Pattern{Affix: "",
|
||||
MaxSignificantDigits: 0x0,
|
||||
MinExponentDigits: 0x0}}
|
||||
|
||||
// Total table size 7101 bytes (6KiB); checksum: A4A81DF0
|
||||
// Total table size 7101 bytes (6KiB); checksum: 5190D0B3
|
||||
|
||||
+63
-62
@@ -4,7 +4,7 @@ package internal
|
||||
|
||||
// Parent maps a compact index of a tag to the compact index of the parent of
|
||||
// this tag.
|
||||
var Parent = []uint16{ // 752 elements
|
||||
var Parent = []uint16{ // 754 elements
|
||||
// Entry 0 - 3F
|
||||
0x0000, 0x0053, 0x00e5, 0x0000, 0x0003, 0x0003, 0x0000, 0x0006,
|
||||
0x0000, 0x0008, 0x0000, 0x000a, 0x0000, 0x000c, 0x000c, 0x000c,
|
||||
@@ -40,77 +40,78 @@ var Parent = []uint16{ // 752 elements
|
||||
0x0086, 0x0086, 0x0086, 0x0086, 0x0085, 0x0085, 0x0086, 0x0086,
|
||||
0x0085, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0000, 0x00ee,
|
||||
0x0000, 0x00f0, 0x00f1, 0x00f1, 0x00f1, 0x00f1, 0x00f1, 0x00f1,
|
||||
0x00f1, 0x00f1, 0x00f0, 0x00f1, 0x00f0, 0x00f0, 0x00f1, 0x00f1,
|
||||
0x00f1, 0x00f1, 0x00f1, 0x00f0, 0x00f1, 0x00f0, 0x00f0, 0x00f1,
|
||||
// Entry 100 - 13F
|
||||
0x00f0, 0x00f1, 0x00f1, 0x00f1, 0x00f1, 0x00f0, 0x00f1, 0x00f1,
|
||||
0x00f1, 0x00f1, 0x00f1, 0x00f1, 0x0000, 0x010c, 0x0000, 0x010e,
|
||||
0x0000, 0x0110, 0x0000, 0x0112, 0x0112, 0x0000, 0x0115, 0x0115,
|
||||
0x0115, 0x0115, 0x0000, 0x011a, 0x0000, 0x011c, 0x0000, 0x011e,
|
||||
0x011e, 0x0000, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121,
|
||||
0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121,
|
||||
0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121,
|
||||
0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121,
|
||||
0x00f1, 0x00f0, 0x00f1, 0x00f1, 0x00f1, 0x00f1, 0x00f0, 0x00f1,
|
||||
0x00f1, 0x00f1, 0x00f1, 0x00f1, 0x00f1, 0x0000, 0x010d, 0x0000,
|
||||
0x010f, 0x0000, 0x0111, 0x0000, 0x0113, 0x0113, 0x0000, 0x0116,
|
||||
0x0116, 0x0116, 0x0116, 0x0000, 0x011b, 0x0000, 0x011d, 0x0000,
|
||||
0x011f, 0x011f, 0x0000, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122,
|
||||
0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122,
|
||||
0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122,
|
||||
0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122,
|
||||
// Entry 140 - 17F
|
||||
0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121,
|
||||
0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121,
|
||||
0x0000, 0x0150, 0x0000, 0x0152, 0x0000, 0x0154, 0x0000, 0x0156,
|
||||
0x0000, 0x0158, 0x0000, 0x015a, 0x015a, 0x015a, 0x0000, 0x015e,
|
||||
0x0000, 0x0000, 0x0161, 0x0000, 0x0163, 0x0000, 0x0165, 0x0165,
|
||||
0x0165, 0x0000, 0x0169, 0x0000, 0x016b, 0x0000, 0x016d, 0x0000,
|
||||
0x016f, 0x016f, 0x0000, 0x0172, 0x0000, 0x0174, 0x0000, 0x0176,
|
||||
0x0000, 0x0178, 0x0000, 0x017a, 0x0000, 0x017c, 0x0000, 0x017e,
|
||||
0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122,
|
||||
0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122,
|
||||
0x0122, 0x0000, 0x0151, 0x0000, 0x0153, 0x0000, 0x0155, 0x0000,
|
||||
0x0157, 0x0000, 0x0159, 0x0000, 0x015b, 0x015b, 0x015b, 0x0000,
|
||||
0x015f, 0x0000, 0x0000, 0x0162, 0x0000, 0x0164, 0x0000, 0x0166,
|
||||
0x0166, 0x0166, 0x0000, 0x016a, 0x0000, 0x016c, 0x0000, 0x016e,
|
||||
0x0000, 0x0170, 0x0170, 0x0000, 0x0173, 0x0000, 0x0175, 0x0000,
|
||||
0x0177, 0x0000, 0x0179, 0x0000, 0x017b, 0x0000, 0x017d, 0x0000,
|
||||
// Entry 180 - 1BF
|
||||
0x0000, 0x0180, 0x0180, 0x0180, 0x0000, 0x0000, 0x0185, 0x0000,
|
||||
0x0000, 0x0188, 0x0000, 0x018a, 0x0000, 0x0000, 0x018d, 0x0000,
|
||||
0x018f, 0x0000, 0x0000, 0x0192, 0x0000, 0x0000, 0x0195, 0x0000,
|
||||
0x017f, 0x0000, 0x0181, 0x0181, 0x0181, 0x0181, 0x0000, 0x0000,
|
||||
0x0187, 0x0000, 0x0000, 0x018a, 0x0000, 0x018c, 0x0000, 0x0000,
|
||||
0x018f, 0x0000, 0x0191, 0x0000, 0x0000, 0x0194, 0x0000, 0x0000,
|
||||
0x0197, 0x0000, 0x0199, 0x0000, 0x019b, 0x0000, 0x019d, 0x0000,
|
||||
0x019f, 0x0000, 0x01a1, 0x0000, 0x01a3, 0x0000, 0x01a5, 0x0000,
|
||||
0x01a7, 0x0000, 0x01a9, 0x01a9, 0x0000, 0x01ac, 0x0000, 0x01ae,
|
||||
0x0000, 0x01b0, 0x0000, 0x01b2, 0x0000, 0x01b4, 0x0000, 0x0000,
|
||||
0x01b7, 0x0000, 0x01b9, 0x0000, 0x01bb, 0x0000, 0x01bd, 0x0000,
|
||||
0x01a7, 0x0000, 0x01a9, 0x0000, 0x01ab, 0x01ab, 0x0000, 0x01ae,
|
||||
0x0000, 0x01b0, 0x0000, 0x01b2, 0x0000, 0x01b4, 0x0000, 0x01b6,
|
||||
0x0000, 0x0000, 0x01b9, 0x0000, 0x01bb, 0x0000, 0x01bd, 0x0000,
|
||||
// Entry 1C0 - 1FF
|
||||
0x01bf, 0x0000, 0x01c1, 0x0000, 0x01c3, 0x01c3, 0x01c3, 0x01c3,
|
||||
0x0000, 0x01c8, 0x0000, 0x01ca, 0x01ca, 0x0000, 0x01cd, 0x0000,
|
||||
0x01bf, 0x0000, 0x01c1, 0x0000, 0x01c3, 0x0000, 0x01c5, 0x01c5,
|
||||
0x01c5, 0x01c5, 0x0000, 0x01ca, 0x0000, 0x01cc, 0x01cc, 0x0000,
|
||||
0x01cf, 0x0000, 0x01d1, 0x0000, 0x01d3, 0x0000, 0x01d5, 0x0000,
|
||||
0x01d7, 0x01d7, 0x0000, 0x01da, 0x0000, 0x01dc, 0x0000, 0x01de,
|
||||
0x01d7, 0x0000, 0x01d9, 0x01d9, 0x0000, 0x01dc, 0x0000, 0x01de,
|
||||
0x0000, 0x01e0, 0x0000, 0x01e2, 0x0000, 0x01e4, 0x0000, 0x01e6,
|
||||
0x0000, 0x01e8, 0x0000, 0x01ea, 0x0000, 0x01ec, 0x01ec, 0x01ec,
|
||||
0x0000, 0x01f0, 0x0000, 0x01f2, 0x0000, 0x01f4, 0x0000, 0x01f6,
|
||||
0x0000, 0x0000, 0x01f9, 0x0000, 0x01fb, 0x01fb, 0x0000, 0x01fe,
|
||||
0x0000, 0x01e8, 0x0000, 0x01ea, 0x0000, 0x01ec, 0x0000, 0x01ee,
|
||||
0x01ee, 0x01ee, 0x0000, 0x01f2, 0x0000, 0x01f4, 0x0000, 0x01f6,
|
||||
0x0000, 0x01f8, 0x0000, 0x0000, 0x01fb, 0x0000, 0x01fd, 0x01fd,
|
||||
// Entry 200 - 23F
|
||||
0x0000, 0x0200, 0x0200, 0x0000, 0x0203, 0x0203, 0x0000, 0x0206,
|
||||
0x0206, 0x0206, 0x0206, 0x0206, 0x0206, 0x0206, 0x0000, 0x020e,
|
||||
0x0000, 0x0210, 0x0000, 0x0212, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0218, 0x0000, 0x0000, 0x021b, 0x0000, 0x021d, 0x021d,
|
||||
0x0000, 0x0220, 0x0000, 0x0222, 0x0222, 0x0000, 0x0000, 0x0226,
|
||||
0x0225, 0x0225, 0x0000, 0x0000, 0x022b, 0x0000, 0x022d, 0x0000,
|
||||
0x022f, 0x0000, 0x023b, 0x0231, 0x023b, 0x023b, 0x023b, 0x023b,
|
||||
0x023b, 0x023b, 0x023b, 0x0231, 0x023b, 0x023b, 0x0000, 0x023e,
|
||||
0x0000, 0x0200, 0x0000, 0x0202, 0x0202, 0x0000, 0x0205, 0x0205,
|
||||
0x0000, 0x0208, 0x0208, 0x0208, 0x0208, 0x0208, 0x0208, 0x0208,
|
||||
0x0000, 0x0210, 0x0000, 0x0212, 0x0000, 0x0214, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x021a, 0x0000, 0x0000, 0x021d, 0x0000,
|
||||
0x021f, 0x021f, 0x0000, 0x0222, 0x0000, 0x0224, 0x0224, 0x0000,
|
||||
0x0000, 0x0228, 0x0227, 0x0227, 0x0000, 0x0000, 0x022d, 0x0000,
|
||||
0x022f, 0x0000, 0x0231, 0x0000, 0x023d, 0x0233, 0x023d, 0x023d,
|
||||
0x023d, 0x023d, 0x023d, 0x023d, 0x023d, 0x0233, 0x023d, 0x023d,
|
||||
// Entry 240 - 27F
|
||||
0x023e, 0x023e, 0x0000, 0x0242, 0x0000, 0x0244, 0x0000, 0x0246,
|
||||
0x0246, 0x0000, 0x0249, 0x0000, 0x024b, 0x024b, 0x024b, 0x024b,
|
||||
0x024b, 0x024b, 0x0000, 0x0252, 0x0000, 0x0254, 0x0000, 0x0256,
|
||||
0x0000, 0x0258, 0x0000, 0x025a, 0x0000, 0x0000, 0x025d, 0x025d,
|
||||
0x025d, 0x0000, 0x0261, 0x0000, 0x0263, 0x0000, 0x0265, 0x0000,
|
||||
0x0000, 0x0268, 0x0267, 0x0267, 0x0000, 0x026c, 0x0000, 0x026e,
|
||||
0x0000, 0x0270, 0x0000, 0x0000, 0x0000, 0x0000, 0x0275, 0x0000,
|
||||
0x0000, 0x0278, 0x0000, 0x027a, 0x027a, 0x027a, 0x027a, 0x0000,
|
||||
0x0000, 0x0240, 0x0240, 0x0240, 0x0000, 0x0244, 0x0000, 0x0246,
|
||||
0x0000, 0x0248, 0x0248, 0x0000, 0x024b, 0x0000, 0x024d, 0x024d,
|
||||
0x024d, 0x024d, 0x024d, 0x024d, 0x0000, 0x0254, 0x0000, 0x0256,
|
||||
0x0000, 0x0258, 0x0000, 0x025a, 0x0000, 0x025c, 0x0000, 0x0000,
|
||||
0x025f, 0x025f, 0x025f, 0x0000, 0x0263, 0x0000, 0x0265, 0x0000,
|
||||
0x0267, 0x0000, 0x0000, 0x026a, 0x0269, 0x0269, 0x0000, 0x026e,
|
||||
0x0000, 0x0270, 0x0000, 0x0272, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0277, 0x0000, 0x0000, 0x027a, 0x0000, 0x027c, 0x027c, 0x027c,
|
||||
// Entry 280 - 2BF
|
||||
0x027f, 0x027f, 0x027f, 0x0000, 0x0283, 0x0283, 0x0283, 0x0283,
|
||||
0x0283, 0x0000, 0x0289, 0x0289, 0x0289, 0x0289, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0291, 0x0291, 0x0291, 0x0000, 0x0295, 0x0295,
|
||||
0x0295, 0x0295, 0x0000, 0x0000, 0x029b, 0x029b, 0x029b, 0x029b,
|
||||
0x0000, 0x02a0, 0x0000, 0x02a2, 0x02a2, 0x0000, 0x02a5, 0x0000,
|
||||
0x02a7, 0x02a7, 0x0000, 0x0000, 0x02ab, 0x0000, 0x0000, 0x02ae,
|
||||
0x0000, 0x02b0, 0x02b0, 0x0000, 0x0000, 0x02b4, 0x0000, 0x02b6,
|
||||
0x0000, 0x02b8, 0x0000, 0x02ba, 0x0000, 0x02bc, 0x02bc, 0x0000,
|
||||
0x027c, 0x0000, 0x0281, 0x0281, 0x0281, 0x0000, 0x0285, 0x0285,
|
||||
0x0285, 0x0285, 0x0285, 0x0000, 0x028b, 0x028b, 0x028b, 0x028b,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0293, 0x0293, 0x0293, 0x0000,
|
||||
0x0297, 0x0297, 0x0297, 0x0297, 0x0000, 0x0000, 0x029d, 0x029d,
|
||||
0x029d, 0x029d, 0x0000, 0x02a2, 0x0000, 0x02a4, 0x02a4, 0x0000,
|
||||
0x02a7, 0x0000, 0x02a9, 0x02a9, 0x0000, 0x0000, 0x02ad, 0x0000,
|
||||
0x0000, 0x02b0, 0x0000, 0x02b2, 0x02b2, 0x0000, 0x0000, 0x02b6,
|
||||
0x0000, 0x02b8, 0x0000, 0x02ba, 0x0000, 0x02bc, 0x0000, 0x02be,
|
||||
// Entry 2C0 - 2FF
|
||||
0x0000, 0x02c0, 0x0000, 0x02c2, 0x02bf, 0x02bf, 0x0000, 0x0000,
|
||||
0x02c7, 0x02c6, 0x02c6, 0x0000, 0x0000, 0x02cc, 0x0000, 0x02ce,
|
||||
0x0000, 0x02d0, 0x0000, 0x0000, 0x02d3, 0x0000, 0x0000, 0x0000,
|
||||
0x02d7, 0x0000, 0x02d9, 0x0000, 0x02db, 0x0000, 0x02dd, 0x02dd,
|
||||
0x0000, 0x02e0, 0x0000, 0x02e2, 0x0000, 0x02e4, 0x02e4, 0x02e4,
|
||||
0x02e4, 0x02e4, 0x0000, 0x02ea, 0x02eb, 0x02ea, 0x0000, 0x02ee,
|
||||
} // Size: 1528 bytes
|
||||
0x02be, 0x0000, 0x0000, 0x02c2, 0x0000, 0x02c4, 0x02c1, 0x02c1,
|
||||
0x0000, 0x0000, 0x02c9, 0x02c8, 0x02c8, 0x0000, 0x0000, 0x02ce,
|
||||
0x0000, 0x02d0, 0x0000, 0x02d2, 0x0000, 0x0000, 0x02d5, 0x0000,
|
||||
0x0000, 0x0000, 0x02d9, 0x0000, 0x02db, 0x0000, 0x02dd, 0x0000,
|
||||
0x02df, 0x02df, 0x0000, 0x02e2, 0x0000, 0x02e4, 0x0000, 0x02e6,
|
||||
0x02e6, 0x02e6, 0x02e6, 0x02e6, 0x0000, 0x02ec, 0x02ed, 0x02ec,
|
||||
0x0000, 0x02f0,
|
||||
} // Size: 1532 bytes
|
||||
|
||||
// Total table size 1528 bytes (1KiB); checksum: B99CF952
|
||||
// Total table size 1532 bytes (1KiB); checksum: 90718A2
|
||||
|
||||
Reference in New Issue
Block a user