barometer: update DMA's vendoring packages
[barometer.git] / src / dma / vendor / golang.org / x / text / unicode / cldr / slice.go
diff --git a/src/dma/vendor/golang.org/x/text/unicode/cldr/slice.go b/src/dma/vendor/golang.org/x/text/unicode/cldr/slice.go
new file mode 100644 (file)
index 0000000..388c983
--- /dev/null
@@ -0,0 +1,144 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cldr
+
+import (
+       "fmt"
+       "reflect"
+       "sort"
+)
+
+// Slice provides utilities for modifying slices of elements.
+// It can be wrapped around any slice of which the element type implements
+// interface Elem.
+type Slice struct {
+       ptr reflect.Value
+       typ reflect.Type
+}
+
+// Value returns the reflect.Value of the underlying slice.
+func (s *Slice) Value() reflect.Value {
+       return s.ptr.Elem()
+}
+
+// MakeSlice wraps a pointer to a slice of Elems.
+// It replaces the array pointed to by the slice so that subsequent modifications
+// do not alter the data in a CLDR type.
+// It panics if an incorrect type is passed.
+func MakeSlice(slicePtr interface{}) Slice {
+       ptr := reflect.ValueOf(slicePtr)
+       if ptr.Kind() != reflect.Ptr {
+               panic(fmt.Sprintf("MakeSlice: argument must be pointer to slice, found %v", ptr.Type()))
+       }
+       sl := ptr.Elem()
+       if sl.Kind() != reflect.Slice {
+               panic(fmt.Sprintf("MakeSlice: argument must point to a slice, found %v", sl.Type()))
+       }
+       intf := reflect.TypeOf((*Elem)(nil)).Elem()
+       if !sl.Type().Elem().Implements(intf) {
+               panic(fmt.Sprintf("MakeSlice: element type of slice (%v) does not implement Elem", sl.Type().Elem()))
+       }
+       nsl := reflect.MakeSlice(sl.Type(), sl.Len(), sl.Len())
+       reflect.Copy(nsl, sl)
+       sl.Set(nsl)
+       return Slice{
+               ptr: ptr,
+               typ: sl.Type().Elem().Elem(),
+       }
+}
+
+func (s Slice) indexForAttr(a string) []int {
+       for i := iter(reflect.Zero(s.typ)); !i.done(); i.next() {
+               if n, _ := xmlName(i.field()); n == a {
+                       return i.index
+               }
+       }
+       panic(fmt.Sprintf("MakeSlice: no attribute %q for type %v", a, s.typ))
+}
+
+// Filter filters s to only include elements for which fn returns true.
+func (s Slice) Filter(fn func(e Elem) bool) {
+       k := 0
+       sl := s.Value()
+       for i := 0; i < sl.Len(); i++ {
+               vi := sl.Index(i)
+               if fn(vi.Interface().(Elem)) {
+                       sl.Index(k).Set(vi)
+                       k++
+               }
+       }
+       sl.Set(sl.Slice(0, k))
+}
+
+// Group finds elements in s for which fn returns the same value and groups
+// them in a new Slice.
+func (s Slice) Group(fn func(e Elem) string) []Slice {
+       m := make(map[string][]reflect.Value)
+       sl := s.Value()
+       for i := 0; i < sl.Len(); i++ {
+               vi := sl.Index(i)
+               key := fn(vi.Interface().(Elem))
+               m[key] = append(m[key], vi)
+       }
+       keys := []string{}
+       for k, _ := range m {
+               keys = append(keys, k)
+       }
+       sort.Strings(keys)
+       res := []Slice{}
+       for _, k := range keys {
+               nsl := reflect.New(sl.Type())
+               nsl.Elem().Set(reflect.Append(nsl.Elem(), m[k]...))
+               res = append(res, MakeSlice(nsl.Interface()))
+       }
+       return res
+}
+
+// SelectAnyOf filters s to contain only elements for which attr matches
+// any of the values.
+func (s Slice) SelectAnyOf(attr string, values ...string) {
+       index := s.indexForAttr(attr)
+       s.Filter(func(e Elem) bool {
+               vf := reflect.ValueOf(e).Elem().FieldByIndex(index)
+               return in(values, vf.String())
+       })
+}
+
+// SelectOnePerGroup filters s to include at most one element e per group of
+// elements matching Key(attr), where e has an attribute a that matches any
+// the values in v.
+// If more than one element in a group matches a value in v preference
+// is given to the element that matches the first value in v.
+func (s Slice) SelectOnePerGroup(a string, v []string) {
+       index := s.indexForAttr(a)
+       grouped := s.Group(func(e Elem) string { return Key(e, a) })
+       sl := s.Value()
+       sl.Set(sl.Slice(0, 0))
+       for _, g := range grouped {
+               e := reflect.Value{}
+               found := len(v)
+               gsl := g.Value()
+               for i := 0; i < gsl.Len(); i++ {
+                       vi := gsl.Index(i).Elem().FieldByIndex(index)
+                       j := 0
+                       for ; j < len(v) && v[j] != vi.String(); j++ {
+                       }
+                       if j < found {
+                               found = j
+                               e = gsl.Index(i)
+                       }
+               }
+               if found < len(v) {
+                       sl.Set(reflect.Append(sl, e))
+               }
+       }
+}
+
+// SelectDraft drops all elements from the list with a draft level smaller than d
+// and selects the highest draft level of the remaining.
+// This method assumes that the input CLDR is canonicalized.
+func (s Slice) SelectDraft(d Draft) {
+       s.SelectOnePerGroup("draft", drafts[len(drafts)-2-int(d):])
+}