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  }