5849898283
Unit tests functional and coverage back to 100% Add more routes to dictionary, add more credentials, add default port 5554, rename cameradar logs ENV variable, improve unit test readability, remove tmp file
145 lines
4.0 KiB
Go
145 lines
4.0 KiB
Go
// 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):])
|
|
}
|