| // Copyright (C) 2015 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package atom |
| |
| import ( |
| "fmt" |
| "log" |
| "strings" |
| |
| "android.googlesource.com/platform/tools/gpu/binary" |
| "android.googlesource.com/platform/tools/gpu/interval" |
| ) |
| |
| // GroupList is a list of Groups. Functions in this package expect the list to |
| // be in ascending atom identifier order, and maintain that order on mutation. |
| type GroupList []Group |
| |
| func (l GroupList) info(depth int) string { |
| parts := make([]string, len(l)) |
| for i, group := range l { |
| parts[i] = fmt.Sprintf("%s%.5d: %s", |
| strings.Repeat(" ", depth), i, group.info(depth)) |
| } |
| return strings.Join(parts, "\n") |
| } |
| |
| // String returns a string representing all groups in the group list. |
| func (l GroupList) String() string { |
| return l.info(0) |
| } |
| |
| // IndexOf returns the index of the group that contains the atom identifier or |
| // -1 if not found. |
| func (l *GroupList) IndexOf(atomId Id) int { |
| return interval.IndexOf(l, uint64(atomId)) |
| } |
| |
| // Add inserts a new atom group into the list with the specified range and name. |
| // If the new group does not overlap any existing groups in the list then it is |
| // inserted into the list, keeping ascending atom-identifier order. |
| // If the new group sits completely within an existing group then this new group |
| // will be added to the existing group's sub-groups. |
| // If the new group completely wraps one or more existing groups in the list |
| // then these existing groups are added as sub-groups to the new group and then |
| // the new group is added to the list, keeping ascending atom-identifier order. |
| // If the new group partially overlaps any existing group then the function will |
| // panic. |
| func (l *GroupList) Add(start, end Id, name string) { |
| r := Range{start, end} |
| g := Group{Name: name, Range: r} |
| s, c := interval.Intersect(l, r.Span()) |
| if c == 0 { |
| // No overlaps, clean insertion |
| i := interval.Merge(l, g.Range.Span()) |
| (*l)[i].Name = g.Name |
| (*l)[i].SubGroups = g.SubGroups |
| } else { |
| // At least one overlap |
| first := (*l)[s] |
| last := (*l)[s+c-1] |
| sIn, eIn := first.Range.Contains(start), last.Range.Contains(end-1) |
| switch { |
| case c == 1 && sIn && eIn: |
| // New group fits entirely within an existing group. Add as subgroup. |
| first.SubGroups.Add(start, end, name) |
| (*l)[s] = first |
| case sIn && start != first.Range.Start: |
| log.Panicf("New group '%s' overlaps with existing group '%s'", g, first) |
| case eIn && end != last.Range.End: |
| log.Panicf("New group '%s' overlaps with existing group '%s'", g, last) |
| default: |
| // New group completely wraps one or more existing groups. Add the |
| // existing group(s) as subgroups to the new group, and add to the list. |
| g.SubGroups = append(g.SubGroups, (*l)[s:s+c]...) |
| i := interval.Merge(l, g.Range.Span()) |
| (*l)[i].Name = g.Name |
| (*l)[i].SubGroups = g.SubGroups |
| } |
| } |
| } |
| |
| // Length returns the number of groups in the list. |
| func (l GroupList) Length() int { |
| return len(l) |
| } |
| |
| // GetSpan returns the atom identifier span for the group at index in the list. |
| func (l GroupList) GetSpan(index int) interval.U64Span { |
| return l[index].Range.Span() |
| } |
| |
| // SetSpan sets the atom identifier span for the group at index in the list. |
| func (l GroupList) SetSpan(index int, span interval.U64Span) { |
| l[index].Range.SetSpan(span) |
| } |
| |
| // Copy copies count groups within the list. |
| func (l GroupList) Copy(to, from, count int) { |
| copy(l[to:to+count], l[from:from+count]) |
| } |
| |
| // Resize adjusts the length of the list. |
| func (l *GroupList) Resize(length int) { |
| if cap(*l) > length { |
| *l = (*l)[:length] |
| } else { |
| old := *l |
| capacity := cap(*l) * 2 |
| if capacity < length { |
| capacity = length |
| } |
| *l = make(GroupList, length, capacity) |
| copy(*l, old) |
| } |
| } |
| |
| // Encode encodes the Group using the specified encoder. |
| func (l GroupList) Encode(e *binary.Encoder) error { |
| if err := e.Uint32(uint32(l.Length())); err != nil { |
| return err |
| } |
| for _, s := range l { |
| if err := s.Encode(e); err != nil { |
| return err |
| } |
| } |
| return nil |
| } |
| |
| // Decode decodes the Group using the specified encoder. |
| func (l *GroupList) Decode(d *binary.Decoder) error { |
| if count, err := d.Uint32(); err == nil { |
| *l = make(GroupList, count) |
| for i := range *l { |
| if err := (*l)[i].Decode(d); err != nil { |
| return err |
| } |
| } |
| } else { |
| return err |
| } |
| return nil |
| } |