Skip to content

Commit

Permalink
Fix bugs in a couple routines, more thorough tests and high-level str…
Browse files Browse the repository at this point in the history
…ing functions
  • Loading branch information
connor4312 committed Dec 25, 2017
1 parent 1b27d5a commit d2a044c
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 11 deletions.
39 changes: 35 additions & 4 deletions itoa.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ const (
PO16 uint64 = 10000000000000000
ZERO_CHARS uint64 = 0x3030303030303030
ZERO_CHARS_32 uint32 = 0x30303030
ZERO_MASK uint32 = 0xFFFFFFF8

MAX_UINT64_DIGITS = 20
)

//
Expand Down Expand Up @@ -160,9 +163,10 @@ func itoaTenThousand(out []byte, x uint32) []byte {
* little endian) zero bytes: count leading zero bits and
* round down to 8.
*/
zeros := uint32(bits.TrailingZeros32(buf)) & ^uint32(8)
zeros := uint32(bits.TrailingZeros32(buf)) & ZERO_MASK
buf += ZERO_CHARS_32 /* BCD -> ASCII. */
buf = buf >> zeros /* Shift away leading zero characters */

// memcpy(out, &buf, 4);
out[0] = byte(buf)
out[1] = byte(buf >> 8)
Expand Down Expand Up @@ -278,7 +282,7 @@ func anItoa(out []byte, x uint32) []byte {

if x < uint32(PO8) {

zeros := uint32(bits.TrailingZeros64(buf)) & ^uint32(8)
zeros := uint32(bits.TrailingZeros64(buf)) & ZERO_MASK

buf += ZERO_CHARS
buf = buf >> zeros
Expand Down Expand Up @@ -334,6 +338,33 @@ func ldivPO16(x uint64) uint64 {
return hi >> 51
}

// FormatUint returns a byte slice containing a uint64 formatted to a string.
// Note that this uses some intermediate memory; if you want to target a binary
// format, use Anltoa.
func FormatUint(x uint64) string {
var buf [MAX_UINT64_DIGITS]byte
remainder := Anltoa(buf[:], x)
return string(buf[:len(buf)-len(remainder)])
}

// FormatInt returns a byte slice containing a int64 formatted to a string.
// Note that this uses some intermediate memory; if you want to target a binary
// format, use Anltoa.
func FormatInt(x int64) string {
if x >= 0 {
return FormatUint(uint64(x))
}

var buf [MAX_UINT64_DIGITS + 1]byte
buf[0] = '-'
remainder := Anltoa(buf[1:], uint64(-x))
return string(buf[:len(buf)-len(remainder)])
}

// Anltoa takes a byte buffer and a number, and encodes the number as a string
// to the buffer. It will panic if the buffer is too small; the maximum number
// of digits a 64-bit uint can be is 20. It returns the portion of the slice
// after the encoded number.
func Anltoa(out []byte, x uint64) []byte {
if x < PO2 {
return itoaHundred(out, uint32(x))
Expand All @@ -353,7 +384,7 @@ func Anltoa(out []byte, x uint64) []byte {
*/
if x < PO8 {
buf := encodeTenThousands(xDivPO4, xModPO4)
zeros := uint32(bits.TrailingZeros64(buf)) & ^uint32(8)
zeros := uint32(bits.TrailingZeros64(buf)) & ZERO_MASK
buf += ZERO_CHARS
buf = buf >> zeros

Expand Down Expand Up @@ -386,7 +417,7 @@ func Anltoa(out []byte, x uint64) []byte {
hiHi := uint64(idivPO4(uint32(xDivPO8)))
hiLo := xDivPO8 - hiHi*PO4
bufHi := encodeTenThousands(hiHi, hiLo)
zeros := uint32(bits.TrailingZeros64(buf)) & ^uint32(8)
zeros := uint32(bits.TrailingZeros64(bufHi)) & ZERO_MASK

bufHi += ZERO_CHARS
bufHi = bufHi >> zeros
Expand Down
53 changes: 46 additions & 7 deletions itoa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,60 @@ package itoa

import (
"fmt"
"math/rand"
"strconv"
"strings"
"testing"
)

_ "github.com/pilosa/pilosa/test"
const (
printerIterations = 10000
)

func TestHello(t *testing.T) {
buf := make([]byte, 8)
Anltoa(buf, 10000000)
if strings.Compare(string(buf), string("10000000")) != 0 {
t.Errorf("\n(%s)\n(%s)", len(string(buf)), len("10000000"))
func testPrinter(t *testing.T, fn func(out []byte) (value interface{}, result string)) {
rand.Seed(0)

buf := make([]byte, 20)
for i := 0; i < printerIterations; i++ {
value, actual := fn(buf)
expected := fmt.Sprintf("%d", value)

if string(expected) != string(actual) {
t.Errorf("Expected %q, got %q", expected, actual)
}
}
}

func TestItoaHundred(t *testing.T) {
testPrinter(t, func(out []byte) (value interface{}, result string) {
v := uint64(rand.Intn(100))
return v, FormatUint(v)
})
}

func TestItoaTenThousand(t *testing.T) {
testPrinter(t, func(out []byte) (value interface{}, result string) {
v := uint64(rand.Intn(10000))
return v, FormatUint(v)
})
}

func TestUint(t *testing.T) {
testPrinter(t, func(out []byte) (value interface{}, result string) {
v := rand.Uint64() >> uint(rand.Intn(64))
return v, FormatUint(v)
})
}
func TestInt(t *testing.T) {
testPrinter(t, func(out []byte) (value interface{}, result string) {
v := rand.Int63() >> uint(rand.Intn(64))
if rand.Intn(1) == 1 {
v = -v
}

return v, FormatInt(v)
})
}

var smallInt = 35
var bigInt = 999999999999999

Expand Down

0 comments on commit d2a044c

Please sign in to comment.