blob: 5046caf78fefaf0f579f2cbcdc6fe1c05ba6fe98 [file] [log] [blame]
// 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
}