Skip to content

Commit 2b2f01f

Browse files
committed
Merge branch '7-c-add-options-to-treat-empty-string-and-nan-as-null' into 'dev'
Resolve "C++: add options to treat empty string and NaN as null" See merge request objectbox/objectbox-generator!5
2 parents 46a39b7 + 73972db commit 2b2f01f

6 files changed

Lines changed: 289 additions & 33 deletions

File tree

cmd/objectbox-generator/objectbox-generator.go

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,10 @@ func main() {
4646

4747
// implements generatorcmd.generatorCommand
4848
type command struct {
49-
langs map[string]*bool
50-
optional *string
49+
langs map[string]*bool
50+
optional *string
51+
empty_string_as_null *bool // pointers due to flag API (https://pkg.go.dev/flag#Bool)
52+
nan_as_null *bool
5153
}
5254

5355
func (cmd command) ShowUsage() {
@@ -92,6 +94,8 @@ func (cmd *command) ConfigureFlags() {
9294

9395
// for c++ generator
9496
cmd.optional = flag.String("optional", "", "C++ wrapper type to use for fields annotated \"optional\"; one of: std::optional, std::unique_ptr, std::shared_ptr")
97+
cmd.empty_string_as_null = flag.Bool("empty-string-as-null", false, "C++: empty strings are treated as 0 (null)")
98+
cmd.nan_as_null = flag.Bool("nan-as-null", false, "C++: NaNs are treated as 0 (null)")
9599
}
96100

97101
func (cmd *command) ParseFlags(remainingPosArgs *[]string, options *generator.Options) error {
@@ -120,15 +124,19 @@ func (cmd *command) ParseFlags(remainingPosArgs *[]string, options *generator.Op
120124
}
121125
case "cpp":
122126
options.CodeGenerator = &cgenerator.CGenerator{
123-
PlainC: false,
124-
LangVersion: 14,
125-
Optional: *cmd.optional,
127+
PlainC: false,
128+
LangVersion: 14,
129+
Optional: *cmd.optional,
130+
EmptyStringAsNull: *cmd.empty_string_as_null,
131+
NaNAsNull: *cmd.nan_as_null,
126132
}
127133
case "cpp11":
128134
options.CodeGenerator = &cgenerator.CGenerator{
129-
PlainC: false,
130-
LangVersion: 11,
131-
Optional: *cmd.optional,
135+
PlainC: false,
136+
LangVersion: 11,
137+
Optional: *cmd.optional,
138+
EmptyStringAsNull: *cmd.empty_string_as_null,
139+
NaNAsNull: *cmd.nan_as_null,
132140
}
133141
default:
134142
return errors.New("you must specify an output language")

internal/generator/c/cgenerator.go

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,11 @@ import (
3434
)
3535

3636
type CGenerator struct {
37-
PlainC bool
38-
LangVersion int // -1: unset, cpp: 11, 14, 17
39-
Optional string // std::optional, std::unique_ptr, std::shared_ptr
37+
PlainC bool
38+
LangVersion int // -1: unset, cpp: 11, 14, 17
39+
Optional string // std::optional, std::unique_ptr, std::shared_ptr
40+
EmptyStringAsNull bool
41+
NaNAsNull bool
4042
}
4143

4244
// BindingFiles returns names of binding files for the given entity file.
@@ -126,13 +128,15 @@ func (gen *CGenerator) generateBindingFile(bindingFile, headerFile string, m *mo
126128
fileIdentifier = replaceSpecialChars.Replace(fileIdentifier)
127129

128130
var tplArguments = struct {
129-
Model *model.ModelInfo
130-
GeneratorVersion int
131-
FileIdentifier string
132-
HeaderFile string
133-
Optional string
134-
LangVersion int
135-
}{m, generator.VersionId, fileIdentifier, filepath.Base(headerFile), gen.Optional, gen.LangVersion}
131+
Model *model.ModelInfo
132+
GeneratorVersion int
133+
FileIdentifier string
134+
HeaderFile string
135+
Optional string
136+
LangVersion int
137+
EmptyStringAsNull bool
138+
NaNAsNull bool
139+
}{m, generator.VersionId, fileIdentifier, filepath.Base(headerFile), gen.Optional, gen.LangVersion, gen.EmptyStringAsNull, gen.NaNAsNull}
136140

137141
var tpl *template.Template
138142

internal/generator/c/meta.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,17 @@ func (mp *fbsField) FbDefaultValue() string {
276276
return "0"
277277
}
278278

279+
// FbIsFloatingPoint returns true if type is float or double
280+
func (mp *fbsField) FbIsFloatingPoint() bool {
281+
switch mp.ModelProperty.Type {
282+
case model.PropertyTypeFloat:
283+
return true
284+
case model.PropertyTypeDouble:
285+
return true
286+
}
287+
return false
288+
}
289+
279290
// Try to determine the namespace of the target entity but don't fail if we can't because it's declared in a different
280291
// file. Assume no namespace in that case and hope for the best.
281292
func (mp *fbsField) relTargetNamespace() string {

internal/generator/c/templates/binding-cpp.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ var CppBindingTemplate = template.Must(template.New("binding-cpp").Funcs(funcMap
3232
{{define "field-value-assign-post"}}{{if IsOptionalPtr .Optional}})){{end}}{{end -}}
3333
3434
#include "{{.HeaderFile}}"
35+
{{if .NaNAsNull}}
36+
#include <cmath>
37+
{{end -}}
3538
{{range $entity := .Model.EntitiesWithMeta}}
3639
{{- range $property := $entity.Properties}}
3740
const
@@ -46,13 +49,17 @@ const obx::RelationStandalone<{{$entity.Meta.CppNamespacePrefix}}{{$entity.Meta.
4649
void {{$entity.Meta.CppNamespacePrefix}}{{$entity.Meta.CppName}}::_OBX_MetaInfo::toFlatBuffer(flatbuffers::FlatBufferBuilder& fbb, const {{$entity.Meta.CppNamespacePrefix}}{{$entity.Meta.CppName}}& object) {
4750
fbb.Clear();
4851
{{- range $property := $entity.Properties}}{{$factory := $property.Meta.FbOffsetFactory}}{{if $factory}}
49-
auto offset{{$property.Meta.CppName}} = {{if $property.Meta.Optional}}!object.{{$property.Meta.CppName}} ? 0 : {{end}}fbb.{{$factory}}({{template "field-value" $property.Meta}});
52+
auto offset{{$property.Meta.CppName}} =
53+
{{- if $property.Meta.Optional}} !object.{{$property.Meta.CppName}} ? 0 : {{end -}}
54+
{{- if and $.EmptyStringAsNull (eq "std::string" $property.Meta.CppType) }} ({{template "field-value" $property.Meta}}).empty() ? 0 :
55+
{{- end }} fbb.{{$factory}}({{template "field-value" $property.Meta}});
5056
{{- end}}{{end}}
5157
flatbuffers::uoffset_t fbStart = fbb.StartTable();
5258
{{range $property := $entity.Properties}}
5359
{{- if $property.Meta.Optional}}if (object.{{$property.Meta.CppName}}) {{end}}
5460
{{- if $property.Meta.FbOffsetFactory}}fbb.AddOffset({{$property.FbvTableOffset}}, offset{{$property.Meta.CppName}});
55-
{{- else}}fbb.AddElement({{$property.FbvTableOffset}}, {{template "field-value" $property.Meta}}{{if eq "bool" $property.Meta.CppType}} ? 1 : 0{{end}});
61+
{{- else -}}
62+
{{- if and $.NaNAsNull $property.Meta.FbIsFloatingPoint -}} if (!std::isnan({{template "field-value" $property.Meta}})) {{end -}} fbb.AddElement({{$property.FbvTableOffset}}, {{template "field-value" $property.Meta}}{{if eq "bool" $property.Meta.CppType}} ? 1 : 0{{end}});
5663
{{- end}}
5764
{{end -}}
5865
flatbuffers::Offset<flatbuffers::Table> offset;

0 commit comments

Comments
 (0)