#ifndef EMPATHY_UTIL_STRINGID_H
#define EMPATHY_UTIL_STRINGID_H
namespace empathy::util
{
class StringId
{
public:
StringId() {}
explicit constexpr StringId( const char* pString ) :
m_uniqueId( CalcCRC( pString ) ),
m_pString( pString )
{}
explicit constexpr StringId( const char* pString, size_t size ) :
m_uniqueId( CalcCRC( pString ) ),
m_pString( pString )
{}
explicit StringId( const string& str );
explicit StringId( string&& str );
explicit StringId( uint32_t uniqueId ) :
m_uniqueId( CalcCRC( uniqueId ) ),
m_pString( ms_pAnonId )
{}
constexpr auto uniqueId() const { return m_uniqueId; }
bool isAnonymous() const { return m_pString == ms_pAnonId; }
constexpr auto operator==( const StringId& rhs ) const
{
return m_uniqueId == rhs.m_uniqueId;
}
constexpr auto operator!=( const StringId& rhs ) const
{
return m_uniqueId != rhs.m_uniqueId;
}
constexpr auto operator<( const StringId& rhs ) const
{
return m_uniqueId < rhs.m_uniqueId;
}
constexpr auto operator>=( const StringId& rhs ) const
{
return m_uniqueId >= rhs.m_uniqueId;
}
constexpr auto operator<=( const StringId& rhs ) const
{
return m_uniqueId <= rhs.m_uniqueId;
}
constexpr auto operator>( const StringId& rhs ) const
{
return m_uniqueId > rhs.m_uniqueId;
}
const char* c_str() const { return m_pString; }
friend ostream& operator<<( ostream& out, const StringId& sid )
{
return out << sid.c_str();
}
private:
constexpr static uint32_t CalcCRC( const char* pString )
{
uint32_t crc = numeric_limits< uint32_t >::max();
while( char c = *pString++ )
crc = ComputeCRC32( c, crc );
return ~crc;
}
constexpr static uint32_t CalcCRC( uint32_t val )
{
uint32_t crc = numeric_limits< uint32_t >::max();
// To reduce the risk of collisions between string ids
// and integer ids, instead of using the value directly,
// compute its crc byte by byte.
// Inject a byte set to 1 first: otherwise,
// we could run pretty fast into a value that would be
// equivalent to a one character string identifier and
// have a collision before even computing the crc.
crc = ComputeCRC32( 1, crc );
crc = ComputeCRC32( val & 0xff, crc );
val = val >> 8;
crc = ComputeCRC32( val & 0xff, crc );
val = val >> 8;
crc = ComputeCRC32( val & 0xff, crc );
val = val >> 8;
crc = ComputeCRC32( val & 0xff, crc );
return ~crc;
}
uint32_t m_uniqueId = ~0;
const char* m_pString = nullptr;
static const char* ms_pAnonId;
static unordered_set< string > ms_DynStrings;
};
}
namespace std
{
template<> struct hash< empathy::util::StringId >
{
size_t operator()( const empathy::util::StringId& x ) const
{
return hash< uint32_t >()( x.uniqueId() );
}
};
}
constexpr auto operator "" _sid(const char* pString, std::size_t s )
{
return empathy::util::StringId( pString, s );
}
#endif