Blacklist hashes for 2d integer elements

The hash table for integer hashes is extremely limited and places most
elements in the same buckets.  This leads to a linear search time for
structures built on this.

This blocks hashes, directing the coder to utilize std::set or std::map
structures instead of hash tables for implementing integer-based
lookups.
This commit is contained in:
Seth Hillbrand 2022-08-25 19:51:11 -07:00
parent ed02d7c974
commit 06786c34d7
9 changed files with 19 additions and 44 deletions

View File

@ -112,7 +112,7 @@ void VIEW_GROUP::ViewDraw( int aLayer, VIEW* aView ) const
const std::vector<VIEW_ITEM*> drawList = updateDrawList();
std::unordered_map<int, std::vector<VIEW_ITEM*>> layer_item_map;
std::map<int, std::vector<VIEW_ITEM*>> layer_item_map;
// Build a list of layers used by the items in the group
for( VIEW_ITEM* item : drawList )
@ -123,13 +123,6 @@ void VIEW_GROUP::ViewDraw( int aLayer, VIEW* aView ) const
for( int i = 0; i < item_layers_count; i++ )
{
wxCHECK2_MSG( item_layers[i] <= LAYER_ID_COUNT, continue, wxT( "Invalid item layer" ) );
if( layer_item_map.count( item_layers[i] ) == 0 )
{
layer_item_map.emplace( std::make_pair( item_layers[i],
std::vector<VIEW_ITEM*>() ) );
}
layer_item_map[ item_layers[i] ].push_back( item );
}
}

View File

@ -29,16 +29,6 @@ size_t std::hash<wxString>::operator()( const wxString& s ) const
#endif
#ifdef USE_KICAD_WXPOINT_LESS_AND_HASH
size_t std::hash<wxPoint>::operator() ( const wxPoint& k ) const
{
auto xhash = std::hash<int>()( k.x );
// 0x9e3779b9 is 2^33 / ( 1 + sqrt(5) )
// Adding this value ensures that consecutive bits of y will not be close to each other
// decreasing the likelihood of hash collision in similar values of x and y
return xhash ^ ( std::hash<int>()( k.y ) + 0x9e3779b9 + ( xhash << 6 ) + ( xhash >> 2 ) );
}
bool std::less<wxPoint>::operator()( const wxPoint& aA, const wxPoint& aB ) const
{
if( aA.x == aB.x )

View File

@ -411,7 +411,7 @@ int ERC_TESTER::TestNoConnectPins()
for( const SCH_SHEET_PATH& sheet : m_schematic->GetSheets() )
{
std::unordered_map<VECTOR2I, std::vector<SCH_PIN*>> pinMap;
std::map<VECTOR2I, std::vector<SCH_PIN*>> pinMap;
for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
{
@ -863,4 +863,4 @@ int ERC_TESTER::TestOffGridEndpoints( int aGridSize )
}
return err_count;
}
}

View File

@ -43,7 +43,7 @@ namespace std
{
template <> struct hash<wxPoint>
{
size_t operator() ( const wxPoint& k ) const;
size_t operator() ( const wxPoint& k ) const = delete;
};
}

View File

@ -611,13 +611,17 @@ typedef VECTOR2<unsigned int> VECTOR2U;
namespace std
{
// Required to enable correct use in std::map/unordered_map
// DO NOT USE hash tables with VECTOR2 elements. It is inefficient
// and degenerates to a linear search. Use the std::map/std::set
// trees instead that utilize the less operator below
// This function is purposely deleted after substantial testing
template <>
struct hash<VECTOR2I>
{
size_t operator()( const VECTOR2I& k ) const;
size_t operator()( const VECTOR2I& k ) const = delete;
};
// Required to enable use of std::hash with maps
// Required to enable use of std::hash with maps.
template <>
struct less<VECTOR2I>
{

View File

@ -19,22 +19,10 @@
#include <math/vector2d.h>
size_t std::hash<VECTOR2I>::operator()( const VECTOR2I& k ) const
{
auto xhash = std::hash<int>()( k.x );
// 0x9e3779b9 is 2^33 / ( 1 + sqrt(5) )
// Adding this value ensures that consecutive bits of y will not be close to each other
// decreasing the likelihood of hash collision in similar values of x and y
return xhash ^ ( std::hash<int>()( k.y ) + 0x9e3779b9 + ( xhash << 6 ) + ( xhash >> 2 ) );
}
bool std::less<VECTOR2I>::operator()( const VECTOR2I& aA, const VECTOR2I& aB ) const
{
if( aA.x == aB.x )
return aA.y < aB.y;
return aA.x < aB.x;
}
}

View File

@ -243,7 +243,7 @@ protected:
bool m_testFootprints;
// constraint -> rule -> provider
std::unordered_map<DRC_CONSTRAINT_T, std::vector<DRC_ENGINE_CONSTRAINT*>*> m_constraintMap;
std::map<DRC_CONSTRAINT_T, std::vector<DRC_ENGINE_CONSTRAINT*>*> m_constraintMap;
DRC_VIOLATION_HANDLER m_violationHandler;
REPORTER* m_reporter;

View File

@ -854,7 +854,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones()
}
// Iterate through all the segments of refSmoothedPoly
std::unordered_map<VECTOR2I, int> conflictPoints;
std::map<VECTOR2I, int> conflictPoints;
for( auto refIt = smoothed_polys[ia].IterateSegmentsWithHoles(); refIt; refIt++ )
{

View File

@ -1140,12 +1140,12 @@ void PCB_SELECTION_TOOL::selectAllConnectedTracks(
auto connectivity = board()->GetConnectivity();
std::unordered_map<VECTOR2I, std::vector<PCB_TRACK*>> trackMap;
std::unordered_map<VECTOR2I, PCB_VIA*> viaMap;
std::unordered_map<VECTOR2I, PAD*> padMap;
std::set<PAD*> startPadSet;
std::vector<BOARD_CONNECTED_ITEM*> cleanupItems;
std::vector<std::pair<VECTOR2I, LSET>> activePts;
std::map<VECTOR2I, std::vector<PCB_TRACK*>> trackMap;
std::map<VECTOR2I, PCB_VIA*> viaMap;
std::map<VECTOR2I, PAD*> padMap;
std::set<PAD*> startPadSet;
std::vector<BOARD_CONNECTED_ITEM*> cleanupItems;
std::vector<std::pair<VECTOR2I, LSET>> activePts;
for( BOARD_CONNECTED_ITEM* startItem : aStartItems )
{