// File: /workspace/github_cpp_makefile_star2_O3/hzeller[P]jcxxgen/schema-compiler.cc
// Function: GenerateCode(char const*, char const*, std::vector<ObjectType*, std::allocator<ObjectType*>> const&, _IO_FILE*)
void GenerateCode(const char *filename,
                  const char *nlohmann_json_include,
                  const ObjectTypeVector &objects,
                  FILE *out) {
  fprintf(out, "// Don't modify. Generated from %s\n", filename);
  fprintf(out, "#pragma once\n"
          "#include <string>\n"
          "#include <vector>\n");
  fprintf(out, "#include %s\n\n", nlohmann_json_include);
  for (const auto& o : objects) {
    fprintf(out, "struct %s", o->name.c_str());
    bool is_first = true;
    for (const auto &e : o->extends) {
      fprintf(out, "%s", is_first ? " :" : ",");
      fprintf(out, " public %s", e.c_str());
      is_first = false;
    }
    fprintf(out, " {\n");
    for (const auto&p : o->properties) {
      std::string type;
      if (p.object_type) type = p.object_type->name;
      else if (p.type == "string") type = "std::string";
      else if (p.type == "integer") type = "int";
      else if (p.type == "object") type = "nlohmann::json";
      else if (p.type == "boolean") type = "bool";
      // TODO: optional and array
      if (type.empty()) {
        std::cerr << p.location << "Not supported yet '" << p.type << "'\n";
        continue;
      }
      if (p.is_array) {
        fprintf(out, "  std::vector<%s> %s", type.c_str(), p.name.c_str());
      } else {
        fprintf(out, "  %s %s", type.c_str(), p.name.c_str());
      }
      if (!p.default_value.empty())
        fprintf(out, " = %s", p.default_value.c_str());
      fprintf(out, ";\n");
      if (p.is_optional) {
        fprintf(out, "  bool has_%s = false;  // optional property\n",
                p.name.c_str());
      }
    }

    // nlohmann::json serialization
    fprintf(out, "\n");
    fprintf(out, "  void Deserialize(const nlohmann::json &j) {\n");
    for (const auto &e : o->extends) {
      fprintf(out, "    %s::Deserialize(j);\n",
              e.c_str());
    }
    for (const auto&p : o->properties) {
      int indent = 4;
      std::string access_call = "j.at(\"" + p.name + "\")";
      std::string access_deref =  access_call + ".";
      if (p.is_optional) {
        fprintf(out, "%*sif (auto found = j.find(\"%s\"); found != j.end()) {\n",
                indent, "", p.name.c_str());
        indent += 4;
        fprintf(out, "%*shas_%s = true;\n", indent, "", p.name.c_str());
        access_call = "*found";
        access_deref = "found->";
      }
      if (p.object_type == nullptr || p.is_array) {
        fprintf(out, "%*s%sget_to(%s);\n",
                indent, "", access_deref.c_str(), p.name.c_str());
      } else {
        fprintf(out, "%*s%s.Deserialize(%s);\n",
                indent, "", p.name.c_str(), access_call.c_str());
      }
      if (p.is_optional) {
        fprintf(out, "%*s}\n", indent-4, "");
      }
    }
    fprintf(out, "  }\n");

    fprintf(out, "  void Serialize(nlohmann::json *j) const {\n");
    for (const auto &e : o->extends) {
      fprintf(out, "    %s::Serialize(j);\n", e.c_str());
    }
    for (const auto&p : o->properties) {
      int indent = 4;
      if (p.is_optional) {
        fprintf(out, "%*sif (has_%s)", indent, "", p.name.c_str());
        indent = 1;
      }
      if (p.object_type == nullptr || p.is_array) {
        fprintf(out, "%*s(*j)[\"%s\"] = %s;\n",
                indent, "", p.name.c_str(), p.name.c_str());
      } else {
        fprintf(out, "%*s%s.Serialize(&(*j)[\"%s\"]);\n",
                indent, "", p.name.c_str(), p.name.c_str());
      }
    }
    fprintf(out, "  }\n");

    fprintf(out, "};\n"); // End of struct

    // functions that are picked up by the nlohmann::json serializer
    // We could generate template code once for all to_json/from_json that take
    // a T obj, but to limit method lookup confusion for other objects that
    // might interact with the json library, let's be explicit for each struct
    fprintf(out, "inline void to_json(nlohmann::json &j, const %s &obj) "
            "{ obj.Serialize(&j); }\n", o->name.c_str());
    fprintf(out, "inline void from_json(const nlohmann::json &j, %s &obj) "
            "{ obj.Deserialize(j); }\n\n", o->name.c_str());
  }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x58, %rsp
movq %rcx, %rbx
movq %rdx, %r14
movq %rsi, %r15
movq %rdi, %rdx
leaq 0xff9c(%rip), %rsi      # 0x160f8
movq %rcx, %rdi
xorl %eax, %eax
callq 0x43d0
leaq 0xffaf(%rip), %rdi      # 0x1611c
movl $0x31, %esi
movl $0x1, %edx
movq %rbx, %rcx
callq 0x4520
leaq 0xffc8(%rip), %rsi      # 0x1614e
movq %rbx, %rdi
movq %r15, %rdx
xorl %eax, %eax
callq 0x43d0
movq (%r14), %r15
movq 0x8(%r14), %rax
movq %rax, -0x78(%rbp)
cmpq %rax, %r15
je 0x684e
leaq 0xffbd(%rip), %r12      # 0x1616b
leaq 0xffb4(%rip), %r13      # 0x16169
movq (%r15), %rax
movq 0x10(%rax), %rdx
movq %rbx, %rdi
leaq 0xff96(%rip), %rsi      # 0x1615c
xorl %eax, %eax
callq 0x43d0
movq %r15, -0x50(%rbp)
movq (%r15), %rax
movq 0x30(%rax), %r14
movq 0x38(%rax), %r15
cmpq %r15, %r14
je 0x620c
leaq 0xff7e(%rip), %rdi      # 0x16166
movq %rbx, %rsi
callq 0x42e0
movq (%r14), %rdx
movq %rbx, %rdi
movq %r12, %rsi
xorl %eax, %eax
callq 0x43d0
addq $0x20, %r14
movq %r13, %rdi
cmpq %r15, %r14
jne 0x61e8
movl $0x3, %esi
movl $0x1, %edx
leaq 0x1007a(%rip), %rdi     # 0x16297
movq %rbx, %rcx
callq 0x4520
movq -0x50(%rbp), %rax
movq (%rax), %rax
movq 0x48(%rax), %r13
movq 0x50(%rax), %r12
cmpq %r12, %r13
leaq 0xff3d(%rip), %r15      # 0x1617b
je 0x6480
addq $0x60, %r13
leaq -0x38(%rbp), %rax
movq %rax, -0x48(%rbp)
movq $0x0, -0x40(%rbp)
movb $0x0, -0x38(%rbp)
movq 0x20(%r13), %rsi
testq %rsi, %rsi
je 0x6277
addq $0x10, %rsi
leaq -0x48(%rbp), %rdi
callq 0x4190
jmp 0x6308
movq %r13, %rdi
movq %r15, %rsi
callq 0x40b0
testl %eax, %eax
je 0x62ce
movq %r13, %rdi
leaq 0xfef2(%rip), %rsi      # 0x16182
callq 0x40b0
testl %eax, %eax
je 0x62dd
movq %r13, %rdi
leaq 0xfee7(%rip), %rsi      # 0x1618a
callq 0x40b0
testl %eax, %eax
je 0x62ec
movq %r13, %rdi
leaq 0xfeea(%rip), %rsi      # 0x161a0
callq 0x40b0
testl %eax, %eax
jne 0x6308
movl $0x4, %r8d
leaq 0xfedc(%rip), %rcx      # 0x161a8
jmp 0x62f9
movl $0xb, %r8d
leaq 0xfe9b(%rip), %rcx      # 0x16176
jmp 0x62f9
movl $0x3, %r8d
leaq 0x1074f(%rip), %rcx     # 0x16a39
jmp 0x62f9
movl $0xe, %r8d
leaq 0xfe98(%rip), %rcx      # 0x16191
movq -0x40(%rbp), %rdx
leaq -0x48(%rbp), %rdi
xorl %esi, %esi
callq 0x4400
cmpq $0x0, -0x40(%rbp)
je 0x6396
movq -0x48(%rbp), %rdx
cmpb $0x0, -0x27(%r13)
movq -0x48(%r13), %rcx
leaq 0xfeaf(%rip), %rsi      # 0x161d6
leaq 0xfe93(%rip), %rax      # 0x161c1
cmovneq %rax, %rsi
movq %rbx, %rdi
xorl %eax, %eax
callq 0x43d0
cmpq $0x0, -0x18(%r13)
je 0x6358
movq -0x20(%r13), %rdx
movq %rbx, %rdi
leaq 0xfe8d(%rip), %rsi      # 0x161de
xorl %eax, %eax
callq 0x43d0
movl $0x2, %esi
movl $0x1, %edx
leaq 0x1000d(%rip), %rdi     # 0x16376
movq %rbx, %rcx
callq 0x4520
cmpb $0x1, -0x28(%r13)
jne 0x6450
movq -0x48(%r13), %rdx
movq %rbx, %rdi
leaq 0xfe5a(%rip), %rsi      # 0x161e4
xorl %eax, %eax
callq 0x43d0
jmp 0x6450
movq -0x60(%r13), %r14
testq %r14, %r14
je 0x63bb
movq %r14, %rdi
callq 0x4140
movq 0x18c3a(%rip), %rdi     # 0x1efe8
movq %r14, %rsi
movq %rax, %rdx
callq 0x4300
jmp 0x63d9
movq 0x18c26(%rip), %rcx     # 0x1efe8
movq (%rcx), %rax
movq -0x18(%rax), %rax
leaq (%rcx,%rax), %rdi
movl 0x20(%rcx,%rax), %esi
orl $0x1, %esi
callq 0x4450
movl $0x1, %edx
movq 0x18c03(%rip), %rdi     # 0x1efe8
leaq 0xfd7b(%rip), %rsi      # 0x16167
callq 0x4300
movl -0x58(%r13), %esi
movq 0x18bec(%rip), %rdi     # 0x1efe8
callq 0x4470
movq %rax, %r14
movl $0x2, %edx
movq %rax, %rdi
leaq 0x10b9c(%rip), %rsi     # 0x16faf
callq 0x4300
movl $0x13, %edx
movq %r14, %rdi
leaq 0xfd86(%rip), %rsi      # 0x161ad
callq 0x4300
movq (%r13), %rsi
movq 0x8(%r13), %rdx
movq %r14, %rdi
callq 0x4300
movl $0x2, %edx
movq %rax, %rdi
leaq 0x100bc(%rip), %rsi     # 0x16507
callq 0x4300
movq -0x48(%rbp), %rdi
leaq -0x38(%rbp), %rax
cmpq %rax, %rdi
je 0x6469
movq -0x38(%rbp), %rsi
incq %rsi
callq 0x4290
leaq 0x88(%r13), %rax
addq $0x28, %r13
cmpq %r12, %r13
movq %rax, %r13
jne 0x6248
movl $0xa, %edi
movq %rbx, %rsi
callq 0x4350
movl $0x2e, %esi
movl $0x1, %edx
leaq 0xfd74(%rip), %rdi      # 0x16212
movq %rbx, %rcx
callq 0x4520
movq -0x50(%rbp), %r12
movq (%r12), %rax
movq 0x30(%rax), %r14
movq 0x38(%rax), %r15
cmpq %r15, %r14
leaq 0xfd81(%rip), %r13      # 0x16241
je 0x64df
movq (%r14), %rdx
movq %rbx, %rdi
movq %r13, %rsi
xorl %eax, %eax
callq 0x43d0
addq $0x20, %r14
cmpq %r15, %r14
jne 0x64c2
movq (%r12), %rax
movq 0x48(%rax), %r12
movq 0x50(%rax), %rax
movq %rax, -0x80(%rbp)
cmpq %rax, %r12
leaq -0x60(%rbp), %r14
leaq 0xfc62(%rip), %r13      # 0x1615b
je 0x66e5
leaq 0x18(%r12), %r13
leaq -0x70(%rbp), %r15
movq %r15, %rdi
leaq 0xfd48(%rip), %rsi      # 0x1625a
movq %r13, %rdx
callq 0x6a00
movq %r15, %rdi
leaq 0xfd3d(%rip), %rsi      # 0x16261
callq 0x4510
leaq -0x38(%rbp), %rsi
movq %rsi, -0x48(%rbp)
movq (%rax), %rdx
movq %rax, %rcx
addq $0x10, %rcx
cmpq %rcx, %rdx
je 0x654d
movq %rdx, -0x48(%rbp)
movq (%rcx), %rdx
movq %rdx, -0x38(%rbp)
jmp 0x6553
movups (%rcx), %xmm0
movups %xmm0, (%rsi)
movq 0x8(%rax), %rdx
movq %rdx, -0x40(%rbp)
movq %rcx, (%rax)
movq $0x0, 0x8(%rax)
movb $0x0, 0x10(%rax)
movq -0x70(%rbp), %rdi
cmpq %r14, %rdi
je 0x657f
movq -0x60(%rbp), %rsi
incq %rsi
callq 0x4290
movq %r14, -0x70(%rbp)
movq -0x48(%rbp), %rsi
movq -0x40(%rbp), %rdx
addq %rsi, %rdx
movq %r15, %rdi
callq 0xc7f0
movq %r15, %rdi
leaq 0x10379(%rip), %rsi     # 0x16919
callq 0x4510
movl $0x4, %r14d
cmpb $0x1, 0x38(%r12)
jne 0x6632
movq (%r13), %r8
movq %rbx, %rdi
leaq 0xfca3(%rip), %rsi      # 0x16264
movl $0x4, %edx
leaq 0xfb8e(%rip), %r14      # 0x1615b
movq %r14, %rcx
xorl %eax, %eax
callq 0x43d0
movq (%r13), %r8
movq %rbx, %rdi
leaq 0xfcb6(%rip), %rsi      # 0x1629b
movl $0x8, %edx
movq %r14, %rcx
xorl %eax, %eax
callq 0x43d0
movq -0x40(%rbp), %rdx
movl $0x6, %r8d
leaq -0x48(%rbp), %rdi
xorl %esi, %esi
leaq 0xfca3(%rip), %rcx      # 0x162ae
callq 0x4400
movl $0x8, %r14d
movq -0x68(%rbp), %rdx
movl $0x7, %r8d
leaq -0x70(%rbp), %rdi
xorl %esi, %esi
leaq 0xfc88(%rip), %rcx      # 0x162b5
callq 0x4400
cmpq $0x0, 0x80(%r12)
je 0x6645
cmpb $0x1, 0x39(%r12)
jne 0x6659
movq -0x70(%rbp), %r8
movq (%r13), %r9
movq %rbx, %rdi
leaq 0xfc66(%rip), %rsi      # 0x162bd
jmp 0x666b
movq (%r13), %r8
movq -0x48(%rbp), %r9
movq %rbx, %rdi
leaq 0xfc64(%rip), %rsi      # 0x162cf
movl %r14d, %edx
leaq 0xfae6(%rip), %r13      # 0x1615b
movq %r13, %rcx
xorl %eax, %eax
callq 0x43d0
cmpb $0x1, 0x38(%r12)
jne 0x66a2
addl $-0x4, %r14d
movq %rbx, %rdi
leaq 0xfc52(%rip), %rsi      # 0x162e7
movl %r14d, %edx
movq %r13, %rcx
xorl %eax, %eax
callq 0x43d0
movq -0x70(%rbp), %rdi
leaq -0x60(%rbp), %r14
cmpq %r14, %rdi
je 0x66bb
movq -0x60(%rbp), %rsi
incq %rsi
callq 0x4290
movq -0x48(%rbp), %rdi
leaq -0x38(%rbp), %rax
cmpq %rax, %rdi
je 0x66d4
movq -0x38(%rbp), %rsi
incq %rsi
callq 0x4290
addq $0x88, %r12
cmpq -0x80(%rbp), %r12
jne 0x64ff
movl $0x4, %esi
movl $0x1, %edx
leaq 0xfbf7(%rip), %rdi      # 0x162ed
movq %rbx, %rcx
callq 0x4520
movl $0x2c, %esi
movl $0x1, %edx
leaq 0xfbe3(%rip), %rdi      # 0x162f2
movq %rbx, %rcx
callq 0x4520
movq -0x50(%rbp), %rax
movq (%rax), %rax
movq 0x30(%rax), %r14
movq 0x38(%rax), %r15
cmpq %r15, %r14
leaq 0xfbef(%rip), %r12      # 0x1631f
je 0x6752
movq (%r14), %rdx
movq %rbx, %rdi
movq %r12, %rsi
xorl %eax, %eax
callq 0x43d0
addq $0x20, %r14
cmpq %r15, %r14
jne 0x6732
movq -0x50(%rbp), %rax
movq (%rax), %rax
movq 0x48(%rax), %r14
movq 0x50(%rax), %r15
cmpq %r15, %r14
leaq 0xfa07(%rip), %r12      # 0x1616b
je 0x67d3
movl $0x4, %edx
cmpb $0x1, 0x38(%r14)
jne 0x678f
movq 0x18(%r14), %r8
movq %rbx, %rdi
leaq 0xfbb6(%rip), %rsi      # 0x16336
movq %r13, %rcx
xorl %eax, %eax
callq 0x43d0
movl $0x1, %edx
cmpq $0x0, 0x80(%r14)
leaq 0xfba7(%rip), %rax      # 0x16345
movq %rax, %rsi
je 0x67b3
cmpb $0x0, 0x39(%r14)
leaq 0xfbab(%rip), %rsi      # 0x1635a
cmovneq %rax, %rsi
movq 0x18(%r14), %r8
movq %rbx, %rdi
movq %r13, %rcx
movq %r8, %r9
xorl %eax, %eax
callq 0x43d0
addq $0x88, %r14
cmpq %r15, %r14
jne 0x6766
movl $0x4, %esi
movl $0x1, %edx
leaq 0xfb09(%rip), %rdi      # 0x162ed
movq %rbx, %rcx
callq 0x4520
movl $0x3, %esi
movl $0x1, %edx
leaq 0xfb7c(%rip), %rdi      # 0x16379
movq %rbx, %rcx
callq 0x4520
movq -0x50(%rbp), %r15
movq (%r15), %rax
movq 0x10(%rax), %rdx
movq %rbx, %rdi
leaq 0xfb63(%rip), %rsi      # 0x1637d
xorl %eax, %eax
callq 0x43d0
movq (%r15), %rax
movq 0x10(%rax), %rdx
movq %rbx, %rdi
leaq 0xfb99(%rip), %rsi      # 0x163cb
xorl %eax, %eax
callq 0x43d0
addq $0x8, %r15
cmpq -0x78(%rbp), %r15
leaq 0xf921(%rip), %r13      # 0x16169
jne 0x61b5
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %rbx
movq -0x70(%rbp), %rdi
cmpq %r14, %rdi
jne 0x688f
jmp 0x68a0
movq %rax, %rbx
movq -0x70(%rbp), %rdi
cmpq %r14, %rdi
je 0x68b9
movq -0x60(%rbp), %rsi
jmp 0x68b1
jmp 0x689d
movq %rax, %rbx
movq -0x70(%rbp), %rdi
leaq -0x60(%rbp), %rax
cmpq %rax, %rdi
je 0x68a0
movq -0x60(%rbp), %rsi
incq %rsi
callq 0x4290
jmp 0x68a0
movq %rax, %rbx
movq -0x48(%rbp), %rdi
leaq -0x38(%rbp), %rax
cmpq %rax, %rdi
je 0x68b9
movq -0x38(%rbp), %rsi
incq %rsi
callq 0x4290
movq %rbx, %rdi
callq 0x4480