Skip to content

Commit

Permalink
apd: add Size method
Browse files Browse the repository at this point in the history
Revives cockroachdb#97.

I disagree with the rationale behind closing that PR. This logic belongs
in this package more than it belongs in CockroachDB code.
  • Loading branch information
nvanbenschoten committed Jan 6, 2022
1 parent 31337c1 commit d671d27
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 0 deletions.
14 changes: 14 additions & 0 deletions bigint.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,20 @@ func (z *BigInt) updateInnerFromUint(val uint, neg bool) {
}
}

const (
bigIntSize = unsafe.Sizeof(BigInt{})
mathBigIntSize = unsafe.Sizeof(big.Int{})
mathWordSize = unsafe.Sizeof(big.Word(0))
)

// Size returns the total memory footprint of z in bytes.
func (z *BigInt) Size() uintptr {
if z.isInline() {
return bigIntSize
}
return bigIntSize + mathBigIntSize + uintptr(cap(z._inner.Bits()))*mathWordSize
}

///////////////////////////////////////////////////////////////////////////////
// inline arithmetic for small values //
///////////////////////////////////////////////////////////////////////////////
Expand Down
8 changes: 8 additions & 0 deletions decimal.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package apd
import (
"strconv"
"strings"
"unsafe"

"database/sql/driver"
"github.com/pkg/errors"
Expand Down Expand Up @@ -737,6 +738,13 @@ func (d *Decimal) Reduce(x *Decimal) (*Decimal, int) {
return d, nd
}

const decimalSize = unsafe.Sizeof(Decimal{})

// Size returns the total memory footprint of d in bytes.
func (d *Decimal) Size() uintptr {
return decimalSize - bigIntSize + d.Coeff.Size()
}

// Value implements the database/sql/driver.Valuer interface. It converts d to a
// string.
func (d Decimal) Value() (driver.Value, error) {
Expand Down
35 changes: 35 additions & 0 deletions decimal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,41 @@ func TestSizeof(t *testing.T) {
}
}

// TestSize tests the Size method on BigInt and Decimal. Unlike Sizeof, which
// returns the shallow size of the structs, the Size method reports the total
// memory footprint of each struct and all referenced objects.
func TestSize(t *testing.T) {
var d Decimal
if e, s := uintptr(32), d.Size(); e != s {
t.Errorf("(*Decimal).Size() != %d: %d", e, s)
}
if e, s := uintptr(24), d.Coeff.Size(); e != s {
t.Errorf("(*BigInt).Size() != %d: %d", e, s)
}
// Set to an inlinable value.
d.SetInt64(1234)
if e, s := uintptr(32), d.Size(); e != s {
t.Errorf("(*Decimal).Size() != %d: %d", e, s)
}
if e, s := uintptr(24), d.Coeff.Size(); e != s {
t.Errorf("(*BigInt).Size() != %d: %d", e, s)
}
// Set to a non-inlinable value.
if _, _, err := d.SetString("123456789123456789123456789.123456789123456789"); err != nil {
t.Fatal(err)
}
if d.Coeff.isInline() {
// Sanity-check, in case inlineWords changes.
t.Fatal("BigInt inlined large value. Did inlineWords change?")
}
if e, s := uintptr(120), d.Size(); e != s {
t.Errorf("(*Decimal).Size() != %d: %d", e, s)
}
if e, s := uintptr(112), d.Coeff.Size(); e != s {
t.Errorf("(*BigInt).Size() != %d: %d", e, s)
}
}

func TestJSONEncoding(t *testing.T) {
var encodingTests = []string{
"0",
Expand Down

0 comments on commit d671d27

Please sign in to comment.