| // Copyright 2022 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 benchproc | |
| // A KeyHeader represents a slice of Keys, combined into a forest of | |
| // trees by common Field values. This is intended to visually present a | |
| // sequence of Keys in a compact form; primarily, as a header on a | |
| // table. | |
| // | |
| // All Keys must have the same Projection. The levels of the tree | |
| // correspond to the Fields of the Projection, and the depth of the tree | |
| // is exactly the number of Fields. A node at level i represents a | |
| // subslice of the Keys that all have the same values as each other for | |
| // fields 0 through i. | |
| // | |
| // For example, given four keys: | |
| // | |
| // K[0] = a:1 b:1 c:1 | |
| // K[1] = a:1 b:1 c:2 | |
| // K[2] = a:2 b:2 c:2 | |
| // K[3] = a:2 b:3 c:3 | |
| // | |
| // the KeyHeader is as follows: | |
| // | |
| // Level 0 a:1 a:2 | |
| // | / \ | |
| // Level 1 b:1 b:2 b:3 | |
| // / \ | | | |
| // Level 2 c:1 c:2 c:2 c:3 | |
| // K[0] K[1] K[2] K[3] | |
| type KeyHeader struct { | |
| // Keys is the sequence of keys at the leaf level of this tree. | |
| // Each level subdivides this sequence. | |
| Keys []Key | |
| // Levels are the labels for each level of the tree. Level i of the | |
| // tree corresponds to the i'th field of all Keys. | |
| Levels []*Field | |
| // Top is the list of tree roots. These nodes are all at level 0. | |
| Top []*KeyHeaderNode | |
| } | |
| // KeyHeaderNode is a node in a KeyHeader. | |
| type KeyHeaderNode struct { | |
| // Field is the index into KeyHeader.Levels of the Field represented | |
| // by this node. This is also the level of this node in the tree, | |
| // starting with 0 at the top. | |
| Field int | |
| // Value is the value that all Keys have in common for Field. | |
| Value string | |
| // Start is the index of the first Key covered by this node. | |
| Start int | |
| // Len is the number of Keys in the sequence represented by this node. | |
| // This is also the number of leaf nodes in the subtree at this node. | |
| Len int | |
| // Children are the children of this node. These are all at level Field+1. | |
| // Child i+1 differs from child i in the value of field Field+1. | |
| Children []*KeyHeaderNode | |
| } | |
| // NewKeyHeader computes the KeyHeader of a slice of Keys by combining | |
| // common prefixes of fields. | |
| func NewKeyHeader(keys []Key) *KeyHeader { | |
| if len(keys) == 0 { | |
| return &KeyHeader{} | |
| } | |
| fields := commonProjection(keys).FlattenedFields() | |
| var walk func(parent *KeyHeaderNode) | |
| walk = func(parent *KeyHeaderNode) { | |
| level := parent.Field + 1 | |
| if level == len(fields) { | |
| return | |
| } | |
| field := fields[level] | |
| var node *KeyHeaderNode | |
| for j, key := range keys[parent.Start : parent.Start+parent.Len] { | |
| val := key.Get(field) | |
| if node != nil && val == node.Value { | |
| // Add this key to the current node. | |
| node.Len++ | |
| } else { | |
| // Start a new node. | |
| node = &KeyHeaderNode{level, val, parent.Start + j, 1, nil} | |
| parent.Children = append(parent.Children, node) | |
| } | |
| } | |
| for _, child := range parent.Children { | |
| walk(child) | |
| } | |
| } | |
| root := &KeyHeaderNode{-1, "", 0, len(keys), nil} | |
| walk(root) | |
| return &KeyHeader{keys, fields, root.Children} | |
| } |