Tao Wen 9 năm trước cách đây
mục cha
commit
c457aeaac2
2 tập tin đã thay đổi với 92 bổ sung27 xóa
  1. 63 25
      jsoniter.go
  2. 29 2
      jsoniter_array_test.go

+ 63 - 25
jsoniter.go

@@ -26,7 +26,6 @@ func init() {
 	}
 }
 
-
 type Iterator struct {
 	reader io.Reader
 	buf    []byte
@@ -57,14 +56,30 @@ func ParseBytes(input []byte) *Iterator {
 	return iter
 }
 
+func (iter *Iterator) Reuse(input []byte) *Iterator {
+	// only for benchmarking
+	iter.reader = nil
+	iter.Error = nil
+	iter.buf = input
+	iter.head = 0
+	iter.tail = len(input)
+	iter.skipWhitespaces()
+	return iter
+}
+
 func ParseString(input string) *Iterator {
 	return ParseBytes([]byte(input))
 }
 
 func (iter *Iterator) skipWhitespaces() {
 	c := iter.readByte()
-	for c == ' ' || c == '\n' || c == '\t' {
-		c = iter.readByte()
+	for {
+		switch c {
+		case ' ', '\n', '\t', 'r':
+			c = iter.readByte()
+			continue
+		}
+		break
 	}
 	iter.unreadByte()
 }
@@ -258,29 +273,20 @@ func (iter *Iterator) ReadInt64() (ret int64) {
 func (iter *Iterator) ReadString() (ret string) {
 	str := make([]byte, 0, 8)
 	c := iter.readByte()
-	if iter.Error != nil {
+	if c == 'n' {
+		iter.skipNull()
 		return
 	}
-	switch c {
-	case 'n':
-		iter.skipNull()
-		if iter.Error != nil {
-			return
-		}
-		return ""
-	case '"':
-	// nothing
-	default:
+	if c != '"' {
 		iter.ReportError("ReadString", `expects " or n`)
 		return
 	}
-	for {
+	for iter.Error == nil {
 		c = iter.readByte()
-		if iter.Error != nil {
-			return
+		if c == '"' {
+			return string(str)
 		}
-		switch c {
-		case '\\':
+		if c == '\\' {
 			c = iter.readByte()
 			if iter.Error != nil {
 				return
@@ -340,12 +346,11 @@ func (iter *Iterator) ReadString() (ret string) {
 					`invalid escape char after \`)
 				return
 			}
-		case '"':
-			return *(*string)(unsafe.Pointer(&str))
-		default:
+		} else {
 			str = append(str, c)
 		}
 	}
+	return
 }
 
 func (iter *Iterator) readU4() (ret rune) {
@@ -434,9 +439,6 @@ func (iter *Iterator) ReadArray() (ret bool) {
 	switch c {
 	case 'n': {
 		iter.skipNull()
-		if iter.Error != nil {
-			return
-		}
 		return false // null
 	}
 	case '[': {
@@ -462,6 +464,42 @@ func (iter *Iterator) ReadArray() (ret bool) {
 	}
 }
 
+func (iter *Iterator) ReadArrayCB(cb func()) {
+	iter.skipWhitespaces()
+	c := iter.readByte()
+	if c == 'n' {
+		iter.skipNull()
+		return // null
+	}
+	if c != '[' {
+		iter.ReportError("ReadArray", "expect [ or n")
+		return
+	}
+	iter.skipWhitespaces()
+	c = iter.readByte()
+	if c == ']' {
+		return // []
+	} else {
+		iter.unreadByte()
+	}
+	for {
+		if iter.Error != nil {
+			return
+		}
+		cb()
+		iter.skipWhitespaces()
+		c = iter.readByte()
+		if c == ']' {
+			return
+		}
+		if c != ',' {
+			iter.ReportError("ReadArray", "expect , or ]")
+			return
+		}
+		iter.skipWhitespaces()
+	}
+}
+
 func (iter *Iterator) ReadObject() (ret string) {
 	iter.skipWhitespaces()
 	c := iter.readByte()

+ 29 - 2
jsoniter_array_test.go

@@ -50,6 +50,17 @@ func Test_two_elements(t *testing.T) {
 	}
 }
 
+func Test_two_elements_cb(t *testing.T) {
+	iter := ParseString(`[1,2]`)
+	total := int64(0)
+	iter.ReadArrayCB(func() {
+		total += iter.ReadInt64()
+	})
+	if total != 3 {
+		t.Fatal(total)
+	}
+}
+
 func Test_invalid_array(t *testing.T) {
 	iter := ParseString(`[`)
 	iter.ReadArray()
@@ -117,16 +128,32 @@ func Test_whitespace_before_comma(t *testing.T) {
 	}
 }
 
-
 func Benchmark_jsoniter_array(b *testing.B) {
+	b.ReportAllocs()
+	input := []byte(`[1,2,3,4,5,6,7,8,9]`)
+	iter := ParseBytes(input)
+	b.ResetTimer()
 	for n := 0; n < b.N; n++ {
-		iter := ParseString(`[1,2,3]`)
+		iter.Reuse(input)
 		for iter.ReadArray() {
 			iter.ReadUint64()
 		}
 	}
 }
 
+func Benchmark_jsoniter_array_cb(b *testing.B) {
+	b.ReportAllocs()
+	input := []byte(`[1,2,3,4,5,6,7,8,9]`)
+	iter := ParseBytes(input)
+	b.ResetTimer()
+	for n := 0; n < b.N; n++ {
+		iter.Reuse(input)
+		iter.ReadArrayCB(func() {
+			iter.ReadUint64()
+		})
+	}
+}
+
 func Benchmark_json_array(b *testing.B) {
 	for n := 0; n < b.N; n++ {
 		result := []interface{}{}