diff --git a/core/include/core/G3Map.h b/core/include/core/G3Map.h index 128695ec..a79c217f 100644 --- a/core/include/core/G3Map.h +++ b/core/include/core/G3Map.h @@ -27,6 +27,9 @@ class G3Map : public G3FrameObject, public std::map { cereal::base_class >(this)); } + template void load(A &ar, unsigned v); + template void save(A &ar, unsigned v) const; + std::string Summary() const { if (this->size() < 5) @@ -72,20 +75,28 @@ G3MAP_OF(std::string, double, G3MapDouble); G3MAP_OF(std::string, G3MapDouble, G3MapMapDouble); G3MAP_OF(std::string, std::vector, G3MapVectorDouble); G3MAP_OF(std::string, std::vector, G3MapVectorBool); -G3MAP_OF(std::string, std::vector, G3MapVectorInt); G3MAP_OF(std::string, std::vector, G3MapVectorString); G3MAP_OF(std::string, G3VectorVectorString, G3MapVectorVectorString); G3MAP_OF(std::string, std::vector >, G3MapVectorComplexDouble); G3MAP_OF(std::string, G3VectorTime, G3MapVectorTime); -G3MAP_OF(std::string, int32_t, G3MapInt); G3MAP_OF(std::string, std::string, G3MapString); G3MAP_OF(std::string, quat, G3MapQuat); G3MAP_OF(std::string, G3VectorQuat, G3MapVectorQuat); +#define G3MAP_SPLIT(key, value, name, version) \ +typedef G3Map< key, value > name; \ +namespace cereal { \ + template struct specialize {}; \ +} \ +G3_POINTERS(name); \ +G3_SERIALIZABLE(name, version); + +G3MAP_SPLIT(std::string, std::vector, G3MapVectorInt, 2); +G3MAP_SPLIT(std::string, int64_t, G3MapInt, 2); + namespace cereal { template struct specialize {}; } G3_POINTERS(G3MapFrameObject); G3_SERIALIZABLE(G3MapFrameObject, 1); #endif - diff --git a/core/src/G3Map.cxx b/core/src/G3Map.cxx index aeff5d26..74c8d420 100644 --- a/core/src/G3Map.cxx +++ b/core/src/G3Map.cxx @@ -4,6 +4,201 @@ #include #include +/* Special load/save for int64_t. */ + +static +int bit_count(std::map const &d) { + // Returns the smallest number N such that all ints in the + // vector could be safely expressed as intN_t. Assumes two's + // complement integers. Return value will be between 1 and + // 64. + uint64_t mask = 0; + for (auto c: d) { + if (c.second < 0) + mask |= ~c.second; + else + mask |= c.second; + } + for (int i=1; i<64; i++) { + if (mask == 0) + return i; + mask >>= 1; + } + return 64; +} + +template +void load_as(A &ar, std::map &dest) { + std::map temp; + ar & cereal::make_nvp("map", temp); + dest.insert(temp.begin(), temp.end()); +} + +template +void save_as(A &ar, const std::map &src) { + std::map temp(src.begin(), src.end()); + ar & cereal::make_nvp("map", temp); +} + +template <> +template +void G3Map::load(A &ar, const unsigned v) +{ + G3_CHECK_VERSION(v); + + ar & cereal::make_nvp("G3FrameObject", + cereal::base_class(this)); + int store_bits = 32; + if (v >= 2) + ar & cereal::make_nvp("store_bits", store_bits); + + switch(store_bits) { + case 64: + ar & cereal::make_nvp("map", + cereal::base_class >(this)); + break; + case 32: + load_as(ar, *this); + break; + case 16: + load_as(ar, *this); + break; + case 8: + load_as(ar, *this); + break; + } +} + +template <> +template +void G3Map::save(A &ar, const unsigned v) const +{ + // v == 2 + ar & cereal::make_nvp("G3FrameObject", + cereal::base_class(this)); + // Count the interesting bits, and convert to nearest power of 2. + int sig_bits = bit_count(*this); + int store_bits = 8; + while (store_bits < sig_bits) + store_bits *= 2; + ar & cereal::make_nvp("store_bits", store_bits); + switch(store_bits) { + case 8: + save_as(ar, *this); + break; + case 16: + save_as(ar, *this); + break; + case 32: + save_as(ar, *this); + break; + default: + ar & cereal::make_nvp("map", + cereal::base_class >(this)); + } +} + +static +int bit_count_vector(std::map > const &d) { + // Returns the smallest number N such that all ints in the + // vector could be safely expressed as intN_t. Assumes two's + // complement integers. Return value will be between 1 and + // 64. + uint64_t mask = 0; + for (auto c: d) { + for (auto cc: c.second) { + if (cc < 0) + mask |= ~cc; + else + mask |= cc; + } + } + for (int i=1; i<64; i++) { + if (mask == 0) + return i; + mask >>= 1; + } + return 64; +} + +template +void load_vector_as(A &ar, std::map > &dest) { + std::map > temp; + ar & cereal::make_nvp("map", temp); + for (auto e: temp) { + std::vector v(e.second.begin(), e.second.end()); + dest[e.first] = v; + } +} + +template +void save_vector_as(A &ar, const std::map > &src) { + std::map > temp; + for (auto e: src) { + std::vector v(e.second.begin(), e.second.end()); + temp[e.first] = v; + } + ar & cereal::make_nvp("map", temp); +} + +template <> +template +void G3Map >::load(A &ar, const unsigned v) +{ + G3_CHECK_VERSION(v); + + ar & cereal::make_nvp("G3FrameObject", + cereal::base_class(this)); + int store_bits = 32; + if (v >= 2) + ar & cereal::make_nvp("store_bits", store_bits); + + switch(store_bits) { + case 64: + ar & cereal::make_nvp("map", + cereal::base_class > >(this)); + break; + case 32: + load_vector_as(ar, *this); + break; + case 16: + load_vector_as(ar, *this); + break; + case 8: + load_vector_as(ar, *this); + break; + } +} + +template <> +template +void G3Map >::save(A &ar, const unsigned v) const +{ + // v == 2 + ar & cereal::make_nvp("G3FrameObject", + cereal::base_class(this)); + // Count the interesting bits, and convert to nearest power of 2. + int sig_bits = bit_count_vector(*this); + int store_bits = 8; + while (store_bits < sig_bits) + store_bits *= 2; + ar & cereal::make_nvp("store_bits", store_bits); + switch(store_bits) { + case 8: + save_vector_as(ar, *this); + break; + case 16: + save_vector_as(ar, *this); + break; + case 32: + save_vector_as(ar, *this); + break; + default: + ar & cereal::make_nvp("map", + cereal::base_class > >(this)); + } +} + template void G3MapFrameObject::save(A &ar, const unsigned v) const { ar << cereal::make_nvp("G3FrameObject", @@ -70,13 +265,11 @@ std::string G3MapFrameObject::Description() const return s.str(); } -G3_SERIALIZABLE_CODE(G3MapInt); G3_SERIALIZABLE_CODE(G3MapDouble); G3_SERIALIZABLE_CODE(G3MapMapDouble); G3_SERIALIZABLE_CODE(G3MapString); G3_SERIALIZABLE_CODE(G3MapQuat); G3_SERIALIZABLE_CODE(G3MapVectorBool); -G3_SERIALIZABLE_CODE(G3MapVectorInt); G3_SERIALIZABLE_CODE(G3MapVectorDouble); G3_SERIALIZABLE_CODE(G3MapVectorString); G3_SERIALIZABLE_CODE(G3MapVectorVectorString); @@ -84,6 +277,9 @@ G3_SERIALIZABLE_CODE(G3MapVectorComplexDouble); G3_SERIALIZABLE_CODE(G3MapVectorTime); G3_SERIALIZABLE_CODE(G3MapVectorQuat); +G3_SPLIT_SERIALIZABLE_CODE(G3MapInt); +G3_SPLIT_SERIALIZABLE_CODE(G3MapVectorInt); + G3_SPLIT_SERIALIZABLE_CODE(G3MapFrameObject); PYBINDINGS("core") {