ยง NaN punning: Storing integers in doubles in JavaScript

This is a technique that allows us to store data inside a double by punning the value of a NaN. This is used inside javascript engines to represent all possible user types as a single NaN. This is well explained at the SpiderMonkey internals page
#include <assert.h>
#include <iostream>
#include <limits>
using namespace std;
// https://en.wikipedia.org/wiki/NaN
union PunDouble { 
    double d;
    struct { 
        uint64_t m      : 51;
        uint32_t qnan: 1;
        uint32_t e      : 11;
        uint32_t s      : 1;
    } bits;
    PunDouble(double d) : d(d) {};
    PunDouble(uint32_t s, uint32_t e, uint64_t m) {
        bits.s = s;
        bits.e = e;
        bits.qnan = 1;
        bits.m = m;
    }
};

union PunInt {
    int32_t i;
    uint32_t bits;
    PunInt(int32_t i): i(i) {};
};

using namespace std;
struct Box {

    inline bool is_int() const { 
        auto pd = PunDouble(d);
        return pd.bits.e == 0b11111111111 && pd.bits.qnan == 1;
    }
    inline bool isdouble() const {
        auto pd = PunDouble(d);
        return (pd.bits.e != 0b11111111111) || (pd.bits.qnan == 0); 
    }
    int32_t get_int() const { 
        assert(is_int());
        uint64_t m = PunDouble(d).bits.m; return PunInt(m).i;
    }
    double get_double() const { assert(isdouble()); return d; }
    Box operator +(const Box &other) const;

    static Box mk_int(int32_t i) { 
        return Box(PunDouble(1, 0b11111111111, PunInt(i).bits).d);
    }
    static Box mk_double(double d) { return Box(d); }
    double rawdouble() const { return d; }
    private:
    double d; Box(double d) : d(d) {}
};

// = 64 bits
Box Box::operator + (const Box &other) const {
    if (isdouble()) { 
        assert(other.isdouble());
        return Box::mk_double(d + other.d);
    }
    else { 
        assert(is_int());
        assert(other.is_int());
        return Box::mk_int(get_int() + other.get_int());
    }
}

ostream &operator << (ostream &o, const Box &b) {
    if (b.isdouble()) { return o << "[" << b.get_double() << "]"; }
    else { return o << "[" << b.get_int() << "]"; }
}

int32_t randint() { return (rand() %2?1:-1) * (rand() % 100); }
                    
int32_t main() {

    // generate random integers, check that addition checks out
    srand(7);
    for(int32_t i = 0; i < 1000; ++i) {
        const int32_t i1 = randint(), i2 = randint();
        const Box b1 = Box::mk_int(i1), b2 = Box::mk_int(i2);
        cout << "i1:" << i1 << "  b1:" << b1 << "  b1.double:" << b1.rawdouble() << "  b1.get_int:" << b1.get_int() << "\n";
        cout << "i2:" << i2 << "  b2:" << b2 << "  b2.double:" << b2.rawdouble() << "  b2.get_int:" << b2.get_int() << "\n";
        assert(b1.is_int());
        assert(b2.is_int());
        assert(b1.get_int() == i1);
        assert(b2.get_int() == i2);
        Box b3 = b1 + b2;
        assert(b3.is_int());
        assert(b3.get_int() == i1 + i2);
    }

    for(int32_t i = 0; i < 1000; ++i) {
        const int32_t p1 = randint(), q1=randint(), p2 = randint(), q2=randint();
        const double d1 = (double)p1/(double)q1;
        const double d2 = (double)p2/(double)q2;
        const Box b1 = Box::mk_double(d1);
        const Box b2 = Box::mk_double(d2);
        cout << "d1: " << d1 << " | b1: " << b1 << "\n";
        cout << "d2 " << d2 << " | b2: " << b2 << "\n";
        assert(b1.isdouble());
        assert(b2.isdouble());

        assert(b1.get_double() == d1);
        assert(b2.get_double() == d2);;
        Box b3 = b1 + b2;
        assert(b3.isdouble());
        assert(b3.get_double() == d1 + d2);
    }
    return 0;
}