mirror of
https://github.com/ii64/sonic.git
synced 2026-06-21 00:46:43 +08:00
* feat: make compilation depth changeable * feat: add option `DefaultMaxInlineDepth` * add recurse depth = 10 * refactor * doc: readme and comment * opt: add `_MAX_FIELDS` to limit the inlining of big struct * update license * fix typo
375 lines
No EOL
17 KiB
Go
375 lines
No EOL
17 KiB
Go
/*
|
|
* 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 issue_test
|
|
|
|
import (
|
|
`bytes`
|
|
`compress/gzip`
|
|
`encoding/json`
|
|
`io/ioutil`
|
|
`reflect`
|
|
`testing`
|
|
`time`
|
|
|
|
. `github.com/bytedance/sonic`
|
|
`github.com/bytedance/sonic/option`
|
|
`github.com/stretchr/testify/require`
|
|
)
|
|
|
|
var jsonData = func() string {
|
|
// Read and decompress the test data.
|
|
b, err := ioutil.ReadFile("../testdata/synthea_fhir.json.gz")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
zr, err := gzip.NewReader(bytes.NewReader(b))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
data, err := ioutil.ReadAll(zr)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return string(data)
|
|
}()
|
|
|
|
type (
|
|
syntheaRoot struct {
|
|
Entry []struct {
|
|
FullURL string `json:"fullUrl"`
|
|
Request *struct {
|
|
Method string `json:"method"`
|
|
URL string `json:"url"`
|
|
} `json:"request"`
|
|
Resource *struct {
|
|
AbatementDateTime time.Time `json:"abatementDateTime"`
|
|
AchievementStatus syntheaCode `json:"achievementStatus"`
|
|
Active bool `json:"active"`
|
|
Activity []struct {
|
|
Detail *struct {
|
|
Code syntheaCode `json:"code"`
|
|
Location syntheaReference `json:"location"`
|
|
Status string `json:"status"`
|
|
} `json:"detail"`
|
|
} `json:"activity"`
|
|
Address []syntheaAddress `json:"address"`
|
|
Addresses []syntheaReference `json:"addresses"`
|
|
AuthoredOn time.Time `json:"authoredOn"`
|
|
BillablePeriod syntheaRange `json:"billablePeriod"`
|
|
BirthDate string `json:"birthDate"`
|
|
CareTeam []struct {
|
|
Provider syntheaReference `json:"provider"`
|
|
Reference string `json:"reference"`
|
|
Role syntheaCode `json:"role"`
|
|
Sequence int64 `json:"sequence"`
|
|
} `json:"careTeam"`
|
|
Category []syntheaCode `json:"category"`
|
|
Claim syntheaReference `json:"claim"`
|
|
Class syntheaCoding `json:"class"`
|
|
ClinicalStatus syntheaCode `json:"clinicalStatus"`
|
|
Code syntheaCode `json:"code"`
|
|
Communication []struct {
|
|
Language syntheaCode `json:"language"`
|
|
} `json:"communication"`
|
|
Component []struct {
|
|
Code syntheaCode `json:"code"`
|
|
ValueQuantity syntheaCoding `json:"valueQuantity"`
|
|
} `json:"component"`
|
|
Contained []struct {
|
|
Beneficiary syntheaReference `json:"beneficiary"`
|
|
ID string `json:"id"`
|
|
Intent string `json:"intent"`
|
|
Payor []syntheaReference `json:"payor"`
|
|
Performer []syntheaReference `json:"performer"`
|
|
Requester syntheaReference `json:"requester"`
|
|
ResourceType string `json:"resourceType"`
|
|
Status string `json:"status"`
|
|
Subject syntheaReference `json:"subject"`
|
|
Type syntheaCode `json:"type"`
|
|
} `json:"contained"`
|
|
Created time.Time `json:"created"`
|
|
DeceasedDateTime time.Time `json:"deceasedDateTime"`
|
|
Description syntheaCode `json:"description"`
|
|
Diagnosis []struct {
|
|
DiagnosisReference syntheaReference `json:"diagnosisReference"`
|
|
Sequence int64 `json:"sequence"`
|
|
Type []syntheaCode `json:"type"`
|
|
} `json:"diagnosis"`
|
|
DosageInstruction []struct {
|
|
AsNeededBoolean bool `json:"asNeededBoolean"`
|
|
DoseAndRate []struct {
|
|
DoseQuantity *struct {
|
|
Value float64 `json:"value"`
|
|
} `json:"doseQuantity"`
|
|
Type syntheaCode `json:"type"`
|
|
} `json:"doseAndRate"`
|
|
Sequence int64 `json:"sequence"`
|
|
Timing *struct {
|
|
Repeat *struct {
|
|
Frequency int64 `json:"frequency"`
|
|
Period float64 `json:"period"`
|
|
PeriodUnit string `json:"periodUnit"`
|
|
} `json:"repeat"`
|
|
} `json:"timing"`
|
|
} `json:"dosageInstruction"`
|
|
EffectiveDateTime time.Time `json:"effectiveDateTime"`
|
|
Encounter syntheaReference `json:"encounter"`
|
|
Extension []syntheaExtension `json:"extension"`
|
|
Gender string `json:"gender"`
|
|
Goal []syntheaReference `json:"goal"`
|
|
ID string `json:"id"`
|
|
Identifier []struct {
|
|
System string `json:"system"`
|
|
Type syntheaCode `json:"type"`
|
|
Use string `json:"use"`
|
|
Value string `json:"value"`
|
|
} `json:"identifier"`
|
|
Insurance []struct {
|
|
Coverage syntheaReference `json:"coverage"`
|
|
Focal bool `json:"focal"`
|
|
Sequence int64 `json:"sequence"`
|
|
} `json:"insurance"`
|
|
Insurer syntheaReference `json:"insurer"`
|
|
Intent string `json:"intent"`
|
|
Issued time.Time `json:"issued"`
|
|
Item []struct {
|
|
Adjudication []struct {
|
|
Amount syntheaCurrency `json:"amount"`
|
|
Category syntheaCode `json:"category"`
|
|
} `json:"adjudication"`
|
|
Category syntheaCode `json:"category"`
|
|
DiagnosisSequence []int64 `json:"diagnosisSequence"`
|
|
Encounter []syntheaReference `json:"encounter"`
|
|
InformationSequence []int64 `json:"informationSequence"`
|
|
LocationCodeableConcept syntheaCode `json:"locationCodeableConcept"`
|
|
Net syntheaCurrency `json:"net"`
|
|
ProcedureSequence []int64 `json:"procedureSequence"`
|
|
ProductOrService syntheaCode `json:"productOrService"`
|
|
Sequence int64 `json:"sequence"`
|
|
ServicedPeriod syntheaRange `json:"servicedPeriod"`
|
|
} `json:"item"`
|
|
LifecycleStatus string `json:"lifecycleStatus"`
|
|
ManagingOrganization []syntheaReference `json:"managingOrganization"`
|
|
MaritalStatus syntheaCode `json:"maritalStatus"`
|
|
MedicationCodeableConcept syntheaCode `json:"medicationCodeableConcept"`
|
|
MultipleBirthBoolean bool `json:"multipleBirthBoolean"`
|
|
Name json.RawMessage `json:"name"`
|
|
NumberOfInstances int64 `json:"numberOfInstances"`
|
|
NumberOfSeries int64 `json:"numberOfSeries"`
|
|
OccurrenceDateTime time.Time `json:"occurrenceDateTime"`
|
|
OnsetDateTime time.Time `json:"onsetDateTime"`
|
|
Outcome string `json:"outcome"`
|
|
Participant []struct {
|
|
Individual syntheaReference `json:"individual"`
|
|
Member syntheaReference `json:"member"`
|
|
Role []syntheaCode `json:"role"`
|
|
} `json:"participant"`
|
|
Patient syntheaReference `json:"patient"`
|
|
Payment *struct {
|
|
Amount syntheaCurrency `json:"amount"`
|
|
} `json:"payment"`
|
|
PerformedPeriod syntheaRange `json:"performedPeriod"`
|
|
Period syntheaRange `json:"period"`
|
|
Prescription syntheaReference `json:"prescription"`
|
|
PrimarySource bool `json:"primarySource"`
|
|
Priority syntheaCode `json:"priority"`
|
|
Procedure []struct {
|
|
ProcedureReference syntheaReference `json:"procedureReference"`
|
|
Sequence int64 `json:"sequence"`
|
|
} `json:"procedure"`
|
|
Provider syntheaReference `json:"provider"`
|
|
ReasonCode []syntheaCode `json:"reasonCode"`
|
|
ReasonReference []syntheaReference `json:"reasonReference"`
|
|
RecordedDate time.Time `json:"recordedDate"`
|
|
Referral syntheaReference `json:"referral"`
|
|
Requester syntheaReference `json:"requester"`
|
|
ResourceType string `json:"resourceType"`
|
|
Result []syntheaReference `json:"result"`
|
|
Series []struct {
|
|
BodySite syntheaCoding `json:"bodySite"`
|
|
Instance []struct {
|
|
Number int64 `json:"number"`
|
|
SopClass syntheaCoding `json:"sopClass"`
|
|
Title string `json:"title"`
|
|
UID string `json:"uid"`
|
|
} `json:"instance"`
|
|
Modality syntheaCoding `json:"modality"`
|
|
Number int64 `json:"number"`
|
|
NumberOfInstances int64 `json:"numberOfInstances"`
|
|
Started string `json:"started"`
|
|
UID string `json:"uid"`
|
|
} `json:"series"`
|
|
ServiceProvider syntheaReference `json:"serviceProvider"`
|
|
Started time.Time `json:"started"`
|
|
Status string `json:"status"`
|
|
Subject syntheaReference `json:"subject"`
|
|
SupportingInfo []struct {
|
|
Category syntheaCode `json:"category"`
|
|
Sequence int64 `json:"sequence"`
|
|
ValueReference syntheaReference `json:"valueReference"`
|
|
} `json:"supportingInfo"`
|
|
Telecom []map[string]string `json:"telecom"`
|
|
Text map[string]string `json:"text"`
|
|
Total json.RawMessage `json:"total"`
|
|
Type json.RawMessage `json:"type"`
|
|
Use string `json:"use"`
|
|
VaccineCode syntheaCode `json:"vaccineCode"`
|
|
ValueCodeableConcept syntheaCode `json:"valueCodeableConcept"`
|
|
ValueQuantity syntheaCoding `json:"valueQuantity"`
|
|
VerificationStatus syntheaCode `json:"verificationStatus"`
|
|
} `json:"resource"`
|
|
} `json:"entry"`
|
|
ResourceType string `json:"resourceType"`
|
|
Type string `json:"type"`
|
|
}
|
|
syntheaCode struct {
|
|
Coding []syntheaCoding `json:"coding"`
|
|
Text string `json:"text"`
|
|
}
|
|
syntheaCoding struct {
|
|
Code string `json:"code"`
|
|
Display string `json:"display"`
|
|
System string `json:"system"`
|
|
Unit string `json:"unit"`
|
|
Value float64 `json:"value"`
|
|
}
|
|
syntheaReference struct {
|
|
Display string `json:"display"`
|
|
Reference string `json:"reference"`
|
|
}
|
|
syntheaAddress struct {
|
|
City string `json:"city"`
|
|
Country string `json:"country"`
|
|
Extension []syntheaExtension `json:"extension"`
|
|
Line []string `json:"line"`
|
|
PostalCode string `json:"postalCode"`
|
|
State string `json:"state"`
|
|
}
|
|
syntheaExtension struct {
|
|
URL string `json:"url"`
|
|
ValueAddress syntheaAddress `json:"valueAddress"`
|
|
ValueCode string `json:"valueCode"`
|
|
ValueDecimal float64 `json:"valueDecimal"`
|
|
ValueString string `json:"valueString"`
|
|
Extension []syntheaExtension `json:"extension"`
|
|
}
|
|
syntheaRange struct {
|
|
End time.Time `json:"end"`
|
|
Start time.Time `json:"start"`
|
|
}
|
|
syntheaCurrency struct {
|
|
Currency string `json:"currency"`
|
|
Value float64 `json:"value"`
|
|
}
|
|
)
|
|
|
|
|
|
func TestPretouchSynteaRoot(t *testing.T) {
|
|
m := new(syntheaRoot)
|
|
s := time.Now()
|
|
println("start decoder pretouch:", s.UnixNano())
|
|
require.Nil(t, Pretouch(reflect.TypeOf(m), option.WithCompileMaxInlineDepth(2), option.WithCompileRecursiveDepth(20)))
|
|
e := time.Now()
|
|
println("end decoder pretouch:", e.UnixNano())
|
|
println("elapsed:", e.Sub(s).Milliseconds(), "ms")
|
|
|
|
s = time.Now()
|
|
println("start decode:", s.UnixNano())
|
|
require.Nil(t, UnmarshalString(jsonData, m))
|
|
e = time.Now()
|
|
println("end decode:", e.UnixNano())
|
|
d1 := e.Sub(s).Nanoseconds()
|
|
println("elapsed:", d1, "ns")
|
|
|
|
s = time.Now()
|
|
println("start decode:", s.UnixNano())
|
|
require.Nil(t, UnmarshalString(jsonData, m))
|
|
e = time.Now()
|
|
println("end decode:", e.UnixNano())
|
|
d2 := e.Sub(s).Nanoseconds()
|
|
println("elapsed:", d2, "ns")
|
|
if d1 > d2 * 10 {
|
|
t.Fatal("decoder pretouch not finish yet")
|
|
}
|
|
|
|
s = time.Now()
|
|
println("start decode:", s.UnixNano())
|
|
require.Nil(t, UnmarshalString(jsonData, m))
|
|
e = time.Now()
|
|
println("end decode:", e.UnixNano())
|
|
d5 := e.Sub(s).Nanoseconds()
|
|
println("elapsed:", d5, "ns")
|
|
if d2 > d5 * 10 {
|
|
t.Fatal("decoder pretouch not finish yet")
|
|
}
|
|
|
|
s = time.Now()
|
|
println("start encode 1:", s.UnixNano())
|
|
_, err := MarshalString(*m)
|
|
require.Nil(t, err)
|
|
e = time.Now()
|
|
println("end encode 1:", e.UnixNano())
|
|
d3 := e.Sub(s).Nanoseconds()
|
|
println("elapsed:", d3, "ns")
|
|
|
|
s = time.Now()
|
|
println("start encode 2:", s.UnixNano())
|
|
_, err = MarshalString(m)
|
|
require.Nil(t, err)
|
|
e = time.Now()
|
|
println("end encode 2:", e.UnixNano())
|
|
d4 := e.Sub(s).Nanoseconds()
|
|
println("elapsed:", d4, "ns")
|
|
// if d3 > d4 * 10 {
|
|
// t.Fatal("encoder pretouch not finish yet")
|
|
// }
|
|
|
|
s = time.Now()
|
|
println("start encode 3:", s.UnixNano())
|
|
_, err = MarshalString(m)
|
|
require.Nil(t, err)
|
|
e = time.Now()
|
|
println("end encode 3:", e.UnixNano())
|
|
d6 := e.Sub(s).Nanoseconds()
|
|
println("elapsed:", d6, "ns")
|
|
if d4 > d6 * 10 {
|
|
t.Fatal("encoder pretouch not finish yet")
|
|
}
|
|
}
|
|
|
|
func BenchmarkDecodeSynteaRoot(b *testing.B) {
|
|
m := new(syntheaRoot)
|
|
require.Nil(b, Pretouch(reflect.TypeOf(m), option.WithCompileRecursiveDepth(10)))
|
|
|
|
b.SetBytes(int64(len(jsonData)))
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_ = UnmarshalString(jsonData, m)
|
|
}
|
|
}
|
|
|
|
func BenchmarkEncodeSynteaRoot(b *testing.B) {
|
|
m := new(syntheaRoot)
|
|
require.Nil(b, Pretouch(reflect.TypeOf(m), option.WithCompileRecursiveDepth(10)))
|
|
require.Nil(b, UnmarshalString(jsonData, m))
|
|
|
|
b.SetBytes(int64(len(jsonData)))
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_, _ = MarshalString(m)
|
|
}
|
|
} |