spreadsheet: add fast paths for appending rows/cells

This commit is contained in:
Todd 2017-09-15 16:44:42 -05:00
parent 382c157c11
commit 9b89ae1f12
3 changed files with 67 additions and 12 deletions

View File

@ -61,20 +61,34 @@ func (r Row) SetHidden(hidden bool) {
// AddCell adds a cell to a spreadsheet.
func (r Row) AddCell() Cell {
c := spreadsheetml.NewCT_Cell()
c.TAttr = spreadsheetml.ST_CellTypeN
r.x.C = append(r.x.C, c)
nextIdx := uint32(0)
for _, c := range r.x.C {
if c.RAttr != nil {
col, _, _ := ParseCellReference(*c.RAttr)
if col := ColumnToIndex(col); col >= nextIdx {
nextIdx = col + 1
}
numCells := uint32(len(r.x.C))
var nextCellID *string
if numCells > 0 {
prevCellName := gooxml.Stringf("%s%d", IndexToColumn(numCells-1), r.RowNumber())
// previous cell has an expected name
if r.x.C[numCells-1].RAttr != nil && *r.x.C[numCells-1].RAttr == *prevCellName {
nextCellID = gooxml.Stringf("%s%d", IndexToColumn(numCells), r.RowNumber())
}
}
c.RAttr = gooxml.Stringf("%s%d", IndexToColumn(nextIdx), r.RowNumber())
c := spreadsheetml.NewCT_Cell()
c.TAttr = spreadsheetml.ST_CellTypeN
r.x.C = append(r.x.C, c)
// fast path failed, so find the last cell and add another
if nextCellID == nil {
nextIdx := uint32(0)
for _, c := range r.x.C {
if c.RAttr != nil {
col, _, _ := ParseCellReference(*c.RAttr)
if col := ColumnToIndex(col); col >= nextIdx {
nextIdx = col + 1
}
}
}
nextCellID = gooxml.Stringf("%s%d", IndexToColumn(nextIdx), r.RowNumber())
}
c.RAttr = nextCellID
return Cell{r.w, r.s, r.x, c}
}

View File

@ -80,11 +80,27 @@ func (s Sheet) AddNumberedRow(rowNum uint32) Row {
return Row{s.w, s.x, r}
}
// addNumberedRowFast is a fast path that can be used when adding consecutive
// rows and not skipping any.
func (s Sheet) addNumberedRowFast(rowNum uint32) Row {
r := sml.NewCT_Row()
r.RAttr = gooxml.Uint32(rowNum)
s.x.SheetData.Row = append(s.x.SheetData.Row, r)
return Row{s.w, s.x, r}
}
// AddRow adds a new row to a sheet. You can mix this with numbered rows,
// however it will get confusing. You should prefer to use either automatically
// numbered rows with AddRow or manually numbered rows with Row/AddNumberedRow
func (s Sheet) AddRow() Row {
maxRowID := uint32(0)
numRows := uint32(len(s.x.SheetData.Row))
// fast path, adding consecutive rows
if numRows > 0 && s.x.SheetData.Row[numRows-1].RAttr != nil && *s.x.SheetData.Row[numRows-1].RAttr == numRows {
return s.addNumberedRowFast(numRows + 1)
}
// find the max row number
for _, r := range s.x.SheetData.Row {
if r.RAttr != nil && *r.RAttr > maxRowID {

View File

@ -0,0 +1,25 @@
package spreadsheet_test
import (
"testing"
"baliance.com/gooxml/spreadsheet"
)
func BenchmarkAddRow(b *testing.B) {
ss := spreadsheet.New()
sheet := ss.AddSheet()
for r := 0; r < b.N; r++ {
sheet.AddRow()
}
}
func BenchmarkAddCell(b *testing.B) {
ss := spreadsheet.New()
sheet := ss.AddSheet()
row := sheet.AddRow()
for c := 0; c < b.N; c++ {
row.AddCell()
}
}