Merge pull request #74 from goccy/feature/add-escaped-op

Optimize about HTML Escape processing
This commit is contained in:
Masaaki Goshima 2020-12-25 22:39:59 +09:00 committed by GitHub
commit 1d1572fb55
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 132275 additions and 9818 deletions

View File

@ -12,36 +12,35 @@ import (
)
type opType struct {
Op string
IndentOp string
Code string
Op string
Code string
Indent func() string
Escaped func() string
HeadToPtrHead func() string
HeadToNPtrHead func() string
HeadToAnonymousHead func() string
HeadToOmitEmptyHead func() string
HeadToStringTagHead func() string
PtrHeadToHead func() string
FieldToOmitEmptyField func() string
FieldToStringTagField func() string
}
type headType struct {
Head string
PtrHead string
NPtrHead string
AnonymousHead string
AnonymousPtrHead string
AnonymousNPtrHead string
OmitEmptyHead string
OmitEmptyPtrHead string
OmitEmptyNPtrHead string
AnonymousOmitEmptyHead string
AnonymousOmitEmptyPtrHead string
AnonymousOmitEmptyNPtrHead string
StringTagHead string
StringTagPtrHead string
StringTagNPtrHead string
AnonymousStringTagHead string
AnonymousStringTagPtrHead string
AnonymousStringTagNPtrHead string
}
type fieldType struct {
Field string
OmitEmptyField string
StringTagField string
func createOpType(op, code string) opType {
return opType{
Op: op,
Code: code,
Indent: func() string { return fmt.Sprintf("%sIndent", op) },
Escaped: func() string { return op },
HeadToPtrHead: func() string { return op },
HeadToNPtrHead: func() string { return op },
HeadToAnonymousHead: func() string { return op },
HeadToOmitEmptyHead: func() string { return op },
HeadToStringTagHead: func() string { return op },
PtrHeadToHead: func() string { return op },
FieldToOmitEmptyField: func() string { return op },
FieldToStringTagField: func() string { return op },
}
}
func _main() error {
@ -88,7 +87,17 @@ func (t opType) toIndent() opType {
switch t {
{{- range $type := .OpTypes }}
case op{{ $type.Op }}:
return op{{ $type.IndentOp }}
return op{{ call $type.Indent }}
{{- end }}
}
return t
}
func (t opType) toEscaped() opType {
switch t {
{{- range $type := .OpTypes }}
case op{{ $type.Op }}:
return op{{ call $type.Escaped }}
{{- end }}
}
return t
@ -96,19 +105,9 @@ func (t opType) toIndent() opType {
func (t opType) headToPtrHead() opType {
switch t {
{{- range $type := .HeadTypes }}
case op{{ $type.Head }}:
return op{{ $type.PtrHead }}
case op{{ $type.AnonymousHead }}:
return op{{ $type.AnonymousPtrHead }}
case op{{ $type.OmitEmptyHead }}:
return op{{ $type.OmitEmptyPtrHead }}
case op{{ $type.AnonymousOmitEmptyHead }}:
return op{{ $type.AnonymousOmitEmptyPtrHead }}
case op{{ $type.StringTagHead }}:
return op{{ $type.StringTagPtrHead }}
case op{{ $type.AnonymousStringTagHead }}:
return op{{ $type.AnonymousStringTagPtrHead }}
{{- range $type := .OpTypes }}
case op{{ $type.Op }}:
return op{{ call $type.HeadToPtrHead }}
{{- end }}
}
return t
@ -116,19 +115,9 @@ func (t opType) headToPtrHead() opType {
func (t opType) headToNPtrHead() opType {
switch t {
{{- range $type := .HeadTypes }}
case op{{ $type.Head }}:
return op{{ $type.NPtrHead }}
case op{{ $type.AnonymousHead }}:
return op{{ $type.AnonymousNPtrHead }}
case op{{ $type.OmitEmptyHead }}:
return op{{ $type.OmitEmptyNPtrHead }}
case op{{ $type.AnonymousOmitEmptyHead }}:
return op{{ $type.AnonymousOmitEmptyNPtrHead }}
case op{{ $type.StringTagHead }}:
return op{{ $type.StringTagNPtrHead }}
case op{{ $type.AnonymousStringTagHead }}:
return op{{ $type.AnonymousStringTagNPtrHead }}
{{- range $type := .OpTypes }}
case op{{ $type.Op }}:
return op{{ call $type.HeadToNPtrHead }}
{{- end }}
}
return t
@ -136,19 +125,9 @@ func (t opType) headToNPtrHead() opType {
func (t opType) headToAnonymousHead() opType {
switch t {
{{- range $type := .HeadTypes }}
case op{{ $type.Head }}:
return op{{ $type.AnonymousHead }}
case op{{ $type.PtrHead }}:
return op{{ $type.AnonymousPtrHead }}
case op{{ $type.OmitEmptyHead }}:
return op{{ $type.AnonymousOmitEmptyHead }}
case op{{ $type.OmitEmptyPtrHead }}:
return op{{ $type.AnonymousOmitEmptyPtrHead }}
case op{{ $type.StringTagHead }}:
return op{{ $type.AnonymousStringTagHead }}
case op{{ $type.StringTagPtrHead }}:
return op{{ $type.AnonymousStringTagPtrHead }}
{{- range $type := .OpTypes }}
case op{{ $type.Op }}:
return op{{ call $type.HeadToAnonymousHead }}
{{- end }}
}
return t
@ -156,11 +135,9 @@ func (t opType) headToAnonymousHead() opType {
func (t opType) headToOmitEmptyHead() opType {
switch t {
{{- range $type := .HeadTypes }}
case op{{ $type.Head }}:
return op{{ $type.OmitEmptyHead }}
case op{{ $type.PtrHead }}:
return op{{ $type.OmitEmptyPtrHead }}
{{- range $type := .OpTypes }}
case op{{ $type.Op }}:
return op{{ call $type.HeadToOmitEmptyHead }}
{{- end }}
}
return t
@ -168,11 +145,9 @@ func (t opType) headToOmitEmptyHead() opType {
func (t opType) headToStringTagHead() opType {
switch t {
{{- range $type := .HeadTypes }}
case op{{ $type.Head }}:
return op{{ $type.StringTagHead }}
case op{{ $type.PtrHead }}:
return op{{ $type.StringTagPtrHead }}
{{- range $type := .OpTypes }}
case op{{ $type.Op }}:
return op{{ call $type.HeadToStringTagHead }}
{{- end }}
}
return t
@ -180,19 +155,9 @@ func (t opType) headToStringTagHead() opType {
func (t opType) ptrHeadToHead() opType {
switch t {
{{- range $type := .HeadTypes }}
case op{{ $type.PtrHead }}, op{{ $type.NPtrHead }}:
return op{{ $type.Head }}
case op{{ $type.AnonymousPtrHead }}, op{{ $type.AnonymousNPtrHead }}:
return op{{ $type.AnonymousHead }}
case op{{ $type.OmitEmptyPtrHead }}, op{{ $type.OmitEmptyNPtrHead }}:
return op{{ $type.OmitEmptyHead }}
case op{{ $type.AnonymousOmitEmptyPtrHead }}, op{{ $type.AnonymousOmitEmptyNPtrHead }}:
return op{{ $type.AnonymousOmitEmptyHead }}
case op{{ $type.StringTagPtrHead }}, op{{ $type.StringTagNPtrHead }}:
return op{{ $type.StringTagHead }}
case op{{ $type.AnonymousStringTagPtrHead }}, op{{ $type.AnonymousStringTagNPtrHead }}:
return op{{ $type.AnonymousStringTagHead }}
{{- range $type := .OpTypes }}
case op{{ $type.Op }}:
return op{{ call $type.PtrHeadToHead }}
{{- end }}
}
return t
@ -200,9 +165,9 @@ func (t opType) ptrHeadToHead() opType {
func (t opType) fieldToOmitEmptyField() opType {
switch t {
{{- range $type := .FieldTypes }}
case op{{ $type.Field }}:
return op{{ $type.OmitEmptyField }}
{{- range $type := .OpTypes }}
case op{{ $type.Op }}:
return op{{ call $type.FieldToOmitEmptyField }}
{{- end }}
}
return t
@ -210,9 +175,9 @@ func (t opType) fieldToOmitEmptyField() opType {
func (t opType) fieldToStringTagField() opType {
switch t {
{{- range $type := .FieldTypes }}
case op{{ $type.Field }}:
return op{{ $type.StringTagField }}
{{- range $type := .OpTypes }}
case op{{ $type.Op }}:
return op{{ call $type.FieldToStringTagField }}
{{- end }}
}
return t
@ -238,210 +203,256 @@ func (t opType) fieldToStringTagField() opType {
primitiveTypes := []string{
"int", "int8", "int16", "int32", "int64",
"uint", "uint8", "uint16", "uint32", "uint64",
"float32", "float64", "bool", "string", "bytes",
"float32", "float64", "bool", "string", "escapedString", "bytes",
"array", "map", "mapLoad", "slice", "struct", "MarshalJSON", "MarshalText", "recursive",
"intString", "int8String", "int16String", "int32String", "int64String",
"uintString", "uint8String", "uint16String", "uint32String", "uint64String",
"intPtr", "int8Ptr", "int16Ptr", "int32Ptr", "int64Ptr",
"uintPtr", "uint8Ptr", "uint16Ptr", "uint32Ptr", "uint64Ptr",
"float32Ptr", "float64Ptr", "boolPtr", "stringPtr", "bytesPtr",
"float32Ptr", "float64Ptr", "boolPtr", "stringPtr", "escapedStringPtr", "bytesPtr",
"intNPtr", "int8NPtr", "int16NPtr", "int32NPtr", "int64NPtr",
"uintNPtr", "uint8NPtr", "uint16NPtr", "uint32NPtr", "uint64NPtr",
"float32NPtr", "float64NPtr", "boolNPtr", "stringNPtr", "bytesNPtr",
"float32NPtr", "float64NPtr", "boolNPtr", "stringNPtr", "escapedStringNPtr", "bytesNPtr",
}
primitiveTypesUpper := []string{}
for _, typ := range primitiveTypes {
primitiveTypesUpper = append(primitiveTypesUpper, strings.ToUpper(string(typ[0]))+typ[1:])
}
opTypes := []opType{
{"End", "EndIndent", "Op"},
{"Interface", "InterfaceIndent", "Op"},
{"InterfaceEnd", "InterfaceEndIndent", "Op"},
{"Ptr", "PtrIndent", "Op"},
{"NPtr", "NPtrIndent", "Op"},
{"SliceHead", "SliceHeadIndent", "SliceHead"},
{"RootSliceHead", "RootSliceHeadIndent", "SliceHead"},
{"SliceElem", "SliceElemIndent", "SliceElem"},
{"RootSliceElem", "RootSliceElemIndent", "SliceElem"},
{"SliceEnd", "SliceEndIndent", "Op"},
{"ArrayHead", "ArrayHeadIndent", "ArrayHead"},
{"ArrayElem", "ArrayElemIndent", "ArrayElem"},
{"ArrayEnd", "ArrayEndIndent", "Op"},
{"MapHead", "MapHeadIndent", "MapHead"},
{"MapHeadLoad", "MapHeadLoadIndent", "MapHead"},
{"MapKey", "MapKeyIndent", "MapKey"},
{"MapValue", "MapValueIndent", "MapValue"},
{"MapEnd", "MapEndIndent", "Op"},
{"StructFieldHead", "StructFieldHeadIndent", "StructField"},
{"StructFieldHeadOmitEmpty", "StructFieldHeadOmitEmptyIndent", "StructField"},
{"StructFieldHeadStringTag", "StructFieldHeadStringTagIndent", "StructField"},
{"StructFieldAnonymousHead", "StructFieldAnonymousHeadIndent", "StructField"},
{"StructFieldAnonymousHeadOmitEmpty", "StructFieldAnonymousHeadOmitEmptyIndent", "StructField"},
{"StructFieldPtrAnonymousHeadOmitEmpty", "StructFieldPtrAnonymousHeadOmitEmptyIndent", "StructField"},
{"StructFieldNPtrAnonymousHeadOmitEmpty", "StructFieldNPtrAnonymousHeadOmitEmptyIndent", "StructField"},
{"StructFieldAnonymousHeadStringTag", "StructFieldAnonymousHeadStringTagIndent", "StructField"},
{"StructFieldPtrAnonymousHeadStringTag", "StructFieldPtrAnonymousHeadStringTagIndent", "StructField"},
{"StructFieldNPtrAnonymousHeadStringTag", "StructFieldNPtrAnonymousHeadStringTagIndent", "StructField"},
{"StructFieldPtrHead", "StructFieldPtrHeadIndent", "StructField"},
{"StructFieldPtrHeadOmitEmpty", "StructFieldPtrHeadOmitEmptyIndent", "StructField"},
{"StructFieldPtrHeadStringTag", "StructFieldPtrHeadStringTagIndent", "StructField"},
{"StructFieldPtrAnonymousHead", "StructFieldPtrAnonymousHeadIndent", "StructField"},
{"StructFieldNPtrHead", "StructFieldNPtrHeadIndent", "StructField"},
{"StructFieldNPtrHeadOmitEmpty", "StructFieldNPtrHeadOmitEmptyIndent", "StructField"},
{"StructFieldNPtrHeadStringTag", "StructFieldNPtrHeadStringTagIndent", "StructField"},
{"StructFieldNPtrAnonymousHead", "StructFieldNPtrAnonymousHeadIndent", "StructField"},
{"StructField", "StructFieldIndent", "StructField"},
{"StructFieldOmitEmpty", "StructFieldOmitEmptyIndent", "StructField"},
{"StructFieldStringTag", "StructFieldStringTagIndent", "StructField"},
{"StructFieldRecursiveEnd", "StructFieldRecursiveEndIndent", "Op"},
{"StructEnd", "StructEndIndent", "StructField"},
{"StructAnonymousEnd", "StructAnonymousEndIndent", "StructField"},
createOpType("End", "Op"),
createOpType("Interface", "Op"),
createOpType("InterfaceEnd", "Op"),
createOpType("Ptr", "Op"),
createOpType("NPtr", "Op"),
createOpType("SliceHead", "SliceHead"),
createOpType("RootSliceHead", "SliceHead"),
createOpType("SliceElem", "SliceElem"),
createOpType("RootSliceElem", "SliceElem"),
createOpType("SliceEnd", "Op"),
createOpType("ArrayHead", "ArrayHead"),
createOpType("ArrayElem", "ArrayElem"),
createOpType("ArrayEnd", "Op"),
createOpType("MapHead", "MapHead"),
createOpType("MapHeadLoad", "MapHead"),
createOpType("MapKey", "MapKey"),
createOpType("MapValue", "MapValue"),
createOpType("MapEnd", "Op"),
createOpType("StructFieldRecursiveEnd", "Op"),
createOpType("StructEnd", "StructField"),
createOpType("StructAnonymousEnd", "StructField"),
}
for _, typ := range primitiveTypesUpper {
opTypes = append(opTypes, opType{
Op: typ,
IndentOp: fmt.Sprintf("%sIndent", typ),
Code: "Op",
})
typ := typ
optype := createOpType(typ, "Op")
switch typ {
case "String", "StringPtr", "StringNPtr":
optype.Escaped = func() string {
return fmt.Sprintf("Escaped%s", typ)
}
}
opTypes = append(opTypes, optype)
}
for _, prefix := range []string{
"StructFieldHead",
"StructFieldHeadOmitEmpty",
"StructFieldHeadStringTag",
"StructFieldAnonymousHead",
"StructFieldAnonymousHeadOmitEmpty",
"StructFieldAnonymousHeadStringTag",
"StructFieldPtrHead",
"StructFieldPtrHeadOmitEmpty",
"StructFieldPtrHeadStringTag",
"StructFieldPtrAnonymousHead",
"StructFieldPtrAnonymousHeadOmitEmpty",
"StructFieldPtrAnonymousHeadStringTag",
"StructFieldNPtrHead",
"StructFieldNPtrHeadOmitEmpty",
"StructFieldNPtrHeadStringTag",
"StructFieldNPtrAnonymousHead",
"StructFieldNPtrAnonymousHeadOmitEmpty",
"StructFieldNPtrAnonymousHeadStringTag",
"StructField",
//"StructFieldPtr",
//"StructFieldNPtr",
"StructFieldOmitEmpty",
"StructFieldStringTag",
} {
for _, typ := range primitiveTypesUpper {
opTypes = append(opTypes, opType{
Op: fmt.Sprintf("%s%s", prefix, typ),
IndentOp: fmt.Sprintf("%s%sIndent", prefix, typ),
Code: "StructField",
})
for _, escapedOrNot := range []string{"", "Escaped"} {
for _, ptrOrNot := range []string{"", "Ptr", "NPtr"} {
for _, headType := range []string{"", "Anonymous"} {
for _, opt := range []string{"", "OmitEmpty", "StringTag"} {
for _, typ := range append(primitiveTypesUpper, "") {
escapedOrNot := escapedOrNot
ptrOrNot := ptrOrNot
headType := headType
opt := opt
typ := typ
op := fmt.Sprintf(
"Struct%sField%s%sHead%s%s",
escapedOrNot,
ptrOrNot,
headType,
opt,
typ,
)
opTypes = append(opTypes, opType{
Op: op,
Code: "StructField",
Indent: func() string { return fmt.Sprintf("%sIndent", op) },
Escaped: func() string {
switch typ {
case "String", "StringPtr", "StringNPtr":
return fmt.Sprintf(
"StructEscapedField%s%sHead%sEscaped%s",
ptrOrNot,
headType,
opt,
typ,
)
}
return fmt.Sprintf(
"StructEscapedField%s%sHead%s%s",
ptrOrNot,
headType,
opt,
typ,
)
},
HeadToPtrHead: func() string {
return fmt.Sprintf(
"Struct%sFieldPtr%sHead%s%s",
escapedOrNot,
headType,
opt,
typ,
)
},
HeadToNPtrHead: func() string {
return fmt.Sprintf(
"Struct%sFieldNPtr%sHead%s%s",
escapedOrNot,
headType,
opt,
typ,
)
},
HeadToAnonymousHead: func() string {
return fmt.Sprintf(
"Struct%sField%sAnonymousHead%s%s",
escapedOrNot,
ptrOrNot,
opt,
typ,
)
},
HeadToOmitEmptyHead: func() string {
return fmt.Sprintf(
"Struct%sField%s%sHeadOmitEmpty%s",
escapedOrNot,
ptrOrNot,
headType,
typ,
)
},
HeadToStringTagHead: func() string {
return fmt.Sprintf(
"Struct%sField%s%sHeadStringTag%s",
escapedOrNot,
ptrOrNot,
headType,
typ,
)
},
PtrHeadToHead: func() string {
return fmt.Sprintf(
"Struct%sField%sHead%s%s",
escapedOrNot,
headType,
opt,
typ,
)
},
FieldToOmitEmptyField: func() string { return op },
FieldToStringTagField: func() string { return op },
})
}
}
}
}
}
for _, escapedOrNot := range []string{"", "Escaped"} {
for _, opt := range []string{"", "OmitEmpty", "StringTag"} {
for _, typ := range append(primitiveTypesUpper, "") {
escapedOrNot := escapedOrNot
opt := opt
typ := typ
op := fmt.Sprintf(
"Struct%sField%s%s",
escapedOrNot,
opt,
typ,
)
opTypes = append(opTypes, opType{
Op: op,
Code: "StructField",
Indent: func() string { return fmt.Sprintf("%sIndent", op) },
Escaped: func() string {
switch typ {
case "String", "StringPtr", "StringNPtr":
return fmt.Sprintf(
"StructEscapedField%sEscaped%s",
opt,
typ,
)
}
return fmt.Sprintf(
"StructEscapedField%s%s",
opt,
typ,
)
},
HeadToPtrHead: func() string { return op },
HeadToNPtrHead: func() string { return op },
HeadToAnonymousHead: func() string { return op },
HeadToOmitEmptyHead: func() string { return op },
HeadToStringTagHead: func() string { return op },
PtrHeadToHead: func() string { return op },
FieldToOmitEmptyField: func() string {
return fmt.Sprintf(
"Struct%sFieldOmitEmpty%s",
escapedOrNot,
typ,
)
},
FieldToStringTagField: func() string {
return fmt.Sprintf(
"Struct%sFieldStringTag%s",
escapedOrNot,
typ,
)
},
})
}
}
}
indentOpTypes := []opType{}
for _, typ := range opTypes {
opTypes = append(opTypes, opType{
Op: typ.IndentOp,
IndentOp: typ.IndentOp,
Code: typ.Code,
typ := typ
indentOpTypes = append(indentOpTypes, opType{
Op: fmt.Sprintf("%sIndent", typ.Op),
Code: typ.Code,
Indent: func() string { return fmt.Sprintf("%sIndent", typ.Op) },
Escaped: func() string { return fmt.Sprintf("%sIndent", typ.Escaped()) },
HeadToPtrHead: func() string {
return fmt.Sprintf("%sIndent", typ.HeadToPtrHead())
},
HeadToNPtrHead: func() string {
return fmt.Sprintf("%sIndent", typ.HeadToNPtrHead())
},
HeadToAnonymousHead: func() string {
return fmt.Sprintf("%sIndent", typ.HeadToAnonymousHead())
},
HeadToOmitEmptyHead: func() string {
return fmt.Sprintf("%sIndent", typ.HeadToOmitEmptyHead())
},
HeadToStringTagHead: func() string {
return fmt.Sprintf("%sIndent", typ.HeadToStringTagHead())
},
PtrHeadToHead: func() string {
return fmt.Sprintf("%sIndent", typ.PtrHeadToHead())
},
FieldToOmitEmptyField: func() string {
return fmt.Sprintf("%sIndent", typ.FieldToOmitEmptyField())
},
FieldToStringTagField: func() string {
return fmt.Sprintf("%sIndent", typ.FieldToStringTagField())
},
})
}
base := headType{
Head: "StructFieldHead",
PtrHead: "StructFieldPtrHead",
NPtrHead: "StructFieldNPtrHead",
AnonymousHead: "StructFieldAnonymousHead",
AnonymousPtrHead: "StructFieldPtrAnonymousHead",
AnonymousNPtrHead: "StructFieldNPtrAnonymousHead",
OmitEmptyHead: "StructFieldHeadOmitEmpty",
OmitEmptyPtrHead: "StructFieldPtrHeadOmitEmpty",
OmitEmptyNPtrHead: "StructFieldNPtrHeadOmitEmpty",
StringTagHead: "StructFieldHeadStringTag",
StringTagPtrHead: "StructFieldPtrHeadStringTag",
StringTagNPtrHead: "StructFieldNPtrHeadStringTag",
AnonymousOmitEmptyHead: "StructFieldAnonymousHeadOmitEmpty",
AnonymousOmitEmptyPtrHead: "StructFieldPtrAnonymousHeadOmitEmpty",
AnonymousOmitEmptyNPtrHead: "StructFieldNPtrAnonymousHeadOmitEmpty",
AnonymousStringTagHead: "StructFieldAnonymousHeadStringTag",
AnonymousStringTagPtrHead: "StructFieldPtrAnonymousHeadStringTag",
AnonymousStringTagNPtrHead: "StructFieldNPtrAnonymousHeadStringTag",
}
headTypes := []headType{base}
for _, prim := range primitiveTypesUpper {
headTypes = append(headTypes, headType{
Head: fmt.Sprintf("%s%s", base.Head, prim),
PtrHead: fmt.Sprintf("%s%s", base.PtrHead, prim),
NPtrHead: fmt.Sprintf("%s%s", base.NPtrHead, prim),
AnonymousHead: fmt.Sprintf("%s%s", base.AnonymousHead, prim),
AnonymousPtrHead: fmt.Sprintf("%s%s", base.AnonymousPtrHead, prim),
AnonymousNPtrHead: fmt.Sprintf("%s%s", base.AnonymousNPtrHead, prim),
OmitEmptyHead: fmt.Sprintf("%s%s", base.OmitEmptyHead, prim),
OmitEmptyPtrHead: fmt.Sprintf("%s%s", base.OmitEmptyPtrHead, prim),
OmitEmptyNPtrHead: fmt.Sprintf("%s%s", base.OmitEmptyNPtrHead, prim),
AnonymousOmitEmptyHead: fmt.Sprintf("%s%s", base.AnonymousOmitEmptyHead, prim),
AnonymousOmitEmptyPtrHead: fmt.Sprintf("%s%s", base.AnonymousOmitEmptyPtrHead, prim),
AnonymousOmitEmptyNPtrHead: fmt.Sprintf("%s%s", base.AnonymousOmitEmptyNPtrHead, prim),
StringTagHead: fmt.Sprintf("%s%s", base.StringTagHead, prim),
StringTagPtrHead: fmt.Sprintf("%s%s", base.StringTagPtrHead, prim),
StringTagNPtrHead: fmt.Sprintf("%s%s", base.StringTagNPtrHead, prim),
AnonymousStringTagHead: fmt.Sprintf("%s%s", base.AnonymousStringTagHead, prim),
AnonymousStringTagPtrHead: fmt.Sprintf("%s%s", base.AnonymousStringTagPtrHead, prim),
AnonymousStringTagNPtrHead: fmt.Sprintf("%s%s", base.AnonymousStringTagNPtrHead, prim),
})
}
for _, typ := range headTypes {
headTypes = append(headTypes, headType{
Head: fmt.Sprintf("%sIndent", typ.Head),
PtrHead: fmt.Sprintf("%sIndent", typ.PtrHead),
NPtrHead: fmt.Sprintf("%sIndent", typ.NPtrHead),
AnonymousHead: fmt.Sprintf("%sIndent", typ.AnonymousHead),
AnonymousPtrHead: fmt.Sprintf("%sIndent", typ.AnonymousPtrHead),
AnonymousNPtrHead: fmt.Sprintf("%sIndent", typ.AnonymousNPtrHead),
OmitEmptyHead: fmt.Sprintf("%sIndent", typ.OmitEmptyHead),
OmitEmptyPtrHead: fmt.Sprintf("%sIndent", typ.OmitEmptyPtrHead),
OmitEmptyNPtrHead: fmt.Sprintf("%sIndent", typ.OmitEmptyNPtrHead),
AnonymousOmitEmptyHead: fmt.Sprintf("%sIndent", typ.AnonymousOmitEmptyHead),
AnonymousOmitEmptyPtrHead: fmt.Sprintf("%sIndent", typ.AnonymousOmitEmptyPtrHead),
AnonymousOmitEmptyNPtrHead: fmt.Sprintf("%sIndent", typ.AnonymousOmitEmptyNPtrHead),
StringTagHead: fmt.Sprintf("%sIndent", typ.StringTagHead),
StringTagPtrHead: fmt.Sprintf("%sIndent", typ.StringTagPtrHead),
StringTagNPtrHead: fmt.Sprintf("%sIndent", typ.StringTagNPtrHead),
AnonymousStringTagHead: fmt.Sprintf("%sIndent", typ.AnonymousStringTagHead),
AnonymousStringTagPtrHead: fmt.Sprintf("%sIndent", typ.AnonymousStringTagPtrHead),
AnonymousStringTagNPtrHead: fmt.Sprintf("%sIndent", typ.AnonymousStringTagNPtrHead),
})
}
baseField := fieldType{
Field: "StructField",
OmitEmptyField: "StructFieldOmitEmpty",
StringTagField: "StructFieldStringTag",
}
fieldTypes := []fieldType{baseField}
for _, prim := range primitiveTypesUpper {
fieldTypes = append(fieldTypes, fieldType{
Field: fmt.Sprintf("%s%s", baseField.Field, prim),
OmitEmptyField: fmt.Sprintf("%s%s", baseField.OmitEmptyField, prim),
StringTagField: fmt.Sprintf("%s%s", baseField.StringTagField, prim),
})
}
for _, typ := range fieldTypes {
fieldTypes = append(fieldTypes, fieldType{
Field: fmt.Sprintf("%sIndent", typ.Field),
OmitEmptyField: fmt.Sprintf("%sIndent", typ.OmitEmptyField),
StringTagField: fmt.Sprintf("%sIndent", typ.StringTagField),
})
}
var b bytes.Buffer
if err := tmpl.Execute(&b, struct {
CodeTypes []string
OpTypes []opType
HeadTypes []headType
FieldTypes []fieldType
CodeTypes []string
OpTypes []opType
}{
CodeTypes: codeTypes,
OpTypes: opTypes,
HeadTypes: headTypes,
FieldTypes: fieldTypes,
CodeTypes: codeTypes,
OpTypes: append(opTypes, indentOpTypes...),
}); err != nil {
return err
}

View File

@ -34,10 +34,19 @@ const (
bufSize = 1024
)
const (
opCodeEscapedType = iota
opCodeEscapedIndentType
opCodeNoEscapeType
opCodeNoEscapeIndentType
)
type opcodeSet struct {
codeIndent *opcode
code *opcode
codeLength int
escapedCode *opcode
escapedCodeIndent *opcode
code *opcode
codeIndent *opcode
codeLength int
}
func loadOpcodeMap() map[uintptr]*opcodeSet {
@ -187,9 +196,17 @@ func (e *Encoder) encode(v interface{}) ([]byte, error) {
if codeSet, exists := opcodeMap[typeptr]; exists {
var code *opcode
if e.enabledIndent {
code = codeSet.codeIndent
if e.enabledHTMLEscape {
code = codeSet.escapedCodeIndent
} else {
code = codeSet.codeIndent
}
} else {
code = codeSet.code
if e.enabledHTMLEscape {
code = codeSet.escapedCode
} else {
code = codeSet.code
}
}
ctx := e.ctx
p := uintptr(header.ptr)
@ -200,31 +217,23 @@ func (e *Encoder) encode(v interface{}) ([]byte, error) {
// noescape trick for header.typ ( reflect.*rtype )
copiedType := *(**rtype)(unsafe.Pointer(&typeptr))
codeIndent, err := e.compileHead(&encodeCompileContext{
typ: copiedType,
root: true,
withIndent: true,
structTypeToCompiledCode: map[uintptr]*compiledCode{},
})
if err != nil {
return nil, err
}
code, err := e.compileHead(&encodeCompileContext{
typ: copiedType,
root: true,
withIndent: false,
structTypeToCompiledCode: map[uintptr]*compiledCode{},
})
if err != nil {
return nil, err
}
codeIndent = copyOpcode(codeIndent)
code = copyOpcode(code)
codeIndent := toIndent(code)
codeLength := code.totalLength()
codeSet := &opcodeSet{
codeIndent: codeIndent,
code: code,
codeLength: codeLength,
escapedCode: toEscaped(code),
escapedCodeIndent: toEscaped(codeIndent),
code: code,
codeIndent: codeIndent,
codeLength: codeLength,
}
storeOpcodeSet(typeptr, codeSet, opcodeMap)
@ -234,9 +243,17 @@ func (e *Encoder) encode(v interface{}) ([]byte, error) {
var c *opcode
if e.enabledIndent {
c = codeIndent
if e.enabledHTMLEscape {
c = codeSet.escapedCodeIndent
} else {
c = codeSet.codeIndent
}
} else {
c = code
if e.enabledHTMLEscape {
c = codeSet.escapedCode
} else {
c = codeSet.code
}
}
b, err = e.run(ctx, b, c)
@ -295,20 +312,6 @@ func encodeIndentComma(b []byte) []byte {
return append(b, ',', '\n')
}
func (e *Encoder) encodeKey(b []byte, code *opcode) []byte {
if e.enabledHTMLEscape {
return append(b, code.escapedKey...)
}
return append(b, code.key...)
}
func (e *Encoder) encodeString(b []byte, s string) []byte {
if e.enabledHTMLEscape {
return encodeEscapedString(b, s)
}
return encodeNoEscapedString(b, s)
}
func encodeByteSlice(b []byte, src []byte) []byte {
encodedLen := base64.StdEncoding.EncodedLen(len(src))
b = append(b, '"')

View File

@ -377,16 +377,6 @@ func (e *Encoder) compileSlice(ctx *encodeCompileContext) (*opcode, error) {
end := newOpCode(ctx, opSliceEnd)
ctx.incIndex()
if ctx.withIndent {
if ctx.root {
header.op = opRootSliceHeadIndent
elemCode.op = opRootSliceElemIndent
} else {
header.op = opSliceHeadIndent
elemCode.op = opSliceElemIndent
}
end.op = opSliceEndIndent
}
header.elem = elemCode
header.end = end
@ -421,12 +411,6 @@ func (e *Encoder) compileArray(ctx *encodeCompileContext) (*opcode, error) {
end := newOpCode(ctx, opArrayEnd)
ctx.incIndex()
if ctx.withIndent {
header.op = opArrayHeadIndent
elemCode.op = opArrayElemIndent
end.op = opArrayEndIndent
}
header.elem = elemCode
header.end = end
header.next = code
@ -487,13 +471,6 @@ func (e *Encoder) compileMap(ctx *encodeCompileContext, withLoad bool) (*opcode,
end := newMapEndCode(ctx, header)
ctx.incIndex()
if ctx.withIndent {
header.op = header.op.toIndent()
key.op = key.op.toIndent()
value.op = value.op.toIndent()
end.op = end.op.toIndent()
}
header.next = keyCode
keyCode.beforeLastCode().next = (*opcode)(unsafe.Pointer(value))
value.next = valueCode
@ -587,88 +564,46 @@ func (e *Encoder) typeToHeaderType(ctx *encodeCompileContext, code *opcode) opTy
}
case opInt:
return opStructFieldHeadInt
case opIntIndent:
return opStructFieldHeadIntIndent
case opInt8:
return opStructFieldHeadInt8
case opInt8Indent:
return opStructFieldHeadInt8Indent
case opInt16:
return opStructFieldHeadInt16
case opInt16Indent:
return opStructFieldHeadInt16Indent
case opInt32:
return opStructFieldHeadInt32
case opInt32Indent:
return opStructFieldHeadInt32Indent
case opInt64:
return opStructFieldHeadInt64
case opInt64Indent:
return opStructFieldHeadInt64Indent
case opUint:
return opStructFieldHeadUint
case opUintIndent:
return opStructFieldHeadUintIndent
case opUint8:
return opStructFieldHeadUint8
case opUint8Indent:
return opStructFieldHeadUint8Indent
case opUint16:
return opStructFieldHeadUint16
case opUint16Indent:
return opStructFieldHeadUint16Indent
case opUint32:
return opStructFieldHeadUint32
case opUint32Indent:
return opStructFieldHeadUint32Indent
case opUint64:
return opStructFieldHeadUint64
case opUint64Indent:
return opStructFieldHeadUint64Indent
case opFloat32:
return opStructFieldHeadFloat32
case opFloat32Indent:
return opStructFieldHeadFloat32Indent
case opFloat64:
return opStructFieldHeadFloat64
case opFloat64Indent:
return opStructFieldHeadFloat64Indent
case opString:
return opStructFieldHeadString
case opStringIndent:
return opStructFieldHeadStringIndent
case opBool:
return opStructFieldHeadBool
case opBoolIndent:
return opStructFieldHeadBoolIndent
case opMapHead:
return opStructFieldHeadMap
case opMapHeadLoad:
return opStructFieldHeadMapLoad
case opMapHeadIndent:
return opStructFieldHeadMapIndent
case opMapHeadLoadIndent:
return opStructFieldHeadMapLoadIndent
case opArrayHead:
return opStructFieldHeadArray
case opArrayHeadIndent:
return opStructFieldHeadArrayIndent
case opSliceHead:
return opStructFieldHeadSlice
case opSliceHeadIndent:
return opStructFieldHeadSliceIndent
case opStructFieldHead:
return opStructFieldHeadStruct
case opStructFieldHeadIndent:
return opStructFieldHeadStructIndent
case opMarshalJSON:
return opStructFieldHeadMarshalJSON
case opMarshalJSONIndent:
return opStructFieldHeadMarshalJSONIndent
case opMarshalText:
return opStructFieldHeadMarshalText
case opMarshalTextIndent:
return opStructFieldHeadMarshalTextIndent
}
return opStructFieldHead
}
@ -753,93 +688,51 @@ func (e *Encoder) typeToFieldType(ctx *encodeCompileContext, code *opcode) opTyp
}
case opInt:
return opStructFieldInt
case opIntIndent:
return opStructFieldIntIndent
case opInt8:
return opStructFieldInt8
case opInt8Indent:
return opStructFieldInt8Indent
case opInt16:
return opStructFieldInt16
case opInt16Indent:
return opStructFieldInt16Indent
case opInt32:
return opStructFieldInt32
case opInt32Indent:
return opStructFieldInt32Indent
case opInt64:
return opStructFieldInt64
case opInt64Indent:
return opStructFieldInt64Indent
case opUint:
return opStructFieldUint
case opUintIndent:
return opStructFieldUintIndent
case opUint8:
return opStructFieldUint8
case opUint8Indent:
return opStructFieldUint8Indent
case opUint16:
return opStructFieldUint16
case opUint16Indent:
return opStructFieldUint16Indent
case opUint32:
return opStructFieldUint32
case opUint32Indent:
return opStructFieldUint32Indent
case opUint64:
return opStructFieldUint64
case opUint64Indent:
return opStructFieldUint64Indent
case opFloat32:
return opStructFieldFloat32
case opFloat32Indent:
return opStructFieldFloat32Indent
case opFloat64:
return opStructFieldFloat64
case opFloat64Indent:
return opStructFieldFloat64Indent
case opString:
return opStructFieldString
case opStringIndent:
return opStructFieldStringIndent
case opBool:
return opStructFieldBool
case opBoolIndent:
return opStructFieldBoolIndent
case opMapHead:
return opStructFieldMap
case opMapHeadLoad:
return opStructFieldMapLoad
case opMapHeadIndent:
return opStructFieldMapIndent
case opMapHeadLoadIndent:
return opStructFieldMapLoadIndent
case opArrayHead:
return opStructFieldArray
case opArrayHeadIndent:
return opStructFieldArrayIndent
case opSliceHead:
return opStructFieldSlice
case opSliceHeadIndent:
return opStructFieldSliceIndent
case opStructFieldHead:
return opStructFieldStruct
case opStructFieldHeadIndent:
return opStructFieldStructIndent
case opMarshalJSON:
return opStructFieldMarshalJSON
case opMarshalJSONIndent:
return opStructFieldMarshalJSONIndent
case opMarshalText:
return opStructFieldMarshalText
case opMarshalTextIndent:
return opStructFieldMarshalTextIndent
}
return opStructField
}
func (e *Encoder) optimizeStructHeader(ctx *encodeCompileContext, code *opcode, tag *structTag, withIndent bool) opType {
func (e *Encoder) optimizeStructHeader(ctx *encodeCompileContext, code *opcode, tag *structTag) opType {
headType := e.typeToHeaderType(ctx, code)
switch {
case tag.isOmitEmpty:
@ -847,13 +740,10 @@ func (e *Encoder) optimizeStructHeader(ctx *encodeCompileContext, code *opcode,
case tag.isString:
headType = headType.headToStringTagHead()
}
if withIndent {
return headType.toIndent()
}
return headType
}
func (e *Encoder) optimizeStructField(ctx *encodeCompileContext, code *opcode, tag *structTag, withIndent bool) opType {
func (e *Encoder) optimizeStructField(ctx *encodeCompileContext, code *opcode, tag *structTag) opType {
fieldType := e.typeToFieldType(ctx, code)
switch {
case tag.isOmitEmpty:
@ -861,9 +751,6 @@ func (e *Encoder) optimizeStructField(ctx *encodeCompileContext, code *opcode, t
case tag.isString:
fieldType = fieldType.fieldToStringTagField()
}
if withIndent {
return fieldType.toIndent()
}
return fieldType
}
@ -884,7 +771,7 @@ func (e *Encoder) compiledCode(ctx *encodeCompileContext) *opcode {
func (e *Encoder) structHeader(ctx *encodeCompileContext, fieldCode *opcode, valueCode *opcode, tag *structTag) *opcode {
fieldCode.indent--
op := e.optimizeStructHeader(ctx, valueCode, tag, ctx.withIndent)
op := e.optimizeStructHeader(ctx, valueCode, tag)
fieldCode.op = op
fieldCode.ptrNum = valueCode.ptrNum
switch op {
@ -900,20 +787,7 @@ func (e *Encoder) structHeader(ctx *encodeCompileContext, fieldCode *opcode, val
opStructFieldHeadOmitEmptyMap,
opStructFieldHeadOmitEmptyMapLoad,
opStructFieldHeadOmitEmptyStruct,
opStructFieldHeadStringTag,
opStructFieldHeadIndent,
opStructFieldHeadSliceIndent,
opStructFieldHeadArrayIndent,
opStructFieldHeadMapIndent,
opStructFieldHeadMapLoadIndent,
opStructFieldHeadStructIndent,
opStructFieldHeadOmitEmptyIndent,
opStructFieldHeadOmitEmptySliceIndent,
opStructFieldHeadOmitEmptyArrayIndent,
opStructFieldHeadOmitEmptyMapIndent,
opStructFieldHeadOmitEmptyMapLoadIndent,
opStructFieldHeadOmitEmptyStructIndent,
opStructFieldHeadStringTagIndent:
opStructFieldHeadStringTag:
return valueCode.beforeLastCode()
}
ctx.decOpcodeIndex()
@ -922,7 +796,7 @@ func (e *Encoder) structHeader(ctx *encodeCompileContext, fieldCode *opcode, val
func (e *Encoder) structField(ctx *encodeCompileContext, fieldCode *opcode, valueCode *opcode, tag *structTag) *opcode {
code := (*opcode)(unsafe.Pointer(fieldCode))
op := e.optimizeStructField(ctx, valueCode, tag, ctx.withIndent)
op := e.optimizeStructField(ctx, valueCode, tag)
fieldCode.op = op
fieldCode.ptrNum = valueCode.ptrNum
switch op {
@ -938,20 +812,7 @@ func (e *Encoder) structField(ctx *encodeCompileContext, fieldCode *opcode, valu
opStructFieldOmitEmptyMap,
opStructFieldOmitEmptyMapLoad,
opStructFieldOmitEmptyStruct,
opStructFieldStringTag,
opStructFieldIndent,
opStructFieldSliceIndent,
opStructFieldArrayIndent,
opStructFieldMapIndent,
opStructFieldMapLoadIndent,
opStructFieldStructIndent,
opStructFieldOmitEmptyIndent,
opStructFieldOmitEmptySliceIndent,
opStructFieldOmitEmptyArrayIndent,
opStructFieldOmitEmptyMapIndent,
opStructFieldOmitEmptyMapLoadIndent,
opStructFieldOmitEmptyStructIndent,
opStructFieldStringTagIndent:
opStructFieldStringTag:
return valueCode.beforeLastCode()
}
ctx.decIndex()
@ -988,10 +849,10 @@ func (e *Encoder) optimizeAnonymousFields(head *opcode) {
var prev *opcode
removedFields := map[*opcode]struct{}{}
for {
if code.op == opStructEnd || code.op == opStructEndIndent {
if code.op == opStructEnd {
break
}
if code.op == opStructField || code.op == opStructFieldIndent {
if code.op == opStructField {
codeType := code.next.op.codeType()
if codeType == codeStructField {
if e.isNotExistsField(code.next) {
@ -1252,9 +1113,6 @@ func (e *Encoder) compileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode,
}
structEndCode.prevField = head
ctx.incIndex()
if ctx.withIndent {
head.op = opStructFieldHeadIndent
}
code = head
}
@ -1262,10 +1120,6 @@ func (e *Encoder) compileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode,
structEndCode.idx = opcodeOffset(ctx.ptrIndex)
ctx.incIndex()
if ctx.withIndent {
structEndCode.op = opStructEndIndent
}
if prevField != nil && prevField.nextField == nil {
prevField.nextField = structEndCode
structEndCode.prevField = prevField

View File

@ -6,7 +6,6 @@ import (
type encodeCompileContext struct {
typ *rtype
withIndent bool
root bool
opcodeIndex int
ptrIndex int
@ -19,7 +18,6 @@ type encodeCompileContext struct {
func (c *encodeCompileContext) context() *encodeCompileContext {
return &encodeCompileContext{
typ: c.typ,
withIndent: c.withIndent,
root: c.root,
opcodeIndex: c.opcodeIndex,
ptrIndex: c.ptrIndex,

View File

@ -53,10 +53,35 @@ func copyOpcode(code *opcode) *opcode {
return code.copy(codeMap)
}
func newOpCodeWithNext(ctx *encodeCompileContext, op opType, next *opcode) *opcode {
if op != opEnd && ctx.withIndent {
op = op.toIndent()
func toIndent(c *opcode) *opcode {
c = copyOpcode(c)
for code := c; code.op != opEnd; {
code.op = code.op.toIndent()
switch code.op.codeType() {
case codeArrayElem, codeSliceElem, codeMapKey:
code = code.end
default:
code = code.next
}
}
return c
}
func toEscaped(c *opcode) *opcode {
c = copyOpcode(c)
for code := c; code.op != opEnd; {
code.op = code.op.toEscaped()
switch code.op.codeType() {
case codeArrayElem, codeSliceElem, codeMapKey:
code = code.end
default:
code = code.next
}
}
return c
}
func newOpCodeWithNext(ctx *encodeCompileContext, op opType, next *opcode) *opcode {
return &opcode{
op: op,
typ: ctx.typ,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff