Ver Fonte

fix write int

Tao Wen há 9 anos atrás
pai
commit
102cd8748e
2 ficheiros alterados com 259 adições e 330 exclusões
  1. 255 326
      feature_stream_int.go
  2. 4 4
      jsoniter_int_test.go

+ 255 - 326
feature_stream_int.go

@@ -3,6 +3,7 @@ package jsoniter
 var digits []uint8
 var digitTens []uint8
 var digitOnes []uint8
+var DIGITS []uint32
 
 func init() {
 	digits = []uint8{
@@ -37,390 +38,318 @@ func init() {
 		'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
 		'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
 	}
+	DIGITS = make([]uint32, 1000)
+	for i := uint32(0); i < 1000; i++ {
+		DIGITS[i] = (((i / 100) + '0') << 16) + ((((i / 10) % 10) + '0') << 8) + i % 10 + '0';
+		if i < 10 {
+			DIGITS[i] += 2 << 24
+		} else if i < 100 {
+			DIGITS[i] += 1 << 24
+		}
+	}
+}
+
+func writeFirstBuf(buf []byte, v uint32, n int) int {
+	start := v >> 24
+	if start == 0 {
+		buf[n] = byte(v >> 16)
+		n++
+		buf[n] = byte(v >> 8)
+		n++
+	} else if start == 1 {
+		buf[n] = byte(v >> 8)
+		n++
+	}
+	buf[n] = byte(v)
+	n++
+	return n
+}
+
+func writeBuf(buf []byte, v uint32, n int) {
+	buf[n] = byte(v >> 16)
+	buf[n + 1] = byte(v >> 8)
+	buf[n + 2] = byte(v)
 }
+
 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
-		}
-	}
+	stream.n = writeFirstBuf(stream.buf, DIGITS[val], stream.n)
 }
 
-func (stream *Stream) WriteInt8(val int8) {
+func (stream *Stream) WriteInt8(nval 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;
+	n := stream.n
+	var val uint8
+	if (nval < 0) {
+		val = uint8(-nval)
+		stream.buf[n] = '-'
+		n++
 	} 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
-		}
+		val = uint8(nval)
 	}
+	stream.n = writeFirstBuf(stream.buf, DIGITS[val], n)
 }
 
 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
-		}
+	q1 := val / 1000
+	if q1 == 0 {
+		stream.n = writeFirstBuf(stream.buf, DIGITS[val], stream.n)
+		return
 	}
+	r1 := val - q1 * 1000;
+	n := writeFirstBuf(stream.buf, DIGITS[q1], stream.n)
+	writeBuf(stream.buf, DIGITS[r1], n)
+	stream.n = n + 3
+	return
 }
 
-func (stream *Stream) WriteInt16(val int16) {
+func (stream *Stream) WriteInt16(nval 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;
-		}
+	n := stream.n
+	var val uint16
+	if (nval < 0) {
+		val = uint16(-nval)
+		stream.buf[n] = '-'
+		n++
 	} else {
-		if val <= 999 {
-			charPos += 3;
-		} else {
-			if val <= 9999 {
-				charPos += 4;
-			} else {
-				charPos += 5;
-			}
-		}
+		val = uint16(nval)
 	}
-	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
-		}
+	q1 := val / 1000
+	if q1 == 0 {
+		stream.n = writeFirstBuf(stream.buf, DIGITS[val], n)
+		return
 	}
+	r1 := val - q1 * 1000;
+	n = writeFirstBuf(stream.buf, DIGITS[q1], n)
+	writeBuf(stream.buf, DIGITS[r1], n)
+	stream.n = n + 3
+	return
 }
 
 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];
+	n := stream.n
+	q1 := val / 1000
+	if q1 == 0 {
+		stream.n = writeFirstBuf(stream.buf, DIGITS[val], n)
+		return
 	}
-
-	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
-		}
+	r1 := val - q1 * 1000;
+	q2 := q1 / 1000
+	if q2 == 0 {
+		n := writeFirstBuf(stream.buf, DIGITS[q1], n)
+		writeBuf(stream.buf, DIGITS[r1], n)
+		stream.n = n + 3
+		return
 	}
+	r2 := q1 - q2 * 1000
+	q3 := q2 / 1000
+	if q3 == 0 {
+		n = writeFirstBuf(stream.buf, DIGITS[q2], n)
+	} else {
+		r3 := q2 - q3 * 1000
+		stream.buf[n] = byte(q3 + '0')
+		n++
+		writeBuf(stream.buf, DIGITS[r3], n)
+		n += 3
+	}
+	writeBuf(stream.buf, DIGITS[r2], n)
+	writeBuf(stream.buf, DIGITS[r1], n + 3)
+	stream.n = n + 6
 }
 
-func (stream *Stream) WriteInt32(val int32) {
+func (stream *Stream) WriteInt32(nval 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;
-			}
-		}
+	n := stream.n
+	var val uint32
+	if (nval < 0) {
+		val = uint32(-nval)
+		stream.buf[n] = '-'
+		n++
 	} 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;
-			}
-		}
+		val = uint32(nval)
 	}
-	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];
+	q1 := val / 1000
+	if q1 == 0 {
+		stream.n = writeFirstBuf(stream.buf, DIGITS[val], n)
+		return
 	}
-
-	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
-		}
+	r1 := val - q1 * 1000;
+	q2 := q1 / 1000
+	if q2 == 0 {
+		n := writeFirstBuf(stream.buf, DIGITS[q1], n)
+		writeBuf(stream.buf, DIGITS[r1], n)
+		stream.n = n + 3
+		return
 	}
+	r2 := q1 - q2 * 1000
+	q3 := q2 / 1000
+	if q3 == 0 {
+		n = writeFirstBuf(stream.buf, DIGITS[q2], n)
+	} else {
+		r3 := q2 - q3 * 1000
+		stream.buf[n] = byte(q3 + '0')
+		n++
+		writeBuf(stream.buf, DIGITS[r3], n)
+		n += 3
+	}
+	writeBuf(stream.buf, DIGITS[r2], n)
+	writeBuf(stream.buf, DIGITS[r1], n + 3)
+	stream.n = n + 6
 }
 
 func (stream *Stream) WriteUint64(val uint64) {
-	if stream.Available() < 10 {
+	if stream.Available() < 20 {
 		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)
+	n := stream.n
+	q1 := val / 1000
+	if q1 == 0 {
+		stream.n = writeFirstBuf(stream.buf, DIGITS[val], n)
 		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];
+	r1 := val - q1 * 1000;
+	q2 := q1 / 1000
+	if q2 == 0 {
+		n := writeFirstBuf(stream.buf, DIGITS[q1], n)
+		writeBuf(stream.buf, DIGITS[r1], n)
+		stream.n = n + 3
+		return
 	}
-
-	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
-		}
+	r2 := q1 - q2 * 1000
+	q3 := q2 / 1000
+	if q3 == 0 {
+		n = writeFirstBuf(stream.buf, DIGITS[q2], n)
+		writeBuf(stream.buf, DIGITS[r2], n)
+		writeBuf(stream.buf, DIGITS[r1], n + 3)
+		stream.n = n + 6
+		return
 	}
-}
-
-func (stream *Stream) WriteInt64(val int64) {
-	if (val < 0) {
-		val = -val
-		stream.writeByte('-')
+	r3 := q2 - q3 * 1000
+	q4 := q3 / 1000
+	if q4 == 0 {
+		n = writeFirstBuf(stream.buf, DIGITS[q3], n)
+		writeBuf(stream.buf, DIGITS[r3], n)
+		writeBuf(stream.buf, DIGITS[r2], n + 3)
+		writeBuf(stream.buf, DIGITS[r1], n + 6)
+		stream.n = n + 9
+		return
 	}
-	stream.WriteUint64(uint64(val))
+	r4 := q3 - q4 * 1000
+	q5 := q4 / 1000
+	if q5 == 0 {
+		n = writeFirstBuf(stream.buf, DIGITS[q4], n)
+		writeBuf(stream.buf, DIGITS[r4], n)
+		writeBuf(stream.buf, DIGITS[r3], n + 3)
+		writeBuf(stream.buf, DIGITS[r2], n + 6)
+		writeBuf(stream.buf, DIGITS[r1], n + 9)
+		stream.n = n + 12
+		return
+	}
+	r5 := q4 - q5 * 1000
+	q6 := q5 / 1000
+	if q6 == 0 {
+		n = writeFirstBuf(stream.buf, DIGITS[q5], n)
+	} else {
+		n = writeFirstBuf(stream.buf, DIGITS[q6], n)
+		r6 := q5 - q6 * 1000
+		writeBuf(stream.buf, DIGITS[r6], n)
+		n += 3
+	}
+	writeBuf(stream.buf, DIGITS[r5], n)
+	writeBuf(stream.buf, DIGITS[r4], n + 3)
+	writeBuf(stream.buf, DIGITS[r3], n + 6)
+	writeBuf(stream.buf, DIGITS[r2], n + 9)
+	writeBuf(stream.buf, DIGITS[r1], n + 12)
+	stream.n = n + 15
 }
 
-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];
+func (stream *Stream) WriteInt64(nval int64) {
+	if stream.Available() < 20 {
+		stream.Flush()
 	}
-
-	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
-		}
+	n := stream.n
+	var val uint64
+	if (nval < 0) {
+		val = uint64(-nval)
+		stream.buf[n] = '-'
+		n++
+	} else {
+		val = uint64(nval)
+	}
+	q1 := val / 1000
+	if q1 == 0 {
+		stream.n = writeFirstBuf(stream.buf, DIGITS[val], n)
+		return
 	}
-	stream.Write(temp[charPos:])
+	r1 := val - q1 * 1000;
+	q2 := q1 / 1000
+	if q2 == 0 {
+		n := writeFirstBuf(stream.buf, DIGITS[q1], n)
+		writeBuf(stream.buf, DIGITS[r1], n)
+		stream.n = n + 3
+		return
+	}
+	r2 := q1 - q2 * 1000
+	q3 := q2 / 1000
+	if q3 == 0 {
+		n = writeFirstBuf(stream.buf, DIGITS[q2], n)
+		writeBuf(stream.buf, DIGITS[r2], n)
+		writeBuf(stream.buf, DIGITS[r1], n + 3)
+		stream.n = n + 6
+		return
+	}
+	r3 := q2 - q3 * 1000
+	q4 := q3 / 1000
+	if q4 == 0 {
+		n = writeFirstBuf(stream.buf, DIGITS[q3], n)
+		writeBuf(stream.buf, DIGITS[r3], n)
+		writeBuf(stream.buf, DIGITS[r2], n + 3)
+		writeBuf(stream.buf, DIGITS[r1], n + 6)
+		stream.n = n + 9
+		return
+	}
+	r4 := q3 - q4 * 1000
+	q5 := q4 / 1000
+	if q5 == 0 {
+		n = writeFirstBuf(stream.buf, DIGITS[q4], n)
+		writeBuf(stream.buf, DIGITS[r4], n)
+		writeBuf(stream.buf, DIGITS[r3], n + 3)
+		writeBuf(stream.buf, DIGITS[r2], n + 6)
+		writeBuf(stream.buf, DIGITS[r1], n + 9)
+		stream.n = n + 12
+		return
+	}
+	r5 := q4 - q5 * 1000
+	q6 := q5 / 1000
+	if q6 == 0 {
+		n = writeFirstBuf(stream.buf, DIGITS[q5], n)
+	} else {
+		stream.buf[n] = byte(q6 + '0')
+		n++
+		r6 := q5 - q6 * 1000
+		writeBuf(stream.buf, DIGITS[r6], n)
+		n += 3
+	}
+	writeBuf(stream.buf, DIGITS[r5], n)
+	writeBuf(stream.buf, DIGITS[r4], n + 3)
+	writeBuf(stream.buf, DIGITS[r3], n + 6)
+	writeBuf(stream.buf, DIGITS[r2], n + 9)
+	writeBuf(stream.buf, DIGITS[r1], n + 12)
+	stream.n = n + 15
 }
 
 func (stream *Stream) WriteInt(val int) {

+ 4 - 4
jsoniter_int_test.go

@@ -132,7 +132,7 @@ func Test_write_uint8(t *testing.T) {
 }
 
 func Test_write_int8(t *testing.T) {
-	vals := []int8{0, 1, -1, 99, 0x7f, -0x7f}
+	vals := []int8{0, 1, -1, 99, 0x7f, -0x80}
 	for _, val := range vals {
 		t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
 			should := require.New(t)
@@ -196,7 +196,7 @@ func Test_write_uint16(t *testing.T) {
 }
 
 func Test_write_int16(t *testing.T) {
-	vals := []int16{0, 1, 11, 111, 255, 0xfff, 0x7fff, -0x7fff}
+	vals := []int16{0, 1, 11, 111, 255, 0xfff, 0x7fff, -0x8000}
 	for _, val := range vals {
 		t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
 			should := require.New(t)
@@ -260,7 +260,7 @@ func Test_write_uint32(t *testing.T) {
 }
 
 func Test_write_int32(t *testing.T) {
-	vals := []int32{0, 1, 11, 111, 255, 999999, 0xfff, 0xffff, 0xfffff, 0xffffff, 0xfffffff, 0x7fffffff, -0x7fffffff}
+	vals := []int32{0, 1, 11, 111, 255, 999999, 0xfff, 0xffff, 0xfffff, 0xffffff, 0xfffffff, 0x7fffffff, -0x80000000}
 	for _, val := range vals {
 		t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
 			should := require.New(t)
@@ -328,7 +328,7 @@ func Test_write_uint64(t *testing.T) {
 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}
+		0xfffffffffffffff, 0x7fffffffffffffff, -0x8000000000000000}
 	for _, val := range vals {
 		t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
 			should := require.New(t)