Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
351 changes: 180 additions & 171 deletions cmd/protoc-gen-cpp-tableau-loader/index.go

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions cmd/protoc-gen-cpp-tableau-loader/messager.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func genHppMessage(gen *protogen.Plugin, file *protogen.File, g *protogen.Genera
pkg := string(file.Desc.Package())
cppFullName := strings.ReplaceAll(pkg, ".", "::") + "::" + string(message.Desc.Name())
messagerFullName := string(message.Desc.FullName())
indexDescriptors := index.ParseIndexDescriptor(gen, message.Desc)
indexDescriptor := index.ParseIndexDescriptor(message.Desc)

g.P("class ", message.Desc.Name(), " : public Messager {")
g.P(" public:")
Expand Down Expand Up @@ -108,7 +108,7 @@ func genHppMessage(gen *protogen.Plugin, file *protogen.File, g *protogen.Genera
}
if options.NeedGenIndex(message.Desc, options.LangCPP) {
g.P()
genHppIndexFinders(g, indexDescriptors)
genHppIndexFinders(g, indexDescriptor)
}
g.P("};")
g.P()
Expand Down Expand Up @@ -154,7 +154,7 @@ func generateCppFileContent(gen *protogen.Plugin, file *protogen.File, g *protog
func genCppMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, message *protogen.Message) {
messagerName := string(message.Desc.Name())
messagerFullName := string(message.Desc.FullName())
indexDescriptors := index.ParseIndexDescriptor(gen, message.Desc)
indexDescriptor := index.ParseIndexDescriptor(message.Desc)

g.P("const std::string ", messagerName, "::kProtoName = ", `"`, messagerName, `";`)
g.P()
Expand All @@ -173,7 +173,7 @@ func genCppMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, message *pro
genCppOrderedMapLoader(g, message.Desc, 1, messagerFullName)
}
if options.NeedGenIndex(message.Desc, options.LangCPP) {
genCppIndexLoader(g, indexDescriptors)
genCppIndexLoader(g, indexDescriptor)
}
g.P(" return true;")
g.P("}")
Expand All @@ -184,7 +184,7 @@ func genCppMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, message *pro
genCppMapGetters(g, message.Desc, 1, nil, messagerName)
genCppOrderedMapGetters(g, message.Desc, 1, nil, messagerName, messagerFullName)
if options.NeedGenIndex(message.Desc, options.LangCPP) {
genCppIndexFinders(g, indexDescriptors, messagerName)
genCppIndexFinders(g, indexDescriptor, messagerName)
g.P()
}
}
Expand Down
1 change: 1 addition & 0 deletions cmd/protoc-gen-cpp-tableau-loader/ordered_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ func genHppOrderedMapGetters(g *protogen.GeneratedFile, md protoreflect.MessageD
func genCppOrderedMapLoader(g *protogen.GeneratedFile, md protoreflect.MessageDescriptor, depth int, messagerFullName string) {
if depth == 1 {
g.P(" // OrderedMap init.")
g.P(" ordered_map_.clear();")
}
for i := 0; i < md.Fields().Len(); i++ {
fd := md.Fields().Get(i)
Expand Down
250 changes: 129 additions & 121 deletions cmd/protoc-gen-go-tableau-loader/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,104 +9,111 @@ import (
"google.golang.org/protobuf/compiler/protogen"
)

func genIndexTypeDef(gen *protogen.Plugin, g *protogen.GeneratedFile, descriptors []*index.IndexDescriptor, messagerName string) {
func genIndexTypeDef(gen *protogen.Plugin, g *protogen.GeneratedFile, descriptor *index.IndexDescriptor, messagerName string) {
g.P("// Index types.")
for _, descriptor := range descriptors {
if len(descriptor.Fields) == 1 {
// single-column index
field := descriptor.Fields[0] // just take first field
g.P("// Index: ", descriptor.Index)
mapType := fmt.Sprintf("%s_Index_%sMap", messagerName, descriptor.Name)
keyType := helper.ParseGoType(gen, field.FD)
g.P("type ", mapType, " = map[", keyType, "][]*", helper.FindMessageGoIdent(gen, descriptor.MD))
} else {
// multi-column index
g.P("// Index: ", descriptor.Index)
keyType := fmt.Sprintf("%s_Index_%sKey", messagerName, descriptor.Name)
mapType := fmt.Sprintf("%s_Index_%sMap", messagerName, descriptor.Name)
for levelMessage := descriptor.LevelMessage; levelMessage != nil; levelMessage = levelMessage.NextLevel {
for _, index := range levelMessage.Indexes {
if len(index.ColFields) == 1 {
// single-column index
field := index.ColFields[0] // just take first field
g.P("// Index: ", index.Index)
mapType := fmt.Sprintf("%s_Index_%sMap", messagerName, index.Name())
keyType := helper.ParseGoType(gen, field.FD)
g.P("type ", mapType, " = map[", keyType, "][]*", helper.FindMessageGoIdent(gen, index.MD))
} else {
// multi-column index
g.P("// Index: ", index.Index)
keyType := fmt.Sprintf("%s_Index_%sKey", messagerName, index.Name())
mapType := fmt.Sprintf("%s_Index_%sMap", messagerName, index.Name())

// generate key struct
// KeyType must be comparable, refer https://go.dev/blog/maps
g.P("type ", keyType, " struct {")
for _, field := range descriptor.Fields {
g.P(helper.ParseIndexFieldNameAsKeyStructFieldName(gen, field.FD), " ", helper.ParseGoType(gen, field.FD))
// generate key struct
// KeyType must be comparable, refer https://go.dev/blog/maps
g.P("type ", keyType, " struct {")
for _, field := range index.ColFields {
g.P(helper.ParseIndexFieldNameAsKeyStructFieldName(gen, field.FD), " ", helper.ParseGoType(gen, field.FD))
}
g.P("}")
g.P("type ", mapType, " = map[", keyType, "][]*", helper.FindMessageGoIdent(gen, index.MD))
}
g.P("}")
g.P("type ", mapType, " = map[", keyType, "][]*", helper.FindMessageGoIdent(gen, descriptor.MD))
g.P()
}
g.P()
}
}

func genIndexField(g *protogen.GeneratedFile, descriptors []*index.IndexDescriptor, messagerName string) {
for _, descriptor := range descriptors {
indexContainerName := "index" + strcase.ToCamel(descriptor.Name) + "Map"
mapType := fmt.Sprintf("%s_Index_%sMap", messagerName, descriptor.Name)
g.P(indexContainerName, " ", mapType)
func genIndexField(g *protogen.GeneratedFile, descriptor *index.IndexDescriptor, messagerName string) {
for levelMessage := descriptor.LevelMessage; levelMessage != nil; levelMessage = levelMessage.NextLevel {
for _, index := range levelMessage.Indexes {
indexContainerName := "index" + strcase.ToCamel(index.Name()) + "Map"
mapType := fmt.Sprintf("%s_Index_%sMap", messagerName, index.Name())
g.P(indexContainerName, " ", mapType)
}
}
}

func genIndexLoader(gen *protogen.Plugin, g *protogen.GeneratedFile, descriptors []*index.IndexDescriptor, messagerName string) {
func genIndexLoader(gen *protogen.Plugin, g *protogen.GeneratedFile, descriptor *index.IndexDescriptor, messagerName string) {
g.P(" // Index init.")
for _, descriptor := range descriptors {
parentDataName := "x.data"
g.P(" // Index: ", descriptor.Index)
genOneIndexLoader(gen, g, 1, descriptor, parentDataName, descriptor.LevelMessage, messagerName)
}
}

func genOneIndexLoader(gen *protogen.Plugin, g *protogen.GeneratedFile, depth int, descriptor *index.IndexDescriptor,
parentDataName string, levelMessage *index.LevelMessage, messagerName string) {
if levelMessage == nil {
return
}
indexContainerName := "index" + strcase.ToCamel(descriptor.Name) + "Map"
if depth == 1 {
g.P("x.", indexContainerName, " = make(", fmt.Sprintf("%s_Index_%sMap", messagerName, descriptor.Name), ")")
for levelMessage := descriptor.LevelMessage; levelMessage != nil; levelMessage = levelMessage.NextLevel {
for _, index := range levelMessage.Indexes {
indexContainerName := "index" + strcase.ToCamel(index.Name()) + "Map"
g.P("x.", indexContainerName, " = make(", fmt.Sprintf("%s_Index_%sMap", messagerName, index.Name()), ")")
}
}
if levelMessage.NextLevel != nil {
parentDataName := "x.data"
depth := 1
for levelMessage := descriptor.LevelMessage; levelMessage != nil; levelMessage = levelMessage.NextLevel {
for _, index := range levelMessage.Indexes {
genOneIndexLoader(gen, g, depth, index, parentDataName, messagerName)
}
itemName := fmt.Sprintf("item%d", depth)
if levelMessage.FD == nil {
break
}
g.P("for _, ", itemName, " := range "+parentDataName+".Get"+helper.ParseIndexFieldName(gen, levelMessage.FD)+"() {")
parentDataName = itemName
genOneIndexLoader(gen, g, depth+1, descriptor, parentDataName, levelMessage.NextLevel, messagerName)
g.P("}")
} else {
if len(levelMessage.Fields) == 1 {
// single-column index
field := levelMessage.Fields[0] // just take the first field
if field.FD.IsList() {
itemName := fmt.Sprintf("item%d", depth)
fieldName := ""
for _, leveledFd := range field.LeveledFDList {
fieldName += ".Get" + helper.ParseIndexFieldName(gen, leveledFd) + "()"
}
g.P("for _, ", itemName, " := range "+parentDataName+fieldName+" {")
g.P("key := ", itemName)
g.P("x.", indexContainerName, "[key] = append(x.", indexContainerName, "[key], ", parentDataName, ")")
g.P("}")
} else {
fieldName := ""
for _, leveledFd := range field.LeveledFDList {
fieldName += ".Get" + helper.ParseIndexFieldName(gen, leveledFd) + "()"
}
g.P("key := ", parentDataName+fieldName)
g.P("x.", indexContainerName, "[key] = append(x.", indexContainerName, "[key], ", parentDataName, ")")
defer g.P("}")
depth++
}
}

func genOneIndexLoader(gen *protogen.Plugin, g *protogen.GeneratedFile, depth int, index *index.LevelIndex,
parentDataName string, messagerName string) {
indexContainerName := "index" + strcase.ToCamel(index.Name()) + "Map"
g.P("{")
g.P(" // Index: ", index.Index)
if len(index.ColFields) == 1 {
// single-column index
field := index.ColFields[0] // just take the first field
if field.FD.IsList() {
itemName := fmt.Sprintf("item%d", depth)
fieldName := ""
for _, leveledFd := range field.LeveledFDList {
fieldName += ".Get" + helper.ParseIndexFieldName(gen, leveledFd) + "()"
}
g.P("for _, ", itemName, " := range "+parentDataName+fieldName+" {")
g.P("key := ", itemName)
g.P("x.", indexContainerName, "[key] = append(x.", indexContainerName, "[key], ", parentDataName, ")")
g.P("}")
} else {
// multi-column index
var keys []string
generateOneMulticolumnIndex(gen, g, depth, descriptor, parentDataName, keys)
fieldName := ""
for _, leveledFd := range field.LeveledFDList {
fieldName += ".Get" + helper.ParseIndexFieldName(gen, leveledFd) + "()"
}
g.P("key := ", parentDataName+fieldName)
g.P("x.", indexContainerName, "[key] = append(x.", indexContainerName, "[key], ", parentDataName, ")")
}
} else {
// multi-column index
generateOneMulticolumnIndex(gen, g, depth, index, parentDataName, messagerName, nil)
}
if depth == 1 && len(descriptor.KeyFields) != 0 {
if len(index.KeyFields) != 0 {
g.P("for _, item := range x.", indexContainerName, " {")
g.P(sortPackage.Ident("Slice"), "(item, func(i, j int) bool {")
for i, field := range descriptor.KeyFields {
for i, field := range index.KeyFields {
fieldName := ""
for _, leveledFd := range field.LeveledFDList {
fieldName += ".Get" + helper.ParseIndexFieldName(gen, leveledFd) + "()"
}
if i == len(descriptor.KeyFields)-1 {
if i == len(index.KeyFields)-1 {
g.P("return item[i]", fieldName, " < item[j]", fieldName)
} else {
g.P("if item[i]", fieldName, " != item[j]", fieldName, " {")
Expand All @@ -117,26 +124,27 @@ func genOneIndexLoader(gen *protogen.Plugin, g *protogen.GeneratedFile, depth in
g.P("})")
g.P("}")
}
g.P("}")
}

func generateOneMulticolumnIndex(gen *protogen.Plugin, g *protogen.GeneratedFile,
depth int, descriptor *index.IndexDescriptor, parentDataName string, keys []string) []string {
depth int, index *index.LevelIndex, parentDataName string, messagerName string, keys []string) []string {
cursor := len(keys)
if cursor >= len(descriptor.Fields) {
if cursor >= len(index.ColFields) {
var keyParams string
for i, key := range keys {
keyParams += key
if i != len(keys)-1 {
keyParams += ", "
}
}
keyType := fmt.Sprintf("%s_Index_%sKey", descriptor.LevelMessage.FD.ContainingMessage().Name(), descriptor.Name)
indexContainerName := "index" + strcase.ToCamel(descriptor.Name) + "Map"
keyType := fmt.Sprintf("%s_Index_%sKey", messagerName, index.Name())
indexContainerName := "index" + strcase.ToCamel(index.Name()) + "Map"
g.P("key := ", keyType, " {", keyParams, "}")
g.P("x.", indexContainerName, "[key] = append(x.", indexContainerName, "[key], ", parentDataName, ")")
return keys
}
field := descriptor.Fields[cursor]
field := index.ColFields[cursor]
if field.FD.IsList() {
itemName := fmt.Sprintf("indexItem%d", cursor)
fieldName := ""
Expand All @@ -145,7 +153,7 @@ func generateOneMulticolumnIndex(gen *protogen.Plugin, g *protogen.GeneratedFile
}
g.P("for _, " + itemName + " := range " + parentDataName + fieldName + " {")
keys = append(keys, itemName)
keys = generateOneMulticolumnIndex(gen, g, depth+1, descriptor, parentDataName, keys)
keys = generateOneMulticolumnIndex(gen, g, depth+1, index, parentDataName, messagerName, keys)
g.P("}")
} else {
fieldName := ""
Expand All @@ -154,56 +162,56 @@ func generateOneMulticolumnIndex(gen *protogen.Plugin, g *protogen.GeneratedFile
}
key := parentDataName + fieldName
keys = append(keys, key)
keys = generateOneMulticolumnIndex(gen, g, depth, descriptor, parentDataName, keys)
keys = generateOneMulticolumnIndex(gen, g, depth, index, parentDataName, messagerName, keys)
}
return keys
}

func genIndexFinders(gen *protogen.Plugin, g *protogen.GeneratedFile, descriptors []*index.IndexDescriptor, messagerName string) {
for _, descriptor := range descriptors {
// sliceType := "[]*" + descriptor.GoIdent
mapType := fmt.Sprintf("%s_Index_%sMap", messagerName, descriptor.Name)
indexContainerName := "index" + strcase.ToCamel(descriptor.Name) + "Map"
func genIndexFinders(gen *protogen.Plugin, g *protogen.GeneratedFile, descriptor *index.IndexDescriptor, messagerName string) {
for levelMessage := descriptor.LevelMessage; levelMessage != nil; levelMessage = levelMessage.NextLevel {
for _, index := range levelMessage.Indexes {
mapType := fmt.Sprintf("%s_Index_%sMap", messagerName, index.Name())
indexContainerName := "index" + strcase.ToCamel(index.Name()) + "Map"

g.P("// Index: ", descriptor.Index)
g.P()
g.P("// Index: ", index.Index)
g.P()

g.P("// Find", descriptor.Name, "Map returns the index(", descriptor.Index, ") to value(", helper.FindMessageGoIdent(gen, descriptor.MD), ") map.")
g.P("// One key may correspond to multiple values, which are contained by a slice.")
g.P("func (x *", messagerName, ") Find", descriptor.Name, "Map() ", mapType, " {")
g.P("return x.", indexContainerName)
g.P("}")
g.P()

var keyType any
var keyName string
if len(descriptor.Fields) == 1 {
// single-column index
field := descriptor.Fields[0] // just take first field
keyType = helper.ParseGoType(gen, field.FD)
keyName = helper.ParseIndexFieldNameAsFuncParam(gen, field.FD)
} else {
// multi-column index
keyType = fmt.Sprintf("%s_Index_%sKey", descriptor.LevelMessage.FD.ContainingMessage().Name(), descriptor.Name)
keyName = "key"
}
g.P("// Find", index.Name(), "Map returns the index(", index.Index, ") to value(", helper.FindMessageGoIdent(gen, index.MD), ") map.")
g.P("// One key may correspond to multiple values, which are contained by a slice.")
g.P("func (x *", messagerName, ") Find", index.Name(), "Map() ", mapType, " {")
g.P("return x.", indexContainerName)
g.P("}")
g.P()

g.P("// Find", descriptor.Name, " returns a slice of all values of the given key.")
g.P("func (x *", messagerName, ") Find", descriptor.Name, "(", keyName, " ", keyType, ") []*", helper.FindMessageGoIdent(gen, descriptor.MD), " {")
g.P("return x.", indexContainerName, "[", keyName, "]")
g.P("}")
g.P()
var keyType any
var keyName string
if len(index.ColFields) == 1 {
// single-column index
field := index.ColFields[0] // just take first field
keyType = helper.ParseGoType(gen, field.FD)
keyName = helper.ParseIndexFieldNameAsFuncParam(gen, field.FD)
} else {
// multi-column index
keyType = fmt.Sprintf("%s_Index_%sKey", messagerName, index.Name())
keyName = "key"
}

g.P("// FindFirst", descriptor.Name, " returns the first value of the given key,")
g.P("// or nil if the key correspond to no value.")
g.P("func (x *", messagerName, ") FindFirst", descriptor.Name, "(", keyName, " ", keyType, ") *", helper.FindMessageGoIdent(gen, descriptor.MD), " {")
g.P("val := x.", indexContainerName, "[", keyName, "]")
g.P("if len(val) > 0 {")
g.P("return val[0]")
g.P("}")
g.P("return nil")
g.P("}")
g.P()
g.P("// Find", index.Name(), " returns a slice of all values of the given key.")
g.P("func (x *", messagerName, ") Find", index.Name(), "(", keyName, " ", keyType, ") []*", helper.FindMessageGoIdent(gen, index.MD), " {")
g.P("return x.", indexContainerName, "[", keyName, "]")
g.P("}")
g.P()

g.P("// FindFirst", index.Name(), " returns the first value of the given key,")
g.P("// or nil if the key correspond to no value.")
g.P("func (x *", messagerName, ") FindFirst", index.Name(), "(", keyName, " ", keyType, ") *", helper.FindMessageGoIdent(gen, index.MD), " {")
g.P("val := x.", indexContainerName, "[", keyName, "]")
g.P("if len(val) > 0 {")
g.P("return val[0]")
g.P("}")
g.P("return nil")
g.P("}")
g.P()
}
}
}
Loading