Four lines of two bits each keep Style at eight bytes; with four bytes of borders a Cell grew to 264 bytes and into the 288-byte size class, which cost every formula cell and every entry typed 32 bytes more.
- commit
- 3fd4dc903960cee7be21f4ffbe031f88efe4a8d6
- parent
- a18133cab31326de2b142dd781ab32c5b89910bd
- author
- Dami <dami.etoile@gmail.com>
- kind
- refactor risk score 2.4 of 3, Jev's estimate
| M | internal/ | 11 | +----- |
| M | internal/ | 20 | +++++------ |
| M | internal/ | 4 | +- |
| M | internal/ | 2 | +- |
| M | internal/ | 52 | ++++++++++++++++++++++-------- |
| M | internal/ | 13 | +++----- |
| M | internal/ | 14 | ++++---- |
| M | internal/ | 8 | ++-- |
| M | internal/ | 2 | +- |
@@ -376,15 +376,8 @@ func excelizeStyleOf(x *excelize.File, id int, cache map[int]xlsxStyle) xlsxStyl
376376 if br.Style > 0 && br.Style < len(excelizeBorderStyles) {377377 l = borderLine(excelizeBorderStyles[br.Style])378378 }379- switch br.Type {380- case "left":381- out.style.Borders.Left = l382- case "right":383- out.style.Borders.Right = l384- case "top":385- out.style.Borders.Top = l386- case "bottom":387- out.style.Borders.Bottom = l379+ if e, ok := xlsxEdges[br.Type]; ok {380+ out.style.Borders = out.style.Borders.With(e, l)388381 }389382 }390383 if al := st.Alignment; al != nil {@@ -50,6 +50,12 @@ func excelBorderStyle(l sheet.Line) string {
5050 return "thin"5151 }5252 53+// xlsxEdges are a <border>'s elements for each edge; start and end are54+// left and right in left-to-right sheets.55+var xlsxEdges = map[string]sheet.Edge{56+ "top": sheet.EdgeTop, "bottom": sheet.EdgeBottom, "left": sheet.EdgeLeft, "start": sheet.EdgeLeft, "right": sheet.EdgeRight, "end": sheet.EdgeRight,57+}58+5359 // readBorder reads the rest of a <border>: its four edges.5460 func readBorder(x *xmlStream) (sheet.Borders, error) {5561 var b sheet.Borders@@ -64,16 +70,8 @@ func readBorder(x *xmlStream) (sheet.Borders, error) {
6470 if x.depth != depth+1 {6571 continue6672 }67- l := borderLine(attrOr(t, "style", ""))68- switch t.Name.Local {69- case "top":70- b.Top = l71- case "bottom":72- b.Bottom = l73- case "left", "start":74- b.Left = l75- case "right", "end":76- b.Right = l73+ if e, ok := xlsxEdges[t.Name.Local]; ok {74+ b = b.With(e, borderLine(attrOr(t, "style", "")))7775 }7876 case xml.EndElement:7977 if x.depth < depth {@@ -101,7 +99,7 @@ func (t *xlsxStyleTable) bordersXML() string {
10199 for _, e := range [...]struct {102100 tag string103101 l sheet.Line104- }{{"left", br.Left}, {"right", br.Right}, {"top", br.Top}, {"bottom", br.Bottom}} {102+ }{{"left", br.Left()}, {"right", br.Right()}, {"top", br.Top()}, {"bottom", br.Bottom()}} {105103 if e.l == sheet.LineNone {106104 fmt.Fprintf(&b, `<%s/>`, e.tag)107105 continue@@ -94,11 +94,11 @@ func TestXLSXLayoutImport(t *testing.T) {
9494 t.Fatal(err)9595 }9696 s := res.Sheet97- want := sheet.Borders{Left: sheet.LineThin, Right: sheet.LineThick, Top: sheet.LineDouble, Bottom: sheet.LineThick}97+ want := sheet.BordersOf(sheet.LineDouble, sheet.LineThick, sheet.LineThin, sheet.LineThick)9898 if got := s.CellStyle(addr(t, "A1")).Borders; got != want {9999 t.Errorf("A1 borders %+v, want %+v", got, want)100100 }101- if got := s.CellStyle(addr(t, "B1")).Borders.Left; got != sheet.LineThin {101+ if got := s.CellStyle(addr(t, "B1")).Borders.Left(); got != sheet.LineThin {102102 t.Errorf("a blank cell's border after the row's values: %v", got)103103 }104104 if s.CellStyle(addr(t, "A2")).Wrap != sheet.WrapOn {@@ -336,7 +336,7 @@ func (t *xlsxStyleTable) dxfsXML() string {
336336 }337337 338338 func newXLSXStyleTable() *xlsxStyleTable {339- return &xlsxStyleTable{ids: map[xlsxStyle]int{{}: 0}, xfs: []xlsxStyle{{}}, fonts: []sheet.Style{{}}, borders: []sheet.Borders{{}}}339+ return &xlsxStyleTable{ids: map[xlsxStyle]int{{}: 0}, xfs: []xlsxStyle{{}}, fonts: []sheet.Style{{}}, borders: []sheet.Borders{0}}340340 }341341 342342 // id is the index of the cell format for f and st.@@ -41,13 +41,40 @@ func ParseLine(s string) (Line, bool) {
4141 // thin.4242 func Heavier(a, b Line) Line { return max(a, b) }4343 44-// Borders are the lines on a cell's four edges.45-type Borders struct {46- Top, Bottom, Left, Right Line44+// Borders are the lines on a cell's four edges, two bits each, so a45+// style stays eight bytes and a cell fits its allocation size class.46+type Borders uint847+48+// Edge is one of a cell's edges.49+type Edge uint850+51+const (52+ EdgeTop Edge = iota53+ EdgeBottom54+ EdgeLeft55+ EdgeRight56+)57+58+// BordersOf is the borders with these lines.59+func BordersOf(top, bottom, left, right Line) Borders {60+ return Borders(0).With(EdgeTop, top).With(EdgeBottom, bottom).With(EdgeLeft, left).With(EdgeRight, right)4761 }4862 63+// Line is the line on edge e.64+func (b Borders) Line(e Edge) Line { return Line(b >> (2 * e) & 3) }65+66+// With is b with edge e drawn with l.67+func (b Borders) With(e Edge, l Line) Borders {68+ return b&^(3<<(2*e)) | Borders(l&3)<<(2*e)69+}70+71+func (b Borders) Top() Line { return b.Line(EdgeTop) }72+func (b Borders) Bottom() Line { return b.Line(EdgeBottom) }73+func (b Borders) Left() Line { return b.Line(EdgeLeft) }74+func (b Borders) Right() Line { return b.Line(EdgeRight) }75+4976 // IsZero reports whether no edge has a line.50-func (b Borders) IsZero() bool { return b == Borders{} }77+func (b Borders) IsZero() bool { return b == 0 }5178 5279 // BorderKind is which edges of a range Format > Borders sets.5380 type BorderKind uint8@@ -117,12 +144,9 @@ func (k BorderKind) edges(r Rect, a Addr) edgeSet {
117144 118145 // apply sets the edges of e on b to l.119146 func (e edgeSet) apply(b *Borders, l Line) {120- for _, on := range [...]struct {121- set bool122- edge *Line123- }{{e.top, &b.Top}, {e.bottom, &b.Bottom}, {e.left, &b.Left}, {e.right, &b.Right}} {124- if on.set {125- *on.edge = l147+ for edge, set := range [...]bool{EdgeTop: e.top, EdgeBottom: e.bottom, EdgeLeft: e.left, EdgeRight: e.right} {148+ if set {149+ *b = b.With(Edge(edge), l)126150 }127151 }128152 }@@ -173,9 +197,9 @@ func (s *Sheet) clearFacing(r Rect, k BorderKind) {
173197 // EdgeAbove is the line on the edge between the cell at a and the one174198 // above it: the heavier of their facing lines.175199 func (s *Sheet) EdgeAbove(a Addr) Line {176- l := s.CellStyle(a).Borders.Top200+ l := s.CellStyle(a).Borders.Top()177201 if a.Row > 0 {178- l = Heavier(l, s.CellStyle(Addr{Col: a.Col, Row: a.Row - 1}).Borders.Bottom)202+ l = Heavier(l, s.CellStyle(Addr{Col: a.Col, Row: a.Row - 1}).Borders.Bottom())179203 }180204 return l181205 }@@ -183,9 +207,9 @@ func (s *Sheet) EdgeAbove(a Addr) Line {
183207 // EdgeLeft is the line on the edge between the cell at a and the one to184208 // its left.185209 func (s *Sheet) EdgeLeft(a Addr) Line {186- l := s.CellStyle(a).Borders.Left210+ l := s.CellStyle(a).Borders.Left()187211 if a.Col > 0 {188- l = Heavier(l, s.CellStyle(Addr{Col: a.Col - 1, Row: a.Row}).Borders.Right)212+ l = Heavier(l, s.CellStyle(Addr{Col: a.Col - 1, Row: a.Row}).Borders.Right())189213 }190214 return l191215 }@@ -118,7 +118,7 @@ func encodeBorders(b Borders) *fileBorders {
118118 if b.IsZero() {119119 return nil120120 }121- return &fileBorders{Top: b.Top.String(), Bottom: b.Bottom.String(), Left: b.Left.String(), Right: b.Right.String()}121+ return &fileBorders{Top: b.Top().String(), Bottom: b.Bottom().String(), Left: b.Left().String(), Right: b.Right().String()}122122 }123123 124124 func decodeBorders(fb *fileBorders) (Borders, error) {@@ -126,15 +126,12 @@ func decodeBorders(fb *fileBorders) (Borders, error) {
126126 if fb == nil {127127 return b, nil128128 }129- for _, e := range [...]struct {130- name string131- to *Line132- }{{fb.Top, &b.Top}, {fb.Bottom, &b.Bottom}, {fb.Left, &b.Left}, {fb.Right, &b.Right}} {133- l, ok := ParseLine(e.name)129+ for edge, name := range [...]string{EdgeTop: fb.Top, EdgeBottom: fb.Bottom, EdgeLeft: fb.Left, EdgeRight: fb.Right} {130+ l, ok := ParseLine(name)134131 if !ok {135- return Borders{}, fmt.Errorf("unknown border line %q", e.name)132+ return 0, fmt.Errorf("unknown border line %q", name)136133 }137- *e.to = l134+ b = b.With(Edge(edge), l)138135 }139136 return b, nil140137 }@@ -28,10 +28,10 @@ func TestBorders(t *testing.T) {
2828 cell string2929 want Borders3030 }{31- {"B2", Borders{Top: LineThin, Left: LineThin}},32- {"C2", Borders{Top: LineThin, Right: LineThin}},33- {"B3", Borders{Bottom: LineThin, Left: LineThin}},34- {"C3", Borders{Bottom: LineThin, Right: LineThin}},31+ {"B2", BordersOf(LineThin, LineNone, LineThin, LineNone)},32+ {"C2", BordersOf(LineThin, LineNone, LineNone, LineThin)},33+ {"B3", BordersOf(LineNone, LineThin, LineThin, LineNone)},34+ {"C3", BordersOf(LineNone, LineThin, LineNone, LineThin)},3535 } {3636 if got := s.CellStyle(at(c.cell)).Borders; got != c.want {3737 t.Errorf("outer: %s = %+v, want %+v", c.cell, got, c.want)@@ -44,12 +44,12 @@ func TestBorders(t *testing.T) {
4444 // Inner draws between the cells only; a later thick top clears the4545 // neighbor's facing bottom, so the last change shows.4646 s.SetBorders(rng("B2:C3"), BorderInner, LineDouble)47- if got := s.CellStyle(at("B2")).Borders; got != (Borders{Top: LineThin, Left: LineThin, Bottom: LineDouble, Right: LineDouble}) {47+ if got := s.CellStyle(at("B2")).Borders; got != BordersOf(LineThin, LineDouble, LineThin, LineDouble) {4848 t.Errorf("inner B2 = %+v", got)4949 }5050 s.SetBorders(rng("B1"), BorderBottom, LineThin)5151 s.SetBorders(rng("B2"), BorderTop, LineThick)52- if got := s.CellStyle(at("B1")).Borders.Bottom; got != LineNone {52+ if got := s.CellStyle(at("B1")).Borders.Bottom(); got != LineNone {5353 t.Errorf("facing bottom kept: %v", got)5454 }5555 if s.EdgeAbove(at("B2")) != LineThick {@@ -66,7 +66,7 @@ func TestBorders(t *testing.T) {
6666 t.Errorf("formatting-only cells left: %d", s.cells.len())6767 }6868 s.Undo()69- if s.CellStyle(at("C3")).Borders.Right != LineThin {69+ if s.CellStyle(at("C3")).Borders.Right() != LineThin {7070 t.Error("undo none")7171 }7272 // Whole columns keep borders on the column.@@ -74,7 +74,7 @@ func (s *Sheet) linesShape() bool {
7474 }7575 7676 // horizontal reports whether b draws its top or bottom edge.77-func (b Borders) horizontal() bool { return b.Top != LineNone || b.Bottom != LineNone }77+func (b Borders) horizontal() bool { return b.Top() != LineNone || b.Bottom() != LineNone }7878 7979 // Shaped reports whether any row may be other than one line of text8080 // under the one above: something wraps or draws borders, a row has a@@ -154,16 +154,16 @@ func (s *Sheet) WrappedIn(row int) []int {
154154 // column's, row's or the sheet's format drawing either.155155 func (s *Sheet) RuleAbove(row int) bool {156156 if s.linesShape() && (s.shapers.colRules || s.lines.sheet.Style.Borders.horizontal() ||157- s.lines.rows[row].Style.Borders.Top != LineNone || row > 0 && s.lines.rows[row-1].Style.Borders.Bottom != LineNone) {157+ s.lines.rows[row].Style.Borders.Top() != LineNone || row > 0 && s.lines.rows[row-1].Style.Borders.Bottom() != LineNone) {158158 return true159159 }160160 found := false161161 s.shapersIn(row, func(c int) {162- found = found || s.CellStyle(Addr{Col: c, Row: row}).Borders.Top != LineNone162+ found = found || s.CellStyle(Addr{Col: c, Row: row}).Borders.Top() != LineNone163163 })164164 if row > 0 && !found {165165 s.shapersIn(row-1, func(c int) {166- found = found || s.CellStyle(Addr{Col: c, Row: row - 1}).Borders.Bottom != LineNone166+ found = found || s.CellStyle(Addr{Col: c, Row: row - 1}).Borders.Bottom() != LineNone167167 })168168 }169169 return found@@ -350,7 +350,7 @@ func Shapes() []Shape {
350350 func Laidout(rows, cols int) *sheet.Sheet {351351 s := sheet.New()352352 r := rand.New(rand.NewPCG(5, 6))353- lines := sheet.Style{Borders: sheet.Borders{Top: sheet.LineThin, Bottom: sheet.LineThin, Left: sheet.LineThin, Right: sheet.LineThin}}353+ lines := sheet.Style{Borders: sheet.BordersOf(sheet.LineThin, sheet.LineThin, sheet.LineThin, sheet.LineThin)}354354 notes := lines355355 notes.Wrap = sheet.WrapOn356356 put := func(a sheet.Addr, input string, st sheet.Style) {