Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
10.4.x.x (relative to 10.4.2.1)
========

Improvements
------------

- Added string constructor and static `fromString` function to `IECore.MurmurHash`.

Build
-----

Expand Down
4 changes: 4 additions & 0 deletions include/IECore/MurmurHash.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ class IECORE_API MurmurHash
inline MurmurHash();
inline MurmurHash( const MurmurHash &other );

// Construct directly from string representation
explicit MurmurHash( const std::string &repr );

// Construct directly from known internal values
inline MurmurHash( uint64_t h1, uint64_t h2 );

Expand All @@ -84,6 +87,7 @@ class IECORE_API MurmurHash
inline bool operator < ( const MurmurHash &other ) const;

std::string toString() const;
static MurmurHash fromString( const std::string &repr );

// Access internal storage for special cases
inline uint64_t h1() const;
Expand Down
48 changes: 46 additions & 2 deletions src/IECore/MurmurHash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,63 @@
//////////////////////////////////////////////////////////////////////////

#include "IECore/MurmurHash.h"
#include "IECore/Exception.h"

#include <boost/format.hpp>

#include <iomanip>
#include <sstream>

using namespace IECore;

std::string MurmurHash::toString() const
namespace
{

std::string internalToString( uint64_t const h1, uint64_t const h2 )
{
std::stringstream s;
s << std::hex << std::setfill( '0' ) << std::setw( 16 ) << m_h1 << std::setw( 16 ) << m_h2;
s << std::hex << std::setfill( '0' ) << std::setw( 16 ) << h1 << std::setw( 16 ) << h2;
return s.str();
}

void internalFromString( const std::string &repr, uint64_t &h1, uint64_t &h2 )
{
if( repr.length() != static_cast<std::string::size_type>( 32 ) )
{
throw Exception(
boost::str(
boost::format(
"Invalid IECore::MurmurHash string representation \"%s\", must have 32 characters" )
% repr
) );
}

std::stringstream s;
s.str( repr.substr( 0, 16 ) );
s >> std::hex >> h1;
s.clear();
s.str( repr.substr( 16, 16 ) );
s >> std::hex >> h2;
}

} // namespace

MurmurHash::MurmurHash( const std::string &repr )
: m_h1( 0 ), m_h2( 0 )
{
internalFromString( repr, m_h1, m_h2 );
}

std::string MurmurHash::toString() const
{
return internalToString( m_h1, m_h2 );
}

MurmurHash MurmurHash::fromString( const std::string &repr )
{
return MurmurHash( repr );
}

std::ostream &IECore::operator << ( std::ostream &o, const MurmurHash &hash )
{
o << hash.toString();
Expand Down
3 changes: 3 additions & 0 deletions src/IECorePython/MurmurHashBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ void IECorePython::bindMurmurHash()
class_<MurmurHash>( "MurmurHash" )
.def( init<>() )
.def( init<const MurmurHash &>() )
.def( init<const std::string &>() )
.def( init<uint64_t, uint64_t>() )
.def( "append", (MurmurHash &(MurmurHash::*)( const float & ))&MurmurHash::append, return_self<>() )
.def( "append", (MurmurHash &(MurmurHash::*)( const double & ))&MurmurHash::append, return_self<>() )
Expand Down Expand Up @@ -198,6 +199,8 @@ void IECorePython::bindMurmurHash()
.def( "__str__", &MurmurHash::toString )
.def( "__hash__", &hash )
.def( "toString", &MurmurHash::toString )
.def( "fromString", (MurmurHash (*)( const std::string & ))&MurmurHash::fromString )
.staticmethod( "fromString" )
.def( "h1", &MurmurHash::h1 )
.def( "h2", &MurmurHash::h2 )
;
Expand Down
33 changes: 33 additions & 0 deletions test/IECore/MurmurHashTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@

import unittest
import imath
import six

import IECore

Expand All @@ -45,6 +46,16 @@ def testConstructor( self ) :
self.assertEqual( str( h ), "0" * 32 )
self.assertEqual( h, IECore.MurmurHash() )

def testStringConstructor( self ) :

h = IECore.MurmurHash()
h.append( 1 )
h.append( "hello" )

s = h.toString()
hs = IECore.MurmurHash( s )
self.assertEqual( h, hs )

def testCopyConstructor( self ) :

h = IECore.MurmurHash()
Expand All @@ -54,6 +65,28 @@ def testCopyConstructor( self ) :
self.assertEqual( h, IECore.MurmurHash( h ) )
self.assertNotEqual( h, IECore.MurmurHash() )

def testRepr( self ) :

h = IECore.MurmurHash()
h.append( 42 )
h.append( "world" )
h2 = eval( repr( h ) )

self.assertEqual( h, h2 )

def testFromString( self ) :

h = IECore.MurmurHash()
h.append( 1 )
h.append( "hello" )

s = h.toString()
hs = IECore.MurmurHash.fromString( s )
self.assertEqual( h, hs )

with six.assertRaisesRegex( self, Exception, ".*must have 32 characters.*" ) :
IECore.MurmurHash.fromString( "InvalidStringRepresentation" )

def testAppend( self ) :

h = IECore.MurmurHash()
Expand Down