diff --git a/cmd/protoc-gen-cpp-tableau-loader/helper/helper.go b/cmd/protoc-gen-cpp-tableau-loader/helper/helper.go index 8f2b2796..2536c7f2 100644 --- a/cmd/protoc-gen-cpp-tableau-loader/helper/helper.go +++ b/cmd/protoc-gen-cpp-tableau-loader/helper/helper.go @@ -88,6 +88,61 @@ func ParseCppType(fd protoreflect.FieldDescriptor) string { } } +// ParseMapKeyType converts a FieldDescriptor to its map key type. +// fd must be an comparable type. +func ParseMapKeyType(fd protoreflect.FieldDescriptor) string { + switch fd.Kind() { + case protoreflect.BoolKind: + return "bool" + case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.EnumKind: + return "int32_t" + case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: + return "uint32_t" + case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: + return "int64_t" + case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: + return "uint64_t" + case protoreflect.FloatKind: + return "float" + case protoreflect.DoubleKind: + return "double" + case protoreflect.StringKind: + return "std::string" + default: + panic(fmt.Sprintf("unsupported kind: %d", fd.Kind())) + } +} + +// ParseOrderedMapKeyType converts a FieldDescriptor to its treemap key type. +// fd must be an ordered type, or a message which can be converted to an ordered type. +func ParseOrderedMapKeyType(fd protoreflect.FieldDescriptor) string { + switch fd.Kind() { + case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.EnumKind: + return "int32_t" + case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: + return "uint32_t" + case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: + return "int64_t" + case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: + return "uint64_t" + case protoreflect.FloatKind: + return "float" + case protoreflect.DoubleKind: + return "double" + case protoreflect.StringKind: + return "std::string" + case protoreflect.MessageKind: + switch fd.Message().FullName() { + case "google.protobuf.Timestamp", "google.protobuf.Duration": + return "int64_t" + default: + } + fallthrough + default: + panic(fmt.Sprintf("unsupported kind: %d", fd.Kind())) + } +} + func ToConstRefType(cpptype string) string { if cpptype == "std::string" { return "const std::string&" @@ -125,7 +180,7 @@ func AddMapKey(fd protoreflect.FieldDescriptor, keys []MapKey) []MapKey { } } } - keys = append(keys, MapKey{ParseCppType(fd.MapKey()), name}) + keys = append(keys, MapKey{ParseMapKeyType(fd.MapKey()), name}) return keys } diff --git a/cmd/protoc-gen-cpp-tableau-loader/index.go b/cmd/protoc-gen-cpp-tableau-loader/index.go index 011838ee..cd9e5ed9 100644 --- a/cmd/protoc-gen-cpp-tableau-loader/index.go +++ b/cmd/protoc-gen-cpp-tableau-loader/index.go @@ -23,8 +23,12 @@ func genHppIndexFinders(g *protogen.GeneratedFile, descriptor *index.IndexDescri g.P(helper.Indent(1), "using ", vectorType, " = std::vector;") keyType := helper.ParseCppType(field.FD) g.P(helper.Indent(1), "using ", mapType, " = std::unordered_map<", keyType, ", ", vectorType, ">;") + g.P(helper.Indent(1), "// Finds the index (", index.Index, ") to value (", vectorType, ") hash map.") + g.P(helper.Indent(1), "// One key may correspond to multiple values, which are contained by a vector.") g.P(helper.Indent(1), "const ", mapType, "& Find", index.Name(), "() const;") + g.P(helper.Indent(1), "// Finds a vector of all values of the given key.") g.P(helper.Indent(1), "const ", vectorType, "* Find", index.Name(), "(", helper.ToConstRefType(keyType), " ", helper.ParseIndexFieldNameAsFuncParam(field.FD), ") const;") + g.P(helper.Indent(1), "// Finds the first value of the given key.") g.P(helper.Indent(1), "const ", helper.ParseCppClassType(index.MD), "* FindFirst", index.Name(), "(", helper.ToConstRefType(keyType), " ", helper.ParseIndexFieldNameAsFuncParam(field.FD), ") const;") g.P() @@ -73,8 +77,12 @@ func genHppIndexFinders(g *protogen.GeneratedFile, descriptor *index.IndexDescri g.P(helper.Indent(1), "using ", vectorType, " = std::vector;") g.P(helper.Indent(1), "using ", mapType, " = std::unordered_map<", keyType, ", ", vectorType, ", ", keyHasherType, ">;") + g.P(helper.Indent(1), "// Finds the index (", index.Index, ") to value (", vectorType, ") hash map.") + g.P(helper.Indent(1), "// One key may correspond to multiple values, which are contained by a vector.") g.P(helper.Indent(1), "const ", mapType, "& Find", index.Name(), "() const;") + g.P(helper.Indent(1), "// Finds a vector of all values of the given key.") g.P(helper.Indent(1), "const ", vectorType, "* Find", index.Name(), "(const ", keyType, "& key) const;") + g.P(helper.Indent(1), "// Finds the first value of the given key.") g.P(helper.Indent(1), "const ", helper.ParseCppClassType(index.MD), "* FindFirst", index.Name(), "(const ", keyType, "& key) const;") g.P() @@ -108,7 +116,7 @@ func genCppIndexLoader(g *protogen.GeneratedFile, descriptor *index.IndexDescrip if !levelMessage.NextLevel.NeedGen() { break } - g.P(helper.Indent(depth), "for (auto&& "+itemName+" : "+parentDataName+"."+helper.ParseIndexFieldName(levelMessage.FD)+"()) {") + g.P(helper.Indent(depth), "for (auto&& ", itemName, " : ", parentDataName, ".", helper.ParseIndexFieldName(levelMessage.FD), "()) {") parentDataName = itemName if levelMessage.FD.IsMap() { parentDataName = itemName + ".second" @@ -134,12 +142,12 @@ func genOneCppIndexLoader(g *protogen.GeneratedFile, depth int, index *index.Lev for _, leveledFd := range field.LeveledFDList { fieldName += "." + helper.ParseIndexFieldName(leveledFd) + "()" } - g.P(helper.Indent(depth+1), "for (auto&& "+itemName+" : "+parentDataName+fieldName+") {") + g.P(helper.Indent(depth+1), "for (auto&& ", itemName, " : ", parentDataName, fieldName, ") {") key := itemName if field.FD.Enum() != nil { key = "static_cast<" + helper.ParseCppType(field.FD) + ">(" + key + ")" } - g.P(helper.Indent(depth+2), indexContainerName, "["+key+"].push_back(&"+parentDataName+");") + g.P(helper.Indent(depth+2), indexContainerName, "[", key, "].push_back(&", parentDataName, ");") g.P(helper.Indent(depth+1), "}") } else { fieldName := "" @@ -147,7 +155,7 @@ func genOneCppIndexLoader(g *protogen.GeneratedFile, depth int, index *index.Lev fieldName += "." + helper.ParseIndexFieldName(leveledFd) + "()" } key := parentDataName + fieldName - g.P(helper.Indent(depth+1), indexContainerName, "["+key+"].push_back(&"+parentDataName+");") + g.P(helper.Indent(depth+1), indexContainerName, "[", key, "].push_back(&", parentDataName, ");") } } else { // multi-column index @@ -202,7 +210,7 @@ func generateOneCppMulticolumnIndex(g *protogen.GeneratedFile, depth int, index keyType := fmt.Sprintf("Index_%sKey", index.Name()) indexContainerName := "index_" + strcase.ToSnake(index.Name()) + "_map_" g.P(helper.Indent(depth+1), keyType, " key{", keyParams, "};") - g.P(helper.Indent(depth+1), indexContainerName, "[key].push_back(&"+parentDataName+");") + g.P(helper.Indent(depth+1), indexContainerName, "[key].push_back(&", parentDataName, ");") return keys } field := index.ColFields[cursor] @@ -212,7 +220,7 @@ func generateOneCppMulticolumnIndex(g *protogen.GeneratedFile, depth int, index for _, leveledFd := range field.LeveledFDList { fieldName += "." + helper.ParseIndexFieldName(leveledFd) + "()" } - g.P(helper.Indent(depth+1), "for (auto&& "+itemName+" : "+parentDataName+fieldName+") {") + g.P(helper.Indent(depth+1), "for (auto&& ", itemName, " : ", parentDataName, fieldName, ") {") key := itemName if field.FD.Enum() != nil { key = "static_cast<" + helper.ParseCppType(field.FD) + ">(" + key + ")" @@ -240,7 +248,7 @@ func genCppIndexFinders(g *protogen.GeneratedFile, descriptor *index.IndexDescri indexContainerName := "index_" + strcase.ToSnake(index.Name()) + "_map_" g.P("// Index: ", index.Index) - g.P("const ", messagerName, "::", mapType, "& "+messagerName+"::Find", index.Name(), "() const { return "+indexContainerName+" ;}") + g.P("const ", messagerName, "::", mapType, "& ", messagerName, "::Find", index.Name(), "() const { return ", indexContainerName, " ;}") g.P() var keyType, keyName string @@ -255,7 +263,7 @@ func genCppIndexFinders(g *protogen.GeneratedFile, descriptor *index.IndexDescri keyName = "key" } - g.P("const ", messagerName, "::", vectorType, "* "+messagerName+"::Find", index.Name(), "(", helper.ToConstRefType(keyType), " ", keyName, ") const {") + g.P("const ", messagerName, "::", vectorType, "* ", messagerName, "::Find", index.Name(), "(", helper.ToConstRefType(keyType), " ", keyName, ") const {") g.P(helper.Indent(1), "auto iter = ", indexContainerName, ".find(", keyName, ");") g.P(helper.Indent(1), "if (iter == ", indexContainerName, ".end()) {") g.P(helper.Indent(2), "return nullptr;") @@ -264,12 +272,12 @@ func genCppIndexFinders(g *protogen.GeneratedFile, descriptor *index.IndexDescri g.P("}") g.P() - g.P("const ", helper.ParseCppClassType(index.MD), "* "+messagerName+"::FindFirst", index.Name(), "(", helper.ToConstRefType(keyType), " ", keyName, ") const {") + g.P("const ", helper.ParseCppClassType(index.MD), "* ", messagerName, "::FindFirst", index.Name(), "(", helper.ToConstRefType(keyType), " ", keyName, ") const {") g.P(helper.Indent(1), "auto conf = Find", index.Name(), "(", keyName, ");") - g.P(helper.Indent(1), "if (conf == nullptr || conf->size() == 0) {") + g.P(helper.Indent(1), "if (conf == nullptr || conf->empty()) {") g.P(helper.Indent(2), "return nullptr;") g.P(helper.Indent(1), "}") - g.P(helper.Indent(1), "return (*conf)[0];") + g.P(helper.Indent(1), "return conf->front();") g.P("}") g.P() } diff --git a/cmd/protoc-gen-cpp-tableau-loader/messager.go b/cmd/protoc-gen-cpp-tableau-loader/messager.go index a653c03e..88326f21 100644 --- a/cmd/protoc-gen-cpp-tableau-loader/messager.go +++ b/cmd/protoc-gen-cpp-tableau-loader/messager.go @@ -90,7 +90,7 @@ func genHppMessage(g *protogen.GeneratedFile, message *protogen.Message) { g.P(helper.Indent(1), "const google::protobuf::Message* Message() const override { return &data_; }") g.P() - if options.NeedGenOrderedMap(message.Desc, options.LangCPP) || options.NeedGenIndex(message.Desc, options.LangCPP) { + if options.NeedGenOrderedMap(message.Desc, options.LangCPP) || options.NeedGenIndex(message.Desc, options.LangCPP) || options.NeedGenOrderedIndex(message.Desc, options.LangCPP) { g.P(" private:") g.P(helper.Indent(1), "virtual bool ProcessAfterLoad() override final;") g.P() @@ -110,6 +110,9 @@ func genHppMessage(g *protogen.GeneratedFile, message *protogen.Message) { g.P() genHppIndexFinders(g, indexDescriptor) } + if options.NeedGenOrderedIndex(message.Desc, options.LangCPP) { + genHppOrderedIndexFinders(g, indexDescriptor) + } g.P("};") g.P() } @@ -168,7 +171,7 @@ func genCppMessage(g *protogen.GeneratedFile, message *protogen.Message) { g.P("}") g.P() - if options.NeedGenOrderedMap(message.Desc, options.LangCPP) || options.NeedGenIndex(message.Desc, options.LangCPP) { + if options.NeedGenOrderedMap(message.Desc, options.LangCPP) || options.NeedGenIndex(message.Desc, options.LangCPP) || options.NeedGenOrderedIndex(message.Desc, options.LangCPP) { g.P("bool ", messagerName, "::ProcessAfterLoad() {") if options.NeedGenOrderedMap(message.Desc, options.LangCPP) { genCppOrderedMapLoader(g, message.Desc, 1, messagerFullName) @@ -176,6 +179,9 @@ func genCppMessage(g *protogen.GeneratedFile, message *protogen.Message) { if options.NeedGenIndex(message.Desc, options.LangCPP) { genCppIndexLoader(g, indexDescriptor) } + if options.NeedGenOrderedIndex(message.Desc, options.LangCPP) { + genCppOrderedIndexLoader(g, indexDescriptor) + } g.P(helper.Indent(1), "return true;") g.P("}") g.P() @@ -188,6 +194,10 @@ func genCppMessage(g *protogen.GeneratedFile, message *protogen.Message) { genCppIndexFinders(g, indexDescriptor, messagerName) g.P() } + if options.NeedGenOrderedIndex(message.Desc, options.LangCPP) { + genCppOrderedIndexFinders(g, indexDescriptor, messagerName) + g.P() + } } func genCppMapGetters(g *protogen.GeneratedFile, md protoreflect.MessageDescriptor, depth int, keys []helper.MapKey, messagerName string) { diff --git a/cmd/protoc-gen-cpp-tableau-loader/ordered_index.go b/cmd/protoc-gen-cpp-tableau-loader/ordered_index.go new file mode 100644 index 00000000..6b675fc8 --- /dev/null +++ b/cmd/protoc-gen-cpp-tableau-loader/ordered_index.go @@ -0,0 +1,190 @@ +package main + +import ( + "fmt" + + "github.com/iancoleman/strcase" + "github.com/tableauio/loader/cmd/protoc-gen-cpp-tableau-loader/helper" + "github.com/tableauio/loader/internal/index" + "google.golang.org/protobuf/compiler/protogen" +) + +func genHppOrderedIndexFinders(g *protogen.GeneratedFile, descriptor *index.IndexDescriptor) { + g.P(helper.Indent(1), "// OrderedIndex accessers.") + for levelMessage := descriptor.LevelMessage; levelMessage != nil; levelMessage = levelMessage.NextLevel { + for _, index := range levelMessage.OrderedIndexes { + // single-column index + field := index.ColFields[0] // just take first field + g.P(helper.Indent(1), "// OrderedIndex: ", index.Index) + g.P(" public:") + vectorType := fmt.Sprintf("OrderedIndex_%sVector", index.Name()) + mapType := fmt.Sprintf("OrderedIndex_%sMap", index.Name()) + g.P(helper.Indent(1), "using ", vectorType, " = std::vector;") + keyType := helper.ParseOrderedMapKeyType(field.FD) + g.P(helper.Indent(1), "using ", mapType, " = std::map<", keyType, ", ", vectorType, ">;") + g.P(helper.Indent(1), "// Finds the ordered index (", index.Index, ") to value (", vectorType, ") hash map.") + g.P(helper.Indent(1), "// One key may correspond to multiple values, which are contained by a vector.") + g.P(helper.Indent(1), "const ", mapType, "& Find", index.Name(), "() const;") + g.P(helper.Indent(1), "// Finds a vector of all values of the given key.") + g.P(helper.Indent(1), "const ", vectorType, "* Find", index.Name(), "(", helper.ToConstRefType(keyType), " ", helper.ParseIndexFieldNameAsFuncParam(field.FD), ") const;") + g.P(helper.Indent(1), "// Finds the first value of the given key.") + g.P(helper.Indent(1), "const ", helper.ParseCppClassType(index.MD), "* FindFirst", index.Name(), "(", helper.ToConstRefType(keyType), " ", helper.ParseIndexFieldNameAsFuncParam(field.FD), ") const;") + g.P() + + g.P(" private:") + indexContainerName := "ordered_index_" + strcase.ToSnake(index.Name()) + "_map_" + g.P(helper.Indent(1), mapType, " ", indexContainerName, ";") + g.P() + } + } +} + +func genCppOrderedIndexLoader(g *protogen.GeneratedFile, descriptor *index.IndexDescriptor) { + g.P(helper.Indent(1), "// OrderedIndex init.") + for levelMessage := descriptor.LevelMessage; levelMessage != nil; levelMessage = levelMessage.NextLevel { + for _, index := range levelMessage.OrderedIndexes { + indexContainerName := "ordered_index_" + strcase.ToSnake(index.Name()) + "_map_" + g.P(helper.Indent(1), indexContainerName, ".clear();") + } + } + parentDataName := "data_" + depth := 1 + for levelMessage := descriptor.LevelMessage; levelMessage != nil; levelMessage = levelMessage.NextLevel { + for _, index := range levelMessage.OrderedIndexes { + genOneCppOrderedIndexLoader(g, depth, index, parentDataName) + } + itemName := fmt.Sprintf("item%d", depth) + if levelMessage.FD == nil { + break + } + if !levelMessage.NextLevel.NeedGen() { + break + } + g.P(helper.Indent(depth), "for (auto&& ", itemName, " : ", parentDataName, ".", helper.ParseIndexFieldName(levelMessage.FD), "()) {") + parentDataName = itemName + if levelMessage.FD.IsMap() { + parentDataName = itemName + ".second" + } + depth++ + } + for i := depth - 1; i > 0; i-- { + g.P(helper.Indent(i), "}") + } + genOrderedIndexSorter(g, descriptor) +} + +func genOneCppOrderedIndexLoader(g *protogen.GeneratedFile, depth int, index *index.LevelIndex, parentDataName string) { + indexContainerName := "ordered_index_" + strcase.ToSnake(index.Name()) + "_map_" + g.P(helper.Indent(depth), "{") + g.P(helper.Indent(depth+1), "// OrderedIndex: ", index.Index) + // single-column index + field := index.ColFields[0] // just take the first field + if field.FD.IsList() { + itemName := fmt.Sprintf("item%d", depth) + fieldName := "" + suffix := "" + for i, leveledFd := range field.LeveledFDList { + fieldName += "." + helper.ParseIndexFieldName(leveledFd) + "()" + if i == len(field.LeveledFDList)-1 && leveledFd.Message() != nil { + switch leveledFd.Message().FullName() { + case "google.protobuf.Timestamp", "google.protobuf.Duration": + suffix = ".seconds()" + default: + } + } + } + g.P(helper.Indent(depth+1), "for (auto&& ", itemName, " : ", parentDataName, fieldName, ") {") + key := itemName + suffix + if field.FD.Enum() != nil { + key = "static_cast<" + helper.ParseCppType(field.FD) + ">(" + key + ")" + } + g.P(helper.Indent(depth+2), indexContainerName, "[", key, "].push_back(&", parentDataName, ");") + g.P(helper.Indent(depth+1), "}") + } else { + fieldName := "" + suffix := "" + for i, leveledFd := range field.LeveledFDList { + fieldName += "." + helper.ParseIndexFieldName(leveledFd) + "()" + if i == len(field.LeveledFDList)-1 && leveledFd.Message() != nil { + switch leveledFd.Message().FullName() { + case "google.protobuf.Timestamp", "google.protobuf.Duration": + suffix = ".seconds()" + default: + } + } + } + key := parentDataName + fieldName + suffix + g.P(helper.Indent(depth+1), indexContainerName, "[", key, "].push_back(&", parentDataName, ");") + } + g.P(helper.Indent(depth), "}") +} + +func genOrderedIndexSorter(g *protogen.GeneratedFile, descriptor *index.IndexDescriptor) { + for levelMessage := descriptor.LevelMessage; levelMessage != nil; levelMessage = levelMessage.NextLevel { + for _, index := range levelMessage.OrderedIndexes { + indexContainerName := "ordered_index_" + strcase.ToSnake(index.Name()) + "_map_" + if len(index.SortedColFields) != 0 { + g.P(helper.Indent(1), "// OrderedIndex(sort): ", index.Index) + g.P(helper.Indent(1), "for (auto&& item : ", indexContainerName, ") {") + g.P(helper.Indent(2), "std::sort(item.second.begin(), item.second.end(),") + g.P(helper.Indent(7), "[](const ", helper.ParseCppClassType(index.MD), "* a, const ", helper.ParseCppClassType(index.MD), "* b) {") + for i, field := range index.SortedColFields { + fieldName := "" + for i, leveledFd := range field.LeveledFDList { + accessOperator := "." + if i == 0 { + accessOperator = "->" + } + fieldName += accessOperator + helper.ParseIndexFieldName(leveledFd) + "()" + } + if i == len(index.SortedColFields)-1 { + g.P(helper.Indent(8), "return a", fieldName, " < b", fieldName, ";") + } else { + g.P(helper.Indent(8), "if (a", fieldName, " != b", fieldName, ") {") + g.P(helper.Indent(9), "return a", fieldName, " < b", fieldName, ";") + g.P(helper.Indent(8), "}") + } + } + g.P(helper.Indent(7), "});") + g.P(helper.Indent(1), "}") + } + } + } +} + +func genCppOrderedIndexFinders(g *protogen.GeneratedFile, descriptor *index.IndexDescriptor, messagerName string) { + for levelMessage := descriptor.LevelMessage; levelMessage != nil; levelMessage = levelMessage.NextLevel { + for _, index := range levelMessage.OrderedIndexes { + vectorType := "OrderedIndex_" + index.Name() + "Vector" + mapType := "OrderedIndex_" + index.Name() + "Map" + indexContainerName := "ordered_index_" + strcase.ToSnake(index.Name()) + "_map_" + + g.P("// OrderedIndex: ", index.Index) + g.P("const ", messagerName, "::", mapType, "& ", messagerName, "::Find", index.Name(), "() const { return ", indexContainerName, " ;}") + g.P() + + // single-column index + field := index.ColFields[0] // just take first field + keyType := helper.ParseOrderedMapKeyType(field.FD) + keyName := helper.ParseIndexFieldNameAsFuncParam(field.FD) + + g.P("const ", messagerName, "::", vectorType, "* ", messagerName, "::Find", index.Name(), "(", helper.ToConstRefType(keyType), " ", keyName, ") const {") + g.P(helper.Indent(1), "auto iter = ", indexContainerName, ".find(", keyName, ");") + g.P(helper.Indent(1), "if (iter == ", indexContainerName, ".end()) {") + g.P(helper.Indent(2), "return nullptr;") + g.P(helper.Indent(1), "}") + g.P(helper.Indent(1), "return &iter->second;") + g.P("}") + g.P() + + g.P("const ", helper.ParseCppClassType(index.MD), "* ", messagerName, "::FindFirst", index.Name(), "(", helper.ToConstRefType(keyType), " ", keyName, ") const {") + g.P(helper.Indent(1), "auto conf = Find", index.Name(), "(", keyName, ");") + g.P(helper.Indent(1), "if (conf == nullptr || conf->empty()) {") + g.P(helper.Indent(2), "return nullptr;") + g.P(helper.Indent(1), "}") + g.P(helper.Indent(1), "return conf->front();") + g.P("}") + g.P() + } + } +} diff --git a/cmd/protoc-gen-cpp-tableau-loader/shard.go b/cmd/protoc-gen-cpp-tableau-loader/shard.go index 3737e659..0d9121dd 100644 --- a/cmd/protoc-gen-cpp-tableau-loader/shard.go +++ b/cmd/protoc-gen-cpp-tableau-loader/shard.go @@ -99,7 +99,7 @@ func generateShardedHubCppFileContent(g *protogen.GeneratedFile, shardIndex int, for _, proto := range protofiles { for _, messager := range fileMessagers[proto] { g.P("template <>") - g.P("const std::shared_ptr<" + messager + "> Hub::Get<" + messager + ">() const {") + g.P("const std::shared_ptr<", messager, "> Hub::Get<", messager, ">() const {") g.P(helper.Indent(1), "return GetMessagerContainerWithProvider()->", strcase.ToSnake(messager), "_;") g.P("}") g.P() diff --git a/cmd/protoc-gen-go-tableau-loader/helper/helper.go b/cmd/protoc-gen-go-tableau-loader/helper/helper.go index a6c4cadc..5a2590d4 100644 --- a/cmd/protoc-gen-go-tableau-loader/helper/helper.go +++ b/cmd/protoc-gen-go-tableau-loader/helper/helper.go @@ -73,6 +73,61 @@ func ParseGoType(gen *protogen.Plugin, fd protoreflect.FieldDescriptor) any { } } +// ParseMapKeyType converts a FieldDescriptor to its map key type. +// fd must be an comparable type. +func ParseMapKeyType(fd protoreflect.FieldDescriptor) string { + switch fd.Kind() { + case protoreflect.BoolKind: + return "bool" + case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.EnumKind: + return "int32" + case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: + return "uint32" + case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: + return "int64" + case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: + return "uint64" + case protoreflect.FloatKind: + return "float" + case protoreflect.DoubleKind: + return "double" + case protoreflect.StringKind: + return "string" + default: + panic(fmt.Sprintf("unsupported kind: %d", fd.Kind())) + } +} + +// ParseOrderedMapKeyType converts a FieldDescriptor to its treemap key type. +// fd must be an ordered type, or a message which can be converted to an ordered type. +func ParseOrderedMapKeyType(fd protoreflect.FieldDescriptor) string { + switch fd.Kind() { + case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.EnumKind: + return "int32" + case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: + return "uint32" + case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: + return "int64" + case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: + return "uint64" + case protoreflect.FloatKind: + return "float" + case protoreflect.DoubleKind: + return "double" + case protoreflect.StringKind: + return "string" + case protoreflect.MessageKind: + switch fd.Message().FullName() { + case "google.protobuf.Timestamp", "google.protobuf.Duration": + return "int64" + default: + } + fallthrough + default: + panic(fmt.Sprintf("unsupported kind: %d", fd.Kind())) + } +} + func FindMessage(gen *protogen.Plugin, md protoreflect.MessageDescriptor) *protogen.Message { if file, ok := gen.FilesByPath[md.ParentFile().Path()]; ok { return FindMessageByDescriptor(file.Messages, md) @@ -191,7 +246,7 @@ func AddMapKey(gen *protogen.Plugin, fd protoreflect.FieldDescriptor, keys []Map } } } - keys = append(keys, MapKey{ParseGoType(gen, fd.MapKey()).(string), name}) + keys = append(keys, MapKey{ParseMapKeyType(fd.MapKey()), name}) return keys } diff --git a/cmd/protoc-gen-go-tableau-loader/index.go b/cmd/protoc-gen-go-tableau-loader/index.go index d0f735f0..869b4877 100644 --- a/cmd/protoc-gen-go-tableau-loader/index.go +++ b/cmd/protoc-gen-go-tableau-loader/index.go @@ -71,7 +71,7 @@ func genIndexLoader(gen *protogen.Plugin, g *protogen.GeneratedFile, descriptor if !levelMessage.NextLevel.NeedGen() { break } - g.P("for _, ", itemName, " := range "+parentDataName+".Get"+helper.ParseIndexFieldName(gen, levelMessage.FD)+"() {") + g.P("for _, ", itemName, " := range ", parentDataName, ".Get", helper.ParseIndexFieldName(gen, levelMessage.FD), "() {") parentDataName = itemName depth++ } @@ -95,7 +95,7 @@ func genOneIndexLoader(gen *protogen.Plugin, g *protogen.GeneratedFile, depth in for _, leveledFd := range field.LeveledFDList { fieldName += ".Get" + helper.ParseIndexFieldName(gen, leveledFd) + "()" } - g.P("for _, ", itemName, " := range "+parentDataName+fieldName+" {") + g.P("for _, ", itemName, " := range ", parentDataName, fieldName, " {") g.P("key := ", itemName) g.P("x.", indexContainerName, "[key] = append(x.", indexContainerName, "[key], ", parentDataName, ")") g.P("}") @@ -104,7 +104,7 @@ func genOneIndexLoader(gen *protogen.Plugin, g *protogen.GeneratedFile, depth in for _, leveledFd := range field.LeveledFDList { fieldName += ".Get" + helper.ParseIndexFieldName(gen, leveledFd) + "()" } - g.P("key := ", parentDataName+fieldName) + g.P("key := ", parentDataName, fieldName) g.P("x.", indexContainerName, "[key] = append(x.", indexContainerName, "[key], ", parentDataName, ")") } } else { @@ -166,7 +166,7 @@ func generateOneMulticolumnIndex(gen *protogen.Plugin, g *protogen.GeneratedFile for _, leveledFd := range field.LeveledFDList { fieldName += ".Get" + helper.ParseIndexFieldName(gen, leveledFd) + "()" } - g.P("for _, " + itemName + " := range " + parentDataName + fieldName + " {") + g.P("for _, ", itemName, " := range ", parentDataName, fieldName, " {") keys = append(keys, itemName) keys = generateOneMulticolumnIndex(gen, g, depth+1, index, parentDataName, messagerName, keys) g.P("}") @@ -191,7 +191,7 @@ func genIndexFinders(gen *protogen.Plugin, g *protogen.GeneratedFile, descriptor g.P("// Index: ", index.Index) g.P() - g.P("// Find", index.Name(), "Map returns the index(", index.Index, ") to value(", helper.FindMessageGoIdent(gen, index.MD), ") map.") + g.P("// Find", index.Name(), "Map finds 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) @@ -211,14 +211,14 @@ func genIndexFinders(gen *protogen.Plugin, g *protogen.GeneratedFile, descriptor keyName = "key" } - g.P("// Find", index.Name(), " returns a slice of all values of the given key.") + g.P("// Find", index.Name(), " finds 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("// FindFirst", index.Name(), " finds the first value of the given key,") + g.P("// or nil if no value found.") 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 {") diff --git a/cmd/protoc-gen-go-tableau-loader/messager.go b/cmd/protoc-gen-go-tableau-loader/messager.go index 137cc239..ab8f19a6 100644 --- a/cmd/protoc-gen-go-tableau-loader/messager.go +++ b/cmd/protoc-gen-go-tableau-loader/messager.go @@ -82,6 +82,9 @@ func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, message *protog if options.NeedGenIndex(message.Desc, options.LangGO) { genIndexTypeDef(gen, g, indexDescriptor, messagerName) } + if options.NeedGenOrderedIndex(message.Desc, options.LangGO) { + genOrderedIndexTypeDef(gen, g, indexDescriptor, messagerName) + } g.P("// ", messagerName, " is a wrapper around protobuf message: ", message.GoIdent, ".") g.P("//") @@ -89,7 +92,7 @@ func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, message *protog g.P("//") g.P("// 1. Easy use: simple yet powerful accessers.") g.P("// 2. Elegant API: concise and clean functions.") - g.P("// 3. Extensibility: Map, OrdererdMap, Index...") + g.P("// 3. Extensibility: Map, OrdererdMap, Index, OrderedIndex...") // messager definition g.P("type ", messagerName, " struct {") g.P("UnimplementedMessager") @@ -100,6 +103,9 @@ func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, message *protog if options.NeedGenIndex(message.Desc, options.LangGO) { genIndexField(g, indexDescriptor, messagerName) } + if options.NeedGenOrderedIndex(message.Desc, options.LangGO) { + genOrderedIndexField(g, indexDescriptor, messagerName) + } g.P("}") g.P() @@ -168,7 +174,7 @@ func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, message *protog g.P("}") g.P() - if options.NeedGenOrderedMap(message.Desc, options.LangGO) || options.NeedGenIndex(message.Desc, options.LangGO) { + if options.NeedGenOrderedMap(message.Desc, options.LangGO) || options.NeedGenIndex(message.Desc, options.LangGO) || options.NeedGenOrderedIndex(message.Desc, options.LangGO) { g.P("// processAfterLoad runs after this messager is loaded.") g.P("func (x *", messagerName, ") processAfterLoad() error {") if options.NeedGenOrderedMap(message.Desc, options.LangGO) { @@ -177,6 +183,9 @@ func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, message *protog if options.NeedGenIndex(message.Desc, options.LangGO) { genIndexLoader(gen, g, indexDescriptor, messagerName) } + if options.NeedGenOrderedIndex(message.Desc, options.LangGO) { + genOrderedIndexLoader(gen, g, indexDescriptor) + } g.P("return nil") g.P("}") g.P() @@ -190,12 +199,15 @@ func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, message *protog if options.NeedGenIndex(message.Desc, options.LangGO) { genIndexFinders(gen, g, indexDescriptor, messagerName) } + if options.NeedGenOrderedIndex(message.Desc, options.LangGO) { + genOrderedIndexFinders(gen, g, indexDescriptor, messagerName) + } } func genMapGetters(gen *protogen.Plugin, g *protogen.GeneratedFile, message *protogen.Message, depth int, keys []helper.MapKey, messagerName string) { for _, field := range message.Fields { fd := field.Desc - if field.Desc.IsMap() { + if fd.IsMap() { keys = helper.AddMapKey(gen, fd, keys) getter := fmt.Sprintf("Get%v", depth) g.P("// ", getter, " finds value in the ", depth, "-level map. It will return") diff --git a/cmd/protoc-gen-go-tableau-loader/ordered_index.go b/cmd/protoc-gen-go-tableau-loader/ordered_index.go new file mode 100644 index 00000000..bb947e49 --- /dev/null +++ b/cmd/protoc-gen-go-tableau-loader/ordered_index.go @@ -0,0 +1,186 @@ +package main + +import ( + "fmt" + + "github.com/iancoleman/strcase" + "github.com/tableauio/loader/cmd/protoc-gen-go-tableau-loader/helper" + "github.com/tableauio/loader/internal/index" + "google.golang.org/protobuf/compiler/protogen" +) + +func genOrderedIndexTypeDef(gen *protogen.Plugin, g *protogen.GeneratedFile, descriptor *index.IndexDescriptor, messagerName string) { + g.P("// OrderedIndex types.") + for levelMessage := descriptor.LevelMessage; levelMessage != nil; levelMessage = levelMessage.NextLevel { + for _, index := range levelMessage.OrderedIndexes { + // single-column index + field := index.ColFields[0] // just take first field + g.P("// OrderedIndex: ", index.Index) + mapType := fmt.Sprintf("%s_OrderedIndex_%sMap", messagerName, index.Name()) + keyType := helper.ParseOrderedMapKeyType(field.FD) + g.P("type ", mapType, " = ", treeMapPackage.Ident("TreeMap"), "[", keyType, ", []*", helper.FindMessageGoIdent(gen, index.MD), "]") + g.P() + } + } +} + +func genOrderedIndexField(g *protogen.GeneratedFile, descriptor *index.IndexDescriptor, messagerName string) { + for levelMessage := descriptor.LevelMessage; levelMessage != nil; levelMessage = levelMessage.NextLevel { + for _, index := range levelMessage.OrderedIndexes { + indexContainerName := "orderedIndex" + strcase.ToCamel(index.Name()) + "Map" + mapType := fmt.Sprintf("%s_OrderedIndex_%sMap", messagerName, index.Name()) + g.P(indexContainerName, " *", mapType) + } + } +} + +func genOrderedIndexLoader(gen *protogen.Plugin, g *protogen.GeneratedFile, descriptor *index.IndexDescriptor) { + g.P("// OrderedIndex init.") + for levelMessage := descriptor.LevelMessage; levelMessage != nil; levelMessage = levelMessage.NextLevel { + for _, index := range levelMessage.OrderedIndexes { + field := index.ColFields[0] // just take first field + indexContainerName := "orderedIndex" + strcase.ToCamel(index.Name()) + "Map" + keyType := helper.ParseOrderedMapKeyType(field.FD) + g.P("x.", indexContainerName, " = ", treeMapPackage.Ident("New"), "[", keyType, ", []*", helper.FindMessageGoIdent(gen, index.MD), "]()") + } + } + parentDataName := "x.data" + depth := 1 + for levelMessage := descriptor.LevelMessage; levelMessage != nil; levelMessage = levelMessage.NextLevel { + for _, index := range levelMessage.OrderedIndexes { + genOneOrderedIndexLoader(gen, g, depth, index, parentDataName) + } + itemName := fmt.Sprintf("item%d", depth) + if levelMessage.FD == nil { + break + } + if !levelMessage.NextLevel.NeedGen() { + break + } + g.P("for _, ", itemName, " := range ", parentDataName, ".Get", helper.ParseIndexFieldName(gen, levelMessage.FD), "() {") + parentDataName = itemName + depth++ + } + for i := depth - 1; i > 0; i-- { + g.P("}") + } + genOrderedIndexSorter(gen, g, descriptor) +} + +func genOneOrderedIndexLoader(gen *protogen.Plugin, g *protogen.GeneratedFile, depth int, index *index.LevelIndex, + parentDataName string) { + indexContainerName := "orderedIndex" + strcase.ToCamel(index.Name()) + "Map" + g.P("{") + g.P("// OrderedIndex: ", index.Index) + // single-column index + field := index.ColFields[0] // just take the first field + if field.FD.IsList() { + itemName := fmt.Sprintf("item%d", depth) + fieldName := "" + suffix := "" + for i, leveledFd := range field.LeveledFDList { + fieldName += ".Get" + helper.ParseIndexFieldName(gen, leveledFd) + "()" + if i == len(field.LeveledFDList)-1 && leveledFd.Message() != nil { + switch leveledFd.Message().FullName() { + case "google.protobuf.Timestamp", "google.protobuf.Duration": + suffix = ".GetSeconds()" + default: + } + } + } + g.P("for _, ", itemName, " := range ", parentDataName, fieldName, " {") + g.P("key := ", itemName, suffix) + g.P("value, _ := x.", indexContainerName, ".Get(key)") + g.P("x.", indexContainerName, ".Put(key, append(value, ", parentDataName, "))") + g.P("}") + } else { + fieldName := "" + suffix := "" + for i, leveledFd := range field.LeveledFDList { + fieldName += ".Get" + helper.ParseIndexFieldName(gen, leveledFd) + "()" + if i == len(field.LeveledFDList)-1 && leveledFd.Message() != nil { + switch leveledFd.Message().FullName() { + case "google.protobuf.Timestamp", "google.protobuf.Duration": + suffix = ".GetSeconds()" + default: + } + } + } + g.P("key := ", parentDataName, fieldName, suffix) + g.P("value, _ := x.", indexContainerName, ".Get(key)") + g.P("x.", indexContainerName, ".Put(key, append(value, ", parentDataName, "))") + } + + g.P("}") +} + +func genOrderedIndexSorter(gen *protogen.Plugin, g *protogen.GeneratedFile, descriptor *index.IndexDescriptor) { + for levelMessage := descriptor.LevelMessage; levelMessage != nil; levelMessage = levelMessage.NextLevel { + for _, index := range levelMessage.OrderedIndexes { + indexContainerName := "orderedIndex" + strcase.ToCamel(index.Name()) + "Map" + if len(index.SortedColFields) != 0 { + g.P("// OrderedIndex(sort): ", index.Index) + g.P("x.", indexContainerName, ".Range(func(key int64, item []*", helper.FindMessageGoIdent(gen, index.MD), ") bool {") + g.P(sortPackage.Ident("Slice"), "(item, func(i, j int) bool {") + for i, field := range index.SortedColFields { + fieldName := "" + for _, leveledFd := range field.LeveledFDList { + fieldName += ".Get" + helper.ParseIndexFieldName(gen, leveledFd) + "()" + } + if i == len(index.SortedColFields)-1 { + g.P("return item[i]", fieldName, " < item[j]", fieldName) + } else { + g.P("if item[i]", fieldName, " != item[j]", fieldName, " {") + g.P("return item[i]", fieldName, " < item[j]", fieldName) + g.P("}") + } + } + g.P("})") + g.P("return true") + g.P("})") + } + } + } +} + +func genOrderedIndexFinders(gen *protogen.Plugin, g *protogen.GeneratedFile, descriptor *index.IndexDescriptor, messagerName string) { + for levelMessage := descriptor.LevelMessage; levelMessage != nil; levelMessage = levelMessage.NextLevel { + for _, index := range levelMessage.OrderedIndexes { + mapType := fmt.Sprintf("%s_OrderedIndex_%sMap", messagerName, index.Name()) + indexContainerName := "orderedIndex" + strcase.ToCamel(index.Name()) + "Map" + + g.P("// OrderedIndex: ", index.Index) + g.P() + + g.P("// Find", index.Name(), "Map finds the ordered index (", index.Index, ") to value (", helper.FindMessageGoIdent(gen, index.MD), ") treemap.") + 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() + + // single-column index + field := index.ColFields[0] // just take first field + keyType := helper.ParseOrderedMapKeyType(field.FD) + keyName := helper.ParseIndexFieldNameAsFuncParam(gen, field.FD) + + g.P("// Find", index.Name(), " finds 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("val, _ := x.", indexContainerName, ".Get(", keyName, ")") + g.P("return val") + g.P("}") + g.P() + + g.P("// FindFirst", index.Name(), " finds the first value of the given key,") + g.P("// or nil if no value found.") + g.P("func (x *", messagerName, ") FindFirst", index.Name(), "(", keyName, " ", keyType, ") *", helper.FindMessageGoIdent(gen, index.MD), " {") + g.P("val := x.Find", index.Name(), "(", keyName, ")") + g.P("if len(val) > 0 {") + g.P("return val[0]") + g.P("}") + g.P("return nil") + g.P("}") + g.P() + } + } +} diff --git a/internal/index/descriptor.go b/internal/index/descriptor.go index 408013f5..44d1d81a 100644 --- a/internal/index/descriptor.go +++ b/internal/index/descriptor.go @@ -51,14 +51,14 @@ type LevelMessage struct { FD protoreflect.FieldDescriptor // Current level message's all index fields - Indexes []*LevelIndex + Indexes, OrderedIndexes []*LevelIndex } func (l *LevelMessage) NeedGen() bool { if l == nil { return false } - return len(l.Indexes) != 0 || l.NextLevel.NeedGen() + return len(l.Indexes) != 0 || len(l.OrderedIndexes) != 0 || l.NextLevel.NeedGen() } type LevelIndex struct { @@ -94,17 +94,25 @@ func parseLevelMessage(md protoreflect.MessageDescriptor) *LevelMessage { } // parseRecursively parses multi-column index related info. -func parseRecursively(index *Index, prefix string, md protoreflect.MessageDescriptor, levelMessage *LevelMessage) { +func parseRecursively(index *Index, prefix string, md protoreflect.MessageDescriptor, levelMessage *LevelMessage, ordered bool) { colFields := parseInSameLevel(index.Cols, prefix, md, nil) sortedColFields := parseInSameLevel(index.SortedCols, prefix, md, nil) if len(colFields) != 0 { // index belongs to current level - levelMessage.Indexes = append(levelMessage.Indexes, &LevelIndex{ + levelIndex := &LevelIndex{ Index: index, MD: md, ColFields: colFields, SortedColFields: sortedColFields, - }) + } + if ordered { + if len(colFields) == 1 { + // only support one column ordered index + levelMessage.OrderedIndexes = append(levelMessage.OrderedIndexes, levelIndex) + } + } else { + levelMessage.Indexes = append(levelMessage.Indexes, levelIndex) + } } else if levelMessage != nil && levelMessage.NextLevel != nil { // index invalid or belongs to deeper level fd := levelMessage.FD @@ -112,9 +120,9 @@ func parseRecursively(index *Index, prefix string, md protoreflect.MessageDescri fdOpts := proto.GetExtension(opts, tableaupb.E_Field).(*tableaupb.FieldOptions) fieldOptName := fdOpts.GetName() if fd.IsMap() { - parseRecursively(index, prefix+fieldOptName, fd.MapValue().Message(), levelMessage.NextLevel) + parseRecursively(index, prefix+fieldOptName, fd.MapValue().Message(), levelMessage.NextLevel, ordered) } else { - parseRecursively(index, prefix+fieldOptName, fd.Message(), levelMessage.NextLevel) + parseRecursively(index, prefix+fieldOptName, fd.Message(), levelMessage.NextLevel, ordered) } } } @@ -165,13 +173,19 @@ func ParseIndexDescriptor(md protoreflect.MessageDescriptor) *IndexDescriptor { descriptor := &IndexDescriptor{ LevelMessage: parseLevelMessage(md), } - indexes := ParseWSOptionIndex(md) + indexes, orderedIndexes := ParseWSOptionIndex(md) // parse indexes into level message for _, index := range indexes { if len(index.Cols) == 0 { continue } - parseRecursively(index, "", md, descriptor.LevelMessage) + parseRecursively(index, "", md, descriptor.LevelMessage, false) + } + for _, index := range orderedIndexes { + if len(index.Cols) == 0 { + continue + } + parseRecursively(index, "", md, descriptor.LevelMessage, true) } // check duplicate index name indexNameMap := map[string]*Index{} diff --git a/internal/index/index.go b/internal/index/index.go index 7917fba9..36354d25 100644 --- a/internal/index/index.go +++ b/internal/index/index.go @@ -76,10 +76,10 @@ func (index *Index) String() string { } // parse worksheet option index -func ParseWSOptionIndex(md protoreflect.MessageDescriptor) []*Index { +func ParseWSOptionIndex(md protoreflect.MessageDescriptor) ([]*Index, []*Index) { opts := md.Options().(*descriptorpb.MessageOptions) wsOpts := proto.GetExtension(opts, tableaupb.E_Worksheet).(*tableaupb.WorksheetOptions) - return parseIndexFrom(wsOpts.Index) + return parseIndexFrom(wsOpts.Index), parseIndexFrom(wsOpts.OrderedIndex) } func parseIndex(indexStr string) *Index { diff --git a/internal/options/options.go b/internal/options/options.go index 12e5735d..c56d5b12 100644 --- a/internal/options/options.go +++ b/internal/options/options.go @@ -12,8 +12,9 @@ import ( ) const ( - optionOrderedMap = "OrderedMap" - optionIndex = "Index" + optionOrderedMap = "OrderedMap" + optionIndex = "Index" + optionOrderedIndex = "OrderedIndex" ) type Language = string @@ -55,6 +56,22 @@ func NeedGenIndex(md protoreflect.MessageDescriptor, lang Language) bool { return true } +func NeedGenOrderedIndex(md protoreflect.MessageDescriptor, lang Language) bool { + opts := md.Options().(*descriptorpb.MessageOptions) + wsOpts := proto.GetExtension(opts, tableaupb.E_Worksheet).(*tableaupb.WorksheetOptions) + if len(wsOpts.GetOrderedIndex()) == 0 { + // No index. + return false + } + if languages, ok := wsOpts.GetLangOptions()[optionOrderedIndex]; ok { + if !slices.Contains(strings.Split(languages, " "), lang) { + // Do not generate index for curr language + return false + } + } + return true +} + func NeedGenFile(f *protogen.File) bool { if !f.Generate { return false diff --git a/test/cpp-tableau-loader/src/protoconf/item_conf.pc.cc b/test/cpp-tableau-loader/src/protoconf/item_conf.pc.cc index 140568e3..6406b148 100644 --- a/test/cpp-tableau-loader/src/protoconf/item_conf.pc.cc +++ b/test/cpp-tableau-loader/src/protoconf/item_conf.pc.cc @@ -136,10 +136,10 @@ const ItemConf::Index_ItemVector* ItemConf::FindItem(protoconf::FruitType type) const protoconf::ItemConf::Item* ItemConf::FindFirstItem(protoconf::FruitType type) const { auto conf = FindItem(type); - if (conf == nullptr || conf->size() == 0) { + if (conf == nullptr || conf->empty()) { return nullptr; } - return (*conf)[0]; + return conf->front(); } // Index: Param@ItemInfo @@ -155,10 +155,10 @@ const ItemConf::Index_ItemInfoVector* ItemConf::FindItemInfo(int32_t param) cons const protoconf::ItemConf::Item* ItemConf::FindFirstItemInfo(int32_t param) const { auto conf = FindItemInfo(param); - if (conf == nullptr || conf->size() == 0) { + if (conf == nullptr || conf->empty()) { return nullptr; } - return (*conf)[0]; + return conf->front(); } // Index: Default@ItemDefaultInfo @@ -174,10 +174,10 @@ const ItemConf::Index_ItemDefaultInfoVector* ItemConf::FindItemDefaultInfo(const const protoconf::ItemConf::Item* ItemConf::FindFirstItemDefaultInfo(const std::string& default_) const { auto conf = FindItemDefaultInfo(default_); - if (conf == nullptr || conf->size() == 0) { + if (conf == nullptr || conf->empty()) { return nullptr; } - return (*conf)[0]; + return conf->front(); } // Index: ExtType@ItemExtInfo @@ -193,10 +193,10 @@ const ItemConf::Index_ItemExtInfoVector* ItemConf::FindItemExtInfo(protoconf::Fr const protoconf::ItemConf::Item* ItemConf::FindFirstItemExtInfo(protoconf::FruitType ext_type) const { auto conf = FindItemExtInfo(ext_type); - if (conf == nullptr || conf->size() == 0) { + if (conf == nullptr || conf->empty()) { return nullptr; } - return (*conf)[0]; + return conf->front(); } // Index: (ID,Name)@AwardItem @@ -212,10 +212,10 @@ const ItemConf::Index_AwardItemVector* ItemConf::FindAwardItem(const Index_Award const protoconf::ItemConf::Item* ItemConf::FindFirstAwardItem(const Index_AwardItemKey& key) const { auto conf = FindAwardItem(key); - if (conf == nullptr || conf->size() == 0) { + if (conf == nullptr || conf->empty()) { return nullptr; } - return (*conf)[0]; + return conf->front(); } // Index: (ID,Type,Param,ExtType)@SpecialItem @@ -231,10 +231,10 @@ const ItemConf::Index_SpecialItemVector* ItemConf::FindSpecialItem(const Index_S const protoconf::ItemConf::Item* ItemConf::FindFirstSpecialItem(const Index_SpecialItemKey& key) const { auto conf = FindSpecialItem(key); - if (conf == nullptr || conf->size() == 0) { + if (conf == nullptr || conf->empty()) { return nullptr; } - return (*conf)[0]; + return conf->front(); } // Index: PathDir@ItemPathDir @@ -250,10 +250,10 @@ const ItemConf::Index_ItemPathDirVector* ItemConf::FindItemPathDir(const std::st const protoconf::ItemConf::Item* ItemConf::FindFirstItemPathDir(const std::string& dir) const { auto conf = FindItemPathDir(dir); - if (conf == nullptr || conf->size() == 0) { + if (conf == nullptr || conf->empty()) { return nullptr; } - return (*conf)[0]; + return conf->front(); } // Index: PathName@ItemPathName @@ -269,10 +269,10 @@ const ItemConf::Index_ItemPathNameVector* ItemConf::FindItemPathName(const std:: const protoconf::ItemConf::Item* ItemConf::FindFirstItemPathName(const std::string& name) const { auto conf = FindItemPathName(name); - if (conf == nullptr || conf->size() == 0) { + if (conf == nullptr || conf->empty()) { return nullptr; } - return (*conf)[0]; + return conf->front(); } // Index: PathFriendID@ItemPathFriendID @@ -288,10 +288,10 @@ const ItemConf::Index_ItemPathFriendIDVector* ItemConf::FindItemPathFriendID(uin const protoconf::ItemConf::Item* ItemConf::FindFirstItemPathFriendID(uint32_t id) const { auto conf = FindItemPathFriendID(id); - if (conf == nullptr || conf->size() == 0) { + if (conf == nullptr || conf->empty()) { return nullptr; } - return (*conf)[0]; + return conf->front(); } // Index: UseEffectType@UseEffectType @@ -307,10 +307,10 @@ const ItemConf::Index_UseEffectTypeVector* ItemConf::FindUseEffectType(protoconf const protoconf::ItemConf::Item* ItemConf::FindFirstUseEffectType(protoconf::UseEffect::Type type) const { auto conf = FindUseEffectType(type); - if (conf == nullptr || conf->size() == 0) { + if (conf == nullptr || conf->empty()) { return nullptr; } - return (*conf)[0]; + return conf->front(); } diff --git a/test/cpp-tableau-loader/src/protoconf/item_conf.pc.h b/test/cpp-tableau-loader/src/protoconf/item_conf.pc.h index 12a6ea69..3a9d38b2 100644 --- a/test/cpp-tableau-loader/src/protoconf/item_conf.pc.h +++ b/test/cpp-tableau-loader/src/protoconf/item_conf.pc.h @@ -43,8 +43,12 @@ class ItemConf : public Messager { public: using Index_ItemVector = std::vector; using Index_ItemMap = std::unordered_map; + // Finds the index (Type) to value (Index_ItemVector) hash map. + // One key may correspond to multiple values, which are contained by a vector. const Index_ItemMap& FindItem() const; + // Finds a vector of all values of the given key. const Index_ItemVector* FindItem(protoconf::FruitType type) const; + // Finds the first value of the given key. const protoconf::ItemConf::Item* FindFirstItem(protoconf::FruitType type) const; private: @@ -54,8 +58,12 @@ class ItemConf : public Messager { public: using Index_ItemInfoVector = std::vector; using Index_ItemInfoMap = std::unordered_map; + // Finds the index (Param@ItemInfo) to value (Index_ItemInfoVector) hash map. + // One key may correspond to multiple values, which are contained by a vector. const Index_ItemInfoMap& FindItemInfo() const; + // Finds a vector of all values of the given key. const Index_ItemInfoVector* FindItemInfo(int32_t param) const; + // Finds the first value of the given key. const protoconf::ItemConf::Item* FindFirstItemInfo(int32_t param) const; private: @@ -65,8 +73,12 @@ class ItemConf : public Messager { public: using Index_ItemDefaultInfoVector = std::vector; using Index_ItemDefaultInfoMap = std::unordered_map; + // Finds the index (Default@ItemDefaultInfo) to value (Index_ItemDefaultInfoVector) hash map. + // One key may correspond to multiple values, which are contained by a vector. const Index_ItemDefaultInfoMap& FindItemDefaultInfo() const; + // Finds a vector of all values of the given key. const Index_ItemDefaultInfoVector* FindItemDefaultInfo(const std::string& default_) const; + // Finds the first value of the given key. const protoconf::ItemConf::Item* FindFirstItemDefaultInfo(const std::string& default_) const; private: @@ -76,8 +88,12 @@ class ItemConf : public Messager { public: using Index_ItemExtInfoVector = std::vector; using Index_ItemExtInfoMap = std::unordered_map; + // Finds the index (ExtType@ItemExtInfo) to value (Index_ItemExtInfoVector) hash map. + // One key may correspond to multiple values, which are contained by a vector. const Index_ItemExtInfoMap& FindItemExtInfo() const; + // Finds a vector of all values of the given key. const Index_ItemExtInfoVector* FindItemExtInfo(protoconf::FruitType ext_type) const; + // Finds the first value of the given key. const protoconf::ItemConf::Item* FindFirstItemExtInfo(protoconf::FruitType ext_type) const; private: @@ -99,8 +115,12 @@ class ItemConf : public Messager { }; using Index_AwardItemVector = std::vector; using Index_AwardItemMap = std::unordered_map; + // Finds the index ((ID,Name)@AwardItem) to value (Index_AwardItemVector) hash map. + // One key may correspond to multiple values, which are contained by a vector. const Index_AwardItemMap& FindAwardItem() const; + // Finds a vector of all values of the given key. const Index_AwardItemVector* FindAwardItem(const Index_AwardItemKey& key) const; + // Finds the first value of the given key. const protoconf::ItemConf::Item* FindFirstAwardItem(const Index_AwardItemKey& key) const; private: @@ -124,8 +144,12 @@ class ItemConf : public Messager { }; using Index_SpecialItemVector = std::vector; using Index_SpecialItemMap = std::unordered_map; + // Finds the index ((ID,Type,Param,ExtType)@SpecialItem) to value (Index_SpecialItemVector) hash map. + // One key may correspond to multiple values, which are contained by a vector. const Index_SpecialItemMap& FindSpecialItem() const; + // Finds a vector of all values of the given key. const Index_SpecialItemVector* FindSpecialItem(const Index_SpecialItemKey& key) const; + // Finds the first value of the given key. const protoconf::ItemConf::Item* FindFirstSpecialItem(const Index_SpecialItemKey& key) const; private: @@ -135,8 +159,12 @@ class ItemConf : public Messager { public: using Index_ItemPathDirVector = std::vector; using Index_ItemPathDirMap = std::unordered_map; + // Finds the index (PathDir@ItemPathDir) to value (Index_ItemPathDirVector) hash map. + // One key may correspond to multiple values, which are contained by a vector. const Index_ItemPathDirMap& FindItemPathDir() const; + // Finds a vector of all values of the given key. const Index_ItemPathDirVector* FindItemPathDir(const std::string& dir) const; + // Finds the first value of the given key. const protoconf::ItemConf::Item* FindFirstItemPathDir(const std::string& dir) const; private: @@ -146,8 +174,12 @@ class ItemConf : public Messager { public: using Index_ItemPathNameVector = std::vector; using Index_ItemPathNameMap = std::unordered_map; + // Finds the index (PathName@ItemPathName) to value (Index_ItemPathNameVector) hash map. + // One key may correspond to multiple values, which are contained by a vector. const Index_ItemPathNameMap& FindItemPathName() const; + // Finds a vector of all values of the given key. const Index_ItemPathNameVector* FindItemPathName(const std::string& name) const; + // Finds the first value of the given key. const protoconf::ItemConf::Item* FindFirstItemPathName(const std::string& name) const; private: @@ -157,8 +189,12 @@ class ItemConf : public Messager { public: using Index_ItemPathFriendIDVector = std::vector; using Index_ItemPathFriendIDMap = std::unordered_map; + // Finds the index (PathFriendID@ItemPathFriendID) to value (Index_ItemPathFriendIDVector) hash map. + // One key may correspond to multiple values, which are contained by a vector. const Index_ItemPathFriendIDMap& FindItemPathFriendID() const; + // Finds a vector of all values of the given key. const Index_ItemPathFriendIDVector* FindItemPathFriendID(uint32_t id) const; + // Finds the first value of the given key. const protoconf::ItemConf::Item* FindFirstItemPathFriendID(uint32_t id) const; private: @@ -168,8 +204,12 @@ class ItemConf : public Messager { public: using Index_UseEffectTypeVector = std::vector; using Index_UseEffectTypeMap = std::unordered_map; + // Finds the index (UseEffectType@UseEffectType) to value (Index_UseEffectTypeVector) hash map. + // One key may correspond to multiple values, which are contained by a vector. const Index_UseEffectTypeMap& FindUseEffectType() const; + // Finds a vector of all values of the given key. const Index_UseEffectTypeVector* FindUseEffectType(protoconf::UseEffect::Type type) const; + // Finds the first value of the given key. const protoconf::ItemConf::Item* FindFirstUseEffectType(protoconf::UseEffect::Type type) const; private: diff --git a/test/cpp-tableau-loader/src/protoconf/test_conf.pc.cc b/test/cpp-tableau-loader/src/protoconf/test_conf.pc.cc index 59b3e691..f5a70ce9 100644 --- a/test/cpp-tableau-loader/src/protoconf/test_conf.pc.cc +++ b/test/cpp-tableau-loader/src/protoconf/test_conf.pc.cc @@ -174,10 +174,10 @@ const ActivityConf::Index_ActivityVector* ActivityConf::FindActivity(const std:: const protoconf::ActivityConf::Activity* ActivityConf::FindFirstActivity(const std::string& activity_name) const { auto conf = FindActivity(activity_name); - if (conf == nullptr || conf->size() == 0) { + if (conf == nullptr || conf->empty()) { return nullptr; } - return (*conf)[0]; + return conf->front(); } // Index: ChapterID @@ -193,10 +193,10 @@ const ActivityConf::Index_ChapterVector* ActivityConf::FindChapter(uint32_t chap const protoconf::ActivityConf::Activity::Chapter* ActivityConf::FindFirstChapter(uint32_t chapter_id) const { auto conf = FindChapter(chapter_id); - if (conf == nullptr || conf->size() == 0) { + if (conf == nullptr || conf->empty()) { return nullptr; } - return (*conf)[0]; + return conf->front(); } // Index: ChapterName@NamedChapter @@ -212,10 +212,10 @@ const ActivityConf::Index_NamedChapterVector* ActivityConf::FindNamedChapter(con const protoconf::ActivityConf::Activity::Chapter* ActivityConf::FindFirstNamedChapter(const std::string& chapter_name) const { auto conf = FindNamedChapter(chapter_name); - if (conf == nullptr || conf->size() == 0) { + if (conf == nullptr || conf->empty()) { return nullptr; } - return (*conf)[0]; + return conf->front(); } // Index: SectionItemID@Award @@ -231,10 +231,10 @@ const ActivityConf::Index_AwardVector* ActivityConf::FindAward(uint32_t id) cons const protoconf::Section::SectionItem* ActivityConf::FindFirstAward(uint32_t id) const { auto conf = FindAward(id); - if (conf == nullptr || conf->size() == 0) { + if (conf == nullptr || conf->empty()) { return nullptr; } - return (*conf)[0]; + return conf->front(); } @@ -315,6 +315,41 @@ bool TaskConf::ProcessAfterLoad() { return a->id() < b->id(); }); } + // OrderedIndex init. + ordered_index_ordered_task_map_.clear(); + ordered_index_task_expiry_map_.clear(); + ordered_index_sorted_task_expiry_map_.clear(); + for (auto&& item1 : data_.task_map()) { + { + // OrderedIndex: Goal@OrderedTask + ordered_index_ordered_task_map_[item1.second.goal()].push_back(&item1.second); + } + { + // OrderedIndex: Expiry@TaskExpiry + ordered_index_task_expiry_map_[item1.second.expiry().seconds()].push_back(&item1.second); + } + { + // OrderedIndex: Expiry@SortedTaskExpiry + ordered_index_sorted_task_expiry_map_[item1.second.expiry().seconds()].push_back(&item1.second); + } + } + // OrderedIndex(sort): Goal@OrderedTask + for (auto&& item : ordered_index_ordered_task_map_) { + std::sort(item.second.begin(), item.second.end(), + [](const protoconf::TaskConf::Task* a, const protoconf::TaskConf::Task* b) { + return a->id() < b->id(); + }); + } + // OrderedIndex(sort): Expiry@SortedTaskExpiry + for (auto&& item : ordered_index_sorted_task_expiry_map_) { + std::sort(item.second.begin(), item.second.end(), + [](const protoconf::TaskConf::Task* a, const protoconf::TaskConf::Task* b) { + if (a->goal() != b->goal()) { + return a->goal() < b->goal(); + } + return a->id() < b->id(); + }); + } return true; } @@ -339,10 +374,68 @@ const TaskConf::Index_TaskVector* TaskConf::FindTask(int64_t activity_id) const const protoconf::TaskConf::Task* TaskConf::FindFirstTask(int64_t activity_id) const { auto conf = FindTask(activity_id); - if (conf == nullptr || conf->size() == 0) { + if (conf == nullptr || conf->empty()) { + return nullptr; + } + return conf->front(); +} + + +// OrderedIndex: Goal@OrderedTask +const TaskConf::OrderedIndex_OrderedTaskMap& TaskConf::FindOrderedTask() const { return ordered_index_ordered_task_map_ ;} + +const TaskConf::OrderedIndex_OrderedTaskVector* TaskConf::FindOrderedTask(int64_t goal) const { + auto iter = ordered_index_ordered_task_map_.find(goal); + if (iter == ordered_index_ordered_task_map_.end()) { + return nullptr; + } + return &iter->second; +} + +const protoconf::TaskConf::Task* TaskConf::FindFirstOrderedTask(int64_t goal) const { + auto conf = FindOrderedTask(goal); + if (conf == nullptr || conf->empty()) { + return nullptr; + } + return conf->front(); +} + +// OrderedIndex: Expiry@TaskExpiry +const TaskConf::OrderedIndex_TaskExpiryMap& TaskConf::FindTaskExpiry() const { return ordered_index_task_expiry_map_ ;} + +const TaskConf::OrderedIndex_TaskExpiryVector* TaskConf::FindTaskExpiry(int64_t expiry) const { + auto iter = ordered_index_task_expiry_map_.find(expiry); + if (iter == ordered_index_task_expiry_map_.end()) { + return nullptr; + } + return &iter->second; +} + +const protoconf::TaskConf::Task* TaskConf::FindFirstTaskExpiry(int64_t expiry) const { + auto conf = FindTaskExpiry(expiry); + if (conf == nullptr || conf->empty()) { + return nullptr; + } + return conf->front(); +} + +// OrderedIndex: Expiry@SortedTaskExpiry +const TaskConf::OrderedIndex_SortedTaskExpiryMap& TaskConf::FindSortedTaskExpiry() const { return ordered_index_sorted_task_expiry_map_ ;} + +const TaskConf::OrderedIndex_SortedTaskExpiryVector* TaskConf::FindSortedTaskExpiry(int64_t expiry) const { + auto iter = ordered_index_sorted_task_expiry_map_.find(expiry); + if (iter == ordered_index_sorted_task_expiry_map_.end()) { + return nullptr; + } + return &iter->second; +} + +const protoconf::TaskConf::Task* TaskConf::FindFirstSortedTaskExpiry(int64_t expiry) const { + auto conf = FindSortedTaskExpiry(expiry); + if (conf == nullptr || conf->empty()) { return nullptr; } - return (*conf)[0]; + return conf->front(); } diff --git a/test/cpp-tableau-loader/src/protoconf/test_conf.pc.h b/test/cpp-tableau-loader/src/protoconf/test_conf.pc.h index 9036b8d5..44cbbc03 100644 --- a/test/cpp-tableau-loader/src/protoconf/test_conf.pc.h +++ b/test/cpp-tableau-loader/src/protoconf/test_conf.pc.h @@ -58,8 +58,12 @@ class ActivityConf : public Messager { public: using Index_ActivityVector = std::vector; using Index_ActivityMap = std::unordered_map; + // Finds the index (ActivityName) to value (Index_ActivityVector) hash map. + // One key may correspond to multiple values, which are contained by a vector. const Index_ActivityMap& FindActivity() const; + // Finds a vector of all values of the given key. const Index_ActivityVector* FindActivity(const std::string& activity_name) const; + // Finds the first value of the given key. const protoconf::ActivityConf::Activity* FindFirstActivity(const std::string& activity_name) const; private: @@ -69,8 +73,12 @@ class ActivityConf : public Messager { public: using Index_ChapterVector = std::vector; using Index_ChapterMap = std::unordered_map; + // Finds the index (ChapterID) to value (Index_ChapterVector) hash map. + // One key may correspond to multiple values, which are contained by a vector. const Index_ChapterMap& FindChapter() const; + // Finds a vector of all values of the given key. const Index_ChapterVector* FindChapter(uint32_t chapter_id) const; + // Finds the first value of the given key. const protoconf::ActivityConf::Activity::Chapter* FindFirstChapter(uint32_t chapter_id) const; private: @@ -80,8 +88,12 @@ class ActivityConf : public Messager { public: using Index_NamedChapterVector = std::vector; using Index_NamedChapterMap = std::unordered_map; + // Finds the index (ChapterName@NamedChapter) to value (Index_NamedChapterVector) hash map. + // One key may correspond to multiple values, which are contained by a vector. const Index_NamedChapterMap& FindNamedChapter() const; + // Finds a vector of all values of the given key. const Index_NamedChapterVector* FindNamedChapter(const std::string& chapter_name) const; + // Finds the first value of the given key. const protoconf::ActivityConf::Activity::Chapter* FindFirstNamedChapter(const std::string& chapter_name) const; private: @@ -91,8 +103,12 @@ class ActivityConf : public Messager { public: using Index_AwardVector = std::vector; using Index_AwardMap = std::unordered_map; + // Finds the index (SectionItemID@Award) to value (Index_AwardVector) hash map. + // One key may correspond to multiple values, which are contained by a vector. const Index_AwardMap& FindAward() const; + // Finds a vector of all values of the given key. const Index_AwardVector* FindAward(uint32_t id) const; + // Finds the first value of the given key. const protoconf::Section::SectionItem* FindFirstAward(uint32_t id) const; private: @@ -153,13 +169,63 @@ class TaskConf : public Messager { public: using Index_TaskVector = std::vector; using Index_TaskMap = std::unordered_map; + // Finds the index (ActivityID) to value (Index_TaskVector) hash map. + // One key may correspond to multiple values, which are contained by a vector. const Index_TaskMap& FindTask() const; + // Finds a vector of all values of the given key. const Index_TaskVector* FindTask(int64_t activity_id) const; + // Finds the first value of the given key. const protoconf::TaskConf::Task* FindFirstTask(int64_t activity_id) const; private: Index_TaskMap index_task_map_; + // OrderedIndex accessers. + // OrderedIndex: Goal@OrderedTask + public: + using OrderedIndex_OrderedTaskVector = std::vector; + using OrderedIndex_OrderedTaskMap = std::map; + // Finds the ordered index (Goal@OrderedTask) to value (OrderedIndex_OrderedTaskVector) hash map. + // One key may correspond to multiple values, which are contained by a vector. + const OrderedIndex_OrderedTaskMap& FindOrderedTask() const; + // Finds a vector of all values of the given key. + const OrderedIndex_OrderedTaskVector* FindOrderedTask(int64_t goal) const; + // Finds the first value of the given key. + const protoconf::TaskConf::Task* FindFirstOrderedTask(int64_t goal) const; + + private: + OrderedIndex_OrderedTaskMap ordered_index_ordered_task_map_; + + // OrderedIndex: Expiry@TaskExpiry + public: + using OrderedIndex_TaskExpiryVector = std::vector; + using OrderedIndex_TaskExpiryMap = std::map; + // Finds the ordered index (Expiry@TaskExpiry) to value (OrderedIndex_TaskExpiryVector) hash map. + // One key may correspond to multiple values, which are contained by a vector. + const OrderedIndex_TaskExpiryMap& FindTaskExpiry() const; + // Finds a vector of all values of the given key. + const OrderedIndex_TaskExpiryVector* FindTaskExpiry(int64_t expiry) const; + // Finds the first value of the given key. + const protoconf::TaskConf::Task* FindFirstTaskExpiry(int64_t expiry) const; + + private: + OrderedIndex_TaskExpiryMap ordered_index_task_expiry_map_; + + // OrderedIndex: Expiry@SortedTaskExpiry + public: + using OrderedIndex_SortedTaskExpiryVector = std::vector; + using OrderedIndex_SortedTaskExpiryMap = std::map; + // Finds the ordered index (Expiry@SortedTaskExpiry) to value (OrderedIndex_SortedTaskExpiryVector) hash map. + // One key may correspond to multiple values, which are contained by a vector. + const OrderedIndex_SortedTaskExpiryMap& FindSortedTaskExpiry() const; + // Finds a vector of all values of the given key. + const OrderedIndex_SortedTaskExpiryVector* FindSortedTaskExpiry(int64_t expiry) const; + // Finds the first value of the given key. + const protoconf::TaskConf::Task* FindFirstSortedTaskExpiry(int64_t expiry) const; + + private: + OrderedIndex_SortedTaskExpiryMap ordered_index_sorted_task_expiry_map_; + }; } // namespace tableau diff --git a/test/go-tableau-loader/protoconf/loader/hero_conf.pc.go b/test/go-tableau-loader/protoconf/loader/hero_conf.pc.go index 88e947d3..d9a172bd 100644 --- a/test/go-tableau-loader/protoconf/loader/hero_conf.pc.go +++ b/test/go-tableau-loader/protoconf/loader/hero_conf.pc.go @@ -29,7 +29,7 @@ type HeroConf_Index_AttrMap = map[string][]*protoconf.HeroConf_Hero_Attr // // 1. Easy use: simple yet powerful accessers. // 2. Elegant API: concise and clean functions. -// 3. Extensibility: Map, OrdererdMap, Index... +// 3. Extensibility: Map, OrdererdMap, Index, OrderedIndex... type HeroConf struct { UnimplementedMessager data, originalData *protoconf.HeroConf @@ -137,19 +137,19 @@ func (x *HeroConf) Get2(name string, title string) (*protoconf.HeroConf_Hero_Att // Index: Title -// FindAttrMap returns the index(Title) to value(protoconf.HeroConf_Hero_Attr) map. +// FindAttrMap finds the index (Title) to value (protoconf.HeroConf_Hero_Attr) map. // One key may correspond to multiple values, which are contained by a slice. func (x *HeroConf) FindAttrMap() HeroConf_Index_AttrMap { return x.indexAttrMap } -// FindAttr returns a slice of all values of the given key. +// FindAttr finds a slice of all values of the given key. func (x *HeroConf) FindAttr(title string) []*protoconf.HeroConf_Hero_Attr { return x.indexAttrMap[title] } -// FindFirstAttr returns the first value of the given key, -// or nil if the key correspond to no value. +// FindFirstAttr finds the first value of the given key, +// or nil if no value found. func (x *HeroConf) FindFirstAttr(title string) *protoconf.HeroConf_Hero_Attr { val := x.indexAttrMap[title] if len(val) > 0 { @@ -170,7 +170,7 @@ type ProtoconfHeroBaseConfHeroMap_OrderedMap = treemap.TreeMap[string, *Protocon // // 1. Easy use: simple yet powerful accessers. // 2. Elegant API: concise and clean functions. -// 3. Extensibility: Map, OrdererdMap, Index... +// 3. Extensibility: Map, OrdererdMap, Index, OrderedIndex... type HeroBaseConf struct { UnimplementedMessager data, originalData *protoconf.HeroBaseConf diff --git a/test/go-tableau-loader/protoconf/loader/item_conf.pc.go b/test/go-tableau-loader/protoconf/loader/item_conf.pc.go index f75edb40..8b27237a 100644 --- a/test/go-tableau-loader/protoconf/loader/item_conf.pc.go +++ b/test/go-tableau-loader/protoconf/loader/item_conf.pc.go @@ -68,7 +68,7 @@ type ItemConf_Index_UseEffectTypeMap = map[protoconf.UseEffect_Type][]*protoconf // // 1. Easy use: simple yet powerful accessers. // 2. Elegant API: concise and clean functions. -// 3. Extensibility: Map, OrdererdMap, Index... +// 3. Extensibility: Map, OrdererdMap, Index, OrderedIndex... type ItemConf struct { UnimplementedMessager data, originalData *protoconf.ItemConf @@ -259,19 +259,19 @@ func (x *ItemConf) GetOrderedMap() *ProtoconfItemConfItemMap_OrderedMap { // Index: Type -// FindItemMap returns the index(Type) to value(protoconf.ItemConf_Item) map. +// FindItemMap finds the index (Type) to value (protoconf.ItemConf_Item) map. // One key may correspond to multiple values, which are contained by a slice. func (x *ItemConf) FindItemMap() ItemConf_Index_ItemMap { return x.indexItemMap } -// FindItem returns a slice of all values of the given key. +// FindItem finds a slice of all values of the given key. func (x *ItemConf) FindItem(type_ protoconf.FruitType) []*protoconf.ItemConf_Item { return x.indexItemMap[type_] } -// FindFirstItem returns the first value of the given key, -// or nil if the key correspond to no value. +// FindFirstItem finds the first value of the given key, +// or nil if no value found. func (x *ItemConf) FindFirstItem(type_ protoconf.FruitType) *protoconf.ItemConf_Item { val := x.indexItemMap[type_] if len(val) > 0 { @@ -282,19 +282,19 @@ func (x *ItemConf) FindFirstItem(type_ protoconf.FruitType) *protoconf.ItemConf_ // Index: Param@ItemInfo -// FindItemInfoMap returns the index(Param@ItemInfo) to value(protoconf.ItemConf_Item) map. +// FindItemInfoMap finds the index (Param@ItemInfo) to value (protoconf.ItemConf_Item) map. // One key may correspond to multiple values, which are contained by a slice. func (x *ItemConf) FindItemInfoMap() ItemConf_Index_ItemInfoMap { return x.indexItemInfoMap } -// FindItemInfo returns a slice of all values of the given key. +// FindItemInfo finds a slice of all values of the given key. func (x *ItemConf) FindItemInfo(param int32) []*protoconf.ItemConf_Item { return x.indexItemInfoMap[param] } -// FindFirstItemInfo returns the first value of the given key, -// or nil if the key correspond to no value. +// FindFirstItemInfo finds the first value of the given key, +// or nil if no value found. func (x *ItemConf) FindFirstItemInfo(param int32) *protoconf.ItemConf_Item { val := x.indexItemInfoMap[param] if len(val) > 0 { @@ -305,19 +305,19 @@ func (x *ItemConf) FindFirstItemInfo(param int32) *protoconf.ItemConf_Item { // Index: Default@ItemDefaultInfo -// FindItemDefaultInfoMap returns the index(Default@ItemDefaultInfo) to value(protoconf.ItemConf_Item) map. +// FindItemDefaultInfoMap finds the index (Default@ItemDefaultInfo) to value (protoconf.ItemConf_Item) map. // One key may correspond to multiple values, which are contained by a slice. func (x *ItemConf) FindItemDefaultInfoMap() ItemConf_Index_ItemDefaultInfoMap { return x.indexItemDefaultInfoMap } -// FindItemDefaultInfo returns a slice of all values of the given key. +// FindItemDefaultInfo finds a slice of all values of the given key. func (x *ItemConf) FindItemDefaultInfo(default_ string) []*protoconf.ItemConf_Item { return x.indexItemDefaultInfoMap[default_] } -// FindFirstItemDefaultInfo returns the first value of the given key, -// or nil if the key correspond to no value. +// FindFirstItemDefaultInfo finds the first value of the given key, +// or nil if no value found. func (x *ItemConf) FindFirstItemDefaultInfo(default_ string) *protoconf.ItemConf_Item { val := x.indexItemDefaultInfoMap[default_] if len(val) > 0 { @@ -328,19 +328,19 @@ func (x *ItemConf) FindFirstItemDefaultInfo(default_ string) *protoconf.ItemConf // Index: ExtType@ItemExtInfo -// FindItemExtInfoMap returns the index(ExtType@ItemExtInfo) to value(protoconf.ItemConf_Item) map. +// FindItemExtInfoMap finds the index (ExtType@ItemExtInfo) to value (protoconf.ItemConf_Item) map. // One key may correspond to multiple values, which are contained by a slice. func (x *ItemConf) FindItemExtInfoMap() ItemConf_Index_ItemExtInfoMap { return x.indexItemExtInfoMap } -// FindItemExtInfo returns a slice of all values of the given key. +// FindItemExtInfo finds a slice of all values of the given key. func (x *ItemConf) FindItemExtInfo(extType protoconf.FruitType) []*protoconf.ItemConf_Item { return x.indexItemExtInfoMap[extType] } -// FindFirstItemExtInfo returns the first value of the given key, -// or nil if the key correspond to no value. +// FindFirstItemExtInfo finds the first value of the given key, +// or nil if no value found. func (x *ItemConf) FindFirstItemExtInfo(extType protoconf.FruitType) *protoconf.ItemConf_Item { val := x.indexItemExtInfoMap[extType] if len(val) > 0 { @@ -351,19 +351,19 @@ func (x *ItemConf) FindFirstItemExtInfo(extType protoconf.FruitType) *protoconf. // Index: (ID,Name)@AwardItem -// FindAwardItemMap returns the index((ID,Name)@AwardItem) to value(protoconf.ItemConf_Item) map. +// FindAwardItemMap finds the index ((ID,Name)@AwardItem) to value (protoconf.ItemConf_Item) map. // One key may correspond to multiple values, which are contained by a slice. func (x *ItemConf) FindAwardItemMap() ItemConf_Index_AwardItemMap { return x.indexAwardItemMap } -// FindAwardItem returns a slice of all values of the given key. +// FindAwardItem finds a slice of all values of the given key. func (x *ItemConf) FindAwardItem(key ItemConf_Index_AwardItemKey) []*protoconf.ItemConf_Item { return x.indexAwardItemMap[key] } -// FindFirstAwardItem returns the first value of the given key, -// or nil if the key correspond to no value. +// FindFirstAwardItem finds the first value of the given key, +// or nil if no value found. func (x *ItemConf) FindFirstAwardItem(key ItemConf_Index_AwardItemKey) *protoconf.ItemConf_Item { val := x.indexAwardItemMap[key] if len(val) > 0 { @@ -374,19 +374,19 @@ func (x *ItemConf) FindFirstAwardItem(key ItemConf_Index_AwardItemKey) *protocon // Index: (ID,Type,Param,ExtType)@SpecialItem -// FindSpecialItemMap returns the index((ID,Type,Param,ExtType)@SpecialItem) to value(protoconf.ItemConf_Item) map. +// FindSpecialItemMap finds the index ((ID,Type,Param,ExtType)@SpecialItem) to value (protoconf.ItemConf_Item) map. // One key may correspond to multiple values, which are contained by a slice. func (x *ItemConf) FindSpecialItemMap() ItemConf_Index_SpecialItemMap { return x.indexSpecialItemMap } -// FindSpecialItem returns a slice of all values of the given key. +// FindSpecialItem finds a slice of all values of the given key. func (x *ItemConf) FindSpecialItem(key ItemConf_Index_SpecialItemKey) []*protoconf.ItemConf_Item { return x.indexSpecialItemMap[key] } -// FindFirstSpecialItem returns the first value of the given key, -// or nil if the key correspond to no value. +// FindFirstSpecialItem finds the first value of the given key, +// or nil if no value found. func (x *ItemConf) FindFirstSpecialItem(key ItemConf_Index_SpecialItemKey) *protoconf.ItemConf_Item { val := x.indexSpecialItemMap[key] if len(val) > 0 { @@ -397,19 +397,19 @@ func (x *ItemConf) FindFirstSpecialItem(key ItemConf_Index_SpecialItemKey) *prot // Index: PathDir@ItemPathDir -// FindItemPathDirMap returns the index(PathDir@ItemPathDir) to value(protoconf.ItemConf_Item) map. +// FindItemPathDirMap finds the index (PathDir@ItemPathDir) to value (protoconf.ItemConf_Item) map. // One key may correspond to multiple values, which are contained by a slice. func (x *ItemConf) FindItemPathDirMap() ItemConf_Index_ItemPathDirMap { return x.indexItemPathDirMap } -// FindItemPathDir returns a slice of all values of the given key. +// FindItemPathDir finds a slice of all values of the given key. func (x *ItemConf) FindItemPathDir(dir string) []*protoconf.ItemConf_Item { return x.indexItemPathDirMap[dir] } -// FindFirstItemPathDir returns the first value of the given key, -// or nil if the key correspond to no value. +// FindFirstItemPathDir finds the first value of the given key, +// or nil if no value found. func (x *ItemConf) FindFirstItemPathDir(dir string) *protoconf.ItemConf_Item { val := x.indexItemPathDirMap[dir] if len(val) > 0 { @@ -420,19 +420,19 @@ func (x *ItemConf) FindFirstItemPathDir(dir string) *protoconf.ItemConf_Item { // Index: PathName@ItemPathName -// FindItemPathNameMap returns the index(PathName@ItemPathName) to value(protoconf.ItemConf_Item) map. +// FindItemPathNameMap finds the index (PathName@ItemPathName) to value (protoconf.ItemConf_Item) map. // One key may correspond to multiple values, which are contained by a slice. func (x *ItemConf) FindItemPathNameMap() ItemConf_Index_ItemPathNameMap { return x.indexItemPathNameMap } -// FindItemPathName returns a slice of all values of the given key. +// FindItemPathName finds a slice of all values of the given key. func (x *ItemConf) FindItemPathName(name string) []*protoconf.ItemConf_Item { return x.indexItemPathNameMap[name] } -// FindFirstItemPathName returns the first value of the given key, -// or nil if the key correspond to no value. +// FindFirstItemPathName finds the first value of the given key, +// or nil if no value found. func (x *ItemConf) FindFirstItemPathName(name string) *protoconf.ItemConf_Item { val := x.indexItemPathNameMap[name] if len(val) > 0 { @@ -443,19 +443,19 @@ func (x *ItemConf) FindFirstItemPathName(name string) *protoconf.ItemConf_Item { // Index: PathFriendID@ItemPathFriendID -// FindItemPathFriendIDMap returns the index(PathFriendID@ItemPathFriendID) to value(protoconf.ItemConf_Item) map. +// FindItemPathFriendIDMap finds the index (PathFriendID@ItemPathFriendID) to value (protoconf.ItemConf_Item) map. // One key may correspond to multiple values, which are contained by a slice. func (x *ItemConf) FindItemPathFriendIDMap() ItemConf_Index_ItemPathFriendIDMap { return x.indexItemPathFriendIdMap } -// FindItemPathFriendID returns a slice of all values of the given key. +// FindItemPathFriendID finds a slice of all values of the given key. func (x *ItemConf) FindItemPathFriendID(id uint32) []*protoconf.ItemConf_Item { return x.indexItemPathFriendIdMap[id] } -// FindFirstItemPathFriendID returns the first value of the given key, -// or nil if the key correspond to no value. +// FindFirstItemPathFriendID finds the first value of the given key, +// or nil if no value found. func (x *ItemConf) FindFirstItemPathFriendID(id uint32) *protoconf.ItemConf_Item { val := x.indexItemPathFriendIdMap[id] if len(val) > 0 { @@ -466,19 +466,19 @@ func (x *ItemConf) FindFirstItemPathFriendID(id uint32) *protoconf.ItemConf_Item // Index: UseEffectType@UseEffectType -// FindUseEffectTypeMap returns the index(UseEffectType@UseEffectType) to value(protoconf.ItemConf_Item) map. +// FindUseEffectTypeMap finds the index (UseEffectType@UseEffectType) to value (protoconf.ItemConf_Item) map. // One key may correspond to multiple values, which are contained by a slice. func (x *ItemConf) FindUseEffectTypeMap() ItemConf_Index_UseEffectTypeMap { return x.indexUseEffectTypeMap } -// FindUseEffectType returns a slice of all values of the given key. +// FindUseEffectType finds a slice of all values of the given key. func (x *ItemConf) FindUseEffectType(type_ protoconf.UseEffect_Type) []*protoconf.ItemConf_Item { return x.indexUseEffectTypeMap[type_] } -// FindFirstUseEffectType returns the first value of the given key, -// or nil if the key correspond to no value. +// FindFirstUseEffectType finds the first value of the given key, +// or nil if no value found. func (x *ItemConf) FindFirstUseEffectType(type_ protoconf.UseEffect_Type) *protoconf.ItemConf_Item { val := x.indexUseEffectTypeMap[type_] if len(val) > 0 { diff --git a/test/go-tableau-loader/protoconf/loader/patch_conf.pc.go b/test/go-tableau-loader/protoconf/loader/patch_conf.pc.go index 158a47b4..94d4b663 100644 --- a/test/go-tableau-loader/protoconf/loader/patch_conf.pc.go +++ b/test/go-tableau-loader/protoconf/loader/patch_conf.pc.go @@ -22,7 +22,7 @@ import ( // // 1. Easy use: simple yet powerful accessers. // 2. Elegant API: concise and clean functions. -// 3. Extensibility: Map, OrdererdMap, Index... +// 3. Extensibility: Map, OrdererdMap, Index, OrderedIndex... type PatchReplaceConf struct { UnimplementedMessager data, originalData *protoconf.PatchReplaceConf @@ -91,7 +91,7 @@ func (x *PatchReplaceConf) originalMessage() proto.Message { // // 1. Easy use: simple yet powerful accessers. // 2. Elegant API: concise and clean functions. -// 3. Extensibility: Map, OrdererdMap, Index... +// 3. Extensibility: Map, OrdererdMap, Index, OrderedIndex... type PatchMergeConf struct { UnimplementedMessager data, originalData *protoconf.PatchMergeConf @@ -171,7 +171,7 @@ func (x *PatchMergeConf) Get1(id uint32) (*protoconf.Item, error) { // // 1. Easy use: simple yet powerful accessers. // 2. Elegant API: concise and clean functions. -// 3. Extensibility: Map, OrdererdMap, Index... +// 3. Extensibility: Map, OrdererdMap, Index, OrderedIndex... type RecursivePatchConf struct { UnimplementedMessager data, originalData *protoconf.RecursivePatchConf diff --git a/test/go-tableau-loader/protoconf/loader/test_conf.pc.go b/test/go-tableau-loader/protoconf/loader/test_conf.pc.go index b67b0716..814499e0 100644 --- a/test/go-tableau-loader/protoconf/loader/test_conf.pc.go +++ b/test/go-tableau-loader/protoconf/loader/test_conf.pc.go @@ -50,7 +50,7 @@ type ActivityConf_Index_AwardMap = map[uint32][]*protoconf.Section_SectionItem // // 1. Easy use: simple yet powerful accessers. // 2. Elegant API: concise and clean functions. -// 3. Extensibility: Map, OrdererdMap, Index... +// 3. Extensibility: Map, OrdererdMap, Index, OrderedIndex... type ActivityConf struct { UnimplementedMessager data, originalData *protoconf.ActivityConf @@ -294,19 +294,19 @@ func (x *ActivityConf) GetOrderedMap3(activityId uint64, chapterId uint32, secti // Index: ActivityName -// FindActivityMap returns the index(ActivityName) to value(protoconf.ActivityConf_Activity) map. +// FindActivityMap finds the index (ActivityName) to value (protoconf.ActivityConf_Activity) map. // One key may correspond to multiple values, which are contained by a slice. func (x *ActivityConf) FindActivityMap() ActivityConf_Index_ActivityMap { return x.indexActivityMap } -// FindActivity returns a slice of all values of the given key. +// FindActivity finds a slice of all values of the given key. func (x *ActivityConf) FindActivity(activityName string) []*protoconf.ActivityConf_Activity { return x.indexActivityMap[activityName] } -// FindFirstActivity returns the first value of the given key, -// or nil if the key correspond to no value. +// FindFirstActivity finds the first value of the given key, +// or nil if no value found. func (x *ActivityConf) FindFirstActivity(activityName string) *protoconf.ActivityConf_Activity { val := x.indexActivityMap[activityName] if len(val) > 0 { @@ -317,19 +317,19 @@ func (x *ActivityConf) FindFirstActivity(activityName string) *protoconf.Activit // Index: ChapterID -// FindChapterMap returns the index(ChapterID) to value(protoconf.ActivityConf_Activity_Chapter) map. +// FindChapterMap finds the index (ChapterID) to value (protoconf.ActivityConf_Activity_Chapter) map. // One key may correspond to multiple values, which are contained by a slice. func (x *ActivityConf) FindChapterMap() ActivityConf_Index_ChapterMap { return x.indexChapterMap } -// FindChapter returns a slice of all values of the given key. +// FindChapter finds a slice of all values of the given key. func (x *ActivityConf) FindChapter(chapterId uint32) []*protoconf.ActivityConf_Activity_Chapter { return x.indexChapterMap[chapterId] } -// FindFirstChapter returns the first value of the given key, -// or nil if the key correspond to no value. +// FindFirstChapter finds the first value of the given key, +// or nil if no value found. func (x *ActivityConf) FindFirstChapter(chapterId uint32) *protoconf.ActivityConf_Activity_Chapter { val := x.indexChapterMap[chapterId] if len(val) > 0 { @@ -340,19 +340,19 @@ func (x *ActivityConf) FindFirstChapter(chapterId uint32) *protoconf.ActivityCon // Index: ChapterName@NamedChapter -// FindNamedChapterMap returns the index(ChapterName@NamedChapter) to value(protoconf.ActivityConf_Activity_Chapter) map. +// FindNamedChapterMap finds the index (ChapterName@NamedChapter) to value (protoconf.ActivityConf_Activity_Chapter) map. // One key may correspond to multiple values, which are contained by a slice. func (x *ActivityConf) FindNamedChapterMap() ActivityConf_Index_NamedChapterMap { return x.indexNamedChapterMap } -// FindNamedChapter returns a slice of all values of the given key. +// FindNamedChapter finds a slice of all values of the given key. func (x *ActivityConf) FindNamedChapter(chapterName string) []*protoconf.ActivityConf_Activity_Chapter { return x.indexNamedChapterMap[chapterName] } -// FindFirstNamedChapter returns the first value of the given key, -// or nil if the key correspond to no value. +// FindFirstNamedChapter finds the first value of the given key, +// or nil if no value found. func (x *ActivityConf) FindFirstNamedChapter(chapterName string) *protoconf.ActivityConf_Activity_Chapter { val := x.indexNamedChapterMap[chapterName] if len(val) > 0 { @@ -363,19 +363,19 @@ func (x *ActivityConf) FindFirstNamedChapter(chapterName string) *protoconf.Acti // Index: SectionItemID@Award -// FindAwardMap returns the index(SectionItemID@Award) to value(protoconf.Section_SectionItem) map. +// FindAwardMap finds the index (SectionItemID@Award) to value (protoconf.Section_SectionItem) map. // One key may correspond to multiple values, which are contained by a slice. func (x *ActivityConf) FindAwardMap() ActivityConf_Index_AwardMap { return x.indexAwardMap } -// FindAward returns a slice of all values of the given key. +// FindAward finds a slice of all values of the given key. func (x *ActivityConf) FindAward(id uint32) []*protoconf.Section_SectionItem { return x.indexAwardMap[id] } -// FindFirstAward returns the first value of the given key, -// or nil if the key correspond to no value. +// FindFirstAward finds the first value of the given key, +// or nil if no value found. func (x *ActivityConf) FindFirstAward(id uint32) *protoconf.Section_SectionItem { val := x.indexAwardMap[id] if len(val) > 0 { @@ -390,7 +390,7 @@ func (x *ActivityConf) FindFirstAward(id uint32) *protoconf.Section_SectionItem // // 1. Easy use: simple yet powerful accessers. // 2. Elegant API: concise and clean functions. -// 3. Extensibility: Map, OrdererdMap, Index... +// 3. Extensibility: Map, OrdererdMap, Index, OrderedIndex... type ChapterConf struct { UnimplementedMessager data, originalData *protoconf.ChapterConf @@ -470,7 +470,7 @@ func (x *ChapterConf) Get1(id uint64) (*protoconf.ChapterConf_Chapter, error) { // // 1. Easy use: simple yet powerful accessers. // 2. Elegant API: concise and clean functions. -// 3. Extensibility: Map, OrdererdMap, Index... +// 3. Extensibility: Map, OrdererdMap, Index, OrderedIndex... type ThemeConf struct { UnimplementedMessager data, originalData *protoconf.ThemeConf @@ -563,17 +563,30 @@ func (x *ThemeConf) Get2(name string, param string) (string, error) { // Index: ActivityID type TaskConf_Index_TaskMap = map[int64][]*protoconf.TaskConf_Task +// OrderedIndex types. +// OrderedIndex: Goal@OrderedTask +type TaskConf_OrderedIndex_OrderedTaskMap = treemap.TreeMap[int64, []*protoconf.TaskConf_Task] + +// OrderedIndex: Expiry@TaskExpiry +type TaskConf_OrderedIndex_TaskExpiryMap = treemap.TreeMap[int64, []*protoconf.TaskConf_Task] + +// OrderedIndex: Expiry@SortedTaskExpiry +type TaskConf_OrderedIndex_SortedTaskExpiryMap = treemap.TreeMap[int64, []*protoconf.TaskConf_Task] + // TaskConf is a wrapper around protobuf message: protoconf.TaskConf. // // It is designed for three goals: // // 1. Easy use: simple yet powerful accessers. // 2. Elegant API: concise and clean functions. -// 3. Extensibility: Map, OrdererdMap, Index... +// 3. Extensibility: Map, OrdererdMap, Index, OrderedIndex... type TaskConf struct { UnimplementedMessager - data, originalData *protoconf.TaskConf - indexTaskMap TaskConf_Index_TaskMap + data, originalData *protoconf.TaskConf + indexTaskMap TaskConf_Index_TaskMap + orderedIndexOrderedTaskMap *TaskConf_OrderedIndex_OrderedTaskMap + orderedIndexTaskExpiryMap *TaskConf_OrderedIndex_TaskExpiryMap + orderedIndexSortedTaskExpiryMap *TaskConf_OrderedIndex_SortedTaskExpiryMap } // Name returns the TaskConf's message name. @@ -653,6 +666,47 @@ func (x *TaskConf) processAfterLoad() error { return item[i].GetId() < item[j].GetId() }) } + // OrderedIndex init. + x.orderedIndexOrderedTaskMap = treemap.New[int64, []*protoconf.TaskConf_Task]() + x.orderedIndexTaskExpiryMap = treemap.New[int64, []*protoconf.TaskConf_Task]() + x.orderedIndexSortedTaskExpiryMap = treemap.New[int64, []*protoconf.TaskConf_Task]() + for _, item1 := range x.data.GetTaskMap() { + { + // OrderedIndex: Goal@OrderedTask + key := item1.GetGoal() + value, _ := x.orderedIndexOrderedTaskMap.Get(key) + x.orderedIndexOrderedTaskMap.Put(key, append(value, item1)) + } + { + // OrderedIndex: Expiry@TaskExpiry + key := item1.GetExpiry().GetSeconds() + value, _ := x.orderedIndexTaskExpiryMap.Get(key) + x.orderedIndexTaskExpiryMap.Put(key, append(value, item1)) + } + { + // OrderedIndex: Expiry@SortedTaskExpiry + key := item1.GetExpiry().GetSeconds() + value, _ := x.orderedIndexSortedTaskExpiryMap.Get(key) + x.orderedIndexSortedTaskExpiryMap.Put(key, append(value, item1)) + } + } + // OrderedIndex(sort): Goal@OrderedTask + x.orderedIndexOrderedTaskMap.Range(func(key int64, item []*protoconf.TaskConf_Task) bool { + sort.Slice(item, func(i, j int) bool { + return item[i].GetId() < item[j].GetId() + }) + return true + }) + // OrderedIndex(sort): Expiry@SortedTaskExpiry + x.orderedIndexSortedTaskExpiryMap.Range(func(key int64, item []*protoconf.TaskConf_Task) bool { + sort.Slice(item, func(i, j int) bool { + if item[i].GetGoal() != item[j].GetGoal() { + return item[i].GetGoal() < item[j].GetGoal() + } + return item[i].GetId() < item[j].GetId() + }) + return true + }) return nil } @@ -669,19 +723,19 @@ func (x *TaskConf) Get1(id int64) (*protoconf.TaskConf_Task, error) { // Index: ActivityID -// FindTaskMap returns the index(ActivityID) to value(protoconf.TaskConf_Task) map. +// FindTaskMap finds the index (ActivityID) to value (protoconf.TaskConf_Task) map. // One key may correspond to multiple values, which are contained by a slice. func (x *TaskConf) FindTaskMap() TaskConf_Index_TaskMap { return x.indexTaskMap } -// FindTask returns a slice of all values of the given key. +// FindTask finds a slice of all values of the given key. func (x *TaskConf) FindTask(activityId int64) []*protoconf.TaskConf_Task { return x.indexTaskMap[activityId] } -// FindFirstTask returns the first value of the given key, -// or nil if the key correspond to no value. +// FindFirstTask finds the first value of the given key, +// or nil if no value found. func (x *TaskConf) FindFirstTask(activityId int64) *protoconf.TaskConf_Task { val := x.indexTaskMap[activityId] if len(val) > 0 { @@ -690,6 +744,78 @@ func (x *TaskConf) FindFirstTask(activityId int64) *protoconf.TaskConf_Task { return nil } +// OrderedIndex: Goal@OrderedTask + +// FindOrderedTaskMap finds the ordered index (Goal@OrderedTask) to value (protoconf.TaskConf_Task) treemap. +// One key may correspond to multiple values, which are contained by a slice. +func (x *TaskConf) FindOrderedTaskMap() *TaskConf_OrderedIndex_OrderedTaskMap { + return x.orderedIndexOrderedTaskMap +} + +// FindOrderedTask finds a slice of all values of the given key. +func (x *TaskConf) FindOrderedTask(goal int64) []*protoconf.TaskConf_Task { + val, _ := x.orderedIndexOrderedTaskMap.Get(goal) + return val +} + +// FindFirstOrderedTask finds the first value of the given key, +// or nil if no value found. +func (x *TaskConf) FindFirstOrderedTask(goal int64) *protoconf.TaskConf_Task { + val := x.FindOrderedTask(goal) + if len(val) > 0 { + return val[0] + } + return nil +} + +// OrderedIndex: Expiry@TaskExpiry + +// FindTaskExpiryMap finds the ordered index (Expiry@TaskExpiry) to value (protoconf.TaskConf_Task) treemap. +// One key may correspond to multiple values, which are contained by a slice. +func (x *TaskConf) FindTaskExpiryMap() *TaskConf_OrderedIndex_TaskExpiryMap { + return x.orderedIndexTaskExpiryMap +} + +// FindTaskExpiry finds a slice of all values of the given key. +func (x *TaskConf) FindTaskExpiry(expiry int64) []*protoconf.TaskConf_Task { + val, _ := x.orderedIndexTaskExpiryMap.Get(expiry) + return val +} + +// FindFirstTaskExpiry finds the first value of the given key, +// or nil if no value found. +func (x *TaskConf) FindFirstTaskExpiry(expiry int64) *protoconf.TaskConf_Task { + val := x.FindTaskExpiry(expiry) + if len(val) > 0 { + return val[0] + } + return nil +} + +// OrderedIndex: Expiry@SortedTaskExpiry + +// FindSortedTaskExpiryMap finds the ordered index (Expiry@SortedTaskExpiry) to value (protoconf.TaskConf_Task) treemap. +// One key may correspond to multiple values, which are contained by a slice. +func (x *TaskConf) FindSortedTaskExpiryMap() *TaskConf_OrderedIndex_SortedTaskExpiryMap { + return x.orderedIndexSortedTaskExpiryMap +} + +// FindSortedTaskExpiry finds a slice of all values of the given key. +func (x *TaskConf) FindSortedTaskExpiry(expiry int64) []*protoconf.TaskConf_Task { + val, _ := x.orderedIndexSortedTaskExpiryMap.Get(expiry) + return val +} + +// FindFirstSortedTaskExpiry finds the first value of the given key, +// or nil if no value found. +func (x *TaskConf) FindFirstSortedTaskExpiry(expiry int64) *protoconf.TaskConf_Task { + val := x.FindSortedTaskExpiry(expiry) + if len(val) > 0 { + return val[0] + } + return nil +} + func init() { Register(func() Messager { return new(ActivityConf) diff --git a/test/proto/test_conf.proto b/test/proto/test_conf.proto index 181bd32d..2f86aa4c 100644 --- a/test/proto/test_conf.proto +++ b/test/proto/test_conf.proto @@ -3,6 +3,7 @@ syntax = "proto3"; package protoconf; import "tableau/protobuf/tableau.proto"; +import "google/protobuf/timestamp.proto"; import "common_conf.proto"; option go_package = "github.com/tableauio/loader/test/go-tableau-loader/protoconf"; @@ -99,6 +100,9 @@ message TaskConf { option (tableau.worksheet) = { name: "TaskConf" index: "ActivityID" + ordered_index: "Goal@OrderedTask" + ordered_index: "Expiry@TaskExpiry" + ordered_index: "Expiry@SortedTaskExpiry" }; map task_map = 1 [(tableau.field) = { key: "ID" layout: LAYOUT_VERTICAL }]; @@ -107,5 +111,6 @@ message TaskConf { int64 activity_id = 2 [(tableau.field) = { name: "ActivityID" }]; int64 goal = 3 [(tableau.field) = { name: "Goal" }]; protoconf.Item reward = 4 [(tableau.field) = { name: "Reward" }]; + google.protobuf.Timestamp expiry = 5 [(tableau.field) = { name: "Expiry" }]; } } \ No newline at end of file diff --git a/third_party/_submodules/tableau b/third_party/_submodules/tableau index a00850ec..883e58f9 160000 --- a/third_party/_submodules/tableau +++ b/third_party/_submodules/tableau @@ -1 +1 @@ -Subproject commit a00850ecc9b066a9691353ed7fe23d01f67be75e +Subproject commit 883e58f977e80cd3992e621cd996a84ee73454ea