github.com/go-xe2/third@v1.0.3/golang.org/x/text/unicode/cldr/slice.go (about) 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 }