diff --git a/Source/buildbindingccpp.go b/Source/buildbindingccpp.go index c54855f8..9621a077 100644 --- a/Source/buildbindingccpp.go +++ b/Source/buildbindingccpp.go @@ -591,7 +591,7 @@ func writeDynamicCPPMethodDeclaration(method ComponentDefinitionMethod, w Langua } func writeDynamicCPPMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace string, ClassIdentifier string, ClassName string, - implementationLines []string, isGlobal bool, includeComments bool, doNotThrow bool, useCPPTypes bool, ExplicitLinking bool, forWASM bool) error { + implementationLines []string, isGlobal bool, includeComments bool, doNotThrow bool, useCPPTypes bool, ExplicitLinking bool, forWASM bool, threadSafeArrayReturn bool) error { WASMPrefix := "" WASMCast := "" @@ -875,6 +875,12 @@ func writeDynamicCPPMethod(method ComponentDefinitionMethod, w LanguageWriter, N } w.Writeln(" {") + + threadSafeArrayReturnRequired := threadSafeArrayReturn && requiresInitCall + if threadSafeArrayReturnRequired { + w.Writeln(" std::lock_guard lock(%s);", getThreadSafeArrayReturnMutexName()) + } + w.Writelns(" ", definitionCodeLines) if requiresInitCall { w.Writeln(" %s%s(%s)%s;", checkErrorCodeBegin, CMethodName, initCallParameters, checkErrorCodeEnd) @@ -1185,6 +1191,14 @@ func getBindingCppVariableName(param ComponentDefinitionParam) string { return "" } +func getThreadSafeArrayReturnMutexName() string { + return "ArrayReturnMutex" +} + +func isThreadSafeArrayReturn(param ComponentDefinitionClass) bool { + return param.ArrayReturnOption == "ThreadSafe" +} + func getCPPInheritanceSpecifier(component ComponentDefinition, class ComponentDefinitionClass, cppClassPrefix string, ClassIdentifier string) (string, string) { cppParentClassName := "" inheritanceSpecifier := "" @@ -1377,6 +1391,10 @@ func writeClassDeclarations(w LanguageWriter, component ComponentDefinition, cpp w.Writeln(" Class %s ", cppClassName) w.Writeln("**************************************************************************************************************************/") w.Writeln("class %s %s{", cppClassName, inheritanceSpecifier) + if isThreadSafeArrayReturn(class) { + w.Writeln("private:") + w.Writeln(" std::mutex %s;", getThreadSafeArrayReturnMutexName()) + } w.Writeln("public:") w.Writeln(" ") if !component.isBaseClass(class) { @@ -1510,6 +1528,7 @@ func buildCppHeader(component ComponentDefinition, w LanguageWriter, NameSpace s w.Writeln("#include ") w.Writeln("#include ") w.Writeln("#include ") + w.Writeln("#include ") w.Writeln("#include ") w.Writeln("#include ") w.Writeln("") @@ -1622,7 +1641,7 @@ func buildCppHeader(component ComponentDefinition, w LanguageWriter, NameSpace s implementationLines = append(implementationLines, fmt.Sprintf(" throw E%sException(%s_ERROR_COULDNOTLOADLIBRARY, \"Unknown namespace \" + %s);", NameSpace, strings.ToUpper(NameSpace), sParamName)) } - err = writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, "Wrapper", implementationLines, true, true, false, useCPPTypes, ExplicitLinking, false) + err = writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, "Wrapper", implementationLines, true, true, false, useCPPTypes, ExplicitLinking, false, false) if err != nil { return err } @@ -1648,7 +1667,7 @@ func buildCppHeader(component ComponentDefinition, w LanguageWriter, NameSpace s w.Writeln(" */") for j := 0; j < len(class.Methods); j++ { method := class.Methods[j] - err := writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, class.ClassName, make([]string, 0), false, true, false, useCPPTypes, ExplicitLinking, false) + err := writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, class.ClassName, make([]string, 0), false, true, false, useCPPTypes, ExplicitLinking, false, isThreadSafeArrayReturn(class)) if err != nil { return err } @@ -2217,7 +2236,7 @@ func buildCppwasmGuestHeader(component ComponentDefinition, w LanguageWriter, Na implementationLines = append(implementationLines, fmt.Sprintf(" throw E%sException(%s_ERROR_COULDNOTLOADLIBRARY, \"Unknown namespace \" + %s);", NameSpace, strings.ToUpper(NameSpace), sParamName)) } - err = writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, "Wrapper", implementationLines, true, true, false, useCPPTypes, ExplicitLinking, true) + err = writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, "Wrapper", implementationLines, true, true, false, useCPPTypes, ExplicitLinking, true, false) if err != nil { return err } @@ -2236,7 +2255,7 @@ func buildCppwasmGuestHeader(component ComponentDefinition, w LanguageWriter, Na w.Writeln(" */") for j := 0; j < len(class.Methods); j++ { method := class.Methods[j] - err := writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, class.ClassName, make([]string, 0), false, true, false, useCPPTypes, ExplicitLinking, true) + err := writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, class.ClassName, make([]string, 0), false, true, false, useCPPTypes, ExplicitLinking, true, isThreadSafeArrayReturn(class)) if err != nil { return err } diff --git a/Source/componentdefinition.go b/Source/componentdefinition.go index 24be9903..7d948539 100644 --- a/Source/componentdefinition.go +++ b/Source/componentdefinition.go @@ -90,6 +90,7 @@ type ComponentDefinitionClass struct { ClassName string `xml:"name,attr"` ClassDescription string `xml:"description,attr"` ParentClass string `xml:"parent,attr"` + ArrayReturnOption string `xml:"arrayReturnOption,attr"` Methods []ComponentDefinitionMethod `xml:"method"` } @@ -531,6 +532,9 @@ func (component *ComponentDefinition) checkClasses() (error) { if len(class.ClassDescription) > 0 && !descriptionIsValid(class.ClassDescription) { return fmt.Errorf ("invalid class description \"%s\" in class \"%s\"", class.ClassDescription, class.ClassName); } + if len(class.ArrayReturnOption) > 0 && !arrayReturnOptionIsValid(class.ArrayReturnOption) { + return fmt.Errorf("invalid class array return option \"%s\" in class \"%s\"", class.ArrayReturnOption, class.ClassName) + } collision, hashExists := classTypeIdIndex[classTypeHash] if hashExists { return fmt.Errorf ("Classes \"%s\" and \"%s\" have a collision in their Class Type Id. Change class name.", classes[collision].ClassName, class.ClassName); @@ -796,6 +800,15 @@ func descriptionIsValid(description string) bool { return false; } +func arrayReturnOptionIsValid(arrayReturnOption string) bool { + switch arrayReturnOption { + case "ThreadSafe": + return true + } + + return false +} + func isScalarType(typeStr string) bool { switch (typeStr) { case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "bool", "single", "double", "pointer":