1// Copyright 2012 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package main
6
7import (
8	"log"
9	"unicode/utf16"
10
11	"golang.org/x/text/collate"
12	"golang.org/x/text/language"
13)
14
15// Input holds an input string in both UTF-8 and UTF-16 format.
16type Input struct {
17	index int // used for restoring to original random order
18	UTF8  []byte
19	UTF16 []uint16
20	key   []byte // used for sorting
21}
22
23func (i Input) String() string {
24	return string(i.UTF8)
25}
26
27func makeInput(s8 []byte, s16 []uint16) Input {
28	return Input{UTF8: s8, UTF16: s16}
29}
30
31func makeInputString(s string) Input {
32	return Input{
33		UTF8:  []byte(s),
34		UTF16: utf16.Encode([]rune(s)),
35	}
36}
37
38// Collator is an interface for architecture-specific implementations of collation.
39type Collator interface {
40	// Key generates a sort key for the given input.  Implemenations
41	// may return nil if a collator does not support sort keys.
42	Key(s Input) []byte
43
44	// Compare returns -1 if a < b, 1 if a > b and 0 if a == b.
45	Compare(a, b Input) int
46}
47
48// CollatorFactory creates a Collator for a given language tag.
49type CollatorFactory struct {
50	name        string
51	makeFn      func(tag string) (Collator, error)
52	description string
53}
54
55var collators = []CollatorFactory{}
56
57// AddFactory registers f as a factory for an implementation of Collator.
58func AddFactory(f CollatorFactory) {
59	collators = append(collators, f)
60}
61
62func getCollator(name, locale string) Collator {
63	for _, f := range collators {
64		if f.name == name {
65			col, err := f.makeFn(locale)
66			if err != nil {
67				log.Fatal(err)
68			}
69			return col
70		}
71	}
72	log.Fatalf("collator of type %q not found", name)
73	return nil
74}
75
76// goCollator is an implemention of Collator using go's own collator.
77type goCollator struct {
78	c   *collate.Collator
79	buf collate.Buffer
80}
81
82func init() {
83	AddFactory(CollatorFactory{"go", newGoCollator, "Go's native collator implementation."})
84}
85
86func newGoCollator(loc string) (Collator, error) {
87	c := &goCollator{c: collate.New(language.Make(loc))}
88	return c, nil
89}
90
91func (c *goCollator) Key(b Input) []byte {
92	return c.c.Key(&c.buf, b.UTF8)
93}
94
95func (c *goCollator) Compare(a, b Input) int {
96	return c.c.Compare(a.UTF8, b.UTF8)
97}
98