Skip to content

Commit

Permalink
add encoder support UintExceedToString
Browse files Browse the repository at this point in the history
  • Loading branch information
period331 committed Jan 2, 2025
1 parent 3f2445c commit fcd8778
Show file tree
Hide file tree
Showing 8 changed files with 323 additions and 147 deletions.
9 changes: 6 additions & 3 deletions api.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,12 @@ type Config struct {
// Encode Infinity or Nan float into `null`, instead of returning an error.
EncodeNullForInfOrNan bool

// Uint64 or Int64 into strings on Marshal
Uint64ToString bool
Int64ToString bool
// Uint64 or Int64 into strings on Marshal
Uint64ToString bool
Int64ToString bool
// UintExceedToString when intSize == 64, if the value of type uint or uint64 exceeds MaxInt64,
// automatically convert it to a string.
UintExceedToString bool
}

var (
Expand Down
398 changes: 266 additions & 132 deletions encode_test.go

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions encoder/encoder_native.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ const (
// Uint64 or Int64 into strings on Marshal
Uint64ToString Options = encoder.Uint64ToString
Int64ToString Options = encoder.Int64ToString
// UintExceedToString when intSize == 64, if the value of type uint or uint64 exceeds MaxInt64,
// automatically convert it to a string.
UintExceedToString Options = encoder.UintExceedToString
)


Expand Down
1 change: 1 addition & 0 deletions internal/encoder/alg/opts.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const (
BitEncodeNullForInfOrNan
BitUint64ToString
BitInt64ToString
BitUintExceedToString

BitPointerValue = 63
)
3 changes: 3 additions & 0 deletions internal/encoder/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ const (
// Uint64 or Int64 into strings on Marshal
Uint64ToString Options = 1 << alg.BitUint64ToString
Int64ToString Options = 1 << alg.BitInt64ToString
// UintExceedToString when intSize == 64, if the value of type uint or uint64 exceeds MaxInt64,
// automatically convert it to a string.
UintExceedToString Options = 1 << alg.BitUintExceedToString
)

// Encoder represents a specific set of encoder configurations.
Expand Down
20 changes: 15 additions & 5 deletions internal/encoder/vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,17 +161,27 @@ func Execute(b *[]byte, p unsafe.Pointer, s *vars.Stack, flags uint64, prog *ir.
v := *(*uint32)(p)
buf = alg.U64toa(buf, uint64(v))
case ir.OP_u64:
if ins.CompatOp() == ir.OP_u ||
ins.IsMapKey() ||
flags&(1<<alg.BitUint64ToString) == 0 {
if ins.IsMapKey() {
v := *(*uint64)(p)
buf = alg.U64toa(buf, uint64(v))
continue
}
buf = append(buf, '"')
quote := false
v := *(*uint64)(p)

if (ins.CompatOp() == ir.OP_u64 && // current value type == uint64
flags&(1<<alg.BitUint64ToString) != 0) ||
(v > uint64(math.MaxInt64) &&
flags&(1<<alg.BitUintExceedToString) != 0) {
quote = true
}
if quote {
buf = append(buf, '"')
}
buf = alg.U64toa(buf, uint64(v))
buf = append(buf, '"')
if quote {
buf = append(buf, '"')
}
case ir.OP_f32:
v := *(*float32)(p)
if math.IsNaN(float64(v)) || math.IsInf(float64(v), 0) {
Expand Down
33 changes: 26 additions & 7 deletions internal/encoder/x86/assembler_regabi_amd64.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ const (
const (
_FM_exp32 = 0x7f800000
_FM_exp64 = 0x7ff0000000000000
_FM_maxint64 = 1<<63 - 1
)

const (
Expand Down Expand Up @@ -875,20 +876,38 @@ func (self *Assembler) _asm_OP_u32(_ *ir.Instr) {
}

func (self *Assembler) _asm_OP_u64(i *ir.Instr) {
if i.CompatOp() == ir.OP_u || i.IsMapKey() {
if i.IsMapKey() {
self.store_int(20, _F_u64toa, "MOVQ")
return
}
self.Emit("BTQ", jit.Imm(int64(alg.BitUint64ToString)), _ARG_fv)
self.Sjmp("JC", "_ui64_to_string{n}")
self.store_int(20, _F_u64toa, "MOVQ")
self.Sjmp("JMP", "_ui64_to_string_end{n}")
self.Link("_ui64_to_string{n}")

if i.CompatOp() == ir.OP_u64 { // current value type == uint64
self.Emit("BTQ", jit.Imm(int64(alg.BitUint64ToString)), _ARG_fv)
self.Sjmp("JC", "_u64_force_to_string{n}")
}

if ir.OP_uint() == ir.OP_u64 { // intSize == 64
self.Emit("BTQ", jit.Imm(int64(alg.BitUintExceedToString)), _ARG_fv)
self.Sjmp("JNC", "_u64_keep_integer{n}")

self.Emit("MOVQ", jit.Ptr(_SP_p, 0), _AX)
self.Emit("MOVQ", jit.Imm(_FM_maxint64), _BX)
self.Emit("CMPQ", _AX, _BX)
self.Sjmp("JBE", "_u64_keep_integer{n}")
self.Sjmp("JMP", "_u64_force_to_string{n}")
} else {
self.Sjmp("JMP", "_u64_keep_integer{n}")
}

self.Link("_u64_force_to_string{n}")
self.add_char('"')
self.store_int(20, _F_u64toa, "MOVQ")
self.add_char('"')
self.Link("_ui64_to_string_end{n}")
self.Sjmp("JMP", "_u64_to_string_end{n}")

self.Link("_u64_keep_integer{n}")
self.store_int(20, _F_u64toa, "MOVQ")
self.Link("_u64_to_string_end{n}")
}

func (self *Assembler) _asm_OP_f32(_ *ir.Instr) {
Expand Down
3 changes: 3 additions & 0 deletions sonic.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ func (cfg Config) Froze() API {
if cfg.Int64ToString {
api.encoderOpts |= encoder.Int64ToString
}
if cfg.UintExceedToString {
api.encoderOpts |= encoder.UintExceedToString
}

// configure decoder options:
if cfg.NoValidateJSONSkip {
Expand Down

0 comments on commit fcd8778

Please sign in to comment.