github.com/wrgl/wrgl@v0.14.0/pkg/widgets/prof/stat_diff_table.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright © 2022 Wrangle Ltd 3 4 package widgetsprof 5 6 import ( 7 "fmt" 8 "sort" 9 10 "github.com/rivo/tview" 11 diffprof "github.com/wrgl/wrgl/pkg/diff/prof" 12 "github.com/wrgl/wrgl/pkg/widgets" 13 ) 14 15 type StatDiffTable struct { 16 *widgets.SelectableTable 17 pool *widgets.CellsPool 18 tpd *diffprof.TableProfileDiff 19 diffCells [][]StatDiffCells 20 rowsPerStat []int 21 statNames []string 22 } 23 24 func NewStatDiffTable(tpd *diffprof.TableProfileDiff) (*StatDiffTable, error) { 25 t := &StatDiffTable{ 26 SelectableTable: widgets.NewSelectableTable(), 27 tpd: tpd, 28 } 29 t.SelectableTable.SetGetCellsFunc(t.getCells). 30 SetMinSelection(1, 1). 31 Select(1, 1, 0) 32 totalRows, err := t.calculateRowsCount() 33 if err != nil { 34 return nil, err 35 } 36 t.VirtualTable.SetFixed(1, 1). 37 SetShape(totalRows+1, len(tpd.Columns)+1). 38 SetSeparator('│') 39 t.pool = widgets.NewCellsPool(t.VirtualTable) 40 return t, nil 41 } 42 43 func (t *StatDiffTable) calculateRowsCount() (int, error) { 44 rows := map[string]int{} 45 diffCells := map[string]map[int]StatDiffCells{} 46 for i, col := range t.tpd.Columns { 47 for _, stat := range col.Stats { 48 var sdc StatDiffCells 49 switch v := stat.(type) { 50 case *diffprof.Uint16Stat: 51 sdc = &uint16StatDiffCells{v} 52 case *diffprof.Uint32Stat: 53 sdc = &uint32StatDiffCells{v} 54 case *diffprof.Float64Stat: 55 sdc = &float64StatDiffCells{v} 56 case *diffprof.TopValuesStat: 57 sdc = &topValuesStatDiffCells{v} 58 case *diffprof.PercentilesStat: 59 sdc = &percentilesStatDiffCells{v} 60 default: 61 return 0, fmt.Errorf("unanticipated type %T", v) 62 } 63 if c, ok := rows[sdc.Name()]; !ok || c < sdc.NumRows() { 64 rows[sdc.Name()] = sdc.NumRows() 65 if !ok { 66 t.statNames = append(t.statNames, sdc.Name()) 67 } 68 } 69 if _, ok := diffCells[sdc.Name()]; !ok { 70 diffCells[sdc.Name()] = map[int]StatDiffCells{} 71 } 72 diffCells[sdc.Name()][i] = sdc 73 } 74 } 75 totalRows := 0 76 sort.Slice(t.statNames, func(i, j int) bool { 77 if t.statNames[i] == "Top values" { 78 return false 79 } 80 if t.statNames[j] == "Top values" { 81 return true 82 } 83 if t.statNames[i] == "Percentiles" { 84 return false 85 } 86 if t.statNames[j] == "Percentiles" { 87 return true 88 } 89 if t.statNames[i] == "NA count" { 90 return true 91 } 92 if t.statNames[j] == "NA count" { 93 return false 94 } 95 return i < j 96 }) 97 for _, name := range t.statNames { 98 n := len(t.diffCells) 99 t.diffCells = append(t.diffCells, make([]StatDiffCells, len(t.tpd.Columns))) 100 for i, sdc := range diffCells[name] { 101 t.diffCells[n][i] = sdc 102 } 103 totalRows += rows[name] 104 t.rowsPerStat = append(t.rowsPerStat, rows[name]) 105 } 106 return totalRows, nil 107 } 108 109 func (t *StatDiffTable) getCells(row, column int) []*widgets.TableCell { 110 if row == 0 { 111 if column == 0 { 112 return nil 113 } 114 cells, ok := t.pool.Get(row, column, 1) 115 if !ok { 116 cells[0].SetText(t.tpd.Columns[column-1].Name). 117 SetStyle(columnStyle). 118 SetAlign(tview.AlignCenter) 119 } 120 return cells 121 } 122 sum := 0 123 // var sc StatDiffCells 124 var statRow int 125 var statInd int 126 for i, rowsCount := range t.rowsPerStat { 127 sum += rowsCount 128 if sum > row-1 { 129 // sc = t.diffCells[i][column-1] 130 statInd = i 131 statRow = row - 1 - sum + rowsCount 132 break 133 } 134 } 135 if column == 0 { 136 cells, ok := t.pool.Get(row, column, 1) 137 if !ok && statRow == 0 { 138 cells[0].SetText(t.statNames[statInd]).SetStyle(statNameStyle) 139 } 140 return cells 141 } 142 sc := t.diffCells[statInd][column-1] 143 if sc != nil { 144 cells, ok := t.pool.Get(row, column, sc.NumColumns()) 145 if !ok && statRow < sc.NumRows() { 146 sc.DecorateCells(statRow, cells) 147 } 148 return cells 149 } 150 cells, _ := t.pool.Get(row, column, 1) 151 return cells 152 }