diff --git a/src/coders/commons.cpp b/src/coders/commons.cpp index 120c180d..14664c0d 100644 --- a/src/coders/commons.cpp +++ b/src/coders/commons.cpp @@ -181,23 +181,27 @@ int64_t BasicParser::parseSimpleInt(int base) { return value; } -double BasicParser::parseNumber(int sign) { +bool BasicParser::parseNumber(int sign, number_u& out) { char c = peek(); int base = 10; if (c == '0' && pos + 1 < source.length() && (base = is_box(source[pos+1])) != 10) { pos += 2; - return parseSimpleInt(base); + out.ival = parseSimpleInt(base); + return true; } else if (c == 'i' && pos + 2 < source.length() && source[pos+1] == 'n' && source[pos+2] == 'f') { pos += 3; - return INFINITY * sign; + out.fval = INFINITY * sign; + return false; } else if (c == 'n' && pos + 2 < source.length() && source[pos+1] == 'a' && source[pos+2] == 'n') { pos += 3; - return NAN * sign; + out.fval = NAN * sign; + return false; } int64_t value = parseSimpleInt(base); if (!hasNext()) { - return value * sign; + out.ival = value * sign; + return true; } c = source[pos]; if (c == 'e' || c == 'E') { @@ -209,7 +213,8 @@ double BasicParser::parseNumber(int sign) { } else if (peek() == '+'){ pos++; } - return sign * value * power(10.0, s * parseSimpleInt(10)); + out.fval = sign * value * power(10.0, s * parseSimpleInt(10)); + return false; } if (c == '.') { pos++; @@ -235,11 +240,14 @@ double BasicParser::parseNumber(int sign) { } else if (peek() == '+'){ pos++; } - return sign * dvalue * power(10.0, s * parseSimpleInt(10)); + out.fval = sign * dvalue * power(10.0, s * parseSimpleInt(10)); + return false; } - return dvalue; + out.fval = dvalue; + return false; } - return value; + out.ival = value; + return true; } string BasicParser::parseString(char quote) { diff --git a/src/coders/commons.h b/src/coders/commons.h index a7769ff3..a76d0fd5 100644 --- a/src/coders/commons.h +++ b/src/coders/commons.h @@ -5,6 +5,11 @@ #include #include "../typedefs.h" +union number_u { + double fval; + int64_t ival; +}; + inline int is_box(int c) { switch (c) { case 'B': @@ -73,7 +78,7 @@ protected: std::string parseName(); int64_t parseSimpleInt(int base); - double parseNumber(int sign); + bool parseNumber(int sign, number_u& out); std::string parseString(char chr); parsing_error error(std::string message); diff --git a/src/coders/json.cpp b/src/coders/json.cpp index 9b7a57b3..971e7cc1 100644 --- a/src/coders/json.cpp +++ b/src/coders/json.cpp @@ -15,7 +15,7 @@ using std::unordered_map; using std::stringstream; using std::make_pair; -inline void newline(std::stringstream& ss, bool nice, uint indent, const std::string indentstr) { +inline void newline(stringstream& ss, bool nice, uint indent, const string indentstr) { if (nice) { ss << "\n"; for (uint i = 0; i < indent; i++) { @@ -26,10 +26,23 @@ inline void newline(std::stringstream& ss, bool nice, uint indent, const std::st } } -void stringify(Value* value, stringstream& ss, int indent, string indentstr, bool nice); -void stringifyObj(JObject* obj, stringstream& ss, int indent, string indentstr, bool nice); +void stringify(Value* value, + stringstream& ss, + int indent, + string indentstr, + bool nice); -void stringify(Value* value, stringstream& ss, int indent, string indentstr, bool nice) { +void stringifyObj(JObject* obj, + stringstream& ss, + int indent, + string indentstr, + bool nice); + +void stringify(Value* value, + stringstream& ss, + int indent, + string indentstr, + bool nice) { if (value->type == valtype::object) { stringifyObj(value->value.obj, ss, indent, indentstr, nice); } @@ -57,7 +70,9 @@ void stringify(Value* value, stringstream& ss, int indent, string indentstr, boo } else if (value->type == valtype::boolean) { ss << (value->value.boolean ? "true" : "false"); } else if (value->type == valtype::number) { - ss << value->value.num; + ss << value->value.decimal; + } else if (value->type == valtype::integer) { + ss << value->value.integer; } else if (value->type == valtype::string) { ss << escape_string(*value->value.str); } @@ -103,11 +118,39 @@ JArray::~JArray() { } std::string JArray::str(size_t index) const { - return *values[index]->value.str; + const auto& val = values[index]; + switch (val->type) { + case valtype::string: return *val->value.str; + case valtype::boolean: return val->value.boolean ? "true" : "false"; + case valtype::number: return std::to_string(val->value.decimal); + case valtype::integer: return std::to_string(val->value.integer); + default: + throw std::runtime_error("type error"); + } } double JArray::num(size_t index) const { - return values[index]->value.num; + const auto& val = values[index]; + switch (val->type) { + case valtype::number: return val->value.decimal; + case valtype::integer: return val->value.integer; + case valtype::string: return std::stoll(*val->value.str); + case valtype::boolean: return val->value.boolean; + default: + throw std::runtime_error("type error"); + } +} + +int64_t JArray::integer(size_t index) const { + const auto& val = values[index]; + switch (val->type) { + case valtype::number: return val->value.decimal; + case valtype::integer: return val->value.integer; + case valtype::string: return std::stoll(*val->value.str); + case valtype::boolean: return val->value.boolean; + default: + throw std::runtime_error("type error"); + } } JObject* JArray::obj(size_t index) const { @@ -130,25 +173,33 @@ JArray& JArray::put(string value) { } JArray& JArray::put(uint value) { - return put((double)value); + return put((int64_t)value); } JArray& JArray::put(int value) { - return put((double)value); + return put((int64_t)value); +} + +JArray& JArray::put(int64_t value) { + valvalue val; + val.integer = value; + values.push_back(new Value(valtype::integer, val)); + return *this; +} + +JArray& JArray::put(uint64_t value) { + return put((int64_t)value); } JArray& JArray::put(double value) { valvalue val; - val.num = value; + val.decimal = value; values.push_back(new Value(valtype::number, val)); return *this; } JArray& JArray::put(float value) { - valvalue val; - val.num = value; - values.push_back(new Value(valtype::number, val)); - return *this; + return put((double)value); } JArray& JArray::put(bool value) { @@ -172,46 +223,96 @@ JArray& JArray::put(JArray* value) { return *this; } +JArray& JArray::putArray() { + JArray* arr = new JArray(); + put(arr); + return *arr; +} + +JObject& JArray::putObj() { + JObject* obj = new JObject(); + put(obj); + return *obj; +} + JObject::~JObject() { for (auto entry : map) { delete entry.second; } } -void JObject::str(std::string key, std::string& dst) const { - auto found = map.find(key); - if (found != map.end()) - dst = *found->second->value.str; +void JObject::str(string key, string& dst) const { + dst = getStr(key, dst); } -void JObject::num(std::string key, double& dst) const { +string JObject::getStr(string key, const string& def) const { auto found = map.find(key); - if (found != map.end()) - dst = found->second->value.num; + if (found == map.end()) + return def; + auto& val = found->second; + switch (val->type) { + case valtype::string: return *val->value.str; + case valtype::boolean: return val->value.boolean ? "true" : "false"; + case valtype::number: return std::to_string(val->value.decimal); + case valtype::integer: return std::to_string(val->value.integer); + default: throw std::runtime_error("type error"); + } } -void JObject::num(std::string key, ubyte& dst) const { +double JObject::getNum(string key, double def) const { auto found = map.find(key); - if (found != map.end()) - dst = found->second->value.num; + if (found == map.end()) + return def; + auto& val = found->second; + switch (val->type) { + case valtype::number: return val->value.decimal; + case valtype::integer: return val->value.integer; + case valtype::string: return std::stoull(*val->value.str); + case valtype::boolean: return val->value.boolean; + default: throw std::runtime_error("type error"); + } +} + +int64_t JObject::getInteger(string key, int64_t def) const { + auto found = map.find(key); + if (found == map.end()) + return def; + auto& val = found->second; + switch (val->type) { + case valtype::number: return val->value.decimal; + case valtype::integer: return val->value.integer; + case valtype::string: return std::stoull(*val->value.str); + case valtype::boolean: return val->value.boolean; + default: throw std::runtime_error("type error"); + } +} + +void JObject::num(string key, double& dst) const { + dst = getNum(key, dst); } void JObject::num(std::string key, float& dst) const { - auto found = map.find(key); - if (found != map.end()) - dst = found->second->value.num; + dst = getNum(key, dst); +} + +void JObject::num(std::string key, ubyte& dst) const { + dst = getInteger(key, dst); } void JObject::num(std::string key, int& dst) const { - auto found = map.find(key); - if (found != map.end()) - dst = found->second->value.num; + dst = getInteger(key, dst); +} + +void JObject::num(std::string key, int64_t& dst) const { + dst = getInteger(key, dst); +} + +void JObject::num(std::string key, uint64_t& dst) const { + dst = getInteger(key, dst); } void JObject::num(std::string key, uint& dst) const { - auto found = map.find(key); - if (found != map.end()) - dst = found->second->value.num; + dst = getInteger(key, dst); } JObject* JObject::obj(std::string key) const { @@ -235,11 +336,24 @@ void JObject::flag(std::string key, bool& dst) const { } JObject& JObject::put(string key, uint value) { - return put(key, (double)value); + return put(key, (int64_t)value); } JObject& JObject::put(string key, int value) { - return put(key, (double)value); + return put(key, (int64_t)value); +} + +JObject& JObject::put(string key, int64_t value) { + auto found = map.find(key); + if (found != map.end()) delete found->second; + valvalue val; + val.integer = value; + map.insert(make_pair(key, new Value(valtype::integer, val))); + return *this; +} + +JObject& JObject::put(string key, uint64_t value) { + return put(key, (int64_t)value); } JObject& JObject::put(string key, float value) { @@ -250,7 +364,7 @@ JObject& JObject::put(string key, double value) { auto found = map.find(key); if (found != map.end()) delete found->second; valvalue val; - val.num = value; + val.decimal = value; map.insert(make_pair(key, new Value(valtype::number, val))); return *this; } @@ -295,12 +409,18 @@ JObject& JObject::put(string key, bool value){ return *this; } -JArray& JObject::putArray(std::string key) { +JArray& JObject::putArray(string key) { JArray* arr = new JArray(); put(key, arr); return *arr; } +JObject& JObject::putObj(string key) { + JObject* obj = new JObject(); + put(key, obj); + return *obj; +} + bool JObject::has(string key) { return map.find(key) != map.end(); } @@ -386,10 +506,10 @@ Value* Parser::parseValue() { val.boolean = false; return new Value(valtype::boolean, val); } else if (literal == "inf") { - val.num = INFINITY; + val.decimal = INFINITY; return new Value(valtype::number, val); } else if (literal == "nan") { - val.num = NAN; + val.decimal = NAN; return new Value(valtype::number, val); } throw error("invalid literal"); @@ -404,12 +524,28 @@ Value* Parser::parseValue() { } if (next == '-' || next == '+') { pos++; - val.num = parseNumber(next == '-' ? -1 : 1); - return new Value(valtype::number, val); + number_u num; + valtype type; + if (parseNumber(next == '-' ? -1 : 1, num)) { + val.integer = num.ival; + type = valtype::integer; + } else { + val.decimal = num.fval; + type = valtype::number; + } + return new Value(type, val); } if (is_digit(next)) { - val.num = parseNumber(1); - return new Value(valtype::number, val); + number_u num; + valtype type; + if (parseNumber(1, num)) { + val.integer = num.ival; + type = valtype::integer; + } else { + val.decimal = num.fval; + type = valtype::number; + } + return new Value(type, val); } if (next == '"' || next == '\'') { pos++; @@ -419,11 +555,11 @@ Value* Parser::parseValue() { throw error("unexpected character '"+string({next})+"'"); } -JObject* json::parse(std::string filename, std::string source) { +JObject* json::parse(string filename, string source) { Parser parser(filename, source); return parser.parse(); } -JObject* json::parse(std::string source) { +JObject* json::parse(string source) { return parse("", source); -} \ No newline at end of file +} diff --git a/src/coders/json.h b/src/coders/json.h index d4961cb7..94d8b5a9 100644 --- a/src/coders/json.h +++ b/src/coders/json.h @@ -19,14 +19,15 @@ namespace json { extern std::string stringify(JObject* obj, bool nice, std::string indent); enum class valtype { - object, array, number, string, boolean + object, array, number, integer, string, boolean }; union valvalue { JObject* obj; JArray* arr; std::string* str; - double num; + double decimal; + int64_t integer; bool boolean; }; @@ -45,6 +46,7 @@ namespace json { std::string str(size_t index) const; double num(size_t index) const; + int64_t integer(size_t num) const; JObject* obj(size_t index) const; JArray* arr(size_t index) const; bool flag(size_t index) const; @@ -55,12 +57,17 @@ namespace json { JArray& put(uint value); JArray& put(int value); + JArray& put(uint64_t value); + JArray& put(int64_t value); JArray& put(float value); JArray& put(double value); JArray& put(std::string value); JArray& put(JObject* value); JArray& put(JArray* value); JArray& put(bool value); + + JArray& putArray(); + JObject& putObj(); }; class JObject { @@ -68,10 +75,15 @@ namespace json { std::unordered_map map; ~JObject(); + std::string getStr(std::string key, const std::string& def) const; + double getNum(std::string key, double def) const; + int64_t getInteger(std::string key, int64_t def) const; void str(std::string key, std::string& dst) const; void num(std::string key, int& dst) const; void num(std::string key, float& dst) const; void num(std::string key, uint& dst) const; + void num(std::string key, int64_t& dst) const; + void num(std::string key, uint64_t& dst) const; void num(std::string key, ubyte& dst) const; void num(std::string key, double& dst) const; JObject* obj(std::string key) const; @@ -80,6 +92,8 @@ namespace json { JObject& put(std::string key, uint value); JObject& put(std::string key, int value); + JObject& put(std::string key, int64_t value); + JObject& put(std::string key, uint64_t value); JObject& put(std::string key, float value); JObject& put(std::string key, double value); JObject& put(std::string key, const char* value); @@ -87,7 +101,9 @@ namespace json { JObject& put(std::string key, JObject* value); JObject& put(std::string key, JArray* value); JObject& put(std::string key, bool value); + JArray& putArray(std::string key); + JObject& putObj(std::string key); bool has(std::string key); }; diff --git a/src/coders/toml.cpp b/src/coders/toml.cpp index fb6bf773..3f5ee332 100644 --- a/src/coders/toml.cpp +++ b/src/coders/toml.cpp @@ -208,16 +208,24 @@ void Reader::readSection(Section* section /*nullable*/) { expect('='); c = peek(); if (is_digit(c)) { - double number = parseNumber(1); - if (section) { - section->set(name, number); + number_u num; + if (parseNumber(1, num)) { + if (section) + section->set(name, (double)num.ival); + } else { + if (section) + section->set(name, num.fval); } } else if (c == '-' || c == '+') { int sign = c == '-' ? -1 : 1; pos++; - double number = parseNumber(sign); - if (section) { - section->set(name, number); + number_u num; + if (parseNumber(sign, num)) { + if (section) + section->set(name, (double)num.ival); + } else { + if (section) + section->set(name, num.fval); } } else if (is_identifier_start(c)) { string identifier = parseName();