Private
Public Access
189 lines
7.2 KiB
C++
189 lines
7.2 KiB
C++
#include "src/lib/types.cpp"
|
|
#include "src/lib/dvalue.cpp"
|
|
#include "src/lib/functionlib.cpp"
|
|
#include "src/lib/fastcgi_request_spec.h"
|
|
#include <cassert>
|
|
#include <cstddef>
|
|
#include <iostream>
|
|
|
|
struct DValueBeforeNumeric {
|
|
char type = 'S';
|
|
String _String;
|
|
f64 _float = 0;
|
|
s64 _array_index = 0;
|
|
bool _bool = false;
|
|
bool _list_mode = false;
|
|
void* _ptr = 0;
|
|
u32 refs = 1;
|
|
std::map<String, DValue*> _map;
|
|
};
|
|
|
|
static_assert(sizeof(DValue) == offsetof(DValueBeforeNumeric, _map) + sizeof(DValueEntries));
|
|
static_assert(alignof(DValue) == alignof(DValueBeforeNumeric));
|
|
static_assert(offsetof(DValue, _float) == offsetof(DValueBeforeNumeric, _float));
|
|
static_assert(offsetof(DValue, _map) == offsetof(DValueBeforeNumeric, _map));
|
|
|
|
static void same_numeric(const DValue& source, const DValue& value)
|
|
{
|
|
assert(value.type == source.type && value.numeric_equal(source));
|
|
assert(value.to_string() == source.to_string());
|
|
assert(value.to_stringmap()["value"] == source.to_string());
|
|
assert(json_encode(value) == source.to_string());
|
|
}
|
|
|
|
static void copies_and_codecs(const DValue& source)
|
|
{
|
|
DValue copied(source);
|
|
same_numeric(source, copied);
|
|
DValue moved(std::move(copied));
|
|
same_numeric(source, moved);
|
|
DValue assigned;
|
|
assigned.set(source);
|
|
same_numeric(source, assigned);
|
|
assigned.set(std::move(moved));
|
|
same_numeric(source, assigned);
|
|
assigned.set("replace type");
|
|
assigned.assign_shared(source);
|
|
same_numeric(source, assigned);
|
|
DValue tree;
|
|
DValue* shared = new DValue(source);
|
|
tree.put_node("shared", shared);
|
|
DValue::unref(shared);
|
|
DValue shared_copy;
|
|
shared_copy.assign_shared(tree);
|
|
assert(shared_copy.key("shared") == tree.key("shared"));
|
|
same_numeric(source, shared_copy["shared"]);
|
|
tree["number"] = source;
|
|
tree["text"] = source.to_string();
|
|
tree["list"].set_array();
|
|
tree["list"].push(source);
|
|
DValue clone(tree);
|
|
same_numeric(source, clone["number"]);
|
|
same_numeric(source, clone["list"][0]);
|
|
assert(clone["text"].type == 'S');
|
|
for(bool local : {false, true})
|
|
{
|
|
String wire = local ? brb_encode_local(tree) : brb_encode(tree);
|
|
DValue decoded;
|
|
String error;
|
|
assert(local ? brb_decode_local(wire, decoded, &error) : brb_decode(wire, decoded, &error));
|
|
same_numeric(source, decoded["number"]);
|
|
same_numeric(source, decoded["list"][0]);
|
|
assert(decoded["text"].type == 'S');
|
|
assert(!decoded.is_list() && decoded["list"].is_list());
|
|
}
|
|
assert(yaml_encode(source) == source.to_string() + "\n");
|
|
assert(xml_encode(source, "number") == "<number>" + source.to_string() + "</number>");
|
|
}
|
|
|
|
int main()
|
|
{
|
|
std::cout << "DValue baseline=" << sizeof(DValueBeforeNumeric) << " numeric=" << sizeof(DValue)
|
|
<< " align=" << alignof(DValue) << " payload_offset=" << offsetof(DValue, _float)
|
|
<< " map_offset=" << offsetof(DValue, _map) << "\n";
|
|
for(s64 value : {std::numeric_limits<s64>::min(), (s64)-9007199254740993LL, (s64)-1, (s64)0, (s64)1,
|
|
(s64)9007199254740991LL, (s64)9007199254740992LL, (s64)9007199254740993LL, std::numeric_limits<s64>::max()})
|
|
{
|
|
DValue number;
|
|
number.set_s64(value);
|
|
assert(number.get_type_name() == "s64" && number.to_s64() == value);
|
|
assert(DValue(" " + std::to_string(value) + " ").to_s64(7) == value);
|
|
assert(number.to_u64() == (value < 0 ? 0 : (u64)value));
|
|
assert(number.to_bool() == (value != 0));
|
|
copies_and_codecs(number);
|
|
DValue floating;
|
|
floating.set((f64)value);
|
|
bool exact = value != std::numeric_limits<s64>::max() && (s64)(f64)value == value;
|
|
assert(number.numeric_equal(floating) == exact);
|
|
assert(floating.numeric_equal(number) == exact);
|
|
}
|
|
for(u64 value : {0ULL, 1ULL, 9007199254740991ULL, 9007199254740992ULL, 9007199254740993ULL,
|
|
9223372036854775807ULL, 9223372036854775808ULL, 18446744073709551615ULL})
|
|
{
|
|
DValue number;
|
|
number.set_u64(value);
|
|
assert(number.get_type_name() == "u64" && number.to_u64() == value);
|
|
assert(DValue("+" + std::to_string(value)).to_u64(7) == value);
|
|
assert(number.to_s64() == (value > (u64)std::numeric_limits<s64>::max() ? std::numeric_limits<s64>::max() : (s64)value));
|
|
assert(number.to_bool() == (value != 0));
|
|
copies_and_codecs(number);
|
|
DValue floating;
|
|
floating.set((f64)value);
|
|
bool exact = value != std::numeric_limits<u64>::max() && (u64)(f64)value == value;
|
|
assert(number.numeric_equal(floating) == exact);
|
|
assert(floating.numeric_equal(number) == exact);
|
|
}
|
|
for(f64 value : {0.12345678901234567, 1.0000000000000002, 1e-200, 1e200})
|
|
{
|
|
DValue number;
|
|
number.set(value);
|
|
String text = number.to_string();
|
|
assert(strtod(text.c_str(), nullptr) == value);
|
|
assert(number.to_stringmap()["value"] == text);
|
|
DValue record;
|
|
record["number"].set(value);
|
|
assert(record.to_stringmap()["number"] == text);
|
|
}
|
|
assert(DValue("1.9").to_s64() == 1 && DValue("1e3").to_u64() == 1000);
|
|
assert(DValue("invalid").to_s64(7) == 7 && DValue("-1").to_u64(7) == 0);
|
|
DValue native(std::numeric_limits<u64>::max());
|
|
assert(native.type == 'U' && native.to_u64() == std::numeric_limits<u64>::max());
|
|
native = std::numeric_limits<s64>::min();
|
|
assert(native.type == 'I' && native.to_s64() == std::numeric_limits<s64>::min());
|
|
native.set(true);
|
|
assert(native.type == 'B' && native.to_bool());
|
|
assert(native.to_string() == "true" && native.to_stringmap()["value"] == "true");
|
|
native = false;
|
|
assert(native.type == 'B' && !native.to_bool());
|
|
assert(native.to_string() == "false" && native.to_stringmap()["value"] == "false");
|
|
DValue metadata;
|
|
metadata["insert_id"] = std::numeric_limits<u64>::max();
|
|
assert(json_encode(metadata) == "{\"insert_id\": 18446744073709551615}");
|
|
DValue left, right;
|
|
left.set_type('I');
|
|
right.set_type('U');
|
|
assert(left.to_s64() == 0 && right.to_u64() == 0 && left.numeric_equal(right));
|
|
right.set(-0.0);
|
|
assert(left.numeric_equal(right) && right.numeric_equal(left));
|
|
left.set_s64(-1);
|
|
right.set_u64(std::numeric_limits<u64>::max());
|
|
assert(!left.numeric_equal(right) && !right.numeric_equal(left));
|
|
left.set_s64(9007199254740993LL);
|
|
right.set_u64(9007199254740993ULL);
|
|
assert(left.numeric_equal(right) && right.numeric_equal(left));
|
|
right.set_u64(9007199254740992ULL);
|
|
assert(!left.numeric_equal(right));
|
|
for(f64 number : {0.5, std::numeric_limits<f64>::infinity(), -std::numeric_limits<f64>::infinity(), std::numeric_limits<f64>::quiet_NaN()})
|
|
{
|
|
right.set(number);
|
|
assert(!left.numeric_equal(right) && !right.numeric_equal(left));
|
|
}
|
|
right.set("9007199254740993");
|
|
assert(!left.numeric_equal(right));
|
|
for(char tag : {'I', 'U'})
|
|
{
|
|
for(const String text : std::initializer_list<String>{"", "+1", "1.5", "1e2", " 1", "1 ", "18446744073709551616", "-9223372036854775809", String("1\0", 2)})
|
|
{
|
|
String wire("BRRB\2\0", 6);
|
|
wire += tag;
|
|
wire += (char)text.size();
|
|
wire += text;
|
|
wire += '\0';
|
|
DValue out;
|
|
String error;
|
|
assert(!brb_decode(wire, out, &error) && !error.empty());
|
|
}
|
|
}
|
|
DValue decoded;
|
|
String error;
|
|
assert(!brb_decode(String("BRRB\2\0U\2-1\0", 11), decoded, &error));
|
|
assert(!brb_decode(String("BRRB\2\0I\23", 8) + "9223372036854775808" + '\0', decoded, &error));
|
|
DValue options, clean, option_error;
|
|
options["port"].set_u64(9000);
|
|
options["timeout_ms"].set_s64(100);
|
|
assert(fastcgi_request_spec(options, clean, option_error));
|
|
assert(clean["port"].to_u64() == 9000 && clean["timeout_ms"].to_s64() == 100);
|
|
assert(json_decode("9007199254740993").type == 'I');
|
|
assert(json_decode("9007199254740993").to_s64() == 9007199254740993LL);
|
|
}
|