Skip to content

Commit

Permalink
Serializer optimized, fixed noThrow serialization of optional
Browse files Browse the repository at this point in the history
  • Loading branch information
Chlumsky committed Mar 25, 2023
1 parent 91fb66a commit 9c4f518
Show file tree
Hide file tree
Showing 18 changed files with 151 additions and 114 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ for a more complex example.

The generated parsers and serializers are highly efficient because
no intermediate DOM or other auxiliary data structures are constructed -
data is read directly to / from the input structures.
data is read directly from / to the input structures.

## How to use

Expand Down Expand Up @@ -102,7 +102,7 @@ for the [`ConfigurationParser`](generated/ConfigurationParser.h) class.
- Custom string, array, object, and optional types if defined in the configuration file, see [below](#Custom-types)
- Namespaces
- Structure inheritance (basic support)
- Full UTF-8 & UTF-16 support
- Full UTF-8 & UTF-16 support in JSON

Currently **NOT** supported but planned features:
- Omitting specific member variables from parsing and serialization - planned via annotations
Expand Down Expand Up @@ -133,8 +133,7 @@ and how they should be written in the configuration file.
You can specify multiple types for each category.

These are mostly demonstrated on types from the standard library,
which however should not be put into the configuration file as they are present implicitly
and would cause collisions.
which however should not be put into the configuration file as they are present by default.

### String (dynamic)

Expand All @@ -147,8 +146,9 @@ and would cause collisions.
"getCharAt": "$S[$I]",
"appendChar": "$S.push_back($X)",
"appendCStr": "$S += $X",
"iterateChars": "for (char $E : $S) { $F }",
"equalsStringLiteral": "$S == $X"
"appendStringLiteral": "$S += $X",
"equalsStringLiteral": "$S == $X",
"iterateChars": "for (char $E : $S) { $F }"
}
} ]
```
Expand Down
6 changes: 6 additions & 0 deletions generated/ConfigurationParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,12 @@ void ConfigurationParser::parseStringAPI(StringAPI &value) {
continue;
}
break;
case 't':
if (buffer == "appendStringLiteral") {
parseStdString(value.appendStringLiteral);
continue;
}
break;
}
}
break;
Expand Down
6 changes: 4 additions & 2 deletions src/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,12 @@ struct StringAPI {
std::string appendChar;
// $S = subject string, $X = C string to append
std::string appendCStr;
// $S = subject string, $I = iterator variable name, $Z = end variable name, $E = name of element (char) variable, $F = loop body
std::string iterateChars;
// $S = subject string, $X = string literal to append
std::string appendStringLiteral;
// $S = subject string, $X = string literal to compare
std::string equalsStringLiteral;
// $S = subject string, $I = iterator variable name, $Z = end variable name, $E = name of element (char) variable, $F = loop body
std::string iterateChars;
};

struct ConstStringAPI {
Expand Down
54 changes: 27 additions & 27 deletions src/SerializerGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ const unsigned SerializerGenerator::FEATURE_SERIALIZE_FLOAT = 0x1000;
const unsigned SerializerGenerator::FEATURE_SERIALIZE_DOUBLE = 0x2000;
const unsigned SerializerGenerator::FEATURE_SERIALIZE_LONG_DOUBLE = 0x4000;

static std::string hexUint8(unsigned char x) {
char buffer[] = "00";
char *c = buffer+sizeof(buffer)-1;
for (int i = 0; i < 2; ++i, x >>= 4)
*--c = "0123456789abcdef"[x&0x0f];
return std::string(buffer);
}

SerializerGenerator::SerializerGenerator(const std::string &className, const StringType *stringType, const Settings &settings) : Generator(className, stringType, settings) { }

void SerializerGenerator::generateSerializerFunction(const Type *type) {
Expand Down Expand Up @@ -80,10 +88,8 @@ std::string SerializerGenerator::generateHeader() {

code += "\nprotected:\n";
code += generateVirtualTypedefs(INDENT);
code += INDENT+stringType()->name().refArgDeclaration("json")+";\n\n";
code += INDENT+className+"("+stringType()->name().refArgDeclaration("json")+");\n";
code += INDENT "void write(char c);\n";
code += INDENT "void write(const char *str);\n";
code += INDENT+stringType()->name().refArgDeclaration(OUTPUT_STRING)+";\n\n";
code += INDENT+className+"("+stringType()->name().refArgDeclaration(OUTPUT_STRING)+");\n";
code += INDENT "void writeEscaped(char c);\n";
code += "\n";

Expand Down Expand Up @@ -150,16 +156,8 @@ std::string SerializerGenerator::generateSource(const std::string &relativeHeade
code += "}\n\n";

// Constructor
code += className+"::"+className+"("+stringType()->name().refArgDeclaration("json")+") : json(json) {\n";
code += INDENT+stringType()->generateClear("json")+";\n";
code += "}\n\n";
// write(char)
code += "void "+className+"::write(char c) {\n";
code += INDENT+stringType()->generateAppendChar("json", "c")+";\n";
code += "}\n\n";
// write(const char *)
code += "void "+className+"::write(const char *str) {\n";
code += INDENT+stringType()->generateAppendCStr("json", "str")+";\n";
code += className+"::"+className+"("+stringType()->name().refArgDeclaration(OUTPUT_STRING)+") : "+OUTPUT_STRING+"("+OUTPUT_STRING+") {\n";
code += INDENT+stringType()->generateClear(OUTPUT_STRING)+";\n";
code += "}\n\n";
// writeEscaped
code += "void "+className+"::writeEscaped(char c) {\n";
Expand All @@ -173,19 +171,19 @@ std::string SerializerGenerator::generateSource(const std::string &relativeHeade
case '\r': alias = 'r'; break;
case '\t': alias = 't'; break;
}
char buffer[256];
if (alias)
sprintf(buffer, INDENT INDENT "case '\\%c': write(\"\\\\%c\"); break;\n", alias, alias);
else
sprintf(buffer, INDENT INDENT "case '\\x%02x': write(\"\\\\u%04x\"); break;\n", i, i);
code += buffer;
code += std::string(INDENT INDENT "case '\\")+alias+"': "+stringType()->generateAppendStringLiteral(OUTPUT_STRING, (std::string("\"\\\\")+alias+"\"").c_str())+"; break;\n";
else {
std::string hexChar = hexUint8((unsigned char) i);
code += INDENT INDENT "case '\\x"+hexChar+"': "+stringType()->generateAppendStringLiteral(OUTPUT_STRING, ("\"\\\\u00"+hexChar+"\"").c_str())+"; break;\n";
}
}
code += INDENT INDENT "case '\"': write(\"\\\\\\\"\"); break;\n";
code += INDENT INDENT "case '\"': "+stringType()->generateAppendStringLiteral(OUTPUT_STRING, "\"\\\\\\\"\"")+"; break;\n";
if (settings().escapeForwardSlash)
code += INDENT INDENT "case '/': write(\"\\\\/\"); break;\n";
code += INDENT INDENT "case '\\\\': write(\"\\\\\\\\\"); break;\n";
code += INDENT INDENT "case '/': "+stringType()->generateAppendStringLiteral(OUTPUT_STRING, "\"\\\\/\"")+"; break;\n";
code += INDENT INDENT "case '\\\\': "+stringType()->generateAppendStringLiteral(OUTPUT_STRING, "\"\\\\\\\\\"")+"; break;\n";
code += INDENT INDENT "default:\n";
code += INDENT INDENT INDENT "write(c);\n";
code += INDENT INDENT INDENT+stringType()->generateAppendChar(OUTPUT_STRING, "c")+";\n";
code += INDENT "}\n";
code += "}\n";

Expand All @@ -195,12 +193,14 @@ std::string SerializerGenerator::generateSource(const std::string &relativeHeade
code += "\n";
code += "template <typename U, typename T>\n";
code += "void "+className+"::writeSigned(T value) {\n";
code += INDENT "if (value < 0)\n";
code += INDENT INDENT "write('-'), value = -value;\n";
code += INDENT "if (value < 0) {\n";
code += INDENT INDENT+stringType()->generateAppendChar(OUTPUT_STRING, "'-'")+";\n";
code += INDENT INDENT "value = -value;\n";
code += INDENT "}\n";
code += INDENT "U unsignedValue = static_cast<U>(value);\n";
code += INDENT "char buffer[4*(sizeof(U)+1)], *cur = &(buffer[4*(sizeof(U)+1)-1] = '\\0');\n";
code += INDENT "do *--cur = '0'+unsignedValue%10; while (unsignedValue /= 10);\n";
code += INDENT "write(cur);\n";
code += INDENT+stringType()->generateAppendCStr(OUTPUT_STRING, "cur")+";\n";
code += "}\n";
}
if (featureBits&FEATURE_WRITE_UNSIGNED) {
Expand All @@ -209,7 +209,7 @@ std::string SerializerGenerator::generateSource(const std::string &relativeHeade
code += "void "+className+"::writeUnsigned(T value) {\n";
code += INDENT "char buffer[4*(sizeof(T)+1)], *cur = &(buffer[4*(sizeof(T)+1)-1] = '\\0');\n";
code += INDENT "do *--cur = '0'+value%10; while (value /= 10);\n";
code += INDENT "write(cur);\n";
code += INDENT+stringType()->generateAppendCStr(OUTPUT_STRING, "cur")+";\n";
code += "}\n";
}

Expand Down
2 changes: 2 additions & 0 deletions src/SerializerGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ class SerializerGenerator : public Generator {
#undef SERIALIZER_GENERATOR_ERROR_STR_DECL
};

static constexpr const char *const OUTPUT_STRING = "json";

static const unsigned FEATURE_WRITE_SIGNED;
static const unsigned FEATURE_WRITE_UNSIGNED;
static const unsigned FEATURE_SERIALIZE_FLOAT;
Expand Down
10 changes: 5 additions & 5 deletions src/types/ArrayContainerType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@ std::string ArrayContainerType::generateParserFunctionBody(ParserGenerator *gene
std::string ArrayContainerType::generateSerializerFunctionBody(SerializerGenerator *generator, const std::string &indent) const {
std::string body;
body += indent+"bool prev = false;\n";
body += indent+"write('[');\n";
body += indent+generator->stringType()->generateAppendChar(SerializerGenerator::OUTPUT_STRING, "'['")+";\n";
std::string iterBody;
iterBody += "if (prev) ";
iterBody += "write(','); ";
iterBody += "prev = true; ";
iterBody += "if (prev) { ";
iterBody += generator->stringType()->generateAppendChar(SerializerGenerator::OUTPUT_STRING, "','");
iterBody += "; } prev = true; ";
iterBody += generator->generateValueSerialization(elementType(), "elem");
body += indent+generateIterateElements("value", "i", "end", "elem", iterBody.c_str())+"\n";
body += indent+"write(']');\n";
body += indent+generator->stringType()->generateAppendChar(SerializerGenerator::OUTPUT_STRING, "']'")+";\n";
return body;
}

Expand Down
56 changes: 31 additions & 25 deletions src/types/BasicType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,31 +72,31 @@ static std::string generateFloatSerialization(SerializerGenerator *generator, Ba
body += indent+INDENT INDENT+generator->generateErrorStatement(SerializerGenerator::Error::UNREPRESENTABLE_FLOAT_VALUE)+";\n";
break;
case Settings::InfPolicy::EXPONENT_OVERFLOW:
body += indent+INDENT INDENT "write(\"-1e999\");\n";
body += indent+INDENT INDENT+generator->stringType()->generateAppendStringLiteral(SerializerGenerator::OUTPUT_STRING, "\"-1e999\"")+";\n";
break;
case Settings::InfPolicy::ZERO_VALUE:
body += indent+INDENT INDENT "write('0');\n";
body += indent+INDENT INDENT+generator->stringType()->generateAppendChar(SerializerGenerator::OUTPUT_STRING, "'0'")+";\n";
break;
case Settings::InfPolicy::NULL_VALUE:
body += indent+INDENT INDENT "write(\"null\");\n";
body += indent+INDENT INDENT+generator->stringType()->generateAppendStringLiteral(SerializerGenerator::OUTPUT_STRING, "\"null\"")+";\n";
break;
case Settings::InfPolicy::UPPERCASE_INF_STRING_VALUE:
body += indent+INDENT INDENT "write(\"\\\"-INF\\\"\");\n";
body += indent+INDENT INDENT+generator->stringType()->generateAppendStringLiteral(SerializerGenerator::OUTPUT_STRING, "\"\\\"-INF\\\"\"")+";\n";
break;
case Settings::InfPolicy::LOWERCASE_INF_STRING_VALUE:
body += indent+INDENT INDENT "write(\"\\\"-inf\\\"\");\n";
body += indent+INDENT INDENT+generator->stringType()->generateAppendStringLiteral(SerializerGenerator::OUTPUT_STRING, "\"\\\"-inf\\\"\"")+";\n";
break;
case Settings::InfPolicy::CAPITALIZED_INF_STRING_VALUE:
body += indent+INDENT INDENT "write(\"\\\"-Inf\\\"\");\n";
body += indent+INDENT INDENT+generator->stringType()->generateAppendStringLiteral(SerializerGenerator::OUTPUT_STRING, "\"\\\"-Inf\\\"\"")+";\n";
break;
case Settings::InfPolicy::UPPERCASE_INFINITY_STRING_VALUE:
body += indent+INDENT INDENT "write(\"\\\"-INFINITY\\\"\");\n";
body += indent+INDENT INDENT+generator->stringType()->generateAppendStringLiteral(SerializerGenerator::OUTPUT_STRING, "\"\\\"-INFINITY\\\"\"")+";\n";
break;
case Settings::InfPolicy::LOWERCASE_INFINITY_STRING_VALUE:
body += indent+INDENT INDENT "write(\"\\\"-infinity\\\"\");\n";
body += indent+INDENT INDENT+generator->stringType()->generateAppendStringLiteral(SerializerGenerator::OUTPUT_STRING, "\"\\\"-infinity\\\"\"")+";\n";
break;
case Settings::InfPolicy::CAPITALIZED_INFINITY_STRING_VALUE:
body += indent+INDENT INDENT "write(\"\\\"-Infinity\\\"\");\n";
body += indent+INDENT INDENT+generator->stringType()->generateAppendStringLiteral(SerializerGenerator::OUTPUT_STRING, "\"\\\"-Infinity\\\"\"")+";\n";
break;
}
body += indent+INDENT INDENT "break;\n";
Expand All @@ -107,31 +107,31 @@ static std::string generateFloatSerialization(SerializerGenerator *generator, Ba
body += indent+INDENT INDENT INDENT+generator->generateErrorStatement(SerializerGenerator::Error::UNREPRESENTABLE_FLOAT_VALUE)+";\n";
break;
case Settings::InfPolicy::EXPONENT_OVERFLOW:
body += indent+INDENT INDENT INDENT "write(\"1e999\");\n";
body += indent+INDENT INDENT+generator->stringType()->generateAppendStringLiteral(SerializerGenerator::OUTPUT_STRING, "\"1e999\"")+";\n";
break;
case Settings::InfPolicy::ZERO_VALUE:
body += indent+INDENT INDENT INDENT "write('0');\n";
body += indent+INDENT INDENT+generator->stringType()->generateAppendChar(SerializerGenerator::OUTPUT_STRING, "'0'")+";\n";
break;
case Settings::InfPolicy::NULL_VALUE:
body += indent+INDENT INDENT INDENT "write(\"null\");\n";
body += indent+INDENT INDENT+generator->stringType()->generateAppendStringLiteral(SerializerGenerator::OUTPUT_STRING, "\"null\"")+";\n";
break;
case Settings::InfPolicy::UPPERCASE_INF_STRING_VALUE:
body += indent+INDENT INDENT INDENT "write(\"\\\"INF\\\"\");\n";
body += indent+INDENT INDENT+generator->stringType()->generateAppendStringLiteral(SerializerGenerator::OUTPUT_STRING, "\"\\\"INF\\\"\"")+";\n";
break;
case Settings::InfPolicy::LOWERCASE_INF_STRING_VALUE:
body += indent+INDENT INDENT INDENT "write(\"\\\"inf\\\"\");\n";
body += indent+INDENT INDENT+generator->stringType()->generateAppendStringLiteral(SerializerGenerator::OUTPUT_STRING, "\"\\\"inf\\\"\"")+";\n";
break;
case Settings::InfPolicy::CAPITALIZED_INF_STRING_VALUE:
body += indent+INDENT INDENT INDENT "write(\"\\\"Inf\\\"\");\n";
body += indent+INDENT INDENT+generator->stringType()->generateAppendStringLiteral(SerializerGenerator::OUTPUT_STRING, "\"\\\"Inf\\\"\"")+";\n";
break;
case Settings::InfPolicy::UPPERCASE_INFINITY_STRING_VALUE:
body += indent+INDENT INDENT INDENT "write(\"\\\"INFINITY\\\"\");\n";
body += indent+INDENT INDENT+generator->stringType()->generateAppendStringLiteral(SerializerGenerator::OUTPUT_STRING, "\"\\\"INFINITY\\\"\"")+";\n";
break;
case Settings::InfPolicy::LOWERCASE_INFINITY_STRING_VALUE:
body += indent+INDENT INDENT INDENT "write(\"\\\"infinity\\\"\");\n";
body += indent+INDENT INDENT+generator->stringType()->generateAppendStringLiteral(SerializerGenerator::OUTPUT_STRING, "\"\\\"infinity\\\"\"")+";\n";
break;
case Settings::InfPolicy::CAPITALIZED_INFINITY_STRING_VALUE:
body += indent+INDENT INDENT INDENT "write(\"\\\"Infinity\\\"\");\n";
body += indent+INDENT INDENT+generator->stringType()->generateAppendStringLiteral(SerializerGenerator::OUTPUT_STRING, "\"\\\"Infinity\\\"\"")+";\n";
break;
}
body += indent+INDENT INDENT INDENT "break;\n";
Expand All @@ -143,24 +143,24 @@ static std::string generateFloatSerialization(SerializerGenerator *generator, Ba
body += indent+INDENT INDENT+generator->generateErrorStatement(SerializerGenerator::Error::UNREPRESENTABLE_FLOAT_VALUE)+";\n";
break;
case Settings::NanPolicy::ZERO_VALUE:
body += indent+INDENT INDENT "write('0');\n";
body += indent+INDENT INDENT+generator->stringType()->generateAppendChar(SerializerGenerator::OUTPUT_STRING, "'0'")+";\n";
break;
case Settings::NanPolicy::NULL_VALUE:
body += indent+INDENT INDENT "write(\"null\");\n";
body += indent+INDENT INDENT+generator->stringType()->generateAppendStringLiteral(SerializerGenerator::OUTPUT_STRING, "\"null\"")+";\n";
break;
case Settings::NanPolicy::UPPERCASE_NAN_STRING_VALUE:
body += indent+INDENT INDENT "write(\"\\\"NAN\\\"\");\n";
body += indent+INDENT INDENT+generator->stringType()->generateAppendStringLiteral(SerializerGenerator::OUTPUT_STRING, "\"\\\"NAN\\\"\"")+";\n";
break;
case Settings::NanPolicy::LOWERCASE_NAN_STRING_VALUE:
body += indent+INDENT INDENT "write(\"\\\"nan\\\"\");\n";
body += indent+INDENT INDENT+generator->stringType()->generateAppendStringLiteral(SerializerGenerator::OUTPUT_STRING, "\"\\\"nan\\\"\"")+";\n";
break;
case Settings::NanPolicy::MIXED_CASE_NAN_STRING_VALUE:
body += indent+INDENT INDENT "write(\"\\\"NaN\\\"\");\n";
body += indent+INDENT INDENT+generator->stringType()->generateAppendStringLiteral(SerializerGenerator::OUTPUT_STRING, "\"\\\"NaN\\\"\"")+";\n";
break;
}
body += indent+INDENT INDENT "break;\n";
body += indent+INDENT "default:\n";
body += indent+INDENT INDENT "write(buffer);\n";
body += indent+INDENT INDENT+generator->stringType()->generateAppendCStr(SerializerGenerator::OUTPUT_STRING, "buffer")+";\n";
body += indent+"}\n";
return body;
}
Expand Down Expand Up @@ -260,7 +260,13 @@ std::string BasicType::generateSerializerFunctionBody(SerializerGenerator *gener
case VOID:
break;
case BOOL:
return indent+"write(value ? \"true\" : \"false\");\n";
return (
indent+"if (value) {\n"+
indent+INDENT+generator->stringType()->generateAppendStringLiteral(SerializerGenerator::OUTPUT_STRING, "\"true\"")+";\n"+
indent+"} else {\n"+
indent+INDENT+generator->stringType()->generateAppendStringLiteral(SerializerGenerator::OUTPUT_STRING, "\"false\"")+";\n"+
indent+"}\n"
);
// Signed integer types
case CHAR:
return generateSignedSerializerFunctionBody(generator, UNSIGNED_CHAR, indent);
Expand Down
5 changes: 3 additions & 2 deletions src/types/ConstStringType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "../pattern-fill.h"
#include "../ParserGenerator.h"
#include "../SerializerGenerator.h"

ConstStringType::ConstStringType(const std::string &name, const StringType *stringType, const ConstStringAPI &api) : Type(TypeName(name)), stringType(stringType), api(api) { }

Expand All @@ -18,9 +19,9 @@ std::string ConstStringType::generateParserFunctionBody(ParserGenerator *generat

std::string ConstStringType::generateSerializerFunctionBody(SerializerGenerator *generator, const std::string &indent) const {
std::string body;
body += indent+"write('\"');\n";
body += indent+generator->stringType()->generateAppendChar(SerializerGenerator::OUTPUT_STRING, "'\"'")+";\n";
body += indent+generateIterateChars("value", "i", "end", "c", "writeEscaped(c);")+"\n";
body += indent+"write('\"');\n";
body += indent+generator->stringType()->generateAppendChar(SerializerGenerator::OUTPUT_STRING, "'\"'")+";\n";
return body;
}

Expand Down
Loading

0 comments on commit 9c4f518

Please sign in to comment.