Use MurmurHash3_x64_128 (MMH3_HASH) for polygon checksum.
Improves performance when moving footprints. See https://gitlab.com/kicad/code/kicad/-/issues/18148
This commit is contained in:
parent
8f02944437
commit
cb41b53ab7
|
@ -47,7 +47,7 @@
|
||||||
#include <geometry/shape_line_chain.h>
|
#include <geometry/shape_line_chain.h>
|
||||||
#include <math/box2.h> // for BOX2I
|
#include <math/box2.h> // for BOX2I
|
||||||
#include <math/vector2d.h> // for VECTOR2I
|
#include <math/vector2d.h> // for VECTOR2I
|
||||||
#include <md5_hash.h>
|
#include <hash_128.h>
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -552,7 +552,7 @@ public:
|
||||||
}
|
}
|
||||||
bool IsTriangulationUpToDate() const;
|
bool IsTriangulationUpToDate() const;
|
||||||
|
|
||||||
MD5_HASH GetHash() const;
|
HASH_128 GetHash() const;
|
||||||
|
|
||||||
virtual bool HasIndexableSubshapes() const override;
|
virtual bool HasIndexableSubshapes() const override;
|
||||||
|
|
||||||
|
@ -1568,7 +1568,7 @@ private:
|
||||||
/// Return true if the polygon set has any holes that touch share a vertex.
|
/// Return true if the polygon set has any holes that touch share a vertex.
|
||||||
bool hasTouchingHoles( const POLYGON& aPoly ) const;
|
bool hasTouchingHoles( const POLYGON& aPoly ) const;
|
||||||
|
|
||||||
MD5_HASH checksum() const;
|
HASH_128 checksum() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::vector<POLYGON> m_polys;
|
std::vector<POLYGON> m_polys;
|
||||||
|
@ -1578,7 +1578,8 @@ protected:
|
||||||
std::mutex m_triangulationMutex;
|
std::mutex m_triangulationMutex;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MD5_HASH m_hash;
|
HASH_128 m_hash;
|
||||||
|
bool m_hashValid = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __SHAPE_POLY_SET_H
|
#endif // __SHAPE_POLY_SET_H
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 Alex Shvartzkop <dudesuchamazing@gmail.com>
|
||||||
|
* Copyright (C) 2024 Kicad Developers, see AUTHORS.txt for contributors.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HASH_128_H_
|
||||||
|
#define HASH_128_H_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A storage class for 128-bit hash value
|
||||||
|
*/
|
||||||
|
struct HASH_128
|
||||||
|
{
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
memset( Value64, 0, sizeof( Value64 ) ); //
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==( const HASH_128& aOther ) const
|
||||||
|
{
|
||||||
|
return memcmp( Value64, aOther.Value64, sizeof( Value64 ) ) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint8_t Value8[16]{}; // Zero-initialized
|
||||||
|
uint32_t Value32[4];
|
||||||
|
uint64_t Value64[2];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // HASH_128_H_
|
|
@ -0,0 +1,196 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 Alex Shvartzkop <dudesuchamazing@gmail.com>
|
||||||
|
* Copyright (C) 2024 Kicad Developers, see AUTHORS.txt for contributors.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Based on https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// MurmurHash3 was written by Austin Appleby, and is placed in the public
|
||||||
|
// domain. The author hereby disclaims copyright to this source code.
|
||||||
|
|
||||||
|
#ifndef MMH3_HASH_H_
|
||||||
|
#define MMH3_HASH_H_
|
||||||
|
|
||||||
|
#include <hash_128.h>
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Platform-specific functions and macros
|
||||||
|
|
||||||
|
// Microsoft Visual Studio
|
||||||
|
#if defined( _MSC_VER )
|
||||||
|
#define FORCE_INLINE __forceinline
|
||||||
|
#include <stdlib.h>
|
||||||
|
#define ROTL64( x, y ) _rotl64( x, y )
|
||||||
|
#define BIG_CONSTANT( x ) ( x )
|
||||||
|
// Other compilers
|
||||||
|
#else // defined(_MSC_VER)
|
||||||
|
#define FORCE_INLINE inline __attribute__( ( always_inline ) )
|
||||||
|
inline uint64_t rotl64( uint64_t x, int8_t r )
|
||||||
|
{
|
||||||
|
return ( x << r ) | ( x >> ( 64 - r ) );
|
||||||
|
}
|
||||||
|
#define ROTL64( x, y ) rotl64( x, y )
|
||||||
|
#define BIG_CONSTANT( x ) ( x##LLU )
|
||||||
|
#endif // !defined(_MSC_VER)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A streaming C++ equivalent for MurmurHash3_x64_128.
|
||||||
|
*/
|
||||||
|
class MMH3_HASH
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MMH3_HASH( uint32_t aSeed = 0 ) { reset( aSeed ); }
|
||||||
|
|
||||||
|
FORCE_INLINE void reset( uint32_t aSeed = 0 )
|
||||||
|
{
|
||||||
|
h1 = aSeed;
|
||||||
|
h2 = aSeed;
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE void add( int32_t input )
|
||||||
|
{
|
||||||
|
blocks[( len % 16 ) / 4] = input;
|
||||||
|
len += 4;
|
||||||
|
|
||||||
|
if( len % 16 == 0 )
|
||||||
|
hashBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE HASH_128 digest()
|
||||||
|
{
|
||||||
|
hashTail();
|
||||||
|
|
||||||
|
HASH_128 h128;
|
||||||
|
hashFinal( h128 );
|
||||||
|
|
||||||
|
return h128;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// Block read - if your platform needs to do endian-swapping or can only
|
||||||
|
// handle aligned reads, do the conversion here
|
||||||
|
FORCE_INLINE uint64_t getblock64( int i )
|
||||||
|
{
|
||||||
|
return blocks64[i]; //
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE void hashBlock()
|
||||||
|
{
|
||||||
|
static const uint64_t c1 = BIG_CONSTANT( 0x87c37b91114253d5 );
|
||||||
|
static const uint64_t c2 = BIG_CONSTANT( 0x4cf5ad432745937f );
|
||||||
|
|
||||||
|
uint64_t k1 = getblock64( 0 );
|
||||||
|
uint64_t k2 = getblock64( 1 );
|
||||||
|
|
||||||
|
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
|
||||||
|
|
||||||
|
h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
|
||||||
|
|
||||||
|
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
|
||||||
|
|
||||||
|
h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE void hashTail()
|
||||||
|
{
|
||||||
|
const uint8_t * tail = (const uint8_t*)(blocks);
|
||||||
|
|
||||||
|
static const uint64_t c1 = BIG_CONSTANT( 0x87c37b91114253d5 );
|
||||||
|
static const uint64_t c2 = BIG_CONSTANT( 0x4cf5ad432745937f );
|
||||||
|
|
||||||
|
uint64_t k1 = 0;
|
||||||
|
uint64_t k2 = 0;
|
||||||
|
|
||||||
|
switch( len & 15)
|
||||||
|
{
|
||||||
|
case 15: k2 ^= ((uint64_t)tail[14]) << 48;
|
||||||
|
case 14: k2 ^= ((uint64_t)tail[13]) << 40;
|
||||||
|
case 13: k2 ^= ((uint64_t)tail[12]) << 32;
|
||||||
|
case 12: k2 ^= ((uint64_t)tail[11]) << 24;
|
||||||
|
case 11: k2 ^= ((uint64_t)tail[10]) << 16;
|
||||||
|
case 10: k2 ^= ((uint64_t)tail[ 9]) << 8;
|
||||||
|
case 9: k2 ^= ((uint64_t)tail[ 8]) << 0;
|
||||||
|
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
|
||||||
|
|
||||||
|
case 8: k1 ^= ((uint64_t)tail[ 7]) << 56;
|
||||||
|
case 7: k1 ^= ((uint64_t)tail[ 6]) << 48;
|
||||||
|
case 6: k1 ^= ((uint64_t)tail[ 5]) << 40;
|
||||||
|
case 5: k1 ^= ((uint64_t)tail[ 4]) << 32;
|
||||||
|
case 4: k1 ^= ((uint64_t)tail[ 3]) << 24;
|
||||||
|
case 3: k1 ^= ((uint64_t)tail[ 2]) << 16;
|
||||||
|
case 2: k1 ^= ((uint64_t)tail[ 1]) << 8;
|
||||||
|
case 1: k1 ^= ((uint64_t)tail[ 0]) << 0;
|
||||||
|
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finalization mix - force all bits of a hash block to avalanche
|
||||||
|
static FORCE_INLINE uint64_t fmix64( uint64_t k )
|
||||||
|
{
|
||||||
|
k ^= k >> 33;
|
||||||
|
k *= BIG_CONSTANT( 0xff51afd7ed558ccd );
|
||||||
|
k ^= k >> 33;
|
||||||
|
k *= BIG_CONSTANT( 0xc4ceb9fe1a85ec53 );
|
||||||
|
k ^= k >> 33;
|
||||||
|
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE void hashFinal( HASH_128& out )
|
||||||
|
{
|
||||||
|
h1 ^= len;
|
||||||
|
h2 ^= len;
|
||||||
|
|
||||||
|
h1 += h2;
|
||||||
|
h2 += h1;
|
||||||
|
|
||||||
|
h1 = fmix64( h1 );
|
||||||
|
h2 = fmix64( h2 );
|
||||||
|
|
||||||
|
h1 += h2;
|
||||||
|
h2 += h1;
|
||||||
|
|
||||||
|
out.Value64[0] = h1;
|
||||||
|
out.Value64[1] = h2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint64_t h1;
|
||||||
|
uint64_t h2;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint32_t blocks[4];
|
||||||
|
uint64_t blocks64[2];
|
||||||
|
};
|
||||||
|
uint32_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#undef FORCE_INLINE
|
||||||
|
#undef ROTL64
|
||||||
|
#undef BIG_CONSTANT
|
||||||
|
|
||||||
|
|
||||||
|
#endif // MMH3_HASH_H_
|
|
@ -53,8 +53,8 @@
|
||||||
#include <math/box2.h> // for BOX2I
|
#include <math/box2.h> // for BOX2I
|
||||||
#include <math/util.h> // for KiROUND, rescale
|
#include <math/util.h> // for KiROUND, rescale
|
||||||
#include <math/vector2d.h> // for VECTOR2I, VECTOR2D, VECTOR2
|
#include <math/vector2d.h> // for VECTOR2I, VECTOR2D, VECTOR2
|
||||||
#include <md5_hash.h>
|
|
||||||
#include <hash.h>
|
#include <hash.h>
|
||||||
|
#include <mmh3_hash.h>
|
||||||
#include <geometry/shape_segment.h>
|
#include <geometry/shape_segment.h>
|
||||||
#include <geometry/shape_circle.h>
|
#include <geometry/shape_circle.h>
|
||||||
|
|
||||||
|
@ -111,12 +111,14 @@ SHAPE_POLY_SET::SHAPE_POLY_SET( const SHAPE_POLY_SET& aOther ) :
|
||||||
}
|
}
|
||||||
|
|
||||||
m_hash = aOther.GetHash();
|
m_hash = aOther.GetHash();
|
||||||
|
m_hashValid = true;
|
||||||
m_triangulationValid = true;
|
m_triangulationValid = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_triangulationValid = false;
|
m_triangulationValid = false;
|
||||||
m_hash = MD5_HASH();
|
m_hash.Clear();
|
||||||
|
m_hashValid = false;
|
||||||
m_triangulatedPolys.clear();
|
m_triangulatedPolys.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,7 +129,8 @@ SHAPE_POLY_SET::SHAPE_POLY_SET( const SHAPE_POLY_SET& aOther, DROP_TRIANGULATION
|
||||||
m_polys( aOther.m_polys )
|
m_polys( aOther.m_polys )
|
||||||
{
|
{
|
||||||
m_triangulationValid = false;
|
m_triangulationValid = false;
|
||||||
m_hash = MD5_HASH();
|
m_hash.Clear();
|
||||||
|
m_hashValid = false;
|
||||||
m_triangulatedPolys.clear();
|
m_triangulatedPolys.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2523,7 +2526,10 @@ void SHAPE_POLY_SET::DeletePolygonAndTriangulationData( int aIdx, bool aUpdateHa
|
||||||
}
|
}
|
||||||
|
|
||||||
if( aUpdateHash )
|
if( aUpdateHash )
|
||||||
|
{
|
||||||
m_hash = checksum();
|
m_hash = checksum();
|
||||||
|
m_hashValid = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2531,6 +2537,7 @@ void SHAPE_POLY_SET::DeletePolygonAndTriangulationData( int aIdx, bool aUpdateHa
|
||||||
void SHAPE_POLY_SET::UpdateTriangulationDataHash()
|
void SHAPE_POLY_SET::UpdateTriangulationDataHash()
|
||||||
{
|
{
|
||||||
m_hash = checksum();
|
m_hash = checksum();
|
||||||
|
m_hashValid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2723,6 +2730,7 @@ void SHAPE_POLY_SET::Move( const VECTOR2I& aVector )
|
||||||
tri->Move( aVector );
|
tri->Move( aVector );
|
||||||
|
|
||||||
m_hash = checksum();
|
m_hash = checksum();
|
||||||
|
m_hashValid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3131,15 +3139,16 @@ SHAPE_POLY_SET &SHAPE_POLY_SET::operator=( const SHAPE_POLY_SET& aOther )
|
||||||
}
|
}
|
||||||
|
|
||||||
m_hash = aOther.m_hash;
|
m_hash = aOther.m_hash;
|
||||||
|
m_hashValid = aOther.m_hashValid;
|
||||||
m_triangulationValid = aOther.m_triangulationValid.load();
|
m_triangulationValid = aOther.m_triangulationValid.load();
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MD5_HASH SHAPE_POLY_SET::GetHash() const
|
HASH_128 SHAPE_POLY_SET::GetHash() const
|
||||||
{
|
{
|
||||||
if( !m_hash.IsValid() )
|
if( !m_hashValid )
|
||||||
return checksum();
|
return checksum();
|
||||||
|
|
||||||
return m_hash;
|
return m_hash;
|
||||||
|
@ -3151,10 +3160,10 @@ bool SHAPE_POLY_SET::IsTriangulationUpToDate() const
|
||||||
if( !m_triangulationValid )
|
if( !m_triangulationValid )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if( !m_hash.IsValid() )
|
if( !m_hashValid )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
MD5_HASH hash = checksum();
|
HASH_128 hash = checksum();
|
||||||
|
|
||||||
return hash == m_hash;
|
return hash == m_hash;
|
||||||
}
|
}
|
||||||
|
@ -3234,7 +3243,7 @@ void SHAPE_POLY_SET::cacheTriangulation( bool aPartition, bool aSimplify,
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock( m_triangulationMutex );
|
std::unique_lock<std::mutex> lock( m_triangulationMutex );
|
||||||
|
|
||||||
if( m_triangulationValid && m_hash.IsValid() )
|
if( m_triangulationValid && m_hashValid )
|
||||||
{
|
{
|
||||||
if( m_hash == checksum() )
|
if( m_hash == checksum() )
|
||||||
return;
|
return;
|
||||||
|
@ -3242,7 +3251,7 @@ void SHAPE_POLY_SET::cacheTriangulation( bool aPartition, bool aSimplify,
|
||||||
|
|
||||||
// Invalidate, in case anything goes wrong below
|
// Invalidate, in case anything goes wrong below
|
||||||
m_triangulationValid = false;
|
m_triangulationValid = false;
|
||||||
m_hash.SetValid( false );
|
m_hashValid = false;
|
||||||
|
|
||||||
auto triangulate =
|
auto triangulate =
|
||||||
[]( SHAPE_POLY_SET& polySet, int forOutline,
|
[]( SHAPE_POLY_SET& polySet, int forOutline,
|
||||||
|
@ -3334,6 +3343,7 @@ void SHAPE_POLY_SET::cacheTriangulation( bool aPartition, bool aSimplify,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_hash = checksum();
|
m_hash = checksum();
|
||||||
|
m_hashValid = true;
|
||||||
// Set valid flag only after everything has been updated
|
// Set valid flag only after everything has been updated
|
||||||
m_triangulationValid = true;
|
m_triangulationValid = true;
|
||||||
}
|
}
|
||||||
|
@ -3354,6 +3364,7 @@ void SHAPE_POLY_SET::cacheTriangulation( bool aPartition, bool aSimplify,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_hash = checksum();
|
m_hash = checksum();
|
||||||
|
m_hashValid = true;
|
||||||
// Set valid flag only after everything has been updated
|
// Set valid flag only after everything has been updated
|
||||||
m_triangulationValid = true;
|
m_triangulationValid = true;
|
||||||
}
|
}
|
||||||
|
@ -3361,31 +3372,31 @@ void SHAPE_POLY_SET::cacheTriangulation( bool aPartition, bool aSimplify,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MD5_HASH SHAPE_POLY_SET::checksum() const
|
HASH_128 SHAPE_POLY_SET::checksum() const
|
||||||
{
|
{
|
||||||
MD5_HASH hash;
|
MMH3_HASH hash( 0x68AF835D ); // Arbitrary seed
|
||||||
|
|
||||||
hash.Hash( m_polys.size() );
|
hash.add( m_polys.size() );
|
||||||
|
|
||||||
for( const POLYGON& outline : m_polys )
|
for( const POLYGON& outline : m_polys )
|
||||||
{
|
{
|
||||||
hash.Hash( outline.size() );
|
hash.add( outline.size() );
|
||||||
|
|
||||||
for( const SHAPE_LINE_CHAIN& lc : outline )
|
for( const SHAPE_LINE_CHAIN& lc : outline )
|
||||||
{
|
{
|
||||||
hash.Hash( lc.PointCount() );
|
hash.add( lc.PointCount() );
|
||||||
|
|
||||||
for( int i = 0; i < lc.PointCount(); i++ )
|
for( int i = 0; i < lc.PointCount(); i++ )
|
||||||
{
|
{
|
||||||
hash.Hash( lc.CPoint( i ).x );
|
VECTOR2I pt = lc.CPoint( i );
|
||||||
hash.Hash( lc.CPoint( i ).y );
|
|
||||||
|
hash.add( pt.x );
|
||||||
|
hash.add( pt.y );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hash.Finalize();
|
return hash.digest();
|
||||||
|
|
||||||
return hash;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1061,8 +1061,8 @@ private:
|
||||||
|
|
||||||
SHAPE_POLY_SET m_courtyard_cache_front; // Note that a footprint can have both front and back
|
SHAPE_POLY_SET m_courtyard_cache_front; // Note that a footprint can have both front and back
|
||||||
SHAPE_POLY_SET m_courtyard_cache_back; // courtyards populated.
|
SHAPE_POLY_SET m_courtyard_cache_back; // courtyards populated.
|
||||||
mutable MD5_HASH m_courtyard_cache_front_hash;
|
mutable HASH_128 m_courtyard_cache_front_hash;
|
||||||
mutable MD5_HASH m_courtyard_cache_back_hash;
|
mutable HASH_128 m_courtyard_cache_back_hash;
|
||||||
mutable std::mutex m_courtyard_cache_mutex;
|
mutable std::mutex m_courtyard_cache_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -576,12 +576,16 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, PAD* aPad )
|
||||||
}
|
}
|
||||||
|
|
||||||
// this string _must_ be unique for a given physical shape, so try to make it unique
|
// this string _must_ be unique for a given physical shape, so try to make it unique
|
||||||
MD5_HASH hash = pad_shape.GetHash();
|
const HASH_128 hash = pad_shape.GetHash();
|
||||||
|
char hashStr[33] = {};
|
||||||
|
|
||||||
|
snprintf( hashStr, sizeof( hashStr ), "%016llX%016llX", hash.Value64[0], hash.Value64[1] );
|
||||||
|
|
||||||
BOX2I rect = aPad->GetBoundingBox();
|
BOX2I rect = aPad->GetBoundingBox();
|
||||||
snprintf( name, sizeof( name ), "Cust%sPad_%.6gx%.6g_%.6gx_%.6g_%d_um_%s",
|
snprintf( name, sizeof( name ), "Cust%sPad_%.6gx%.6g_%.6gx_%.6g_%d_um_%s",
|
||||||
uniqifier.c_str(), IU2um( aPad->GetSize().x ), IU2um( aPad->GetSize().y ),
|
uniqifier.c_str(), IU2um( aPad->GetSize().x ), IU2um( aPad->GetSize().y ),
|
||||||
IU2um( rect.GetWidth() ), IU2um( rect.GetHeight() ), (int) polygonal_shape.size(),
|
IU2um( rect.GetWidth() ), IU2um( rect.GetHeight() ), (int) polygonal_shape.size(),
|
||||||
hash.Format( true ).c_str() );
|
hashStr );
|
||||||
name[sizeof( name ) - 1] = 0;
|
name[sizeof( name ) - 1] = 0;
|
||||||
|
|
||||||
padstack->SetPadstackId( name );
|
padstack->SetPadstackId( name );
|
||||||
|
|
|
@ -406,7 +406,7 @@ void ZONE::SetCornerRadius( unsigned int aRadius )
|
||||||
static SHAPE_POLY_SET g_nullPoly;
|
static SHAPE_POLY_SET g_nullPoly;
|
||||||
|
|
||||||
|
|
||||||
MD5_HASH ZONE::GetHashValue( PCB_LAYER_ID aLayer )
|
HASH_128 ZONE::GetHashValue( PCB_LAYER_ID aLayer )
|
||||||
{
|
{
|
||||||
if( !m_filledPolysHash.count( aLayer ) )
|
if( !m_filledPolysHash.count( aLayer ) )
|
||||||
return g_nullPoly.GetHash();
|
return g_nullPoly.GetHash();
|
||||||
|
|
|
@ -782,7 +782,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @return the hash value previously calculated by BuildHashValue().
|
* @return the hash value previously calculated by BuildHashValue().
|
||||||
*/
|
*/
|
||||||
MD5_HASH GetHashValue( PCB_LAYER_ID aLayer );
|
HASH_128 GetHashValue( PCB_LAYER_ID aLayer );
|
||||||
|
|
||||||
double Similarity( const BOARD_ITEM& aOther ) const override;
|
double Similarity( const BOARD_ITEM& aOther ) const override;
|
||||||
|
|
||||||
|
@ -904,7 +904,7 @@ protected:
|
||||||
LSET m_fillFlags;
|
LSET m_fillFlags;
|
||||||
|
|
||||||
/// A hash value used in zone filling calculations to see if the filled areas are up to date
|
/// A hash value used in zone filling calculations to see if the filled areas are up to date
|
||||||
std::map<PCB_LAYER_ID, MD5_HASH> m_filledPolysHash;
|
std::map<PCB_LAYER_ID, HASH_128> m_filledPolysHash;
|
||||||
|
|
||||||
ZONE_BORDER_DISPLAY_STYLE m_borderStyle; // border display style, see enum above
|
ZONE_BORDER_DISPLAY_STYLE m_borderStyle; // border display style, see enum above
|
||||||
int m_borderHatchPitch; // for DIAGONAL_EDGE, distance between 2 lines
|
int m_borderHatchPitch; // for DIAGONAL_EDGE, distance between 2 lines
|
||||||
|
|
|
@ -92,7 +92,7 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE*>& aZones, bool aCheck, wxWindow*
|
||||||
std::lock_guard<KISPINLOCK> lock( m_board->GetConnectivity()->GetLock() );
|
std::lock_guard<KISPINLOCK> lock( m_board->GetConnectivity()->GetLock() );
|
||||||
|
|
||||||
std::vector<std::pair<ZONE*, PCB_LAYER_ID>> toFill;
|
std::vector<std::pair<ZONE*, PCB_LAYER_ID>> toFill;
|
||||||
std::map<std::pair<ZONE*, PCB_LAYER_ID>, MD5_HASH> oldFillHashes;
|
std::map<std::pair<ZONE*, PCB_LAYER_ID>, HASH_128> oldFillHashes;
|
||||||
std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> isolatedIslandsMap;
|
std::map<ZONE*, std::map<PCB_LAYER_ID, ISOLATED_ISLANDS>> isolatedIslandsMap;
|
||||||
|
|
||||||
std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_board->GetConnectivity();
|
std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_board->GetConnectivity();
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
|
|
||||||
// Code under test
|
// Code under test
|
||||||
#include <trigo.h>
|
#include <trigo.h>
|
||||||
|
#include <hash_128.h>
|
||||||
#include <geometry/shape_arc.h>
|
#include <geometry/shape_arc.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -317,4 +318,205 @@ BOOST_AUTO_TEST_CASE( TestInterceptsNegativeX )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE( TestHash128 )
|
||||||
|
{
|
||||||
|
const HASH_128 zero;
|
||||||
|
|
||||||
|
for( size_t i = 0; i < 16; i++ )
|
||||||
|
BOOST_CHECK( zero.Value8[i] == 0 );
|
||||||
|
|
||||||
|
HASH_128* zero_h = new HASH_128;
|
||||||
|
|
||||||
|
for( size_t i = 0; i < 16; i++ )
|
||||||
|
BOOST_CHECK( zero_h->Value8[i] == 0 );
|
||||||
|
|
||||||
|
delete zero_h;
|
||||||
|
|
||||||
|
HASH_128 h;
|
||||||
|
h.Value64[0] = 0x00CDEF0123456789ULL;
|
||||||
|
h.Value64[1] = 0x56789ABCDEF01234ULL;
|
||||||
|
|
||||||
|
BOOST_CHECK( h != zero );
|
||||||
|
|
||||||
|
HASH_128 b = h;
|
||||||
|
BOOST_CHECK( b != zero );
|
||||||
|
|
||||||
|
BOOST_CHECK( b == h );
|
||||||
|
BOOST_CHECK( h == b );
|
||||||
|
|
||||||
|
char hashStr[33] = {};
|
||||||
|
snprintf( hashStr, sizeof( hashStr ), "%016llX%016llX", h.Value64[0], h.Value64[1] );
|
||||||
|
|
||||||
|
BOOST_CHECK( std::string( hashStr ) == std::string( "00CDEF012345678956789ABCDEF01234" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Test MMH3_HASH against the original MurmurHash3_x64_128 implementation
|
||||||
|
|
||||||
|
#include <mmh3_hash.h>
|
||||||
|
|
||||||
|
void MurmurHash3_x64_128( const void* key, const int len, const uint32_t seed, void* out );
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE( TestMMH3Hash )
|
||||||
|
{
|
||||||
|
std::vector<std::vector<int32_t>> data;
|
||||||
|
|
||||||
|
for( size_t i = 0; i < 10; i++ )
|
||||||
|
{
|
||||||
|
std::vector<int32_t>& vec = data.emplace_back();
|
||||||
|
|
||||||
|
size_t vecSize = rand() % 128;
|
||||||
|
|
||||||
|
for( size_t j = 0; j < vecSize; j++ )
|
||||||
|
vec.emplace_back( rand() );
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t seed = 0; // Test 0 seed first
|
||||||
|
|
||||||
|
for( const std::vector<int32_t>& vec : data )
|
||||||
|
{
|
||||||
|
MMH3_HASH mmh3( seed );
|
||||||
|
|
||||||
|
for( const int32_t val : vec )
|
||||||
|
mmh3.add( val );
|
||||||
|
|
||||||
|
HASH_128 h128 = mmh3.digest();
|
||||||
|
|
||||||
|
HASH_128 orig128;
|
||||||
|
MurmurHash3_x64_128( (void*) vec.data(), vec.size() * sizeof( vec[0] ), seed,
|
||||||
|
(void*) orig128.Value64 );
|
||||||
|
|
||||||
|
BOOST_CHECK( h128 == orig128 );
|
||||||
|
|
||||||
|
// Generate new random seed
|
||||||
|
seed = rand();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// The original MurmurHash3_x64_128 implementation
|
||||||
|
|
||||||
|
|
||||||
|
// Microsoft Visual Studio
|
||||||
|
#if defined( _MSC_VER )
|
||||||
|
#define FORCE_INLINE __forceinline
|
||||||
|
#include <stdlib.h>
|
||||||
|
#define ROTL64( x, y ) _rotl64( x, y )
|
||||||
|
#define BIG_CONSTANT( x ) ( x )
|
||||||
|
// Other compilers
|
||||||
|
#else // defined(_MSC_VER)
|
||||||
|
#define FORCE_INLINE inline __attribute__( ( always_inline ) )
|
||||||
|
inline uint64_t rotl64( uint64_t x, int8_t r )
|
||||||
|
{
|
||||||
|
return ( x << r ) | ( x >> ( 64 - r ) );
|
||||||
|
}
|
||||||
|
#define ROTL64( x, y ) rotl64( x, y )
|
||||||
|
#define BIG_CONSTANT( x ) ( x##LLU )
|
||||||
|
#endif // !defined(_MSC_VER)
|
||||||
|
|
||||||
|
|
||||||
|
FORCE_INLINE uint64_t getblock64 ( const uint64_t * p, int i )
|
||||||
|
{
|
||||||
|
return p[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE uint64_t fmix64 ( uint64_t k )
|
||||||
|
{
|
||||||
|
k ^= k >> 33;
|
||||||
|
k *= BIG_CONSTANT(0xff51afd7ed558ccd);
|
||||||
|
k ^= k >> 33;
|
||||||
|
k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
|
||||||
|
k ^= k >> 33;
|
||||||
|
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MurmurHash3_x64_128 ( const void * key, const int len,
|
||||||
|
const uint32_t seed, void * out )
|
||||||
|
{
|
||||||
|
const uint8_t * data = (const uint8_t*)key;
|
||||||
|
const int nblocks = len / 16;
|
||||||
|
|
||||||
|
uint64_t h1 = seed;
|
||||||
|
uint64_t h2 = seed;
|
||||||
|
|
||||||
|
const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5);
|
||||||
|
const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f);
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// body
|
||||||
|
|
||||||
|
const uint64_t * blocks = (const uint64_t *)(data);
|
||||||
|
|
||||||
|
for(int i = 0; i < nblocks; i++)
|
||||||
|
{
|
||||||
|
uint64_t k1 = getblock64(blocks,i*2+0);
|
||||||
|
uint64_t k2 = getblock64(blocks,i*2+1);
|
||||||
|
|
||||||
|
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
|
||||||
|
|
||||||
|
h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
|
||||||
|
|
||||||
|
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
|
||||||
|
|
||||||
|
h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// tail
|
||||||
|
|
||||||
|
const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
|
||||||
|
|
||||||
|
uint64_t k1 = 0;
|
||||||
|
uint64_t k2 = 0;
|
||||||
|
|
||||||
|
switch(len & 15)
|
||||||
|
{
|
||||||
|
case 15: k2 ^= ((uint64_t)tail[14]) << 48;
|
||||||
|
case 14: k2 ^= ((uint64_t)tail[13]) << 40;
|
||||||
|
case 13: k2 ^= ((uint64_t)tail[12]) << 32;
|
||||||
|
case 12: k2 ^= ((uint64_t)tail[11]) << 24;
|
||||||
|
case 11: k2 ^= ((uint64_t)tail[10]) << 16;
|
||||||
|
case 10: k2 ^= ((uint64_t)tail[ 9]) << 8;
|
||||||
|
case 9: k2 ^= ((uint64_t)tail[ 8]) << 0;
|
||||||
|
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
|
||||||
|
|
||||||
|
case 8: k1 ^= ((uint64_t)tail[ 7]) << 56;
|
||||||
|
case 7: k1 ^= ((uint64_t)tail[ 6]) << 48;
|
||||||
|
case 6: k1 ^= ((uint64_t)tail[ 5]) << 40;
|
||||||
|
case 5: k1 ^= ((uint64_t)tail[ 4]) << 32;
|
||||||
|
case 4: k1 ^= ((uint64_t)tail[ 3]) << 24;
|
||||||
|
case 3: k1 ^= ((uint64_t)tail[ 2]) << 16;
|
||||||
|
case 2: k1 ^= ((uint64_t)tail[ 1]) << 8;
|
||||||
|
case 1: k1 ^= ((uint64_t)tail[ 0]) << 0;
|
||||||
|
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// finalization
|
||||||
|
|
||||||
|
h1 ^= len; h2 ^= len;
|
||||||
|
|
||||||
|
h1 += h2;
|
||||||
|
h2 += h1;
|
||||||
|
|
||||||
|
h1 = fmix64(h1);
|
||||||
|
h2 = fmix64(h2);
|
||||||
|
|
||||||
|
h1 += h2;
|
||||||
|
h2 += h1;
|
||||||
|
|
||||||
|
((uint64_t*)out)[0] = h1;
|
||||||
|
((uint64_t*)out)[1] = h2;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#undef FORCE_INLINE
|
||||||
|
#undef ROTL64
|
||||||
|
#undef BIG_CONSTANT
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
Loading…
Reference in New Issue