Program Listing for File hash-id.h

Return to documentation for file (aslam_cv2/aslam_cv_common/include/aslam/common/hash-id.h)

#ifndef ASLAM_HASH_ID_H_
#define ASLAM_HASH_ID_H_

#include <chrono>
#include <cstring>
#include <functional>
#include <iomanip>
#include <iostream>
#include <random>
#include <mutex>

namespace aslam {

constexpr bool kIs64BitArch = (sizeof(void*) == 8);

struct HashPrimeAndBase {
  static constexpr std::size_t kPrime =
      kIs64BitArch ? 1099511628211ull : 16777619u;
  static constexpr std::size_t kOffsetBasis =
      kIs64BitArch ? 14695981039346656037ull : 2166136261u;
};

class HashId {
 public:
  inline HashId() {
    setInvalid();
  }
  inline HashId(const HashId& other){
    *this = other;
  }
  inline HashId(const uint64_t source[2]) {
    fromUint64(source);
  }

  inline void fromUint64(const uint64_t source[2]) {
    memcpy(reinterpret_cast<void*>(&val_.u64),
           reinterpret_cast<const void*>(source), sizeof(val_.u64));
  }

  inline void toUint64(uint64_t destination[2]) const {
    memcpy(reinterpret_cast<void*>(destination),
           reinterpret_cast<const void*>(&val_.u64), sizeof(val_.u64));
  }

  inline static HashId random() {
    HashId generated;
    generated.randomize();
    return generated;
  }

  inline const std::string hexString() const {
    char buffer[2*sizeof(val_) + 1]; // 1 for the \0 character
    buffer[2*sizeof(val_)] = '\0';
    for (size_t i = 0; i < sizeof(val_); ++i){
      buffer[2 * i + 1] = kHexConversion[val_.c[i] & 0xf];
      buffer[2 * i] = kHexConversion[val_.c[i] >> 4];
    }
    return std::string(buffer);
  }

  inline const std::string shortHex() const {
    return hexString().substr(0u, 4u);
  }

  inline bool fromHexString(const std::string& hexString) {
    // hexadecimal string takes 2 characters per byte
    if (hexString.size() != 2*sizeof(val_)){
      return false;
    }
    for (size_t i = 0; i < sizeof(val_); ++i){
      val_.c[i] = static_cast<unsigned char>(
          stoul(std::string(hexString, 2*i, 2), 0, 16));
    }
    return true;
  }

  inline size_t hashToSizeT() const {
    size_t hash = HashPrimeAndBase::kOffsetBasis;
    hash ^= val_.u64[0];
    hash *= HashPrimeAndBase::kPrime;
    hash ^= val_.u64[1];
    hash *= HashPrimeAndBase::kPrime;
    return hash;
  }
  inline size_t hashToSizeTFast() const {
    size_t hash = HashPrimeAndBase::kOffsetBasis;
    hash ^= val_.u64[0];
    hash ^= val_.u64[1];
    return hash;
  }

  inline void randomize(){
    static std::mt19937_64 rng(time64());
    static std::mutex m_rng;
    {
      std::unique_lock<std::mutex> lock(m_rng);
      val_.u64[0] = rng();
      val_.u64[1] = rng();
    }
  }

  inline void operator =(const HashId& other) {
    memcpy(&val_, &other.val_, sizeof(val_));
  }

  inline bool operator <(const HashId& other) const {
    if (val_.u64[0] == other.val_.u64[0]){
      return val_.u64[1] < other.val_.u64[1];
    }
    return val_.u64[0] < other.val_.u64[0];
  }
  inline bool operator >(const HashId& other) const {
    if (val_.u64[0] == other.val_.u64[0]){
      return val_.u64[1] > other.val_.u64[1];
    }
    return val_.u64[0] > other.val_.u64[0];
  }
  inline bool operator ==(const HashId& other) const {
    return val_.u64[0] == other.val_.u64[0] && val_.u64[1] == other.val_.u64[1];
  }
  inline bool operator !=(const HashId& other) const{
    return !(*this == other);
  }

  inline void setInvalid() {
    memset(&val_, 0, sizeof(val_));
  }
  inline bool isValid() const {
    return val_.u64[0] != 0 || val_.u64[1] != 0;
  }

 private:
  inline static int64_t time64() {
    std::chrono::high_resolution_clock::duration current =
        std::chrono::high_resolution_clock::now().time_since_epoch();
    using std::chrono::duration_cast;
    using std::chrono::nanoseconds;
    // count() specified to return at least 64 bits
    return duration_cast<nanoseconds>(current).count();
  }

  union HashVal {
    unsigned char c[16];
    uint64_t u64[2];
  };
  HashVal val_;

  static const char kHexConversion[];
};

} // namespace aslam

namespace std {

inline ostream& operator<<(ostream& out, const aslam::HashId& hash) {
  out << hash.hexString();
  return out;
}

template<>
struct hash<aslam::HashId>{
  typedef aslam::HashId argument_type;
  typedef std::size_t value_type;

  value_type operator()(const argument_type& hash_id) const {
    return hash_id.hashToSizeT();
  }
};
} // namespace std


#define ASLAM_DEFINE_HASHID_HASH(FullyQualifiedIdTypeName)              \
  namespace std {                                                       \
  template<>                                                            \
  struct hash<FullyQualifiedIdTypeName>{                                \
      typedef FullyQualifiedIdTypeName argument_type;                     \
      typedef std::size_t value_type;                                     \
      value_type operator()(const argument_type& hash_id) const {         \
        return hash_id.hashToSizeT();                                     \
      }                                                                   \
    };                                                                    \
}  /* namespace std */                                                \
    extern void DefineIDHash ## __FILE__ ## __LINE__(void)

#endif // ASLAM_HASH_ID_H_