You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

144 lines
4.0 KiB

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