mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-01-22 06:10:20 +00:00
[chore]: Bump github.com/gin-contrib/gzip from 1.0.1 to 1.1.0 (#3639)
Bumps [github.com/gin-contrib/gzip](https://github.com/gin-contrib/gzip) from 1.0.1 to 1.1.0. - [Release notes](https://github.com/gin-contrib/gzip/releases) - [Changelog](https://github.com/gin-contrib/gzip/blob/master/.goreleaser.yaml) - [Commits](https://github.com/gin-contrib/gzip/compare/v1.0.1...v1.1.0) --- updated-dependencies: - dependency-name: github.com/gin-contrib/gzip dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
parent
8cfae010a9
commit
4d423102c1
22
go.mod
22
go.mod
|
@ -47,7 +47,7 @@ require (
|
|||
github.com/buckket/go-blurhash v1.1.0
|
||||
github.com/coreos/go-oidc/v3 v3.11.0
|
||||
github.com/gin-contrib/cors v1.7.2
|
||||
github.com/gin-contrib/gzip v1.0.1
|
||||
github.com/gin-contrib/gzip v1.1.0
|
||||
github.com/gin-contrib/sessions v1.0.1
|
||||
github.com/gin-gonic/gin v1.10.0
|
||||
github.com/go-playground/form/v4 v4.2.1
|
||||
|
@ -93,7 +93,7 @@ require (
|
|||
go.uber.org/automaxprocs v1.6.0
|
||||
golang.org/x/crypto v0.31.0
|
||||
golang.org/x/image v0.23.0
|
||||
golang.org/x/net v0.32.0
|
||||
golang.org/x/net v0.33.0
|
||||
golang.org/x/oauth2 v0.24.0
|
||||
golang.org/x/text v0.21.0
|
||||
gopkg.in/mcuadros/go-syslog.v2 v2.3.0
|
||||
|
@ -114,8 +114,8 @@ require (
|
|||
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/buger/jsonparser v1.1.1 // indirect
|
||||
github.com/bytedance/sonic v1.11.6 // indirect
|
||||
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
||||
github.com/bytedance/sonic v1.12.6 // indirect
|
||||
github.com/bytedance/sonic/loader v0.2.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/cilium/ebpf v0.9.1 // indirect
|
||||
|
@ -133,7 +133,7 @@ require (
|
|||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.7 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-errors/errors v1.1.1 // indirect
|
||||
github.com/go-fed/httpsig v1.1.0 // indirect
|
||||
|
@ -154,9 +154,9 @@ require (
|
|||
github.com/go-openapi/validate v0.24.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
||||
github.com/go-playground/validator/v10 v10.23.0 // indirect
|
||||
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b // indirect
|
||||
github.com/goccy/go-json v0.10.3 // indirect
|
||||
github.com/goccy/go-json v0.10.4 // indirect
|
||||
github.com/godbus/dbus/v5 v5.0.4 // indirect
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d // indirect
|
||||
|
@ -179,7 +179,7 @@ require (
|
|||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
|
@ -196,7 +196,7 @@ require (
|
|||
github.com/ncruces/julianday v1.0.0 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.0.2 // indirect
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
|
@ -231,7 +231,7 @@ require (
|
|||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/arch v0.8.0 // indirect
|
||||
golang.org/x/arch v0.12.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect
|
||||
golang.org/x/mod v0.18.0 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
|
@ -240,7 +240,7 @@ require (
|
|||
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
||||
google.golang.org/grpc v1.66.1 // indirect
|
||||
google.golang.org/protobuf v1.34.2 // indirect
|
||||
google.golang.org/protobuf v1.36.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect
|
||||
|
|
49
go.sum
generated
49
go.sum
generated
|
@ -105,10 +105,11 @@ github.com/buckket/go-blurhash v1.1.0 h1:X5M6r0LIvwdvKiUtiNcRL2YlmOfMzYobI3VCKCZ
|
|||
github.com/buckket/go-blurhash v1.1.0/go.mod h1:aT2iqo5W9vu9GpyoLErKfTHwgODsZp3bQfXjXJUxNb8=
|
||||
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
|
||||
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
|
||||
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
|
||||
github.com/bytedance/sonic v1.12.6 h1:/isNmCUF2x3Sh8RAp/4mh4ZGkcFAX/hLrzrK3AvpRzk=
|
||||
github.com/bytedance/sonic v1.12.6/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
|
||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/bytedance/sonic/loader v0.2.1 h1:1GgorWTqf12TA8mma4DDSbaQigE2wOgQo7iCjjJv3+E=
|
||||
github.com/bytedance/sonic/loader v0.2.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
|
@ -176,14 +177,14 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos
|
|||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/fxamacker/cbor v1.5.1 h1:XjQWBgdmQyqimslUh5r4tUGmoqzHmBFQOImkWGi2awg=
|
||||
github.com/fxamacker/cbor v1.5.1/go.mod h1:3aPGItF174ni7dDzd6JZ206H8cmr4GDNBGpPa971zsU=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||
github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA=
|
||||
github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU=
|
||||
github.com/gavv/httpexpect v2.0.0+incompatible h1:1X9kcRshkSKEjNJJxX9Y9mQ5BRfbxU5kORdjhlA1yX8=
|
||||
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
|
||||
github.com/gin-contrib/cors v1.7.2 h1:oLDHxdg8W/XDoN/8zamqk/Drgt4oVZDvaV0YmvVICQw=
|
||||
github.com/gin-contrib/cors v1.7.2/go.mod h1:SUJVARKgQ40dmrzgXEVxj2m7Ig1v1qIboQkPDTQ9t2E=
|
||||
github.com/gin-contrib/gzip v1.0.1 h1:HQ8ENHODeLY7a4g1Au/46Z92bdGFl74OhxcZble9WJE=
|
||||
github.com/gin-contrib/gzip v1.0.1/go.mod h1:njt428fdUNRvjuJf16tZMYZ2Yl+WQB53X5wmhDwXvC4=
|
||||
github.com/gin-contrib/gzip v1.1.0 h1:kVw7Nr9M+Z6Ch4qo7aGMbiqxDeyQFru+07MgAcUF62M=
|
||||
github.com/gin-contrib/gzip v1.1.0/go.mod h1:iHJXCup4CWiKyPUEl+GwkHjchl+YyYuMKbOCiXujPIA=
|
||||
github.com/gin-contrib/sessions v1.0.1 h1:3hsJyNs7v7N8OtelFmYXFrulAf6zSR7nW/putcPEHxI=
|
||||
github.com/gin-contrib/sessions v1.0.1/go.mod h1:ouxSFM24/OgIud5MJYQJLpy6AwxQ5EYO9yLhbtObGkM=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
|
@ -239,15 +240,15 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
|
|||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
|
||||
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o=
|
||||
github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
github.com/go-session/session v3.1.2+incompatible/go.mod h1:8B3iivBQjrz/JtC68Np2T1yBBLxTan3mn/3OM0CyRt0=
|
||||
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
|
||||
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b h1:khEcpUM4yFcxg4/FHQWkvVRmgijNXRfzkIDHh23ggEo=
|
||||
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
|
||||
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
|
||||
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM=
|
||||
github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||
|
@ -385,8 +386,8 @@ github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IX
|
|||
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
|
||||
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
|
@ -452,8 +453,8 @@ github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNia
|
|||
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
|
@ -516,7 +517,6 @@ github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+
|
|||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
|
@ -526,8 +526,6 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
|
@ -665,9 +663,8 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
|||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
|
||||
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/arch v0.12.0 h1:UsYJhbzPYGsT0HbEdmYcqtCv8UNGvnaL561NnIUvaKg=
|
||||
golang.org/x/arch v0.12.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
|
@ -746,8 +743,8 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
|
|||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
|
||||
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
|
||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -805,7 +802,6 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
|
@ -953,8 +949,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
|
|||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
|
||||
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
@ -1012,6 +1008,5 @@ mvdan.cc/xurls/v2 v2.5.0 h1:lyBNOm8Wo71UknhUs4QTFUNNMyxy2JEIaKKo0RWOh+8=
|
|||
mvdan.cc/xurls/v2 v2.5.0/go.mod h1:yQgaGQ1rFtJUzkmKiHYSSfuQxqfYmd//X6PxvholpeE=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
|
5
vendor/github.com/bytedance/sonic/.gitignore
generated
vendored
5
vendor/github.com/bytedance/sonic/.gitignore
generated
vendored
|
@ -49,4 +49,7 @@ ast/bench.sh
|
|||
|
||||
!testdata/*.json.gz
|
||||
fuzz/testdata
|
||||
*__debug_bin
|
||||
*__debug_bin*
|
||||
*pprof
|
||||
*coverage.txt
|
||||
tools/venv/*
|
48
vendor/github.com/bytedance/sonic/README.md
generated
vendored
48
vendor/github.com/bytedance/sonic/README.md
generated
vendored
|
@ -6,9 +6,9 @@ A blazingly fast JSON serializing & deserializing library, accelerated by JI
|
|||
|
||||
## Requirement
|
||||
|
||||
- Go 1.16~1.22
|
||||
- Linux / MacOS / Windows(need go1.17 above)
|
||||
- Amd64 ARCH
|
||||
- Go: 1.17~1.23
|
||||
- OS: Linux / MacOS / Windows
|
||||
- CPU: AMD64 / ARM64(need go1.20 above)
|
||||
|
||||
## Features
|
||||
|
||||
|
@ -282,6 +282,22 @@ sub := root.Get("key3").Index(2).Int64() // == 3
|
|||
|
||||
**Tip**: since `Index()` uses offset to locate data, which is much faster than scanning like `Get()`, we suggest you use it as much as possible. And sonic also provides another API `IndexOrGet()` to underlying use offset as well as ensure the key is matched.
|
||||
|
||||
#### SearchOption
|
||||
|
||||
`Searcher` provides some options for user to meet different needs:
|
||||
|
||||
```go
|
||||
opts := ast.SearchOption{ CopyReturn: true ... }
|
||||
val, err := sonic.GetWithOptions(JSON, opts, "key")
|
||||
```
|
||||
|
||||
- CopyReturn
|
||||
Indicate the searcher to copy the result JSON string instead of refer from the input. This can help to reduce memory usage if you cache the results
|
||||
- ConcurentRead
|
||||
Since `ast.Node` use `Lazy-Load` design, it doesn't support Concurrently-Read by default. If you want to read it concurrently, please specify it.
|
||||
- ValidateJSON
|
||||
Indicate the searcher to validate the entire JSON. This option is enabled by default, which slow down the search speed a little.
|
||||
|
||||
#### Set/Unset
|
||||
|
||||
Modify the json content by Set()/Unset()
|
||||
|
@ -368,16 +384,12 @@ See [ast/visitor.go](https://github.com/bytedance/sonic/blob/main/ast/visitor.go
|
|||
|
||||
## Compatibility
|
||||
|
||||
Sonic **DOES NOT** ensure to support all environments, due to the difficulty of developing high-performance codes. For developers who use sonic to build their applications in different environments, we have the following suggestions:
|
||||
For developers who want to use sonic to meet diffirent scenarios, we provide some integrated configs as `sonic.API`
|
||||
|
||||
- Developing on **Mac M1**: Make sure you have Rosetta 2 installed on your machine, and set `GOARCH=amd64` when building your application. Rosetta 2 can automatically translate x86 binaries to arm64 binaries and run x86 applications on Mac M1.
|
||||
- Developing on **Linux arm64**: You can install qemu and use the `qemu-x86_64 -cpu max` command to convert x86 binaries to amr64 binaries for applications built with sonic. The qemu can achieve a similar transfer effect to Rosetta 2 on Mac M1.
|
||||
|
||||
For developers who want to use sonic on Linux arm64 without qemu, or those who want to handle JSON strictly consistent with `encoding/json`, we provide some compatible APIs as `sonic.API`
|
||||
|
||||
- `ConfigDefault`: the sonic's default config (`EscapeHTML=false`,`SortKeys=false`...) to run on sonic-supporting environment. It will fall back to `encoding/json` with the corresponding config, and some options like `SortKeys=false` will be invalid.
|
||||
- `ConfigStd`: the std-compatible config (`EscapeHTML=true`,`SortKeys=true`...) to run on sonic-supporting environment. It will fall back to `encoding/json`.
|
||||
- `ConfigFastest`: the fastest config (`NoQuoteTextMarshaler=true`) to run on sonic-supporting environment. It will fall back to `encoding/json` with the corresponding config, and some options will be invalid.
|
||||
- `ConfigDefault`: the sonic's default config (`EscapeHTML=false`,`SortKeys=false`...) to run sonic fast meanwhile ensure security.
|
||||
- `ConfigStd`: the std-compatible config (`EscapeHTML=true`,`SortKeys=true`...)
|
||||
- `ConfigFastest`: the fastest config (`NoQuoteTextMarshaler=true`) to run on sonic as fast as possible.
|
||||
Sonic **DOES NOT** ensure to support all environments, due to the difficulty of developing high-performance codes. On non-sonic-supporting environment, the implementation will fall back to `encoding/json`. Thus beflow configs will all equal to `ConfigStd`.
|
||||
|
||||
## Tips
|
||||
|
||||
|
@ -466,6 +478,18 @@ For better performance, in previous case the `ast.Visitor` will be the better ch
|
|||
|
||||
But `ast.Visitor` is not a very handy API. You might need to write a lot of code to implement your visitor and carefully maintain the tree hierarchy during decoding. Please read the comments in [ast/visitor.go](https://github.com/bytedance/sonic/blob/main/ast/visitor.go) carefully if you decide to use this API.
|
||||
|
||||
### Buffer Size
|
||||
|
||||
Sonic use memory pool in many places like `encoder.Encode`, `ast.Node.MarshalJSON` to improve performace, which may produce more memory usage (in-use) when server's load is high. See [issue 614](https://github.com/bytedance/sonic/issues/614). Therefore, we introduce some options to let user control the behavior of memory pool. See [option](https://pkg.go.dev/github.com/bytedance/sonic@v1.11.9/option#pkg-variables) package.
|
||||
|
||||
### Faster JSON skip
|
||||
|
||||
For security, sonic use [FSM](native/skip_one.c) algorithm to validate JSON when decoding raw JSON or encoding `json.Marshaler`, which is much slower (1~10x) than [SIMD-searching-pair](native/skip_one_fast.c) algorithm. If user has many redundant JSON value and DO NOT NEED to strictly validate JSON correctness, you can enable below options:
|
||||
|
||||
- `Config.NoValidateSkipJSON`: for faster skipping JSON when decoding, such as unknown fields, json.Unmarshaler(json.RawMessage), mismatched values, and redundant array elements
|
||||
- `Config.NoValidateJSONMarshaler`: avoid validating JSON when encoding `json.Marshaler`
|
||||
- `SearchOption.ValidateJSON`: indicates if validate located JSON value when `Get`
|
||||
|
||||
## Community
|
||||
|
||||
Sonic is a subproject of [CloudWeGo](https://www.cloudwego.io/). We are committed to building a cloud native ecosystem.
|
||||
|
|
50
vendor/github.com/bytedance/sonic/README_ZH_CN.md
generated
vendored
50
vendor/github.com/bytedance/sonic/README_ZH_CN.md
generated
vendored
|
@ -6,9 +6,9 @@
|
|||
|
||||
## 依赖
|
||||
|
||||
- Go 1.16~1.22
|
||||
- Linux / MacOS / Windows(需要 Go1.17 以上)
|
||||
- Amd64 架构
|
||||
- Go: 1.17~1.23
|
||||
- OS: Linux / MacOS / Windows
|
||||
- CPU: AMD64 / ARM64(需要 Go1.20 以上)
|
||||
|
||||
## 接口
|
||||
|
||||
|
@ -260,7 +260,7 @@ fmt.Printf("%+v", data) // {A:0 B:1}
|
|||
|
||||
### `Ast.Node`
|
||||
|
||||
Sonic/ast.Node 是完全独立的 JSON 抽象语法树库。它实现了序列化和反序列化,并提供了获取和修改通用数据的鲁棒的 API。
|
||||
Sonic/ast.Node 是完全独立的 JSON 抽象语法树库。它实现了序列化和反序列化,并提供了获取和修改JSON数据的鲁棒的 API。
|
||||
|
||||
#### 查找/索引
|
||||
|
||||
|
@ -282,6 +282,22 @@ sub := root.Get("key3").Index(2).Int64() // == 3
|
|||
|
||||
**注意**:由于 `Index()` 使用偏移量来定位数据,比使用扫描的 `Get()` 要快的多,建议尽可能的使用 `Index` 。 Sonic 也提供了另一个 API, `IndexOrGet()` ,以偏移量为基础并且也确保键的匹配。
|
||||
|
||||
#### 查找选项
|
||||
|
||||
`ast.Searcher`提供了一些选项,以满足用户的不同需求:
|
||||
|
||||
```go
|
||||
opts := ast.SearchOption{CopyReturn: true…}
|
||||
val, err := sonic.GetWithOptions(JSON, opts, "key")
|
||||
```
|
||||
|
||||
- CopyReturn
|
||||
指示搜索器复制结果JSON字符串,而不是从输入引用。如果用户缓存结果,这有助于减少内存使用
|
||||
- ConcurentRead
|
||||
因为`ast.Node`使用`Lazy-Load`设计,默认不支持并发读取。如果您想同时读取,请指定它。
|
||||
- ValidateJSON
|
||||
指示搜索器来验证整个JSON。默认情况下启用该选项, 但是对于查找速度有一定影响。
|
||||
|
||||
#### 修改
|
||||
|
||||
使用 `Set()` / `Unset()` 修改 json 的内容
|
||||
|
@ -368,16 +384,12 @@ type Visitor interface {
|
|||
|
||||
## 兼容性
|
||||
|
||||
由于开发高性能代码的困难性, Sonic **不**保证对所有环境的支持。对于在不同环境中使用 Sonic 构建应用程序的开发者,我们有以下建议:
|
||||
对于想要使用sonic来满足不同场景的开发人员,我们提供了一些集成配置:
|
||||
|
||||
- 在 **Mac M1** 上开发:确保在您的计算机上安装了 Rosetta 2,并在构建时设置 `GOARCH=amd64` 。 Rosetta 2 可以自动将 x86 二进制文件转换为 arm64 二进制文件,并在 Mac M1 上运行 x86 应用程序。
|
||||
- 在 **Linux arm64** 上开发:您可以安装 qemu 并使用 `qemu-x86_64 -cpu max` 命令来将 x86 二进制文件转换为 arm64 二进制文件。qemu可以实现与Mac M1上的Rosetta 2类似的转换效果。
|
||||
|
||||
对于希望在不使用 qemu 下使用 sonic 的开发者,或者希望处理 JSON 时与 `encoding/JSON` 严格保持一致的开发者,我们在 `sonic.API` 中提供了一些兼容性 API
|
||||
|
||||
- `ConfigDefault`: 在支持 sonic 的环境下 sonic 的默认配置(`EscapeHTML=false`,`SortKeys=false`等)。行为与具有相应配置的 `encoding/json` 一致,一些选项,如 `SortKeys=false` 将无效。
|
||||
- `ConfigStd`: 在支持 sonic 的环境下与标准库兼容的配置(`EscapeHTML=true`,`SortKeys=true`等)。行为与 `encoding/json` 一致。
|
||||
- `ConfigFastest`: 在支持 sonic 的环境下运行最快的配置(`NoQuoteTextMarshaler=true`)。行为与具有相应配置的 `encoding/json` 一致,某些选项将无效。
|
||||
- `ConfigDefault`: sonic的默认配置 (`EscapeHTML=false`, `SortKeys=false`…) 保证性能同时兼顾安全性。
|
||||
- `ConfigStd`: 与 `encoding/json` 保证完全兼容的配置
|
||||
- `ConfigFastest`: 最快的配置(`NoQuoteTextMarshaler=true...`) 保证性能最优但是会缺少一些安全性检查(validate UTF8 等)
|
||||
Sonic **不**确保支持所有环境,由于开发高性能代码的困难。在不支持sonic的环境中,实现将回落到 `encoding/json`。因此上述配置将全部等于`ConfigStd`。
|
||||
|
||||
## 注意事项
|
||||
|
||||
|
@ -464,6 +476,18 @@ go someFunc(user)
|
|||
|
||||
但是,`ast.Visitor` 并不是一个很易用的 API。你可能需要写大量的代码去实现自己的 `ast.Visitor`,并且需要在解析过程中仔细维护树的层级。如果你决定要使用这个 API,请先仔细阅读 [ast/visitor.go](https://github.com/bytedance/sonic/blob/main/ast/visitor.go) 中的注释。
|
||||
|
||||
### 缓冲区大小
|
||||
|
||||
Sonic在许多地方使用内存池,如`encoder.Encode`, `ast.Node.MarshalJSON`等来提高性能,这可能会在服务器负载高时产生更多的内存使用(in-use)。参见[issue 614](https://github.com/bytedance/sonic/issues/614)。因此,我们引入了一些选项来让用户配置内存池的行为。参见[option](https://pkg.go.dev/github.com/bytedance/sonic@v1.11.9/option#pkg-variables)包。
|
||||
|
||||
### 更快的 JSON Skip
|
||||
|
||||
为了安全起见,在跳过原始JSON 时,sonic decoder 默认使用[FSM](native/skip_one.c)算法扫描来跳过同时校验 JSON。它相比[SIMD-searching-pair](native/skip_one_fast.c)算法跳过要慢得多(1~10倍)。如果用户有很多冗余的JSON值,并且不需要严格验证JSON的正确性,你可以启用以下选项:
|
||||
|
||||
- `Config.NoValidateSkipJSON`: 用于在解码时更快地跳过JSON,例如未知字段,`json.RawMessage`,不匹配的值和冗余的数组元素等
|
||||
- `Config.NoValidateJSONMarshaler`: 编码JSON时避免验证JSON。封送拆收器
|
||||
- `SearchOption.ValidateJSON`: 指示当`Get`时是否验证定位的JSON值
|
||||
|
||||
## 社区
|
||||
|
||||
Sonic 是 [CloudWeGo](https://www.cloudwego.io/) 下的一个子项目。我们致力于构建云原生生态系统。
|
||||
|
|
33
vendor/github.com/bytedance/sonic/api.go
generated
vendored
33
vendor/github.com/bytedance/sonic/api.go
generated
vendored
|
@ -23,6 +23,16 @@
|
|||
`github.com/bytedance/sonic/internal/rt`
|
||||
)
|
||||
|
||||
const (
|
||||
// UseStdJSON indicates you are using fallback implementation (encoding/json)
|
||||
UseStdJSON = iota
|
||||
// UseSonicJSON indicates you are using real sonic implementation
|
||||
UseSonicJSON
|
||||
)
|
||||
|
||||
// APIKind is the kind of API, 0 is std json, 1 is sonic.
|
||||
const APIKind = apiKind
|
||||
|
||||
// Config is a combination of sonic/encoder.Options and sonic/decoder.Options
|
||||
type Config struct {
|
||||
// EscapeHTML indicates encoder to escape all HTML characters
|
||||
|
@ -74,9 +84,16 @@ type Config struct {
|
|||
// NoValidateJSONMarshaler indicates that the encoder should not validate the output string
|
||||
// after encoding the JSONMarshaler to JSON.
|
||||
NoValidateJSONMarshaler bool
|
||||
|
||||
// NoValidateJSONSkip indicates the decoder should not validate the JSON value when skipping it,
|
||||
// such as unknown-fields, mismatched-type, redundant elements..
|
||||
NoValidateJSONSkip bool
|
||||
|
||||
// NoEncoderNewline indicates that the encoder should not add a newline after every message
|
||||
NoEncoderNewline bool
|
||||
|
||||
// Encode Infinity or Nan float into `null`, instead of returning an error.
|
||||
EncodeNullForInfOrNan bool
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -96,6 +113,7 @@ type Config struct {
|
|||
ConfigFastest = Config{
|
||||
NoQuoteTextMarshaler: true,
|
||||
NoValidateJSONMarshaler: true,
|
||||
NoValidateJSONSkip: true,
|
||||
}.Froze()
|
||||
)
|
||||
|
||||
|
@ -157,6 +175,13 @@ func Marshal(val interface{}) ([]byte, error) {
|
|||
return ConfigDefault.Marshal(val)
|
||||
}
|
||||
|
||||
// MarshalIndent is like Marshal but applies Indent to format the output.
|
||||
// Each JSON element in the output will begin on a new line beginning with prefix
|
||||
// followed by one or more copies of indent according to the indentation nesting.
|
||||
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
|
||||
return ConfigDefault.MarshalIndent(v, prefix, indent)
|
||||
}
|
||||
|
||||
// MarshalString returns the JSON encoding string of v.
|
||||
func MarshalString(val interface{}) (string, error) {
|
||||
return ConfigDefault.MarshalToString(val)
|
||||
|
@ -189,6 +214,14 @@ func Get(src []byte, path ...interface{}) (ast.Node, error) {
|
|||
return GetCopyFromString(rt.Mem2Str(src), path...)
|
||||
}
|
||||
|
||||
//GetWithOptions searches and locates the given path from src json,
|
||||
// with specific options of ast.Searcher
|
||||
func GetWithOptions(src []byte, opts ast.SearchOptions, path ...interface{}) (ast.Node, error) {
|
||||
s := ast.NewSearcher(rt.Mem2Str(src))
|
||||
s.SearchOptions = opts
|
||||
return s.GetByPath(path...)
|
||||
}
|
||||
|
||||
// GetFromString is same with Get except src is string.
|
||||
//
|
||||
// WARNING: The returned JSON is **Referenced** from the input.
|
||||
|
|
6
vendor/github.com/bytedance/sonic/ast/api.go
generated
vendored
6
vendor/github.com/bytedance/sonic/ast/api.go
generated
vendored
|
@ -1,5 +1,5 @@
|
|||
//go:build (amd64 && go1.16 && !go1.23) || (arm64 && go1.20 && !go1.23)
|
||||
// +build amd64,go1.16,!go1.23 arm64,go1.20,!go1.23
|
||||
//go:build (amd64 && go1.17 && !go1.24) || (arm64 && go1.20 && !go1.24)
|
||||
// +build amd64,go1.17,!go1.24 arm64,go1.20,!go1.24
|
||||
|
||||
/*
|
||||
* Copyright 2022 ByteDance Inc.
|
||||
|
@ -61,7 +61,7 @@ func quote(buf *[]byte, val string) {
|
|||
}
|
||||
|
||||
// double buf size
|
||||
*b = growslice(typeByte, *b, b.Cap*2)
|
||||
*b = rt.GrowSlice(typeByte, *b, b.Cap*2)
|
||||
// ret is the complement of consumed input
|
||||
ret = ^ret
|
||||
// update input buffer
|
||||
|
|
4
vendor/github.com/bytedance/sonic/ast/api_compat.go
generated
vendored
4
vendor/github.com/bytedance/sonic/ast/api_compat.go
generated
vendored
|
@ -1,4 +1,4 @@
|
|||
// +build !amd64,!arm64 go1.23 !go1.16 arm64,!go1.20
|
||||
// +build !amd64,!arm64 go1.24 !go1.17 arm64,!go1.20
|
||||
|
||||
/*
|
||||
* Copyright 2022 ByteDance Inc.
|
||||
|
@ -27,7 +27,7 @@
|
|||
)
|
||||
|
||||
func init() {
|
||||
println("WARNING:(ast) sonic only supports Go1.16~1.22, but your environment is not suitable")
|
||||
println("WARNING:(ast) sonic only supports go1.17~1.23, but your environment is not suitable")
|
||||
}
|
||||
|
||||
func quote(buf *[]byte, val string) {
|
||||
|
|
89
vendor/github.com/bytedance/sonic/ast/buffer.go
generated
vendored
89
vendor/github.com/bytedance/sonic/ast/buffer.go
generated
vendored
|
@ -17,8 +17,10 @@
|
|||
package ast
|
||||
|
||||
import (
|
||||
`sort`
|
||||
`unsafe`
|
||||
"sort"
|
||||
"unsafe"
|
||||
|
||||
"github.com/bytedance/sonic/internal/caching"
|
||||
)
|
||||
|
||||
type nodeChunk [_DEFAULT_NODE_CAP]Node
|
||||
|
@ -90,18 +92,11 @@ func (self *linkedNodes) Pop() {
|
|||
self.size--
|
||||
}
|
||||
|
||||
func (self *linkedPairs) Pop() {
|
||||
if self == nil || self.size == 0 {
|
||||
return
|
||||
}
|
||||
self.Set(self.size-1, Pair{})
|
||||
self.size--
|
||||
}
|
||||
|
||||
func (self *linkedNodes) Push(v Node) {
|
||||
self.Set(self.size, v)
|
||||
}
|
||||
|
||||
|
||||
func (self *linkedNodes) Set(i int, v Node) {
|
||||
if i < _DEFAULT_NODE_CAP {
|
||||
self.head[i] = v
|
||||
|
@ -195,11 +190,22 @@ func (self *linkedNodes) FromSlice(con []Node) {
|
|||
type pairChunk [_DEFAULT_NODE_CAP]Pair
|
||||
|
||||
type linkedPairs struct {
|
||||
index map[uint64]int
|
||||
head pairChunk
|
||||
tail []*pairChunk
|
||||
size int
|
||||
}
|
||||
|
||||
func (self *linkedPairs) BuildIndex() {
|
||||
if self.index == nil {
|
||||
self.index = make(map[uint64]int, self.size)
|
||||
}
|
||||
for i:=0; i<self.size; i++ {
|
||||
p := self.At(i)
|
||||
self.index[p.hash] = i
|
||||
}
|
||||
}
|
||||
|
||||
func (self *linkedPairs) Cap() int {
|
||||
if self == nil {
|
||||
return 0
|
||||
|
@ -233,7 +239,31 @@ func (self *linkedPairs) Push(v Pair) {
|
|||
self.Set(self.size, v)
|
||||
}
|
||||
|
||||
func (self *linkedPairs) Pop() {
|
||||
if self == nil || self.size == 0 {
|
||||
return
|
||||
}
|
||||
self.Unset(self.size-1)
|
||||
self.size--
|
||||
}
|
||||
|
||||
func (self *linkedPairs) Unset(i int) {
|
||||
if self.index != nil {
|
||||
p := self.At(i)
|
||||
delete(self.index, p.hash)
|
||||
}
|
||||
self.set(i, Pair{})
|
||||
}
|
||||
|
||||
func (self *linkedPairs) Set(i int, v Pair) {
|
||||
if self.index != nil {
|
||||
h := v.hash
|
||||
self.index[h] = i
|
||||
}
|
||||
self.set(i, v)
|
||||
}
|
||||
|
||||
func (self *linkedPairs) set(i int, v Pair) {
|
||||
if i < _DEFAULT_NODE_CAP {
|
||||
self.head[i] = v
|
||||
if self.size <= i {
|
||||
|
@ -276,6 +306,21 @@ func (self *linkedPairs) growTailLength(l int) {
|
|||
|
||||
// linear search
|
||||
func (self *linkedPairs) Get(key string) (*Pair, int) {
|
||||
if self.index != nil {
|
||||
// fast-path
|
||||
i, ok := self.index[caching.StrHash(key)]
|
||||
if ok {
|
||||
n := self.At(i)
|
||||
if n.Key == key {
|
||||
return n, i
|
||||
}
|
||||
// hash conflicts
|
||||
goto linear_search
|
||||
} else {
|
||||
return nil, -1
|
||||
}
|
||||
}
|
||||
linear_search:
|
||||
for i:=0; i<self.size; i++ {
|
||||
if n := self.At(i); n.Key == key {
|
||||
return n, i
|
||||
|
@ -313,15 +358,27 @@ func (self *linkedPairs) ToMap(con map[string]Node) {
|
|||
}
|
||||
}
|
||||
|
||||
func (self *linkedPairs) copyPairs(to []Pair, from []Pair, l int) {
|
||||
copy(to, from)
|
||||
if self.index != nil {
|
||||
for i:=0; i<l; i++ {
|
||||
// NOTICE: in case of user not pass hash, just cal it
|
||||
h := caching.StrHash(from[i].Key)
|
||||
from[i].hash = h
|
||||
self.index[h] = i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *linkedPairs) FromSlice(con []Pair) {
|
||||
self.size = len(con)
|
||||
i := self.size-1
|
||||
a, b := i/_DEFAULT_NODE_CAP-1, i%_DEFAULT_NODE_CAP
|
||||
if a < 0 {
|
||||
copy(self.head[:b+1], con)
|
||||
self.copyPairs(self.head[:b+1], con, b+1)
|
||||
return
|
||||
} else {
|
||||
copy(self.head[:], con)
|
||||
self.copyPairs(self.head[:], con, len(self.head))
|
||||
con = con[_DEFAULT_NODE_CAP:]
|
||||
}
|
||||
|
||||
|
@ -333,12 +390,12 @@ func (self *linkedPairs) FromSlice(con []Pair) {
|
|||
|
||||
for i:=0; i<a; i++ {
|
||||
self.tail[i] = new(pairChunk)
|
||||
copy(self.tail[i][:], con)
|
||||
self.copyPairs(self.tail[i][:], con, len(self.tail[i]))
|
||||
con = con[_DEFAULT_NODE_CAP:]
|
||||
}
|
||||
|
||||
self.tail[a] = new(pairChunk)
|
||||
copy(self.tail[a][:b+1], con)
|
||||
self.copyPairs(self.tail[a][:b+1], con, b+1)
|
||||
}
|
||||
|
||||
func (self *linkedPairs) Less(i, j int) bool {
|
||||
|
@ -347,6 +404,10 @@ func (self *linkedPairs) Less(i, j int) bool {
|
|||
|
||||
func (self *linkedPairs) Swap(i, j int) {
|
||||
a, b := self.At(i), self.At(j)
|
||||
if self.index != nil {
|
||||
self.index[a.hash] = j
|
||||
self.index[b.hash] = i
|
||||
}
|
||||
*a, *b = *b, *a
|
||||
}
|
||||
|
||||
|
|
86
vendor/github.com/bytedance/sonic/ast/decode.go
generated
vendored
86
vendor/github.com/bytedance/sonic/ast/decode.go
generated
vendored
|
@ -17,19 +17,23 @@
|
|||
package ast
|
||||
|
||||
import (
|
||||
`encoding/base64`
|
||||
`runtime`
|
||||
`strconv`
|
||||
`unsafe`
|
||||
"encoding/base64"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"unsafe"
|
||||
|
||||
`github.com/bytedance/sonic/internal/native/types`
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
"github.com/bytedance/sonic/internal/native/types"
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
"github.com/bytedance/sonic/internal/utils"
|
||||
)
|
||||
|
||||
const _blankCharsMask = (1 << ' ') | (1 << '\t') | (1 << '\r') | (1 << '\n')
|
||||
// Hack: this is used for both checking space and cause firendly compile errors in 32-bit arch.
|
||||
const _Sonic_Not_Support_32Bit_Arch__Checking_32Bit_Arch_Here = (1 << ' ') | (1 << '\t') | (1 << '\r') | (1 << '\n')
|
||||
|
||||
var bytesNull = []byte("null")
|
||||
|
||||
const (
|
||||
bytesNull = "null"
|
||||
strNull = "null"
|
||||
bytesTrue = "true"
|
||||
bytesFalse = "false"
|
||||
bytesObject = "{}"
|
||||
|
@ -37,7 +41,7 @@
|
|||
)
|
||||
|
||||
func isSpace(c byte) bool {
|
||||
return (int(1<<c) & _blankCharsMask) != 0
|
||||
return (int(1<<c) & _Sonic_Not_Support_32Bit_Arch__Checking_32Bit_Arch_Here) != 0
|
||||
}
|
||||
|
||||
//go:nocheckptr
|
||||
|
@ -63,7 +67,7 @@ func decodeNull(src string, pos int) (ret int) {
|
|||
if ret > len(src) {
|
||||
return -int(types.ERR_EOF)
|
||||
}
|
||||
if src[pos:ret] == bytesNull {
|
||||
if src[pos:ret] == strNull {
|
||||
return ret
|
||||
} else {
|
||||
return -int(types.ERR_INVALID_CHAR)
|
||||
|
@ -287,67 +291,7 @@ func decodeValue(src string, pos int, skipnum bool) (ret int, v types.JsonState)
|
|||
|
||||
//go:nocheckptr
|
||||
func skipNumber(src string, pos int) (ret int) {
|
||||
sp := uintptr(rt.IndexChar(src, pos))
|
||||
se := uintptr(rt.IndexChar(src, len(src)))
|
||||
if uintptr(sp) >= se {
|
||||
return -int(types.ERR_EOF)
|
||||
}
|
||||
|
||||
if c := *(*byte)(unsafe.Pointer(sp)); c == '-' {
|
||||
sp += 1
|
||||
}
|
||||
ss := sp
|
||||
|
||||
var pointer bool
|
||||
var exponent bool
|
||||
var lastIsDigit bool
|
||||
var nextNeedDigit = true
|
||||
|
||||
for ; sp < se; sp += uintptr(1) {
|
||||
c := *(*byte)(unsafe.Pointer(sp))
|
||||
if isDigit(c) {
|
||||
lastIsDigit = true
|
||||
nextNeedDigit = false
|
||||
continue
|
||||
} else if nextNeedDigit {
|
||||
return -int(types.ERR_INVALID_CHAR)
|
||||
} else if c == '.' {
|
||||
if !lastIsDigit || pointer || exponent || sp == ss {
|
||||
return -int(types.ERR_INVALID_CHAR)
|
||||
}
|
||||
pointer = true
|
||||
lastIsDigit = false
|
||||
nextNeedDigit = true
|
||||
continue
|
||||
} else if c == 'e' || c == 'E' {
|
||||
if !lastIsDigit || exponent {
|
||||
return -int(types.ERR_INVALID_CHAR)
|
||||
}
|
||||
if sp == se-1 {
|
||||
return -int(types.ERR_EOF)
|
||||
}
|
||||
exponent = true
|
||||
lastIsDigit = false
|
||||
nextNeedDigit = false
|
||||
continue
|
||||
} else if c == '-' || c == '+' {
|
||||
if prev := *(*byte)(unsafe.Pointer(sp - 1)); prev != 'e' && prev != 'E' {
|
||||
return -int(types.ERR_INVALID_CHAR)
|
||||
}
|
||||
lastIsDigit = false
|
||||
nextNeedDigit = true
|
||||
continue
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if nextNeedDigit {
|
||||
return -int(types.ERR_EOF)
|
||||
}
|
||||
|
||||
runtime.KeepAlive(src)
|
||||
return int(uintptr(sp) - uintptr((*rt.GoString)(unsafe.Pointer(&src)).Ptr))
|
||||
return utils.SkipNumber(src, pos)
|
||||
}
|
||||
|
||||
//go:nocheckptr
|
||||
|
|
55
vendor/github.com/bytedance/sonic/ast/encode.go
generated
vendored
55
vendor/github.com/bytedance/sonic/ast/encode.go
generated
vendored
|
@ -17,12 +17,11 @@
|
|||
package ast
|
||||
|
||||
import (
|
||||
`sync`
|
||||
`unicode/utf8`
|
||||
)
|
||||
"sync"
|
||||
"unicode/utf8"
|
||||
|
||||
const (
|
||||
_MaxBuffer = 1024 // 1KB buffer size
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
"github.com/bytedance/sonic/option"
|
||||
)
|
||||
|
||||
func quoteString(e *[]byte, s string) {
|
||||
|
@ -30,7 +29,7 @@ func quoteString(e *[]byte, s string) {
|
|||
start := 0
|
||||
for i := 0; i < len(s); {
|
||||
if b := s[i]; b < utf8.RuneSelf {
|
||||
if safeSet[b] {
|
||||
if rt.SafeSet[b] {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
@ -54,8 +53,8 @@ func quoteString(e *[]byte, s string) {
|
|||
// user-controlled strings are rendered into JSON
|
||||
// and served to some browsers.
|
||||
*e = append(*e, `u00`...)
|
||||
*e = append(*e, hex[b>>4])
|
||||
*e = append(*e, hex[b&0xF])
|
||||
*e = append(*e, rt.Hex[b>>4])
|
||||
*e = append(*e, rt.Hex[b&0xF])
|
||||
}
|
||||
i++
|
||||
start = i
|
||||
|
@ -76,7 +75,7 @@ func quoteString(e *[]byte, s string) {
|
|||
*e = append(*e, s[start:i]...)
|
||||
}
|
||||
*e = append(*e, `\u202`...)
|
||||
*e = append(*e, hex[c&0xF])
|
||||
*e = append(*e, rt.Hex[c&0xF])
|
||||
i += size
|
||||
start = i
|
||||
continue
|
||||
|
@ -92,16 +91,24 @@ func quoteString(e *[]byte, s string) {
|
|||
var bytesPool = sync.Pool{}
|
||||
|
||||
func (self *Node) MarshalJSON() ([]byte, error) {
|
||||
if self == nil {
|
||||
return bytesNull, nil
|
||||
}
|
||||
|
||||
buf := newBuffer()
|
||||
err := self.encode(buf)
|
||||
if err != nil {
|
||||
freeBuffer(buf)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := make([]byte, len(*buf))
|
||||
copy(ret, *buf)
|
||||
freeBuffer(buf)
|
||||
var ret []byte
|
||||
if !rt.CanSizeResue(cap(*buf)) {
|
||||
ret = *buf
|
||||
} else {
|
||||
ret = make([]byte, len(*buf))
|
||||
copy(ret, *buf)
|
||||
freeBuffer(buf)
|
||||
}
|
||||
return ret, err
|
||||
}
|
||||
|
||||
|
@ -109,21 +116,24 @@ func newBuffer() *[]byte {
|
|||
if ret := bytesPool.Get(); ret != nil {
|
||||
return ret.(*[]byte)
|
||||
} else {
|
||||
buf := make([]byte, 0, _MaxBuffer)
|
||||
buf := make([]byte, 0, option.DefaultAstBufferSize)
|
||||
return &buf
|
||||
}
|
||||
}
|
||||
|
||||
func freeBuffer(buf *[]byte) {
|
||||
if !rt.CanSizeResue(cap(*buf)) {
|
||||
return
|
||||
}
|
||||
*buf = (*buf)[:0]
|
||||
bytesPool.Put(buf)
|
||||
}
|
||||
|
||||
func (self *Node) encode(buf *[]byte) error {
|
||||
if self.IsRaw() {
|
||||
if self.isRaw() {
|
||||
return self.encodeRaw(buf)
|
||||
}
|
||||
switch self.Type() {
|
||||
switch int(self.itype()) {
|
||||
case V_NONE : return ErrNotExist
|
||||
case V_ERROR : return self.Check()
|
||||
case V_NULL : return self.encodeNull(buf)
|
||||
|
@ -139,16 +149,21 @@ func (self *Node) encode(buf *[]byte) error {
|
|||
}
|
||||
|
||||
func (self *Node) encodeRaw(buf *[]byte) error {
|
||||
raw, err := self.Raw()
|
||||
if err != nil {
|
||||
return err
|
||||
lock := self.rlock()
|
||||
if !self.isRaw() {
|
||||
self.runlock()
|
||||
return self.encode(buf)
|
||||
}
|
||||
raw := self.toString()
|
||||
if lock {
|
||||
self.runlock()
|
||||
}
|
||||
*buf = append(*buf, raw...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *Node) encodeNull(buf *[]byte) error {
|
||||
*buf = append(*buf, bytesNull...)
|
||||
*buf = append(*buf, strNull...)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
6
vendor/github.com/bytedance/sonic/ast/error.go
generated
vendored
6
vendor/github.com/bytedance/sonic/ast/error.go
generated
vendored
|
@ -17,6 +17,10 @@ func newError(err types.ParsingError, msg string) *Node {
|
|||
}
|
||||
}
|
||||
|
||||
func newErrorPair(err SyntaxError) *Pair {
|
||||
return &Pair{0, "", *newSyntaxError(err)}
|
||||
}
|
||||
|
||||
// Error returns error message if the node is invalid
|
||||
func (self Node) Error() string {
|
||||
if self.t != V_ERROR {
|
||||
|
@ -79,7 +83,7 @@ func (self SyntaxError) description() string {
|
|||
|
||||
/* check for empty source */
|
||||
if self.Src == "" {
|
||||
return fmt.Sprintf("no sources available: %#v", self)
|
||||
return fmt.Sprintf("no sources available, the input json is empty: %#v", self)
|
||||
}
|
||||
|
||||
/* prevent slicing before the beginning */
|
||||
|
|
21
vendor/github.com/bytedance/sonic/ast/iterator.go
generated
vendored
21
vendor/github.com/bytedance/sonic/ast/iterator.go
generated
vendored
|
@ -17,19 +17,29 @@
|
|||
package ast
|
||||
|
||||
import (
|
||||
`fmt`
|
||||
"fmt"
|
||||
|
||||
`github.com/bytedance/sonic/internal/native/types`
|
||||
"github.com/bytedance/sonic/internal/caching"
|
||||
"github.com/bytedance/sonic/internal/native/types"
|
||||
)
|
||||
|
||||
type Pair struct {
|
||||
hash uint64
|
||||
Key string
|
||||
Value Node
|
||||
}
|
||||
|
||||
func NewPair(key string, val Node) Pair {
|
||||
return Pair{
|
||||
hash: caching.StrHash(key),
|
||||
Key: key,
|
||||
Value: val,
|
||||
}
|
||||
}
|
||||
|
||||
// Values returns iterator for array's children traversal
|
||||
func (self *Node) Values() (ListIterator, error) {
|
||||
if err := self.should(types.V_ARRAY, "an array"); err != nil {
|
||||
if err := self.should(types.V_ARRAY); err != nil {
|
||||
return ListIterator{}, err
|
||||
}
|
||||
return self.values(), nil
|
||||
|
@ -41,7 +51,7 @@ func (self *Node) values() ListIterator {
|
|||
|
||||
// Properties returns iterator for object's children traversal
|
||||
func (self *Node) Properties() (ObjectIterator, error) {
|
||||
if err := self.should(types.V_OBJECT, "an object"); err != nil {
|
||||
if err := self.should(types.V_OBJECT); err != nil {
|
||||
return ObjectIterator{}, err
|
||||
}
|
||||
return self.properties(), nil
|
||||
|
@ -168,6 +178,9 @@ func (s Sequence) String() string {
|
|||
//
|
||||
// NOTICE: A unsetted node WON'T trigger sc, but its index still counts into Path.Index
|
||||
func (self *Node) ForEach(sc Scanner) error {
|
||||
if err := self.checkRaw(); err != nil {
|
||||
return err
|
||||
}
|
||||
switch self.itype() {
|
||||
case types.V_ARRAY:
|
||||
iter, err := self.Values()
|
||||
|
|
303
vendor/github.com/bytedance/sonic/ast/node.go
generated
vendored
303
vendor/github.com/bytedance/sonic/ast/node.go
generated
vendored
|
@ -17,13 +17,15 @@
|
|||
package ast
|
||||
|
||||
import (
|
||||
`encoding/json`
|
||||
`fmt`
|
||||
`strconv`
|
||||
`unsafe`
|
||||
|
||||
`github.com/bytedance/sonic/internal/native/types`
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
|
||||
"github.com/bytedance/sonic/internal/native/types"
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -36,7 +38,7 @@
|
|||
_V_ARRAY_LAZY = _V_LAZY | types.V_ARRAY
|
||||
_V_OBJECT_LAZY = _V_LAZY | types.V_OBJECT
|
||||
_MASK_LAZY = _V_LAZY - 1
|
||||
_MASK_RAW = _V_RAW - 1
|
||||
_MASK_RAW = _V_RAW - 1
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -56,6 +58,7 @@ type Node struct {
|
|||
t types.ValueType
|
||||
l uint
|
||||
p unsafe.Pointer
|
||||
m *sync.RWMutex
|
||||
}
|
||||
|
||||
// UnmarshalJSON is just an adapter to json.Unmarshaler.
|
||||
|
@ -79,17 +82,39 @@ func (self *Node) UnmarshalJSON(data []byte) (err error) {
|
|||
// V_STRING = 7 (json value string)
|
||||
// V_NUMBER = 33 (json value number )
|
||||
// V_ANY = 34 (golang interface{})
|
||||
//
|
||||
// Deprecated: not concurrent safe. Use TypeSafe instead
|
||||
func (self Node) Type() int {
|
||||
return int(self.t & _MASK_LAZY & _MASK_RAW)
|
||||
}
|
||||
|
||||
func (self Node) itype() types.ValueType {
|
||||
// Type concurrently-safe returns json type represented by the node
|
||||
// It will be one of belows:
|
||||
// V_NONE = 0 (empty node, key not exists)
|
||||
// V_ERROR = 1 (error node)
|
||||
// V_NULL = 2 (json value `null`, key exists)
|
||||
// V_TRUE = 3 (json value `true`)
|
||||
// V_FALSE = 4 (json value `false`)
|
||||
// V_ARRAY = 5 (json value array)
|
||||
// V_OBJECT = 6 (json value object)
|
||||
// V_STRING = 7 (json value string)
|
||||
// V_NUMBER = 33 (json value number )
|
||||
// V_ANY = 34 (golang interface{})
|
||||
func (self *Node) TypeSafe() int {
|
||||
return int(self.loadt() & _MASK_LAZY & _MASK_RAW)
|
||||
}
|
||||
|
||||
func (self *Node) itype() types.ValueType {
|
||||
return self.t & _MASK_LAZY & _MASK_RAW
|
||||
}
|
||||
|
||||
// Exists returns false only if the self is nil or empty node V_NONE
|
||||
func (self *Node) Exists() bool {
|
||||
return self.Valid() && self.t != _V_NONE
|
||||
if self == nil {
|
||||
return false
|
||||
}
|
||||
t := self.loadt()
|
||||
return t != V_ERROR && t != _V_NONE
|
||||
}
|
||||
|
||||
// Valid reports if self is NOT V_ERROR or nil
|
||||
|
@ -97,7 +122,7 @@ func (self *Node) Valid() bool {
|
|||
if self == nil {
|
||||
return false
|
||||
}
|
||||
return self.t != V_ERROR
|
||||
return self.loadt() != V_ERROR
|
||||
}
|
||||
|
||||
// Check checks if the node itself is valid, and return:
|
||||
|
@ -106,24 +131,31 @@ func (self *Node) Valid() bool {
|
|||
func (self *Node) Check() error {
|
||||
if self == nil {
|
||||
return ErrNotExist
|
||||
} else if self.t != V_ERROR {
|
||||
} else if self.loadt() != V_ERROR {
|
||||
return nil
|
||||
} else {
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
||||
// IsRaw returns true if node's underlying value is raw json
|
||||
// isRaw returns true if node's underlying value is raw json
|
||||
//
|
||||
// Deprecated: not concurent safe
|
||||
func (self Node) IsRaw() bool {
|
||||
return self.t&_V_RAW != 0
|
||||
return self.t & _V_RAW != 0
|
||||
}
|
||||
|
||||
// IsRaw returns true if node's underlying value is raw json
|
||||
func (self *Node) isRaw() bool {
|
||||
return self.loadt() & _V_RAW != 0
|
||||
}
|
||||
|
||||
func (self *Node) isLazy() bool {
|
||||
return self != nil && self.t&_V_LAZY != 0
|
||||
return self != nil && self.t & _V_LAZY != 0
|
||||
}
|
||||
|
||||
func (self *Node) isAny() bool {
|
||||
return self != nil && self.t == _V_ANY
|
||||
return self != nil && self.loadt() == _V_ANY
|
||||
}
|
||||
|
||||
/** Simple Value Methods **/
|
||||
|
@ -133,18 +165,26 @@ func (self *Node) Raw() (string, error) {
|
|||
if self == nil {
|
||||
return "", ErrNotExist
|
||||
}
|
||||
if !self.IsRaw() {
|
||||
lock := self.rlock()
|
||||
if !self.isRaw() {
|
||||
if lock {
|
||||
self.runlock()
|
||||
}
|
||||
buf, err := self.MarshalJSON()
|
||||
return rt.Mem2Str(buf), err
|
||||
}
|
||||
return self.toString(), nil
|
||||
ret := self.toString()
|
||||
if lock {
|
||||
self.runlock()
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *Node) checkRaw() error {
|
||||
if err := self.Check(); err != nil {
|
||||
return err
|
||||
}
|
||||
if self.IsRaw() {
|
||||
if self.isRaw() {
|
||||
self.parseRaw(false)
|
||||
}
|
||||
return self.Check()
|
||||
|
@ -504,7 +544,7 @@ func (self *Node) Len() (int, error) {
|
|||
}
|
||||
}
|
||||
|
||||
func (self Node) len() int {
|
||||
func (self *Node) len() int {
|
||||
return int(self.l)
|
||||
}
|
||||
|
||||
|
@ -527,7 +567,7 @@ func (self *Node) Cap() (int, error) {
|
|||
//
|
||||
// If self is V_NONE or V_NULL, it becomes V_OBJECT and sets the node at the key.
|
||||
func (self *Node) Set(key string, node Node) (bool, error) {
|
||||
if err := self.Check(); err != nil {
|
||||
if err := self.checkRaw(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := node.Check(); err != nil {
|
||||
|
@ -535,7 +575,7 @@ func (self *Node) Set(key string, node Node) (bool, error) {
|
|||
}
|
||||
|
||||
if self.t == _V_NONE || self.t == types.V_NULL {
|
||||
*self = NewObject([]Pair{{key, node}})
|
||||
*self = NewObject([]Pair{NewPair(key, node)})
|
||||
return false, nil
|
||||
} else if self.itype() != types.V_OBJECT {
|
||||
return false, ErrUnsupportType
|
||||
|
@ -549,7 +589,7 @@ func (self *Node) Set(key string, node Node) (bool, error) {
|
|||
*self = newObject(new(linkedPairs))
|
||||
}
|
||||
s := (*linkedPairs)(self.p)
|
||||
s.Push(Pair{key, node})
|
||||
s.Push(NewPair(key, node))
|
||||
self.l++
|
||||
return false, nil
|
||||
|
||||
|
@ -568,7 +608,7 @@ func (self *Node) SetAny(key string, val interface{}) (bool, error) {
|
|||
|
||||
// Unset REMOVE (soft) the node of given key under object parent, and reports if the key has existed.
|
||||
func (self *Node) Unset(key string) (bool, error) {
|
||||
if err := self.should(types.V_OBJECT, "an object"); err != nil {
|
||||
if err := self.should(types.V_OBJECT); err != nil {
|
||||
return false, err
|
||||
}
|
||||
// NOTICE: must get acurate length before deduct
|
||||
|
@ -589,7 +629,7 @@ func (self *Node) Unset(key string) (bool, error) {
|
|||
//
|
||||
// The index must be within self's children.
|
||||
func (self *Node) SetByIndex(index int, node Node) (bool, error) {
|
||||
if err := self.Check(); err != nil {
|
||||
if err := self.checkRaw(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := node.Check(); err != nil {
|
||||
|
@ -669,7 +709,7 @@ func (self *Node) UnsetByIndex(index int) (bool, error) {
|
|||
//
|
||||
// If self is V_NONE or V_NULL, it becomes V_ARRAY and sets the node at index 0.
|
||||
func (self *Node) Add(node Node) error {
|
||||
if err := self.Check(); err != nil {
|
||||
if err := self.checkRaw(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -677,7 +717,7 @@ func (self *Node) Add(node Node) error {
|
|||
*self = NewArray([]Node{node})
|
||||
return nil
|
||||
}
|
||||
if err := self.should(types.V_ARRAY, "an array"); err != nil {
|
||||
if err := self.should(types.V_ARRAY); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -740,7 +780,7 @@ func (self *Node) Pop() error {
|
|||
//
|
||||
// WARN: this will change address of elements, which is a dangerous action.
|
||||
func (self *Node) Move(dst, src int) error {
|
||||
if err := self.should(types.V_ARRAY, "an array"); err != nil {
|
||||
if err := self.should(types.V_ARRAY); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -812,7 +852,7 @@ func (self *Node) GetByPath(path ...interface{}) *Node {
|
|||
|
||||
// Get loads given key of an object node on demands
|
||||
func (self *Node) Get(key string) *Node {
|
||||
if err := self.should(types.V_OBJECT, "an object"); err != nil {
|
||||
if err := self.should(types.V_OBJECT); err != nil {
|
||||
return unwrapError(err)
|
||||
}
|
||||
n, _ := self.skipKey(key)
|
||||
|
@ -845,14 +885,14 @@ func (self *Node) Index(idx int) *Node {
|
|||
// IndexPair indexies pair at given idx,
|
||||
// node type MUST be either V_OBJECT
|
||||
func (self *Node) IndexPair(idx int) *Pair {
|
||||
if err := self.should(types.V_OBJECT, "an object"); err != nil {
|
||||
if err := self.should(types.V_OBJECT); err != nil {
|
||||
return nil
|
||||
}
|
||||
return self.skipIndexPair(idx)
|
||||
}
|
||||
|
||||
func (self *Node) indexOrGet(idx int, key string) (*Node, int) {
|
||||
if err := self.should(types.V_OBJECT, "an object"); err != nil {
|
||||
if err := self.should(types.V_OBJECT); err != nil {
|
||||
return unwrapError(err), idx
|
||||
}
|
||||
|
||||
|
@ -889,10 +929,10 @@ func (self *Node) Map() (map[string]interface{}, error) {
|
|||
return nil, ErrUnsupportType
|
||||
}
|
||||
}
|
||||
if err := self.should(types.V_OBJECT, "an object"); err != nil {
|
||||
if err := self.should(types.V_OBJECT); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := self.loadAllKey(); err != nil {
|
||||
if err := self.loadAllKey(false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return self.toGenericObject()
|
||||
|
@ -908,10 +948,10 @@ func (self *Node) MapUseNumber() (map[string]interface{}, error) {
|
|||
return nil, ErrUnsupportType
|
||||
}
|
||||
}
|
||||
if err := self.should(types.V_OBJECT, "an object"); err != nil {
|
||||
if err := self.should(types.V_OBJECT); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := self.loadAllKey(); err != nil {
|
||||
if err := self.loadAllKey(false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return self.toGenericObjectUseNumber()
|
||||
|
@ -928,7 +968,7 @@ func (self *Node) MapUseNode() (map[string]Node, error) {
|
|||
return nil, ErrUnsupportType
|
||||
}
|
||||
}
|
||||
if err := self.should(types.V_OBJECT, "an object"); err != nil {
|
||||
if err := self.should(types.V_OBJECT); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := self.skipAllKey(); err != nil {
|
||||
|
@ -1034,10 +1074,10 @@ func (self *Node) Array() ([]interface{}, error) {
|
|||
return nil, ErrUnsupportType
|
||||
}
|
||||
}
|
||||
if err := self.should(types.V_ARRAY, "an array"); err != nil {
|
||||
if err := self.should(types.V_ARRAY); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := self.loadAllIndex(); err != nil {
|
||||
if err := self.loadAllIndex(false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return self.toGenericArray()
|
||||
|
@ -1053,10 +1093,10 @@ func (self *Node) ArrayUseNumber() ([]interface{}, error) {
|
|||
return nil, ErrUnsupportType
|
||||
}
|
||||
}
|
||||
if err := self.should(types.V_ARRAY, "an array"); err != nil {
|
||||
if err := self.should(types.V_ARRAY); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := self.loadAllIndex(); err != nil {
|
||||
if err := self.loadAllIndex(false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return self.toGenericArrayUseNumber()
|
||||
|
@ -1073,7 +1113,7 @@ func (self *Node) ArrayUseNode() ([]Node, error) {
|
|||
return nil, ErrUnsupportType
|
||||
}
|
||||
}
|
||||
if err := self.should(types.V_ARRAY, "an array"); err != nil {
|
||||
if err := self.should(types.V_ARRAY); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := self.skipAllIndex(); err != nil {
|
||||
|
@ -1129,12 +1169,12 @@ func (self *Node) Interface() (interface{}, error) {
|
|||
}
|
||||
return v, nil
|
||||
case _V_ARRAY_LAZY :
|
||||
if err := self.loadAllIndex(); err != nil {
|
||||
if err := self.loadAllIndex(false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return self.toGenericArray()
|
||||
case _V_OBJECT_LAZY :
|
||||
if err := self.loadAllKey(); err != nil {
|
||||
if err := self.loadAllKey(false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return self.toGenericObject()
|
||||
|
@ -1168,12 +1208,12 @@ func (self *Node) InterfaceUseNumber() (interface{}, error) {
|
|||
case types.V_STRING : return self.toString(), nil
|
||||
case _V_NUMBER : return self.toNumber(), nil
|
||||
case _V_ARRAY_LAZY :
|
||||
if err := self.loadAllIndex(); err != nil {
|
||||
if err := self.loadAllIndex(false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return self.toGenericArrayUseNumber()
|
||||
case _V_OBJECT_LAZY :
|
||||
if err := self.loadAllKey(); err != nil {
|
||||
if err := self.loadAllKey(false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return self.toGenericObjectUseNumber()
|
||||
|
@ -1205,70 +1245,30 @@ func (self *Node) InterfaceUseNode() (interface{}, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// LoadAll loads all the node's children and children's children as parsed.
|
||||
// After calling it, the node can be safely used on concurrency
|
||||
// LoadAll loads the node's children
|
||||
// and ensure all its children can be READ concurrently (include its children's children)
|
||||
func (self *Node) LoadAll() error {
|
||||
if self.IsRaw() {
|
||||
self.parseRaw(true)
|
||||
return self.Check()
|
||||
}
|
||||
|
||||
switch self.itype() {
|
||||
case types.V_ARRAY:
|
||||
e := self.len()
|
||||
if err := self.loadAllIndex(); err != nil {
|
||||
return err
|
||||
}
|
||||
for i := 0; i < e; i++ {
|
||||
n := self.nodeAt(i)
|
||||
if n.IsRaw() {
|
||||
n.parseRaw(true)
|
||||
}
|
||||
if err := n.Check(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case types.V_OBJECT:
|
||||
e := self.len()
|
||||
if err := self.loadAllKey(); err != nil {
|
||||
return err
|
||||
}
|
||||
for i := 0; i < e; i++ {
|
||||
n := self.pairAt(i)
|
||||
if n.Value.IsRaw() {
|
||||
n.Value.parseRaw(true)
|
||||
}
|
||||
if err := n.Value.Check(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return self.Check()
|
||||
}
|
||||
return self.Load()
|
||||
}
|
||||
|
||||
// Load loads the node's children as parsed.
|
||||
// After calling it, only the node itself can be used on concurrency (not include its children)
|
||||
// and ensure all its children can be READ concurrently (include its children's children)
|
||||
func (self *Node) Load() error {
|
||||
if err := self.checkRaw(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch self.t {
|
||||
case _V_ARRAY_LAZY:
|
||||
return self.skipAllIndex()
|
||||
case _V_OBJECT_LAZY:
|
||||
return self.skipAllKey()
|
||||
default:
|
||||
return self.Check()
|
||||
case _V_ARRAY_LAZY: self.loadAllIndex(true)
|
||||
case _V_OBJECT_LAZY: self.loadAllKey(true)
|
||||
case V_ERROR: return self
|
||||
case V_NONE: return nil
|
||||
}
|
||||
if self.m == nil {
|
||||
self.m = new(sync.RWMutex)
|
||||
}
|
||||
return self.checkRaw()
|
||||
}
|
||||
|
||||
/**---------------------------------- Internal Helper Methods ----------------------------------**/
|
||||
|
||||
func (self *Node) should(t types.ValueType, s string) error {
|
||||
func (self *Node) should(t types.ValueType) error {
|
||||
if err := self.checkRaw(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1439,13 +1439,17 @@ func (self *Node) skipIndexPair(index int) *Pair {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (self *Node) loadAllIndex() error {
|
||||
func (self *Node) loadAllIndex(loadOnce bool) error {
|
||||
if !self.isLazy() {
|
||||
return nil
|
||||
}
|
||||
var err types.ParsingError
|
||||
parser, stack := self.getParserAndArrayStack()
|
||||
parser.noLazy = true
|
||||
if !loadOnce {
|
||||
parser.noLazy = true
|
||||
} else {
|
||||
parser.loadOnce = true
|
||||
}
|
||||
*self, err = parser.decodeArray(&stack.v)
|
||||
if err != 0 {
|
||||
return parser.ExportError(err)
|
||||
|
@ -1453,14 +1457,19 @@ func (self *Node) loadAllIndex() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (self *Node) loadAllKey() error {
|
||||
func (self *Node) loadAllKey(loadOnce bool) error {
|
||||
if !self.isLazy() {
|
||||
return nil
|
||||
}
|
||||
var err types.ParsingError
|
||||
parser, stack := self.getParserAndObjectStack()
|
||||
parser.noLazy = true
|
||||
*self, err = parser.decodeObject(&stack.v)
|
||||
if !loadOnce {
|
||||
parser.noLazy = true
|
||||
*self, err = parser.decodeObject(&stack.v)
|
||||
} else {
|
||||
parser.loadOnce = true
|
||||
*self, err = parser.decodeObject(&stack.v)
|
||||
}
|
||||
if err != 0 {
|
||||
return parser.ExportError(err)
|
||||
}
|
||||
|
@ -1629,7 +1638,23 @@ func NewRaw(json string) Node {
|
|||
if it == _V_NONE {
|
||||
return Node{}
|
||||
}
|
||||
return newRawNode(parser.s[start:parser.p], it)
|
||||
return newRawNode(parser.s[start:parser.p], it, false)
|
||||
}
|
||||
|
||||
// NewRawConcurrentRead creates a node of raw json, which can be READ
|
||||
// (GetByPath/Get/Index/GetOrIndex/Int64/Bool/Float64/String/Number/Interface/Array/Map/Raw/MarshalJSON) concurrently.
|
||||
// If the input json is invalid, NewRaw returns a error Node.
|
||||
func NewRawConcurrentRead(json string) Node {
|
||||
parser := NewParserObj(json)
|
||||
start, err := parser.skip()
|
||||
if err != 0 {
|
||||
return *newError(err, err.Message())
|
||||
}
|
||||
it := switchRawType(parser.s[start])
|
||||
if it == _V_NONE {
|
||||
return Node{}
|
||||
}
|
||||
return newRawNode(parser.s[start:parser.p], it, true)
|
||||
}
|
||||
|
||||
// NewAny creates a node of type V_ANY if any's type isn't Node or *Node,
|
||||
|
@ -1653,7 +1678,7 @@ func NewBytes(src []byte) Node {
|
|||
if len(src) == 0 {
|
||||
panic("empty src bytes")
|
||||
}
|
||||
out := encodeBase64(src)
|
||||
out := rt.EncodeBase64(src)
|
||||
return NewString(out)
|
||||
}
|
||||
|
||||
|
@ -1689,15 +1714,15 @@ func NewNumber(v string) Node {
|
|||
}
|
||||
}
|
||||
|
||||
func (node Node) toNumber() json.Number {
|
||||
func (node *Node) toNumber() json.Number {
|
||||
return json.Number(rt.StrFrom(node.p, int64(node.l)))
|
||||
}
|
||||
|
||||
func (self Node) toString() string {
|
||||
func (self *Node) toString() string {
|
||||
return rt.StrFrom(self.p, int64(self.l))
|
||||
}
|
||||
|
||||
func (node Node) toFloat64() (float64, error) {
|
||||
func (node *Node) toFloat64() (float64, error) {
|
||||
ret, err := node.toNumber().Float64()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -1705,7 +1730,7 @@ func (node Node) toFloat64() (float64, error) {
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func (node Node) toInt64() (int64, error) {
|
||||
func (node *Node) toInt64() (int64, error) {
|
||||
ret,err := node.toNumber().Int64()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -1741,6 +1766,8 @@ func NewArray(v []Node) Node {
|
|||
return newArray(s)
|
||||
}
|
||||
|
||||
const _Threshold_Index = 16
|
||||
|
||||
func newArray(v *linkedNodes) Node {
|
||||
return Node{
|
||||
t: types.V_ARRAY,
|
||||
|
@ -1764,6 +1791,9 @@ func NewObject(v []Pair) Node {
|
|||
}
|
||||
|
||||
func newObject(v *linkedPairs) Node {
|
||||
if v.size > _Threshold_Index {
|
||||
v.BuildIndex()
|
||||
}
|
||||
return Node{
|
||||
t: types.V_OBJECT,
|
||||
l: uint(v.Len()),
|
||||
|
@ -1772,53 +1802,42 @@ func newObject(v *linkedPairs) Node {
|
|||
}
|
||||
|
||||
func (self *Node) setObject(v *linkedPairs) {
|
||||
if v.size > _Threshold_Index {
|
||||
v.BuildIndex()
|
||||
}
|
||||
self.t = types.V_OBJECT
|
||||
self.l = uint(v.Len())
|
||||
self.p = unsafe.Pointer(v)
|
||||
}
|
||||
|
||||
func newRawNode(str string, typ types.ValueType) Node {
|
||||
return Node{
|
||||
t: _V_RAW | typ,
|
||||
p: rt.StrPtr(str),
|
||||
l: uint(len(str)),
|
||||
}
|
||||
}
|
||||
|
||||
func (self *Node) parseRaw(full bool) {
|
||||
lock := self.lock()
|
||||
defer self.unlock()
|
||||
if !self.isRaw() {
|
||||
return
|
||||
}
|
||||
raw := self.toString()
|
||||
parser := NewParserObj(raw)
|
||||
var e types.ParsingError
|
||||
if full {
|
||||
parser.noLazy = true
|
||||
parser.skipValue = false
|
||||
*self, e = parser.Parse()
|
||||
} else if lock {
|
||||
var n Node
|
||||
parser.noLazy = true
|
||||
parser.loadOnce = true
|
||||
n, e = parser.Parse()
|
||||
self.assign(n)
|
||||
} else {
|
||||
*self, e = parser.Parse()
|
||||
}
|
||||
var e types.ParsingError
|
||||
*self, e = parser.Parse()
|
||||
if e != 0 {
|
||||
*self = *newSyntaxError(parser.syntaxError(e))
|
||||
}
|
||||
}
|
||||
|
||||
var typeJumpTable = [256]types.ValueType{
|
||||
'"' : types.V_STRING,
|
||||
'-' : _V_NUMBER,
|
||||
'0' : _V_NUMBER,
|
||||
'1' : _V_NUMBER,
|
||||
'2' : _V_NUMBER,
|
||||
'3' : _V_NUMBER,
|
||||
'4' : _V_NUMBER,
|
||||
'5' : _V_NUMBER,
|
||||
'6' : _V_NUMBER,
|
||||
'7' : _V_NUMBER,
|
||||
'8' : _V_NUMBER,
|
||||
'9' : _V_NUMBER,
|
||||
'[' : types.V_ARRAY,
|
||||
'f' : types.V_FALSE,
|
||||
'n' : types.V_NULL,
|
||||
't' : types.V_TRUE,
|
||||
'{' : types.V_OBJECT,
|
||||
}
|
||||
|
||||
func switchRawType(c byte) types.ValueType {
|
||||
return typeJumpTable[c]
|
||||
func (self *Node) assign(n Node) {
|
||||
self.l = n.l
|
||||
self.p = n.p
|
||||
atomic.StoreInt64(&self.t, n.t)
|
||||
}
|
||||
|
|
142
vendor/github.com/bytedance/sonic/ast/parser.go
generated
vendored
142
vendor/github.com/bytedance/sonic/ast/parser.go
generated
vendored
|
@ -17,14 +17,16 @@
|
|||
package ast
|
||||
|
||||
import (
|
||||
`fmt`
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
`github.com/bytedance/sonic/internal/native/types`
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
"github.com/bytedance/sonic/internal/native/types"
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
)
|
||||
|
||||
const (
|
||||
_DEFAULT_NODE_CAP int = 8
|
||||
_DEFAULT_NODE_CAP int = 16
|
||||
_APPEND_GROW_SHIFT = 1
|
||||
)
|
||||
|
||||
|
@ -45,6 +47,7 @@ type Parser struct {
|
|||
p int
|
||||
s string
|
||||
noLazy bool
|
||||
loadOnce bool
|
||||
skipValue bool
|
||||
dbuf *byte
|
||||
}
|
||||
|
@ -115,6 +118,10 @@ func (self *Parser) lspace(sp int) int {
|
|||
return sp
|
||||
}
|
||||
|
||||
func (self *Parser) backward() {
|
||||
for ; self.p >= 0 && isSpace(self.s[self.p]); self.p-=1 {}
|
||||
}
|
||||
|
||||
func (self *Parser) decodeArray(ret *linkedNodes) (Node, types.ParsingError) {
|
||||
sp := self.p
|
||||
ns := len(self.s)
|
||||
|
@ -148,7 +155,7 @@ func (self *Parser) decodeArray(ret *linkedNodes) (Node, types.ParsingError) {
|
|||
if t == _V_NONE {
|
||||
return Node{}, types.ERR_INVALID_CHAR
|
||||
}
|
||||
val = newRawNode(self.s[start:self.p], t)
|
||||
val = newRawNode(self.s[start:self.p], t, false)
|
||||
}else{
|
||||
/* decode the value */
|
||||
if val, err = self.Parse(); err != 0 {
|
||||
|
@ -234,7 +241,7 @@ func (self *Parser) decodeObject(ret *linkedPairs) (Node, types.ParsingError) {
|
|||
if t == _V_NONE {
|
||||
return Node{}, types.ERR_INVALID_CHAR
|
||||
}
|
||||
val = newRawNode(self.s[start:self.p], t)
|
||||
val = newRawNode(self.s[start:self.p], t, false)
|
||||
} else {
|
||||
/* decode the value */
|
||||
if val, err = self.Parse(); err != 0 {
|
||||
|
@ -244,7 +251,7 @@ func (self *Parser) decodeObject(ret *linkedPairs) (Node, types.ParsingError) {
|
|||
|
||||
/* add the value to result */
|
||||
// FIXME: ret's address may change here, thus previous referred node in ret may be invalid !!
|
||||
ret.Push(Pair{Key: key, Value: val})
|
||||
ret.Push(NewPair(key, val))
|
||||
self.p = self.lspace(self.p)
|
||||
|
||||
/* check for EOF */
|
||||
|
@ -291,6 +298,10 @@ func (self *Parser) Pos() int {
|
|||
return self.p
|
||||
}
|
||||
|
||||
|
||||
// Parse returns a ast.Node representing the parser's JSON.
|
||||
// NOTICE: the specific parsing lazy dependens parser's option
|
||||
// It only parse first layer and first child for Object or Array be default
|
||||
func (self *Parser) Parse() (Node, types.ParsingError) {
|
||||
switch val := self.decodeValue(); val.Vt {
|
||||
case types.V_EOF : return Node{}, types.ERR_EOF
|
||||
|
@ -299,22 +310,48 @@ func (self *Parser) Parse() (Node, types.ParsingError) {
|
|||
case types.V_FALSE : return falseNode, 0
|
||||
case types.V_STRING : return self.decodeString(val.Iv, val.Ep)
|
||||
case types.V_ARRAY:
|
||||
s := self.p - 1;
|
||||
if p := skipBlank(self.s, self.p); p >= self.p && self.s[p] == ']' {
|
||||
self.p = p + 1
|
||||
return Node{t: types.V_ARRAY}, 0
|
||||
}
|
||||
if self.noLazy {
|
||||
if self.loadOnce {
|
||||
self.noLazy = false
|
||||
}
|
||||
return self.decodeArray(new(linkedNodes))
|
||||
}
|
||||
// NOTICE: loadOnce always keep raw json for object or array
|
||||
if self.loadOnce {
|
||||
self.p = s
|
||||
s, e := self.skipFast()
|
||||
if e != 0 {
|
||||
return Node{}, e
|
||||
}
|
||||
return newRawNode(self.s[s:self.p], types.V_ARRAY, true), 0
|
||||
}
|
||||
return newLazyArray(self), 0
|
||||
case types.V_OBJECT:
|
||||
s := self.p - 1;
|
||||
if p := skipBlank(self.s, self.p); p >= self.p && self.s[p] == '}' {
|
||||
self.p = p + 1
|
||||
return Node{t: types.V_OBJECT}, 0
|
||||
}
|
||||
// NOTICE: loadOnce always keep raw json for object or array
|
||||
if self.noLazy {
|
||||
if self.loadOnce {
|
||||
self.noLazy = false
|
||||
}
|
||||
return self.decodeObject(new(linkedPairs))
|
||||
}
|
||||
if self.loadOnce {
|
||||
self.p = s
|
||||
s, e := self.skipFast()
|
||||
if e != 0 {
|
||||
return Node{}, e
|
||||
}
|
||||
return newRawNode(self.s[s:self.p], types.V_OBJECT, true), 0
|
||||
}
|
||||
return newLazyObject(self), 0
|
||||
case types.V_DOUBLE : return NewNumber(self.s[val.Ep:self.p]), 0
|
||||
case types.V_INTEGER : return NewNumber(self.s[val.Ep:self.p]), 0
|
||||
|
@ -471,7 +508,7 @@ func (self *Node) skipNextNode() *Node {
|
|||
if t == _V_NONE {
|
||||
return newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR))
|
||||
}
|
||||
val = newRawNode(parser.s[start:parser.p], t)
|
||||
val = newRawNode(parser.s[start:parser.p], t, false)
|
||||
}
|
||||
|
||||
/* add the value to result */
|
||||
|
@ -510,7 +547,7 @@ func (self *Node) skipNextPair() (*Pair) {
|
|||
|
||||
/* check for EOF */
|
||||
if parser.p = parser.lspace(sp); parser.p >= ns {
|
||||
return &Pair{"", *newSyntaxError(parser.syntaxError(types.ERR_EOF))}
|
||||
return newErrorPair(parser.syntaxError(types.ERR_EOF))
|
||||
}
|
||||
|
||||
/* check for empty object */
|
||||
|
@ -527,7 +564,7 @@ func (self *Node) skipNextPair() (*Pair) {
|
|||
|
||||
/* decode the key */
|
||||
if njs = parser.decodeValue(); njs.Vt != types.V_STRING {
|
||||
return &Pair{"", *newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR))}
|
||||
return newErrorPair(parser.syntaxError(types.ERR_INVALID_CHAR))
|
||||
}
|
||||
|
||||
/* extract the key */
|
||||
|
@ -537,34 +574,34 @@ func (self *Node) skipNextPair() (*Pair) {
|
|||
/* check for escape sequence */
|
||||
if njs.Ep != -1 {
|
||||
if key, err = unquote(key); err != 0 {
|
||||
return &Pair{key, *newSyntaxError(parser.syntaxError(err))}
|
||||
return newErrorPair(parser.syntaxError(err))
|
||||
}
|
||||
}
|
||||
|
||||
/* expect a ':' delimiter */
|
||||
if err = parser.delim(); err != 0 {
|
||||
return &Pair{key, *newSyntaxError(parser.syntaxError(err))}
|
||||
return newErrorPair(parser.syntaxError(err))
|
||||
}
|
||||
|
||||
/* skip the value */
|
||||
if start, err := parser.skipFast(); err != 0 {
|
||||
return &Pair{key, *newSyntaxError(parser.syntaxError(err))}
|
||||
return newErrorPair(parser.syntaxError(err))
|
||||
} else {
|
||||
t := switchRawType(parser.s[start])
|
||||
if t == _V_NONE {
|
||||
return &Pair{key, *newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR))}
|
||||
return newErrorPair(parser.syntaxError(types.ERR_INVALID_CHAR))
|
||||
}
|
||||
val = newRawNode(parser.s[start:parser.p], t)
|
||||
val = newRawNode(parser.s[start:parser.p], t, false)
|
||||
}
|
||||
|
||||
/* add the value to result */
|
||||
ret.Push(Pair{Key: key, Value: val})
|
||||
ret.Push(NewPair(key, val))
|
||||
self.l++
|
||||
parser.p = parser.lspace(parser.p)
|
||||
|
||||
/* check for EOF */
|
||||
if parser.p >= ns {
|
||||
return &Pair{key, *newSyntaxError(parser.syntaxError(types.ERR_EOF))}
|
||||
return newErrorPair(parser.syntaxError(types.ERR_EOF))
|
||||
}
|
||||
|
||||
/* check for the next character */
|
||||
|
@ -577,7 +614,7 @@ func (self *Node) skipNextPair() (*Pair) {
|
|||
self.setObject(ret)
|
||||
return ret.At(ret.Len()-1)
|
||||
default:
|
||||
return &Pair{key, *newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR))}
|
||||
return newErrorPair(parser.syntaxError(types.ERR_INVALID_CHAR))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -658,3 +695,72 @@ func backward(src string, i int) int {
|
|||
for ; i>=0 && isSpace(src[i]); i-- {}
|
||||
return i
|
||||
}
|
||||
|
||||
|
||||
func newRawNode(str string, typ types.ValueType, lock bool) Node {
|
||||
ret := Node{
|
||||
t: typ | _V_RAW,
|
||||
p: rt.StrPtr(str),
|
||||
l: uint(len(str)),
|
||||
}
|
||||
if lock {
|
||||
ret.m = new(sync.RWMutex)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
var typeJumpTable = [256]types.ValueType{
|
||||
'"' : types.V_STRING,
|
||||
'-' : _V_NUMBER,
|
||||
'0' : _V_NUMBER,
|
||||
'1' : _V_NUMBER,
|
||||
'2' : _V_NUMBER,
|
||||
'3' : _V_NUMBER,
|
||||
'4' : _V_NUMBER,
|
||||
'5' : _V_NUMBER,
|
||||
'6' : _V_NUMBER,
|
||||
'7' : _V_NUMBER,
|
||||
'8' : _V_NUMBER,
|
||||
'9' : _V_NUMBER,
|
||||
'[' : types.V_ARRAY,
|
||||
'f' : types.V_FALSE,
|
||||
'n' : types.V_NULL,
|
||||
't' : types.V_TRUE,
|
||||
'{' : types.V_OBJECT,
|
||||
}
|
||||
|
||||
func switchRawType(c byte) types.ValueType {
|
||||
return typeJumpTable[c]
|
||||
}
|
||||
|
||||
func (self *Node) loadt() types.ValueType {
|
||||
return (types.ValueType)(atomic.LoadInt64(&self.t))
|
||||
}
|
||||
|
||||
func (self *Node) lock() bool {
|
||||
if m := self.m; m != nil {
|
||||
m.Lock()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *Node) unlock() {
|
||||
if m := self.m; m != nil {
|
||||
m.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
func (self *Node) rlock() bool {
|
||||
if m := self.m; m != nil {
|
||||
m.RLock()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *Node) runlock() {
|
||||
if m := self.m; m != nil {
|
||||
m.RUnlock()
|
||||
}
|
||||
}
|
||||
|
|
31
vendor/github.com/bytedance/sonic/ast/search.go
generated
vendored
31
vendor/github.com/bytedance/sonic/ast/search.go
generated
vendored
|
@ -21,8 +21,23 @@
|
|||
`github.com/bytedance/sonic/internal/native/types`
|
||||
)
|
||||
|
||||
// SearchOptions controls Searcher's behavior
|
||||
type SearchOptions struct {
|
||||
// ValidateJSON indicates the searcher to validate the entire JSON
|
||||
ValidateJSON bool
|
||||
|
||||
// CopyReturn indicates the searcher to copy the result JSON instead of refer from the input
|
||||
// This can help to reduce memory usage if you cache the results
|
||||
CopyReturn bool
|
||||
|
||||
// ConcurrentRead indicates the searcher to return a concurrently-READ-safe node,
|
||||
// including: GetByPath/Get/Index/GetOrIndex/Int64/Bool/Float64/String/Number/Interface/Array/Map/Raw/MarshalJSON
|
||||
ConcurrentRead bool
|
||||
}
|
||||
|
||||
type Searcher struct {
|
||||
parser Parser
|
||||
SearchOptions
|
||||
}
|
||||
|
||||
func NewSearcher(str string) *Searcher {
|
||||
|
@ -31,12 +46,16 @@ func NewSearcher(str string) *Searcher {
|
|||
s: str,
|
||||
noLazy: false,
|
||||
},
|
||||
SearchOptions: SearchOptions{
|
||||
ValidateJSON: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetByPathCopy search in depth from top json and returns a **Copied** json node at the path location
|
||||
func (self *Searcher) GetByPathCopy(path ...interface{}) (Node, error) {
|
||||
return self.getByPath(true, true, path...)
|
||||
self.CopyReturn = true
|
||||
return self.getByPath(path...)
|
||||
}
|
||||
|
||||
// GetByPathNoCopy search in depth from top json and returns a **Referenced** json node at the path location
|
||||
|
@ -44,15 +63,15 @@ func (self *Searcher) GetByPathCopy(path ...interface{}) (Node, error) {
|
|||
// WARN: this search directly refer partial json from top json, which has faster speed,
|
||||
// may consumes more memory.
|
||||
func (self *Searcher) GetByPath(path ...interface{}) (Node, error) {
|
||||
return self.getByPath(false, true, path...)
|
||||
return self.getByPath(path...)
|
||||
}
|
||||
|
||||
func (self *Searcher) getByPath(copystring bool, validate bool, path ...interface{}) (Node, error) {
|
||||
func (self *Searcher) getByPath(path ...interface{}) (Node, error) {
|
||||
var err types.ParsingError
|
||||
var start int
|
||||
|
||||
self.parser.p = 0
|
||||
start, err = self.parser.getByPath(validate, path...)
|
||||
start, err = self.parser.getByPath(self.ValidateJSON, path...)
|
||||
if err != 0 {
|
||||
// for compatibility with old version
|
||||
if err == types.ERR_NOT_FOUND {
|
||||
|
@ -71,12 +90,12 @@ func (self *Searcher) getByPath(copystring bool, validate bool, path ...interfac
|
|||
|
||||
// copy string to reducing memory usage
|
||||
var raw string
|
||||
if copystring {
|
||||
if self.CopyReturn {
|
||||
raw = rt.Mem2Str([]byte(self.parser.s[start:self.parser.p]))
|
||||
} else {
|
||||
raw = self.parser.s[start:self.parser.p]
|
||||
}
|
||||
return newRawNode(raw, t), nil
|
||||
return newRawNode(raw, t, self.ConcurrentRead), nil
|
||||
}
|
||||
|
||||
// GetByPath searches a path and returns relaction and types of target
|
||||
|
|
142
vendor/github.com/bytedance/sonic/ast/stubs.go
generated
vendored
Normal file
142
vendor/github.com/bytedance/sonic/ast/stubs.go
generated
vendored
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package ast
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
"unsafe"
|
||||
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
)
|
||||
|
||||
//go:noescape
|
||||
//go:linkname memmove runtime.memmove
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr)
|
||||
|
||||
//go:linkname unsafe_NewArray reflect.unsafe_NewArray
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func unsafe_NewArray(typ *rt.GoType, n int) unsafe.Pointer
|
||||
|
||||
//go:nosplit
|
||||
func mem2ptr(s []byte) unsafe.Pointer {
|
||||
return (*rt.GoSlice)(unsafe.Pointer(&s)).Ptr
|
||||
}
|
||||
|
||||
var safeSet = [utf8.RuneSelf]bool{
|
||||
' ': true,
|
||||
'!': true,
|
||||
'"': false,
|
||||
'#': true,
|
||||
'$': true,
|
||||
'%': true,
|
||||
'&': true,
|
||||
'\'': true,
|
||||
'(': true,
|
||||
')': true,
|
||||
'*': true,
|
||||
'+': true,
|
||||
',': true,
|
||||
'-': true,
|
||||
'.': true,
|
||||
'/': true,
|
||||
'0': true,
|
||||
'1': true,
|
||||
'2': true,
|
||||
'3': true,
|
||||
'4': true,
|
||||
'5': true,
|
||||
'6': true,
|
||||
'7': true,
|
||||
'8': true,
|
||||
'9': true,
|
||||
':': true,
|
||||
';': true,
|
||||
'<': true,
|
||||
'=': true,
|
||||
'>': true,
|
||||
'?': true,
|
||||
'@': true,
|
||||
'A': true,
|
||||
'B': true,
|
||||
'C': true,
|
||||
'D': true,
|
||||
'E': true,
|
||||
'F': true,
|
||||
'G': true,
|
||||
'H': true,
|
||||
'I': true,
|
||||
'J': true,
|
||||
'K': true,
|
||||
'L': true,
|
||||
'M': true,
|
||||
'N': true,
|
||||
'O': true,
|
||||
'P': true,
|
||||
'Q': true,
|
||||
'R': true,
|
||||
'S': true,
|
||||
'T': true,
|
||||
'U': true,
|
||||
'V': true,
|
||||
'W': true,
|
||||
'X': true,
|
||||
'Y': true,
|
||||
'Z': true,
|
||||
'[': true,
|
||||
'\\': false,
|
||||
']': true,
|
||||
'^': true,
|
||||
'_': true,
|
||||
'`': true,
|
||||
'a': true,
|
||||
'b': true,
|
||||
'c': true,
|
||||
'd': true,
|
||||
'e': true,
|
||||
'f': true,
|
||||
'g': true,
|
||||
'h': true,
|
||||
'i': true,
|
||||
'j': true,
|
||||
'k': true,
|
||||
'l': true,
|
||||
'm': true,
|
||||
'n': true,
|
||||
'o': true,
|
||||
'p': true,
|
||||
'q': true,
|
||||
'r': true,
|
||||
's': true,
|
||||
't': true,
|
||||
'u': true,
|
||||
'v': true,
|
||||
'w': true,
|
||||
'x': true,
|
||||
'y': true,
|
||||
'z': true,
|
||||
'{': true,
|
||||
'|': true,
|
||||
'}': true,
|
||||
'~': true,
|
||||
'\u007f': true,
|
||||
}
|
||||
|
||||
var hex = "0123456789abcdef"
|
||||
|
||||
//go:linkname unquoteBytes encoding/json.unquoteBytes
|
||||
func unquoteBytes(s []byte) (t []byte, ok bool)
|
55
vendor/github.com/bytedance/sonic/ast/stubs_go115.go
generated
vendored
55
vendor/github.com/bytedance/sonic/ast/stubs_go115.go
generated
vendored
|
@ -1,55 +0,0 @@
|
|||
// +build !go1.20
|
||||
|
||||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package ast
|
||||
|
||||
import (
|
||||
`unsafe`
|
||||
`unicode/utf8`
|
||||
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
)
|
||||
|
||||
//go:noescape
|
||||
//go:linkname memmove runtime.memmove
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr)
|
||||
|
||||
//go:linkname unsafe_NewArray reflect.unsafe_NewArray
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func unsafe_NewArray(typ *rt.GoType, n int) unsafe.Pointer
|
||||
|
||||
//go:linkname growslice runtime.growslice
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func growslice(et *rt.GoType, old rt.GoSlice, cap int) rt.GoSlice
|
||||
|
||||
//go:nosplit
|
||||
func mem2ptr(s []byte) unsafe.Pointer {
|
||||
return (*rt.GoSlice)(unsafe.Pointer(&s)).Ptr
|
||||
}
|
||||
|
||||
var (
|
||||
//go:linkname safeSet encoding/json.safeSet
|
||||
safeSet [utf8.RuneSelf]bool
|
||||
|
||||
//go:linkname hex encoding/json.hex
|
||||
hex string
|
||||
)
|
||||
|
||||
//go:linkname unquoteBytes encoding/json.unquoteBytes
|
||||
func unquoteBytes(s []byte) (t []byte, ok bool)
|
55
vendor/github.com/bytedance/sonic/ast/stubs_go120.go
generated
vendored
55
vendor/github.com/bytedance/sonic/ast/stubs_go120.go
generated
vendored
|
@ -1,55 +0,0 @@
|
|||
// +build go1.20
|
||||
|
||||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package ast
|
||||
|
||||
import (
|
||||
`unsafe`
|
||||
`unicode/utf8`
|
||||
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
)
|
||||
|
||||
//go:noescape
|
||||
//go:linkname memmove runtime.memmove
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr)
|
||||
|
||||
//go:linkname unsafe_NewArray reflect.unsafe_NewArray
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func unsafe_NewArray(typ *rt.GoType, n int) unsafe.Pointer
|
||||
|
||||
//go:linkname growslice reflect.growslice
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func growslice(et *rt.GoType, old rt.GoSlice, cap int) rt.GoSlice
|
||||
|
||||
//go:nosplit
|
||||
func mem2ptr(s []byte) unsafe.Pointer {
|
||||
return (*rt.GoSlice)(unsafe.Pointer(&s)).Ptr
|
||||
}
|
||||
|
||||
var (
|
||||
//go:linkname safeSet encoding/json.safeSet
|
||||
safeSet [utf8.RuneSelf]bool
|
||||
|
||||
//go:linkname hex encoding/json.hex
|
||||
hex string
|
||||
)
|
||||
|
||||
//go:linkname unquoteBytes encoding/json.unquoteBytes
|
||||
func unquoteBytes(s []byte) (t []byte, ok bool)
|
45
vendor/github.com/bytedance/sonic/ast/visitor.go
generated
vendored
45
vendor/github.com/bytedance/sonic/ast/visitor.go
generated
vendored
|
@ -18,6 +18,7 @@
|
|||
|
||||
import (
|
||||
`encoding/json`
|
||||
`errors`
|
||||
|
||||
`github.com/bytedance/sonic/internal/native/types`
|
||||
)
|
||||
|
@ -174,6 +175,19 @@ func (self *traverser) decodeArray() error {
|
|||
sp := self.parser.p
|
||||
ns := len(self.parser.s)
|
||||
|
||||
/* allocate array space and parse every element */
|
||||
if err := self.visitor.OnArrayBegin(_DEFAULT_NODE_CAP); err != nil {
|
||||
if err == VisitOPSkip {
|
||||
// NOTICE: for user needs to skip entiry object
|
||||
self.parser.p -= 1
|
||||
if _, e := self.parser.skipFast(); e != 0 {
|
||||
return e
|
||||
}
|
||||
return self.visitor.OnArrayEnd()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
/* check for EOF */
|
||||
self.parser.p = self.parser.lspace(sp)
|
||||
if self.parser.p >= ns {
|
||||
|
@ -183,16 +197,9 @@ func (self *traverser) decodeArray() error {
|
|||
/* check for empty array */
|
||||
if self.parser.s[self.parser.p] == ']' {
|
||||
self.parser.p++
|
||||
if err := self.visitor.OnArrayBegin(0); err != nil {
|
||||
return err
|
||||
}
|
||||
return self.visitor.OnArrayEnd()
|
||||
}
|
||||
|
||||
/* allocate array space and parse every element */
|
||||
if err := self.visitor.OnArrayBegin(_DEFAULT_NODE_CAP); err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
/* decode the value */
|
||||
if err := self.decodeValue(); err != nil {
|
||||
|
@ -223,6 +230,19 @@ func (self *traverser) decodeObject() error {
|
|||
sp := self.parser.p
|
||||
ns := len(self.parser.s)
|
||||
|
||||
/* allocate object space and decode each pair */
|
||||
if err := self.visitor.OnObjectBegin(_DEFAULT_NODE_CAP); err != nil {
|
||||
if err == VisitOPSkip {
|
||||
// NOTICE: for user needs to skip entiry object
|
||||
self.parser.p -= 1
|
||||
if _, e := self.parser.skipFast(); e != 0 {
|
||||
return e
|
||||
}
|
||||
return self.visitor.OnObjectEnd()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
/* check for EOF */
|
||||
self.parser.p = self.parser.lspace(sp)
|
||||
if self.parser.p >= ns {
|
||||
|
@ -232,16 +252,9 @@ func (self *traverser) decodeObject() error {
|
|||
/* check for empty object */
|
||||
if self.parser.s[self.parser.p] == '}' {
|
||||
self.parser.p++
|
||||
if err := self.visitor.OnObjectBegin(0); err != nil {
|
||||
return err
|
||||
}
|
||||
return self.visitor.OnObjectEnd()
|
||||
}
|
||||
|
||||
/* allocate object space and decode each pair */
|
||||
if err := self.visitor.OnObjectBegin(_DEFAULT_NODE_CAP); err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
var njs types.JsonState
|
||||
var err types.ParsingError
|
||||
|
@ -313,3 +326,7 @@ func (self *traverser) decodeString(iv int64, ep int) error {
|
|||
}
|
||||
return self.visitor.OnString(out)
|
||||
}
|
||||
|
||||
// If visitor return this error on `OnObjectBegin()` or `OnArrayBegin()`,
|
||||
// the transverer will skip entiry object or array
|
||||
var VisitOPSkip = errors.New("")
|
||||
|
|
4
vendor/github.com/bytedance/sonic/compat.go
generated
vendored
4
vendor/github.com/bytedance/sonic/compat.go
generated
vendored
|
@ -1,4 +1,4 @@
|
|||
// +build !amd64 !go1.16 go1.23
|
||||
// +build !amd64,!arm64 go1.24 !go1.17 arm64,!go1.20
|
||||
|
||||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
|
@ -27,6 +27,8 @@
|
|||
`github.com/bytedance/sonic/option`
|
||||
)
|
||||
|
||||
const apiKind = UseStdJSON
|
||||
|
||||
type frozenConfig struct {
|
||||
Config
|
||||
}
|
||||
|
|
6
vendor/github.com/bytedance/sonic/decoder/decoder_compat.go
generated
vendored
6
vendor/github.com/bytedance/sonic/decoder/decoder_compat.go
generated
vendored
|
@ -1,4 +1,4 @@
|
|||
// +build !amd64 !go1.16 go1.23
|
||||
// +build !amd64,!arm64 go1.24 !go1.17 arm64,!go1.20
|
||||
|
||||
/*
|
||||
* Copyright 2023 ByteDance Inc.
|
||||
|
@ -30,7 +30,7 @@
|
|||
)
|
||||
|
||||
func init() {
|
||||
println("WARNING: sonic only supports Go1.16~1.22 && CPU amd64, but your environment is not suitable")
|
||||
println("WARNING: sonic/decoder only supports (Go1.17~1.23 && CPU amd64) or (go1.20~1.23 && CPU arm64), but your environment is not suitable")
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -42,6 +42,7 @@ func init() {
|
|||
_F_use_number = types.B_USE_NUMBER
|
||||
_F_validate_string = types.B_VALIDATE_STRING
|
||||
_F_allow_control = types.B_ALLOW_CONTROL
|
||||
_F_no_validate_json = types.B_NO_VALIDATE_JSON
|
||||
)
|
||||
|
||||
type Options uint64
|
||||
|
@ -53,6 +54,7 @@ func init() {
|
|||
OptionDisableUnknown Options = 1 << _F_disable_unknown
|
||||
OptionCopyString Options = 1 << _F_copy_string
|
||||
OptionValidateString Options = 1 << _F_validate_string
|
||||
OptionNoValidateJSON Options = 1 << _F_no_validate_json
|
||||
)
|
||||
|
||||
func (self *Decoder) SetOptions(opts Options) {
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// +build amd64,go1.16,!go1.23
|
||||
//go:build (amd64 && go1.17 && !go1.24) || (arm64 && go1.20 && !go1.24)
|
||||
// +build amd64,go1.17,!go1.24 arm64,go1.20,!go1.24
|
||||
|
||||
|
||||
/*
|
||||
* Copyright 2023 ByteDance Inc.
|
||||
|
@ -19,50 +21,51 @@
|
|||
package decoder
|
||||
|
||||
import (
|
||||
`github.com/bytedance/sonic/internal/decoder`
|
||||
`github.com/bytedance/sonic/internal/decoder/api`
|
||||
)
|
||||
|
||||
// Decoder is the decoder context object
|
||||
type Decoder = decoder.Decoder
|
||||
type Decoder = api.Decoder
|
||||
|
||||
// SyntaxError represents json syntax error
|
||||
type SyntaxError = decoder.SyntaxError
|
||||
type SyntaxError = api.SyntaxError
|
||||
|
||||
// MismatchTypeError represents dismatching between json and object
|
||||
type MismatchTypeError = decoder.MismatchTypeError
|
||||
type MismatchTypeError = api.MismatchTypeError
|
||||
|
||||
// Options for decode.
|
||||
type Options = decoder.Options
|
||||
type Options = api.Options
|
||||
|
||||
const (
|
||||
OptionUseInt64 Options = decoder.OptionUseInt64
|
||||
OptionUseNumber Options = decoder.OptionUseNumber
|
||||
OptionUseUnicodeErrors Options = decoder.OptionUseUnicodeErrors
|
||||
OptionDisableUnknown Options = decoder.OptionDisableUnknown
|
||||
OptionCopyString Options = decoder.OptionCopyString
|
||||
OptionValidateString Options = decoder.OptionValidateString
|
||||
OptionUseInt64 Options = api.OptionUseInt64
|
||||
OptionUseNumber Options = api.OptionUseNumber
|
||||
OptionUseUnicodeErrors Options = api.OptionUseUnicodeErrors
|
||||
OptionDisableUnknown Options = api.OptionDisableUnknown
|
||||
OptionCopyString Options = api.OptionCopyString
|
||||
OptionValidateString Options = api.OptionValidateString
|
||||
OptionNoValidateJSON Options = api.OptionNoValidateJSON
|
||||
)
|
||||
|
||||
// StreamDecoder is the decoder context object for streaming input.
|
||||
type StreamDecoder = decoder.StreamDecoder
|
||||
type StreamDecoder = api.StreamDecoder
|
||||
|
||||
var (
|
||||
// NewDecoder creates a new decoder instance.
|
||||
NewDecoder = decoder.NewDecoder
|
||||
NewDecoder = api.NewDecoder
|
||||
|
||||
// NewStreamDecoder adapts to encoding/json.NewDecoder API.
|
||||
//
|
||||
// NewStreamDecoder returns a new decoder that reads from r.
|
||||
NewStreamDecoder = decoder.NewStreamDecoder
|
||||
NewStreamDecoder = api.NewStreamDecoder
|
||||
|
||||
// Pretouch compiles vt ahead-of-time to avoid JIT compilation on-the-fly, in
|
||||
// order to reduce the first-hit latency.
|
||||
//
|
||||
// Opts are the compile options, for example, "option.WithCompileRecursiveDepth" is
|
||||
// a compile option to set the depth of recursive compile for the nested struct type.
|
||||
Pretouch = decoder.Pretouch
|
||||
Pretouch = api.Pretouch
|
||||
|
||||
// Skip skips only one json value, and returns first non-blank character position and its ending position if it is valid.
|
||||
// Otherwise, returns negative error code using start and invalid character position using end
|
||||
Skip = decoder.Skip
|
||||
Skip = api.Skip
|
||||
)
|
4
vendor/github.com/bytedance/sonic/encoder/encoder_compat.go
generated
vendored
4
vendor/github.com/bytedance/sonic/encoder/encoder_compat.go
generated
vendored
|
@ -1,4 +1,4 @@
|
|||
// +build !amd64 !go1.16 go1.23
|
||||
// +build !amd64,!arm64 go1.24 !go1.17 arm64,!go1.20
|
||||
|
||||
/*
|
||||
* Copyright 2023 ByteDance Inc.
|
||||
|
@ -28,7 +28,7 @@
|
|||
)
|
||||
|
||||
func init() {
|
||||
println("WARNING:(encoder) sonic only supports Go1.16~1.22 && CPU amd64, but your environment is not suitable")
|
||||
println("WARNING:(encoder) sonic only supports (Go1.17~1.23 && CPU amd64) or (G01.20~1.23 && CPU arm64) , but your environment is not suitable")
|
||||
}
|
||||
|
||||
// EnableFallback indicates if encoder use fallback
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build amd64,go1.16,!go1.23
|
||||
// +build amd64,go1.17,!go1.24 arm64,go1.20,!go1.24
|
||||
|
||||
/*
|
||||
* Copyright 2023 ByteDance Inc.
|
||||
|
@ -70,6 +70,9 @@
|
|||
|
||||
// CompatibleWithStd is used to be compatible with std encoder.
|
||||
CompatibleWithStd Options = encoder.CompatibleWithStd
|
||||
|
||||
// Encode Infinity or Nan float into `null`, instead of returning an error.
|
||||
EncodeNullForInfOrNan Options = encoder.EncodeNullForInfOrNan
|
||||
)
|
||||
|
||||
|
1
vendor/github.com/bytedance/sonic/go.work.sum
generated
vendored
Normal file
1
vendor/github.com/bytedance/sonic/go.work.sum
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
46
vendor/github.com/bytedance/sonic/internal/base64/b64_amd64.go
generated
vendored
Normal file
46
vendor/github.com/bytedance/sonic/internal/base64/b64_amd64.go
generated
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
// +build amd64,go1.17,!go1.24
|
||||
|
||||
/**
|
||||
* Copyright 2023 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package base64
|
||||
|
||||
import (
|
||||
"github.com/cloudwego/base64x"
|
||||
)
|
||||
|
||||
func DecodeBase64(src string) ([]byte, error) {
|
||||
return base64x.StdEncoding.DecodeString(src)
|
||||
}
|
||||
|
||||
func EncodeBase64(buf []byte, src []byte) []byte {
|
||||
if len(src) == 0 {
|
||||
return append(buf, '"', '"')
|
||||
}
|
||||
buf = append(buf, '"')
|
||||
need := base64x.StdEncoding.EncodedLen(len(src))
|
||||
if cap(buf) - len(buf) < need {
|
||||
tmp := make([]byte, len(buf), len(buf) + need*2)
|
||||
copy(tmp, buf)
|
||||
buf = tmp
|
||||
}
|
||||
base64x.StdEncoding.Encode(buf[len(buf):cap(buf)], src)
|
||||
buf = buf[:len(buf) + need]
|
||||
buf = append(buf, '"')
|
||||
return buf
|
||||
}
|
||||
|
||||
|
44
vendor/github.com/bytedance/sonic/internal/base64/b64_compat.go
generated
vendored
Normal file
44
vendor/github.com/bytedance/sonic/internal/base64/b64_compat.go
generated
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
// +build !amd64 !go1.17 go1.24
|
||||
|
||||
/*
|
||||
* Copyright 2022 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package base64
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
)
|
||||
|
||||
func EncodeBase64(buf []byte, src []byte) []byte {
|
||||
if len(src) == 0 {
|
||||
return append(buf, '"', '"')
|
||||
}
|
||||
buf = append(buf, '"')
|
||||
need := base64.StdEncoding.EncodedLen(len(src))
|
||||
if cap(buf) - len(buf) < need {
|
||||
tmp := make([]byte, len(buf), len(buf) + need*2)
|
||||
copy(tmp, buf)
|
||||
buf = tmp
|
||||
}
|
||||
base64.StdEncoding.Encode(buf[len(buf):cap(buf)], src)
|
||||
buf = buf[:len(buf) + need]
|
||||
buf = append(buf, '"')
|
||||
return buf
|
||||
}
|
||||
|
||||
func DecodeBase64(src string) ([]byte, error) {
|
||||
return base64.StdEncoding.DecodeString(src)
|
||||
}
|
4
vendor/github.com/bytedance/sonic/internal/cpu/features.go
generated
vendored
4
vendor/github.com/bytedance/sonic/internal/cpu/features.go
generated
vendored
|
@ -24,7 +24,6 @@
|
|||
)
|
||||
|
||||
var (
|
||||
HasAVX = cpuid.CPU.Has(cpuid.AVX)
|
||||
HasAVX2 = cpuid.CPU.Has(cpuid.AVX2)
|
||||
HasSSE = cpuid.CPU.Has(cpuid.SSE)
|
||||
)
|
||||
|
@ -33,7 +32,8 @@ func init() {
|
|||
switch v := os.Getenv("SONIC_MODE"); v {
|
||||
case "" : break
|
||||
case "auto" : break
|
||||
case "noavx" : HasAVX = false; fallthrough
|
||||
case "noavx" : HasAVX2 = false
|
||||
// will also disable avx, act as `noavx`, we remain it to make sure forward compatibility
|
||||
case "noavx2" : HasAVX2 = false
|
||||
default : panic(fmt.Sprintf("invalid mode: '%s', should be one of 'auto', 'noavx', 'noavx2'", v))
|
||||
}
|
||||
|
|
|
@ -14,51 +14,52 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package decoder
|
||||
package api
|
||||
|
||||
import (
|
||||
`unsafe`
|
||||
`encoding/json`
|
||||
`reflect`
|
||||
`runtime`
|
||||
|
||||
`github.com/bytedance/sonic/internal/native`
|
||||
`github.com/bytedance/sonic/internal/native/types`
|
||||
`github.com/bytedance/sonic/internal/decoder/consts`
|
||||
`github.com/bytedance/sonic/internal/decoder/errors`
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
`github.com/bytedance/sonic/option`
|
||||
`github.com/bytedance/sonic/utf8`
|
||||
)
|
||||
|
||||
const (
|
||||
_F_use_int64 = 0
|
||||
_F_disable_urc = 2
|
||||
_F_disable_unknown = 3
|
||||
_F_copy_string = 4
|
||||
_F_allow_control = consts.F_allow_control
|
||||
_F_copy_string = consts.F_copy_string
|
||||
_F_disable_unknown = consts.F_disable_unknown
|
||||
_F_disable_urc = consts.F_disable_urc
|
||||
_F_use_int64 = consts.F_use_int64
|
||||
_F_use_number = consts.F_use_number
|
||||
_F_validate_string = consts.F_validate_string
|
||||
|
||||
_F_use_number = types.B_USE_NUMBER
|
||||
_F_validate_string = types.B_VALIDATE_STRING
|
||||
_F_allow_control = types.B_ALLOW_CONTROL
|
||||
_MaxStack = consts.MaxStack
|
||||
|
||||
OptionUseInt64 = consts.OptionUseInt64
|
||||
OptionUseNumber = consts.OptionUseNumber
|
||||
OptionUseUnicodeErrors = consts.OptionUseUnicodeErrors
|
||||
OptionDisableUnknown = consts.OptionDisableUnknown
|
||||
OptionCopyString = consts.OptionCopyString
|
||||
OptionValidateString = consts.OptionValidateString
|
||||
OptionNoValidateJSON = consts.OptionNoValidateJSON
|
||||
)
|
||||
|
||||
type Options uint64
|
||||
|
||||
const (
|
||||
OptionUseInt64 Options = 1 << _F_use_int64
|
||||
OptionUseNumber Options = 1 << _F_use_number
|
||||
OptionUseUnicodeErrors Options = 1 << _F_disable_urc
|
||||
OptionDisableUnknown Options = 1 << _F_disable_unknown
|
||||
OptionCopyString Options = 1 << _F_copy_string
|
||||
OptionValidateString Options = 1 << _F_validate_string
|
||||
type (
|
||||
Options = consts.Options
|
||||
MismatchTypeError = errors.MismatchTypeError
|
||||
SyntaxError = errors.SyntaxError
|
||||
)
|
||||
|
||||
func (self *Decoder) SetOptions(opts Options) {
|
||||
if (opts & OptionUseNumber != 0) && (opts & OptionUseInt64 != 0) {
|
||||
if (opts & consts.OptionUseNumber != 0) && (opts & consts.OptionUseInt64 != 0) {
|
||||
panic("can't set OptionUseInt64 and OptionUseNumber both!")
|
||||
}
|
||||
self.f = uint64(opts)
|
||||
}
|
||||
|
||||
|
||||
// Decoder is the decoder context object
|
||||
type Decoder struct {
|
||||
i int
|
||||
|
@ -109,44 +110,7 @@ func (self *Decoder) CheckTrailings() error {
|
|||
// Decode parses the JSON-encoded data from current position and stores the result
|
||||
// in the value pointed to by val.
|
||||
func (self *Decoder) Decode(val interface{}) error {
|
||||
/* validate json if needed */
|
||||
if (self.f & (1 << _F_validate_string)) != 0 && !utf8.ValidateString(self.s){
|
||||
dbuf := utf8.CorrectWith(nil, rt.Str2Mem(self.s), "\ufffd")
|
||||
self.s = rt.Mem2Str(dbuf)
|
||||
}
|
||||
|
||||
vv := rt.UnpackEface(val)
|
||||
vp := vv.Value
|
||||
|
||||
/* check for nil type */
|
||||
if vv.Type == nil {
|
||||
return &json.InvalidUnmarshalError{}
|
||||
}
|
||||
|
||||
/* must be a non-nil pointer */
|
||||
if vp == nil || vv.Type.Kind() != reflect.Ptr {
|
||||
return &json.InvalidUnmarshalError{Type: vv.Type.Pack()}
|
||||
}
|
||||
|
||||
etp := rt.PtrElem(vv.Type)
|
||||
|
||||
/* check the defined pointer type for issue 379 */
|
||||
if vv.Type.IsNamed() {
|
||||
newp := vp
|
||||
etp = vv.Type
|
||||
vp = unsafe.Pointer(&newp)
|
||||
}
|
||||
|
||||
/* create a new stack, and call the decoder */
|
||||
sb := newStack()
|
||||
nb, err := decodeTypedPointer(self.s, self.i, etp, vp, sb, self.f)
|
||||
/* return the stack back */
|
||||
self.i = nb
|
||||
freeStack(sb)
|
||||
|
||||
/* avoid GC ahead */
|
||||
runtime.KeepAlive(vv)
|
||||
return err
|
||||
return decodeImpl(&self.s, &self.i, self.f, val)
|
||||
}
|
||||
|
||||
// UseInt64 indicates the Decoder to unmarshal an integer into an interface{} as an
|
||||
|
@ -194,53 +158,7 @@ func (self *Decoder) ValidateString() {
|
|||
// Opts are the compile options, for example, "option.WithCompileRecursiveDepth" is
|
||||
// a compile option to set the depth of recursive compile for the nested struct type.
|
||||
func Pretouch(vt reflect.Type, opts ...option.CompileOption) error {
|
||||
cfg := option.DefaultCompileOptions()
|
||||
for _, opt := range opts {
|
||||
opt(&cfg)
|
||||
}
|
||||
return pretouchRec(map[reflect.Type]bool{vt:true}, cfg)
|
||||
}
|
||||
|
||||
func pretouchType(_vt reflect.Type, opts option.CompileOptions) (map[reflect.Type]bool, error) {
|
||||
/* compile function */
|
||||
compiler := newCompiler().apply(opts)
|
||||
decoder := func(vt *rt.GoType, _ ...interface{}) (interface{}, error) {
|
||||
if pp, err := compiler.compile(_vt); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
as := newAssembler(pp)
|
||||
as.name = _vt.String()
|
||||
return as.Load(), nil
|
||||
}
|
||||
}
|
||||
|
||||
/* find or compile */
|
||||
vt := rt.UnpackType(_vt)
|
||||
if val := programCache.Get(vt); val != nil {
|
||||
return nil, nil
|
||||
} else if _, err := programCache.Compute(vt, decoder); err == nil {
|
||||
return compiler.rec, nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func pretouchRec(vtm map[reflect.Type]bool, opts option.CompileOptions) error {
|
||||
if opts.RecursiveDepth < 0 || len(vtm) == 0 {
|
||||
return nil
|
||||
}
|
||||
next := make(map[reflect.Type]bool)
|
||||
for vt := range(vtm) {
|
||||
sub, err := pretouchType(vt, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for svt := range(sub) {
|
||||
next[svt] = true
|
||||
}
|
||||
}
|
||||
opts.RecursiveDepth -= 1
|
||||
return pretouchRec(next, opts)
|
||||
return pretouchImpl(vt, opts...)
|
||||
}
|
||||
|
||||
// Skip skips only one json value, and returns first non-blank character position and its ending position if it is valid.
|
38
vendor/github.com/bytedance/sonic/internal/decoder/api/decoder_amd64.go
generated
vendored
Normal file
38
vendor/github.com/bytedance/sonic/internal/decoder/api/decoder_amd64.go
generated
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
//go:build go1.17 && !go1.24
|
||||
// +build go1.17,!go1.24
|
||||
|
||||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/bytedance/sonic/internal/envs"
|
||||
"github.com/bytedance/sonic/internal/decoder/jitdec"
|
||||
"github.com/bytedance/sonic/internal/decoder/optdec"
|
||||
)
|
||||
|
||||
var (
|
||||
pretouchImpl = jitdec.Pretouch
|
||||
decodeImpl = jitdec.Decode
|
||||
)
|
||||
|
||||
func init() {
|
||||
if envs.UseOptDec {
|
||||
pretouchImpl = optdec.Pretouch
|
||||
decodeImpl = optdec.Decode
|
||||
}
|
||||
}
|
|
@ -1,6 +1,4 @@
|
|||
// Code generated by Makefile, DO NOT EDIT.
|
||||
|
||||
// Code generated by Makefile, DO NOT EDIT.
|
||||
// +build go1.17,!go1.24
|
||||
|
||||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
|
@ -18,19 +16,23 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package avx
|
||||
package api
|
||||
|
||||
import (
|
||||
`unsafe`
|
||||
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
`github.com/bytedance/sonic/internal/decoder/optdec`
|
||||
`github.com/bytedance/sonic/internal/envs`
|
||||
)
|
||||
|
||||
var F_u64toa func(out unsafe.Pointer, val uint64) (ret int)
|
||||
var (
|
||||
pretouchImpl = optdec.Pretouch
|
||||
decodeImpl = optdec.Decode
|
||||
)
|
||||
|
||||
var S_u64toa uintptr
|
||||
|
||||
//go:nosplit
|
||||
func u64toa(out *byte, val uint64) (ret int) {
|
||||
return F_u64toa(rt.NoEscape(unsafe.Pointer(out)), val)
|
||||
func init() {
|
||||
// whe in aarch64. we enable all optimize
|
||||
envs.EnableOptDec()
|
||||
envs.EnableFastMap()
|
||||
}
|
||||
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package decoder
|
||||
package api
|
||||
|
||||
import (
|
||||
`bytes`
|
||||
|
@ -47,6 +47,12 @@ type StreamDecoder struct {
|
|||
},
|
||||
}
|
||||
|
||||
func freeBytes(buf []byte) {
|
||||
if rt.CanSizeResue(cap(buf)) {
|
||||
bufPool.Put(buf[:0])
|
||||
}
|
||||
}
|
||||
|
||||
// NewStreamDecoder adapts to encoding/json.NewDecoder API.
|
||||
//
|
||||
// NewStreamDecoder returns a new decoder that reads from r.
|
||||
|
@ -61,25 +67,16 @@ func NewStreamDecoder(r io.Reader) *StreamDecoder {
|
|||
func (self *StreamDecoder) Decode(val interface{}) (err error) {
|
||||
// read more data into buf
|
||||
if self.More() {
|
||||
// println(string(self.buf))
|
||||
var s = self.scanp
|
||||
try_skip:
|
||||
var e = len(self.buf)
|
||||
// println("s:", s, "e:", e, "scanned:",self.scanned, "scanp:",self.scanp, self.buf)
|
||||
var src = rt.Mem2Str(self.buf[s:e])
|
||||
// if len(src) > 5 {
|
||||
// println(src[:5], src[len(src)-5:])
|
||||
// } else {
|
||||
// println(src)
|
||||
// }
|
||||
// try skip
|
||||
var x = 0;
|
||||
if y := native.SkipOneFast(&src, &x); y < 0 {
|
||||
if self.readMore() {
|
||||
// println("more")
|
||||
goto try_skip
|
||||
} else {
|
||||
// println("no more")
|
||||
err = SyntaxError{e, self.s, types.ParsingError(-s), ""}
|
||||
self.setErr(err)
|
||||
return
|
||||
|
@ -89,7 +86,6 @@ func (self *StreamDecoder) Decode(val interface{}) (err error) {
|
|||
e = x + s
|
||||
}
|
||||
|
||||
// println("decode: ", s, e)
|
||||
// must copy string here for safety
|
||||
self.Decoder.Reset(string(self.buf[s:e]))
|
||||
err = self.Decoder.Decode(val)
|
||||
|
@ -101,13 +97,11 @@ func (self *StreamDecoder) Decode(val interface{}) (err error) {
|
|||
self.scanp = e
|
||||
_, empty := self.scan()
|
||||
if empty {
|
||||
// println("recycle")
|
||||
// no remain valid bytes, thus we just recycle buffer
|
||||
mem := self.buf
|
||||
self.buf = nil
|
||||
bufPool.Put(mem[:0])
|
||||
freeBytes(mem)
|
||||
} else {
|
||||
// println("keep")
|
||||
// remain undecoded bytes, move them onto head
|
||||
n := copy(self.buf, self.buf[self.scanp:])
|
||||
self.buf = self.buf[:n]
|
||||
|
@ -123,7 +117,6 @@ func (self *StreamDecoder) Decode(val interface{}) (err error) {
|
|||
// InputOffset returns the input stream byte offset of the current decoder position.
|
||||
// The offset gives the location of the end of the most recently returned token and the beginning of the next token.
|
||||
func (self *StreamDecoder) InputOffset() int64 {
|
||||
// println("input offset",self.scanned, self.scanp)
|
||||
return self.scanned + int64(self.scanp)
|
||||
}
|
||||
|
||||
|
@ -178,7 +171,7 @@ func (self *StreamDecoder) setErr(err error) {
|
|||
self.err = err
|
||||
mem := self.buf[:0]
|
||||
self.buf = nil
|
||||
bufPool.Put(mem)
|
||||
freeBytes(mem)
|
||||
}
|
||||
|
||||
func (self *StreamDecoder) peek() (byte, error) {
|
||||
|
@ -237,12 +230,10 @@ func realloc(buf *[]byte) bool {
|
|||
l := uint(len(*buf))
|
||||
c := uint(cap(*buf))
|
||||
if c == 0 {
|
||||
// println("use pool!")
|
||||
*buf = bufPool.Get().([]byte)
|
||||
return true
|
||||
}
|
||||
if c - l <= c >> minLeftBufferShift {
|
||||
// println("realloc!")
|
||||
e := l+(l>>minLeftBufferShift)
|
||||
if e <= c {
|
||||
e = c*2
|
130
vendor/github.com/bytedance/sonic/internal/decoder/asm_stubs_amd64_go116.go
generated
vendored
130
vendor/github.com/bytedance/sonic/internal/decoder/asm_stubs_amd64_go116.go
generated
vendored
|
@ -1,130 +0,0 @@
|
|||
// +build go1.16,!go1.17
|
||||
|
||||
// Copyright 2023 CloudWeGo Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package decoder
|
||||
|
||||
import (
|
||||
`strconv`
|
||||
_ `unsafe`
|
||||
|
||||
`github.com/bytedance/sonic/internal/jit`
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
`github.com/twitchyliquid64/golang-asm/obj`
|
||||
`github.com/twitchyliquid64/golang-asm/obj/x86`
|
||||
)
|
||||
|
||||
var _runtime_writeBarrier uintptr = rt.GcwbAddr()
|
||||
|
||||
//go:linkname gcWriteBarrierAX runtime.gcWriteBarrier
|
||||
func gcWriteBarrierAX()
|
||||
|
||||
var (
|
||||
_V_writeBarrier = jit.Imm(int64(_runtime_writeBarrier))
|
||||
|
||||
_F_gcWriteBarrierAX = jit.Func(gcWriteBarrierAX)
|
||||
)
|
||||
|
||||
func (self *_Assembler) WritePtrAX(i int, rec obj.Addr, saveDI bool) {
|
||||
self.Emit("MOVQ", _V_writeBarrier, _R10)
|
||||
self.Emit("CMPL", jit.Ptr(_R10, 0), jit.Imm(0))
|
||||
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
if saveDI {
|
||||
self.save(_DI)
|
||||
}
|
||||
self.Emit("LEAQ", rec, _DI)
|
||||
self.Emit("MOVQ", _F_gcWriteBarrierAX, _R10) // MOVQ ${fn}, AX
|
||||
self.Rjmp("CALL", _R10)
|
||||
if saveDI {
|
||||
self.load(_DI)
|
||||
}
|
||||
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
self.Emit("MOVQ", _AX, rec)
|
||||
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
}
|
||||
|
||||
func (self *_Assembler) WriteRecNotAX(i int, ptr obj.Addr, rec obj.Addr, saveDI bool, saveAX bool) {
|
||||
if rec.Reg == x86.REG_AX || rec.Index == x86.REG_AX {
|
||||
panic("rec contains AX!")
|
||||
}
|
||||
self.Emit("MOVQ", _V_writeBarrier, _R10)
|
||||
self.Emit("CMPL", jit.Ptr(_R10, 0), jit.Imm(0))
|
||||
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
if saveAX {
|
||||
self.Emit("XCHGQ", ptr, _AX)
|
||||
} else {
|
||||
self.Emit("MOVQ", ptr, _AX)
|
||||
}
|
||||
if saveDI {
|
||||
self.save(_DI)
|
||||
}
|
||||
self.Emit("LEAQ", rec, _DI)
|
||||
self.Emit("MOVQ", _F_gcWriteBarrierAX, _R10) // MOVQ ${fn}, AX
|
||||
self.Rjmp("CALL", _R10)
|
||||
if saveDI {
|
||||
self.load(_DI)
|
||||
}
|
||||
if saveAX {
|
||||
self.Emit("XCHGQ", ptr, _AX)
|
||||
}
|
||||
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
self.Emit("MOVQ", ptr, rec)
|
||||
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
}
|
||||
|
||||
|
||||
func (self *_ValueDecoder) WritePtrAX(i int, rec obj.Addr, saveDI bool) {
|
||||
self.Emit("MOVQ", _V_writeBarrier, _R10)
|
||||
self.Emit("CMPL", jit.Ptr(_R10, 0), jit.Imm(0))
|
||||
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
if saveDI {
|
||||
self.save(_DI)
|
||||
}
|
||||
self.Emit("LEAQ", rec, _DI)
|
||||
self.Emit("MOVQ", _F_gcWriteBarrierAX, _R10) // MOVQ ${fn}, AX
|
||||
self.Rjmp("CALL", _R10)
|
||||
if saveDI {
|
||||
self.load(_DI)
|
||||
}
|
||||
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
self.Emit("MOVQ", _AX, rec)
|
||||
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
}
|
||||
|
||||
func (self *_ValueDecoder) WriteRecNotAX(i int, ptr obj.Addr, rec obj.Addr, saveDI bool) {
|
||||
if rec.Reg == x86.REG_AX || rec.Index == x86.REG_AX {
|
||||
panic("rec contains AX!")
|
||||
}
|
||||
self.Emit("MOVQ", _V_writeBarrier, _R10)
|
||||
self.Emit("CMPL", jit.Ptr(_R10, 0), jit.Imm(0))
|
||||
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
self.Emit("MOVQ", ptr, _AX)
|
||||
if saveDI {
|
||||
self.save(_DI)
|
||||
}
|
||||
self.Emit("LEAQ", rec, _DI)
|
||||
self.Emit("MOVQ", _F_gcWriteBarrierAX, _R10) // MOVQ ${fn}, AX
|
||||
self.Rjmp("CALL", _R10)
|
||||
if saveDI {
|
||||
self.load(_DI)
|
||||
}
|
||||
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
self.Emit("MOVQ", ptr, rec)
|
||||
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
}
|
1950
vendor/github.com/bytedance/sonic/internal/decoder/assembler_stkabi_amd64.go
generated
vendored
1950
vendor/github.com/bytedance/sonic/internal/decoder/assembler_stkabi_amd64.go
generated
vendored
File diff suppressed because it is too large
Load diff
36
vendor/github.com/bytedance/sonic/internal/decoder/consts/option.go
generated
vendored
Normal file
36
vendor/github.com/bytedance/sonic/internal/decoder/consts/option.go
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
|
||||
package consts
|
||||
|
||||
import (
|
||||
`github.com/bytedance/sonic/internal/native/types`
|
||||
)
|
||||
|
||||
|
||||
const (
|
||||
F_use_int64 = 0
|
||||
F_disable_urc = 2
|
||||
F_disable_unknown = 3
|
||||
F_copy_string = 4
|
||||
|
||||
|
||||
F_use_number = types.B_USE_NUMBER
|
||||
F_validate_string = types.B_VALIDATE_STRING
|
||||
F_allow_control = types.B_ALLOW_CONTROL
|
||||
F_no_validate_json = types.B_NO_VALIDATE_JSON
|
||||
)
|
||||
|
||||
type Options uint64
|
||||
|
||||
const (
|
||||
OptionUseInt64 Options = 1 << F_use_int64
|
||||
OptionUseNumber Options = 1 << F_use_number
|
||||
OptionUseUnicodeErrors Options = 1 << F_disable_urc
|
||||
OptionDisableUnknown Options = 1 << F_disable_unknown
|
||||
OptionCopyString Options = 1 << F_copy_string
|
||||
OptionValidateString Options = 1 << F_validate_string
|
||||
OptionNoValidateJSON Options = 1 << F_no_validate_json
|
||||
)
|
||||
|
||||
const (
|
||||
MaxStack = 4096
|
||||
)
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package decoder
|
||||
package errors
|
||||
|
||||
import (
|
||||
`encoding/json`
|
||||
|
@ -46,7 +46,7 @@ func (self SyntaxError) Description() string {
|
|||
func (self SyntaxError) description() string {
|
||||
/* check for empty source */
|
||||
if self.Src == "" {
|
||||
return fmt.Sprintf("no sources available: %#v", self)
|
||||
return fmt.Sprintf("no sources available, the input json is empty: %#v", self)
|
||||
}
|
||||
|
||||
p, x, q, y := calcBounds(len(self.Src), self.Pos)
|
||||
|
@ -112,12 +112,12 @@ func clamp_zero(v int) int {
|
|||
|
||||
/** JIT Error Helpers **/
|
||||
|
||||
var stackOverflow = &json.UnsupportedValueError {
|
||||
var StackOverflow = &json.UnsupportedValueError {
|
||||
Str : "Value nesting too deep",
|
||||
Value : reflect.ValueOf("..."),
|
||||
}
|
||||
|
||||
func error_wrap(src string, pos int, code types.ParsingError) error {
|
||||
func ErrorWrap(src string, pos int, code types.ParsingError) error {
|
||||
return *error_wrap_heap(src, pos, code)
|
||||
}
|
||||
|
||||
|
@ -130,7 +130,7 @@ func error_wrap_heap(src string, pos int, code types.ParsingError) *SyntaxError
|
|||
}
|
||||
}
|
||||
|
||||
func error_type(vt *rt.GoType) error {
|
||||
func ErrorType(vt *rt.GoType) error {
|
||||
return &json.UnmarshalTypeError{Type: vt.Pack()}
|
||||
}
|
||||
|
||||
|
@ -171,7 +171,7 @@ func (self MismatchTypeError) Description() string {
|
|||
return fmt.Sprintf("Mismatch type %s with value %s %s", self.Type.String(), swithchJSONType(self.Src, self.Pos), se.description())
|
||||
}
|
||||
|
||||
func error_mismatch(src string, pos int, vt *rt.GoType) error {
|
||||
func ErrorMismatch(src string, pos int, vt *rt.GoType) error {
|
||||
return &MismatchTypeError {
|
||||
Pos : pos,
|
||||
Src : src,
|
||||
|
@ -179,11 +179,11 @@ func error_mismatch(src string, pos int, vt *rt.GoType) error {
|
|||
}
|
||||
}
|
||||
|
||||
func error_field(name string) error {
|
||||
func ErrorField(name string) error {
|
||||
return errors.New("json: unknown field " + strconv.Quote(name))
|
||||
}
|
||||
|
||||
func error_value(value string, vtype reflect.Type) error {
|
||||
func ErrorValue(value string, vtype reflect.Type) error {
|
||||
return &json.UnmarshalTypeError {
|
||||
Type : vtype,
|
||||
Value : value,
|
733
vendor/github.com/bytedance/sonic/internal/decoder/generic_stkabi_amd64.go
generated
vendored
733
vendor/github.com/bytedance/sonic/internal/decoder/generic_stkabi_amd64.go
generated
vendored
|
@ -1,733 +0,0 @@
|
|||
// +build go1.16,!go1.17
|
||||
|
||||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package decoder
|
||||
|
||||
import (
|
||||
`encoding/json`
|
||||
`fmt`
|
||||
`reflect`
|
||||
|
||||
`github.com/bytedance/sonic/internal/jit`
|
||||
`github.com/bytedance/sonic/internal/native`
|
||||
`github.com/bytedance/sonic/internal/native/types`
|
||||
`github.com/twitchyliquid64/golang-asm/obj`
|
||||
)
|
||||
|
||||
/** Crucial Registers:
|
||||
*
|
||||
* ST(BX) : ro, decoder stack
|
||||
* DF(R10) : ro, decoder flags
|
||||
* EP(R11) : wo, error pointer
|
||||
* IP(R12) : ro, input pointer
|
||||
* IL(R13) : ro, input length
|
||||
* IC(R14) : rw, input cursor
|
||||
* VP(R15) : ro, value pointer (to an interface{})
|
||||
*/
|
||||
|
||||
const (
|
||||
_VD_args = 8 // 8 bytes for passing arguments to this functions
|
||||
_VD_fargs = 64 // 64 bytes for passing arguments to other Go functions
|
||||
_VD_saves = 40 // 40 bytes for saving the registers before CALL instructions
|
||||
_VD_locals = 88 // 88 bytes for local variables
|
||||
)
|
||||
|
||||
const (
|
||||
_VD_offs = _VD_fargs + _VD_saves + _VD_locals
|
||||
_VD_size = _VD_offs + 8 // 8 bytes for the parent frame pointer
|
||||
)
|
||||
|
||||
var (
|
||||
_VAR_ss = _VAR_ss_Vt
|
||||
_VAR_df = jit.Ptr(_SP, _VD_fargs + _VD_saves)
|
||||
)
|
||||
|
||||
var (
|
||||
_VAR_ss_Vt = jit.Ptr(_SP, _VD_fargs + _VD_saves + 8)
|
||||
_VAR_ss_Dv = jit.Ptr(_SP, _VD_fargs + _VD_saves + 16)
|
||||
_VAR_ss_Iv = jit.Ptr(_SP, _VD_fargs + _VD_saves + 24)
|
||||
_VAR_ss_Ep = jit.Ptr(_SP, _VD_fargs + _VD_saves + 32)
|
||||
_VAR_ss_Db = jit.Ptr(_SP, _VD_fargs + _VD_saves + 40)
|
||||
_VAR_ss_Dc = jit.Ptr(_SP, _VD_fargs + _VD_saves + 48)
|
||||
)
|
||||
|
||||
var (
|
||||
_VAR_cs_LR = jit.Ptr(_SP, _VD_fargs + _VD_saves + 56)
|
||||
_VAR_cs_p = jit.Ptr(_SP, _VD_fargs + _VD_saves + 64)
|
||||
_VAR_cs_n = jit.Ptr(_SP, _VD_fargs + _VD_saves + 72)
|
||||
_VAR_cs_d = jit.Ptr(_SP, _VD_fargs + _VD_saves + 80)
|
||||
)
|
||||
|
||||
type _ValueDecoder struct {
|
||||
jit.BaseAssembler
|
||||
}
|
||||
|
||||
func (self *_ValueDecoder) build() uintptr {
|
||||
self.Init(self.compile)
|
||||
return *(*uintptr)(self.Load("decode_value", _VD_size, _VD_args, argPtrs_generic, localPtrs_generic))
|
||||
}
|
||||
|
||||
/** Function Calling Helpers **/
|
||||
|
||||
func (self *_ValueDecoder) save(r ...obj.Addr) {
|
||||
for i, v := range r {
|
||||
if i > _VD_saves / 8 - 1 {
|
||||
panic("too many registers to save")
|
||||
} else {
|
||||
self.Emit("MOVQ", v, jit.Ptr(_SP, _VD_fargs + int64(i) * 8))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_ValueDecoder) load(r ...obj.Addr) {
|
||||
for i, v := range r {
|
||||
if i > _VD_saves / 8 - 1 {
|
||||
panic("too many registers to load")
|
||||
} else {
|
||||
self.Emit("MOVQ", jit.Ptr(_SP, _VD_fargs + int64(i) * 8), v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_ValueDecoder) call(fn obj.Addr) {
|
||||
self.Emit("MOVQ", fn, _AX) // MOVQ ${fn}, AX
|
||||
self.Rjmp("CALL", _AX) // CALL AX
|
||||
}
|
||||
|
||||
func (self *_ValueDecoder) call_go(fn obj.Addr) {
|
||||
self.save(_REG_go...) // SAVE $REG_go
|
||||
self.call(fn) // CALL ${fn}
|
||||
self.load(_REG_go...) // LOAD $REG_go
|
||||
}
|
||||
|
||||
/** Decoder Assembler **/
|
||||
|
||||
const (
|
||||
_S_val = iota + 1
|
||||
_S_arr
|
||||
_S_arr_0
|
||||
_S_obj
|
||||
_S_obj_0
|
||||
_S_obj_delim
|
||||
_S_obj_sep
|
||||
)
|
||||
|
||||
const (
|
||||
_S_omask_key = (1 << _S_obj_0) | (1 << _S_obj_sep)
|
||||
_S_omask_end = (1 << _S_obj_0) | (1 << _S_obj)
|
||||
_S_vmask = (1 << _S_val) | (1 << _S_arr_0)
|
||||
)
|
||||
|
||||
const (
|
||||
_A_init_len = 1
|
||||
_A_init_cap = 16
|
||||
)
|
||||
|
||||
const (
|
||||
_ST_Sp = 0
|
||||
_ST_Vt = _PtrBytes
|
||||
_ST_Vp = _PtrBytes * (types.MAX_RECURSE + 1)
|
||||
)
|
||||
|
||||
var (
|
||||
_V_true = jit.Imm(int64(pbool(true)))
|
||||
_V_false = jit.Imm(int64(pbool(false)))
|
||||
_F_value = jit.Imm(int64(native.S_value))
|
||||
)
|
||||
|
||||
var (
|
||||
_V_max = jit.Imm(int64(types.V_MAX))
|
||||
_E_eof = jit.Imm(int64(types.ERR_EOF))
|
||||
_E_invalid = jit.Imm(int64(types.ERR_INVALID_CHAR))
|
||||
_E_recurse = jit.Imm(int64(types.ERR_RECURSE_EXCEED_MAX))
|
||||
)
|
||||
|
||||
var (
|
||||
_F_convTslice = jit.Func(convTslice)
|
||||
_F_convTstring = jit.Func(convTstring)
|
||||
_F_invalid_vtype = jit.Func(invalid_vtype)
|
||||
)
|
||||
|
||||
var (
|
||||
_T_map = jit.Type(reflect.TypeOf((map[string]interface{})(nil)))
|
||||
_T_bool = jit.Type(reflect.TypeOf(false))
|
||||
_T_int64 = jit.Type(reflect.TypeOf(int64(0)))
|
||||
_T_eface = jit.Type(reflect.TypeOf((*interface{})(nil)).Elem())
|
||||
_T_slice = jit.Type(reflect.TypeOf(([]interface{})(nil)))
|
||||
_T_string = jit.Type(reflect.TypeOf(""))
|
||||
_T_number = jit.Type(reflect.TypeOf(json.Number("")))
|
||||
_T_float64 = jit.Type(reflect.TypeOf(float64(0)))
|
||||
)
|
||||
|
||||
var _R_tab = map[int]string {
|
||||
'[': "_decode_V_ARRAY",
|
||||
'{': "_decode_V_OBJECT",
|
||||
':': "_decode_V_KEY_SEP",
|
||||
',': "_decode_V_ELEM_SEP",
|
||||
']': "_decode_V_ARRAY_END",
|
||||
'}': "_decode_V_OBJECT_END",
|
||||
}
|
||||
|
||||
func (self *_ValueDecoder) compile() {
|
||||
self.Emit("SUBQ", jit.Imm(_VD_size), _SP) // SUBQ $_VD_size, SP
|
||||
self.Emit("MOVQ", _BP, jit.Ptr(_SP, _VD_offs)) // MOVQ BP, _VD_offs(SP)
|
||||
self.Emit("LEAQ", jit.Ptr(_SP, _VD_offs), _BP) // LEAQ _VD_offs(SP), BP
|
||||
|
||||
/* initialize the state machine */
|
||||
self.Emit("XORL", _CX, _CX) // XORL CX, CX
|
||||
self.Emit("MOVQ", _DF, _VAR_df) // MOVQ DF, df
|
||||
/* initialize digital buffer first */
|
||||
self.Emit("MOVQ", jit.Imm(_MaxDigitNums), _VAR_ss_Dc) // MOVQ $_MaxDigitNums, ss.Dcap
|
||||
self.Emit("LEAQ", jit.Ptr(_ST, _DbufOffset), _AX) // LEAQ _DbufOffset(ST), AX
|
||||
self.Emit("MOVQ", _AX, _VAR_ss_Db) // MOVQ AX, ss.Dbuf
|
||||
/* add ST offset */
|
||||
self.Emit("ADDQ", jit.Imm(_FsmOffset), _ST) // ADDQ _FsmOffset, _ST
|
||||
self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp
|
||||
self.WriteRecNotAX(0, _VP, jit.Ptr(_ST, _ST_Vp), false) // MOVQ VP, ST.Vp[0]
|
||||
self.Emit("MOVQ", jit.Imm(_S_val), jit.Ptr(_ST, _ST_Vt)) // MOVQ _S_val, ST.Vt[0]
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/* set the value from previous round */
|
||||
self.Link("_set_value") // _set_value:
|
||||
self.Emit("MOVL" , jit.Imm(_S_vmask), _DX) // MOVL _S_vmask, DX
|
||||
self.Emit("MOVQ" , jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ" , jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
|
||||
self.Emit("BTQ" , _AX, _DX) // BTQ AX, DX
|
||||
self.Sjmp("JNC" , "_vtype_error") // JNC _vtype_error
|
||||
self.Emit("XORL" , _SI, _SI) // XORL SI, SI
|
||||
self.Emit("SUBQ" , jit.Imm(1), jit.Ptr(_ST, _ST_Sp)) // SUBQ $1, ST.Sp
|
||||
self.Emit("XCHGQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // XCHGQ ST.Vp[CX], SI
|
||||
self.Emit("MOVQ" , _R8, jit.Ptr(_SI, 0)) // MOVQ R8, (SI)
|
||||
self.WriteRecNotAX(1, _R9, jit.Ptr(_SI, 8), false) // MOVQ R9, 8(SI)
|
||||
|
||||
/* check for value stack */
|
||||
self.Link("_next") // _next:
|
||||
self.Emit("MOVQ" , jit.Ptr(_ST, _ST_Sp), _AX) // MOVQ ST.Sp, AX
|
||||
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
|
||||
self.Sjmp("JS" , "_return") // JS _return
|
||||
|
||||
/* fast path: test up to 4 characters manually */
|
||||
self.Emit("CMPQ" , _IC, _IL) // CMPQ IC, IL
|
||||
self.Sjmp("JAE" , "_decode_V_EOF") // JAE _decode_V_EOF
|
||||
self.Emit("MOVBQZX", jit.Sib(_IP, _IC, 1, 0), _AX) // MOVBQZX (IP)(IC), AX
|
||||
self.Emit("MOVQ" , jit.Imm(_BM_space), _DX) // MOVQ _BM_space, DX
|
||||
self.Emit("CMPQ" , _AX, jit.Imm(' ')) // CMPQ AX, $' '
|
||||
self.Sjmp("JA" , "_decode_fast") // JA _decode_fast
|
||||
self.Emit("BTQ" , _AX, _DX) // BTQ _AX, _DX
|
||||
self.Sjmp("JNC" , "_decode_fast") // JNC _decode_fast
|
||||
self.Emit("ADDQ" , jit.Imm(1), _IC) // ADDQ $1, IC
|
||||
|
||||
/* at least 1 to 3 spaces */
|
||||
for i := 0; i < 3; i++ {
|
||||
self.Emit("CMPQ" , _IC, _IL) // CMPQ IC, IL
|
||||
self.Sjmp("JAE" , "_decode_V_EOF") // JAE _decode_V_EOF
|
||||
self.Emit("MOVBQZX", jit.Sib(_IP, _IC, 1, 0), _AX) // MOVBQZX (IP)(IC), AX
|
||||
self.Emit("CMPQ" , _AX, jit.Imm(' ')) // CMPQ AX, $' '
|
||||
self.Sjmp("JA" , "_decode_fast") // JA _decode_fast
|
||||
self.Emit("BTQ" , _AX, _DX) // BTQ _AX, _DX
|
||||
self.Sjmp("JNC" , "_decode_fast") // JNC _decode_fast
|
||||
self.Emit("ADDQ" , jit.Imm(1), _IC) // ADDQ $1, IC
|
||||
}
|
||||
|
||||
/* at least 4 spaces */
|
||||
self.Emit("CMPQ" , _IC, _IL) // CMPQ IC, IL
|
||||
self.Sjmp("JAE" , "_decode_V_EOF") // JAE _decode_V_EOF
|
||||
self.Emit("MOVBQZX", jit.Sib(_IP, _IC, 1, 0), _AX) // MOVBQZX (IP)(IC), AX
|
||||
|
||||
/* fast path: use lookup table to select decoder */
|
||||
self.Link("_decode_fast") // _decode_fast:
|
||||
self.Byte(0x48, 0x8d, 0x3d) // LEAQ ?(PC), DI
|
||||
self.Sref("_decode_tab", 4) // .... &_decode_tab
|
||||
self.Emit("MOVLQSX", jit.Sib(_DI, _AX, 4, 0), _AX) // MOVLQSX (DI)(AX*4), AX
|
||||
self.Emit("TESTQ" , _AX, _AX) // TESTQ AX, AX
|
||||
self.Sjmp("JZ" , "_decode_native") // JZ _decode_native
|
||||
self.Emit("ADDQ" , jit.Imm(1), _IC) // ADDQ $1, IC
|
||||
self.Emit("ADDQ" , _DI, _AX) // ADDQ DI, AX
|
||||
self.Rjmp("JMP" , _AX) // JMP AX
|
||||
|
||||
/* decode with native decoder */
|
||||
self.Link("_decode_native") // _decode_native:
|
||||
self.Emit("MOVQ", _IP, _DI) // MOVQ IP, DI
|
||||
self.Emit("MOVQ", _IL, _SI) // MOVQ IL, SI
|
||||
self.Emit("MOVQ", _IC, _DX) // MOVQ IC, DX
|
||||
self.Emit("LEAQ", _VAR_ss, _CX) // LEAQ ss, CX
|
||||
self.Emit("MOVQ", _VAR_df, _R8) // MOVQ $df, R8
|
||||
self.Emit("BTSQ", jit.Imm(_F_allow_control), _R8) // ANDQ $1<<_F_allow_control, R8
|
||||
self.call(_F_value) // CALL value
|
||||
self.Emit("MOVQ", _AX, _IC) // MOVQ AX, IC
|
||||
|
||||
/* check for errors */
|
||||
self.Emit("MOVQ" , _VAR_ss_Vt, _AX) // MOVQ ss.Vt, AX
|
||||
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
|
||||
self.Sjmp("JS" , "_parsing_error")
|
||||
self.Sjmp("JZ" , "_invalid_vtype") // JZ _invalid_vtype
|
||||
self.Emit("CMPQ" , _AX, _V_max) // CMPQ AX, _V_max
|
||||
self.Sjmp("JA" , "_invalid_vtype") // JA _invalid_vtype
|
||||
|
||||
/* jump table selector */
|
||||
self.Byte(0x48, 0x8d, 0x3d) // LEAQ ?(PC), DI
|
||||
self.Sref("_switch_table", 4) // .... &_switch_table
|
||||
self.Emit("MOVLQSX", jit.Sib(_DI, _AX, 4, -4), _AX) // MOVLQSX -4(DI)(AX*4), AX
|
||||
self.Emit("ADDQ" , _DI, _AX) // ADDQ DI, AX
|
||||
self.Rjmp("JMP" , _AX) // JMP AX
|
||||
|
||||
/** V_EOF **/
|
||||
self.Link("_decode_V_EOF") // _decode_V_EOF:
|
||||
self.Emit("MOVL", _E_eof, _EP) // MOVL _E_eof, EP
|
||||
self.Sjmp("JMP" , "_error") // JMP _error
|
||||
|
||||
/** V_NULL **/
|
||||
self.Link("_decode_V_NULL") // _decode_V_NULL:
|
||||
self.Emit("XORL", _R8, _R8) // XORL R8, R8
|
||||
self.Emit("XORL", _R9, _R9) // XORL R9, R9
|
||||
self.Emit("LEAQ", jit.Ptr(_IC, -4), _DI) // LEAQ -4(IC), DI
|
||||
self.Sjmp("JMP" , "_set_value") // JMP _set_value
|
||||
|
||||
/** V_TRUE **/
|
||||
self.Link("_decode_V_TRUE") // _decode_V_TRUE:
|
||||
self.Emit("MOVQ", _T_bool, _R8) // MOVQ _T_bool, R8
|
||||
// TODO: maybe modified by users?
|
||||
self.Emit("MOVQ", _V_true, _R9) // MOVQ _V_true, R9
|
||||
self.Emit("LEAQ", jit.Ptr(_IC, -4), _DI) // LEAQ -4(IC), DI
|
||||
self.Sjmp("JMP" , "_set_value") // JMP _set_value
|
||||
|
||||
/** V_FALSE **/
|
||||
self.Link("_decode_V_FALSE") // _decode_V_FALSE:
|
||||
self.Emit("MOVQ", _T_bool, _R8) // MOVQ _T_bool, R8
|
||||
self.Emit("MOVQ", _V_false, _R9) // MOVQ _V_false, R9
|
||||
self.Emit("LEAQ", jit.Ptr(_IC, -5), _DI) // LEAQ -5(IC), DI
|
||||
self.Sjmp("JMP" , "_set_value") // JMP _set_value
|
||||
|
||||
/** V_ARRAY **/
|
||||
self.Link("_decode_V_ARRAY") // _decode_V_ARRAY
|
||||
self.Emit("MOVL", jit.Imm(_S_vmask), _DX) // MOVL _S_vmask, DX
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
|
||||
self.Emit("BTQ" , _AX, _DX) // BTQ AX, DX
|
||||
self.Sjmp("JNC" , "_invalid_char") // JNC _invalid_char
|
||||
|
||||
/* create a new array */
|
||||
self.Emit("MOVQ", _T_eface, _AX) // MOVQ _T_eface, AX
|
||||
self.Emit("MOVQ", _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP)
|
||||
self.Emit("MOVQ", jit.Imm(_A_init_len), jit.Ptr(_SP, 8)) // MOVQ _A_init_len, 8(SP)
|
||||
self.Emit("MOVQ", jit.Imm(_A_init_cap), jit.Ptr(_SP, 16)) // MOVQ _A_init_cap, 16(SP)
|
||||
self.call_go(_F_makeslice) // CALL_GO runtime.makeslice
|
||||
self.Emit("MOVQ", jit.Ptr(_SP, 24), _DX) // MOVQ 24(SP), DX
|
||||
|
||||
/* pack into an interface */
|
||||
self.Emit("MOVQ", _DX, jit.Ptr(_SP, 0)) // MOVQ DX, (SP)
|
||||
self.Emit("MOVQ", jit.Imm(_A_init_len), jit.Ptr(_SP, 8)) // MOVQ _A_init_len, 8(SP)
|
||||
self.Emit("MOVQ", jit.Imm(_A_init_cap), jit.Ptr(_SP, 16)) // MOVQ _A_init_cap, 16(SP)
|
||||
self.call_go(_F_convTslice) // CALL_GO runtime.convTslice
|
||||
self.Emit("MOVQ", jit.Ptr(_SP, 24), _R8) // MOVQ 24(SP), R8
|
||||
|
||||
/* replace current state with an array */
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI
|
||||
self.Emit("MOVQ", jit.Imm(_S_arr), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_arr, ST.Vt[CX]
|
||||
self.Emit("MOVQ", _T_slice, _AX) // MOVQ _T_slice, AX
|
||||
self.Emit("MOVQ", _AX, jit.Ptr(_SI, 0)) // MOVQ AX, (SI)
|
||||
self.WriteRecNotAX(2, _R8, jit.Ptr(_SI, 8), false) // MOVQ R8, 8(SI)
|
||||
|
||||
/* add a new slot for the first element */
|
||||
self.Emit("ADDQ", jit.Imm(1), _CX) // ADDQ $1, CX
|
||||
self.Emit("CMPQ", _CX, jit.Imm(types.MAX_RECURSE)) // CMPQ CX, ${types.MAX_RECURSE}
|
||||
self.Sjmp("JAE" , "_stack_overflow") // JA _stack_overflow
|
||||
self.Emit("MOVQ", jit.Ptr(_R8, 0), _AX) // MOVQ (R8), AX
|
||||
self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp
|
||||
self.WritePtrAX(3, jit.Sib(_ST, _CX, 8, _ST_Vp), false) // MOVQ AX, ST.Vp[CX]
|
||||
self.Emit("MOVQ", jit.Imm(_S_arr_0), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_arr_0, ST.Vt[CX]
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/** V_OBJECT **/
|
||||
self.Link("_decode_V_OBJECT") // _decode_V_OBJECT:
|
||||
self.Emit("MOVL", jit.Imm(_S_vmask), _DX) // MOVL _S_vmask, DX
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
|
||||
self.Emit("BTQ" , _AX, _DX) // BTQ AX, DX
|
||||
self.Sjmp("JNC" , "_invalid_char") // JNC _invalid_char
|
||||
self.call_go(_F_makemap_small) // CALL_GO runtime.makemap_small
|
||||
self.Emit("MOVQ", jit.Ptr(_SP, 0), _AX) // MOVQ (SP), AX
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Imm(_S_obj_0), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_obj, ST.Vt[CX]
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI
|
||||
self.Emit("MOVQ", _T_map, _DX) // MOVQ _T_map, DX
|
||||
self.Emit("MOVQ", _DX, jit.Ptr(_SI, 0)) // MOVQ DX, (SI)
|
||||
self.WritePtrAX(4, jit.Ptr(_SI, 8), false) // MOVQ AX, 8(SI)
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/** V_STRING **/
|
||||
self.Link("_decode_V_STRING") // _decode_V_STRING:
|
||||
self.Emit("MOVQ", _VAR_ss_Iv, _CX) // MOVQ ss.Iv, CX
|
||||
self.Emit("MOVQ", _IC, _AX) // MOVQ IC, AX
|
||||
self.Emit("SUBQ", _CX, _AX) // SUBQ CX, AX
|
||||
|
||||
/* check for escapes */
|
||||
self.Emit("CMPQ", _VAR_ss_Ep, jit.Imm(-1)) // CMPQ ss.Ep, $-1
|
||||
self.Sjmp("JNE" , "_unquote") // JNE _unquote
|
||||
self.Emit("SUBQ", jit.Imm(1), _AX) // SUBQ $1, AX
|
||||
self.Emit("LEAQ", jit.Sib(_IP, _CX, 1, 0), _R8) // LEAQ (IP)(CX), R8
|
||||
self.Byte(0x48, 0x8d, 0x3d) // LEAQ (PC), DI
|
||||
self.Sref("_copy_string_end", 4)
|
||||
self.Emit("BTQ", jit.Imm(_F_copy_string), _VAR_df)
|
||||
self.Sjmp("JC", "copy_string")
|
||||
self.Link("_copy_string_end")
|
||||
self.Emit("XORL", _DX, _DX) // XORL DX, DX
|
||||
/* strings with no escape sequences */
|
||||
self.Link("_noescape") // _noescape:
|
||||
self.Emit("MOVL", jit.Imm(_S_omask_key), _DI) // MOVL _S_omask, DI
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _SI) // MOVQ ST.Vt[CX], SI
|
||||
self.Emit("BTQ" , _SI, _DI) // BTQ SI, DI
|
||||
self.Sjmp("JC" , "_object_key") // JC _object_key
|
||||
|
||||
/* check for pre-packed strings, avoid 1 allocation */
|
||||
self.Emit("TESTQ", _DX, _DX) // TESTQ DX, DX
|
||||
self.Sjmp("JNZ" , "_packed_str") // JNZ _packed_str
|
||||
self.Emit("MOVQ" , _R8, jit.Ptr(_SP, 0)) // MOVQ R8, (SP)
|
||||
self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 8)) // MOVQ AX, 8(SP)
|
||||
self.call_go(_F_convTstring) // CALL_GO runtime.convTstring
|
||||
self.Emit("MOVQ" , jit.Ptr(_SP, 16), _R9) // MOVQ 16(SP), R9
|
||||
|
||||
/* packed string already in R9 */
|
||||
self.Link("_packed_str") // _packed_str:
|
||||
self.Emit("MOVQ", _T_string, _R8) // MOVQ _T_string, R8
|
||||
self.Emit("MOVQ", _VAR_ss_Iv, _DI) // MOVQ ss.Iv, DI
|
||||
self.Emit("SUBQ", jit.Imm(1), _DI) // SUBQ $1, DI
|
||||
self.Sjmp("JMP" , "_set_value") // JMP _set_value
|
||||
|
||||
/* the string is an object key, get the map */
|
||||
self.Link("_object_key")
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI
|
||||
self.Emit("MOVQ", jit.Ptr(_SI, 8), _SI) // MOVQ 8(SI), SI
|
||||
|
||||
/* add a new delimiter */
|
||||
self.Emit("ADDQ", jit.Imm(1), _CX) // ADDQ $1, CX
|
||||
self.Emit("CMPQ", _CX, jit.Imm(types.MAX_RECURSE)) // CMPQ CX, ${types.MAX_RECURSE}
|
||||
self.Sjmp("JAE" , "_stack_overflow") // JA _stack_overflow
|
||||
self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp
|
||||
self.Emit("MOVQ", jit.Imm(_S_obj_delim), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_obj_delim, ST.Vt[CX]
|
||||
|
||||
/* add a new slot int the map */
|
||||
self.Emit("MOVQ", _T_map, _DX) // MOVQ _T_map, DX
|
||||
self.Emit("MOVQ", _DX, jit.Ptr(_SP, 0)) // MOVQ DX, (SP)
|
||||
self.Emit("MOVQ", _SI, jit.Ptr(_SP, 8)) // MOVQ SI, 8(SP)
|
||||
self.Emit("MOVQ", _R8, jit.Ptr(_SP, 16)) // MOVQ R9, 16(SP)
|
||||
self.Emit("MOVQ", _AX, jit.Ptr(_SP, 24)) // MOVQ AX, 24(SP)
|
||||
self.call_go(_F_mapassign_faststr) // CALL_GO runtime.mapassign_faststr
|
||||
self.Emit("MOVQ", jit.Ptr(_SP, 32), _AX) // MOVQ 32(SP), AX
|
||||
|
||||
/* add to the pointer stack */
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.WritePtrAX(6, jit.Sib(_ST, _CX, 8, _ST_Vp), false) // MOVQ AX, ST.Vp[CX]
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/* allocate memory to store the string header and unquoted result */
|
||||
self.Link("_unquote") // _unquote:
|
||||
self.Emit("ADDQ", jit.Imm(15), _AX) // ADDQ $15, AX
|
||||
self.Emit("MOVQ", _T_byte, _CX) // MOVQ _T_byte, CX
|
||||
self.Emit("MOVQ", _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP)
|
||||
self.Emit("MOVQ", _CX, jit.Ptr(_SP, 8)) // MOVQ CX, 8(SP)
|
||||
self.Emit("MOVB", jit.Imm(0), jit.Ptr(_SP, 16)) // MOVB $0, 16(SP)
|
||||
self.call_go(_F_mallocgc) // CALL_GO runtime.mallocgc
|
||||
self.Emit("MOVQ", jit.Ptr(_SP, 24), _R9) // MOVQ 24(SP), R9
|
||||
|
||||
/* prepare the unquoting parameters */
|
||||
self.Emit("MOVQ" , _VAR_ss_Iv, _CX) // MOVQ ss.Iv, CX
|
||||
self.Emit("LEAQ" , jit.Sib(_IP, _CX, 1, 0), _DI) // LEAQ (IP)(CX), DI
|
||||
self.Emit("NEGQ" , _CX) // NEGQ CX
|
||||
self.Emit("LEAQ" , jit.Sib(_IC, _CX, 1, -1), _SI) // LEAQ -1(IC)(CX), SI
|
||||
self.Emit("LEAQ" , jit.Ptr(_R9, 16), _DX) // LEAQ 16(R8), DX
|
||||
self.Emit("LEAQ" , _VAR_ss_Ep, _CX) // LEAQ ss.Ep, CX
|
||||
self.Emit("XORL" , _R8, _R8) // XORL R8, R8
|
||||
self.Emit("BTQ" , jit.Imm(_F_disable_urc), _VAR_df) // BTQ ${_F_disable_urc}, fv
|
||||
self.Emit("SETCC", _R8) // SETCC R8
|
||||
self.Emit("SHLQ" , jit.Imm(types.B_UNICODE_REPLACE), _R8) // SHLQ ${types.B_UNICODE_REPLACE}, R8
|
||||
|
||||
/* unquote the string, with R9 been preserved */
|
||||
self.save(_R9) // SAVE R9
|
||||
self.call(_F_unquote) // CALL unquote
|
||||
self.load(_R9) // LOAD R9
|
||||
|
||||
/* check for errors */
|
||||
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
|
||||
self.Sjmp("JS" , "_unquote_error") // JS _unquote_error
|
||||
self.Emit("MOVL" , jit.Imm(1), _DX) // MOVL $1, DX
|
||||
self.Emit("LEAQ" , jit.Ptr(_R9, 16), _R8) // ADDQ $16, R8
|
||||
self.Emit("MOVQ" , _R8, jit.Ptr(_R9, 0)) // MOVQ R8, (R9)
|
||||
self.Emit("MOVQ" , _AX, jit.Ptr(_R9, 8)) // MOVQ AX, 8(R9)
|
||||
self.Sjmp("JMP" , "_noescape") // JMP _noescape
|
||||
|
||||
/** V_DOUBLE **/
|
||||
self.Link("_decode_V_DOUBLE") // _decode_V_DOUBLE:
|
||||
self.Emit("BTQ" , jit.Imm(_F_use_number), _VAR_df) // BTQ _F_use_number, df
|
||||
self.Sjmp("JC" , "_use_number") // JC _use_number
|
||||
self.Emit("MOVSD", _VAR_ss_Dv, _X0) // MOVSD ss.Dv, X0
|
||||
self.Sjmp("JMP" , "_use_float64") // JMP _use_float64
|
||||
|
||||
/** V_INTEGER **/
|
||||
self.Link("_decode_V_INTEGER") // _decode_V_INTEGER:
|
||||
self.Emit("BTQ" , jit.Imm(_F_use_number), _VAR_df) // BTQ _F_use_number, df
|
||||
self.Sjmp("JC" , "_use_number") // JC _use_number
|
||||
self.Emit("BTQ" , jit.Imm(_F_use_int64), _VAR_df) // BTQ _F_use_int64, df
|
||||
self.Sjmp("JC" , "_use_int64") // JC _use_int64
|
||||
self.Emit("MOVQ" , _VAR_ss_Iv, _AX) // MOVQ ss.Iv, AX
|
||||
self.Emit("CVTSQ2SD", _AX, _X0) // CVTSQ2SD AX, X0
|
||||
|
||||
/* represent numbers as `float64` */
|
||||
self.Link("_use_float64") // _use_float64:
|
||||
self.Emit("MOVSD", _X0, jit.Ptr(_SP, 0)) // MOVSD X0, (SP)
|
||||
self.call_go(_F_convT64) // CALL_GO runtime.convT64
|
||||
self.Emit("MOVQ" , _T_float64, _R8) // MOVQ _T_float64, R8
|
||||
self.Emit("MOVQ" , jit.Ptr(_SP, 8), _R9) // MOVQ 8(SP), R9
|
||||
self.Emit("MOVQ" , _VAR_ss_Ep, _DI) // MOVQ ss.Ep, DI
|
||||
self.Sjmp("JMP" , "_set_value") // JMP _set_value
|
||||
|
||||
/* represent numbers as `json.Number` */
|
||||
self.Link("_use_number") // _use_number
|
||||
self.Emit("MOVQ", _VAR_ss_Ep, _AX) // MOVQ ss.Ep, AX
|
||||
self.Emit("LEAQ", jit.Sib(_IP, _AX, 1, 0), _SI) // LEAQ (IP)(AX), SI
|
||||
self.Emit("MOVQ", _IC, _CX) // MOVQ IC, CX
|
||||
self.Emit("SUBQ", _AX, _CX) // SUBQ AX, CX
|
||||
self.Emit("MOVQ", _SI, jit.Ptr(_SP, 0)) // MOVQ SI, (SP)
|
||||
self.Emit("MOVQ", _CX, jit.Ptr(_SP, 8)) // MOVQ CX, 8(SP)
|
||||
self.call_go(_F_convTstring) // CALL_GO runtime.convTstring
|
||||
self.Emit("MOVQ", _T_number, _R8) // MOVQ _T_number, R8
|
||||
self.Emit("MOVQ", jit.Ptr(_SP, 16), _R9) // MOVQ 16(SP), R9
|
||||
self.Emit("MOVQ", _VAR_ss_Ep, _DI) // MOVQ ss.Ep, DI
|
||||
self.Sjmp("JMP" , "_set_value") // JMP _set_value
|
||||
|
||||
/* represent numbers as `int64` */
|
||||
self.Link("_use_int64") // _use_int64:
|
||||
self.Emit("MOVQ", _VAR_ss_Iv, _AX) // MOVQ ss.Iv, AX
|
||||
self.Emit("MOVQ", _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP)
|
||||
self.call_go(_F_convT64) // CALL_GO runtime.convT64
|
||||
self.Emit("MOVQ", _T_int64, _R8) // MOVQ _T_int64, R8
|
||||
self.Emit("MOVQ", jit.Ptr(_SP, 8), _R9) // MOVQ 8(SP), R9
|
||||
self.Emit("MOVQ", _VAR_ss_Ep, _DI) // MOVQ ss.Ep, DI
|
||||
self.Sjmp("JMP" , "_set_value") // JMP _set_value
|
||||
|
||||
/** V_KEY_SEP **/
|
||||
self.Link("_decode_V_KEY_SEP") // _decode_V_KEY_SEP:
|
||||
// self.Byte(0xcc)
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
|
||||
self.Emit("CMPQ", _AX, jit.Imm(_S_obj_delim)) // CMPQ AX, _S_obj_delim
|
||||
self.Sjmp("JNE" , "_invalid_char") // JNE _invalid_char
|
||||
self.Emit("MOVQ", jit.Imm(_S_val), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_val, ST.Vt[CX]
|
||||
self.Emit("MOVQ", jit.Imm(_S_obj), jit.Sib(_ST, _CX, 8, _ST_Vt - 8)) // MOVQ _S_obj, ST.Vt[CX - 1]
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/** V_ELEM_SEP **/
|
||||
self.Link("_decode_V_ELEM_SEP") // _decode_V_ELEM_SEP:
|
||||
self.Emit("MOVQ" , jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ" , jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
|
||||
self.Emit("CMPQ" , _AX, jit.Imm(_S_arr)) // CMPQ _AX, _S_arr
|
||||
self.Sjmp("JE" , "_array_sep") // JZ _next
|
||||
self.Emit("CMPQ" , _AX, jit.Imm(_S_obj)) // CMPQ _AX, _S_arr
|
||||
self.Sjmp("JNE" , "_invalid_char") // JNE _invalid_char
|
||||
self.Emit("MOVQ" , jit.Imm(_S_obj_sep), jit.Sib(_ST, _CX, 8, _ST_Vt))
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/* arrays */
|
||||
self.Link("_array_sep")
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI
|
||||
self.Emit("MOVQ", jit.Ptr(_SI, 8), _SI) // MOVQ 8(SI), SI
|
||||
self.Emit("MOVQ", jit.Ptr(_SI, 8), _DX) // MOVQ 8(SI), DX
|
||||
self.Emit("CMPQ", _DX, jit.Ptr(_SI, 16)) // CMPQ DX, 16(SI)
|
||||
self.Sjmp("JAE" , "_array_more") // JAE _array_more
|
||||
|
||||
/* add a slot for the new element */
|
||||
self.Link("_array_append") // _array_append:
|
||||
self.Emit("ADDQ", jit.Imm(1), jit.Ptr(_SI, 8)) // ADDQ $1, 8(SI)
|
||||
self.Emit("MOVQ", jit.Ptr(_SI, 0), _SI) // MOVQ (SI), SI
|
||||
self.Emit("ADDQ", jit.Imm(1), _CX) // ADDQ $1, CX
|
||||
self.Emit("CMPQ", _CX, jit.Imm(types.MAX_RECURSE)) // CMPQ CX, ${types.MAX_RECURSE}
|
||||
self.Sjmp("JAE" , "_stack_overflow")
|
||||
self.Emit("SHLQ", jit.Imm(1), _DX) // SHLQ $1, DX
|
||||
self.Emit("LEAQ", jit.Sib(_SI, _DX, 8, 0), _SI) // LEAQ (SI)(DX*8), SI
|
||||
self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp
|
||||
self.WriteRecNotAX(7 , _SI, jit.Sib(_ST, _CX, 8, _ST_Vp), false) // MOVQ SI, ST.Vp[CX]
|
||||
self.Emit("MOVQ", jit.Imm(_S_val), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_val, ST.Vt[CX}
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/** V_ARRAY_END **/
|
||||
self.Link("_decode_V_ARRAY_END") // _decode_V_ARRAY_END:
|
||||
self.Emit("XORL", _DX, _DX) // XORL DX, DX
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
|
||||
self.Emit("CMPQ", _AX, jit.Imm(_S_arr_0)) // CMPQ AX, _S_arr_0
|
||||
self.Sjmp("JE" , "_first_item") // JE _first_item
|
||||
self.Emit("CMPQ", _AX, jit.Imm(_S_arr)) // CMPQ AX, _S_arr
|
||||
self.Sjmp("JNE" , "_invalid_char") // JNE _invalid_char
|
||||
self.Emit("SUBQ", jit.Imm(1), jit.Ptr(_ST, _ST_Sp)) // SUBQ $1, ST.Sp
|
||||
self.Emit("MOVQ", _DX, jit.Sib(_ST, _CX, 8, _ST_Vp)) // MOVQ DX, ST.Vp[CX]
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/* first element of an array */
|
||||
self.Link("_first_item") // _first_item:
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("SUBQ", jit.Imm(2), jit.Ptr(_ST, _ST_Sp)) // SUBQ $2, ST.Sp
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp - 8), _SI) // MOVQ ST.Vp[CX - 1], SI
|
||||
self.Emit("MOVQ", jit.Ptr(_SI, 8), _SI) // MOVQ 8(SI), SI
|
||||
self.Emit("MOVQ", _DX, jit.Sib(_ST, _CX, 8, _ST_Vp - 8)) // MOVQ DX, ST.Vp[CX - 1]
|
||||
self.Emit("MOVQ", _DX, jit.Sib(_ST, _CX, 8, _ST_Vp)) // MOVQ DX, ST.Vp[CX]
|
||||
self.Emit("MOVQ", _DX, jit.Ptr(_SI, 8)) // MOVQ DX, 8(SI)
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/** V_OBJECT_END **/
|
||||
self.Link("_decode_V_OBJECT_END") // _decode_V_OBJECT_END:
|
||||
self.Emit("MOVL", jit.Imm(_S_omask_end), _DX) // MOVL _S_omask, DI
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
|
||||
self.Emit("BTQ" , _AX, _DX)
|
||||
self.Sjmp("JNC" , "_invalid_char") // JNE _invalid_char
|
||||
self.Emit("XORL", _AX, _AX) // XORL AX, AX
|
||||
self.Emit("SUBQ", jit.Imm(1), jit.Ptr(_ST, _ST_Sp)) // SUBQ $1, ST.Sp
|
||||
self.Emit("MOVQ", _AX, jit.Sib(_ST, _CX, 8, _ST_Vp)) // MOVQ AX, ST.Vp[CX]
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/* return from decoder */
|
||||
self.Link("_return") // _return:
|
||||
self.Emit("XORL", _EP, _EP) // XORL EP, EP
|
||||
self.Emit("MOVQ", _EP, jit.Ptr(_ST, _ST_Vp)) // MOVQ EP, ST.Vp[0]
|
||||
self.Link("_epilogue") // _epilogue:
|
||||
self.Emit("SUBQ", jit.Imm(_FsmOffset), _ST) // SUBQ _FsmOffset, _ST
|
||||
self.Emit("MOVQ", jit.Ptr(_SP, _VD_offs), _BP) // MOVQ _VD_offs(SP), BP
|
||||
self.Emit("ADDQ", jit.Imm(_VD_size), _SP) // ADDQ $_VD_size, SP
|
||||
self.Emit("RET") // RET
|
||||
|
||||
/* array expand */
|
||||
self.Link("_array_more") // _array_more:
|
||||
self.Emit("MOVQ" , _T_eface, _AX) // MOVQ _T_eface, AX
|
||||
self.Emit("MOVOU", jit.Ptr(_SI, 0), _X0) // MOVOU (SI), X0
|
||||
self.Emit("MOVQ" , jit.Ptr(_SI, 16), _DX) // MOVQ 16(SI), DX
|
||||
self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP)
|
||||
self.Emit("MOVOU", _X0, jit.Ptr(_SP, 8)) // MOVOU X0, 8(SP)
|
||||
self.Emit("MOVQ" , _DX, jit.Ptr(_SP, 24)) // MOVQ DX, 24(SP)
|
||||
self.Emit("SHLQ" , jit.Imm(1), _DX) // SHLQ $1, DX
|
||||
self.Emit("MOVQ" , _DX, jit.Ptr(_SP, 32)) // MOVQ DX, 32(SP)
|
||||
self.call_go(_F_growslice) // CALL_GO runtime.growslice
|
||||
self.Emit("MOVQ" , jit.Ptr(_SP, 40), _DI) // MOVOU 40(SP), DI
|
||||
self.Emit("MOVQ" , jit.Ptr(_SP, 48), _DX) // MOVOU 48(SP), DX
|
||||
self.Emit("MOVQ" , jit.Ptr(_SP, 56), _AX) // MOVQ 56(SP), AX
|
||||
|
||||
/* update the slice */
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI
|
||||
self.Emit("MOVQ", jit.Ptr(_SI, 8), _SI) // MOVQ 8(SI), SI
|
||||
self.Emit("MOVQ", _DX, jit.Ptr(_SI, 8)) // MOVQ DX, 8(SI)
|
||||
self.Emit("MOVQ", _AX, jit.Ptr(_SI, 16)) // MOVQ AX, 16(AX)
|
||||
self.WriteRecNotAX(8 , _DI, jit.Ptr(_SI, 0), false) // MOVQ R10, (SI)
|
||||
self.Sjmp("JMP" , "_array_append") // JMP _array_append
|
||||
|
||||
/* copy string */
|
||||
self.Link("copy_string") // pointer: R8, length: AX, return addr: DI
|
||||
// self.Byte(0xcc)
|
||||
self.Emit("MOVQ", _R8, _VAR_cs_p)
|
||||
self.Emit("MOVQ", _AX, _VAR_cs_n)
|
||||
self.Emit("MOVQ", _DI, _VAR_cs_LR)
|
||||
self.Emit("MOVQ", _T_byte, _R8)
|
||||
self.Emit("MOVQ", _R8, jit.Ptr(_SP, 0))
|
||||
self.Emit("MOVQ", _AX, jit.Ptr(_SP, 8))
|
||||
self.Emit("MOVQ", _AX, jit.Ptr(_SP, 16))
|
||||
self.call_go(_F_makeslice)
|
||||
self.Emit("MOVQ", jit.Ptr(_SP, 24), _R8)
|
||||
self.Emit("MOVQ", _R8, _VAR_cs_d)
|
||||
self.Emit("MOVQ", _R8, jit.Ptr(_SP, 0))
|
||||
self.Emit("MOVQ", _VAR_cs_p, _R8)
|
||||
self.Emit("MOVQ", _R8, jit.Ptr(_SP, 8))
|
||||
self.Emit("MOVQ", _VAR_cs_n, _AX)
|
||||
self.Emit("MOVQ", _AX, jit.Ptr(_SP, 16))
|
||||
self.call_go(_F_memmove)
|
||||
self.Emit("MOVQ", _VAR_cs_d, _R8)
|
||||
self.Emit("MOVQ", _VAR_cs_n, _AX)
|
||||
self.Emit("MOVQ", _VAR_cs_LR, _DI)
|
||||
// self.Byte(0xcc)
|
||||
self.Rjmp("JMP", _DI)
|
||||
|
||||
/* error handlers */
|
||||
self.Link("_stack_overflow")
|
||||
self.Emit("MOVL" , _E_recurse, _EP) // MOVQ _E_recurse, EP
|
||||
self.Sjmp("JMP" , "_error") // JMP _error
|
||||
self.Link("_vtype_error") // _vtype_error:
|
||||
self.Emit("MOVQ" , _DI, _IC) // MOVQ DI, IC
|
||||
self.Emit("MOVL" , _E_invalid, _EP) // MOVL _E_invalid, EP
|
||||
self.Sjmp("JMP" , "_error") // JMP _error
|
||||
self.Link("_invalid_char") // _invalid_char:
|
||||
self.Emit("SUBQ" , jit.Imm(1), _IC) // SUBQ $1, IC
|
||||
self.Emit("MOVL" , _E_invalid, _EP) // MOVL _E_invalid, EP
|
||||
self.Sjmp("JMP" , "_error") // JMP _error
|
||||
self.Link("_unquote_error") // _unquote_error:
|
||||
self.Emit("MOVQ" , _VAR_ss_Iv, _IC) // MOVQ ss.Iv, IC
|
||||
self.Emit("SUBQ" , jit.Imm(1), _IC) // SUBQ $1, IC
|
||||
self.Link("_parsing_error") // _parsing_error:
|
||||
self.Emit("NEGQ" , _AX) // NEGQ AX
|
||||
self.Emit("MOVQ" , _AX, _EP) // MOVQ AX, EP
|
||||
self.Link("_error") // _error:
|
||||
self.Emit("PXOR" , _X0, _X0) // PXOR X0, X0
|
||||
self.Emit("MOVOU", _X0, jit.Ptr(_VP, 0)) // MOVOU X0, (VP)
|
||||
self.Sjmp("JMP" , "_epilogue") // JMP _epilogue
|
||||
|
||||
/* invalid value type, never returns */
|
||||
self.Link("_invalid_vtype")
|
||||
self.Emit("MOVQ", _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP)
|
||||
self.call(_F_invalid_vtype) // CALL invalid_type
|
||||
self.Emit("UD2") // UD2
|
||||
|
||||
/* switch jump table */
|
||||
self.Link("_switch_table") // _switch_table:
|
||||
self.Sref("_decode_V_EOF", 0) // SREF &_decode_V_EOF, $0
|
||||
self.Sref("_decode_V_NULL", -4) // SREF &_decode_V_NULL, $-4
|
||||
self.Sref("_decode_V_TRUE", -8) // SREF &_decode_V_TRUE, $-8
|
||||
self.Sref("_decode_V_FALSE", -12) // SREF &_decode_V_FALSE, $-12
|
||||
self.Sref("_decode_V_ARRAY", -16) // SREF &_decode_V_ARRAY, $-16
|
||||
self.Sref("_decode_V_OBJECT", -20) // SREF &_decode_V_OBJECT, $-20
|
||||
self.Sref("_decode_V_STRING", -24) // SREF &_decode_V_STRING, $-24
|
||||
self.Sref("_decode_V_DOUBLE", -28) // SREF &_decode_V_DOUBLE, $-28
|
||||
self.Sref("_decode_V_INTEGER", -32) // SREF &_decode_V_INTEGER, $-32
|
||||
self.Sref("_decode_V_KEY_SEP", -36) // SREF &_decode_V_KEY_SEP, $-36
|
||||
self.Sref("_decode_V_ELEM_SEP", -40) // SREF &_decode_V_ELEM_SEP, $-40
|
||||
self.Sref("_decode_V_ARRAY_END", -44) // SREF &_decode_V_ARRAY_END, $-44
|
||||
self.Sref("_decode_V_OBJECT_END", -48) // SREF &_decode_V_OBJECT_END, $-48
|
||||
|
||||
/* fast character lookup table */
|
||||
self.Link("_decode_tab") // _decode_tab:
|
||||
self.Sref("_decode_V_EOF", 0) // SREF &_decode_V_EOF, $0
|
||||
|
||||
/* generate rest of the tabs */
|
||||
for i := 1; i < 256; i++ {
|
||||
if to, ok := _R_tab[i]; ok {
|
||||
self.Sref(to, -int64(i) * 4)
|
||||
} else {
|
||||
self.Byte(0x00, 0x00, 0x00, 0x00)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Generic Decoder **/
|
||||
|
||||
var (
|
||||
_subr_decode_value = new(_ValueDecoder).build()
|
||||
)
|
||||
|
||||
//go:nosplit
|
||||
func invalid_vtype(vt types.ValueType) {
|
||||
throw(fmt.Sprintf("invalid value type: %d", vt))
|
||||
}
|
37
vendor/github.com/bytedance/sonic/internal/decoder/generic_stkabi_amd64_test.s
generated
vendored
37
vendor/github.com/bytedance/sonic/internal/decoder/generic_stkabi_amd64_test.s
generated
vendored
|
@ -1,37 +0,0 @@
|
|||
// +build go1.16,!go1.17
|
||||
|
||||
//
|
||||
// Copyright 2021 ByteDance Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#include "go_asm.h"
|
||||
#include "funcdata.h"
|
||||
#include "textflag.h"
|
||||
|
||||
TEXT ·decodeValueStub(SB), NOSPLIT, $0 - 72
|
||||
NO_LOCAL_POINTERS
|
||||
PXOR X0, X0
|
||||
MOVOU X0, rv+48(FP)
|
||||
MOVQ st+0(FP), BX
|
||||
MOVQ sp+8(FP), R12
|
||||
MOVQ sn+16(FP), R13
|
||||
MOVQ ic+24(FP), R14
|
||||
MOVQ vp+32(FP), R15
|
||||
MOVQ df+40(FP), R10
|
||||
MOVQ ·_subr_decode_value(SB), AX
|
||||
CALL AX
|
||||
MOVQ R14, rp+48(FP)
|
||||
MOVQ R11, ex+56(FP)
|
||||
RET
|
|
@ -14,7 +14,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package decoder
|
||||
package jitdec
|
||||
|
||||
import (
|
||||
`strconv`
|
|
@ -1,4 +1,4 @@
|
|||
// +build go1.21,!go1.23
|
||||
// +build go1.21,!go1.24
|
||||
|
||||
// Copyright 2023 CloudWeGo Authors
|
||||
//
|
||||
|
@ -14,7 +14,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package decoder
|
||||
package jitdec
|
||||
|
||||
import (
|
||||
`strconv`
|
|
@ -1,4 +1,5 @@
|
|||
// +build go1.17,!go1.23
|
||||
//go:build go1.17 && !go1.24
|
||||
// +build go1.17,!go1.24
|
||||
|
||||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
|
@ -16,21 +17,22 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package decoder
|
||||
package jitdec
|
||||
|
||||
import (
|
||||
`encoding/json`
|
||||
`fmt`
|
||||
`math`
|
||||
`reflect`
|
||||
`unsafe`
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
`github.com/bytedance/sonic/internal/caching`
|
||||
`github.com/bytedance/sonic/internal/jit`
|
||||
`github.com/bytedance/sonic/internal/native`
|
||||
`github.com/bytedance/sonic/internal/native/types`
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
`github.com/twitchyliquid64/golang-asm/obj`
|
||||
"github.com/bytedance/sonic/internal/caching"
|
||||
"github.com/bytedance/sonic/internal/jit"
|
||||
"github.com/bytedance/sonic/internal/native"
|
||||
"github.com/bytedance/sonic/internal/native/types"
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
"github.com/twitchyliquid64/golang-asm/obj"
|
||||
)
|
||||
|
||||
/** Register Allocations
|
||||
|
@ -292,7 +294,6 @@ func (self *_Assembler) compile() {
|
|||
_OP_array_clear_p : (*_Assembler)._asm_OP_array_clear_p,
|
||||
_OP_slice_init : (*_Assembler)._asm_OP_slice_init,
|
||||
_OP_slice_append : (*_Assembler)._asm_OP_slice_append,
|
||||
_OP_object_skip : (*_Assembler)._asm_OP_object_skip,
|
||||
_OP_object_next : (*_Assembler)._asm_OP_object_next,
|
||||
_OP_struct_field : (*_Assembler)._asm_OP_struct_field,
|
||||
_OP_unmarshal : (*_Assembler)._asm_OP_unmarshal,
|
||||
|
@ -312,6 +313,7 @@ func (self *_Assembler) compile() {
|
|||
_OP_check_char_0 : (*_Assembler)._asm_OP_check_char_0,
|
||||
_OP_dismatch_err : (*_Assembler)._asm_OP_dismatch_err,
|
||||
_OP_go_skip : (*_Assembler)._asm_OP_go_skip,
|
||||
_OP_skip_emtpy : (*_Assembler)._asm_OP_skip_empty,
|
||||
_OP_add : (*_Assembler)._asm_OP_add,
|
||||
_OP_check_empty : (*_Assembler)._asm_OP_check_empty,
|
||||
_OP_debug : (*_Assembler)._asm_OP_debug,
|
||||
|
@ -385,7 +387,7 @@ func (self *_Assembler) prologue() {
|
|||
|
||||
var (
|
||||
_REG_go = []obj.Addr { _ST, _VP, _IP, _IL, _IC }
|
||||
_REG_rt = []obj.Addr { _ST, _VP, _IP, _IL, _IC, _IL }
|
||||
_REG_rt = []obj.Addr { _ST, _VP, _IP, _IL, _IC }
|
||||
)
|
||||
|
||||
func (self *_Assembler) save(r ...obj.Addr) {
|
||||
|
@ -481,6 +483,7 @@ func (self *_Assembler) call_vf(fn obj.Addr) {
|
|||
_V_stackOverflow = jit.Imm(int64(uintptr(unsafe.Pointer(&stackOverflow))))
|
||||
_I_json_UnsupportedValueError = jit.Itab(_T_error, reflect.TypeOf(new(json.UnsupportedValueError)))
|
||||
_I_json_MismatchTypeError = jit.Itab(_T_error, reflect.TypeOf(new(MismatchTypeError)))
|
||||
_I_json_MismatchQuotedError = jit.Itab(_T_error, reflect.TypeOf(new(MismatchQuotedError)))
|
||||
)
|
||||
|
||||
func (self *_Assembler) type_error() {
|
||||
|
@ -492,9 +495,9 @@ func (self *_Assembler) type_error() {
|
|||
func (self *_Assembler) mismatch_error() {
|
||||
self.Link(_LB_mismatch_error) // _type_error:
|
||||
self.Emit("MOVQ", _VAR_et, _ET) // MOVQ _VAR_et, ET
|
||||
self.Emit("MOVQ", _VAR_ic, _EP) // MOVQ _VAR_ic, EP
|
||||
self.Emit("MOVQ", _I_json_MismatchTypeError, _CX) // MOVQ _I_json_MismatchType, CX
|
||||
self.Emit("CMPQ", _ET, _CX) // CMPQ ET, CX
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _EpOffset), _EP) // MOVQ stack.Ep, EP
|
||||
self.Sjmp("JE" , _LB_error) // JE _LB_error
|
||||
self.Emit("MOVQ", _ARG_sp, _AX)
|
||||
self.Emit("MOVQ", _ARG_sl, _BX)
|
||||
|
@ -600,6 +603,28 @@ func (self *_Assembler) _asm_OP_go_skip(p *_Instr) {
|
|||
self.Sjmp("JMP" , _LB_skip_one) // JMP _skip_one
|
||||
}
|
||||
|
||||
var _F_IndexByte = jit.Func(strings.IndexByte)
|
||||
|
||||
func (self *_Assembler) _asm_OP_skip_empty(p *_Instr) {
|
||||
// self.Byte(0xcc)
|
||||
self.call_sf(_F_skip_one) // CALL_SF skip_one
|
||||
// self.Byte(0xcc)
|
||||
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
|
||||
self.Sjmp("JS" , _LB_parsing_error_v) // JS _parse_error_v
|
||||
self.Emit("BTQ", jit.Imm(_F_disable_unknown), _ARG_fv)
|
||||
self.Xjmp("JNC", p.vi())
|
||||
self.Emit("LEAQ", jit.Sib(_IC, _AX, 1, 0), _BX)
|
||||
self.Emit("MOVQ", _BX, _ARG_sv_n)
|
||||
self.Emit("LEAQ", jit.Sib(_IP, _AX, 1, 0), _AX)
|
||||
self.Emit("MOVQ", _AX, _ARG_sv_p)
|
||||
self.Emit("MOVQ", jit.Imm(':'), _CX)
|
||||
self.call_go(_F_IndexByte)
|
||||
// self.Byte(0xcc)
|
||||
self.Emit("TESTQ", _AX, _AX)
|
||||
// disallow unknown field
|
||||
self.Sjmp("JNS", _LB_field_error)
|
||||
}
|
||||
|
||||
func (self *_Assembler) skip_one() {
|
||||
self.Link(_LB_skip_one) // _skip:
|
||||
self.Emit("MOVQ", _VAR_ic, _IC) // MOVQ _VAR_ic, IC
|
||||
|
@ -972,11 +997,13 @@ func (self *_Assembler) mem_clear_rem(size int64, ptrfree bool) {
|
|||
|
||||
var (
|
||||
_F_decodeJsonUnmarshaler obj.Addr
|
||||
_F_decodeJsonUnmarshalerQuoted obj.Addr
|
||||
_F_decodeTextUnmarshaler obj.Addr
|
||||
)
|
||||
|
||||
func init() {
|
||||
_F_decodeJsonUnmarshaler = jit.Func(decodeJsonUnmarshaler)
|
||||
_F_decodeJsonUnmarshalerQuoted = jit.Func(decodeJsonUnmarshalerQuoted)
|
||||
_F_decodeTextUnmarshaler = jit.Func(decodeTextUnmarshaler)
|
||||
}
|
||||
|
||||
|
@ -1057,18 +1084,18 @@ func (self *_Assembler) mapassign_utext(t reflect.Type, addressable bool) {
|
|||
var (
|
||||
_F_skip_one = jit.Imm(int64(native.S_skip_one))
|
||||
_F_skip_array = jit.Imm(int64(native.S_skip_array))
|
||||
_F_skip_object = jit.Imm(int64(native.S_skip_object))
|
||||
_F_skip_number = jit.Imm(int64(native.S_skip_number))
|
||||
)
|
||||
|
||||
func (self *_Assembler) unmarshal_json(t reflect.Type, deref bool) {
|
||||
func (self *_Assembler) unmarshal_json(t reflect.Type, deref bool, f obj.Addr) {
|
||||
self.call_sf(_F_skip_one) // CALL_SF skip_one
|
||||
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
|
||||
self.Sjmp("JS" , _LB_parsing_error_v) // JS _parse_error_v
|
||||
self.Emit("MOVQ", _IC, _VAR_ic) // store for mismatche error skip
|
||||
self.slice_from_r(_AX, 0) // SLICE_R AX, $0
|
||||
self.Emit("MOVQ" , _DI, _ARG_sv_p) // MOVQ DI, sv.p
|
||||
self.Emit("MOVQ" , _SI, _ARG_sv_n) // MOVQ SI, sv.n
|
||||
self.unmarshal_func(t, _F_decodeJsonUnmarshaler, deref) // UNMARSHAL json, ${t}, ${deref}
|
||||
self.unmarshal_func(t, f, deref) // UNMARSHAL json, ${t}, ${deref}
|
||||
}
|
||||
|
||||
func (self *_Assembler) unmarshal_text(t reflect.Type, deref bool) {
|
||||
|
@ -1103,7 +1130,19 @@ func (self *_Assembler) unmarshal_func(t reflect.Type, fn obj.Addr, deref bool)
|
|||
self.Emit("MOVQ" , _ARG_sv_n, _DI) // MOVQ sv.n, DI
|
||||
self.call_go(fn) // CALL_GO ${fn}
|
||||
self.Emit("TESTQ", _ET, _ET) // TESTQ ET, ET
|
||||
self.Sjmp("JNZ" , _LB_error) // JNZ _error
|
||||
if fn == _F_decodeJsonUnmarshalerQuoted {
|
||||
self.Sjmp("JZ" , "_unmarshal_func_end_{n}") // JZ _unmarshal_func_end_{n}
|
||||
self.Emit("MOVQ", _I_json_MismatchQuotedError, _CX) // MOVQ _I_json_MismatchQuotedError, CX
|
||||
self.Emit("CMPQ", _ET, _CX) // check if MismatchQuotedError
|
||||
self.Sjmp("JNE" , _LB_error) // JNE _error
|
||||
self.Emit("MOVQ", jit.Type(t), _CX) // store current type
|
||||
self.Emit("MOVQ", _CX, _VAR_et) // store current type as mismatched type
|
||||
self.Emit("MOVQ", _VAR_ic, _IC) // recover the pos at mismatched, continue to parse
|
||||
self.Emit("XORL", _ET, _ET) // clear ET
|
||||
self.Link("_unmarshal_func_end_{n}")
|
||||
} else {
|
||||
self.Sjmp("JNE" , _LB_error) // JNE _error
|
||||
}
|
||||
}
|
||||
|
||||
/** Dynamic Decoding Routine **/
|
||||
|
@ -1136,8 +1175,8 @@ func (self *_Assembler) decode_dynamic(vt obj.Addr, vp obj.Addr) {
|
|||
self.Emit("MOVQ", _I_json_MismatchTypeError, _CX) // MOVQ _I_json_MismatchTypeError, CX
|
||||
self.Emit("CMPQ", _ET, _CX) // CMPQ ET, CX
|
||||
self.Sjmp("JNE", _LB_error) // JNE LB_error
|
||||
self.Emit("MOVQ", _EP, _VAR_ic) // MOVQ EP, VAR_ic
|
||||
self.Emit("MOVQ", _ET, _VAR_et) // MOVQ ET, VAR_et
|
||||
self.WriteRecNotAX(14, _EP, jit.Ptr(_ST, _EpOffset), false, false) // MOVQ EP, stack.Ep
|
||||
self.Link("_decode_dynamic_end_{n}")
|
||||
}
|
||||
|
||||
|
@ -1146,7 +1185,7 @@ func (self *_Assembler) decode_dynamic(vt obj.Addr, vp obj.Addr) {
|
|||
var (
|
||||
_F_memequal = jit.Func(memequal)
|
||||
_F_memmove = jit.Func(memmove)
|
||||
_F_growslice = jit.Func(growslice)
|
||||
_F_growslice = jit.Func(rt.GrowSlice)
|
||||
_F_makeslice = jit.Func(makeslice)
|
||||
_F_makemap_small = jit.Func(makemap_small)
|
||||
_F_mapassign_fast64 = jit.Func(mapassign_fast64)
|
||||
|
@ -1698,12 +1737,6 @@ func (self *_Assembler) _asm_OP_slice_append(p *_Instr) {
|
|||
self.Link("_append_slice_end_{n}")
|
||||
}
|
||||
|
||||
func (self *_Assembler) _asm_OP_object_skip(_ *_Instr) {
|
||||
self.call_sf(_F_skip_object) // CALL_SF skip_object
|
||||
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
|
||||
self.Sjmp("JS" , _LB_parsing_error_v) // JS _parse_error_v
|
||||
}
|
||||
|
||||
func (self *_Assembler) _asm_OP_object_next(_ *_Instr) {
|
||||
self.call_sf(_F_skip_one) // CALL_SF skip_one
|
||||
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
|
||||
|
@ -1774,11 +1807,19 @@ func (self *_Assembler) _asm_OP_struct_field(p *_Instr) {
|
|||
}
|
||||
|
||||
func (self *_Assembler) _asm_OP_unmarshal(p *_Instr) {
|
||||
self.unmarshal_json(p.vt(), true)
|
||||
if iv := p.i64(); iv != 0 {
|
||||
self.unmarshal_json(p.vt(), true, _F_decodeJsonUnmarshalerQuoted)
|
||||
} else {
|
||||
self.unmarshal_json(p.vt(), true, _F_decodeJsonUnmarshaler)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_Assembler) _asm_OP_unmarshal_p(p *_Instr) {
|
||||
self.unmarshal_json(p.vt(), false)
|
||||
if iv := p.i64(); iv != 0 {
|
||||
self.unmarshal_json(p.vt(), false, _F_decodeJsonUnmarshalerQuoted)
|
||||
} else {
|
||||
self.unmarshal_json(p.vt(), false, _F_decodeJsonUnmarshaler)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_Assembler) _asm_OP_unmarshal_text(p *_Instr) {
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package decoder
|
||||
package jitdec
|
||||
|
||||
import (
|
||||
`encoding/json`
|
||||
|
@ -77,7 +77,6 @@
|
|||
_OP_array_clear_p
|
||||
_OP_slice_init
|
||||
_OP_slice_append
|
||||
_OP_object_skip
|
||||
_OP_object_next
|
||||
_OP_struct_field
|
||||
_OP_unmarshal
|
||||
|
@ -97,6 +96,7 @@
|
|||
_OP_check_char_0
|
||||
_OP_dismatch_err
|
||||
_OP_go_skip
|
||||
_OP_skip_emtpy
|
||||
_OP_add
|
||||
_OP_check_empty
|
||||
_OP_debug
|
||||
|
@ -155,7 +155,6 @@
|
|||
_OP_array_skip : "array_skip",
|
||||
_OP_slice_init : "slice_init",
|
||||
_OP_slice_append : "slice_append",
|
||||
_OP_object_skip : "object_skip",
|
||||
_OP_object_next : "object_next",
|
||||
_OP_struct_field : "struct_field",
|
||||
_OP_unmarshal : "unmarshal",
|
||||
|
@ -271,6 +270,13 @@ func newInsVt(op _Op, vt reflect.Type) _Instr {
|
|||
}
|
||||
}
|
||||
|
||||
func newInsVtI(op _Op, vt reflect.Type, iv int) _Instr {
|
||||
return _Instr {
|
||||
u: packOp(op) | rt.PackInt(iv),
|
||||
p: unsafe.Pointer(rt.UnpackType(vt)),
|
||||
}
|
||||
}
|
||||
|
||||
func newInsVf(op _Op, vf *caching.FieldMap) _Instr {
|
||||
return _Instr {
|
||||
u: packOp(op),
|
||||
|
@ -452,6 +458,10 @@ func (self *_Program) rtt(op _Op, vt reflect.Type) {
|
|||
*self = append(*self, newInsVt(op, vt))
|
||||
}
|
||||
|
||||
func (self *_Program) rtti(op _Op, vt reflect.Type, iv int) {
|
||||
*self = append(*self, newInsVtI(op, vt, iv))
|
||||
}
|
||||
|
||||
func (self *_Program) fmv(op _Op, vf *caching.FieldMap) {
|
||||
*self = append(*self, newInsVf(op, vf))
|
||||
}
|
||||
|
@ -527,35 +537,54 @@ func (self *_Compiler) compile(vt reflect.Type) (ret _Program, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func (self *_Compiler) checkMarshaler(p *_Program, vt reflect.Type) bool {
|
||||
const (
|
||||
checkMarshalerFlags_quoted = 1
|
||||
)
|
||||
|
||||
func (self *_Compiler) checkMarshaler(p *_Program, vt reflect.Type, flags int, exec bool) bool {
|
||||
pt := reflect.PtrTo(vt)
|
||||
|
||||
/* check for `json.Unmarshaler` with pointer receiver */
|
||||
if pt.Implements(jsonUnmarshalerType) {
|
||||
p.rtt(_OP_unmarshal_p, pt)
|
||||
if exec {
|
||||
p.add(_OP_lspace)
|
||||
p.rtti(_OP_unmarshal_p, pt, flags)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/* check for `json.Unmarshaler` */
|
||||
if vt.Implements(jsonUnmarshalerType) {
|
||||
p.add(_OP_lspace)
|
||||
self.compileUnmarshalJson(p, vt)
|
||||
if exec {
|
||||
p.add(_OP_lspace)
|
||||
self.compileUnmarshalJson(p, vt, flags)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if flags == checkMarshalerFlags_quoted {
|
||||
// text marshaler shouldn't be supported for quoted string
|
||||
return false
|
||||
}
|
||||
|
||||
/* check for `encoding.TextMarshaler` with pointer receiver */
|
||||
if pt.Implements(encodingTextUnmarshalerType) {
|
||||
p.add(_OP_lspace)
|
||||
self.compileUnmarshalTextPtr(p, pt)
|
||||
if exec {
|
||||
p.add(_OP_lspace)
|
||||
self.compileUnmarshalTextPtr(p, pt, flags)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/* check for `encoding.TextUnmarshaler` */
|
||||
if vt.Implements(encodingTextUnmarshalerType) {
|
||||
p.add(_OP_lspace)
|
||||
self.compileUnmarshalText(p, vt)
|
||||
if exec {
|
||||
p.add(_OP_lspace)
|
||||
self.compileUnmarshalText(p, vt, flags)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -567,7 +596,7 @@ func (self *_Compiler) compileOne(p *_Program, sp int, vt reflect.Type) {
|
|||
return
|
||||
}
|
||||
|
||||
if self.checkMarshaler(p, vt) {
|
||||
if self.checkMarshaler(p, vt, 0, true) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -690,7 +719,7 @@ func (self *_Compiler) compilePtr(p *_Program, sp int, et reflect.Type) {
|
|||
|
||||
/* dereference all the way down */
|
||||
for et.Kind() == reflect.Ptr {
|
||||
if self.checkMarshaler(p, et) {
|
||||
if self.checkMarshaler(p, et, 0, true) {
|
||||
return
|
||||
}
|
||||
et = et.Elem()
|
||||
|
@ -872,7 +901,24 @@ func (self *_Compiler) compileStructBody(p *_Program, sp int, vt reflect.Type) {
|
|||
n := p.pc()
|
||||
p.add(_OP_is_null)
|
||||
|
||||
skip := self.checkIfSkip(p, vt, '{')
|
||||
j := p.pc()
|
||||
p.chr(_OP_check_char_0, '{')
|
||||
p.rtt(_OP_dismatch_err, vt)
|
||||
|
||||
/* special case for empty object */
|
||||
if len(fv) == 0 {
|
||||
p.pin(j)
|
||||
s := p.pc()
|
||||
p.add(_OP_skip_emtpy)
|
||||
p.pin(s)
|
||||
p.pin(n)
|
||||
return
|
||||
}
|
||||
|
||||
skip := p.pc()
|
||||
p.add(_OP_go_skip)
|
||||
p.pin(j)
|
||||
p.int(_OP_add, 1)
|
||||
|
||||
p.add(_OP_save)
|
||||
p.add(_OP_lspace)
|
||||
|
@ -890,11 +936,6 @@ func (self *_Compiler) compileStructBody(p *_Program, sp int, vt reflect.Type) {
|
|||
p.chr(_OP_check_char, '}')
|
||||
p.chr(_OP_match_char, ',')
|
||||
|
||||
/* special case of an empty struct */
|
||||
if len(fv) == 0 {
|
||||
p.add(_OP_object_skip)
|
||||
goto end_of_object
|
||||
}
|
||||
|
||||
/* match the remaining fields */
|
||||
p.add(_OP_lspace)
|
||||
|
@ -930,7 +971,6 @@ func (self *_Compiler) compileStructBody(p *_Program, sp int, vt reflect.Type) {
|
|||
p.int(_OP_goto, y0)
|
||||
}
|
||||
|
||||
end_of_object:
|
||||
p.pin(x)
|
||||
p.pin(y1)
|
||||
p.add(_OP_drop)
|
||||
|
@ -938,7 +978,22 @@ func (self *_Compiler) compileStructBody(p *_Program, sp int, vt reflect.Type) {
|
|||
p.pin(skip)
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileStructFieldStrUnmarshal(p *_Program, vt reflect.Type) {
|
||||
p.add(_OP_lspace)
|
||||
n0 := p.pc()
|
||||
p.add(_OP_is_null)
|
||||
self.checkMarshaler(p, vt, checkMarshalerFlags_quoted, true)
|
||||
p.pin(n0)
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileStructFieldStr(p *_Program, sp int, vt reflect.Type) {
|
||||
// according to std, json.Unmarshaler should be called before stringize
|
||||
// see https://github.com/bytedance/sonic/issues/670
|
||||
if self.checkMarshaler(p, vt, checkMarshalerFlags_quoted, false) {
|
||||
self.compileStructFieldStrUnmarshal(p, vt)
|
||||
return
|
||||
}
|
||||
|
||||
n1 := -1
|
||||
ft := vt
|
||||
sv := false
|
||||
|
@ -1106,7 +1161,7 @@ func (self *_Compiler) compileUnmarshalEnd(p *_Program, vt reflect.Type, i int)
|
|||
p.pin(j)
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileUnmarshalJson(p *_Program, vt reflect.Type) {
|
||||
func (self *_Compiler) compileUnmarshalJson(p *_Program, vt reflect.Type, flags int) {
|
||||
i := p.pc()
|
||||
v := _OP_unmarshal
|
||||
p.add(_OP_is_null)
|
||||
|
@ -1117,11 +1172,11 @@ func (self *_Compiler) compileUnmarshalJson(p *_Program, vt reflect.Type) {
|
|||
}
|
||||
|
||||
/* call the unmarshaler */
|
||||
p.rtt(v, vt)
|
||||
p.rtti(v, vt, flags)
|
||||
self.compileUnmarshalEnd(p, vt, i)
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileUnmarshalText(p *_Program, vt reflect.Type) {
|
||||
func (self *_Compiler) compileUnmarshalText(p *_Program, vt reflect.Type, iv int) {
|
||||
i := p.pc()
|
||||
v := _OP_unmarshal_text
|
||||
p.add(_OP_is_null)
|
||||
|
@ -1134,15 +1189,15 @@ func (self *_Compiler) compileUnmarshalText(p *_Program, vt reflect.Type) {
|
|||
}
|
||||
|
||||
/* call the unmarshaler */
|
||||
p.rtt(v, vt)
|
||||
p.rtti(v, vt, iv)
|
||||
self.compileUnmarshalEnd(p, vt, i)
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileUnmarshalTextPtr(p *_Program, vt reflect.Type) {
|
||||
func (self *_Compiler) compileUnmarshalTextPtr(p *_Program, vt reflect.Type, iv int) {
|
||||
i := p.pc()
|
||||
p.add(_OP_is_null)
|
||||
p.chr(_OP_match_char, '"')
|
||||
p.rtt(_OP_unmarshal_text_p, vt)
|
||||
p.rtti(_OP_unmarshal_text_p, vt, iv)
|
||||
p.pin(i)
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package decoder
|
||||
package jitdec
|
||||
|
||||
import (
|
||||
`os`
|
140
vendor/github.com/bytedance/sonic/internal/decoder/jitdec/decoder.go
generated
vendored
Normal file
140
vendor/github.com/bytedance/sonic/internal/decoder/jitdec/decoder.go
generated
vendored
Normal file
|
@ -0,0 +1,140 @@
|
|||
package jitdec
|
||||
|
||||
import (
|
||||
`unsafe`
|
||||
`encoding/json`
|
||||
`reflect`
|
||||
`runtime`
|
||||
|
||||
`github.com/bytedance/sonic/internal/decoder/consts`
|
||||
`github.com/bytedance/sonic/internal/decoder/errors`
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
`github.com/bytedance/sonic/utf8`
|
||||
`github.com/bytedance/sonic/option`
|
||||
)
|
||||
|
||||
type (
|
||||
MismatchTypeError = errors.MismatchTypeError
|
||||
SyntaxError = errors.SyntaxError
|
||||
)
|
||||
|
||||
const (
|
||||
_F_allow_control = consts.F_allow_control
|
||||
_F_copy_string = consts.F_copy_string
|
||||
_F_disable_unknown = consts.F_disable_unknown
|
||||
_F_disable_urc = consts.F_disable_urc
|
||||
_F_use_int64 = consts.F_use_int64
|
||||
_F_use_number = consts.F_use_number
|
||||
_F_no_validate_json = consts.F_no_validate_json
|
||||
_F_validate_string = consts.F_validate_string
|
||||
)
|
||||
|
||||
var (
|
||||
error_wrap = errors.ErrorWrap
|
||||
error_type = errors.ErrorType
|
||||
error_field = errors.ErrorField
|
||||
error_value = errors.ErrorValue
|
||||
error_mismatch = errors.ErrorMismatch
|
||||
stackOverflow = errors.StackOverflow
|
||||
)
|
||||
|
||||
|
||||
// Decode parses the JSON-encoded data from current position and stores the result
|
||||
// in the value pointed to by val.
|
||||
func Decode(s *string, i *int, f uint64, val interface{}) error {
|
||||
/* validate json if needed */
|
||||
if (f & (1 << _F_validate_string)) != 0 && !utf8.ValidateString(*s){
|
||||
dbuf := utf8.CorrectWith(nil, rt.Str2Mem(*s), "\ufffd")
|
||||
*s = rt.Mem2Str(dbuf)
|
||||
}
|
||||
|
||||
vv := rt.UnpackEface(val)
|
||||
vp := vv.Value
|
||||
|
||||
/* check for nil type */
|
||||
if vv.Type == nil {
|
||||
return &json.InvalidUnmarshalError{}
|
||||
}
|
||||
|
||||
/* must be a non-nil pointer */
|
||||
if vp == nil || vv.Type.Kind() != reflect.Ptr {
|
||||
return &json.InvalidUnmarshalError{Type: vv.Type.Pack()}
|
||||
}
|
||||
|
||||
etp := rt.PtrElem(vv.Type)
|
||||
|
||||
/* check the defined pointer type for issue 379 */
|
||||
if vv.Type.IsNamed() {
|
||||
newp := vp
|
||||
etp = vv.Type
|
||||
vp = unsafe.Pointer(&newp)
|
||||
}
|
||||
|
||||
/* create a new stack, and call the decoder */
|
||||
sb := newStack()
|
||||
nb, err := decodeTypedPointer(*s, *i, etp, vp, sb, f)
|
||||
/* return the stack back */
|
||||
*i = nb
|
||||
freeStack(sb)
|
||||
|
||||
/* avoid GC ahead */
|
||||
runtime.KeepAlive(vv)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
// Pretouch compiles vt ahead-of-time to avoid JIT compilation on-the-fly, in
|
||||
// order to reduce the first-hit latency.
|
||||
//
|
||||
// Opts are the compile options, for example, "option.WithCompileRecursiveDepth" is
|
||||
// a compile option to set the depth of recursive compile for the nested struct type.
|
||||
func Pretouch(vt reflect.Type, opts ...option.CompileOption) error {
|
||||
cfg := option.DefaultCompileOptions()
|
||||
for _, opt := range opts {
|
||||
opt(&cfg)
|
||||
}
|
||||
return pretouchRec(map[reflect.Type]bool{vt:true}, cfg)
|
||||
}
|
||||
|
||||
func pretouchType(_vt reflect.Type, opts option.CompileOptions) (map[reflect.Type]bool, error) {
|
||||
/* compile function */
|
||||
compiler := newCompiler().apply(opts)
|
||||
decoder := func(vt *rt.GoType, _ ...interface{}) (interface{}, error) {
|
||||
if pp, err := compiler.compile(_vt); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
as := newAssembler(pp)
|
||||
as.name = _vt.String()
|
||||
return as.Load(), nil
|
||||
}
|
||||
}
|
||||
|
||||
/* find or compile */
|
||||
vt := rt.UnpackType(_vt)
|
||||
if val := programCache.Get(vt); val != nil {
|
||||
return nil, nil
|
||||
} else if _, err := programCache.Compute(vt, decoder); err == nil {
|
||||
return compiler.rec, nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func pretouchRec(vtm map[reflect.Type]bool, opts option.CompileOptions) error {
|
||||
if opts.RecursiveDepth < 0 || len(vtm) == 0 {
|
||||
return nil
|
||||
}
|
||||
next := make(map[reflect.Type]bool)
|
||||
for vt := range(vtm) {
|
||||
sub, err := pretouchType(vt, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for svt := range(sub) {
|
||||
next[svt] = true
|
||||
}
|
||||
}
|
||||
opts.RecursiveDepth -= 1
|
||||
return pretouchRec(next, opts)
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// +build go1.17,!go1.23
|
||||
// +build go1.17,!go1.24
|
||||
|
||||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
|
@ -16,7 +16,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package decoder
|
||||
package jitdec
|
||||
|
||||
import (
|
||||
`encoding/json`
|
|
@ -1,4 +1,4 @@
|
|||
// +build go1.17,!go1.23
|
||||
// +build go1.17,!go1.24
|
||||
|
||||
//
|
||||
// Copyright 2021 ByteDance Inc.
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package decoder
|
||||
package jitdec
|
||||
|
||||
import (
|
||||
`sync`
|
||||
|
@ -36,6 +36,7 @@
|
|||
_PtrBytes = _PTR_SIZE / 8
|
||||
_FsmOffset = (_MaxStack + 1) * _PtrBytes
|
||||
_DbufOffset = _FsmOffset + int64(unsafe.Sizeof(types.StateMachine{})) + types.MAX_RECURSE * _PtrBytes
|
||||
_EpOffset = _DbufOffset + _MaxDigitNums
|
||||
_StackSize = unsafe.Sizeof(_Stack{})
|
||||
)
|
||||
|
||||
|
@ -53,6 +54,7 @@ type _Stack struct {
|
|||
mm types.StateMachine
|
||||
vp [types.MAX_RECURSE]unsafe.Pointer
|
||||
dp [_MaxDigitNums]byte
|
||||
ep unsafe.Pointer
|
||||
}
|
||||
|
||||
type _Decoder func(
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package decoder
|
||||
package jitdec
|
||||
|
||||
import (
|
||||
`encoding`
|
||||
|
@ -39,6 +39,20 @@ func decodeJsonUnmarshaler(vv interface{}, s string) error {
|
|||
return vv.(json.Unmarshaler).UnmarshalJSON(rt.Str2Mem(s))
|
||||
}
|
||||
|
||||
// used to distinguish between MismatchQuoted and other MismatchedTyped errors, see issue #670 and #716
|
||||
type MismatchQuotedError struct {}
|
||||
|
||||
func (*MismatchQuotedError) Error() string {
|
||||
return "mismatch quoted"
|
||||
}
|
||||
|
||||
func decodeJsonUnmarshalerQuoted(vv interface{}, s string) error {
|
||||
if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' {
|
||||
return &MismatchQuotedError{}
|
||||
}
|
||||
return vv.(json.Unmarshaler).UnmarshalJSON(rt.Str2Mem(s[1:len(s)-1]))
|
||||
}
|
||||
|
||||
func decodeTextUnmarshaler(vv interface{}, s string) error {
|
||||
return vv.(encoding.TextUnmarshaler).UnmarshalText(rt.Str2Mem(s))
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// +build go1.16,!go1.20
|
||||
// +build go1.17,!go1.20
|
||||
|
||||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
|
@ -16,7 +16,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package decoder
|
||||
package jitdec
|
||||
|
||||
import (
|
||||
`unsafe`
|
||||
|
@ -72,11 +72,6 @@ func mallocgc(size uintptr, typ *rt.GoType, needzero bool) unsafe.Pointer
|
|||
//goland:noinspection GoUnusedParameter
|
||||
func makeslice(et *rt.GoType, len int, cap int) unsafe.Pointer
|
||||
|
||||
//go:noescape
|
||||
//go:linkname growslice runtime.growslice
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func growslice(et *rt.GoType, old rt.GoSlice, cap int) rt.GoSlice
|
||||
|
||||
//go:linkname makemap_small runtime.makemap_small
|
||||
func makemap_small() unsafe.Pointer
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package decoder
|
||||
package jitdec
|
||||
|
||||
import (
|
||||
`unsafe`
|
||||
|
@ -72,11 +72,6 @@ func mallocgc(size uintptr, typ *rt.GoType, needzero bool) unsafe.Pointer
|
|||
//goland:noinspection GoUnusedParameter
|
||||
func makeslice(et *rt.GoType, len int, cap int) unsafe.Pointer
|
||||
|
||||
//go:noescape
|
||||
//go:linkname growslice reflect.growslice
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func growslice(et *rt.GoType, old rt.GoSlice, cap int) rt.GoSlice
|
||||
|
||||
//go:linkname makemap_small runtime.makemap_small
|
||||
func makemap_small() unsafe.Pointer
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package decoder
|
||||
package jitdec
|
||||
|
||||
import (
|
||||
`encoding`
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package decoder
|
||||
package jitdec
|
||||
|
||||
import (
|
||||
`unsafe`
|
174
vendor/github.com/bytedance/sonic/internal/decoder/optdec/compile_struct.go
generated
vendored
Normal file
174
vendor/github.com/bytedance/sonic/internal/decoder/optdec/compile_struct.go
generated
vendored
Normal file
|
@ -0,0 +1,174 @@
|
|||
package optdec
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
caching "github.com/bytedance/sonic/internal/optcaching"
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
"github.com/bytedance/sonic/internal/resolver"
|
||||
)
|
||||
|
||||
const (
|
||||
_MAX_FIELDS = 50 // cutoff at 50 fields struct
|
||||
)
|
||||
|
||||
func (c *compiler) compileIntStringOption(vt reflect.Type) decFunc {
|
||||
switch vt.Size() {
|
||||
case 4:
|
||||
switch vt.Kind() {
|
||||
case reflect.Uint:
|
||||
fallthrough
|
||||
case reflect.Uintptr:
|
||||
return &u32StringDecoder{}
|
||||
case reflect.Int:
|
||||
return &i32StringDecoder{}
|
||||
}
|
||||
case 8:
|
||||
switch vt.Kind() {
|
||||
case reflect.Uint:
|
||||
fallthrough
|
||||
case reflect.Uintptr:
|
||||
return &u64StringDecoder{}
|
||||
case reflect.Int:
|
||||
return &i64StringDecoder{}
|
||||
}
|
||||
default:
|
||||
panic("not supported pointer size: " + fmt.Sprint(vt.Size()))
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func isInteger(vt reflect.Type) bool {
|
||||
switch vt.Kind() {
|
||||
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint, reflect.Uintptr, reflect.Int: return true
|
||||
default: return false
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compiler) assertStringOptTypes(vt reflect.Type) {
|
||||
if c.depth > _CompileMaxDepth {
|
||||
panic(*stackOverflow)
|
||||
}
|
||||
|
||||
c.depth += 1
|
||||
defer func () {
|
||||
c.depth -= 1
|
||||
}()
|
||||
|
||||
if isInteger(vt) {
|
||||
return
|
||||
}
|
||||
|
||||
switch vt.Kind() {
|
||||
case reflect.String, reflect.Bool, reflect.Float32, reflect.Float64:
|
||||
return
|
||||
case reflect.Ptr: c.assertStringOptTypes(vt.Elem())
|
||||
default:
|
||||
panicForInvalidStrType(vt)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compiler) compileFieldStringOption(vt reflect.Type) decFunc {
|
||||
c.assertStringOptTypes(vt)
|
||||
unmDec := c.tryCompilePtrUnmarshaler(vt, true)
|
||||
if unmDec != nil {
|
||||
return unmDec
|
||||
}
|
||||
|
||||
switch vt.Kind() {
|
||||
case reflect.String:
|
||||
if vt == jsonNumberType {
|
||||
return &numberStringDecoder{}
|
||||
}
|
||||
return &strStringDecoder{}
|
||||
case reflect.Bool:
|
||||
return &boolStringDecoder{}
|
||||
case reflect.Int8:
|
||||
return &i8StringDecoder{}
|
||||
case reflect.Int16:
|
||||
return &i16StringDecoder{}
|
||||
case reflect.Int32:
|
||||
return &i32StringDecoder{}
|
||||
case reflect.Int64:
|
||||
return &i64StringDecoder{}
|
||||
case reflect.Uint8:
|
||||
return &u8StringDecoder{}
|
||||
case reflect.Uint16:
|
||||
return &u16StringDecoder{}
|
||||
case reflect.Uint32:
|
||||
return &u32StringDecoder{}
|
||||
case reflect.Uint64:
|
||||
return &u64StringDecoder{}
|
||||
case reflect.Float32:
|
||||
return &f32StringDecoder{}
|
||||
case reflect.Float64:
|
||||
return &f64StringDecoder{}
|
||||
case reflect.Uint:
|
||||
fallthrough
|
||||
case reflect.Uintptr:
|
||||
fallthrough
|
||||
case reflect.Int:
|
||||
return c.compileIntStringOption(vt)
|
||||
case reflect.Ptr:
|
||||
return &ptrStrDecoder{
|
||||
typ: rt.UnpackType(vt.Elem()),
|
||||
deref: c.compileFieldStringOption(vt.Elem()),
|
||||
}
|
||||
default:
|
||||
panicForInvalidStrType(vt)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compiler) compileStruct(vt reflect.Type) decFunc {
|
||||
c.enter(vt)
|
||||
defer c.exit(vt)
|
||||
if c.namedPtr {
|
||||
c.namedPtr = false
|
||||
return c.compileStructBody(vt)
|
||||
}
|
||||
|
||||
if c.depth >= c.opts.MaxInlineDepth + 1 || (c.counts > 0 && vt.NumField() >= _MAX_FIELDS) {
|
||||
return &recuriveDecoder{
|
||||
typ: rt.UnpackType(vt),
|
||||
}
|
||||
} else {
|
||||
return c.compileStructBody(vt)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compiler) compileStructBody(vt reflect.Type) decFunc {
|
||||
fv := resolver.ResolveStruct(vt)
|
||||
entries := make([]fieldEntry, 0, len(fv))
|
||||
|
||||
for _, f := range fv {
|
||||
var dec decFunc
|
||||
/* dealt with field tag options */
|
||||
if f.Opts&resolver.F_stringize != 0 {
|
||||
dec = c.compileFieldStringOption(f.Type)
|
||||
} else {
|
||||
dec = c.compile(f.Type)
|
||||
}
|
||||
|
||||
/* deal with embedded pointer fields */
|
||||
if f.Path[0].Kind == resolver.F_deref {
|
||||
dec = &embeddedFieldPtrDecoder{
|
||||
field: f,
|
||||
fieldDec: dec,
|
||||
fieldName: f.Name,
|
||||
}
|
||||
}
|
||||
|
||||
entries = append(entries, fieldEntry{
|
||||
FieldMeta: f,
|
||||
fieldDec: dec,
|
||||
})
|
||||
}
|
||||
return &structDecoder{
|
||||
fieldMap: caching.NewFieldLookup(fv),
|
||||
fields: entries,
|
||||
structName: vt.Name(),
|
||||
typ: vt,
|
||||
}
|
||||
}
|
449
vendor/github.com/bytedance/sonic/internal/decoder/optdec/compiler.go
generated
vendored
Normal file
449
vendor/github.com/bytedance/sonic/internal/decoder/optdec/compiler.go
generated
vendored
Normal file
|
@ -0,0 +1,449 @@
|
|||
package optdec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/bytedance/sonic/option"
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
"github.com/bytedance/sonic/internal/caching"
|
||||
)
|
||||
|
||||
var (
|
||||
programCache = caching.CreateProgramCache()
|
||||
)
|
||||
|
||||
func findOrCompile(vt *rt.GoType) (decFunc, error) {
|
||||
makeDecoder := func(vt *rt.GoType, _ ...interface{}) (interface{}, error) {
|
||||
ret, err := newCompiler().compileType(vt.Pack())
|
||||
return ret, err
|
||||
}
|
||||
if val := programCache.Get(vt); val != nil {
|
||||
return val.(decFunc), nil
|
||||
} else if ret, err := programCache.Compute(vt, makeDecoder); err == nil {
|
||||
return ret.(decFunc), nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
type compiler struct {
|
||||
visited map[reflect.Type]bool
|
||||
depth int
|
||||
counts int
|
||||
opts option.CompileOptions
|
||||
namedPtr bool
|
||||
}
|
||||
|
||||
func newCompiler() *compiler {
|
||||
return &compiler{
|
||||
visited: make(map[reflect.Type]bool),
|
||||
opts: option.DefaultCompileOptions(),
|
||||
}
|
||||
}
|
||||
|
||||
func (self *compiler) apply(opts option.CompileOptions) *compiler {
|
||||
self.opts = opts
|
||||
return self
|
||||
}
|
||||
|
||||
const _CompileMaxDepth = 4096
|
||||
|
||||
func (c *compiler) enter(vt reflect.Type) {
|
||||
c.visited[vt] = true
|
||||
c.depth += 1
|
||||
|
||||
if c.depth > _CompileMaxDepth {
|
||||
panic(*stackOverflow)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compiler) exit(vt reflect.Type) {
|
||||
c.visited[vt] = false
|
||||
c.depth -= 1
|
||||
}
|
||||
|
||||
func (c *compiler) compileInt(vt reflect.Type) decFunc {
|
||||
switch vt.Size() {
|
||||
case 4:
|
||||
switch vt.Kind() {
|
||||
case reflect.Uint:
|
||||
fallthrough
|
||||
case reflect.Uintptr:
|
||||
return &u32Decoder{}
|
||||
case reflect.Int:
|
||||
return &i32Decoder{}
|
||||
}
|
||||
case 8:
|
||||
switch vt.Kind() {
|
||||
case reflect.Uint:
|
||||
fallthrough
|
||||
case reflect.Uintptr:
|
||||
return &u64Decoder{}
|
||||
case reflect.Int:
|
||||
return &i64Decoder{}
|
||||
}
|
||||
default:
|
||||
panic("not supported pointer size: " + fmt.Sprint(vt.Size()))
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func (c *compiler) rescue(ep *error) {
|
||||
if val := recover(); val != nil {
|
||||
if err, ok := val.(error); ok {
|
||||
*ep = err
|
||||
} else {
|
||||
panic(val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compiler) compileType(vt reflect.Type) (rt decFunc, err error) {
|
||||
defer c.rescue(&err)
|
||||
rt = c.compile(vt)
|
||||
return rt, err
|
||||
}
|
||||
|
||||
func (c *compiler) compile(vt reflect.Type) decFunc {
|
||||
if c.visited[vt] {
|
||||
return &recuriveDecoder{
|
||||
typ: rt.UnpackType(vt),
|
||||
}
|
||||
}
|
||||
|
||||
dec := c.tryCompilePtrUnmarshaler(vt, false)
|
||||
if dec != nil {
|
||||
return dec
|
||||
}
|
||||
|
||||
return c.compileBasic(vt)
|
||||
}
|
||||
|
||||
func (c *compiler) compileBasic(vt reflect.Type) decFunc {
|
||||
defer func() {
|
||||
c.counts += 1
|
||||
}()
|
||||
switch vt.Kind() {
|
||||
case reflect.Bool:
|
||||
return &boolDecoder{}
|
||||
case reflect.Int8:
|
||||
return &i8Decoder{}
|
||||
case reflect.Int16:
|
||||
return &i16Decoder{}
|
||||
case reflect.Int32:
|
||||
return &i32Decoder{}
|
||||
case reflect.Int64:
|
||||
return &i64Decoder{}
|
||||
case reflect.Uint8:
|
||||
return &u8Decoder{}
|
||||
case reflect.Uint16:
|
||||
return &u16Decoder{}
|
||||
case reflect.Uint32:
|
||||
return &u32Decoder{}
|
||||
case reflect.Uint64:
|
||||
return &u64Decoder{}
|
||||
case reflect.Float32:
|
||||
return &f32Decoder{}
|
||||
case reflect.Float64:
|
||||
return &f64Decoder{}
|
||||
case reflect.Uint:
|
||||
fallthrough
|
||||
case reflect.Uintptr:
|
||||
fallthrough
|
||||
case reflect.Int:
|
||||
return c.compileInt(vt)
|
||||
case reflect.String:
|
||||
return c.compileString(vt)
|
||||
case reflect.Array:
|
||||
return c.compileArray(vt)
|
||||
case reflect.Interface:
|
||||
return c.compileInterface(vt)
|
||||
case reflect.Map:
|
||||
return c.compileMap(vt)
|
||||
case reflect.Ptr:
|
||||
return c.compilePtr(vt)
|
||||
case reflect.Slice:
|
||||
return c.compileSlice(vt)
|
||||
case reflect.Struct:
|
||||
return c.compileStruct(vt)
|
||||
default:
|
||||
panic(&json.UnmarshalTypeError{Type: vt})
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compiler) compilePtr(vt reflect.Type) decFunc {
|
||||
c.enter(vt)
|
||||
defer c.exit(vt)
|
||||
|
||||
// specail logic for Named Ptr, issue 379
|
||||
if reflect.PtrTo(vt.Elem()) != vt {
|
||||
c.namedPtr = true
|
||||
return &ptrDecoder{
|
||||
typ: rt.UnpackType(vt.Elem()),
|
||||
deref: c.compileBasic(vt.Elem()),
|
||||
}
|
||||
}
|
||||
|
||||
return &ptrDecoder{
|
||||
typ: rt.UnpackType(vt.Elem()),
|
||||
deref: c.compile(vt.Elem()),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compiler) compileArray(vt reflect.Type) decFunc {
|
||||
c.enter(vt)
|
||||
defer c.exit(vt)
|
||||
return &arrayDecoder{
|
||||
len: vt.Len(),
|
||||
elemType: rt.UnpackType(vt.Elem()),
|
||||
elemDec: c.compile(vt.Elem()),
|
||||
typ: vt,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compiler) compileString(vt reflect.Type) decFunc {
|
||||
if vt == jsonNumberType {
|
||||
return &numberDecoder{}
|
||||
}
|
||||
return &stringDecoder{}
|
||||
|
||||
}
|
||||
|
||||
func (c *compiler) tryCompileSliceUnmarshaler(vt reflect.Type) decFunc {
|
||||
pt := reflect.PtrTo(vt.Elem())
|
||||
if pt.Implements(jsonUnmarshalerType) {
|
||||
return &sliceDecoder{
|
||||
elemType: rt.UnpackType(vt.Elem()),
|
||||
elemDec: c.compile(vt.Elem()),
|
||||
typ: vt,
|
||||
}
|
||||
}
|
||||
|
||||
if pt.Implements(encodingTextUnmarshalerType) {
|
||||
return &sliceDecoder{
|
||||
elemType: rt.UnpackType(vt.Elem()),
|
||||
elemDec: c.compile(vt.Elem()),
|
||||
typ: vt,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *compiler) compileSlice(vt reflect.Type) decFunc {
|
||||
c.enter(vt)
|
||||
defer c.exit(vt)
|
||||
|
||||
// Some common slice, use a decoder, to avoid function calls
|
||||
et := rt.UnpackType(vt.Elem())
|
||||
|
||||
/* first checking `[]byte` */
|
||||
if et.Kind() == reflect.Uint8 /* []byte */ {
|
||||
return c.compileSliceBytes(vt)
|
||||
}
|
||||
|
||||
dec := c.tryCompileSliceUnmarshaler(vt)
|
||||
if dec != nil {
|
||||
return dec
|
||||
}
|
||||
|
||||
if vt == reflect.TypeOf([]interface{}{}) {
|
||||
return &sliceEfaceDecoder{}
|
||||
}
|
||||
if et.IsInt32() {
|
||||
return &sliceI32Decoder{}
|
||||
}
|
||||
if et.IsInt64() {
|
||||
return &sliceI64Decoder{}
|
||||
}
|
||||
if et.IsUint32() {
|
||||
return &sliceU32Decoder{}
|
||||
}
|
||||
if et.IsUint64() {
|
||||
return &sliceU64Decoder{}
|
||||
}
|
||||
if et.Kind() == reflect.String {
|
||||
return &sliceStringDecoder{}
|
||||
}
|
||||
|
||||
return &sliceDecoder{
|
||||
elemType: rt.UnpackType(vt.Elem()),
|
||||
elemDec: c.compile(vt.Elem()),
|
||||
typ: vt,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compiler) compileSliceBytes(vt reflect.Type) decFunc {
|
||||
ep := reflect.PtrTo(vt.Elem())
|
||||
|
||||
if ep.Implements(jsonUnmarshalerType) {
|
||||
return &sliceBytesUnmarshalerDecoder{
|
||||
elemType: rt.UnpackType(vt.Elem()),
|
||||
elemDec: c.compile(vt.Elem()),
|
||||
typ: vt,
|
||||
}
|
||||
}
|
||||
|
||||
if ep.Implements(encodingTextUnmarshalerType) {
|
||||
return &sliceBytesUnmarshalerDecoder{
|
||||
elemType: rt.UnpackType(vt.Elem()),
|
||||
elemDec: c.compile(vt.Elem()),
|
||||
typ: vt,
|
||||
}
|
||||
}
|
||||
|
||||
return &sliceBytesDecoder{}
|
||||
}
|
||||
|
||||
func (c *compiler) compileInterface(vt reflect.Type) decFunc {
|
||||
c.enter(vt)
|
||||
defer c.exit(vt)
|
||||
if vt.NumMethod() == 0 {
|
||||
return &efaceDecoder{}
|
||||
}
|
||||
|
||||
if vt.Implements(jsonUnmarshalerType) {
|
||||
return &unmarshalJSONDecoder{
|
||||
typ: rt.UnpackType(vt),
|
||||
}
|
||||
}
|
||||
|
||||
if vt.Implements(encodingTextUnmarshalerType) {
|
||||
return &unmarshalTextDecoder{
|
||||
typ: rt.UnpackType(vt),
|
||||
}
|
||||
}
|
||||
|
||||
return &ifaceDecoder{
|
||||
typ: rt.UnpackType(vt),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compiler) compileMap(vt reflect.Type) decFunc {
|
||||
c.enter(vt)
|
||||
defer c.exit(vt)
|
||||
// check the key unmarshaler at first
|
||||
decKey := tryCompileKeyUnmarshaler(vt)
|
||||
if decKey != nil {
|
||||
return &mapDecoder{
|
||||
mapType: rt.MapType(rt.UnpackType(vt)),
|
||||
keyDec: decKey,
|
||||
elemDec: c.compile(vt.Elem()),
|
||||
}
|
||||
}
|
||||
|
||||
// Most common map, use a decoder, to avoid function calls
|
||||
if vt == reflect.TypeOf(map[string]interface{}{}) {
|
||||
return &mapEfaceDecoder{}
|
||||
} else if vt == reflect.TypeOf(map[string]string{}) {
|
||||
return &mapStringDecoder{}
|
||||
}
|
||||
|
||||
// Some common integer map later
|
||||
mt := rt.MapType(rt.UnpackType(vt))
|
||||
|
||||
if mt.Key.Kind() == reflect.String {
|
||||
return &mapStrKeyDecoder{
|
||||
mapType: mt,
|
||||
assign: rt.GetMapStrAssign(vt),
|
||||
elemDec: c.compile(vt.Elem()),
|
||||
}
|
||||
}
|
||||
|
||||
if mt.Key.IsInt64() {
|
||||
return &mapI64KeyDecoder{
|
||||
mapType: mt,
|
||||
elemDec: c.compile(vt.Elem()),
|
||||
assign: rt.GetMap64Assign(vt),
|
||||
}
|
||||
}
|
||||
|
||||
if mt.Key.IsInt32() {
|
||||
return &mapI32KeyDecoder{
|
||||
mapType: mt,
|
||||
elemDec: c.compile(vt.Elem()),
|
||||
assign: rt.GetMap32Assign(vt),
|
||||
}
|
||||
}
|
||||
|
||||
if mt.Key.IsUint64() {
|
||||
return &mapU64KeyDecoder{
|
||||
mapType: mt,
|
||||
elemDec: c.compile(vt.Elem()),
|
||||
assign: rt.GetMap64Assign(vt),
|
||||
}
|
||||
}
|
||||
|
||||
if mt.Key.IsUint32() {
|
||||
return &mapU32KeyDecoder{
|
||||
mapType: mt,
|
||||
elemDec: c.compile(vt.Elem()),
|
||||
assign: rt.GetMap32Assign(vt),
|
||||
}
|
||||
}
|
||||
|
||||
// Generic map
|
||||
return &mapDecoder{
|
||||
mapType: mt,
|
||||
keyDec: c.compileMapKey(vt),
|
||||
elemDec: c.compile(vt.Elem()),
|
||||
}
|
||||
}
|
||||
|
||||
func tryCompileKeyUnmarshaler(vt reflect.Type) decKey {
|
||||
pt := reflect.PtrTo(vt.Key())
|
||||
|
||||
/* check for `encoding.TextUnmarshaler` with pointer receiver */
|
||||
if pt.Implements(encodingTextUnmarshalerType) {
|
||||
return decodeKeyTextUnmarshaler
|
||||
}
|
||||
|
||||
/* not support map key with `json.Unmarshaler` */
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *compiler) compileMapKey(vt reflect.Type) decKey {
|
||||
switch vt.Key().Kind() {
|
||||
case reflect.Int8:
|
||||
return decodeKeyI8
|
||||
case reflect.Int16:
|
||||
return decodeKeyI16
|
||||
case reflect.Uint8:
|
||||
return decodeKeyU8
|
||||
case reflect.Uint16:
|
||||
return decodeKeyU16
|
||||
default:
|
||||
panic(&json.UnmarshalTypeError{Type: vt})
|
||||
}
|
||||
}
|
||||
|
||||
// maybe vt is a named type, and not a pointer receiver, see issue 379
|
||||
func (c *compiler) tryCompilePtrUnmarshaler(vt reflect.Type, strOpt bool) decFunc {
|
||||
pt := reflect.PtrTo(vt)
|
||||
|
||||
/* check for `json.Unmarshaler` with pointer receiver */
|
||||
if pt.Implements(jsonUnmarshalerType) {
|
||||
return &unmarshalJSONDecoder{
|
||||
typ: rt.UnpackType(pt),
|
||||
strOpt: strOpt,
|
||||
}
|
||||
}
|
||||
|
||||
/* check for `encoding.TextMarshaler` with pointer receiver */
|
||||
if pt.Implements(encodingTextUnmarshalerType) {
|
||||
/* TextUnmarshal not support ,strig tag */
|
||||
if strOpt {
|
||||
panicForInvalidStrType(vt)
|
||||
}
|
||||
return &unmarshalTextDecoder{
|
||||
typ: rt.UnpackType(pt),
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func panicForInvalidStrType(vt reflect.Type) {
|
||||
panic(error_type(rt.UnpackType(vt)))
|
||||
}
|
60
vendor/github.com/bytedance/sonic/internal/decoder/optdec/const.go
generated
vendored
Normal file
60
vendor/github.com/bytedance/sonic/internal/decoder/optdec/const.go
generated
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
package optdec
|
||||
|
||||
import "math"
|
||||
|
||||
/*
|
||||
Copied from sonic-rs
|
||||
// JSON Value Type
|
||||
const NULL: u64 = 0;
|
||||
const BOOL: u64 = 2;
|
||||
const FALSE: u64 = BOOL;
|
||||
const TRUE: u64 = (1 << 3) | BOOL;
|
||||
const NUMBER: u64 = 3;
|
||||
const UINT: u64 = NUMBER;
|
||||
const SINT: u64 = (1 << 3) | NUMBER;
|
||||
const REAL: u64 = (2 << 3) | NUMBER;
|
||||
const RAWNUMBER: u64 = (3 << 3) | NUMBER;
|
||||
const STRING: u64 = 4;
|
||||
const STRING_COMMON: u64 = STRING;
|
||||
const STRING_HASESCAPED: u64 = (1 << 3) | STRING;
|
||||
const OBJECT: u64 = 6;
|
||||
const ARRAY: u64 = 7;
|
||||
|
||||
/// JSON Type Mask
|
||||
const POS_MASK: u64 = (!0) << 32;
|
||||
const POS_BITS: u64 = 32;
|
||||
const TYPE_MASK: u64 = 0xFF;
|
||||
const TYPE_BITS: u64 = 8;
|
||||
|
||||
*/
|
||||
|
||||
const (
|
||||
// BasicType: 3 bits
|
||||
KNull = 0 // xxxxx000
|
||||
KBool = 2 // xxxxx010
|
||||
KNumber = 3 // xxxxx011
|
||||
KString = 4 // xxxxx100
|
||||
KRaw = 5 // xxxxx101
|
||||
KObject = 6 // xxxxx110
|
||||
KArray = 7 // xxxxx111
|
||||
|
||||
// SubType: 2 bits
|
||||
KFalse = (0 << 3) | KBool // xxx00_010, 2
|
||||
KTrue = (1 << 3) | KBool // xxx01_010, 10
|
||||
KUint = (0 << 3) | KNumber // xxx00_011, 3
|
||||
KSint = (1 << 3) | KNumber // xxx01_011, 11
|
||||
KReal = (2 << 3) | KNumber // xxx10_011, 19
|
||||
KRawNumber = (3 << 3) | KNumber // xxx11_011, 27
|
||||
KStringCommon = KString // xxx00_100, 4
|
||||
KStringEscaped = (1 << 3) | KString // xxx01_100, 12
|
||||
)
|
||||
|
||||
const (
|
||||
PosMask = math.MaxUint64 << 32
|
||||
PosBits = 32
|
||||
TypeMask = 0xFF
|
||||
TypeBits = 8
|
||||
|
||||
ConLenMask = uint64(math.MaxUint32)
|
||||
ConLenBits = 32
|
||||
)
|
3
vendor/github.com/bytedance/sonic/internal/decoder/optdec/context.go
generated
vendored
Normal file
3
vendor/github.com/bytedance/sonic/internal/decoder/optdec/context.go
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
package optdec
|
||||
|
||||
type context = Context
|
160
vendor/github.com/bytedance/sonic/internal/decoder/optdec/decoder.go
generated
vendored
Normal file
160
vendor/github.com/bytedance/sonic/internal/decoder/optdec/decoder.go
generated
vendored
Normal file
|
@ -0,0 +1,160 @@
|
|||
package optdec
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
"encoding/json"
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
"github.com/bytedance/sonic/option"
|
||||
"github.com/bytedance/sonic/internal/decoder/errors"
|
||||
"github.com/bytedance/sonic/internal/decoder/consts"
|
||||
)
|
||||
|
||||
|
||||
type (
|
||||
MismatchTypeError = errors.MismatchTypeError
|
||||
SyntaxError = errors.SyntaxError
|
||||
)
|
||||
|
||||
const (
|
||||
_F_allow_control = consts.F_allow_control
|
||||
_F_copy_string = consts.F_copy_string
|
||||
_F_disable_unknown = consts.F_disable_unknown
|
||||
_F_disable_urc = consts.F_disable_urc
|
||||
_F_use_int64 = consts.F_use_int64
|
||||
_F_use_number = consts.F_use_number
|
||||
_F_validate_string = consts.F_validate_string
|
||||
)
|
||||
|
||||
type Options = consts.Options
|
||||
|
||||
const (
|
||||
OptionUseInt64 = consts.OptionUseInt64
|
||||
OptionUseNumber = consts.OptionUseNumber
|
||||
OptionUseUnicodeErrors = consts.OptionUseUnicodeErrors
|
||||
OptionDisableUnknown = consts.OptionDisableUnknown
|
||||
OptionCopyString = consts.OptionCopyString
|
||||
OptionValidateString = consts.OptionValidateString
|
||||
)
|
||||
|
||||
|
||||
func Decode(s *string, i *int, f uint64, val interface{}) error {
|
||||
vv := rt.UnpackEface(val)
|
||||
vp := vv.Value
|
||||
|
||||
/* check for nil type */
|
||||
if vv.Type == nil {
|
||||
return &json.InvalidUnmarshalError{}
|
||||
}
|
||||
|
||||
/* must be a non-nil pointer */
|
||||
if vp == nil || vv.Type.Kind() != reflect.Ptr {
|
||||
return &json.InvalidUnmarshalError{Type: vv.Type.Pack()}
|
||||
}
|
||||
|
||||
etp := rt.PtrElem(vv.Type)
|
||||
|
||||
/* check the defined pointer type for issue 379 */
|
||||
if vv.Type.IsNamed() {
|
||||
newp := vp
|
||||
etp = vv.Type
|
||||
vp = unsafe.Pointer(&newp)
|
||||
}
|
||||
|
||||
dec, err := findOrCompile(etp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
/* parse into document */
|
||||
ctx, err := NewContext(*s, *i, uint64(f), etp)
|
||||
defer ctx.Delete()
|
||||
if ctx.Parser.Utf8Inv {
|
||||
*s = ctx.Parser.Json
|
||||
}
|
||||
if err != nil {
|
||||
goto fix_error;
|
||||
}
|
||||
err = dec.FromDom(vp, ctx.Root(), &ctx)
|
||||
|
||||
fix_error:
|
||||
err = fix_error(*s, *i, err)
|
||||
|
||||
// update position at last
|
||||
*i += ctx.Parser.Pos()
|
||||
return err
|
||||
}
|
||||
|
||||
func fix_error(json string, pos int, err error) error {
|
||||
if e, ok := err.(SyntaxError); ok {
|
||||
return SyntaxError{
|
||||
Pos: int(e.Pos) + pos,
|
||||
Src: json,
|
||||
Msg: e.Msg,
|
||||
}
|
||||
}
|
||||
|
||||
if e, ok := err.(MismatchTypeError); ok {
|
||||
return &MismatchTypeError {
|
||||
Pos: int(e.Pos) + pos,
|
||||
Src: json,
|
||||
Type: e.Type,
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Pretouch compiles vt ahead-of-time to avoid JIT compilation on-the-fly, in
|
||||
// order to reduce the first-hit latency.
|
||||
//
|
||||
// Opts are the compile options, for example, "option.WithCompileRecursiveDepth" is
|
||||
// a compile option to set the depth of recursive compile for the nested struct type.
|
||||
func Pretouch(vt reflect.Type, opts ...option.CompileOption) error {
|
||||
cfg := option.DefaultCompileOptions()
|
||||
for _, opt := range opts {
|
||||
opt(&cfg)
|
||||
}
|
||||
return pretouchRec(map[reflect.Type]bool{vt:true}, cfg)
|
||||
}
|
||||
|
||||
func pretouchType(_vt reflect.Type, opts option.CompileOptions) (map[reflect.Type]bool, error) {
|
||||
/* compile function */
|
||||
compiler := newCompiler().apply(opts)
|
||||
decoder := func(vt *rt.GoType, _ ...interface{}) (interface{}, error) {
|
||||
if f, err := compiler.compileType(_vt); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return f, nil
|
||||
}
|
||||
}
|
||||
|
||||
/* find or compile */
|
||||
vt := rt.UnpackType(_vt)
|
||||
if val := programCache.Get(vt); val != nil {
|
||||
return nil, nil
|
||||
} else if _, err := programCache.Compute(vt, decoder); err == nil {
|
||||
return compiler.visited, nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func pretouchRec(vtm map[reflect.Type]bool, opts option.CompileOptions) error {
|
||||
if opts.RecursiveDepth < 0 || len(vtm) == 0 {
|
||||
return nil
|
||||
}
|
||||
next := make(map[reflect.Type]bool)
|
||||
for vt := range(vtm) {
|
||||
sub, err := pretouchType(vt, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for svt := range(sub) {
|
||||
next[svt] = true
|
||||
}
|
||||
}
|
||||
opts.RecursiveDepth -= 1
|
||||
return pretouchRec(next, opts)
|
||||
}
|
73
vendor/github.com/bytedance/sonic/internal/decoder/optdec/errors.go
generated
vendored
Normal file
73
vendor/github.com/bytedance/sonic/internal/decoder/optdec/errors.go
generated
vendored
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package optdec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
)
|
||||
|
||||
/** JIT Error Helpers **/
|
||||
|
||||
var stackOverflow = &json.UnsupportedValueError{
|
||||
Str: "Value nesting too deep",
|
||||
Value: reflect.ValueOf("..."),
|
||||
}
|
||||
|
||||
func error_type(vt *rt.GoType) error {
|
||||
return &json.UnmarshalTypeError{Type: vt.Pack()}
|
||||
}
|
||||
|
||||
func error_mismatch(node Node, ctx *context, typ reflect.Type) error {
|
||||
return MismatchTypeError{
|
||||
Pos: node.Position(),
|
||||
Src: ctx.Parser.Json,
|
||||
Type: typ,
|
||||
}
|
||||
}
|
||||
|
||||
func newUnmatched(pos int, vt *rt.GoType) error {
|
||||
return MismatchTypeError{
|
||||
Pos: pos,
|
||||
Src: "",
|
||||
Type: vt.Pack(),
|
||||
}
|
||||
}
|
||||
|
||||
func error_field(name string) error {
|
||||
return errors.New("json: unknown field " + strconv.Quote(name))
|
||||
}
|
||||
|
||||
func error_value(value string, vtype reflect.Type) error {
|
||||
return &json.UnmarshalTypeError{
|
||||
Type: vtype,
|
||||
Value: value,
|
||||
}
|
||||
}
|
||||
|
||||
func error_syntax(pos int, src string, msg string) error {
|
||||
return SyntaxError{
|
||||
Pos: pos,
|
||||
Src: src,
|
||||
Msg: msg,
|
||||
}
|
||||
}
|
||||
|
281
vendor/github.com/bytedance/sonic/internal/decoder/optdec/functor.go
generated
vendored
Normal file
281
vendor/github.com/bytedance/sonic/internal/decoder/optdec/functor.go
generated
vendored
Normal file
|
@ -0,0 +1,281 @@
|
|||
package optdec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
"unsafe"
|
||||
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
"github.com/bytedance/sonic/internal/resolver"
|
||||
)
|
||||
|
||||
type decFunc interface {
|
||||
FromDom(vp unsafe.Pointer, node Node, ctx *context) error
|
||||
}
|
||||
|
||||
type ptrDecoder struct {
|
||||
typ *rt.GoType
|
||||
deref decFunc
|
||||
}
|
||||
|
||||
// Pointer Value is allocated in the Caller
|
||||
func (d *ptrDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
*(*unsafe.Pointer)(vp) = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
if *(*unsafe.Pointer)(vp) == nil {
|
||||
*(*unsafe.Pointer)(vp) = rt.Mallocgc(d.typ.Size, d.typ, true)
|
||||
}
|
||||
|
||||
return d.deref.FromDom(*(*unsafe.Pointer)(vp), node, ctx)
|
||||
}
|
||||
|
||||
type embeddedFieldPtrDecoder struct {
|
||||
field resolver.FieldMeta
|
||||
fieldDec decFunc
|
||||
fieldName string
|
||||
}
|
||||
|
||||
// Pointer Value is allocated in the Caller
|
||||
func (d *embeddedFieldPtrDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// seek into the pointer
|
||||
vp = unsafe.Pointer(uintptr(vp) - uintptr(d.field.Path[0].Size))
|
||||
for _, f := range d.field.Path {
|
||||
deref := rt.UnpackType(f.Type)
|
||||
vp = unsafe.Pointer(uintptr(vp) + f.Size)
|
||||
if f.Kind == resolver.F_deref {
|
||||
if *(*unsafe.Pointer)(vp) == nil {
|
||||
*(*unsafe.Pointer)(vp) = rt.Mallocgc(deref.Size, deref, true)
|
||||
}
|
||||
vp = *(*unsafe.Pointer)(vp)
|
||||
}
|
||||
}
|
||||
return d.fieldDec.FromDom(vp, node, ctx)
|
||||
}
|
||||
|
||||
type i8Decoder struct{}
|
||||
|
||||
func (d *i8Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
ret, ok := node.AsI64(ctx)
|
||||
if !ok || ret > math.MaxInt8 || ret < math.MinInt8 {
|
||||
return error_mismatch(node, ctx, int8Type)
|
||||
}
|
||||
|
||||
*(*int8)(vp) = int8(ret)
|
||||
return nil
|
||||
}
|
||||
|
||||
type i16Decoder struct{}
|
||||
|
||||
func (d *i16Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
ret, ok := node.AsI64(ctx)
|
||||
if !ok || ret > math.MaxInt16 || ret < math.MinInt16 {
|
||||
return error_mismatch(node, ctx, int16Type)
|
||||
}
|
||||
|
||||
*(*int16)(vp) = int16(ret)
|
||||
return nil
|
||||
}
|
||||
|
||||
type i32Decoder struct{}
|
||||
|
||||
func (d *i32Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
ret, ok := node.AsI64(ctx)
|
||||
if !ok || ret > math.MaxInt32 || ret < math.MinInt32 {
|
||||
return error_mismatch(node, ctx, int32Type)
|
||||
}
|
||||
|
||||
*(*int32)(vp) = int32(ret)
|
||||
return nil
|
||||
}
|
||||
|
||||
type i64Decoder struct{}
|
||||
|
||||
func (d *i64Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
ret, ok := node.AsI64(ctx)
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, int64Type)
|
||||
}
|
||||
|
||||
*(*int64)(vp) = int64(ret)
|
||||
return nil
|
||||
}
|
||||
|
||||
type u8Decoder struct{}
|
||||
|
||||
func (d *u8Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
ret, ok := node.AsU64(ctx)
|
||||
if !ok || ret > math.MaxUint8 {
|
||||
err := error_mismatch(node, ctx, uint8Type)
|
||||
return err
|
||||
}
|
||||
|
||||
*(*uint8)(vp) = uint8(ret)
|
||||
return nil
|
||||
}
|
||||
|
||||
type u16Decoder struct{}
|
||||
|
||||
func (d *u16Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
ret, ok := node.AsU64(ctx)
|
||||
if !ok || ret > math.MaxUint16 {
|
||||
return error_mismatch(node, ctx, uint16Type)
|
||||
}
|
||||
*(*uint16)(vp) = uint16(ret)
|
||||
return nil
|
||||
}
|
||||
|
||||
type u32Decoder struct{}
|
||||
|
||||
func (d *u32Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
ret, ok := node.AsU64(ctx)
|
||||
if !ok || ret > math.MaxUint32 {
|
||||
return error_mismatch(node, ctx, uint32Type)
|
||||
}
|
||||
|
||||
*(*uint32)(vp) = uint32(ret)
|
||||
return nil
|
||||
}
|
||||
|
||||
type u64Decoder struct{}
|
||||
|
||||
func (d *u64Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
ret, ok := node.AsU64(ctx)
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, uint64Type)
|
||||
}
|
||||
|
||||
*(*uint64)(vp) = uint64(ret)
|
||||
return nil
|
||||
}
|
||||
|
||||
type f32Decoder struct{}
|
||||
|
||||
func (d *f32Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
ret, ok := node.AsF64(ctx)
|
||||
if !ok || ret > math.MaxFloat32 || ret < -math.MaxFloat32 {
|
||||
return error_mismatch(node, ctx, float32Type)
|
||||
}
|
||||
|
||||
*(*float32)(vp) = float32(ret)
|
||||
return nil
|
||||
}
|
||||
|
||||
type f64Decoder struct{}
|
||||
|
||||
func (d *f64Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
ret, ok := node.AsF64(ctx)
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, float64Type)
|
||||
}
|
||||
|
||||
*(*float64)(vp) = float64(ret)
|
||||
return nil
|
||||
}
|
||||
|
||||
type boolDecoder struct {
|
||||
}
|
||||
|
||||
func (d *boolDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
ret, ok := node.AsBool()
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, boolType)
|
||||
}
|
||||
|
||||
*(*bool)(vp) = bool(ret)
|
||||
return nil
|
||||
}
|
||||
|
||||
type stringDecoder struct {
|
||||
}
|
||||
|
||||
func (d *stringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
ret, ok := node.AsStr(ctx)
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, stringType)
|
||||
}
|
||||
*(*string)(vp) = ret
|
||||
return nil
|
||||
}
|
||||
|
||||
type numberDecoder struct {
|
||||
}
|
||||
|
||||
func (d *numberDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
num, ok := node.AsNumber(ctx)
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, jsonNumberType)
|
||||
}
|
||||
*(*json.Number)(vp) = num
|
||||
return nil
|
||||
}
|
||||
|
||||
type recuriveDecoder struct {
|
||||
typ *rt.GoType
|
||||
}
|
||||
|
||||
func (d *recuriveDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
dec, err := findOrCompile(d.typ)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return dec.FromDom(vp, node, ctx)
|
||||
}
|
110
vendor/github.com/bytedance/sonic/internal/decoder/optdec/helper.go
generated
vendored
Normal file
110
vendor/github.com/bytedance/sonic/internal/decoder/optdec/helper.go
generated
vendored
Normal file
|
@ -0,0 +1,110 @@
|
|||
package optdec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
"github.com/bytedance/sonic/internal/native"
|
||||
"github.com/bytedance/sonic/internal/utils"
|
||||
"github.com/bytedance/sonic/internal/native/types"
|
||||
)
|
||||
|
||||
|
||||
func SkipNumberFast(json string, start int) (int, bool) {
|
||||
// find the number ending, we pasred in native, it alway valid
|
||||
pos := start
|
||||
for pos < len(json) && json[pos] != ']' && json[pos] != '}' && json[pos] != ',' {
|
||||
if json[pos] >= '0' && json[pos] <= '9' || json[pos] == '.' || json[pos] == '-' || json[pos] == '+' || json[pos] == 'e' || json[pos] == 'E' {
|
||||
pos += 1
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// if not found number, return false
|
||||
if pos == start {
|
||||
return pos, false
|
||||
}
|
||||
return pos, true
|
||||
}
|
||||
|
||||
|
||||
func isSpace(c byte) bool {
|
||||
return c == ' ' || c == '\t' || c == '\n' || c == '\r'
|
||||
}
|
||||
|
||||
// pos is the start index of the raw
|
||||
func ValidNumberFast(raw string) bool {
|
||||
ret := utils.SkipNumber(raw, 0)
|
||||
if ret < 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// check trainling chars
|
||||
for ret < len(raw) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func SkipOneFast2(json string, pos *int) (int, error) {
|
||||
// find the number ending, we pasred in sonic-cpp, it alway valid
|
||||
start := native.SkipOneFast(&json, pos)
|
||||
if start < 0 {
|
||||
return -1, error_syntax(*pos, json, types.ParsingError(-start).Error())
|
||||
}
|
||||
return start, nil
|
||||
}
|
||||
|
||||
func SkipOneFast(json string, pos int) (string, error) {
|
||||
// find the number ending, we pasred in sonic-cpp, it alway valid
|
||||
start := native.SkipOneFast(&json, &pos)
|
||||
if start < 0 {
|
||||
// TODO: details error code
|
||||
return "", error_syntax(pos, json, types.ParsingError(-start).Error())
|
||||
}
|
||||
return json[start:pos], nil
|
||||
}
|
||||
|
||||
func ParseI64(raw string) (int64, error) {
|
||||
i64, err := strconv.ParseInt(raw, 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return i64, nil
|
||||
}
|
||||
|
||||
func ParseBool(raw string) (bool, error) {
|
||||
var b bool
|
||||
err := json.Unmarshal([]byte(raw), &b)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func ParseU64(raw string) (uint64, error) {
|
||||
u64, err := strconv.ParseUint(raw, 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return u64, nil
|
||||
}
|
||||
|
||||
func ParseF64(raw string) (float64, error) {
|
||||
f64, err := strconv.ParseFloat(raw, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return f64, nil
|
||||
}
|
||||
|
||||
func Unquote(raw string) (string, error) {
|
||||
var u string
|
||||
err := json.Unmarshal([]byte(raw), &u)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return u, nil
|
||||
}
|
169
vendor/github.com/bytedance/sonic/internal/decoder/optdec/interface.go
generated
vendored
Normal file
169
vendor/github.com/bytedance/sonic/internal/decoder/optdec/interface.go
generated
vendored
Normal file
|
@ -0,0 +1,169 @@
|
|||
package optdec
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"unsafe"
|
||||
"reflect"
|
||||
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
)
|
||||
|
||||
type efaceDecoder struct {
|
||||
}
|
||||
|
||||
func (d *efaceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
*(*interface{})(vp) = interface{}(nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
eface := *(*rt.GoEface)(vp)
|
||||
|
||||
// not pointer type, or nil pointer, or *interface{}
|
||||
if eface.Value == nil || eface.Type.Kind() != reflect.Ptr || rt.PtrElem(eface.Type) == anyType {
|
||||
ret, err := node.AsEface(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*(*interface{})(vp) = ret
|
||||
return nil
|
||||
}
|
||||
|
||||
etp := rt.PtrElem(eface.Type)
|
||||
vp = eface.Value
|
||||
|
||||
/* check the defined pointer type for issue 379 */
|
||||
if eface.Type.IsNamed() {
|
||||
newp := vp
|
||||
etp = eface.Type
|
||||
vp = unsafe.Pointer(&newp)
|
||||
}
|
||||
|
||||
dec, err := findOrCompile(etp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return dec.FromDom(vp, node, ctx)
|
||||
}
|
||||
|
||||
type ifaceDecoder struct {
|
||||
typ *rt.GoType
|
||||
}
|
||||
|
||||
func (d *ifaceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
*(*unsafe.Pointer)(vp) = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
iface := *(*rt.GoIface)(vp)
|
||||
if iface.Itab == nil {
|
||||
return error_type(d.typ)
|
||||
}
|
||||
|
||||
vt := iface.Itab.Vt
|
||||
|
||||
// not pointer type, or nil pointer, or *interface{}
|
||||
if vp == nil || vt.Kind() != reflect.Ptr || rt.PtrElem(vt) == anyType {
|
||||
ret, err := node.AsEface(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*(*interface{})(vp) = ret
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
etp := rt.PtrElem(vt)
|
||||
vp = iface.Value
|
||||
|
||||
/* check the defined pointer type for issue 379 */
|
||||
if vt.IsNamed() {
|
||||
newp := vp
|
||||
etp = vt
|
||||
vp = unsafe.Pointer(&newp)
|
||||
}
|
||||
|
||||
dec, err := findOrCompile(etp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return dec.FromDom(vp, node, ctx)
|
||||
}
|
||||
|
||||
type unmarshalTextDecoder struct {
|
||||
typ *rt.GoType
|
||||
}
|
||||
|
||||
func (d *unmarshalTextDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
*(*unsafe.Pointer)(vp) = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
txt, ok := node.AsStringText(ctx)
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, d.typ.Pack())
|
||||
}
|
||||
|
||||
v := *(*interface{})(unsafe.Pointer(&rt.GoEface{
|
||||
Type: d.typ,
|
||||
Value: vp,
|
||||
}))
|
||||
|
||||
// fast path
|
||||
if u, ok := v.(encoding.TextUnmarshaler); ok {
|
||||
return u.UnmarshalText(txt)
|
||||
}
|
||||
|
||||
// slow path
|
||||
rv := reflect.ValueOf(v)
|
||||
if u, ok := rv.Interface().(encoding.TextUnmarshaler); ok {
|
||||
return u.UnmarshalText(txt)
|
||||
}
|
||||
|
||||
return error_type(d.typ)
|
||||
}
|
||||
|
||||
type unmarshalJSONDecoder struct {
|
||||
typ *rt.GoType
|
||||
strOpt bool
|
||||
}
|
||||
|
||||
func (d *unmarshalJSONDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
v := *(*interface{})(unsafe.Pointer(&rt.GoEface{
|
||||
Type: d.typ,
|
||||
Value: vp,
|
||||
}))
|
||||
|
||||
var input []byte
|
||||
if d.strOpt && node.IsNull() {
|
||||
input = []byte("null")
|
||||
} else if d.strOpt {
|
||||
s, ok := node.AsStringText(ctx)
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, d.typ.Pack())
|
||||
}
|
||||
input = s
|
||||
} else {
|
||||
input = []byte(node.AsRaw(ctx))
|
||||
}
|
||||
|
||||
// fast path
|
||||
if u, ok := v.(json.Unmarshaler); ok {
|
||||
return u.UnmarshalJSON((input))
|
||||
}
|
||||
|
||||
// slow path
|
||||
rv := reflect.ValueOf(v)
|
||||
if u, ok := rv.Interface().(json.Unmarshaler); ok {
|
||||
return u.UnmarshalJSON(input)
|
||||
}
|
||||
|
||||
return error_type(d.typ)
|
||||
}
|
430
vendor/github.com/bytedance/sonic/internal/decoder/optdec/map.go
generated
vendored
Normal file
430
vendor/github.com/bytedance/sonic/internal/decoder/optdec/map.go
generated
vendored
Normal file
|
@ -0,0 +1,430 @@
|
|||
package optdec
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"math"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
)
|
||||
|
||||
/** Decoder for most common map types: map[string]interface{}, map[string]string **/
|
||||
|
||||
type mapEfaceDecoder struct {
|
||||
}
|
||||
|
||||
func (d *mapEfaceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
*(*map[string]interface{})(vp) = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
return node.AsMapEface(ctx, vp)
|
||||
}
|
||||
|
||||
type mapStringDecoder struct {
|
||||
}
|
||||
|
||||
func (d *mapStringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
*(*map[string]string)(vp) = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
return node.AsMapString(ctx, vp)
|
||||
}
|
||||
|
||||
/** Decoder for map with string key **/
|
||||
|
||||
type mapStrKeyDecoder struct {
|
||||
mapType *rt.GoMapType
|
||||
elemDec decFunc
|
||||
assign rt.MapStrAssign
|
||||
typ reflect.Type
|
||||
}
|
||||
|
||||
func (d *mapStrKeyDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
*(*unsafe.Pointer)(vp) = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
obj, ok := node.AsObj()
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, d.mapType.Pack())
|
||||
}
|
||||
|
||||
// allocate map
|
||||
m := *(*unsafe.Pointer)(vp)
|
||||
if m == nil {
|
||||
m = rt.Makemap(&d.mapType.GoType, obj.Len())
|
||||
}
|
||||
|
||||
var gerr error
|
||||
next := obj.Children()
|
||||
for i := 0; i < obj.Len(); i++ {
|
||||
keyn := NewNode(next)
|
||||
key, _ := keyn.AsStr(ctx)
|
||||
|
||||
valn := NewNode(PtrOffset(next, 1))
|
||||
valp := d.assign(d.mapType, m, key)
|
||||
err := d.elemDec.FromDom(valp, valn, ctx)
|
||||
if gerr == nil && err != nil {
|
||||
gerr = err
|
||||
}
|
||||
next = valn.Next()
|
||||
}
|
||||
|
||||
*(*unsafe.Pointer)(vp) = m
|
||||
return gerr
|
||||
}
|
||||
|
||||
/** Decoder for map with int32 or int64 key **/
|
||||
|
||||
type mapI32KeyDecoder struct {
|
||||
mapType *rt.GoMapType
|
||||
elemDec decFunc
|
||||
assign rt.Map32Assign
|
||||
}
|
||||
|
||||
func (d *mapI32KeyDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
*(*unsafe.Pointer)(vp) = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
obj, ok := node.AsObj()
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, d.mapType.Pack())
|
||||
}
|
||||
|
||||
// allocate map
|
||||
m := *(*unsafe.Pointer)(vp)
|
||||
if m == nil {
|
||||
m = rt.Makemap(&d.mapType.GoType, obj.Len())
|
||||
}
|
||||
|
||||
next := obj.Children()
|
||||
var gerr error
|
||||
for i := 0; i < obj.Len(); i++ {
|
||||
keyn := NewNode(next)
|
||||
k, ok := keyn.ParseI64(ctx)
|
||||
if !ok || k > math.MaxInt32 || k < math.MinInt32 {
|
||||
if gerr == nil {
|
||||
gerr = error_mismatch(keyn, ctx, d.mapType.Pack())
|
||||
}
|
||||
valn := NewNode(PtrOffset(next, 1))
|
||||
next = valn.Next()
|
||||
continue
|
||||
}
|
||||
|
||||
key := int32(k)
|
||||
ku32 := *(*uint32)(unsafe.Pointer(&key))
|
||||
valn := NewNode(PtrOffset(next, 1))
|
||||
valp := d.assign(d.mapType, m, ku32)
|
||||
err := d.elemDec.FromDom(valp, valn, ctx)
|
||||
if gerr == nil && err != nil {
|
||||
gerr = err
|
||||
}
|
||||
|
||||
next = valn.Next()
|
||||
}
|
||||
|
||||
*(*unsafe.Pointer)(vp) = m
|
||||
return gerr
|
||||
}
|
||||
|
||||
type mapI64KeyDecoder struct {
|
||||
mapType *rt.GoMapType
|
||||
elemDec decFunc
|
||||
assign rt.Map64Assign
|
||||
}
|
||||
|
||||
func (d *mapI64KeyDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
*(*unsafe.Pointer)(vp) = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
obj, ok := node.AsObj()
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, d.mapType.Pack())
|
||||
}
|
||||
|
||||
// allocate map
|
||||
m := *(*unsafe.Pointer)(vp)
|
||||
if m == nil {
|
||||
m = rt.Makemap(&d.mapType.GoType, obj.Len())
|
||||
}
|
||||
|
||||
var gerr error
|
||||
next := obj.Children()
|
||||
for i := 0; i < obj.Len(); i++ {
|
||||
keyn := NewNode(next)
|
||||
key, ok := keyn.ParseI64(ctx)
|
||||
|
||||
if !ok {
|
||||
if gerr == nil {
|
||||
gerr = error_mismatch(keyn, ctx, d.mapType.Pack())
|
||||
}
|
||||
valn := NewNode(PtrOffset(next, 1))
|
||||
next = valn.Next()
|
||||
continue
|
||||
}
|
||||
|
||||
ku64 := *(*uint64)(unsafe.Pointer(&key))
|
||||
valn := NewNode(PtrOffset(next, 1))
|
||||
valp := d.assign(d.mapType, m, ku64)
|
||||
err := d.elemDec.FromDom(valp, valn, ctx)
|
||||
if gerr == nil && err != nil {
|
||||
gerr = err
|
||||
}
|
||||
next = valn.Next()
|
||||
}
|
||||
|
||||
*(*unsafe.Pointer)(vp) = m
|
||||
return gerr
|
||||
}
|
||||
|
||||
/** Decoder for map with unt32 or uint64 key **/
|
||||
|
||||
type mapU32KeyDecoder struct {
|
||||
mapType *rt.GoMapType
|
||||
elemDec decFunc
|
||||
assign rt.Map32Assign
|
||||
}
|
||||
|
||||
func (d *mapU32KeyDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
*(*unsafe.Pointer)(vp) = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
obj, ok := node.AsObj()
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, d.mapType.Pack())
|
||||
}
|
||||
|
||||
// allocate map
|
||||
m := *(*unsafe.Pointer)(vp)
|
||||
if m == nil {
|
||||
m = rt.Makemap(&d.mapType.GoType, obj.Len())
|
||||
}
|
||||
|
||||
var gerr error
|
||||
next := obj.Children()
|
||||
for i := 0; i < obj.Len(); i++ {
|
||||
keyn := NewNode(next)
|
||||
k, ok := keyn.ParseU64(ctx)
|
||||
if !ok || k > math.MaxUint32 {
|
||||
if gerr == nil {
|
||||
gerr = error_mismatch(keyn, ctx, d.mapType.Pack())
|
||||
}
|
||||
valn := NewNode(PtrOffset(next, 1))
|
||||
next = valn.Next()
|
||||
continue
|
||||
}
|
||||
|
||||
key := uint32(k)
|
||||
valn := NewNode(PtrOffset(next, 1))
|
||||
valp := d.assign(d.mapType, m, key)
|
||||
err := d.elemDec.FromDom(valp, valn, ctx)
|
||||
if gerr == nil && err != nil {
|
||||
gerr = err
|
||||
}
|
||||
next = valn.Next()
|
||||
}
|
||||
|
||||
*(*unsafe.Pointer)(vp) = m
|
||||
return gerr
|
||||
}
|
||||
|
||||
type mapU64KeyDecoder struct {
|
||||
mapType *rt.GoMapType
|
||||
elemDec decFunc
|
||||
assign rt.Map64Assign
|
||||
}
|
||||
|
||||
func (d *mapU64KeyDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
*(*unsafe.Pointer)(vp) = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
obj, ok := node.AsObj()
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, d.mapType.Pack())
|
||||
}
|
||||
// allocate map
|
||||
m := *(*unsafe.Pointer)(vp)
|
||||
if m == nil {
|
||||
m = rt.Makemap(&d.mapType.GoType, obj.Len())
|
||||
}
|
||||
|
||||
var gerr error
|
||||
next := obj.Children()
|
||||
for i := 0; i < obj.Len(); i++ {
|
||||
keyn := NewNode(next)
|
||||
key, ok := keyn.ParseU64(ctx)
|
||||
if !ok {
|
||||
if gerr == nil {
|
||||
gerr = error_mismatch(keyn, ctx, d.mapType.Pack())
|
||||
}
|
||||
valn := NewNode(PtrOffset(next, 1))
|
||||
next = valn.Next()
|
||||
continue
|
||||
}
|
||||
|
||||
valn := NewNode(PtrOffset(next, 1))
|
||||
valp := d.assign(d.mapType, m, key)
|
||||
err := d.elemDec.FromDom(valp, valn, ctx)
|
||||
if gerr == nil && err != nil {
|
||||
gerr = err
|
||||
}
|
||||
next = valn.Next()
|
||||
}
|
||||
|
||||
*(*unsafe.Pointer)(vp) = m
|
||||
return gerr
|
||||
}
|
||||
|
||||
/** Decoder for generic cases */
|
||||
|
||||
type decKey func(dec *mapDecoder, raw string, ctx *context) (interface{}, error)
|
||||
|
||||
func decodeKeyU8(dec *mapDecoder, raw string, ctx *context) (interface{}, error) {
|
||||
key, err := Unquote(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret, err := ParseU64(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ret > math.MaxUint8 {
|
||||
return nil, error_value(key, dec.mapType.Key.Pack())
|
||||
}
|
||||
return uint8(ret), nil
|
||||
}
|
||||
|
||||
func decodeKeyU16(dec *mapDecoder, raw string, ctx *context) (interface{}, error) {
|
||||
key, err := Unquote(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret, err := ParseU64(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ret > math.MaxUint16 {
|
||||
return nil, error_value(key, dec.mapType.Key.Pack())
|
||||
}
|
||||
return uint16(ret), nil
|
||||
}
|
||||
|
||||
func decodeKeyI8(dec *mapDecoder, raw string, ctx *context) (interface{}, error) {
|
||||
key, err := Unquote(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret, err := ParseI64(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ret > math.MaxInt8 || ret < math.MinInt8 {
|
||||
return nil, error_value(key, dec.mapType.Key.Pack())
|
||||
}
|
||||
return int8(ret), nil
|
||||
}
|
||||
|
||||
func decodeKeyI16(dec *mapDecoder, raw string, ctx *context) (interface{}, error) {
|
||||
key, err := Unquote(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret, err := ParseI64(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ret > math.MaxInt16 || ret < math.MinInt16 {
|
||||
return nil, error_value(key, dec.mapType.Key.Pack())
|
||||
}
|
||||
return int16(ret), nil
|
||||
}
|
||||
|
||||
func decodeKeyJSONUnmarshaler(dec *mapDecoder, raw string, _ *context) (interface{}, error) {
|
||||
ret := reflect.New(dec.mapType.Key.Pack()).Interface()
|
||||
err := ret.(json.Unmarshaler).UnmarshalJSON([]byte(raw))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func decodeKeyTextUnmarshaler(dec *mapDecoder, raw string, ctx *context) (interface{}, error) {
|
||||
key, err := Unquote(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := reflect.New(dec.mapType.Key.Pack()).Interface()
|
||||
err = ret.(encoding.TextUnmarshaler).UnmarshalText([]byte(key))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
type mapDecoder struct {
|
||||
mapType *rt.GoMapType
|
||||
keyDec decKey
|
||||
elemDec decFunc
|
||||
}
|
||||
|
||||
func (d *mapDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
*(*unsafe.Pointer)(vp) = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
obj, ok := node.AsObj()
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, d.mapType.Pack())
|
||||
}
|
||||
|
||||
// allocate map
|
||||
m := *(*unsafe.Pointer)(vp)
|
||||
if m == nil {
|
||||
m = rt.Makemap(&d.mapType.GoType, obj.Len())
|
||||
}
|
||||
|
||||
next := obj.Children()
|
||||
var gerr error
|
||||
for i := 0; i < obj.Len(); i++ {
|
||||
keyn := NewNode(next)
|
||||
raw := keyn.AsRaw(ctx)
|
||||
key, err := d.keyDec(d, raw, ctx)
|
||||
if err != nil {
|
||||
if gerr == nil {
|
||||
gerr = error_mismatch(keyn, ctx, d.mapType.Pack())
|
||||
}
|
||||
valn := NewNode(PtrOffset(next, 1))
|
||||
next = valn.Next()
|
||||
continue
|
||||
}
|
||||
|
||||
valn := NewNode(PtrOffset(next, 1))
|
||||
keyp := rt.UnpackEface(key).Value
|
||||
valp := rt.Mapassign(d.mapType, m, keyp)
|
||||
err = d.elemDec.FromDom(valp, valn, ctx)
|
||||
if gerr == nil && err != nil {
|
||||
gerr = err
|
||||
}
|
||||
|
||||
next = valn.Next()
|
||||
}
|
||||
|
||||
*(*unsafe.Pointer)(vp) = m
|
||||
return gerr
|
||||
}
|
269
vendor/github.com/bytedance/sonic/internal/decoder/optdec/native.go
generated
vendored
Normal file
269
vendor/github.com/bytedance/sonic/internal/decoder/optdec/native.go
generated
vendored
Normal file
|
@ -0,0 +1,269 @@
|
|||
package optdec
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
"sync"
|
||||
|
||||
"github.com/bytedance/sonic/internal/native"
|
||||
"github.com/bytedance/sonic/internal/native/types"
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
"github.com/bytedance/sonic/utf8"
|
||||
)
|
||||
|
||||
|
||||
type ErrorCode int
|
||||
|
||||
const (
|
||||
SONIC_OK = 0;
|
||||
SONIC_CONTROL_CHAR = 1;
|
||||
SONIC_INVALID_ESCAPED = 2;
|
||||
SONIC_INVALID_NUM = 3;
|
||||
SONIC_FLOAT_INF = 4;
|
||||
SONIC_EOF = 5;
|
||||
SONIC_INVALID_CHAR = 6;
|
||||
SONIC_EXPECT_KEY = 7;
|
||||
SONIC_EXPECT_COLON = 8;
|
||||
SONIC_EXPECT_OBJ_COMMA_OR_END = 9;
|
||||
SONIC_EXPECT_ARR_COMMA_OR_END = 10;
|
||||
SONIC_VISIT_FAILED = 11;
|
||||
SONIC_INVALID_ESCAPED_UTF = 12;
|
||||
SONIC_INVALID_LITERAL = 13;
|
||||
SONIC_STACK_OVERFLOW = 14;
|
||||
)
|
||||
|
||||
var ParsingErrors = []string{
|
||||
SONIC_OK : "ok",
|
||||
SONIC_CONTROL_CHAR : "control chars in string",
|
||||
SONIC_INVALID_ESCAPED : "invalid escaped chars in string",
|
||||
SONIC_INVALID_NUM : "invalid number",
|
||||
SONIC_FLOAT_INF : "float infinity",
|
||||
SONIC_EOF : "eof",
|
||||
SONIC_INVALID_CHAR : "invalid chars",
|
||||
SONIC_EXPECT_KEY : "expect a json key",
|
||||
SONIC_EXPECT_COLON : "expect a `:`",
|
||||
SONIC_EXPECT_OBJ_COMMA_OR_END : "expect a `,` or `}`",
|
||||
SONIC_EXPECT_ARR_COMMA_OR_END : "expect a `,` or `]`",
|
||||
SONIC_VISIT_FAILED : "failed in json visitor",
|
||||
SONIC_INVALID_ESCAPED_UTF : "invalid escaped unicodes",
|
||||
SONIC_INVALID_LITERAL : "invalid literal(true/false/null)",
|
||||
SONIC_STACK_OVERFLOW : "json is exceeded max depth 4096, cause stack overflow",
|
||||
}
|
||||
|
||||
func (code ErrorCode) Error() string {
|
||||
return ParsingErrors[code]
|
||||
}
|
||||
|
||||
type node struct {
|
||||
typ uint64
|
||||
val uint64
|
||||
}
|
||||
|
||||
// should consitent with native/parser.c
|
||||
type _nospaceBlock struct {
|
||||
_ [8]byte
|
||||
_ [8]byte
|
||||
}
|
||||
|
||||
// should consitent with native/parser.c
|
||||
type nodeBuf struct {
|
||||
ncur uintptr
|
||||
parent int64
|
||||
depth uint64
|
||||
nstart uintptr
|
||||
nend uintptr
|
||||
stat jsonStat
|
||||
}
|
||||
|
||||
func (self *nodeBuf) init(nodes []node) {
|
||||
self.ncur = uintptr(unsafe.Pointer(&nodes[0]))
|
||||
self.nstart = self.ncur
|
||||
self.nend = self.ncur + uintptr(cap(nodes)) * unsafe.Sizeof(node{})
|
||||
self.parent = -1
|
||||
}
|
||||
|
||||
// should consitent with native/parser.c
|
||||
type Parser struct {
|
||||
Json string
|
||||
padded []byte
|
||||
nodes []node
|
||||
dbuf []byte
|
||||
backup []node
|
||||
|
||||
options uint64
|
||||
// JSON cursor
|
||||
start uintptr
|
||||
cur uintptr
|
||||
end uintptr
|
||||
_nbk _nospaceBlock
|
||||
|
||||
// node buffer cursor
|
||||
nbuf nodeBuf
|
||||
Utf8Inv bool
|
||||
isEface bool
|
||||
}
|
||||
|
||||
// only when parse non-empty object/array are needed.
|
||||
type jsonStat struct {
|
||||
object uint32
|
||||
array uint32
|
||||
str uint32
|
||||
number uint32
|
||||
array_elems uint32
|
||||
object_keys uint32
|
||||
max_depth uint32
|
||||
}
|
||||
|
||||
|
||||
var (
|
||||
defaultJsonPaddedCap uintptr = 1 << 20 // 1 Mb
|
||||
defaultNodesCap uintptr = (1 << 20) / unsafe.Sizeof(node{}) // 1 Mb
|
||||
)
|
||||
|
||||
var parsePool sync.Pool = sync.Pool {
|
||||
New: func () interface{} {
|
||||
return &Parser{
|
||||
options: 0,
|
||||
padded: make([]byte, 0, defaultJsonPaddedCap),
|
||||
nodes: make([]node, defaultNodesCap, defaultNodesCap),
|
||||
dbuf: make([]byte, types.MaxDigitNums, types.MaxDigitNums),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var padding string = "x\"x\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
|
||||
func newParser(data string, pos int, opt uint64) *Parser {
|
||||
p := parsePool.Get().(*Parser)
|
||||
|
||||
/* validate json if needed */
|
||||
if (opt & (1 << _F_validate_string)) != 0 && !utf8.ValidateString(data){
|
||||
dbuf := utf8.CorrectWith(nil, rt.Str2Mem(data[pos:]), "\ufffd")
|
||||
dbuf = append(dbuf, padding...)
|
||||
p.Json = rt.Mem2Str(dbuf[:len(dbuf) - len(padding)])
|
||||
p.Utf8Inv = true
|
||||
p.start = uintptr((*rt.GoString)(unsafe.Pointer(&p.Json)).Ptr)
|
||||
} else {
|
||||
p.Json = data
|
||||
// TODO: prevent too large JSON
|
||||
p.padded = append(p.padded, data[pos:]...)
|
||||
p.padded = append(p.padded, padding...)
|
||||
p.start = uintptr((*rt.GoSlice)(unsafe.Pointer(&p.padded)).Ptr)
|
||||
}
|
||||
|
||||
p.cur = p.start
|
||||
p.end = p.cur + uintptr(len(p.Json))
|
||||
p.options = opt
|
||||
p.nbuf.init(p.nodes)
|
||||
return p
|
||||
}
|
||||
|
||||
|
||||
func (p *Parser) Pos() int {
|
||||
return int(p.cur - p.start)
|
||||
}
|
||||
|
||||
func (p *Parser) JsonBytes() []byte {
|
||||
if p.Utf8Inv {
|
||||
return (rt.Str2Mem(p.Json))
|
||||
} else {
|
||||
return p.padded
|
||||
}
|
||||
}
|
||||
|
||||
var nodeType = rt.UnpackType(reflect.TypeOf(node{}))
|
||||
|
||||
//go:inline
|
||||
func calMaxNodeCap(jsonSize int) int {
|
||||
return jsonSize / 2 + 2
|
||||
}
|
||||
|
||||
func (p *Parser) parse() ErrorCode {
|
||||
// when decode into struct, we should decode number as possible
|
||||
old := p.options
|
||||
if !p.isEface {
|
||||
p.options &^= 1 << _F_use_number
|
||||
}
|
||||
|
||||
// fast path with limited node buffer
|
||||
err := ErrorCode(native.ParseWithPadding(unsafe.Pointer(p)))
|
||||
if err != SONIC_VISIT_FAILED {
|
||||
p.options = old
|
||||
return err
|
||||
}
|
||||
|
||||
// check OoB here
|
||||
offset := p.nbuf.ncur - p.nbuf.nstart
|
||||
curLen := offset / unsafe.Sizeof(node{})
|
||||
if curLen != uintptr(len(p.nodes)) {
|
||||
panic(fmt.Sprintf("current len: %d, real len: %d cap: %d", curLen, len(p.nodes), cap(p.nodes)))
|
||||
}
|
||||
|
||||
// node buf is not enough, continue parse
|
||||
// the maxCap is always meet all valid JSON
|
||||
maxCap := calMaxNodeCap(len(p.Json))
|
||||
slice := rt.GoSlice{
|
||||
Ptr: rt.Mallocgc(uintptr(maxCap) * nodeType.Size, nodeType, false),
|
||||
Len: maxCap,
|
||||
Cap: maxCap,
|
||||
}
|
||||
rt.Memmove(unsafe.Pointer(slice.Ptr), unsafe.Pointer(&p.nodes[0]), offset)
|
||||
p.backup = p.nodes
|
||||
p.nodes = *(*[]node)(unsafe.Pointer(&slice))
|
||||
|
||||
// update node cursor
|
||||
p.nbuf.nstart = uintptr(unsafe.Pointer(&p.nodes[0]))
|
||||
p.nbuf.nend = p.nbuf.nstart + uintptr(cap(p.nodes)) * unsafe.Sizeof(node{})
|
||||
p.nbuf.ncur = p.nbuf.nstart + offset
|
||||
|
||||
// continue parse json
|
||||
err = ErrorCode(native.ParseWithPadding(unsafe.Pointer(p)))
|
||||
p.options = old
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *Parser) reset() {
|
||||
p.options = 0
|
||||
p.padded = p.padded[:0]
|
||||
// nodes is too large here, we will not reset it and use small backup nodes buffer
|
||||
if p.backup != nil {
|
||||
p.nodes = p.backup
|
||||
p.backup = nil
|
||||
}
|
||||
p.start = 0
|
||||
p.cur = 0
|
||||
p.end = 0
|
||||
p.Json = ""
|
||||
p.nbuf = nodeBuf{}
|
||||
p._nbk = _nospaceBlock{}
|
||||
p.Utf8Inv = false
|
||||
p.isEface = false
|
||||
}
|
||||
|
||||
func (p *Parser) free() {
|
||||
p.reset()
|
||||
parsePool.Put(p)
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func (p *Parser) fixError(code ErrorCode) error {
|
||||
if code == SONIC_OK {
|
||||
return nil
|
||||
}
|
||||
|
||||
if p.Pos() == 0 {
|
||||
code = SONIC_EOF;
|
||||
}
|
||||
|
||||
pos := p.Pos() - 1
|
||||
return error_syntax(pos, p.Json, ParsingErrors[code])
|
||||
}
|
||||
|
||||
func Parse(data string, opt uint64) error {
|
||||
p := newParser(data, 0, opt)
|
||||
err := p.parse()
|
||||
p.free()
|
||||
return err
|
||||
}
|
1278
vendor/github.com/bytedance/sonic/internal/decoder/optdec/node.go
generated
vendored
Normal file
1278
vendor/github.com/bytedance/sonic/internal/decoder/optdec/node.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
224
vendor/github.com/bytedance/sonic/internal/decoder/optdec/slice.go
generated
vendored
Normal file
224
vendor/github.com/bytedance/sonic/internal/decoder/optdec/slice.go
generated
vendored
Normal file
|
@ -0,0 +1,224 @@
|
|||
package optdec
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
)
|
||||
|
||||
type sliceDecoder struct {
|
||||
elemType *rt.GoType
|
||||
elemDec decFunc
|
||||
typ reflect.Type
|
||||
}
|
||||
|
||||
var (
|
||||
emptyPtr = &struct{}{}
|
||||
)
|
||||
|
||||
func (d *sliceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
*(*rt.GoSlice)(vp) = rt.GoSlice{}
|
||||
return nil
|
||||
}
|
||||
|
||||
arr, ok := node.AsArr()
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, d.typ)
|
||||
}
|
||||
|
||||
slice := rt.MakeSlice(vp, d.elemType, arr.Len())
|
||||
elems := slice.Ptr
|
||||
next := arr.Children()
|
||||
|
||||
var gerr error
|
||||
for i := 0; i < arr.Len(); i++ {
|
||||
val := NewNode(next)
|
||||
elem := unsafe.Pointer(uintptr(elems) + uintptr(i)*d.elemType.Size)
|
||||
err := d.elemDec.FromDom(elem, val, ctx)
|
||||
if gerr == nil && err != nil {
|
||||
gerr = err
|
||||
}
|
||||
next = val.Next()
|
||||
}
|
||||
|
||||
*(*rt.GoSlice)(vp) = *slice
|
||||
return gerr
|
||||
}
|
||||
|
||||
type arrayDecoder struct {
|
||||
len int
|
||||
elemType *rt.GoType
|
||||
elemDec decFunc
|
||||
typ reflect.Type
|
||||
}
|
||||
|
||||
//go:nocheckptr
|
||||
func (d *arrayDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
arr, ok := node.AsArr()
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, d.typ)
|
||||
}
|
||||
|
||||
next := arr.Children()
|
||||
i := 0
|
||||
|
||||
var gerr error
|
||||
for ; i < d.len && i < arr.Len(); i++ {
|
||||
elem := unsafe.Pointer(uintptr(vp) + uintptr(i)*d.elemType.Size)
|
||||
val := NewNode(next)
|
||||
err := d.elemDec.FromDom(elem, val, ctx)
|
||||
if gerr == nil && err != nil {
|
||||
gerr = err
|
||||
}
|
||||
next = val.Next()
|
||||
}
|
||||
|
||||
/* zero rest of array */
|
||||
ptr := unsafe.Pointer(uintptr(vp) + uintptr(i)*d.elemType.Size)
|
||||
n := uintptr(d.len-i) * d.elemType.Size
|
||||
rt.ClearMemory(d.elemType, ptr, n)
|
||||
return gerr
|
||||
}
|
||||
|
||||
type sliceEfaceDecoder struct {
|
||||
}
|
||||
|
||||
func (d *sliceEfaceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
*(*rt.GoSlice)(vp) = rt.GoSlice{}
|
||||
return nil
|
||||
}
|
||||
|
||||
return node.AsSliceEface(ctx, vp)
|
||||
}
|
||||
|
||||
type sliceI32Decoder struct {
|
||||
}
|
||||
|
||||
func (d *sliceI32Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
*(*rt.GoSlice)(vp) = rt.GoSlice{}
|
||||
return nil
|
||||
}
|
||||
|
||||
return node.AsSliceI32(ctx, vp)
|
||||
}
|
||||
|
||||
type sliceI64Decoder struct {
|
||||
}
|
||||
|
||||
func (d *sliceI64Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
*(*rt.GoSlice)(vp) = rt.GoSlice{}
|
||||
return nil
|
||||
}
|
||||
|
||||
return node.AsSliceI64(ctx, vp)
|
||||
}
|
||||
|
||||
type sliceU32Decoder struct {
|
||||
}
|
||||
|
||||
func (d *sliceU32Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
*(*rt.GoSlice)(vp) = rt.GoSlice{}
|
||||
return nil
|
||||
}
|
||||
|
||||
return node.AsSliceU32(ctx, vp)
|
||||
}
|
||||
|
||||
type sliceU64Decoder struct {
|
||||
}
|
||||
|
||||
func (d *sliceU64Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
*(*rt.GoSlice)(vp) = rt.GoSlice{}
|
||||
return nil
|
||||
}
|
||||
|
||||
return node.AsSliceU64(ctx, vp)
|
||||
}
|
||||
|
||||
type sliceStringDecoder struct {
|
||||
}
|
||||
|
||||
func (d *sliceStringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
*(*rt.GoSlice)(vp) = rt.GoSlice{}
|
||||
return nil
|
||||
}
|
||||
|
||||
return node.AsSliceString(ctx, vp)
|
||||
}
|
||||
|
||||
type sliceBytesDecoder struct {
|
||||
}
|
||||
|
||||
func (d *sliceBytesDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
*(*rt.GoSlice)(vp) = rt.GoSlice{}
|
||||
return nil
|
||||
}
|
||||
|
||||
s, err := node.AsSliceBytes(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*(*[]byte)(vp) = s
|
||||
return nil
|
||||
}
|
||||
|
||||
type sliceBytesUnmarshalerDecoder struct {
|
||||
elemType *rt.GoType
|
||||
elemDec decFunc
|
||||
typ reflect.Type
|
||||
}
|
||||
|
||||
func (d *sliceBytesUnmarshalerDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
*(*rt.GoSlice)(vp) = rt.GoSlice{}
|
||||
return nil
|
||||
}
|
||||
|
||||
/* parse JSON string into `[]byte` */
|
||||
if node.IsStr() {
|
||||
slice, err := node.AsSliceBytes(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*(*[]byte)(vp) = slice
|
||||
return nil
|
||||
}
|
||||
|
||||
/* parse JSON array into `[]byte` */
|
||||
arr, ok := node.AsArr()
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, d.typ)
|
||||
}
|
||||
|
||||
slice := rt.MakeSlice(vp, d.elemType, arr.Len())
|
||||
elems := slice.Ptr
|
||||
|
||||
var gerr error
|
||||
next := arr.Children()
|
||||
for i := 0; i < arr.Len(); i++ {
|
||||
child := NewNode(next)
|
||||
elem := unsafe.Pointer(uintptr(elems) + uintptr(i)*d.elemType.Size)
|
||||
err := d.elemDec.FromDom(elem, child, ctx)
|
||||
if gerr == nil && err != nil {
|
||||
gerr = err
|
||||
}
|
||||
next = child.Next()
|
||||
}
|
||||
|
||||
*(*rt.GoSlice)(vp) = *slice
|
||||
return gerr
|
||||
}
|
360
vendor/github.com/bytedance/sonic/internal/decoder/optdec/stringopts.go
generated
vendored
Normal file
360
vendor/github.com/bytedance/sonic/internal/decoder/optdec/stringopts.go
generated
vendored
Normal file
|
@ -0,0 +1,360 @@
|
|||
package optdec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
"unsafe"
|
||||
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
)
|
||||
|
||||
type ptrStrDecoder struct {
|
||||
typ *rt.GoType
|
||||
deref decFunc
|
||||
}
|
||||
|
||||
// Pointer Value is allocated in the Caller
|
||||
func (d *ptrStrDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
*(*unsafe.Pointer)(vp) = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
s, ok := node.AsStrRef(ctx)
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, stringType)
|
||||
}
|
||||
|
||||
if s == "null" {
|
||||
*(*unsafe.Pointer)(vp) = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
if *(*unsafe.Pointer)(vp) == nil {
|
||||
*(*unsafe.Pointer)(vp) = rt.Mallocgc(d.typ.Size, d.typ, true)
|
||||
}
|
||||
|
||||
return d.deref.FromDom(*(*unsafe.Pointer)(vp), node, ctx)
|
||||
}
|
||||
|
||||
type boolStringDecoder struct {
|
||||
}
|
||||
|
||||
func (d *boolStringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
s, ok := node.AsStrRef(ctx)
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, stringType)
|
||||
}
|
||||
|
||||
if s == "null" {
|
||||
return nil
|
||||
}
|
||||
|
||||
b, err := ParseBool(s)
|
||||
if err != nil {
|
||||
return error_mismatch(node, ctx, boolType)
|
||||
}
|
||||
|
||||
*(*bool)(vp) = b
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseI64(node Node, ctx *context) (int64, error, bool) {
|
||||
if node.IsNull() {
|
||||
return 0, nil, true
|
||||
}
|
||||
|
||||
s, ok := node.AsStrRef(ctx)
|
||||
if !ok {
|
||||
return 0, error_mismatch(node, ctx, stringType), false
|
||||
}
|
||||
|
||||
if s == "null" {
|
||||
return 0, nil, true
|
||||
}
|
||||
|
||||
ret, err := ParseI64(s)
|
||||
return ret, err, false
|
||||
}
|
||||
|
||||
type i8StringDecoder struct{}
|
||||
|
||||
func (d *i8StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
ret, err, null := parseI64(node, ctx)
|
||||
if null {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ret > math.MaxInt8 || ret < math.MinInt8 {
|
||||
return error_mismatch(node, ctx, int8Type)
|
||||
}
|
||||
|
||||
*(*int8)(vp) = int8(ret)
|
||||
return nil
|
||||
}
|
||||
|
||||
type i16StringDecoder struct{}
|
||||
|
||||
func (d *i16StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
ret, err, null := parseI64(node, ctx)
|
||||
if null {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ret > math.MaxInt16 || ret < math.MinInt16 {
|
||||
return error_mismatch(node, ctx, int16Type)
|
||||
}
|
||||
|
||||
*(*int16)(vp) = int16(ret)
|
||||
return nil
|
||||
}
|
||||
|
||||
type i32StringDecoder struct{}
|
||||
|
||||
func (d *i32StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
ret, err, null := parseI64(node, ctx)
|
||||
if null {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ret > math.MaxInt32 || ret < math.MinInt32 {
|
||||
return error_mismatch(node, ctx, int32Type)
|
||||
}
|
||||
|
||||
*(*int32)(vp) = int32(ret)
|
||||
return nil
|
||||
}
|
||||
|
||||
type i64StringDecoder struct{}
|
||||
|
||||
func (d *i64StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
ret, err, null := parseI64(node, ctx)
|
||||
if null {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*(*int64)(vp) = int64(ret)
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseU64(node Node, ctx *context) (uint64, error, bool) {
|
||||
if node.IsNull() {
|
||||
return 0, nil, true
|
||||
}
|
||||
|
||||
s, ok := node.AsStrRef(ctx)
|
||||
if !ok {
|
||||
return 0, error_mismatch(node, ctx, stringType), false
|
||||
}
|
||||
|
||||
if s == "null" {
|
||||
return 0, nil, true
|
||||
}
|
||||
|
||||
ret, err := ParseU64(s)
|
||||
return ret, err, false
|
||||
}
|
||||
|
||||
type u8StringDecoder struct{}
|
||||
|
||||
func (d *u8StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
ret, err, null := parseU64(node, ctx)
|
||||
if null {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ret > math.MaxUint8 {
|
||||
return error_mismatch(node, ctx, uint8Type)
|
||||
}
|
||||
|
||||
*(*uint8)(vp) = uint8(ret)
|
||||
return nil
|
||||
}
|
||||
|
||||
type u16StringDecoder struct{}
|
||||
|
||||
func (d *u16StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
ret, err, null := parseU64(node, ctx)
|
||||
if null {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ret > math.MaxUint16 {
|
||||
return error_mismatch(node, ctx, uint16Type)
|
||||
}
|
||||
|
||||
*(*uint16)(vp) = uint16(ret)
|
||||
return nil
|
||||
}
|
||||
|
||||
type u32StringDecoder struct{}
|
||||
|
||||
func (d *u32StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
ret, err, null := parseU64(node, ctx)
|
||||
if null {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ret > math.MaxUint32 {
|
||||
return error_mismatch(node, ctx, uint32Type)
|
||||
}
|
||||
|
||||
*(*uint32)(vp) = uint32(ret)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
type u64StringDecoder struct{}
|
||||
|
||||
func (d *u64StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
ret, err, null := parseU64(node, ctx)
|
||||
if null {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*(*uint64)(vp) = uint64(ret)
|
||||
return nil
|
||||
}
|
||||
|
||||
type f32StringDecoder struct{}
|
||||
|
||||
func (d *f32StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
s, ok := node.AsStrRef(ctx)
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, stringType)
|
||||
}
|
||||
|
||||
if s == "null" {
|
||||
return nil
|
||||
}
|
||||
|
||||
ret, err := ParseF64(s)
|
||||
if err != nil || ret > math.MaxFloat32 || ret < -math.MaxFloat32 {
|
||||
return error_mismatch(node, ctx, float32Type)
|
||||
}
|
||||
|
||||
*(*float32)(vp) = float32(ret)
|
||||
return nil
|
||||
}
|
||||
|
||||
type f64StringDecoder struct{}
|
||||
|
||||
func (d *f64StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
s, ok := node.AsStrRef(ctx)
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, stringType)
|
||||
}
|
||||
|
||||
if s == "null" {
|
||||
return nil
|
||||
}
|
||||
|
||||
ret, err := ParseF64(s)
|
||||
if err != nil {
|
||||
return error_mismatch(node, ctx, float64Type)
|
||||
}
|
||||
|
||||
*(*float64)(vp) = float64(ret)
|
||||
return nil
|
||||
}
|
||||
|
||||
/* parse string field with string options */
|
||||
type strStringDecoder struct{}
|
||||
|
||||
func (d *strStringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
s, ok := node.AsStrRef(ctx)
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, stringType)
|
||||
}
|
||||
|
||||
if s == "null" {
|
||||
return nil
|
||||
}
|
||||
|
||||
s, err := Unquote(s)
|
||||
if err != nil {
|
||||
return error_mismatch(node, ctx, stringType)
|
||||
}
|
||||
|
||||
*(*string)(vp) = s
|
||||
return nil
|
||||
}
|
||||
|
||||
type numberStringDecoder struct{}
|
||||
|
||||
func (d *numberStringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
s, ok := node.AsStrRef(ctx)
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, stringType)
|
||||
}
|
||||
|
||||
if s == "null" {
|
||||
return nil
|
||||
}
|
||||
|
||||
num, ok := node.ParseNumber(ctx)
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, jsonNumberType)
|
||||
}
|
||||
|
||||
end, ok := SkipNumberFast(s, 0)
|
||||
// has error or trailing chars
|
||||
if !ok || end != len(s) {
|
||||
return error_mismatch(node, ctx, jsonNumberType)
|
||||
}
|
||||
|
||||
*(*json.Number)(vp) = json.Number(num)
|
||||
return nil
|
||||
}
|
61
vendor/github.com/bytedance/sonic/internal/decoder/optdec/structs.go
generated
vendored
Normal file
61
vendor/github.com/bytedance/sonic/internal/decoder/optdec/structs.go
generated
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
package optdec
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
caching "github.com/bytedance/sonic/internal/optcaching"
|
||||
"github.com/bytedance/sonic/internal/resolver"
|
||||
)
|
||||
|
||||
type fieldEntry struct {
|
||||
resolver.FieldMeta
|
||||
fieldDec decFunc
|
||||
}
|
||||
|
||||
type structDecoder struct {
|
||||
fieldMap caching.FieldLookup
|
||||
fields []fieldEntry
|
||||
structName string
|
||||
typ reflect.Type
|
||||
}
|
||||
|
||||
func (d *structDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
|
||||
if node.IsNull() {
|
||||
return nil
|
||||
}
|
||||
|
||||
var gerr error
|
||||
obj, ok := node.AsObj()
|
||||
if !ok {
|
||||
return error_mismatch(node, ctx, d.typ)
|
||||
}
|
||||
|
||||
next := obj.Children()
|
||||
for i := 0; i < obj.Len(); i++ {
|
||||
key, _ := NewNode(next).AsStrRef(ctx)
|
||||
val := NewNode(PtrOffset(next, 1))
|
||||
next = val.Next()
|
||||
|
||||
// find field idx
|
||||
idx := d.fieldMap.Get(key)
|
||||
if idx == -1 {
|
||||
if Options(ctx.Options())&OptionDisableUnknown != 0 {
|
||||
return error_field(key)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
offset := d.fields[idx].Path[0].Size
|
||||
elem := unsafe.Pointer(uintptr(vp) + offset)
|
||||
err := d.fields[idx].fieldDec.FromDom(elem, val, ctx)
|
||||
|
||||
// deal with mismatch type errors
|
||||
if gerr == nil && err != nil {
|
||||
// TODO: better error info
|
||||
gerr = err
|
||||
}
|
||||
}
|
||||
return gerr
|
||||
}
|
||||
|
60
vendor/github.com/bytedance/sonic/internal/decoder/optdec/types.go
generated
vendored
Normal file
60
vendor/github.com/bytedance/sonic/internal/decoder/optdec/types.go
generated
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package optdec
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
)
|
||||
|
||||
var (
|
||||
boolType = reflect.TypeOf(bool(false))
|
||||
byteType = reflect.TypeOf(byte(0))
|
||||
intType = reflect.TypeOf(int(0))
|
||||
int8Type = reflect.TypeOf(int8(0))
|
||||
int16Type = reflect.TypeOf(int16(0))
|
||||
int32Type = reflect.TypeOf(int32(0))
|
||||
int64Type = reflect.TypeOf(int64(0))
|
||||
uintType = reflect.TypeOf(uint(0))
|
||||
uint8Type = reflect.TypeOf(uint8(0))
|
||||
uint16Type = reflect.TypeOf(uint16(0))
|
||||
uint32Type = reflect.TypeOf(uint32(0))
|
||||
uint64Type = reflect.TypeOf(uint64(0))
|
||||
float32Type = reflect.TypeOf(float32(0))
|
||||
float64Type = reflect.TypeOf(float64(0))
|
||||
stringType = reflect.TypeOf("")
|
||||
bytesType = reflect.TypeOf([]byte(nil))
|
||||
jsonNumberType = reflect.TypeOf(json.Number(""))
|
||||
base64CorruptInputError = reflect.TypeOf(base64.CorruptInputError(0))
|
||||
anyType = rt.UnpackType(reflect.TypeOf((*interface{})(nil)).Elem())
|
||||
)
|
||||
|
||||
var (
|
||||
errorType = reflect.TypeOf((*error)(nil)).Elem()
|
||||
jsonUnmarshalerType = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem()
|
||||
encodingTextUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
|
||||
)
|
||||
|
||||
func rtype(t reflect.Type) (*rt.GoItab, *rt.GoType) {
|
||||
p := (*rt.GoIface)(unsafe.Pointer(&t))
|
||||
return p.Itab, (*rt.GoType)(p.Value)
|
||||
}
|
|
@ -14,15 +14,16 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package encoder
|
||||
package alg
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"github.com/bytedance/sonic/internal/native"
|
||||
"github.com/bytedance/sonic/internal/encoder/vars"
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
)
|
||||
|
||||
|
@ -32,8 +33,8 @@ type _MapPair struct {
|
|||
m [32]byte
|
||||
}
|
||||
|
||||
type _MapIterator struct {
|
||||
it rt.GoMapIterator // must be the first field
|
||||
type MapIterator struct {
|
||||
It rt.GoMapIterator // must be the first field
|
||||
kv rt.GoSlice // slice of _MapPair
|
||||
ki int
|
||||
}
|
||||
|
@ -44,43 +45,43 @@ type _MapIterator struct {
|
|||
)
|
||||
|
||||
func init() {
|
||||
if unsafe.Offsetof(_MapIterator{}.it) != 0 {
|
||||
if unsafe.Offsetof(MapIterator{}.It) != 0 {
|
||||
panic("_MapIterator.it is not the first field")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func newIterator() *_MapIterator {
|
||||
func newIterator() *MapIterator {
|
||||
if v := iteratorPool.Get(); v == nil {
|
||||
return new(_MapIterator)
|
||||
return new(MapIterator)
|
||||
} else {
|
||||
return resetIterator(v.(*_MapIterator))
|
||||
return resetIterator(v.(*MapIterator))
|
||||
}
|
||||
}
|
||||
|
||||
func resetIterator(p *_MapIterator) *_MapIterator {
|
||||
func resetIterator(p *MapIterator) *MapIterator {
|
||||
p.ki = 0
|
||||
p.it = rt.GoMapIterator{}
|
||||
p.It = rt.GoMapIterator{}
|
||||
p.kv.Len = 0
|
||||
return p
|
||||
}
|
||||
|
||||
func (self *_MapIterator) at(i int) *_MapPair {
|
||||
func (self *MapIterator) at(i int) *_MapPair {
|
||||
return (*_MapPair)(unsafe.Pointer(uintptr(self.kv.Ptr) + uintptr(i) * unsafe.Sizeof(_MapPair{})))
|
||||
}
|
||||
|
||||
func (self *_MapIterator) add() (p *_MapPair) {
|
||||
func (self *MapIterator) add() (p *_MapPair) {
|
||||
p = self.at(self.kv.Len)
|
||||
self.kv.Len++
|
||||
return
|
||||
}
|
||||
|
||||
func (self *_MapIterator) data() (p []_MapPair) {
|
||||
func (self *MapIterator) data() (p []_MapPair) {
|
||||
*(*rt.GoSlice)(unsafe.Pointer(&p)) = self.kv
|
||||
return
|
||||
}
|
||||
|
||||
func (self *_MapIterator) append(t *rt.GoType, k unsafe.Pointer, v unsafe.Pointer) (err error) {
|
||||
func (self *MapIterator) append(t *rt.GoType, k unsafe.Pointer, v unsafe.Pointer) (err error) {
|
||||
p := self.add()
|
||||
p.v = v
|
||||
|
||||
|
@ -94,26 +95,26 @@ func (self *_MapIterator) append(t *rt.GoType, k unsafe.Pointer, v unsafe.Pointe
|
|||
return nil
|
||||
}
|
||||
|
||||
func (self *_MapIterator) appendGeneric(p *_MapPair, t *rt.GoType, v reflect.Kind, k unsafe.Pointer) error {
|
||||
func (self *MapIterator) appendGeneric(p *_MapPair, t *rt.GoType, v reflect.Kind, k unsafe.Pointer) error {
|
||||
switch v {
|
||||
case reflect.Int : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], int64(*(*int)(k)))]) ; return nil
|
||||
case reflect.Int8 : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], int64(*(*int8)(k)))]) ; return nil
|
||||
case reflect.Int16 : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], int64(*(*int16)(k)))]) ; return nil
|
||||
case reflect.Int32 : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], int64(*(*int32)(k)))]) ; return nil
|
||||
case reflect.Int64 : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], *(*int64)(k))]) ; return nil
|
||||
case reflect.Uint : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uint)(k)))]) ; return nil
|
||||
case reflect.Uint8 : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uint8)(k)))]) ; return nil
|
||||
case reflect.Uint16 : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uint16)(k)))]) ; return nil
|
||||
case reflect.Uint32 : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uint32)(k)))]) ; return nil
|
||||
case reflect.Uint64 : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], *(*uint64)(k))]) ; return nil
|
||||
case reflect.Uintptr : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uintptr)(k)))]) ; return nil
|
||||
case reflect.Int : p.k = rt.Mem2Str(strconv.AppendInt(p.m[:0], int64(*(*int)(k)), 10)) ; return nil
|
||||
case reflect.Int8 : p.k = rt.Mem2Str(strconv.AppendInt(p.m[:0], int64(*(*int8)(k)), 10)) ; return nil
|
||||
case reflect.Int16 : p.k = rt.Mem2Str(strconv.AppendInt(p.m[:0], int64(*(*int16)(k)), 10)) ; return nil
|
||||
case reflect.Int32 : p.k = rt.Mem2Str(strconv.AppendInt(p.m[:0], int64(*(*int32)(k)), 10)) ; return nil
|
||||
case reflect.Int64 : p.k = rt.Mem2Str(strconv.AppendInt(p.m[:0], int64(*(*int64)(k)), 10)) ; return nil
|
||||
case reflect.Uint : p.k = rt.Mem2Str(strconv.AppendUint(p.m[:0], uint64(*(*uint)(k)), 10)) ; return nil
|
||||
case reflect.Uint8 : p.k = rt.Mem2Str(strconv.AppendUint(p.m[:0], uint64(*(*uint8)(k)), 10)) ; return nil
|
||||
case reflect.Uint16 : p.k = rt.Mem2Str(strconv.AppendUint(p.m[:0], uint64(*(*uint16)(k)), 10)) ; return nil
|
||||
case reflect.Uint32 : p.k = rt.Mem2Str(strconv.AppendUint(p.m[:0], uint64(*(*uint32)(k)), 10)) ; return nil
|
||||
case reflect.Uint64 : p.k = rt.Mem2Str(strconv.AppendUint(p.m[:0], uint64(*(*uint64)(k)), 10)) ; return nil
|
||||
case reflect.Uintptr : p.k = rt.Mem2Str(strconv.AppendUint(p.m[:0], uint64(*(*uintptr)(k)), 10)) ; return nil
|
||||
case reflect.Interface : return self.appendInterface(p, t, k)
|
||||
case reflect.Struct, reflect.Ptr : return self.appendConcrete(p, t, k)
|
||||
default : panic("unexpected map key type")
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_MapIterator) appendConcrete(p *_MapPair, t *rt.GoType, k unsafe.Pointer) (err error) {
|
||||
func (self *MapIterator) appendConcrete(p *_MapPair, t *rt.GoType, k unsafe.Pointer) (err error) {
|
||||
// compiler has already checked that the type implements the encoding.MarshalText interface
|
||||
if !t.Indirect() {
|
||||
k = *(*unsafe.Pointer)(k)
|
||||
|
@ -127,7 +128,7 @@ func (self *_MapIterator) appendConcrete(p *_MapPair, t *rt.GoType, k unsafe.Poi
|
|||
return
|
||||
}
|
||||
|
||||
func (self *_MapIterator) appendInterface(p *_MapPair, t *rt.GoType, k unsafe.Pointer) (err error) {
|
||||
func (self *MapIterator) appendInterface(p *_MapPair, t *rt.GoType, k unsafe.Pointer) (err error) {
|
||||
if len(rt.IfaceType(t).Methods) == 0 {
|
||||
panic("unexpected map key type")
|
||||
} else if p.k, err = asText(k); err == nil {
|
||||
|
@ -137,17 +138,17 @@ func (self *_MapIterator) appendInterface(p *_MapPair, t *rt.GoType, k unsafe.Po
|
|||
}
|
||||
}
|
||||
|
||||
func iteratorStop(p *_MapIterator) {
|
||||
func IteratorStop(p *MapIterator) {
|
||||
iteratorPool.Put(p)
|
||||
}
|
||||
|
||||
func iteratorNext(p *_MapIterator) {
|
||||
func IteratorNext(p *MapIterator) {
|
||||
i := p.ki
|
||||
t := &p.it
|
||||
t := &p.It
|
||||
|
||||
/* check for unordered iteration */
|
||||
if i < 0 {
|
||||
mapiternext(t)
|
||||
rt.Mapiternext(t)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -164,25 +165,25 @@ func iteratorNext(p *_MapIterator) {
|
|||
p.ki++
|
||||
}
|
||||
|
||||
func iteratorStart(t *rt.GoMapType, m *rt.GoMap, fv uint64) (*_MapIterator, error) {
|
||||
func IteratorStart(t *rt.GoMapType, m *rt.GoMap, fv uint64) (*MapIterator, error) {
|
||||
it := newIterator()
|
||||
mapiterinit(t, m, &it.it)
|
||||
rt.Mapiterinit(t, m, &it.It)
|
||||
|
||||
/* check for key-sorting, empty map don't need sorting */
|
||||
if m.Count == 0 || (fv & uint64(SortMapKeys)) == 0 {
|
||||
if m.Count == 0 || (fv & (1<<BitSortMapKeys)) == 0 {
|
||||
it.ki = -1
|
||||
return it, nil
|
||||
}
|
||||
|
||||
/* pre-allocate space if needed */
|
||||
if m.Count > it.kv.Cap {
|
||||
it.kv = growslice(iteratorPair, it.kv, m.Count)
|
||||
it.kv = rt.GrowSlice(iteratorPair, it.kv, m.Count)
|
||||
}
|
||||
|
||||
/* dump all the key-value pairs */
|
||||
for ; it.it.K != nil; mapiternext(&it.it) {
|
||||
if err := it.append(t.Key, it.it.K, it.it.V); err != nil {
|
||||
iteratorStop(it)
|
||||
for ; it.It.K != nil; rt.Mapiternext(&it.It) {
|
||||
if err := it.append(t.Key, it.It.K, it.It.V); err != nil {
|
||||
IteratorStop(it)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
@ -193,7 +194,13 @@ func iteratorStart(t *rt.GoMapType, m *rt.GoMap, fv uint64) (*_MapIterator, erro
|
|||
}
|
||||
|
||||
/* load the first pair into iterator */
|
||||
it.it.V = it.at(0).v
|
||||
it.it.K = unsafe.Pointer(&it.at(0).k)
|
||||
it.It.V = it.at(0).v
|
||||
it.It.K = unsafe.Pointer(&it.at(0).k)
|
||||
return it, nil
|
||||
}
|
||||
|
||||
func asText(v unsafe.Pointer) (string, error) {
|
||||
text := rt.AssertI2I(rt.UnpackType(vars.EncodingTextMarshalerType), *(*rt.GoIface)(v))
|
||||
r, e := (*(*encoding.TextMarshaler)(unsafe.Pointer(&text))).MarshalText()
|
||||
return rt.Mem2Str(r), e
|
||||
}
|
31
vendor/github.com/bytedance/sonic/internal/encoder/alg/opts.go
generated
vendored
Normal file
31
vendor/github.com/bytedance/sonic/internal/encoder/alg/opts.go
generated
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* Copyright 2024 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package alg
|
||||
|
||||
const (
|
||||
BitSortMapKeys = iota
|
||||
BitEscapeHTML
|
||||
BitCompactMarshaler
|
||||
BitNoQuoteTextMarshaler
|
||||
BitNoNullSliceOrMap
|
||||
BitValidateString
|
||||
BitNoValidateJSONMarshaler
|
||||
BitNoEncoderNewline
|
||||
BitEncodeNullForInfOrNan
|
||||
|
||||
BitPointerValue = 63
|
||||
)
|
95
vendor/github.com/bytedance/sonic/internal/encoder/alg/primitives.go
generated
vendored
Normal file
95
vendor/github.com/bytedance/sonic/internal/encoder/alg/primitives.go
generated
vendored
Normal file
|
@ -0,0 +1,95 @@
|
|||
/**
|
||||
* Copyright 2024 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package alg
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/bytedance/sonic/internal/encoder/vars"
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
)
|
||||
|
||||
func Compact(p *[]byte, v []byte) error {
|
||||
buf := vars.NewBuffer()
|
||||
err := json.Compact(buf, v)
|
||||
|
||||
/* check for errors */
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
/* add to result */
|
||||
v = buf.Bytes()
|
||||
*p = append(*p, v...)
|
||||
|
||||
/* return the buffer into pool */
|
||||
vars.FreeBuffer(buf)
|
||||
return nil
|
||||
}
|
||||
|
||||
func EncodeNil(rb *[]byte) error {
|
||||
*rb = append(*rb, 'n', 'u', 'l', 'l')
|
||||
return nil
|
||||
}
|
||||
|
||||
// func Make_EncodeTypedPointer(computor func(*rt.GoType, ...interface{}) (interface{}, error)) func(*[]byte, *rt.GoType, *unsafe.Pointer, *vars.Stack, uint64) error {
|
||||
// return func(buf *[]byte, vt *rt.GoType, vp *unsafe.Pointer, sb *vars.Stack, fv uint64) error {
|
||||
// if vt == nil {
|
||||
// return EncodeNil(buf)
|
||||
// } else if fn, err := vars.FindOrCompile(vt, (fv&(1<<BitPointerValue)) != 0, computor); err != nil {
|
||||
// return err
|
||||
// } else if vt.Indirect() {
|
||||
// err := fn(buf, *vp, sb, fv)
|
||||
// return err
|
||||
// } else {
|
||||
// err := fn(buf, unsafe.Pointer(vp), sb, fv)
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
func EncodeJsonMarshaler(buf *[]byte, val json.Marshaler, opt uint64) error {
|
||||
if ret, err := val.MarshalJSON(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
if opt&(1<<BitCompactMarshaler) != 0 {
|
||||
return Compact(buf, ret)
|
||||
}
|
||||
if opt&(1<<BitNoValidateJSONMarshaler) == 0 {
|
||||
if ok, s := Valid(ret); !ok {
|
||||
return vars.Error_marshaler(ret, s)
|
||||
}
|
||||
}
|
||||
*buf = append(*buf, ret...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func EncodeTextMarshaler(buf *[]byte, val encoding.TextMarshaler, opt uint64) error {
|
||||
if ret, err := val.MarshalText(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
if opt&(1<<BitNoQuoteTextMarshaler) != 0 {
|
||||
*buf = append(*buf, ret...)
|
||||
return nil
|
||||
}
|
||||
*buf = Quote(*buf, rt.Mem2Str(ret), false)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package encoder
|
||||
package alg
|
||||
|
||||
// Algorithm 3-way Radix Quicksort, d means the radix.
|
||||
// Reference: https://algs4.cs.princeton.edu/51radix/Quick3string.java.html
|
198
vendor/github.com/bytedance/sonic/internal/encoder/alg/spec.go
generated
vendored
Normal file
198
vendor/github.com/bytedance/sonic/internal/encoder/alg/spec.go
generated
vendored
Normal file
|
@ -0,0 +1,198 @@
|
|||
//go:build (amd64 && go1.16 && !go1.24) || (arm64 && go1.20 && !go1.24)
|
||||
// +build amd64,go1.16,!go1.24 arm64,go1.20,!go1.24
|
||||
|
||||
/**
|
||||
* Copyright 2024 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package alg
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
"github.com/bytedance/sonic/internal/native"
|
||||
"github.com/bytedance/sonic/internal/native/types"
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
)
|
||||
|
||||
// Valid validates json and returns first non-blank character position,
|
||||
// if it is only one valid json value.
|
||||
// Otherwise returns invalid character position using start.
|
||||
//
|
||||
// Note: it does not check for the invalid UTF-8 characters.
|
||||
func Valid(data []byte) (ok bool, start int) {
|
||||
n := len(data)
|
||||
if n == 0 {
|
||||
return false, -1
|
||||
}
|
||||
s := rt.Mem2Str(data)
|
||||
p := 0
|
||||
m := types.NewStateMachine()
|
||||
ret := native.ValidateOne(&s, &p, m, 0)
|
||||
types.FreeStateMachine(m)
|
||||
|
||||
if ret < 0 {
|
||||
return false, p-1
|
||||
}
|
||||
|
||||
/* check for trailing spaces */
|
||||
for ;p < n; p++ {
|
||||
if (types.SPACE_MASK & (1 << data[p])) == 0 {
|
||||
return false, p
|
||||
}
|
||||
}
|
||||
|
||||
return true, ret
|
||||
}
|
||||
|
||||
var typeByte = rt.UnpackEface(byte(0)).Type
|
||||
|
||||
//go:nocheckptr
|
||||
func Quote(buf []byte, val string, double bool) []byte {
|
||||
if len(val) == 0 {
|
||||
if double {
|
||||
return append(buf, `"\"\""`...)
|
||||
}
|
||||
return append(buf, `""`...)
|
||||
}
|
||||
|
||||
if double {
|
||||
buf = append(buf, `"\"`...)
|
||||
} else {
|
||||
buf = append(buf, `"`...)
|
||||
}
|
||||
sp := rt.IndexChar(val, 0)
|
||||
nb := len(val)
|
||||
b := (*rt.GoSlice)(unsafe.Pointer(&buf))
|
||||
|
||||
// input buffer
|
||||
for nb > 0 {
|
||||
// output buffer
|
||||
dp := unsafe.Pointer(uintptr(b.Ptr) + uintptr(b.Len))
|
||||
dn := b.Cap - b.Len
|
||||
// call native.Quote, dn is byte count it outputs
|
||||
opts := uint64(0)
|
||||
if double {
|
||||
opts = types.F_DOUBLE_UNQUOTE
|
||||
}
|
||||
ret := native.Quote(sp, nb, dp, &dn, opts)
|
||||
// update *buf length
|
||||
b.Len += dn
|
||||
|
||||
// no need more output
|
||||
if ret >= 0 {
|
||||
break
|
||||
}
|
||||
|
||||
// double buf size
|
||||
*b = rt.GrowSlice(typeByte, *b, b.Cap*2)
|
||||
// ret is the complement of consumed input
|
||||
ret = ^ret
|
||||
// update input buffer
|
||||
nb -= ret
|
||||
sp = unsafe.Pointer(uintptr(sp) + uintptr(ret))
|
||||
}
|
||||
|
||||
runtime.KeepAlive(buf)
|
||||
runtime.KeepAlive(sp)
|
||||
if double {
|
||||
buf = append(buf, `\""`...)
|
||||
} else {
|
||||
buf = append(buf, `"`...)
|
||||
}
|
||||
|
||||
return buf
|
||||
}
|
||||
|
||||
func HtmlEscape(dst []byte, src []byte) []byte {
|
||||
var sidx int
|
||||
|
||||
dst = append(dst, src[:0]...) // avoid check nil dst
|
||||
sbuf := (*rt.GoSlice)(unsafe.Pointer(&src))
|
||||
dbuf := (*rt.GoSlice)(unsafe.Pointer(&dst))
|
||||
|
||||
/* grow dst if it is shorter */
|
||||
if cap(dst)-len(dst) < len(src)+types.BufPaddingSize {
|
||||
cap := len(src)*3/2 + types.BufPaddingSize
|
||||
*dbuf = rt.GrowSlice(typeByte, *dbuf, cap)
|
||||
}
|
||||
|
||||
for sidx < sbuf.Len {
|
||||
sp := rt.Add(sbuf.Ptr, uintptr(sidx))
|
||||
dp := rt.Add(dbuf.Ptr, uintptr(dbuf.Len))
|
||||
|
||||
sn := sbuf.Len - sidx
|
||||
dn := dbuf.Cap - dbuf.Len
|
||||
nb := native.HTMLEscape(sp, sn, dp, &dn)
|
||||
|
||||
/* check for errors */
|
||||
if dbuf.Len += dn; nb >= 0 {
|
||||
break
|
||||
}
|
||||
|
||||
/* not enough space, grow the slice and try again */
|
||||
sidx += ^nb
|
||||
*dbuf = rt.GrowSlice(typeByte, *dbuf, dbuf.Cap*2)
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
func F64toa(buf []byte, v float64) ([]byte) {
|
||||
if v == 0 {
|
||||
return append(buf, '0')
|
||||
}
|
||||
buf = rt.GuardSlice2(buf, 64)
|
||||
ret := native.F64toa((*byte)(rt.IndexByte(buf, len(buf))), v)
|
||||
if ret > 0 {
|
||||
return buf[:len(buf)+ret]
|
||||
} else {
|
||||
return buf
|
||||
}
|
||||
}
|
||||
|
||||
func F32toa(buf []byte, v float32) ([]byte) {
|
||||
if v == 0 {
|
||||
return append(buf, '0')
|
||||
}
|
||||
buf = rt.GuardSlice2(buf, 64)
|
||||
ret := native.F32toa((*byte)(rt.IndexByte(buf, len(buf))), v)
|
||||
if ret > 0 {
|
||||
return buf[:len(buf)+ret]
|
||||
} else {
|
||||
return buf
|
||||
}
|
||||
}
|
||||
|
||||
func I64toa(buf []byte, v int64) ([]byte) {
|
||||
buf = rt.GuardSlice2(buf, 32)
|
||||
ret := native.I64toa((*byte)(rt.IndexByte(buf, len(buf))), v)
|
||||
if ret > 0 {
|
||||
return buf[:len(buf)+ret]
|
||||
} else {
|
||||
return buf
|
||||
}
|
||||
}
|
||||
|
||||
func U64toa(buf []byte, v uint64) ([]byte) {
|
||||
buf = rt.GuardSlice2(buf, 32)
|
||||
ret := native.U64toa((*byte)(rt.IndexByte(buf, len(buf))), v)
|
||||
if ret > 0 {
|
||||
return buf[:len(buf)+ret]
|
||||
} else {
|
||||
return buf
|
||||
}
|
||||
}
|
||||
|
148
vendor/github.com/bytedance/sonic/internal/encoder/alg/spec_compat.go
generated
vendored
Normal file
148
vendor/github.com/bytedance/sonic/internal/encoder/alg/spec_compat.go
generated
vendored
Normal file
|
@ -0,0 +1,148 @@
|
|||
// +build !amd64,!arm64 go1.24 !go1.16 arm64,!go1.20
|
||||
|
||||
/**
|
||||
* Copyright 2024 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package alg
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
"unicode/utf8"
|
||||
"strconv"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
)
|
||||
|
||||
// Valid validates json and returns first non-blank character position,
|
||||
// if it is only one valid json value.
|
||||
// Otherwise returns invalid character position using start.
|
||||
//
|
||||
// Note: it does not check for the invalid UTF-8 characters.
|
||||
func Valid(data []byte) (ok bool, start int) {
|
||||
ok = json.Valid(data)
|
||||
return ok, 0
|
||||
}
|
||||
|
||||
var typeByte = rt.UnpackEface(byte(0)).Type
|
||||
|
||||
func Quote(e []byte, s string, double bool) []byte {
|
||||
if len(s) == 0 {
|
||||
if double {
|
||||
return append(e, `"\"\""`...)
|
||||
}
|
||||
return append(e, `""`...)
|
||||
}
|
||||
|
||||
b := e
|
||||
ss := len(e)
|
||||
e = append(e, '"')
|
||||
start := 0
|
||||
|
||||
for i := 0; i < len(s); {
|
||||
if b := s[i]; b < utf8.RuneSelf {
|
||||
if rt.SafeSet[b] {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if start < i {
|
||||
e = append(e, s[start:i]...)
|
||||
}
|
||||
e = append(e, '\\')
|
||||
switch b {
|
||||
case '\\', '"':
|
||||
e = append(e, b)
|
||||
case '\n':
|
||||
e = append(e, 'n')
|
||||
case '\r':
|
||||
e = append(e, 'r')
|
||||
case '\t':
|
||||
e = append(e, 't')
|
||||
default:
|
||||
// This encodes bytes < 0x20 except for \t, \n and \r.
|
||||
// If escapeHTML is set, it also escapes <, >, and &
|
||||
// because they can lead to security holes when
|
||||
// user-controlled strings are rendered into JSON
|
||||
// and served to some browsers.
|
||||
e = append(e, `u00`...)
|
||||
e = append(e, rt.Hex[b>>4])
|
||||
e = append(e, rt.Hex[b&0xF])
|
||||
}
|
||||
i++
|
||||
start = i
|
||||
continue
|
||||
}
|
||||
c, size := utf8.DecodeRuneInString(s[i:])
|
||||
// if correct && c == utf8.RuneError && size == 1 {
|
||||
// if start < i {
|
||||
// e = append(e, s[start:i]...)
|
||||
// }
|
||||
// e = append(e, `\ufffd`...)
|
||||
// i += size
|
||||
// start = i
|
||||
// continue
|
||||
// }
|
||||
if c == '\u2028' || c == '\u2029' {
|
||||
if start < i {
|
||||
e = append(e, s[start:i]...)
|
||||
}
|
||||
e = append(e, `\u202`...)
|
||||
e = append(e, rt.Hex[c&0xF])
|
||||
i += size
|
||||
start = i
|
||||
continue
|
||||
}
|
||||
i += size
|
||||
}
|
||||
|
||||
if start < len(s) {
|
||||
e = append(e, s[start:]...)
|
||||
}
|
||||
e = append(e, '"')
|
||||
|
||||
if double {
|
||||
return strconv.AppendQuote(b, string(e[ss:]))
|
||||
} else {
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
func HtmlEscape(dst []byte, src []byte) []byte {
|
||||
buf := bytes.NewBuffer(dst)
|
||||
json.HTMLEscape(buf, src)
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func F64toa(buf []byte, v float64) ([]byte) {
|
||||
bs := bytes.NewBuffer(buf)
|
||||
_ = json.NewEncoder(bs).Encode(v)
|
||||
return bs.Bytes()
|
||||
}
|
||||
|
||||
func F32toa(buf []byte, v float32) ([]byte) {
|
||||
bs := bytes.NewBuffer(buf)
|
||||
_ = json.NewEncoder(bs).Encode(v)
|
||||
return bs.Bytes()
|
||||
}
|
||||
|
||||
func I64toa(buf []byte, v int64) ([]byte) {
|
||||
return strconv.AppendInt(buf, int64(v), 10)
|
||||
}
|
||||
|
||||
func U64toa(buf []byte, v uint64) ([]byte) {
|
||||
return strconv.AppendUint(buf, v, 10)
|
||||
}
|
51
vendor/github.com/bytedance/sonic/internal/encoder/asm_stubs_amd64_go116.go
generated
vendored
51
vendor/github.com/bytedance/sonic/internal/encoder/asm_stubs_amd64_go116.go
generated
vendored
|
@ -1,51 +0,0 @@
|
|||
// +build go1.16,!go1.17
|
||||
|
||||
// Copyright 2023 CloudWeGo Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package encoder
|
||||
|
||||
import (
|
||||
`strconv`
|
||||
|
||||
`github.com/bytedance/sonic/internal/jit`
|
||||
`github.com/twitchyliquid64/golang-asm/obj`
|
||||
`github.com/twitchyliquid64/golang-asm/obj/x86`
|
||||
)
|
||||
|
||||
var (
|
||||
_V_writeBarrier = jit.Imm(int64(_runtime_writeBarrier))
|
||||
|
||||
_F_gcWriteBarrierAX = jit.Func(gcWriteBarrierAX)
|
||||
)
|
||||
|
||||
func (self *_Assembler) WritePtr(i int, ptr obj.Addr, rec obj.Addr) {
|
||||
if rec.Reg == x86.REG_AX || rec.Index == x86.REG_AX {
|
||||
panic("rec contains AX!")
|
||||
}
|
||||
self.Emit("MOVQ", _V_writeBarrier, _R10)
|
||||
self.Emit("CMPL", jit.Ptr(_R10, 0), jit.Imm(0))
|
||||
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
self.Emit("MOVQ", ptr, _AX)
|
||||
self.xsave(_DI)
|
||||
self.Emit("LEAQ", rec, _DI)
|
||||
self.Emit("MOVQ", _F_gcWriteBarrierAX, _R10) // MOVQ ${fn}, AX
|
||||
self.Rjmp("CALL", _R10)
|
||||
self.xload(_DI)
|
||||
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
self.Emit("MOVQ", ptr, rec)
|
||||
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
}
|
||||
|
1176
vendor/github.com/bytedance/sonic/internal/encoder/assembler_regabi_amd64.go
generated
vendored
1176
vendor/github.com/bytedance/sonic/internal/encoder/assembler_regabi_amd64.go
generated
vendored
File diff suppressed because it is too large
Load diff
1175
vendor/github.com/bytedance/sonic/internal/encoder/assembler_stkabi_amd64.go
generated
vendored
1175
vendor/github.com/bytedance/sonic/internal/encoder/assembler_stkabi_amd64.go
generated
vendored
File diff suppressed because it is too large
Load diff
1379
vendor/github.com/bytedance/sonic/internal/encoder/compiler.go
generated
vendored
1379
vendor/github.com/bytedance/sonic/internal/encoder/compiler.go
generated
vendored
File diff suppressed because it is too large
Load diff
205
vendor/github.com/bytedance/sonic/internal/encoder/debug_go117.go
generated
vendored
205
vendor/github.com/bytedance/sonic/internal/encoder/debug_go117.go
generated
vendored
|
@ -1,205 +0,0 @@
|
|||
// +build go1.17,!go1.23
|
||||
|
||||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package encoder
|
||||
|
||||
import (
|
||||
`fmt`
|
||||
`os`
|
||||
`runtime`
|
||||
`strings`
|
||||
`unsafe`
|
||||
|
||||
`github.com/bytedance/sonic/internal/jit`
|
||||
`github.com/twitchyliquid64/golang-asm/obj`
|
||||
)
|
||||
|
||||
const _FP_debug = 128
|
||||
|
||||
var (
|
||||
debugSyncGC = os.Getenv("SONIC_SYNC_GC") != ""
|
||||
debugAsyncGC = os.Getenv("SONIC_NO_ASYNC_GC") == ""
|
||||
debugCheckPtr = os.Getenv("SONIC_CHECK_POINTER") != ""
|
||||
)
|
||||
|
||||
var (
|
||||
_Instr_End = newInsOp(_OP_is_nil)
|
||||
|
||||
_F_gc = jit.Func(gc)
|
||||
_F_println = jit.Func(println_wrapper)
|
||||
_F_print = jit.Func(print)
|
||||
)
|
||||
|
||||
func (self *_Assembler) dsave(r ...obj.Addr) {
|
||||
for i, v := range r {
|
||||
if i > _FP_debug / 8 - 1 {
|
||||
panic("too many registers to save")
|
||||
} else {
|
||||
self.Emit("MOVQ", v, jit.Ptr(_SP, _FP_fargs + _FP_saves + _FP_locals + int64(i) * 8))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_Assembler) dload(r ...obj.Addr) {
|
||||
for i, v := range r {
|
||||
if i > _FP_debug / 8 - 1 {
|
||||
panic("too many registers to load")
|
||||
} else {
|
||||
self.Emit("MOVQ", jit.Ptr(_SP, _FP_fargs + _FP_saves + _FP_locals + int64(i) * 8), v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func println_wrapper(i int, op1 int, op2 int){
|
||||
println(i, " Intrs ", op1, _OpNames[op1], "next: ", op2, _OpNames[op2])
|
||||
}
|
||||
|
||||
func print(i int){
|
||||
println(i)
|
||||
}
|
||||
|
||||
func gc() {
|
||||
if !debugSyncGC {
|
||||
return
|
||||
}
|
||||
runtime.GC()
|
||||
// debug.FreeOSMemory()
|
||||
}
|
||||
|
||||
func (self *_Assembler) dcall(fn obj.Addr) {
|
||||
self.Emit("MOVQ", fn, _R10) // MOVQ ${fn}, R10
|
||||
self.Rjmp("CALL", _R10) // CALL R10
|
||||
}
|
||||
|
||||
func (self *_Assembler) debug_gc() {
|
||||
if !debugSyncGC {
|
||||
return
|
||||
}
|
||||
self.dsave(_REG_debug...)
|
||||
self.dcall(_F_gc)
|
||||
self.dload(_REG_debug...)
|
||||
}
|
||||
|
||||
func (self *_Assembler) debug_instr(i int, v *_Instr) {
|
||||
if debugSyncGC {
|
||||
if i+1 == len(self.p) {
|
||||
self.print_gc(i, v, &_Instr_End)
|
||||
} else {
|
||||
next := &(self.p[i+1])
|
||||
self.print_gc(i, v, next)
|
||||
name := _OpNames[next.op()]
|
||||
if strings.Contains(name, "save") {
|
||||
return
|
||||
}
|
||||
}
|
||||
// self.debug_gc()
|
||||
}
|
||||
}
|
||||
|
||||
//go:noescape
|
||||
//go:linkname checkptrBase runtime.checkptrBase
|
||||
func checkptrBase(p unsafe.Pointer) uintptr
|
||||
|
||||
//go:noescape
|
||||
//go:linkname findObject runtime.findObject
|
||||
func findObject(p, refBase, refOff uintptr) (base uintptr, s unsafe.Pointer, objIndex uintptr)
|
||||
|
||||
var (
|
||||
_F_checkptr = jit.Func(checkptr)
|
||||
_F_printptr = jit.Func(printptr)
|
||||
)
|
||||
|
||||
var (
|
||||
_R10 = jit.Reg("R10")
|
||||
)
|
||||
var _REG_debug = []obj.Addr {
|
||||
jit.Reg("AX"),
|
||||
jit.Reg("BX"),
|
||||
jit.Reg("CX"),
|
||||
jit.Reg("DX"),
|
||||
jit.Reg("DI"),
|
||||
jit.Reg("SI"),
|
||||
jit.Reg("BP"),
|
||||
jit.Reg("SP"),
|
||||
jit.Reg("R8"),
|
||||
jit.Reg("R9"),
|
||||
jit.Reg("R10"),
|
||||
jit.Reg("R11"),
|
||||
jit.Reg("R12"),
|
||||
jit.Reg("R13"),
|
||||
jit.Reg("R14"),
|
||||
jit.Reg("R15"),
|
||||
}
|
||||
|
||||
func checkptr(ptr uintptr) {
|
||||
if ptr == 0 {
|
||||
return
|
||||
}
|
||||
fmt.Printf("pointer: %x\n", ptr)
|
||||
f := checkptrBase(unsafe.Pointer(uintptr(ptr)))
|
||||
if f == 0 {
|
||||
fmt.Printf("! unknown-based pointer: %x\n", ptr)
|
||||
} else if f == 1 {
|
||||
fmt.Printf("! stack pointer: %x\n", ptr)
|
||||
} else {
|
||||
fmt.Printf("base: %x\n", f)
|
||||
}
|
||||
findobj(ptr)
|
||||
}
|
||||
|
||||
func findobj(ptr uintptr) {
|
||||
base, s, objIndex := findObject(ptr, 0, 0)
|
||||
if s != nil && base == 0 {
|
||||
fmt.Printf("! invalid pointer: %x\n", ptr)
|
||||
}
|
||||
fmt.Printf("objIndex: %d\n", objIndex)
|
||||
}
|
||||
|
||||
func (self *_Assembler) check_ptr(ptr obj.Addr, lea bool) {
|
||||
if !debugCheckPtr {
|
||||
return
|
||||
}
|
||||
|
||||
self.dsave(_REG_debug...)
|
||||
if lea {
|
||||
self.Emit("LEAQ", ptr, _R10)
|
||||
} else {
|
||||
self.Emit("MOVQ", ptr, _R10)
|
||||
}
|
||||
self.Emit("MOVQ", _R10, jit.Ptr(_SP, 0))
|
||||
self.dcall(_F_checkptr)
|
||||
self.dload(_REG_debug...)
|
||||
}
|
||||
|
||||
func printptr(i int, ptr uintptr) {
|
||||
fmt.Printf("[%d] ptr: %x\n", i, ptr)
|
||||
}
|
||||
|
||||
func (self *_Assembler) print_ptr(i int, ptr obj.Addr, lea bool) {
|
||||
self.dsave(_REG_debug...)
|
||||
if lea {
|
||||
self.Emit("LEAQ", ptr, _R10)
|
||||
} else {
|
||||
self.Emit("MOVQ", ptr, _R10)
|
||||
}
|
||||
|
||||
self.Emit("MOVQ", jit.Imm(int64(i)), _AX)
|
||||
self.Emit("MOVQ", _R10, _BX)
|
||||
self.dcall(_F_printptr)
|
||||
self.dload(_REG_debug...)
|
||||
}
|
24
vendor/github.com/bytedance/sonic/internal/encoder/encode_norace.go
generated
vendored
Normal file
24
vendor/github.com/bytedance/sonic/internal/encoder/encode_norace.go
generated
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
//go:build !race
|
||||
// +build !race
|
||||
|
||||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package encoder
|
||||
|
||||
func encodeIntoCheckRace(buf *[]byte, val interface{}, opts Options) error {
|
||||
return encodeInto(buf, val, opts)
|
||||
}
|
54
vendor/github.com/bytedance/sonic/internal/encoder/encode_race.go
generated
vendored
Normal file
54
vendor/github.com/bytedance/sonic/internal/encoder/encode_race.go
generated
vendored
Normal file
|
@ -0,0 +1,54 @@
|
|||
//go:build race
|
||||
// +build race
|
||||
|
||||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package encoder
|
||||
|
||||
import (
|
||||
`encoding/json`
|
||||
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
)
|
||||
|
||||
|
||||
func helpDetectDataRace(val interface{}) {
|
||||
var out []byte
|
||||
defer func() {
|
||||
if v := recover(); v != nil {
|
||||
// NOTICE: help user to locate where panic occurs
|
||||
println("panic when encoding on: ", truncate(out))
|
||||
panic(v)
|
||||
}
|
||||
}()
|
||||
out, _ = json.Marshal(val)
|
||||
}
|
||||
|
||||
func encodeIntoCheckRace(buf *[]byte, val interface{}, opts Options) error {
|
||||
err := encodeInto(buf, val, opts)
|
||||
/* put last to make the panic from sonic will always be caught at first */
|
||||
helpDetectDataRace(val)
|
||||
return err
|
||||
}
|
||||
|
||||
func truncate(json []byte) string {
|
||||
if len(json) <= 256 {
|
||||
return rt.Mem2Str(json)
|
||||
} else {
|
||||
return rt.Mem2Str(json[len(json)-256:])
|
||||
}
|
||||
}
|
169
vendor/github.com/bytedance/sonic/internal/encoder/encoder.go
generated
vendored
169
vendor/github.com/bytedance/sonic/internal/encoder/encoder.go
generated
vendored
|
@ -17,72 +17,62 @@
|
|||
package encoder
|
||||
|
||||
import (
|
||||
`bytes`
|
||||
`encoding/json`
|
||||
`reflect`
|
||||
`runtime`
|
||||
`unsafe`
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
`github.com/bytedance/sonic/internal/native`
|
||||
`github.com/bytedance/sonic/internal/native/types`
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
`github.com/bytedance/sonic/utf8`
|
||||
`github.com/bytedance/sonic/option`
|
||||
"github.com/bytedance/sonic/utf8"
|
||||
"github.com/bytedance/sonic/internal/encoder/alg"
|
||||
"github.com/bytedance/sonic/internal/encoder/vars"
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
"github.com/bytedance/sonic/option"
|
||||
)
|
||||
|
||||
// Options is a set of encoding options.
|
||||
type Options uint64
|
||||
|
||||
const (
|
||||
bitSortMapKeys = iota
|
||||
bitEscapeHTML
|
||||
bitCompactMarshaler
|
||||
bitNoQuoteTextMarshaler
|
||||
bitNoNullSliceOrMap
|
||||
bitValidateString
|
||||
bitNoValidateJSONMarshaler
|
||||
bitNoEncoderNewline
|
||||
|
||||
// used for recursive compile
|
||||
bitPointerValue = 63
|
||||
)
|
||||
|
||||
const (
|
||||
// SortMapKeys indicates that the keys of a map needs to be sorted
|
||||
// before serializing into JSON.
|
||||
// WARNING: This hurts performance A LOT, USE WITH CARE.
|
||||
SortMapKeys Options = 1 << bitSortMapKeys
|
||||
SortMapKeys Options = 1 << alg.BitSortMapKeys
|
||||
|
||||
// EscapeHTML indicates encoder to escape all HTML characters
|
||||
// after serializing into JSON (see https://pkg.go.dev/encoding/json#HTMLEscape).
|
||||
// WARNING: This hurts performance A LOT, USE WITH CARE.
|
||||
EscapeHTML Options = 1 << bitEscapeHTML
|
||||
EscapeHTML Options = 1 << alg.BitEscapeHTML
|
||||
|
||||
// CompactMarshaler indicates that the output JSON from json.Marshaler
|
||||
// is always compact and needs no validation
|
||||
CompactMarshaler Options = 1 << bitCompactMarshaler
|
||||
CompactMarshaler Options = 1 << alg.BitCompactMarshaler
|
||||
|
||||
// NoQuoteTextMarshaler indicates that the output text from encoding.TextMarshaler
|
||||
// is always escaped string and needs no quoting
|
||||
NoQuoteTextMarshaler Options = 1 << bitNoQuoteTextMarshaler
|
||||
NoQuoteTextMarshaler Options = 1 << alg.BitNoQuoteTextMarshaler
|
||||
|
||||
// NoNullSliceOrMap indicates all empty Array or Object are encoded as '[]' or '{}',
|
||||
// instead of 'null'
|
||||
NoNullSliceOrMap Options = 1 << bitNoNullSliceOrMap
|
||||
// instead of 'null'.
|
||||
// NOTE: The priority of this option is lower than json tag `omitempty`.
|
||||
NoNullSliceOrMap Options = 1 << alg.BitNoNullSliceOrMap
|
||||
|
||||
// ValidateString indicates that encoder should validate the input string
|
||||
// before encoding it into JSON.
|
||||
ValidateString Options = 1 << bitValidateString
|
||||
ValidateString Options = 1 << alg.BitValidateString
|
||||
|
||||
// NoValidateJSONMarshaler indicates that the encoder should not validate the output string
|
||||
// after encoding the JSONMarshaler to JSON.
|
||||
NoValidateJSONMarshaler Options = 1 << bitNoValidateJSONMarshaler
|
||||
NoValidateJSONMarshaler Options = 1 << alg.BitNoValidateJSONMarshaler
|
||||
|
||||
// NoEncoderNewline indicates that the encoder should not add a newline after every message
|
||||
NoEncoderNewline Options = 1 << bitNoEncoderNewline
|
||||
NoEncoderNewline Options = 1 << alg.BitNoEncoderNewline
|
||||
|
||||
// CompatibleWithStd is used to be compatible with std encoder.
|
||||
CompatibleWithStd Options = SortMapKeys | EscapeHTML | CompactMarshaler
|
||||
|
||||
// Encode Infinity or Nan float into `null`, instead of returning an error.
|
||||
EncodeNullForInfOrNan Options = 1 << alg.BitEncodeNullForInfOrNan
|
||||
)
|
||||
|
||||
// Encoder represents a specific set of encoder configurations.
|
||||
|
@ -171,53 +161,45 @@ func (enc *Encoder) SetIndent(prefix, indent string) {
|
|||
|
||||
// Quote returns the JSON-quoted version of s.
|
||||
func Quote(s string) string {
|
||||
var n int
|
||||
var p []byte
|
||||
|
||||
/* check for empty string */
|
||||
if s == "" {
|
||||
return `""`
|
||||
}
|
||||
|
||||
/* allocate space for result */
|
||||
n = len(s) + 2
|
||||
p = make([]byte, 0, n)
|
||||
|
||||
/* call the encoder */
|
||||
_ = encodeString(&p, s)
|
||||
return rt.Mem2Str(p)
|
||||
buf := make([]byte, 0, len(s)+2)
|
||||
buf = alg.Quote(buf, s, false)
|
||||
return rt.Mem2Str(buf)
|
||||
}
|
||||
|
||||
// Encode returns the JSON encoding of val, encoded with opts.
|
||||
func Encode(val interface{}, opts Options) ([]byte, error) {
|
||||
var ret []byte
|
||||
|
||||
buf := newBytes()
|
||||
err := encodeInto(&buf, val, opts)
|
||||
buf := vars.NewBytes()
|
||||
err := encodeIntoCheckRace(buf, val, opts)
|
||||
|
||||
/* check for errors */
|
||||
if err != nil {
|
||||
freeBytes(buf)
|
||||
vars.FreeBytes(buf)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
/* htmlescape or correct UTF-8 if opts enable */
|
||||
old := buf
|
||||
buf = encodeFinish(old, opts)
|
||||
pbuf := ((*rt.GoSlice)(unsafe.Pointer(&buf))).Ptr
|
||||
pold := ((*rt.GoSlice)(unsafe.Pointer(&old))).Ptr
|
||||
*buf = encodeFinish(*old, opts)
|
||||
pbuf := ((*rt.GoSlice)(unsafe.Pointer(buf))).Ptr
|
||||
pold := ((*rt.GoSlice)(unsafe.Pointer(old))).Ptr
|
||||
|
||||
/* return when allocated a new buffer */
|
||||
if pbuf != pold {
|
||||
freeBytes(old)
|
||||
return buf, nil
|
||||
vars.FreeBytes(old)
|
||||
return *buf, nil
|
||||
}
|
||||
|
||||
/* make a copy of the result */
|
||||
ret = make([]byte, len(buf))
|
||||
copy(ret, buf)
|
||||
|
||||
freeBytes(buf)
|
||||
if rt.CanSizeResue(cap(*buf)) {
|
||||
ret = make([]byte, len(*buf))
|
||||
copy(ret, *buf)
|
||||
vars.FreeBytes(buf)
|
||||
} else {
|
||||
ret = *buf
|
||||
}
|
||||
|
||||
/* return the buffer into pool */
|
||||
return ret, nil
|
||||
}
|
||||
|
@ -225,7 +207,7 @@ func Encode(val interface{}, opts Options) ([]byte, error) {
|
|||
// EncodeInto is like Encode but uses a user-supplied buffer instead of allocating
|
||||
// a new one.
|
||||
func EncodeInto(buf *[]byte, val interface{}, opts Options) error {
|
||||
err := encodeInto(buf, val, opts)
|
||||
err := encodeIntoCheckRace(buf, val, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -234,15 +216,15 @@ func EncodeInto(buf *[]byte, val interface{}, opts Options) error {
|
|||
}
|
||||
|
||||
func encodeInto(buf *[]byte, val interface{}, opts Options) error {
|
||||
stk := newStack()
|
||||
stk := vars.NewStack()
|
||||
efv := rt.UnpackEface(val)
|
||||
err := encodeTypedPointer(buf, efv.Type, &efv.Value, stk, uint64(opts))
|
||||
|
||||
/* return the stack into pool */
|
||||
if err != nil {
|
||||
resetStack(stk)
|
||||
vars.ResetStack(stk)
|
||||
}
|
||||
freeStack(stk)
|
||||
vars.FreeStack(stk)
|
||||
|
||||
/* avoid GC ahead */
|
||||
runtime.KeepAlive(buf)
|
||||
|
@ -254,13 +236,12 @@ func encodeFinish(buf []byte, opts Options) []byte {
|
|||
if opts & EscapeHTML != 0 {
|
||||
buf = HTMLEscape(nil, buf)
|
||||
}
|
||||
if opts & ValidateString != 0 && !utf8.Validate(buf) {
|
||||
if (opts & ValidateString != 0) && !utf8.Validate(buf) {
|
||||
buf = utf8.CorrectWith(nil, buf, `\ufffd`)
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
var typeByte = rt.UnpackType(reflect.TypeOf(byte(0)))
|
||||
|
||||
// HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029
|
||||
// characters inside string literals changed to \u003c, \u003e, \u0026, \u2028, \u2029
|
||||
|
@ -269,7 +250,7 @@ func encodeFinish(buf []byte, opts Options) []byte {
|
|||
// escaping within <script> tags, so an alternative JSON encoding must
|
||||
// be used.
|
||||
func HTMLEscape(dst []byte, src []byte) []byte {
|
||||
return htmlEscape(dst, src)
|
||||
return alg.HtmlEscape(dst, src)
|
||||
}
|
||||
|
||||
// EncodeIndented is like Encode but applies Indent to format the output.
|
||||
|
@ -277,37 +258,40 @@ func HTMLEscape(dst []byte, src []byte) []byte {
|
|||
// followed by one or more copies of indent according to the indentation nesting.
|
||||
func EncodeIndented(val interface{}, prefix string, indent string, opts Options) ([]byte, error) {
|
||||
var err error
|
||||
var out []byte
|
||||
var buf *bytes.Buffer
|
||||
|
||||
/* encode into the buffer */
|
||||
out = newBytes()
|
||||
err = EncodeInto(&out, val, opts)
|
||||
out := vars.NewBytes()
|
||||
err = EncodeInto(out, val, opts)
|
||||
|
||||
/* check for errors */
|
||||
if err != nil {
|
||||
freeBytes(out)
|
||||
vars.FreeBytes(out)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
/* indent the JSON */
|
||||
buf = newBuffer()
|
||||
err = json.Indent(buf, out, prefix, indent)
|
||||
buf = vars.NewBuffer()
|
||||
err = json.Indent(buf, *out, prefix, indent)
|
||||
vars.FreeBytes(out)
|
||||
|
||||
/* check for errors */
|
||||
if err != nil {
|
||||
freeBytes(out)
|
||||
freeBuffer(buf)
|
||||
vars.FreeBuffer(buf)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
/* copy to the result buffer */
|
||||
ret := make([]byte, buf.Len())
|
||||
copy(ret, buf.Bytes())
|
||||
|
||||
/* return the buffers into pool */
|
||||
freeBytes(out)
|
||||
freeBuffer(buf)
|
||||
var ret []byte
|
||||
if rt.CanSizeResue(cap(buf.Bytes())) {
|
||||
ret = make([]byte, buf.Len())
|
||||
copy(ret, buf.Bytes())
|
||||
/* return the buffers into pool */
|
||||
vars.FreeBuffer(buf)
|
||||
} else {
|
||||
ret = buf.Bytes()
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
|
@ -330,26 +314,5 @@ func Pretouch(vt reflect.Type, opts ...option.CompileOption) error {
|
|||
//
|
||||
// Note: it does not check for the invalid UTF-8 characters.
|
||||
func Valid(data []byte) (ok bool, start int) {
|
||||
n := len(data)
|
||||
if n == 0 {
|
||||
return false, -1
|
||||
}
|
||||
s := rt.Mem2Str(data)
|
||||
p := 0
|
||||
m := types.NewStateMachine()
|
||||
ret := native.ValidateOne(&s, &p, m, types.F_VALIDATE_STRING)
|
||||
types.FreeStateMachine(m)
|
||||
|
||||
if ret < 0 {
|
||||
return false, p-1
|
||||
}
|
||||
|
||||
/* check for trailing spaces */
|
||||
for ;p < n; p++ {
|
||||
if (types.SPACE_MASK & (1 << data[p])) == 0 {
|
||||
return false, p
|
||||
}
|
||||
}
|
||||
|
||||
return true, ret
|
||||
return alg.Valid(data)
|
||||
}
|
||||
|
|
473
vendor/github.com/bytedance/sonic/internal/encoder/ir/op.go
generated
vendored
Normal file
473
vendor/github.com/bytedance/sonic/internal/encoder/ir/op.go
generated
vendored
Normal file
|
@ -0,0 +1,473 @@
|
|||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package ir
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"github.com/bytedance/sonic/internal/encoder/vars"
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
)
|
||||
|
||||
type Op uint8
|
||||
|
||||
const (
|
||||
OP_null Op = iota + 1
|
||||
OP_empty_arr
|
||||
OP_empty_obj
|
||||
OP_bool
|
||||
OP_i8
|
||||
OP_i16
|
||||
OP_i32
|
||||
OP_i64
|
||||
OP_u8
|
||||
OP_u16
|
||||
OP_u32
|
||||
OP_u64
|
||||
OP_f32
|
||||
OP_f64
|
||||
OP_str
|
||||
OP_bin
|
||||
OP_quote
|
||||
OP_number
|
||||
OP_eface
|
||||
OP_iface
|
||||
OP_byte
|
||||
OP_text
|
||||
OP_deref
|
||||
OP_index
|
||||
OP_load
|
||||
OP_save
|
||||
OP_drop
|
||||
OP_drop_2
|
||||
OP_recurse
|
||||
OP_is_nil
|
||||
OP_is_nil_p1
|
||||
OP_is_zero_1
|
||||
OP_is_zero_2
|
||||
OP_is_zero_4
|
||||
OP_is_zero_8
|
||||
OP_is_zero_map
|
||||
OP_goto
|
||||
OP_map_iter
|
||||
OP_map_stop
|
||||
OP_map_check_key
|
||||
OP_map_write_key
|
||||
OP_map_value_next
|
||||
OP_slice_len
|
||||
OP_slice_next
|
||||
OP_marshal
|
||||
OP_marshal_p
|
||||
OP_marshal_text
|
||||
OP_marshal_text_p
|
||||
OP_cond_set
|
||||
OP_cond_testc
|
||||
)
|
||||
|
||||
const (
|
||||
_INT_SIZE = 32 << (^uint(0) >> 63)
|
||||
_PTR_SIZE = 32 << (^uintptr(0) >> 63)
|
||||
_PTR_BYTE = unsafe.Sizeof(uintptr(0))
|
||||
)
|
||||
|
||||
const OpSize = unsafe.Sizeof(NewInsOp(0))
|
||||
|
||||
var OpNames = [256]string{
|
||||
OP_null: "null",
|
||||
OP_empty_arr: "empty_arr",
|
||||
OP_empty_obj: "empty_obj",
|
||||
OP_bool: "bool",
|
||||
OP_i8: "i8",
|
||||
OP_i16: "i16",
|
||||
OP_i32: "i32",
|
||||
OP_i64: "i64",
|
||||
OP_u8: "u8",
|
||||
OP_u16: "u16",
|
||||
OP_u32: "u32",
|
||||
OP_u64: "u64",
|
||||
OP_f32: "f32",
|
||||
OP_f64: "f64",
|
||||
OP_str: "str",
|
||||
OP_bin: "bin",
|
||||
OP_quote: "quote",
|
||||
OP_number: "number",
|
||||
OP_eface: "eface",
|
||||
OP_iface: "iface",
|
||||
OP_byte: "byte",
|
||||
OP_text: "text",
|
||||
OP_deref: "deref",
|
||||
OP_index: "index",
|
||||
OP_load: "load",
|
||||
OP_save: "save",
|
||||
OP_drop: "drop",
|
||||
OP_drop_2: "drop_2",
|
||||
OP_recurse: "recurse",
|
||||
OP_is_nil: "is_nil",
|
||||
OP_is_nil_p1: "is_nil_p1",
|
||||
OP_is_zero_1: "is_zero_1",
|
||||
OP_is_zero_2: "is_zero_2",
|
||||
OP_is_zero_4: "is_zero_4",
|
||||
OP_is_zero_8: "is_zero_8",
|
||||
OP_is_zero_map: "is_zero_map",
|
||||
OP_goto: "goto",
|
||||
OP_map_iter: "map_iter",
|
||||
OP_map_stop: "map_stop",
|
||||
OP_map_check_key: "map_check_key",
|
||||
OP_map_write_key: "map_write_key",
|
||||
OP_map_value_next: "map_value_next",
|
||||
OP_slice_len: "slice_len",
|
||||
OP_slice_next: "slice_next",
|
||||
OP_marshal: "marshal",
|
||||
OP_marshal_p: "marshal_p",
|
||||
OP_marshal_text: "marshal_text",
|
||||
OP_marshal_text_p: "marshal_text_p",
|
||||
OP_cond_set: "cond_set",
|
||||
OP_cond_testc: "cond_testc",
|
||||
}
|
||||
|
||||
func (self Op) String() string {
|
||||
if ret := OpNames[self]; ret != "" {
|
||||
return ret
|
||||
} else {
|
||||
return "<invalid>"
|
||||
}
|
||||
}
|
||||
|
||||
func OP_int() Op {
|
||||
switch _INT_SIZE {
|
||||
case 32:
|
||||
return OP_i32
|
||||
case 64:
|
||||
return OP_i64
|
||||
default:
|
||||
panic("unsupported int size")
|
||||
}
|
||||
}
|
||||
|
||||
func OP_uint() Op {
|
||||
switch _INT_SIZE {
|
||||
case 32:
|
||||
return OP_u32
|
||||
case 64:
|
||||
return OP_u64
|
||||
default:
|
||||
panic("unsupported uint size")
|
||||
}
|
||||
}
|
||||
|
||||
func OP_uintptr() Op {
|
||||
switch _PTR_SIZE {
|
||||
case 32:
|
||||
return OP_u32
|
||||
case 64:
|
||||
return OP_u64
|
||||
default:
|
||||
panic("unsupported pointer size")
|
||||
}
|
||||
}
|
||||
|
||||
func OP_is_zero_ints() Op {
|
||||
switch _INT_SIZE {
|
||||
case 32:
|
||||
return OP_is_zero_4
|
||||
case 64:
|
||||
return OP_is_zero_8
|
||||
default:
|
||||
panic("unsupported integer size")
|
||||
}
|
||||
}
|
||||
|
||||
type Instr struct {
|
||||
o Op
|
||||
u int // union {op: 8, _: 8, vi: 48}, vi maybe int or len(str)
|
||||
p unsafe.Pointer // maybe GoString.Ptr, or *GoType
|
||||
}
|
||||
|
||||
func NewInsOp(op Op) Instr {
|
||||
return Instr{o: op}
|
||||
}
|
||||
|
||||
func NewInsVi(op Op, vi int) Instr {
|
||||
return Instr{o: op, u: vi}
|
||||
}
|
||||
|
||||
func NewInsVs(op Op, vs string) Instr {
|
||||
return Instr{
|
||||
o: op,
|
||||
u: len(vs),
|
||||
p: (*rt.GoString)(unsafe.Pointer(&vs)).Ptr,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInsVt(op Op, vt reflect.Type) Instr {
|
||||
return Instr{
|
||||
o: op,
|
||||
p: unsafe.Pointer(rt.UnpackType(vt)),
|
||||
}
|
||||
}
|
||||
|
||||
type typAndTab struct {
|
||||
vt *rt.GoType
|
||||
itab *rt.GoItab
|
||||
}
|
||||
|
||||
func NewInsVtab(op Op, vt reflect.Type, itab *rt.GoItab) Instr {
|
||||
return Instr{
|
||||
o: op,
|
||||
p: unsafe.Pointer(&typAndTab{
|
||||
vt: rt.UnpackType(vt),
|
||||
itab: itab,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func NewInsVp(op Op, vt reflect.Type, pv bool) Instr {
|
||||
i := 0
|
||||
if pv {
|
||||
i = 1
|
||||
}
|
||||
return Instr{
|
||||
o: op,
|
||||
u: i,
|
||||
p: unsafe.Pointer(rt.UnpackType(vt)),
|
||||
}
|
||||
}
|
||||
|
||||
func (self Instr) Op() Op {
|
||||
return Op(self.o)
|
||||
}
|
||||
|
||||
func (self Instr) Vi() int {
|
||||
return self.u
|
||||
}
|
||||
|
||||
func (self Instr) Vf() uint8 {
|
||||
return (*rt.GoType)(self.p).KindFlags
|
||||
}
|
||||
|
||||
func (self Instr) Vs() (v string) {
|
||||
(*rt.GoString)(unsafe.Pointer(&v)).Ptr = self.p
|
||||
(*rt.GoString)(unsafe.Pointer(&v)).Len = self.Vi()
|
||||
return
|
||||
}
|
||||
|
||||
func (self Instr) Vk() reflect.Kind {
|
||||
return (*rt.GoType)(self.p).Kind()
|
||||
}
|
||||
|
||||
func (self Instr) Vt() reflect.Type {
|
||||
return (*rt.GoType)(self.p).Pack()
|
||||
}
|
||||
|
||||
func (self Instr) Vr() *rt.GoType {
|
||||
return (*rt.GoType)(self.p)
|
||||
}
|
||||
|
||||
func (self Instr) Vp() (vt reflect.Type, pv bool) {
|
||||
return (*rt.GoType)(self.p).Pack(), self.u == 1
|
||||
}
|
||||
|
||||
func (self Instr) Vtab() (vt *rt.GoType, itab *rt.GoItab) {
|
||||
tt := (*typAndTab)(self.p)
|
||||
return tt.vt, tt.itab
|
||||
}
|
||||
|
||||
func (self Instr) Vp2() (vt *rt.GoType, pv bool) {
|
||||
return (*rt.GoType)(self.p), self.u == 1
|
||||
}
|
||||
|
||||
func (self Instr) I64() int64 {
|
||||
return int64(self.Vi())
|
||||
}
|
||||
|
||||
func (self Instr) Byte() byte {
|
||||
return byte(self.Vi())
|
||||
}
|
||||
|
||||
func (self Instr) Vlen() int {
|
||||
return int((*rt.GoType)(self.p).Size)
|
||||
}
|
||||
|
||||
func (self Instr) isBranch() bool {
|
||||
switch self.Op() {
|
||||
case OP_goto:
|
||||
fallthrough
|
||||
case OP_is_nil:
|
||||
fallthrough
|
||||
case OP_is_nil_p1:
|
||||
fallthrough
|
||||
case OP_is_zero_1:
|
||||
fallthrough
|
||||
case OP_is_zero_2:
|
||||
fallthrough
|
||||
case OP_is_zero_4:
|
||||
fallthrough
|
||||
case OP_is_zero_8:
|
||||
fallthrough
|
||||
case OP_map_check_key:
|
||||
fallthrough
|
||||
case OP_map_write_key:
|
||||
fallthrough
|
||||
case OP_slice_next:
|
||||
fallthrough
|
||||
case OP_cond_testc:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (self Instr) Disassemble() string {
|
||||
switch self.Op() {
|
||||
case OP_byte:
|
||||
return fmt.Sprintf("%-18s%s", self.Op().String(), strconv.QuoteRune(rune(self.Vi())))
|
||||
case OP_text:
|
||||
return fmt.Sprintf("%-18s%s", self.Op().String(), strconv.Quote(self.Vs()))
|
||||
case OP_index:
|
||||
return fmt.Sprintf("%-18s%d", self.Op().String(), self.Vi())
|
||||
case OP_recurse:
|
||||
fallthrough
|
||||
case OP_map_iter:
|
||||
return fmt.Sprintf("%-18s%s", self.Op().String(), self.Vt())
|
||||
case OP_marshal:
|
||||
fallthrough
|
||||
case OP_marshal_p:
|
||||
fallthrough
|
||||
case OP_marshal_text:
|
||||
fallthrough
|
||||
case OP_marshal_text_p:
|
||||
vt, _ := self.Vtab()
|
||||
return fmt.Sprintf("%-18s%s", self.Op().String(), vt.Pack())
|
||||
case OP_goto:
|
||||
fallthrough
|
||||
case OP_is_nil:
|
||||
fallthrough
|
||||
case OP_is_nil_p1:
|
||||
fallthrough
|
||||
case OP_is_zero_1:
|
||||
fallthrough
|
||||
case OP_is_zero_2:
|
||||
fallthrough
|
||||
case OP_is_zero_4:
|
||||
fallthrough
|
||||
case OP_is_zero_8:
|
||||
fallthrough
|
||||
case OP_is_zero_map:
|
||||
fallthrough
|
||||
case OP_cond_testc:
|
||||
fallthrough
|
||||
case OP_map_check_key:
|
||||
fallthrough
|
||||
case OP_map_write_key:
|
||||
return fmt.Sprintf("%-18sL_%d", self.Op().String(), self.Vi())
|
||||
case OP_slice_next:
|
||||
return fmt.Sprintf("%-18sL_%d, %s", self.Op().String(), self.Vi(), self.Vt())
|
||||
default:
|
||||
return fmt.Sprintf("%#v", self)
|
||||
}
|
||||
}
|
||||
|
||||
type (
|
||||
Program []Instr
|
||||
)
|
||||
|
||||
func (self Program) PC() int {
|
||||
return len(self)
|
||||
}
|
||||
|
||||
func (self Program) Tag(n int) {
|
||||
if n >= vars.MaxStack {
|
||||
panic("type nesting too deep")
|
||||
}
|
||||
}
|
||||
|
||||
func (self Program) Pin(i int) {
|
||||
v := &self[i]
|
||||
v.u = self.PC()
|
||||
}
|
||||
|
||||
func (self Program) Rel(v []int) {
|
||||
for _, i := range v {
|
||||
self.Pin(i)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *Program) Add(op Op) {
|
||||
*self = append(*self, NewInsOp(op))
|
||||
}
|
||||
|
||||
func (self *Program) Key(op Op) {
|
||||
*self = append(*self,
|
||||
NewInsVi(OP_byte, '"'),
|
||||
NewInsOp(op),
|
||||
NewInsVi(OP_byte, '"'),
|
||||
)
|
||||
}
|
||||
|
||||
func (self *Program) Int(op Op, vi int) {
|
||||
*self = append(*self, NewInsVi(op, vi))
|
||||
}
|
||||
|
||||
func (self *Program) Str(op Op, vs string) {
|
||||
*self = append(*self, NewInsVs(op, vs))
|
||||
}
|
||||
|
||||
func (self *Program) Rtt(op Op, vt reflect.Type) {
|
||||
*self = append(*self, NewInsVt(op, vt))
|
||||
}
|
||||
|
||||
func (self *Program) Vp(op Op, vt reflect.Type, pv bool) {
|
||||
*self = append(*self, NewInsVp(op, vt, pv))
|
||||
}
|
||||
|
||||
func (self *Program) Vtab(op Op, vt reflect.Type, itab *rt.GoItab) {
|
||||
*self = append(*self, NewInsVtab(op, vt, itab))
|
||||
}
|
||||
|
||||
func (self Program) Disassemble() string {
|
||||
nb := len(self)
|
||||
tab := make([]bool, nb+1)
|
||||
ret := make([]string, 0, nb+1)
|
||||
|
||||
/* prescan to get all the labels */
|
||||
for _, ins := range self {
|
||||
if ins.isBranch() {
|
||||
tab[ins.Vi()] = true
|
||||
}
|
||||
}
|
||||
|
||||
/* disassemble each instruction */
|
||||
for i, ins := range self {
|
||||
if !tab[i] {
|
||||
ret = append(ret, "\t"+ins.Disassemble())
|
||||
} else {
|
||||
ret = append(ret, fmt.Sprintf("L_%d:\n\t%s", i, ins.Disassemble()))
|
||||
}
|
||||
}
|
||||
|
||||
/* add the last label, if needed */
|
||||
if tab[nb] {
|
||||
ret = append(ret, fmt.Sprintf("L_%d:", nb))
|
||||
}
|
||||
|
||||
/* add an "end" indicator, and join all the strings */
|
||||
return strings.Join(append(ret, "\tend"), "\n")
|
||||
}
|
193
vendor/github.com/bytedance/sonic/internal/encoder/pools.go
generated
vendored
193
vendor/github.com/bytedance/sonic/internal/encoder/pools.go
generated
vendored
|
@ -1,193 +0,0 @@
|
|||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package encoder
|
||||
|
||||
import (
|
||||
`bytes`
|
||||
`sync`
|
||||
`unsafe`
|
||||
`errors`
|
||||
`reflect`
|
||||
|
||||
`github.com/bytedance/sonic/internal/caching`
|
||||
`github.com/bytedance/sonic/option`
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
)
|
||||
|
||||
const (
|
||||
_MaxStack = 4096 // 4k states
|
||||
|
||||
_StackSize = unsafe.Sizeof(_Stack{})
|
||||
)
|
||||
|
||||
var (
|
||||
bytesPool = sync.Pool{}
|
||||
stackPool = sync.Pool{}
|
||||
bufferPool = sync.Pool{}
|
||||
programCache = caching.CreateProgramCache()
|
||||
)
|
||||
|
||||
type _State struct {
|
||||
x int
|
||||
f uint64
|
||||
p unsafe.Pointer
|
||||
q unsafe.Pointer
|
||||
}
|
||||
|
||||
type _Stack struct {
|
||||
sp uint64
|
||||
sb [_MaxStack]_State
|
||||
}
|
||||
|
||||
type _Encoder func(
|
||||
rb *[]byte,
|
||||
vp unsafe.Pointer,
|
||||
sb *_Stack,
|
||||
fv uint64,
|
||||
) error
|
||||
|
||||
var _KeepAlive struct {
|
||||
rb *[]byte
|
||||
vp unsafe.Pointer
|
||||
sb *_Stack
|
||||
fv uint64
|
||||
err error
|
||||
frame [_FP_offs]byte
|
||||
}
|
||||
|
||||
var errCallShadow = errors.New("DON'T CALL THIS!")
|
||||
|
||||
// Faker func of _Encoder, used to export its stackmap as _Encoder's
|
||||
func _Encoder_Shadow(rb *[]byte, vp unsafe.Pointer, sb *_Stack, fv uint64) (err error) {
|
||||
// align to assembler_amd64.go: _FP_offs
|
||||
var frame [_FP_offs]byte
|
||||
|
||||
// must keep all args and frames noticeable to GC
|
||||
_KeepAlive.rb = rb
|
||||
_KeepAlive.vp = vp
|
||||
_KeepAlive.sb = sb
|
||||
_KeepAlive.fv = fv
|
||||
_KeepAlive.err = err
|
||||
_KeepAlive.frame = frame
|
||||
|
||||
return errCallShadow
|
||||
}
|
||||
|
||||
func newBytes() []byte {
|
||||
if ret := bytesPool.Get(); ret != nil {
|
||||
return ret.([]byte)
|
||||
} else {
|
||||
return make([]byte, 0, option.DefaultEncoderBufferSize)
|
||||
}
|
||||
}
|
||||
|
||||
func newStack() *_Stack {
|
||||
if ret := stackPool.Get(); ret == nil {
|
||||
return new(_Stack)
|
||||
} else {
|
||||
return ret.(*_Stack)
|
||||
}
|
||||
}
|
||||
|
||||
func resetStack(p *_Stack) {
|
||||
memclrNoHeapPointers(unsafe.Pointer(p), _StackSize)
|
||||
}
|
||||
|
||||
func newBuffer() *bytes.Buffer {
|
||||
if ret := bufferPool.Get(); ret != nil {
|
||||
return ret.(*bytes.Buffer)
|
||||
} else {
|
||||
return bytes.NewBuffer(make([]byte, 0, option.DefaultEncoderBufferSize))
|
||||
}
|
||||
}
|
||||
|
||||
func freeBytes(p []byte) {
|
||||
p = p[:0]
|
||||
bytesPool.Put(p)
|
||||
}
|
||||
|
||||
func freeStack(p *_Stack) {
|
||||
p.sp = 0
|
||||
stackPool.Put(p)
|
||||
}
|
||||
|
||||
func freeBuffer(p *bytes.Buffer) {
|
||||
p.Reset()
|
||||
bufferPool.Put(p)
|
||||
}
|
||||
|
||||
func makeEncoder(vt *rt.GoType, ex ...interface{}) (interface{}, error) {
|
||||
if pp, err := newCompiler().compile(vt.Pack(), ex[0].(bool)); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
as := newAssembler(pp)
|
||||
as.name = vt.String()
|
||||
return as.Load(), nil
|
||||
}
|
||||
}
|
||||
|
||||
func findOrCompile(vt *rt.GoType, pv bool) (_Encoder, error) {
|
||||
if val := programCache.Get(vt); val != nil {
|
||||
return val.(_Encoder), nil
|
||||
} else if ret, err := programCache.Compute(vt, makeEncoder, pv); err == nil {
|
||||
return ret.(_Encoder), nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func pretouchType(_vt reflect.Type, opts option.CompileOptions, v uint8) (map[reflect.Type]uint8, error) {
|
||||
/* compile function */
|
||||
compiler := newCompiler().apply(opts)
|
||||
encoder := func(vt *rt.GoType, ex ...interface{}) (interface{}, error) {
|
||||
if pp, err := compiler.compile(_vt, ex[0].(bool)); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
as := newAssembler(pp)
|
||||
as.name = vt.String()
|
||||
return as.Load(), nil
|
||||
}
|
||||
}
|
||||
|
||||
/* find or compile */
|
||||
vt := rt.UnpackType(_vt)
|
||||
if val := programCache.Get(vt); val != nil {
|
||||
return nil, nil
|
||||
} else if _, err := programCache.Compute(vt, encoder, v == 1); err == nil {
|
||||
return compiler.rec, nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func pretouchRec(vtm map[reflect.Type]uint8, opts option.CompileOptions) error {
|
||||
if opts.RecursiveDepth < 0 || len(vtm) == 0 {
|
||||
return nil
|
||||
}
|
||||
next := make(map[reflect.Type]uint8)
|
||||
for vt, v := range vtm {
|
||||
sub, err := pretouchType(vt, opts, v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for svt, v := range sub {
|
||||
next[svt] = v
|
||||
}
|
||||
}
|
||||
opts.RecursiveDepth -= 1
|
||||
return pretouchRec(next, opts)
|
||||
}
|
97
vendor/github.com/bytedance/sonic/internal/encoder/pools_amd64.go
generated
vendored
Normal file
97
vendor/github.com/bytedance/sonic/internal/encoder/pools_amd64.go
generated
vendored
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package encoder
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
"github.com/bytedance/sonic/internal/encoder/vars"
|
||||
"github.com/bytedance/sonic/internal/encoder/x86"
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
"github.com/bytedance/sonic/option"
|
||||
)
|
||||
|
||||
|
||||
func ForceUseJit() {
|
||||
x86.SetCompiler(makeEncoderX86)
|
||||
pretouchType = pretouchTypeX86
|
||||
encodeTypedPointer = x86.EncodeTypedPointer
|
||||
vars.UseVM = false
|
||||
}
|
||||
|
||||
func init() {
|
||||
if vars.UseVM {
|
||||
ForceUseVM()
|
||||
} else {
|
||||
ForceUseJit()
|
||||
}
|
||||
}
|
||||
|
||||
var _KeepAlive struct {
|
||||
rb *[]byte
|
||||
vp unsafe.Pointer
|
||||
sb *vars.Stack
|
||||
fv uint64
|
||||
err error
|
||||
frame [x86.FP_offs]byte
|
||||
}
|
||||
|
||||
var errCallShadow = errors.New("DON'T CALL THIS!")
|
||||
|
||||
// Faker func of _Encoder, used to export its stackmap as _Encoder's
|
||||
func _Encoder_Shadow(rb *[]byte, vp unsafe.Pointer, sb *vars.Stack, fv uint64) (err error) {
|
||||
// align to assembler_amd64.go: x86.FP_offs
|
||||
var frame [x86.FP_offs]byte
|
||||
|
||||
// must keep all args and frames noticeable to GC
|
||||
_KeepAlive.rb = rb
|
||||
_KeepAlive.vp = vp
|
||||
_KeepAlive.sb = sb
|
||||
_KeepAlive.fv = fv
|
||||
_KeepAlive.err = err
|
||||
_KeepAlive.frame = frame
|
||||
|
||||
return errCallShadow
|
||||
}
|
||||
|
||||
func makeEncoderX86(vt *rt.GoType, ex ...interface{}) (interface{}, error) {
|
||||
pp, err := NewCompiler().Compile(vt.Pack(), ex[0].(bool))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
as := x86.NewAssembler(pp)
|
||||
as.Name = vt.String()
|
||||
return as.Load(), nil
|
||||
}
|
||||
|
||||
func pretouchTypeX86(_vt reflect.Type, opts option.CompileOptions, v uint8) (map[reflect.Type]uint8, error) {
|
||||
/* compile function */
|
||||
compiler := NewCompiler().apply(opts)
|
||||
|
||||
/* find or compile */
|
||||
vt := rt.UnpackType(_vt)
|
||||
if val := vars.GetProgram(vt); val != nil {
|
||||
return nil, nil
|
||||
} else if _, err := vars.ComputeProgram(vt, makeEncoderX86, v == 1); err == nil {
|
||||
return compiler.rec, nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
24
vendor/github.com/bytedance/sonic/internal/encoder/pools_compt.go
generated
vendored
Normal file
24
vendor/github.com/bytedance/sonic/internal/encoder/pools_compt.go
generated
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
//go:build !amd64
|
||||
// +build !amd64
|
||||
|
||||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package encoder
|
||||
|
||||
func init() {
|
||||
ForceUseVM()
|
||||
}
|
167
vendor/github.com/bytedance/sonic/internal/encoder/primitives.go
generated
vendored
167
vendor/github.com/bytedance/sonic/internal/encoder/primitives.go
generated
vendored
|
@ -1,167 +0,0 @@
|
|||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package encoder
|
||||
|
||||
import (
|
||||
`encoding`
|
||||
`encoding/json`
|
||||
`unsafe`
|
||||
|
||||
`github.com/bytedance/sonic/internal/jit`
|
||||
`github.com/bytedance/sonic/internal/native`
|
||||
`github.com/bytedance/sonic/internal/native/types`
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
)
|
||||
|
||||
/** Encoder Primitives **/
|
||||
|
||||
func encodeNil(rb *[]byte) error {
|
||||
*rb = append(*rb, 'n', 'u', 'l', 'l')
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeString(buf *[]byte, val string) error {
|
||||
var sidx int
|
||||
var pbuf *rt.GoSlice
|
||||
var pstr *rt.GoString
|
||||
|
||||
/* opening quote */
|
||||
*buf = append(*buf, '"')
|
||||
pbuf = (*rt.GoSlice)(unsafe.Pointer(buf))
|
||||
pstr = (*rt.GoString)(unsafe.Pointer(&val))
|
||||
|
||||
/* encode with native library */
|
||||
for sidx < pstr.Len {
|
||||
sn := pstr.Len - sidx
|
||||
dn := pbuf.Cap - pbuf.Len
|
||||
sp := padd(pstr.Ptr, sidx)
|
||||
dp := padd(pbuf.Ptr, pbuf.Len)
|
||||
nb := native.Quote(sp, sn, dp, &dn, 0)
|
||||
|
||||
/* check for errors */
|
||||
if pbuf.Len += dn; nb >= 0 {
|
||||
break
|
||||
}
|
||||
|
||||
/* not enough space, grow the slice and try again */
|
||||
sidx += ^nb
|
||||
*pbuf = growslice(rt.UnpackType(byteType), *pbuf, pbuf.Cap * 2)
|
||||
}
|
||||
|
||||
/* closing quote */
|
||||
*buf = append(*buf, '"')
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeTypedPointer(buf *[]byte, vt *rt.GoType, vp *unsafe.Pointer, sb *_Stack, fv uint64) error {
|
||||
if vt == nil {
|
||||
return encodeNil(buf)
|
||||
} else if fn, err := findOrCompile(vt, (fv&(1<<bitPointerValue)) != 0); err != nil {
|
||||
return err
|
||||
} else if vt.Indirect() {
|
||||
rt.MoreStack(_FP_size + native.MaxFrameSize)
|
||||
err := fn(buf, *vp, sb, fv)
|
||||
return err
|
||||
} else {
|
||||
rt.MoreStack(_FP_size + native.MaxFrameSize)
|
||||
err := fn(buf, unsafe.Pointer(vp), sb, fv)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func encodeJsonMarshaler(buf *[]byte, val json.Marshaler, opt Options) error {
|
||||
if ret, err := val.MarshalJSON(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
if opt & CompactMarshaler != 0 {
|
||||
return compact(buf, ret)
|
||||
}
|
||||
if opt & NoValidateJSONMarshaler == 0 {
|
||||
if ok, s := Valid(ret); !ok {
|
||||
return error_marshaler(ret, s)
|
||||
}
|
||||
}
|
||||
*buf = append(*buf, ret...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func encodeTextMarshaler(buf *[]byte, val encoding.TextMarshaler, opt Options) error {
|
||||
if ret, err := val.MarshalText(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
if opt & NoQuoteTextMarshaler != 0 {
|
||||
*buf = append(*buf, ret...)
|
||||
return nil
|
||||
}
|
||||
return encodeString(buf, rt.Mem2Str(ret) )
|
||||
}
|
||||
}
|
||||
|
||||
func htmlEscape(dst []byte, src []byte) []byte {
|
||||
var sidx int
|
||||
|
||||
dst = append(dst, src[:0]...) // avoid check nil dst
|
||||
sbuf := (*rt.GoSlice)(unsafe.Pointer(&src))
|
||||
dbuf := (*rt.GoSlice)(unsafe.Pointer(&dst))
|
||||
|
||||
/* grow dst if it is shorter */
|
||||
if cap(dst) - len(dst) < len(src) + types.BufPaddingSize {
|
||||
cap := len(src) * 3 / 2 + types.BufPaddingSize
|
||||
*dbuf = growslice(typeByte, *dbuf, cap)
|
||||
}
|
||||
|
||||
for sidx < sbuf.Len {
|
||||
sp := padd(sbuf.Ptr, sidx)
|
||||
dp := padd(dbuf.Ptr, dbuf.Len)
|
||||
|
||||
sn := sbuf.Len - sidx
|
||||
dn := dbuf.Cap - dbuf.Len
|
||||
nb := native.HTMLEscape(sp, sn, dp, &dn)
|
||||
|
||||
/* check for errors */
|
||||
if dbuf.Len += dn; nb >= 0 {
|
||||
break
|
||||
}
|
||||
|
||||
/* not enough space, grow the slice and try again */
|
||||
sidx += ^nb
|
||||
*dbuf = growslice(typeByte, *dbuf, dbuf.Cap * 2)
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
var (
|
||||
argPtrs = []bool { true, true, true, false }
|
||||
localPtrs = []bool{}
|
||||
)
|
||||
|
||||
var (
|
||||
_F_assertI2I = jit.Func(rt.AssertI2I2)
|
||||
)
|
||||
|
||||
func asText(v unsafe.Pointer) (string, error) {
|
||||
text := rt.AssertI2I2(_T_encoding_TextMarshaler, *(*rt.GoIface)(v))
|
||||
r, e := (*(*encoding.TextMarshaler)(unsafe.Pointer(&text))).MarshalText()
|
||||
return rt.Mem2Str(r), e
|
||||
}
|
||||
|
||||
func asJson(v unsafe.Pointer) (string, error) {
|
||||
text := rt.AssertI2I2(_T_json_Marshaler, *(*rt.GoIface)(v))
|
||||
r, e := (*(*json.Marshaler)(unsafe.Pointer(&text))).MarshalJSON()
|
||||
return rt.Mem2Str(r), e
|
||||
}
|
28
vendor/github.com/bytedance/sonic/internal/encoder/stream.go
generated
vendored
28
vendor/github.com/bytedance/sonic/internal/encoder/stream.go
generated
vendored
|
@ -17,8 +17,10 @@
|
|||
package encoder
|
||||
|
||||
import (
|
||||
`encoding/json`
|
||||
`io`
|
||||
"encoding/json"
|
||||
"io"
|
||||
|
||||
"github.com/bytedance/sonic/internal/encoder/vars"
|
||||
)
|
||||
|
||||
// StreamEncoder uses io.Writer as input.
|
||||
|
@ -36,21 +38,20 @@ func NewStreamEncoder(w io.Writer) *StreamEncoder {
|
|||
|
||||
// Encode encodes interface{} as JSON to io.Writer
|
||||
func (enc *StreamEncoder) Encode(val interface{}) (err error) {
|
||||
buf := newBytes()
|
||||
out := buf
|
||||
out := vars.NewBytes()
|
||||
|
||||
/* encode into the buffer */
|
||||
err = EncodeInto(&out, val, enc.Opts)
|
||||
err = EncodeInto(out, val, enc.Opts)
|
||||
if err != nil {
|
||||
goto free_bytes
|
||||
}
|
||||
|
||||
if enc.indent != "" || enc.prefix != "" {
|
||||
/* indent the JSON */
|
||||
buf := newBuffer()
|
||||
err = json.Indent(buf, out, enc.prefix, enc.indent)
|
||||
buf := vars.NewBuffer()
|
||||
err = json.Indent(buf, *out, enc.prefix, enc.indent)
|
||||
if err != nil {
|
||||
freeBuffer(buf)
|
||||
vars.FreeBuffer(buf)
|
||||
goto free_bytes
|
||||
}
|
||||
|
||||
|
@ -62,16 +63,17 @@ func (enc *StreamEncoder) Encode(val interface{}) (err error) {
|
|||
/* copy into io.Writer */
|
||||
_, err = io.Copy(enc.w, buf)
|
||||
if err != nil {
|
||||
freeBuffer(buf)
|
||||
vars.FreeBuffer(buf)
|
||||
goto free_bytes
|
||||
}
|
||||
|
||||
} else {
|
||||
/* copy into io.Writer */
|
||||
var n int
|
||||
for len(out) > 0 {
|
||||
n, err = enc.w.Write(out)
|
||||
out = out[n:]
|
||||
buf := *out
|
||||
for len(buf) > 0 {
|
||||
n, err = enc.w.Write(buf)
|
||||
buf = buf[n:]
|
||||
if err != nil {
|
||||
goto free_bytes
|
||||
}
|
||||
|
@ -84,6 +86,6 @@ func (enc *StreamEncoder) Encode(val interface{}) (err error) {
|
|||
}
|
||||
|
||||
free_bytes:
|
||||
freeBytes(buf)
|
||||
vars.FreeBytes(out)
|
||||
return err
|
||||
}
|
||||
|
|
61
vendor/github.com/bytedance/sonic/internal/encoder/stubs_go116.go
generated
vendored
61
vendor/github.com/bytedance/sonic/internal/encoder/stubs_go116.go
generated
vendored
|
@ -1,61 +0,0 @@
|
|||
// +build go1.16,!go1.17
|
||||
|
||||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package encoder
|
||||
|
||||
import (
|
||||
`unsafe`
|
||||
|
||||
_ `github.com/cloudwego/base64x`
|
||||
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
)
|
||||
|
||||
//go:linkname _subr__b64encode github.com/cloudwego/base64x._subr__b64encode
|
||||
var _subr__b64encode uintptr
|
||||
|
||||
//go:noescape
|
||||
//go:linkname memmove runtime.memmove
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr)
|
||||
|
||||
//go:linkname growslice runtime.growslice
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func growslice(et *rt.GoType, old rt.GoSlice, cap int) rt.GoSlice
|
||||
|
||||
//go:linkname mapiternext runtime.mapiternext
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mapiternext(it *rt.GoMapIterator)
|
||||
|
||||
//go:linkname mapiterinit runtime.mapiterinit
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mapiterinit(t *rt.GoMapType, m *rt.GoMap, it *rt.GoMapIterator)
|
||||
|
||||
//go:linkname isValidNumber encoding/json.isValidNumber
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func isValidNumber(s string) bool
|
||||
|
||||
//go:noescape
|
||||
//go:linkname memclrNoHeapPointers runtime.memclrNoHeapPointers
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
|
||||
|
||||
var _runtime_writeBarrier uintptr = rt.GcwbAddr()
|
||||
|
||||
//go:linkname gcWriteBarrierAX runtime.gcWriteBarrier
|
||||
func gcWriteBarrierAX()
|
62
vendor/github.com/bytedance/sonic/internal/encoder/stubs_go117.go
generated
vendored
62
vendor/github.com/bytedance/sonic/internal/encoder/stubs_go117.go
generated
vendored
|
@ -1,62 +0,0 @@
|
|||
// +build go1.17,!go1.20
|
||||
|
||||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package encoder
|
||||
|
||||
import (
|
||||
`unsafe`
|
||||
|
||||
_ `github.com/cloudwego/base64x`
|
||||
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
)
|
||||
|
||||
//go:linkname _subr__b64encode github.com/cloudwego/base64x._subr__b64encode
|
||||
var _subr__b64encode uintptr
|
||||
|
||||
//go:noescape
|
||||
//go:linkname memmove runtime.memmove
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr)
|
||||
|
||||
//go:linkname growslice runtime.growslice
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func growslice(et *rt.GoType, old rt.GoSlice, cap int) rt.GoSlice
|
||||
|
||||
//go:linkname mapiternext runtime.mapiternext
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mapiternext(it *rt.GoMapIterator)
|
||||
|
||||
//go:linkname mapiterinit runtime.mapiterinit
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mapiterinit(t *rt.GoMapType, m *rt.GoMap, it *rt.GoMapIterator)
|
||||
|
||||
//go:linkname isValidNumber encoding/json.isValidNumber
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func isValidNumber(s string) bool
|
||||
|
||||
//go:noescape
|
||||
//go:linkname memclrNoHeapPointers runtime.memclrNoHeapPointers
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
|
||||
|
||||
//go:linkname _runtime_writeBarrier runtime.writeBarrier
|
||||
var _runtime_writeBarrier uintptr
|
||||
|
||||
//go:linkname gcWriteBarrierAX runtime.gcWriteBarrier
|
||||
func gcWriteBarrierAX()
|
62
vendor/github.com/bytedance/sonic/internal/encoder/stubs_go120.go
generated
vendored
62
vendor/github.com/bytedance/sonic/internal/encoder/stubs_go120.go
generated
vendored
|
@ -1,62 +0,0 @@
|
|||
// +build go1.20,!go1.21
|
||||
|
||||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package encoder
|
||||
|
||||
import (
|
||||
`unsafe`
|
||||
|
||||
_ `github.com/cloudwego/base64x`
|
||||
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
)
|
||||
|
||||
//go:linkname _subr__b64encode github.com/cloudwego/base64x._subr__b64encode
|
||||
var _subr__b64encode uintptr
|
||||
|
||||
//go:noescape
|
||||
//go:linkname memmove runtime.memmove
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr)
|
||||
|
||||
//go:linkname growslice reflect.growslice
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func growslice(et *rt.GoType, old rt.GoSlice, cap int) rt.GoSlice
|
||||
|
||||
//go:linkname mapiternext runtime.mapiternext
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mapiternext(it *rt.GoMapIterator)
|
||||
|
||||
//go:linkname mapiterinit runtime.mapiterinit
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mapiterinit(t *rt.GoMapType, m *rt.GoMap, it *rt.GoMapIterator)
|
||||
|
||||
//go:linkname isValidNumber encoding/json.isValidNumber
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func isValidNumber(s string) bool
|
||||
|
||||
//go:noescape
|
||||
//go:linkname memclrNoHeapPointers runtime.memclrNoHeapPointers
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
|
||||
|
||||
//go:linkname _runtime_writeBarrier runtime.writeBarrier
|
||||
var _runtime_writeBarrier uintptr
|
||||
|
||||
//go:linkname gcWriteBarrierAX runtime.gcWriteBarrier
|
||||
func gcWriteBarrierAX()
|
62
vendor/github.com/bytedance/sonic/internal/encoder/stubs_go121.go
generated
vendored
62
vendor/github.com/bytedance/sonic/internal/encoder/stubs_go121.go
generated
vendored
|
@ -1,62 +0,0 @@
|
|||
// +build go1.21
|
||||
|
||||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package encoder
|
||||
|
||||
import (
|
||||
`unsafe`
|
||||
|
||||
_ `github.com/cloudwego/base64x`
|
||||
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
)
|
||||
|
||||
//go:linkname _subr__b64encode github.com/cloudwego/base64x._subr__b64encode
|
||||
var _subr__b64encode uintptr
|
||||
|
||||
//go:noescape
|
||||
//go:linkname memmove runtime.memmove
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr)
|
||||
|
||||
//go:linkname growslice reflect.growslice
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func growslice(et *rt.GoType, old rt.GoSlice, cap int) rt.GoSlice
|
||||
|
||||
//go:linkname mapiternext runtime.mapiternext
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mapiternext(it *rt.GoMapIterator)
|
||||
|
||||
//go:linkname mapiterinit runtime.mapiterinit
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mapiterinit(t *rt.GoMapType, m *rt.GoMap, it *rt.GoMapIterator)
|
||||
|
||||
//go:linkname isValidNumber encoding/json.isValidNumber
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func isValidNumber(s string) bool
|
||||
|
||||
//go:noescape
|
||||
//go:linkname memclrNoHeapPointers runtime.memclrNoHeapPointers
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
|
||||
|
||||
//go:linkname _runtime_writeBarrier runtime.writeBarrier
|
||||
var _runtime_writeBarrier uintptr
|
||||
|
||||
//go:linkname gcWriteBarrier2 runtime.gcWriteBarrier2
|
||||
func gcWriteBarrier2()
|
52
vendor/github.com/bytedance/sonic/internal/encoder/utils.go
generated
vendored
52
vendor/github.com/bytedance/sonic/internal/encoder/utils.go
generated
vendored
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package encoder
|
||||
|
||||
import (
|
||||
`encoding/json`
|
||||
`unsafe`
|
||||
|
||||
`github.com/bytedance/sonic/loader`
|
||||
)
|
||||
|
||||
//go:nosplit
|
||||
func padd(p unsafe.Pointer, v int) unsafe.Pointer {
|
||||
return unsafe.Pointer(uintptr(p) + uintptr(v))
|
||||
}
|
||||
|
||||
//go:nosplit
|
||||
func ptoenc(p loader.Function) _Encoder {
|
||||
return *(*_Encoder)(unsafe.Pointer(&p))
|
||||
}
|
||||
|
||||
func compact(p *[]byte, v []byte) error {
|
||||
buf := newBuffer()
|
||||
err := json.Compact(buf, v)
|
||||
|
||||
/* check for errors */
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
/* add to result */
|
||||
v = buf.Bytes()
|
||||
*p = append(*p, v...)
|
||||
|
||||
/* return the buffer into pool */
|
||||
freeBuffer(buf)
|
||||
return nil
|
||||
}
|
48
vendor/github.com/bytedance/sonic/internal/encoder/vars/cache.go
generated
vendored
Normal file
48
vendor/github.com/bytedance/sonic/internal/encoder/vars/cache.go
generated
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 2021 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package vars
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
)
|
||||
|
||||
type Encoder func(
|
||||
rb *[]byte,
|
||||
vp unsafe.Pointer,
|
||||
sb *Stack,
|
||||
fv uint64,
|
||||
) error
|
||||
|
||||
func FindOrCompile(vt *rt.GoType, pv bool, compiler func(*rt.GoType, ... interface{}) (interface{}, error)) (interface{}, error) {
|
||||
if val := programCache.Get(vt); val != nil {
|
||||
return val, nil
|
||||
} else if ret, err := programCache.Compute(vt, compiler, pv); err == nil {
|
||||
return ret, nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func GetProgram(vt *rt.GoType) (interface{}) {
|
||||
return programCache.Get(vt)
|
||||
}
|
||||
|
||||
func ComputeProgram(vt *rt.GoType, compute func(*rt.GoType, ... interface{}) (interface{}, error), pv bool) (interface{}, error) {
|
||||
return programCache.Compute(vt, compute, pv)
|
||||
}
|
42
vendor/github.com/bytedance/sonic/internal/encoder/vars/const.go
generated
vendored
Normal file
42
vendor/github.com/bytedance/sonic/internal/encoder/vars/const.go
generated
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* Copyright 2024 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package vars
|
||||
|
||||
import (
|
||||
"os"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
MaxStack = 4096 // 4k states
|
||||
StackSize = unsafe.Sizeof(Stack{})
|
||||
StateSize = int64(unsafe.Sizeof(State{}))
|
||||
StackLimit = MaxStack * StateSize
|
||||
)
|
||||
|
||||
const (
|
||||
MAX_ILBUF = 100000 // cutoff at 100k of IL instructions
|
||||
MAX_FIELDS = 50 // cutoff at 50 fields struct
|
||||
)
|
||||
|
||||
var (
|
||||
DebugSyncGC = os.Getenv("SONIC_SYNC_GC") != ""
|
||||
DebugAsyncGC = os.Getenv("SONIC_NO_ASYNC_GC") == ""
|
||||
DebugCheckPtr = os.Getenv("SONIC_CHECK_POINTER") != ""
|
||||
)
|
||||
|
||||
var UseVM = os.Getenv("SONIC_ENCODER_USE_VM") != ""
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package encoder
|
||||
package vars
|
||||
|
||||
import (
|
||||
`encoding/json`
|
||||
|
@ -26,39 +26,39 @@
|
|||
`github.com/bytedance/sonic/internal/rt`
|
||||
)
|
||||
|
||||
var _ERR_too_deep = &json.UnsupportedValueError {
|
||||
var ERR_too_deep = &json.UnsupportedValueError {
|
||||
Str : "Value nesting too deep",
|
||||
Value : reflect.ValueOf("..."),
|
||||
}
|
||||
|
||||
var _ERR_nan_or_infinite = &json.UnsupportedValueError {
|
||||
var ERR_nan_or_infinite = &json.UnsupportedValueError {
|
||||
Str : "NaN or ±Infinite",
|
||||
Value : reflect.ValueOf("NaN or ±Infinite"),
|
||||
}
|
||||
|
||||
func error_type(vtype reflect.Type) error {
|
||||
func Error_type(vtype reflect.Type) error {
|
||||
return &json.UnsupportedTypeError{Type: vtype}
|
||||
}
|
||||
|
||||
func error_number(number json.Number) error {
|
||||
func Error_number(number json.Number) error {
|
||||
return &json.UnsupportedValueError {
|
||||
Str : "invalid number literal: " + strconv.Quote(string(number)),
|
||||
Value : reflect.ValueOf(number),
|
||||
}
|
||||
}
|
||||
|
||||
func error_marshaler(ret []byte, pos int) error {
|
||||
func Error_marshaler(ret []byte, pos int) error {
|
||||
return fmt.Errorf("invalid Marshaler output json syntax at %d: %q", pos, ret)
|
||||
}
|
||||
|
||||
const (
|
||||
panicNilPointerOfNonEmptyString int = 1 + iota
|
||||
PanicNilPointerOfNonEmptyString int = 1 + iota
|
||||
)
|
||||
|
||||
func goPanic(code int, val unsafe.Pointer) {
|
||||
func GoPanic(code int, val unsafe.Pointer) {
|
||||
switch(code){
|
||||
case panicNilPointerOfNonEmptyString:
|
||||
panic(fmt.Sprintf("val: %#v has nil pointer while its length is not zero!", (*rt.GoString)(val)))
|
||||
case PanicNilPointerOfNonEmptyString:
|
||||
panic(fmt.Sprintf("val: %#v has nil pointer while its length is not zero!\nThis is a nil pointer exception (NPE) problem. There might be a data race issue. It is recommended to execute the tests related to the code with the `-race` compile flag to detect the problem.", (*rt.GoString)(val)))
|
||||
default:
|
||||
panic("encoder error!")
|
||||
}
|
146
vendor/github.com/bytedance/sonic/internal/encoder/vars/stack.go
generated
vendored
Normal file
146
vendor/github.com/bytedance/sonic/internal/encoder/vars/stack.go
generated
vendored
Normal file
|
@ -0,0 +1,146 @@
|
|||
/**
|
||||
* Copyright 2024 ByteDance Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package vars
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"github.com/bytedance/sonic/internal/caching"
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
"github.com/bytedance/sonic/option"
|
||||
)
|
||||
|
||||
type State struct {
|
||||
x int
|
||||
f uint64
|
||||
p unsafe.Pointer
|
||||
q unsafe.Pointer
|
||||
}
|
||||
|
||||
type Stack struct {
|
||||
sp uintptr
|
||||
sb [MaxStack]State
|
||||
}
|
||||
|
||||
var (
|
||||
bytesPool = sync.Pool{}
|
||||
stackPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return &Stack{}
|
||||
},
|
||||
}
|
||||
bufferPool = sync.Pool{}
|
||||
programCache = caching.CreateProgramCache()
|
||||
)
|
||||
|
||||
func NewBytes() *[]byte {
|
||||
if ret := bytesPool.Get(); ret != nil {
|
||||
return ret.(*[]byte)
|
||||
} else {
|
||||
ret := make([]byte, 0, option.DefaultEncoderBufferSize)
|
||||
return &ret
|
||||
}
|
||||
}
|
||||
|
||||
func NewStack() *Stack {
|
||||
ret := stackPool.Get().(*Stack)
|
||||
ret.sp = 0
|
||||
return ret
|
||||
}
|
||||
|
||||
func ResetStack(p *Stack) {
|
||||
rt.MemclrNoHeapPointers(unsafe.Pointer(p), StackSize)
|
||||
}
|
||||
|
||||
func (s *Stack) Top() *State {
|
||||
return (*State)(rt.Add(unsafe.Pointer(&s.sb[0]), s.sp))
|
||||
}
|
||||
|
||||
func (s *Stack) Cur() *State {
|
||||
return (*State)(rt.Add(unsafe.Pointer(&s.sb[0]), s.sp - uintptr(StateSize)))
|
||||
}
|
||||
|
||||
const _MaxStackSP = uintptr(MaxStack * StateSize)
|
||||
|
||||
func (s *Stack) Push(v State) bool {
|
||||
if uintptr(s.sp) >= _MaxStackSP {
|
||||
return false
|
||||
}
|
||||
st := s.Top()
|
||||
*st = v
|
||||
s.sp += uintptr(StateSize)
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *Stack) Pop() State {
|
||||
s.sp -= uintptr(StateSize)
|
||||
st := s.Top()
|
||||
ret := *st
|
||||
*st = State{}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (s *Stack) Load() (int, uint64, unsafe.Pointer, unsafe.Pointer) {
|
||||
st := s.Cur()
|
||||
return st.x, st.f, st.p, st.q
|
||||
}
|
||||
|
||||
func (s *Stack) Save(x int, f uint64, p unsafe.Pointer, q unsafe.Pointer) bool {
|
||||
return s.Push(State{x: x, f:f, p: p, q: q})
|
||||
}
|
||||
|
||||
func (s *Stack) Drop() (int, uint64, unsafe.Pointer, unsafe.Pointer) {
|
||||
st := s.Pop()
|
||||
return st.x, st.f, st.p, st.q
|
||||
}
|
||||
|
||||
func NewBuffer() *bytes.Buffer {
|
||||
if ret := bufferPool.Get(); ret != nil {
|
||||
return ret.(*bytes.Buffer)
|
||||
} else {
|
||||
return bytes.NewBuffer(make([]byte, 0, option.DefaultEncoderBufferSize))
|
||||
}
|
||||
}
|
||||
|
||||
func FreeBytes(p *[]byte) {
|
||||
if rt.CanSizeResue(cap(*p)) {
|
||||
(*p) = (*p)[:0]
|
||||
bytesPool.Put(p)
|
||||
}
|
||||
}
|
||||
|
||||
func FreeStack(p *Stack) {
|
||||
p.sp = 0
|
||||
stackPool.Put(p)
|
||||
}
|
||||
|
||||
func FreeBuffer(p *bytes.Buffer) {
|
||||
if rt.CanSizeResue(cap(p.Bytes())) {
|
||||
p.Reset()
|
||||
bufferPool.Put(p)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
ArgPtrs = []bool{true, true, true, false}
|
||||
LocalPtrs = []bool{}
|
||||
|
||||
ArgPtrs_generic = []bool{true}
|
||||
LocalPtrs_generic = []bool{}
|
||||
)
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package encoder
|
||||
package vars
|
||||
|
||||
import (
|
||||
`encoding`
|
||||
|
@ -23,19 +23,19 @@
|
|||
)
|
||||
|
||||
var (
|
||||
byteType = reflect.TypeOf(byte(0))
|
||||
jsonNumberType = reflect.TypeOf(json.Number(""))
|
||||
jsonUnsupportedValueType = reflect.TypeOf(new(json.UnsupportedValueError))
|
||||
ByteType = reflect.TypeOf(byte(0))
|
||||
JsonNumberType = reflect.TypeOf(json.Number(""))
|
||||
JsonUnsupportedValueType = reflect.TypeOf(new(json.UnsupportedValueError))
|
||||
)
|
||||
|
||||
var (
|
||||
errorType = reflect.TypeOf((*error)(nil)).Elem()
|
||||
jsonMarshalerType = reflect.TypeOf((*json.Marshaler)(nil)).Elem()
|
||||
encodingTextMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
|
||||
ErrorType = reflect.TypeOf((*error)(nil)).Elem()
|
||||
JsonMarshalerType = reflect.TypeOf((*json.Marshaler)(nil)).Elem()
|
||||
EncodingTextMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
|
||||
)
|
||||
|
||||
func isSimpleByte(vt reflect.Type) bool {
|
||||
if vt.Kind() != byteType.Kind() {
|
||||
func IsSimpleByte(vt reflect.Type) bool {
|
||||
if vt.Kind() != ByteType.Kind() {
|
||||
return false
|
||||
} else {
|
||||
return !isEitherMarshaler(vt) && !isEitherMarshaler(reflect.PtrTo(vt))
|
||||
|
@ -43,5 +43,5 @@ func isSimpleByte(vt reflect.Type) bool {
|
|||
}
|
||||
|
||||
func isEitherMarshaler(vt reflect.Type) bool {
|
||||
return vt.Implements(jsonMarshalerType) || vt.Implements(encodingTextMarshalerType)
|
||||
return vt.Implements(JsonMarshalerType) || vt.Implements(EncodingTextMarshalerType)
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue