Browse Source

breaking: serialize random::Tape using uint64_t to ensure losslessness

Sam Jaffe 2 years ago
parent
commit
155efaec45
2 changed files with 22 additions and 2 deletions
  1. 2 1
      include/random/tape.h
  2. 20 1
      src/tape.cxx

+ 2 - 1
include/random/tape.h

@@ -20,13 +20,14 @@ class Tape : public Device {
 public:
   // Allow for the serialization and de-serialization of this Tape
   using serial_type =
-      std::vector<std::tuple<bool, std::string, double, double, double>>;
+      std::vector<std::tuple<bool, std::string, uint64_t, uint64_t, uint64_t>>;
 
 private:
   enum class Type : char;
   template <typename T> struct EntryT {
     EntryT(T min, T max) : min(min), max(max), result() {}
     EntryT(T min, T max, T result) : min(min), max(max), result(result) {}
+    EntryT(uint64_t min, uint64_t max, uint64_t result);
 
     T min;
     T max;

+ 20 - 1
src/tape.cxx

@@ -12,9 +12,28 @@
 
 #define IS_A(T) tname == typeid(T).name()
 
+namespace {
+uint64_t cast(double d) { return reinterpret_cast<uint64_t&>(d); }
+uint64_t cast(unsigned int j) { return j; }
+}
+
 namespace engine::random {
 enum class Tape::Type : char { Inclusive, Exclusive };
 
+template <>
+Tape::EntryT<unsigned int>::EntryT(uint64_t min, uint64_t max, uint64_t result)
+    : min(static_cast<unsigned int>(min)),
+      max(static_cast<unsigned int>(max)),
+      result(static_cast<unsigned int>(result))
+{}
+
+template <>
+Tape::EntryT<double>::EntryT(uint64_t min, uint64_t max, uint64_t result)
+    : min(reinterpret_cast<double&>(min)),
+      max(reinterpret_cast<double&>(max)),
+      result(reinterpret_cast<double&>(result))
+{}
+
 Tape::Tape(serial_type serial) {
   for (auto const & [exclusive, tname, min, max, result] : serial) {
     Type const type = exclusive ? Type::Exclusive : Type::Inclusive;
@@ -30,7 +49,7 @@ Tape::operator serial_type() const {
   serial_type rval;
   auto insert = [&rval](auto type, auto const & entry) {
     rval.emplace_back(type == Type::Exclusive, typeid(entry.min).name(),
-                      entry.min, entry.max, entry.result);
+                      cast(entry.min), cast(entry.max), cast(entry.result));
   };
   for (auto const & [type, entry] : entries_) {
     std::visit(insert, std::variant<Type>(type), entry);