File: json_exhaustive_roundtrip_int.cpp

package info (click to toggle)
glaze 7.0.2-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 9,036 kB
  • sloc: cpp: 142,035; sh: 109; ansic: 26; makefile: 12
file content (131 lines) | stat: -rw-r--r-- 4,058 bytes parent folder | download | duplicates (3)
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);
}