Tao Wen 9 tahun lalu
induk
melakukan
5e50b3e11c
3 mengubah file dengan 562 tambahan dan 113 penghapusan
  1. 424 0
      feature_stream_int.go
  2. 137 3
      jsoniter_int_test.go
  3. 1 110
      stream.go

+ 424 - 0
feature_stream_int.go

@@ -0,0 +1,424 @@
+package jsoniter
+
+var digits []uint8
+var digitTens []uint8
+var digitOnes []uint8
+
+func init() {
+	digits = []uint8{
+		'0', '1', '2', '3', '4', '5',
+		'6', '7', '8', '9', 'a', 'b',
+		'c', 'd', 'e', 'f', 'g', 'h',
+		'i', 'j', 'k', 'l', 'm', 'n',
+		'o', 'p', 'q', 'r', 's', 't',
+		'u', 'v', 'w', 'x', 'y', 'z',
+	}
+	digitTens = []uint8{
+		'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
+		'1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
+		'2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
+		'3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
+		'4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
+		'5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
+		'6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
+		'7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
+		'8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
+		'9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
+	}
+	digitOnes = []uint8{
+		'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+		'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+		'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+		'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+		'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+		'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+		'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+		'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+		'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+		'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+	}
+}
+func (stream *Stream) WriteUint8(val uint8) {
+	if stream.Available() < 3 {
+		stream.Flush()
+	}
+	charPos := stream.n
+	if val <= 9 {
+		charPos += 1;
+	} else {
+		if val <= 99 {
+			charPos += 2;
+		} else {
+			charPos += 3;
+		}
+	}
+	stream.n = charPos
+	var q uint8
+	for {
+		q = val / 10
+		r := val - ((q << 3) + (q << 1))  // r = i-(q*10) ...
+		charPos--
+		stream.buf[charPos] = digits[r]
+		val = q;
+		if val == 0 {
+			break
+		}
+	}
+}
+
+func (stream *Stream) WriteInt8(val int8) {
+	if stream.Available() < 4 {
+		stream.Flush()
+	}
+	charPos := stream.n
+	if (val < 0) {
+		charPos += 1
+		val = -val
+		stream.buf[stream.n] = '-'
+	}
+	if val <= 9 {
+		charPos += 1;
+	} else {
+		if val <= 99 {
+			charPos += 2;
+		} else {
+			charPos += 3;
+		}
+	}
+	stream.n = charPos
+	var q int8
+	for {
+		q = val / 10
+		r := val - ((q << 3) + (q << 1))  // r = i-(q*10) ...
+		charPos--
+		stream.buf[charPos] = digits[r]
+		val = q;
+		if val == 0 {
+			break
+		}
+	}
+}
+
+func (stream *Stream) WriteUint16(val uint16) {
+	if stream.Available() < 5 {
+		stream.Flush()
+	}
+	charPos := stream.n
+	if val <= 99 {
+		if val <= 9 {
+			charPos += 1;
+		} else {
+			charPos += 2;
+		}
+	} else {
+		if val <= 999 {
+			charPos += 3;
+		} else {
+			if val <= 9999 {
+				charPos += 4;
+			} else {
+				charPos += 5;
+			}
+		}
+	}
+	stream.n = charPos
+	var q uint16
+	for {
+		q = val / 10
+		r := val - ((q << 3) + (q << 1))  // r = i-(q*10) ...
+		charPos--
+		stream.buf[charPos] = digits[r]
+		val = q;
+		if val == 0 {
+			break
+		}
+	}
+}
+
+func (stream *Stream) WriteInt16(val int16) {
+	if stream.Available() < 6 {
+		stream.Flush()
+	}
+	charPos := stream.n
+	if (val < 0) {
+		charPos += 1
+		val = -val
+		stream.buf[stream.n] = '-'
+	}
+	if val <= 99 {
+		if val <= 9 {
+			charPos += 1;
+		} else {
+			charPos += 2;
+		}
+	} else {
+		if val <= 999 {
+			charPos += 3;
+		} else {
+			if val <= 9999 {
+				charPos += 4;
+			} else {
+				charPos += 5;
+			}
+		}
+	}
+	stream.n = charPos
+	var q int16
+	for {
+		q = val / 10
+		r := val - ((q << 3) + (q << 1))  // r = i-(q*10) ...
+		charPos--
+		stream.buf[charPos] = digits[r]
+		val = q;
+		if val == 0 {
+			break
+		}
+	}
+}
+
+func (stream *Stream) WriteUint32(val uint32) {
+	if stream.Available() < 10 {
+		stream.Flush()
+	}
+	charPos := stream.n
+	if val <= 99999 {
+		if val <= 999 {
+			if val <= 9 {
+				charPos += 1;
+			} else {
+				if val <= 99 {
+					charPos += 2;
+				} else {
+					charPos += 3;
+				}
+			}
+		} else {
+			if val <= 9999 {
+				charPos += 4;
+			} else {
+				charPos += 5;
+			}
+		}
+	} else {
+		if val < 99999999 {
+			if val <= 999999 {
+				charPos += 6;
+			} else {
+				if val <= 9999999 {
+					charPos += 7;
+				} else {
+					charPos += 8;
+				}
+			}
+		} else {
+			if val <= 999999999 {
+				charPos += 9;
+			} else {
+				charPos += 10;
+			}
+		}
+	}
+	stream.n = charPos
+
+	var q uint32
+	for val >= 65536 {
+		q = val / 100;
+		// really: r = i - (q * 100);
+		r := val - ((q << 6) + (q << 5) + (q << 2));
+		val = q;
+		charPos--
+		stream.buf[charPos] = digitOnes[r];
+		charPos--
+		stream.buf[charPos] = digitTens[r];
+	}
+
+	for {
+		q = val / 10
+		r := val - ((q << 3) + (q << 1))  // r = i-(q*10) ...
+		charPos--
+		stream.buf[charPos] = digits[r]
+		val = q;
+		if val == 0 {
+			break
+		}
+	}
+}
+
+func (stream *Stream) WriteInt32(val int32) {
+	if stream.Available() < 11 {
+		stream.Flush()
+	}
+	charPos := stream.n
+	if (val < 0) {
+		charPos += 1
+		val = -val
+		stream.buf[stream.n] = '-'
+	}
+	if val <= 99999 {
+		if val <= 999 {
+			if val <= 9 {
+				charPos += 1;
+			} else {
+				if val <= 99 {
+					charPos += 2;
+				} else {
+					charPos += 3;
+				}
+			}
+		} else {
+			if val <= 9999 {
+				charPos += 4;
+			} else {
+				charPos += 5;
+			}
+		}
+	} else {
+		if val < 99999999 {
+			if val <= 999999 {
+				charPos += 6;
+			} else {
+				if val <= 9999999 {
+					charPos += 7;
+				} else {
+					charPos += 8;
+				}
+			}
+		} else {
+			if val <= 999999999 {
+				charPos += 9;
+			} else {
+				charPos += 10;
+			}
+		}
+	}
+	stream.n = charPos
+
+	var q int32
+	for val >= 65536 {
+		q = val / 100;
+		// really: r = i - (q * 100);
+		r := val - ((q << 6) + (q << 5) + (q << 2));
+		val = q;
+		charPos--
+		stream.buf[charPos] = digitOnes[r];
+		charPos--
+		stream.buf[charPos] = digitTens[r];
+	}
+
+	for {
+		q = val / 10
+		r := val - ((q << 3) + (q << 1))  // r = i-(q*10) ...
+		charPos--
+		stream.buf[charPos] = digits[r]
+		val = q;
+		if val == 0 {
+			break
+		}
+	}
+}
+
+func (stream *Stream) WriteUint64(val uint64) {
+	if stream.Available() < 10 {
+		stream.Flush()
+	}
+	charPos := stream.n
+	if val <= 99999 {
+		if val <= 999 {
+			if val <= 9 {
+				charPos += 1;
+			} else {
+				if val <= 99 {
+					charPos += 2;
+				} else {
+					charPos += 3;
+				}
+			}
+		} else {
+			if val <= 9999 {
+				charPos += 4;
+			} else {
+				charPos += 5;
+			}
+		}
+	} else if val < 9999999999 {
+		if val < 99999999 {
+			if val <= 999999 {
+				charPos += 6;
+			} else {
+				if val <= 9999999 {
+					charPos += 7;
+				} else {
+					charPos += 8;
+				}
+			}
+		} else {
+			if val <= 999999999 {
+				charPos += 9;
+			} else {
+				charPos += 10;
+			}
+		}
+	} else {
+		stream.writeUint64SlowPath(val)
+		return
+	}
+	stream.n = charPos
+	var q uint64
+	for val >= 65536 {
+		q = val / 100;
+		// really: r = i - (q * 100);
+		r := val - ((q << 6) + (q << 5) + (q << 2));
+		val = q;
+		charPos--
+		stream.buf[charPos] = digitOnes[r];
+		charPos--
+		stream.buf[charPos] = digitTens[r];
+	}
+
+	for {
+		q = val / 10
+		r := val - ((q << 3) + (q << 1))  // r = i-(q*10) ...
+		charPos--
+		stream.buf[charPos] = digits[r]
+		val = q;
+		if val == 0 {
+			break
+		}
+	}
+}
+
+func (stream *Stream) WriteInt64(val int64) {
+	if (val < 0) {
+		val = -val
+		stream.writeByte('-')
+	}
+	stream.WriteUint64(uint64(val))
+}
+
+func (stream *Stream) writeUint64SlowPath(val uint64) {
+	var temp [20]byte
+	charPos := 20
+	var q uint64
+	for val >= 65536 {
+		q = val / 100;
+		// really: r = i - (q * 100);
+		r := val - ((q << 6) + (q << 5) + (q << 2));
+		val = q;
+		charPos--
+		temp[charPos] = digitOnes[r];
+		charPos--
+		temp[charPos] = digitTens[r];
+	}
+
+	for {
+		q = val / 10
+		r := val - ((q << 3) + (q << 1))  // r = i-(q*10) ...
+		charPos--
+		temp[charPos] = digits[r]
+		val = q;
+		if val == 0 {
+			break
+		}
+	}
+	stream.Write(temp[charPos:])
+}

+ 137 - 3
jsoniter_int_test.go

@@ -7,6 +7,7 @@ import (
 	"github.com/json-iterator/go/require"
 	"fmt"
 	"strconv"
+	"io/ioutil"
 )
 
 func Test_decode_decode_uint64_0(t *testing.T) {
@@ -81,7 +82,7 @@ func Test_write_uint8(t *testing.T) {
 			stream.WriteUint8(val)
 			stream.Flush()
 			should.Nil(stream.Error)
-			should.Equal(strconv.Itoa(int(val)), buf.String())
+			should.Equal(strconv.FormatUint(uint64(val), 10), buf.String())
 		})
 	}
 	should := require.New(t)
@@ -104,7 +105,7 @@ func Test_write_int8(t *testing.T) {
 			stream.WriteInt8(val)
 			stream.Flush()
 			should.Nil(stream.Error)
-			should.Equal(strconv.Itoa(int(val)), buf.String())
+			should.Equal(strconv.FormatInt(int64(val), 10), buf.String())
 		})
 	}
 	should := require.New(t)
@@ -127,7 +128,7 @@ func Test_write_uint16(t *testing.T) {
 			stream.WriteUint16(val)
 			stream.Flush()
 			should.Nil(stream.Error)
-			should.Equal(strconv.Itoa(int(val)), buf.String())
+			should.Equal(strconv.FormatUint(uint64(val), 10), buf.String())
 		})
 	}
 	should := require.New(t)
@@ -140,6 +141,139 @@ func Test_write_uint16(t *testing.T) {
 	should.Equal("a10000", buf.String())
 }
 
+func Test_write_int16(t *testing.T) {
+	vals := []int16{0, 1, 11, 111, 255, 0xfff, 0x7fff, -0x7fff}
+	for _, val := range vals {
+		t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
+			should := require.New(t)
+			buf := &bytes.Buffer{}
+			stream := NewStream(buf, 4096)
+			stream.WriteInt16(val)
+			stream.Flush()
+			should.Nil(stream.Error)
+			should.Equal(strconv.FormatInt(int64(val), 10), buf.String())
+		})
+	}
+	should := require.New(t)
+	buf := &bytes.Buffer{}
+	stream := NewStream(buf, 6)
+	stream.WriteString("a")
+	stream.WriteInt16(-10000) // should clear buffer
+	stream.Flush()
+	should.Nil(stream.Error)
+	should.Equal("a-10000", buf.String())
+}
+
+func Test_write_uint32(t *testing.T) {
+	vals := []uint32{0, 1, 11, 111, 255, 999999, 0xfff, 0xffff, 0xfffff, 0xffffff, 0xfffffff, 0xffffffff}
+	for _, val := range vals {
+		t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
+			should := require.New(t)
+			buf := &bytes.Buffer{}
+			stream := NewStream(buf, 4096)
+			stream.WriteUint32(val)
+			stream.Flush()
+			should.Nil(stream.Error)
+			should.Equal(strconv.FormatUint(uint64(val), 10), buf.String())
+		})
+	}
+	should := require.New(t)
+	buf := &bytes.Buffer{}
+	stream := NewStream(buf, 10)
+	stream.WriteString("a")
+	stream.WriteUint32(0xffffffff) // should clear buffer
+	stream.Flush()
+	should.Nil(stream.Error)
+	should.Equal("a4294967295", buf.String())
+}
+
+func Test_write_int32(t *testing.T) {
+	vals := []int32{0, 1, 11, 111, 255, 999999, 0xfff, 0xffff, 0xfffff, 0xffffff, 0xfffffff, 0x7fffffff, -0x7fffffff}
+	for _, val := range vals {
+		t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
+			should := require.New(t)
+			buf := &bytes.Buffer{}
+			stream := NewStream(buf, 4096)
+			stream.WriteInt32(val)
+			stream.Flush()
+			should.Nil(stream.Error)
+			should.Equal(strconv.FormatInt(int64(val), 10), buf.String())
+		})
+	}
+	should := require.New(t)
+	buf := &bytes.Buffer{}
+	stream := NewStream(buf, 11)
+	stream.WriteString("a")
+	stream.WriteInt32(-0x7fffffff) // should clear buffer
+	stream.Flush()
+	should.Nil(stream.Error)
+	should.Equal("a-2147483647", buf.String())
+}
+
+func Test_write_uint64(t *testing.T) {
+	vals := []uint64{0, 1, 11, 111, 255, 999999, 0xfff, 0xffff, 0xfffff, 0xffffff, 0xfffffff, 0xffffffff,
+		0xfffffffff,0xffffffffff,0xfffffffffff,0xffffffffffff,0xfffffffffffff,0xffffffffffffff,
+		0xfffffffffffffff,0xffffffffffffffff}
+	for _, val := range vals {
+		t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
+			should := require.New(t)
+			buf := &bytes.Buffer{}
+			stream := NewStream(buf, 4096)
+			stream.WriteUint64(val)
+			stream.Flush()
+			should.Nil(stream.Error)
+			should.Equal(strconv.FormatUint(uint64(val), 10), buf.String())
+		})
+	}
+	should := require.New(t)
+	buf := &bytes.Buffer{}
+	stream := NewStream(buf, 10)
+	stream.WriteString("a")
+	stream.WriteUint64(0xffffffff) // should clear buffer
+	stream.Flush()
+	should.Nil(stream.Error)
+	should.Equal("a4294967295", buf.String())
+}
+
+func Test_write_int64(t *testing.T) {
+	vals := []int64{0, 1, 11, 111, 255, 999999, 0xfff, 0xffff, 0xfffff, 0xffffff, 0xfffffff, 0xffffffff,
+		0xfffffffff,0xffffffffff,0xfffffffffff,0xffffffffffff,0xfffffffffffff,0xffffffffffffff,
+		0xfffffffffffffff,0x7fffffffffffffff,-0x7fffffffffffffff}
+	for _, val := range vals {
+		t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
+			should := require.New(t)
+			buf := &bytes.Buffer{}
+			stream := NewStream(buf, 4096)
+			stream.WriteInt64(val)
+			stream.Flush()
+			should.Nil(stream.Error)
+			should.Equal(strconv.FormatInt(val, 10), buf.String())
+		})
+	}
+	should := require.New(t)
+	buf := &bytes.Buffer{}
+	stream := NewStream(buf, 10)
+	stream.WriteString("a")
+	stream.WriteInt64(0xffffffff) // should clear buffer
+	stream.Flush()
+	should.Nil(stream.Error)
+	should.Equal("a4294967295", buf.String())
+}
+
+func Benchmark_jsoniter_encode_int(b *testing.B) {
+	stream := NewStream(ioutil.Discard, 64)
+	for n := 0; n < b.N; n++ {
+		stream.n = 0
+		stream.WriteUint64(0xffffffff)
+	}
+}
+
+func Benchmark_itoa(b *testing.B) {
+	for n := 0; n < b.N; n++ {
+		strconv.FormatInt(0xffffffff, 10)
+	}
+}
+
 func Benchmark_jsoniter_int(b *testing.B) {
 	for n := 0; n < b.N; n++ {
 		iter := ParseString(`-100`)

+ 1 - 110
stream.go

@@ -5,18 +5,9 @@ import (
 )
 
 var bytesNull []byte
-var digits []uint8;
 
 func init() {
 	bytesNull = []byte("null")
-	digits = []uint8{
-		'0', '1', '2', '3', '4', '5',
-		'6', '7', '8', '9', 'a', 'b',
-		'c', 'd', 'e', 'f', 'g', 'h',
-		'i', 'j', 'k', 'l', 'm', 'n',
-		'o', 'p', 'q', 'r', 's', 't',
-		'u', 'v', 'w', 'x', 'y', 'z',
-	}
 }
 
 type Stream struct {
@@ -71,7 +62,7 @@ func (b *Stream) Write(p []byte) (nn int, err error) {
 
 
 // WriteByte writes a single byte.
-func (b *Stream) WriteByte(c byte) error {
+func (b *Stream) writeByte(c byte) error {
 	if b.Error != nil {
 		return b.Error
 	}
@@ -125,105 +116,5 @@ func (stream *Stream) WriteNull() {
 	stream.Write(bytesNull)
 }
 
-func (stream *Stream) WriteUint8(val uint8) {
-	if stream.Available() < 3 {
-		stream.Flush()
-	}
-	charPos := stream.n
-	if val <= 9 {
-		charPos += 1;
-	} else {
-		if val <= 99 {
-			charPos += 2;
-		} else {
-			charPos += 3;
-		}
-	}
-	stream.n = charPos
-	var q uint8
-	var r uint8
-	for {
-		q = val / 10
-		r = val - ((q << 3) + (q << 1))  // r = i-(q*10) ...
-		charPos--
-		stream.buf[charPos] = digits[r]
-		val = q;
-		if val == 0 {
-			break
-		}
-	}
-}
-
-func (stream *Stream) WriteInt8(val int8) {
-	if stream.Available() < 4 {
-		stream.Flush()
-	}
-	charPos := stream.n
-	if (val < 0) {
-		charPos += 1
-		val = -val
-		stream.buf[stream.n] = '-'
-	}
-	if val <= 9 {
-		charPos += 1;
-	} else {
-		if val <= 99 {
-			charPos += 2;
-		} else {
-			charPos += 3;
-		}
-	}
-	stream.n = charPos
-	var q int8
-	var r int8
-	for {
-		q = val / 10
-		r = val - ((q << 3) + (q << 1))  // r = i-(q*10) ...
-		charPos--
-		stream.buf[charPos] = digits[r]
-		val = q;
-		if val == 0 {
-			break
-		}
-	}
-}
-
-func (stream *Stream) WriteUint16(val uint16) {
-	if stream.Available() < 5 {
-		stream.Flush()
-	}
-	charPos := stream.n
-	if val <= 99 {
-		if val <= 9 {
-			charPos += 1;
-		} else {
-			charPos += 2;
-		}
-	} else {
-		if val <= 999 {
-			charPos += 3;
-		} else {
-			if val <= 9999 {
-				charPos += 4;
-			} else {
-				charPos += 5;
-			}
-		}
-	}
-	stream.n = charPos
-	var q uint16
-	var r uint16
-	for {
-		q = val / 10
-		r = val - ((q << 3) + (q << 1))  // r = i-(q*10) ...
-		charPos--
-		stream.buf[charPos] = digits[r]
-		val = q;
-		if val == 0 {
-			break
-		}
-	}
-}
-
 func (stream *Stream) WriteVal(val interface{}) {
 }