diff --git a/language/language.go b/language/language.go index 3c19041..5eecceb 100644 --- a/language/language.go +++ b/language/language.go @@ -593,7 +593,7 @@ func (t Tag) Extension(x byte) (ext Extension, ok bool) { return Extension{ext}, true } } - return Extension{string(x)}, false + return Extension{}, false } // Extensions returns all extensions of t. diff --git a/language/match.go b/language/match.go index eec72bc..8ad9505 100644 --- a/language/match.go +++ b/language/match.go @@ -396,8 +396,8 @@ type matcher struct { // matchHeader has the lists of tags for exact matches and matches based on // maximized and canonicalized tags for a given language. type matchHeader struct { - exact []haveTag - max []haveTag + exact []*haveTag + max []*haveTag } // haveTag holds a supported Tag and its maximized script and region. The maximized @@ -457,7 +457,7 @@ func (h *matchHeader) addIfNew(n haveTag, exact bool) { } } if exact { - h.exact = append(h.exact, n) + h.exact = append(h.exact, &n) } // Allow duplicate maximized tags, but create a linked list to allow quickly // comparing the equivalents and bail out. @@ -472,7 +472,7 @@ func (h *matchHeader) addIfNew(n haveTag, exact bool) { break } } - h.max = append(h.max, n) + h.max = append(h.max, &n) } // header returns the matchHeader for the given language. It creates one if @@ -503,7 +503,7 @@ func newMatcher(supported []Tag) *matcher { pair, _ := makeHaveTag(tag, i) m.header(tag.lang).addIfNew(pair, true) } - m.default_ = &m.header(supported[0].lang).exact[0] + m.default_ = m.header(supported[0].lang).exact[0] for i, tag := range supported { pair, max := makeHaveTag(tag, i) if max != tag.lang { @@ -520,7 +520,8 @@ func newMatcher(supported []Tag) *matcher { return } hw := m.header(langID(want)) - for _, v := range hh.max { + for _, ht := range hh.max { + v := *ht if conf < v.conf { v.conf = conf } @@ -580,7 +581,7 @@ func (m *matcher) getBest(want ...Tag) (got *haveTag, orig Tag, c Confidence) { continue } for i := range h.exact { - have := &h.exact[i] + have := h.exact[i] if have.tag.equalsRest(w) { return have, w, Exact } @@ -591,7 +592,7 @@ func (m *matcher) getBest(want ...Tag) (got *haveTag, orig Tag, c Confidence) { // Base language is not defined. if h != nil { for i := range h.exact { - have := &h.exact[i] + have := h.exact[i] if have.tag.equalsRest(w) { return have, w, Exact } @@ -609,11 +610,11 @@ func (m *matcher) getBest(want ...Tag) (got *haveTag, orig Tag, c Confidence) { } // Check for match based on maximized tag. for i := range h.max { - have := &h.max[i] + have := h.max[i] best.update(have, w, max.script, max.region) if best.conf == Exact { for have.nextMax != 0 { - have = &h.max[have.nextMax] + have = h.max[have.nextMax] best.update(have, w, max.script, max.region) } return best.have, best.want, High diff --git a/language/match_test.go b/language/match_test.go index 57b1644..9d87a09 100644 --- a/language/match_test.go +++ b/language/match_test.go @@ -10,6 +10,8 @@ import ( "fmt" "strings" "testing" + + "golang.org/x/text/internal/testtext" ) var verbose = flag.Bool("verbose", false, "set to true to print the internal tables of matchers") @@ -246,22 +248,23 @@ func (t haveTag) String() string { return fmt.Sprintf("%v:%d:%v:%v-%v|%v", t.tag, t.index, t.conf, t.maxRegion, t.maxScript, t.altScript) } +func parseSupported(list string) (out []Tag) { + for _, s := range strings.Split(list, ",") { + out = append(out, mk(strings.TrimSpace(s))) + } + return out +} + // The test set for TestBestMatch is defined in data_test.go. func TestBestMatch(t *testing.T) { - parse := func(list string) (out []Tag) { - for _, s := range strings.Split(list, ",") { - out = append(out, mk(strings.TrimSpace(s))) - } - return out - } for i, tt := range matchTests { - supported := parse(tt.supported) + supported := parseSupported(tt.supported) m := newMatcher(supported) if *verbose { fmt.Printf("%s:\n%v\n", tt.comment, m) } for _, tm := range tt.test { - tag, _, conf := m.Match(parse(tm.desired)...) + tag, _, conf := m.Match(parseSupported(tm.desired)...) if tag.String() != tm.match { t.Errorf("%d:%s: find %s in %q: have %s; want %s (%v)\n", i, tt.comment, tm.desired, tt.supported, tag, tm.match, conf) } @@ -269,6 +272,18 @@ func TestBestMatch(t *testing.T) { } } +func TestBestMatchAlloc(t *testing.T) { + m := NewMatcher(parseSupported("en sr nl")) + // Go allocates when creating a list of tags from a single tag! + list := []Tag{English} + avg := testtext.AllocsPerRun(1, func() { + m.Match(list...) + }) + if avg > 0 { + t.Errorf("got %f; want 0", avg) + } +} + var benchHave = []Tag{ mk("en"), mk("en-GB"),