1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <glaze/glaze.hpp>
#include <iostream>
#include <thread>
#include <vector>
// must be outside test(), compilation fails on gcc 13 otherwise
template <typename T>
struct Value
{
T value{};
};
template <typename T>
void test()
{
using S = Value<T>;
using UT = std::make_unsigned_t<T>;
auto testone = [](const UT loopvar, auto& outbuf, auto& outbuf_size) {
S s;
std::memcpy(&s.value, &loopvar, sizeof(T));
// Test normal mode (to_chars_40kb - 40KB tables)
outbuf.clear();
const auto writeec = glz::write_json(s, outbuf);
if (writeec) [[unlikely]] {
std::cerr << "failed writing " << s.value << " to json (normal mode)\n";
std::abort();
}
auto restored = glz::read_json<S>(outbuf);
if (!restored) [[unlikely]] {
std::cerr << "failed parsing " << outbuf << " (normal mode)\n";
std::abort();
}
if (const auto r = restored.value().value; r != s.value) [[unlikely]] {
std::cerr << "failed roundtrip (normal mode), got " << r << " instead of " << s.value << //
" (diff is " << r - s.value << ") when parsing " << outbuf << '\n';
std::abort();
}
// Test size mode (to_chars - 400B tables)
outbuf_size.clear();
const auto writeec_size = glz::write<glz::opts_size{}>(s, outbuf_size);
if (writeec_size) [[unlikely]] {
std::cerr << "failed writing " << s.value << " to json (size mode)\n";
std::abort();
}
S restored_size{};
const auto readec_size = glz::read<glz::opts_size{}>(restored_size, outbuf_size);
if (readec_size) [[unlikely]] {
std::cerr << "failed parsing " << outbuf_size << " (size mode)\n";
std::abort();
}
if (const auto r = restored_size.value; r != s.value) [[unlikely]] {
std::cerr << "failed roundtrip (size mode), got " << r << " instead of " << s.value << //
" (diff is " << r - s.value << ") when parsing " << outbuf_size << '\n';
std::abort();
}
// Verify both modes produce identical output
if (outbuf != outbuf_size) [[unlikely]] {
std::cerr << "normal and size mode produced different output for " << s.value << //
": normal=" << outbuf << ", size=" << outbuf_size << '\n';
std::abort();
}
};
auto testrange = [&](const UT start, const UT stop) {
std::string outbuf;
std::string outbuf_size;
for (UT i = start; i < stop; ++i) {
testone(i, outbuf, outbuf_size);
}
};
const auto nthreads = std::thread::hardware_concurrency();
const UT step = (std::numeric_limits<UT>::max)() / nthreads;
// can't use jthread, does not exist in all stdlibs.
std::vector<std::thread> threads;
threads.reserve(nthreads);
for (size_t threadi = 0; threadi < nthreads; ++threadi) {
const UT start = threadi * step;
const UT stop = (threadi == nthreads - 1) ? (std::numeric_limits<UT>::max)() : start + step;
// std::cout << "thread i=" << threadi << " goes from " << start << " to " << stop << '\n';
threads.emplace_back(testrange, start, stop);
}
// test the last value here.
{
std::string buf;
std::string buf_size;
testone((std::numeric_limits<UT>::max)(), buf, buf_size);
}
std::cout << "started testing in " << nthreads << " threads." << std::endl;
for (auto& t : threads) {
t.join();
}
std::cout << "tested " << (std::numeric_limits<UT>::max)() << " values of " << (std::is_unsigned_v<T> ? "un" : "")
<< "signed type of size " << sizeof(T) << std::endl;
}
void testonetype(int bits)
{
switch (bits) {
case 16:
test<std::int16_t>();
test<std::uint16_t>();
break;
case 32:
test<std::int32_t>();
test<std::uint32_t>();
break;
}
}
int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[])
{
testonetype(16);
testonetype(32);
}
|