OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / text / unicode / cldr / slice.go
1 // Copyright 2013 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
5 package cldr
6
7 import (
8         "fmt"
9         "reflect"
10         "sort"
11 )
12
13 // Slice provides utilities for modifying slices of elements.
14 // It can be wrapped around any slice of which the element type implements
15 // interface Elem.
16 type Slice struct {
17         ptr reflect.Value
18         typ reflect.Type
19 }
20
21 // Value returns the reflect.Value of the underlying slice.
22 func (s *Slice) Value() reflect.Value {
23         return s.ptr.Elem()
24 }
25
26 // MakeSlice wraps a pointer to a slice of Elems.
27 // It replaces the array pointed to by the slice so that subsequent modifications
28 // do not alter the data in a CLDR type.
29 // It panics if an incorrect type is passed.
30 func MakeSlice(slicePtr interface{}) Slice {
31         ptr := reflect.ValueOf(slicePtr)
32         if ptr.Kind() != reflect.Ptr {
33                 panic(fmt.Sprintf("MakeSlice: argument must be pointer to slice, found %v", ptr.Type()))
34         }
35         sl := ptr.Elem()
36         if sl.Kind() != reflect.Slice {
37                 panic(fmt.Sprintf("MakeSlice: argument must point to a slice, found %v", sl.Type()))
38         }
39         intf := reflect.TypeOf((*Elem)(nil)).Elem()
40         if !sl.Type().Elem().Implements(intf) {
41                 panic(fmt.Sprintf("MakeSlice: element type of slice (%v) does not implement Elem", sl.Type().Elem()))
42         }
43         nsl := reflect.MakeSlice(sl.Type(), sl.Len(), sl.Len())
44         reflect.Copy(nsl, sl)
45         sl.Set(nsl)
46         return Slice{
47                 ptr: ptr,
48                 typ: sl.Type().Elem().Elem(),
49         }
50 }
51
52 func (s Slice) indexForAttr(a string) []int {
53         for i := iter(reflect.Zero(s.typ)); !i.done(); i.next() {
54                 if n, _ := xmlName(i.field()); n == a {
55                         return i.index
56                 }
57         }
58         panic(fmt.Sprintf("MakeSlice: no attribute %q for type %v", a, s.typ))
59 }
60
61 // Filter filters s to only include elements for which fn returns true.
62 func (s Slice) Filter(fn func(e Elem) bool) {
63         k := 0
64         sl := s.Value()
65         for i := 0; i < sl.Len(); i++ {
66                 vi := sl.Index(i)
67                 if fn(vi.Interface().(Elem)) {
68                         sl.Index(k).Set(vi)
69                         k++
70                 }
71         }
72         sl.Set(sl.Slice(0, k))
73 }
74
75 // Group finds elements in s for which fn returns the same value and groups
76 // them in a new Slice.
77 func (s Slice) Group(fn func(e Elem) string) []Slice {
78         m := make(map[string][]reflect.Value)
79         sl := s.Value()
80         for i := 0; i < sl.Len(); i++ {
81                 vi := sl.Index(i)
82                 key := fn(vi.Interface().(Elem))
83                 m[key] = append(m[key], vi)
84         }
85         keys := []string{}
86         for k, _ := range m {
87                 keys = append(keys, k)
88         }
89         sort.Strings(keys)
90         res := []Slice{}
91         for _, k := range keys {
92                 nsl := reflect.New(sl.Type())
93                 nsl.Elem().Set(reflect.Append(nsl.Elem(), m[k]...))
94                 res = append(res, MakeSlice(nsl.Interface()))
95         }
96         return res
97 }
98
99 // SelectAnyOf filters s to contain only elements for which attr matches
100 // any of the values.
101 func (s Slice) SelectAnyOf(attr string, values ...string) {
102         index := s.indexForAttr(attr)
103         s.Filter(func(e Elem) bool {
104                 vf := reflect.ValueOf(e).Elem().FieldByIndex(index)
105                 return in(values, vf.String())
106         })
107 }
108
109 // SelectOnePerGroup filters s to include at most one element e per group of
110 // elements matching Key(attr), where e has an attribute a that matches any
111 // the values in v.
112 // If more than one element in a group matches a value in v preference
113 // is given to the element that matches the first value in v.
114 func (s Slice) SelectOnePerGroup(a string, v []string) {
115         index := s.indexForAttr(a)
116         grouped := s.Group(func(e Elem) string { return Key(e, a) })
117         sl := s.Value()
118         sl.Set(sl.Slice(0, 0))
119         for _, g := range grouped {
120                 e := reflect.Value{}
121                 found := len(v)
122                 gsl := g.Value()
123                 for i := 0; i < gsl.Len(); i++ {
124                         vi := gsl.Index(i).Elem().FieldByIndex(index)
125                         j := 0
126                         for ; j < len(v) && v[j] != vi.String(); j++ {
127                         }
128                         if j < found {
129                                 found = j
130                                 e = gsl.Index(i)
131                         }
132                 }
133                 if found < len(v) {
134                         sl.Set(reflect.Append(sl, e))
135                 }
136         }
137 }
138
139 // SelectDraft drops all elements from the list with a draft level smaller than d
140 // and selects the highest draft level of the remaining.
141 // This method assumes that the input CLDR is canonicalized.
142 func (s Slice) SelectDraft(d Draft) {
143         s.SelectOnePerGroup("draft", drafts[len(drafts)-2-int(d):])
144 }