Hash.h

// Hash.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2019

#pragma once
#ifndef Ceda_cxUtils_Hash_H
#define Ceda_cxUtils_Hash_H

#include "cxUtils.h"
#include "BasicTypes.h"
#include "HPTime.h"
#include "xdeque.h"
#include "xvector.h"
#include <functional>
#include <deque>
#include <list>
#include <vector>
#include <map>
#include <set>
#include <string>

namespace ceda
{
typedef uint64 hash_t;

class HashArchive
{
public:
    // Allow implicit conversions to/from a uint64
    HashArchive(hash_t v) : hash_(v) {}
    operator hash_t() const { return hash_; }
    
private:
    hash_t hash_;
};

template<typename It>
inline HashArchive HashRange(HashArchive ar, It begin, It end)
{
    while(begin != end)
    {
        ar = ar << *begin;
        ++begin;
    }
    return ar;
}

inline hash_t HashValue(bool v) { return (hash_t)v; }
inline hash_t HashValue(char v) { return (hash_t)v; }
inline hash_t HashValue(signed char v) { return (hash_t)v; }
inline hash_t HashValue(unsigned char v) { return (hash_t)v; }
//inline hash_t HashValue(char8_t v) { return (hash_t)v; }
inline hash_t HashValue(char16_t v) { return (hash_t)v; }
inline hash_t HashValue(char32_t v) { return (hash_t)v; }
inline hash_t HashValue(wchar_t v) { return (hash_t)v; }
inline hash_t HashValue(short v) { return (hash_t)v; }
inline hash_t HashValue(unsigned short v) { return (hash_t)v; }
inline hash_t HashValue(int v) { return (hash_t)v; }
inline hash_t HashValue(unsigned int v) { return (hash_t)v; }
inline hash_t HashValue(long v) { return (hash_t)v; }
inline hash_t HashValue(unsigned long v) { return (hash_t)v; }
inline hash_t HashValue(long long v) { return (hash_t)v; }
inline hash_t HashValue(unsigned long long v) { return (hash_t)v; }
inline hash_t HashValue(float v) { return *reinterpret_cast<const uint32*>(&v); }
inline hash_t HashValue(double v) { return *reinterpret_cast<const uint64*>(&v); }
inline hash_t HashValue(long double v) { return *reinterpret_cast<const uint64*>(&v); }

/*
template <typename T> 
hash_t HashCombine(hash_t seed, const T& v)
{ 
    std::hash<T> hasher;
    return seed ^ (hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
}
*/
template <typename T> 
hash_t HashCombine(hash_t seed, const T& v)
{ 
    return seed ^ (HashValue(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
}

inline HashArchive operator<<(HashArchive ar, bool f) { return HashCombine(ar,f); }
inline HashArchive operator<<(HashArchive ar, int8 f) { return HashCombine(ar,f); }
inline HashArchive operator<<(HashArchive ar, uint8 f) { return HashCombine(ar,f); }
inline HashArchive operator<<(HashArchive ar, int16 f) { return HashCombine(ar,f); }
inline HashArchive operator<<(HashArchive ar, uint16 f) { return HashCombine(ar,f); }
inline HashArchive operator<<(HashArchive ar, int32 f) { return HashCombine(ar,f); }
inline HashArchive operator<<(HashArchive ar, uint32 f) { return HashCombine(ar,f); }
inline HashArchive operator<<(HashArchive ar, int64 f) { return HashCombine(ar,f); }
inline HashArchive operator<<(HashArchive ar, uint64 f) { return HashCombine(ar,f); }
inline HashArchive operator<<(HashArchive ar, float32 f) { return HashCombine(ar,f); }
inline HashArchive operator<<(HashArchive ar, float64 f) { return HashCombine(ar,f); }
inline HashArchive operator<<(HashArchive ar, char f) { return HashCombine(ar,f); }

template <typename T,typename A> 
HashArchive operator<<(HashArchive ar, const std::vector<T,A>& x)
{
    return HashRange(ar, x.begin(), x.end());
}

HashArchive operator<<(HashArchive ar, const std::string& x)
{
    return HashRange(ar, x.begin(), x.end());
}

template <typename T,typename A> 
HashArchive operator<<(HashArchive ar, const std::deque<T,A>& x)
{
    return HashRange(ar, x.begin(), x.end());
}

template <typename T,typename A> 
HashArchive operator<<(HashArchive ar, const std::list<T,A>& x)
{
    return HashRange(ar, x.begin(), x.end());
}

HashArchive operator<<(HashArchive ar, const HPTime& x)
{
    return ar << x.m_ticks;    
}

template <typename U, typename V> 
HashArchive operator<<(HashArchive ar, const std::pair<U,V>& x)
{
    return ar << x.first << x.second;
}

template <typename K,typename T,typename P,typename A> 
HashArchive operator<<(HashArchive ar, const std::map<K,T,P,A>& x)
{
    return HashRange(ar, x.begin(), x.end());
}

template <typename K,typename P,typename A> 
HashArchive operator<<(HashArchive ar, const std::set<K,P,A>& x)
{
    return HashRange(ar, x.begin(), x.end());
}

template <typename T,ssize_t pageSize> 
HashArchive operator<<(HashArchive ar, const xdeque<T,pageSize>& x)
{
    return HashRange(ar, x.begin(), x.end());
}

template <typename T> 
HashArchive operator<<(HashArchive ar, const xvector<T>& x)
{
    return HashRange(ar, x.begin(), x.end());
}

} // namespace ceda

#endif // include guard