Skip to content

Commit

Permalink
add cache
Browse files Browse the repository at this point in the history
  • Loading branch information
suhuaqin authored and Your Name committed May 3, 2024
1 parent db054d4 commit 52b2965
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 49 deletions.
49 changes: 24 additions & 25 deletions aper.go
Original file line number Diff line number Diff line change
Expand Up @@ -769,21 +769,19 @@ func parseField(v reflect.Value, pd *perBitData, params fieldParameters) error {
case reflect.Struct:

structType := fieldType
var structParams []fieldParameters
structField, err := structFieldCache.load(structType)
if err != nil {
return err
}
var optionalCount uint
var optionalPresents uint64

// pass tag for optional
for i := 0; i < structType.NumField(); i++ {
if structType.Field(i).PkgPath != "" {
return fmt.Errorf("struct contains unexported fields : " + structType.Field(i).PkgPath)
}
tempParams := parseFieldParameters(structType.Field(i).Tag.Get("aper"))
for i := 0; i < len(structField); i++ {
// for optional flag
if tempParams.optional {
if structField[i].FieldParameters.optional {
optionalCount++
}
structParams = append(structParams, tempParams)
}

if optionalCount > 0 {
Expand All @@ -796,19 +794,19 @@ func parseField(v reflect.Value, pd *perBitData, params fieldParameters) error {
}

// CHOICE or OpenType
if structType.NumField() > 0 && structType.Field(0).Name == "Present" {
if len(structField) > 0 && structField[0].FieldName == "Present" {
var present int = 0
if params.openType {
if params.referenceFieldValue == nil {
return fmt.Errorf("OpenType reference value is empty")
}
refValue := *params.referenceFieldValue

for j, param := range structParams {
for j, param := range structField {
if j == 0 {
continue
}
if param.referenceFieldValue != nil && *param.referenceFieldValue == refValue {
if param.FieldParameters.referenceFieldValue != nil && *param.FieldParameters.referenceFieldValue == refValue {
present = j
break
}
Expand All @@ -817,12 +815,12 @@ func parseField(v reflect.Value, pd *perBitData, params fieldParameters) error {
val.Field(0).SetInt(0)
perTrace(2, "OpenType reference value does not match any field")
return pd.parseOpenType(true, reflect.Value{}, fieldParameters{})
} else if present >= structType.NumField() {
} else if present >= len(structField) {
return fmt.Errorf("OpenType Present is bigger than number of struct field")
} else {
val.Field(0).SetInt(int64(present))
perTrace(2, "Decoded Present index of OpenType is %d ", present)
return pd.parseOpenType(false, val.Field(present), structParams[present])
return pd.parseOpenType(false, val.Field(present), structField[present].FieldParameters)
}
} else {
if presentTmp, err := pd.getChoiceIndex(valueExtensible, params.valueUpperBound); err != nil {
Expand All @@ -833,44 +831,45 @@ func parseField(v reflect.Value, pd *perBitData, params fieldParameters) error {
val.Field(0).SetInt(int64(present))
if present == 0 {
return fmt.Errorf("CHOICE present is 0(present's field number)")
} else if present >= structType.NumField() {
} else if present >= len(structField) {
return fmt.Errorf("CHOICE Present is bigger than number of struct field")
} else {
return parseField(val.Field(present), pd, structParams[present])
return parseField(val.Field(present), pd, structField[present].FieldParameters)
}
}
}

for i := 0; i < structType.NumField(); i++ {
if structParams[i].optional && optionalCount > 0 {
for i := 0; i < len(structField); i++ {
if structField[i].FieldParameters.optional && optionalCount > 0 {
optionalCount--
if optionalPresents&(1<<optionalCount) == 0 {
perTrace(3, "Field \"%s\" in %s is OPTIONAL and not present", structType.Field(i).Name, structType)
perTrace(3, "Field \"%s\" in %s is OPTIONAL and not present", structField[i].FieldName, structType)
continue
} else {
perTrace(3, "Field \"%s\" in %s is OPTIONAL and present", structType.Field(i).Name, structType)
perTrace(3, "Field \"%s\" in %s is OPTIONAL and present", structField[i].FieldName, structType)
}
}
// for open type reference
if structParams[i].openType {
fieldName := structParams[i].referenceFieldName
tempFieldParameters := structField[i].FieldParameters
if tempFieldParameters.openType {
fieldName := tempFieldParameters.referenceFieldName
var index int
for index = 0; index < i; index++ {
if structType.Field(index).Name == fieldName {
if structField[index].FieldName == fieldName {
break
}
}
if index == i {
return fmt.Errorf("Open type is not reference to the other field in the struct")
}
structParams[i].referenceFieldValue = new(int64)
tempFieldParameters.referenceFieldValue = new(int64)
if referenceFieldValue, err := getReferenceFieldValue(val.Field(index)); err != nil {
return err
} else {
*structParams[i].referenceFieldValue = referenceFieldValue
*tempFieldParameters.referenceFieldValue = referenceFieldValue
}
}
if err := parseField(val.Field(i), pd, structParams[i]); err != nil {
if err := parseField(val.Field(i), pd, tempFieldParameters); err != nil {
return err
}
}
Expand Down
43 changes: 43 additions & 0 deletions cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package aper

import (
"fmt"
"reflect"
"sync"
)

var fieldParametersCache sync.Map

Check failure on line 9 in cache.go

View workflow job for this annotation

GitHub Actions / lint (1.18)

File is not `gofumpt`-ed (gofumpt)
var structFieldCache structFieldCacheT

type structFieldCacheT struct {
m sync.Map
}

func (f *structFieldCacheT) load(k reflect.Type) ([]structFieldElem, error) {
v, ok := f.m.Load(k)
if ok {
return v.([]structFieldElem), nil
}

numField := k.NumField()
result := make([]structFieldElem, 0, numField)
for i := 0; i < numField; i++ {
field := k.Field(i)
if field.PkgPath != "" {
return nil, fmt.Errorf("struct contains unexported fields : " + field.PkgPath)
}

result = append(result, structFieldElem{
FieldName: field.Name,
FieldParameters: parseFieldParameters(field.Tag.Get("aper")),
})
}
f.m.Store(k, result)

return result, nil
}

type structFieldElem struct {
FieldName string
FieldParameters fieldParameters
}
8 changes: 8 additions & 0 deletions common.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ type fieldParameters struct {
// parseFieldParameters will parse it into a fieldParameters structure,
// ignoring unknown parts of the string. TODO:PrintableString
func parseFieldParameters(str string) (params fieldParameters) {
vAny, ok := fieldParametersCache.Load(str)
if ok {
return vAny.(fieldParameters)
}

for _, part := range strings.Split(str, ",") {
switch {
case part == "optional":
Expand Down Expand Up @@ -74,5 +79,8 @@ func parseFieldParameters(str string) (params fieldParameters) {
}
}
}

fieldParametersCache.Store(str, params)

return params
}
46 changes: 22 additions & 24 deletions marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,10 @@ func (pd *perRawBitData) makeField(v reflect.Value, params fieldParameters) erro
case reflect.Struct:

structType := fieldType
var structParams []fieldParameters
structField, err := structFieldCache.load(structType)
if err != nil {
return err
}
var optionalCount uint
var optionalPresents uint64
var sequenceType bool
Expand All @@ -689,16 +692,12 @@ func (pd *perRawBitData) makeField(v reflect.Value, params fieldParameters) erro
return err
}
}
sequenceType = (structType.NumField() <= 0 || structType.Field(0).Name != "Present")
sequenceType = len(structField) <= 0 || structField[0].FieldName != "Present"
// pass tag for optional
for i := 0; i < structType.NumField(); i++ {
if structType.Field(i).PkgPath != "" {
return fmt.Errorf("struct contains unexported fields : " + structType.Field(i).PkgPath)
}
tempParams := parseFieldParameters(structType.Field(i).Tag.Get("aper"))
if sequenceType {
if sequenceType {
for i := 0; i < len(structField); i++ {
// for optional flag
if tempParams.optional {
if structField[i].FieldParameters.optional {
optionalCount++
optionalPresents <<= 1
if !v.Field(i).IsNil() {
Expand All @@ -708,8 +707,6 @@ func (pd *perRawBitData) makeField(v reflect.Value, params fieldParameters) erro
return fmt.Errorf("nil element in SEQUENCE type")
}
}

structParams = append(structParams, tempParams)
}
if optionalCount > 0 {
perTrace(2, "putting optional(%d), optionalPresents is %0b", optionalCount, optionalPresents)
Expand All @@ -723,26 +720,26 @@ func (pd *perRawBitData) makeField(v reflect.Value, params fieldParameters) erro
present := int(v.Field(0).Int())
if present == 0 {
return fmt.Errorf("CHOICE or OpenType present is 0(present's field number)")
} else if present >= structType.NumField() {
} else if present >= len(structField) {
return fmt.Errorf("Present is bigger than number of struct field")
} else if params.openType {
if params.referenceFieldValue == nil {
return fmt.Errorf("OpenType reference value is empty")
}
refValue := *params.referenceFieldValue

if structParams[present].referenceFieldValue == nil || *structParams[present].referenceFieldValue != refValue {
if structField[present].FieldParameters.referenceFieldValue == nil || *structField[present].FieldParameters.referenceFieldValue != refValue {

Check failure on line 731 in marshal.go

View workflow job for this annotation

GitHub Actions / lint (1.18)

line is 145 characters (lll)
return fmt.Errorf("reference value and present reference value is not match")
}
perTrace(2, "Encoding Present index of OpenType is %d ", present)
if err := pd.appendOpenType(val.Field(present), structParams[present]); err != nil {
if err := pd.appendOpenType(val.Field(present), structField[present].FieldParameters); err != nil {
return err
}
} else {
if err := pd.appendChoiceIndex(present, params.valueExtensible, params.valueUpperBound); err != nil {
return err
}
if err := pd.makeField(val.Field(present), structParams[present]); err != nil {
if err := pd.makeField(val.Field(present), structField[present].FieldParameters); err != nil {
return err
}
}
Expand All @@ -751,35 +748,36 @@ func (pd *perRawBitData) makeField(v reflect.Value, params fieldParameters) erro

for i := 0; i < structType.NumField(); i++ {
// optional
if structParams[i].optional && optionalCount > 0 {
if structField[i].FieldParameters.optional && optionalCount > 0 {
optionalCount--
if optionalPresents&(1<<optionalCount) == 0 {
perTrace(3, "Field \"%s\" in %s is OPTIONAL and not present", structType.Field(i).Name, structType)
perTrace(3, "Field \"%s\" in %s is OPTIONAL and not present", structField[i].FieldName, structType)
continue
} else {
perTrace(3, "Field \"%s\" in %s is OPTIONAL and present", structType.Field(i).Name, structType)
perTrace(3, "Field \"%s\" in %s is OPTIONAL and present", structField[i].FieldName, structType)
}
}
// for open type reference
if structParams[i].openType {
fieldName := structParams[i].referenceFieldName
tempFieldParameters := structField[i].FieldParameters
if tempFieldParameters.openType {
fieldName := tempFieldParameters.referenceFieldName
var index int
for index = 0; index < i; index++ {
if structType.Field(index).Name == fieldName {
if structField[index].FieldName == fieldName {
break
}
}
if index == i {
return fmt.Errorf("Open type is not reference to the other field in the struct")
}
structParams[i].referenceFieldValue = new(int64)
tempFieldParameters.referenceFieldValue = new(int64)
if value, err := getReferenceFieldValue(val.Field(index)); err != nil {
return err
} else {
*structParams[i].referenceFieldValue = value
*tempFieldParameters.referenceFieldValue = value
}
}
if err := pd.makeField(val.Field(i), structParams[i]); err != nil {
if err := pd.makeField(val.Field(i), tempFieldParameters); err != nil {
return err
}
}
Expand Down

0 comments on commit 52b2965

Please sign in to comment.