LCOV - code coverage report
Current view: top level - pebble/metamorphic - diagram.go (source / functions) Hit Total Coverage
Test: 2024-04-09 08:16Z 278b6a67 - tests only.lcov Lines: 56 64 87.5 %
Date: 2024-04-09 08:16:41 Functions: 0 0 -

          Line data    Source code
       1             : // Copyright 2024 The LevelDB-Go and Pebble Authors. All rights reserved. Use
       2             : // of this source code is governed by a BSD-style license that can be found in
       3             : // the LICENSE file.
       4             : 
       5             : package metamorphic
       6             : 
       7             : import "strings"
       8             : 
       9             : // TryToGenerateDiagram attempts to generate a user-readable ASCII diagram of
      10             : // the keys involved in the operations.
      11             : //
      12             : // If the diagram would be too large to be practical, returns the empty string
      13             : // (with no error).
      14           1 : func TryToGenerateDiagram(opsData []byte) (string, error) {
      15           1 :         ops, err := parse(opsData, parserOpts{})
      16           1 :         if err != nil {
      17           0 :                 return "", err
      18           0 :         }
      19           1 :         if len(ops) > 200 {
      20           0 :                 return "", nil
      21           0 :         }
      22           1 :         keySet := make(map[string]struct{})
      23           1 :         for _, o := range ops {
      24           1 :                 for _, r := range o.diagramKeyRanges() {
      25           1 :                         keySet[string(r.Start)] = struct{}{}
      26           1 :                         keySet[string(r.End)] = struct{}{}
      27           1 :                 }
      28             :         }
      29           1 :         if len(keySet) == 0 {
      30           0 :                 return "", nil
      31           0 :         }
      32           1 :         keys := sortedKeys(keySet)
      33           1 :         axis1, axis2, pos := genAxis(keys)
      34           1 :         if len(axis1) > 200 {
      35           0 :                 return "", nil
      36           0 :         }
      37             : 
      38           1 :         var rows []string
      39           1 :         for _, o := range ops {
      40           1 :                 ranges := o.diagramKeyRanges()
      41           1 :                 var row strings.Builder
      42           1 :                 for _, r := range ranges {
      43           1 :                         s := pos[string(r.Start)]
      44           1 :                         e := pos[string(r.End)]
      45           1 :                         for row.Len() < s {
      46           1 :                                 row.WriteByte(' ')
      47           1 :                         }
      48           1 :                         row.WriteByte('|')
      49           1 :                         if e > s {
      50           1 :                                 for row.Len() < e {
      51           1 :                                         row.WriteByte('-')
      52           1 :                                 }
      53           1 :                                 row.WriteByte('|')
      54             :                         }
      55             :                 }
      56           1 :                 for row.Len() <= len(axis1) {
      57           1 :                         row.WriteByte(' ')
      58           1 :                 }
      59           1 :                 row.WriteString(o.String())
      60           1 : 
      61           1 :                 rows = append(rows, row.String())
      62             :         }
      63           1 :         rows = append(rows, axis1, axis2)
      64           1 :         return strings.Join(rows, "\n"), nil
      65             : }
      66             : 
      67             : // genAxis generates the horizontal key axis and returns two rows (one for axis
      68             : // one for labels), along with a map from key to column.
      69             : 
      70             : // Example:
      71             : //
      72             : //      axisRow:    |----|----|----|
      73             : //      labelRow:   a    bar  foo  zed
      74             : //      pos:        a:0, bar:5, foo:10, zed:15
      75           1 : func genAxis(keys []string) (axisRow string, labelRow string, pos map[string]int) {
      76           1 :         const minSpaceBetweenKeys = 4
      77           1 :         const minSpaceBetweenKeyLabels = 2
      78           1 :         var a, b strings.Builder
      79           1 :         pos = make(map[string]int)
      80           1 :         for i, k := range keys {
      81           1 :                 if i > 0 {
      82           1 :                         b.WriteString(strings.Repeat(" ", minSpaceBetweenKeyLabels))
      83           1 :                         for b.Len() <= a.Len()+minSpaceBetweenKeys {
      84           1 :                                 b.WriteByte(' ')
      85           1 :                         }
      86           1 :                         for a.Len() < b.Len() {
      87           1 :                                 a.WriteByte('-')
      88           1 :                         }
      89             :                 }
      90           1 :                 pos[k] = a.Len()
      91           1 :                 a.WriteByte('|')
      92           1 :                 b.WriteString(k)
      93             :         }
      94           1 :         return a.String(), b.String(), pos
      95             : }

Generated by: LCOV version 1.14