github.com/jgbaldwinbrown/perf@v0.1.1/benchproc/keyheader.go (about)

     1  // Copyright 2022 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 benchproc
     6  
     7  // A KeyHeader represents a slice of Keys, combined into a forest of
     8  // trees by common Field values. This is intended to visually present a
     9  // sequence of Keys in a compact form; primarily, as a header on a
    10  // table.
    11  //
    12  // All Keys must have the same Projection. The levels of the tree
    13  // correspond to the Fields of the Projection, and the depth of the tree
    14  // is exactly the number of Fields. A node at level i represents a
    15  // subslice of the Keys that all have the same values as each other for
    16  // fields 0 through i.
    17  //
    18  // For example, given four keys:
    19  //
    20  //	K[0] = a:1 b:1 c:1
    21  //	K[1] = a:1 b:1 c:2
    22  //	K[2] = a:2 b:2 c:2
    23  //	K[3] = a:2 b:3 c:3
    24  //
    25  // the KeyHeader is as follows:
    26  //
    27  //	Level 0      a:1         a:2
    28  //	              |         /   \
    29  //	Level 1      b:1      b:2   b:3
    30  //	            /   \      |     |
    31  //	Level 2   c:1   c:2   c:2   c:3
    32  //	          K[0]  K[1]  K[2]  K[3]
    33  type KeyHeader struct {
    34  	// Keys is the sequence of keys at the leaf level of this tree.
    35  	// Each level subdivides this sequence.
    36  	Keys []Key
    37  
    38  	// Levels are the labels for each level of the tree. Level i of the
    39  	// tree corresponds to the i'th field of all Keys.
    40  	Levels []*Field
    41  
    42  	// Top is the list of tree roots. These nodes are all at level 0.
    43  	Top []*KeyHeaderNode
    44  }
    45  
    46  // KeyHeaderNode is a node in a KeyHeader.
    47  type KeyHeaderNode struct {
    48  	// Field is the index into KeyHeader.Levels of the Field represented
    49  	// by this node. This is also the level of this node in the tree,
    50  	// starting with 0 at the top.
    51  	Field int
    52  
    53  	// Value is the value that all Keys have in common for Field.
    54  	Value string
    55  
    56  	// Start is the index of the first Key covered by this node.
    57  	Start int
    58  	// Len is the number of Keys in the sequence represented by this node.
    59  	// This is also the number of leaf nodes in the subtree at this node.
    60  	Len int
    61  
    62  	// Children are the children of this node. These are all at level Field+1.
    63  	// Child i+1 differs from child i in the value of field Field+1.
    64  	Children []*KeyHeaderNode
    65  }
    66  
    67  // NewKeyHeader computes the KeyHeader of a slice of Keys by combining
    68  // common prefixes of fields.
    69  func NewKeyHeader(keys []Key) *KeyHeader {
    70  	if len(keys) == 0 {
    71  		return &KeyHeader{}
    72  	}
    73  
    74  	fields := commonProjection(keys).FlattenedFields()
    75  
    76  	var walk func(parent *KeyHeaderNode)
    77  	walk = func(parent *KeyHeaderNode) {
    78  		level := parent.Field + 1
    79  		if level == len(fields) {
    80  			return
    81  		}
    82  		field := fields[level]
    83  		var node *KeyHeaderNode
    84  		for j, key := range keys[parent.Start : parent.Start+parent.Len] {
    85  			val := key.Get(field)
    86  			if node != nil && val == node.Value {
    87  				// Add this key to the current node.
    88  				node.Len++
    89  			} else {
    90  				// Start a new node.
    91  				node = &KeyHeaderNode{level, val, parent.Start + j, 1, nil}
    92  				parent.Children = append(parent.Children, node)
    93  			}
    94  		}
    95  		for _, child := range parent.Children {
    96  			walk(child)
    97  		}
    98  	}
    99  	root := &KeyHeaderNode{-1, "", 0, len(keys), nil}
   100  	walk(root)
   101  	return &KeyHeader{keys, fields, root.Children}
   102  }