mirror of https://github.com/KLayout/klayout.git
WIP: bug fixes, stability of tests
This commit is contained in:
parent
5281397b17
commit
4beb8db15a
|
|
@ -306,6 +306,22 @@ void AsIfFlatRegion::invalidate_bbox ()
|
|||
m_bbox_valid = false;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct ComparePolygonsWithProperties
|
||||
{
|
||||
bool operator() (const std::pair<db::properties_id_type, const db::Polygon *> &a, const std::pair<db::properties_id_type, const db::Polygon *> &b) const
|
||||
{
|
||||
if (a.first != b.first) {
|
||||
return db::properties_id_less (a.first, b.first);
|
||||
}
|
||||
return *a.second < *b.second;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void AsIfFlatRegion::merge_polygons_to (db::Shapes &output, bool min_coherence, unsigned int min_wc) const
|
||||
{
|
||||
db::EdgeProcessor ep (report_progress (), progress_desc ());
|
||||
|
|
@ -336,7 +352,7 @@ void AsIfFlatRegion::merge_polygons_to (db::Shapes &output, bool min_coherence,
|
|||
addressable_polygons.inc ();
|
||||
}
|
||||
|
||||
std::sort (polygons_by_prop_id.begin (), polygons_by_prop_id.end ());
|
||||
std::sort (polygons_by_prop_id.begin (), polygons_by_prop_id.end (), ComparePolygonsWithProperties ());
|
||||
|
||||
for (auto p = polygons_by_prop_id.begin (); p != polygons_by_prop_id.end (); ) {
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@
|
|||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "tlHash.h"
|
||||
|
||||
#include "dbPoint.h"
|
||||
#include "dbVector.h"
|
||||
#include "dbBox.h"
|
||||
|
|
@ -36,39 +38,25 @@
|
|||
#include "dbEdgePair.h"
|
||||
#include "dbInstances.h"
|
||||
#include "dbLayout.h"
|
||||
#include "dbTypes.h"
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
namespace db
|
||||
{
|
||||
DB_PUBLIC size_t hash_for_properties_id (properties_id_type id);
|
||||
}
|
||||
|
||||
/**
|
||||
* This header defines some hash functions for various database objects
|
||||
* for use with std::unordered_map and std::unordered_set
|
||||
*
|
||||
* It also provides namespace abstraction for the std_ext namespace
|
||||
*/
|
||||
|
||||
namespace std
|
||||
{
|
||||
inline size_t hcombine (size_t h1, size_t h2)
|
||||
{
|
||||
return (h1 << 4) ^ (h1 >> 4) ^ h2;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline size_t hfunc (const T &t)
|
||||
{
|
||||
hash <T> hf;
|
||||
return hf (t);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline size_t hfunc (const T &t, size_t h)
|
||||
{
|
||||
hash <T> hf;
|
||||
return hcombine (h, hf (t));
|
||||
}
|
||||
|
||||
inline size_t hfunc_coord (db::DCoord d)
|
||||
{
|
||||
return hfunc (int64_t (floor (0.5 + d / db::coord_traits<db::DCoord>::prec ())));
|
||||
|
|
@ -510,13 +498,13 @@ namespace std
|
|||
template <class O>
|
||||
size_t hfunc (const db::object_with_properties<O> &o, size_t h)
|
||||
{
|
||||
return hfunc ((const O &) o, hfunc (o.properties_id (), h));
|
||||
return hfunc ((const O &) o, hcombine (db::hash_for_properties_id (o.properties_id ()), h));
|
||||
}
|
||||
|
||||
template <class O>
|
||||
size_t hfunc (const db::object_with_properties<O> &o)
|
||||
{
|
||||
return hfunc ((const O &) o, hfunc (o.properties_id ()));
|
||||
return hfunc ((const O &) o, db::hash_for_properties_id (o.properties_id ()));
|
||||
}
|
||||
|
||||
template <class O>
|
||||
|
|
@ -657,156 +645,6 @@ namespace std
|
|||
return hfunc (o);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Generic hash for a pair of objects
|
||||
*/
|
||||
|
||||
template <class T1, class T2>
|
||||
size_t hfunc (const std::pair <T1, T2> &o, size_t h)
|
||||
{
|
||||
return hfunc (o.first, hfunc (o.second, h));
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
size_t hfunc (const std::pair <T1, T2> &o)
|
||||
{
|
||||
return hfunc (o.first, hfunc (o.second));
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
struct hash <std::pair <T1, T2> >
|
||||
{
|
||||
size_t operator() (const std::pair<T1, T2> &o) const
|
||||
{
|
||||
return hfunc (o);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Generic hash for an unordered set
|
||||
*/
|
||||
|
||||
template <class T>
|
||||
size_t hfunc (const std::unordered_set <T> &o, size_t h)
|
||||
{
|
||||
for (typename std::unordered_set<T>::const_iterator i = o.begin (); i != o.end (); ++i) {
|
||||
h = hfunc (*i, h);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
size_t hfunc (const std::unordered_set <T> &o)
|
||||
{
|
||||
return hfunc (o, size_t (0));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct hash <std::unordered_set <T> >
|
||||
{
|
||||
size_t operator() (const std::unordered_set<T> &o) const
|
||||
{
|
||||
return hfunc (o);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Generic hash for an ordered set
|
||||
*/
|
||||
|
||||
template <class T>
|
||||
size_t hfunc (const std::set <T> &o, size_t h)
|
||||
{
|
||||
for (typename std::set<T>::const_iterator i = o.begin (); i != o.end (); ++i) {
|
||||
h = hfunc (*i, h);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
size_t hfunc (const std::set <T> &o)
|
||||
{
|
||||
return hfunc (o, size_t (0));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct hash <std::set <T> >
|
||||
{
|
||||
size_t operator() (const std::set<T> &o) const
|
||||
{
|
||||
return hfunc (o);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Generic hash for an unordered map
|
||||
*/
|
||||
|
||||
template <class T1, class T2>
|
||||
size_t hfunc (const std::unordered_map<T1, T2> &o, size_t h)
|
||||
{
|
||||
for (typename std::unordered_map<T1, T2>::const_iterator i = o.begin (); i != o.end (); ++i) {
|
||||
h = hfunc (i->first, hfunc (i->second, h));
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
size_t hfunc (const std::unordered_map<T1, T2> &o)
|
||||
{
|
||||
return hfunc (o, size_t (0));
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
struct hash <std::unordered_map<T1, T2> >
|
||||
{
|
||||
size_t operator() (const std::unordered_map<T1, T2> &o) const
|
||||
{
|
||||
return hfunc (o);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Generic hash for an ordered map
|
||||
*/
|
||||
|
||||
template <class T1, class T2>
|
||||
size_t hfunc (const std::map<T1, T2> &o, size_t h)
|
||||
{
|
||||
for (typename std::map<T1, T2>::const_iterator i = o.begin (); i != o.end (); ++i) {
|
||||
h = hfunc (i->first, hfunc (i->second, h));
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
size_t hfunc (const std::map<T1, T2> &o)
|
||||
{
|
||||
return hfunc (o, size_t (0));
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
struct hash <std::map<T1, T2> >
|
||||
{
|
||||
size_t operator() (const std::map<T1, T2> &o) const
|
||||
{
|
||||
return hfunc (o);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a pointer hash from the pointer's value
|
||||
*/
|
||||
template <class X>
|
||||
struct ptr_hash_from_value
|
||||
{
|
||||
size_t operator() (const X *ptr) const
|
||||
{
|
||||
return ptr ? hash<X> () (*ptr) : 0;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include <map>
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <cstring>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
|
@ -412,6 +413,26 @@ template DB_PUBLIC bool Connectivity::interact<db::ICplxTrans> (const db::Cell &
|
|||
// ------------------------------------------------------------------------------
|
||||
// local_cluster implementation
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
local_cluster<T>::AttrCompare::operator() (local_cluster<T>::attr_id a, local_cluster<T>::attr_id b) const
|
||||
{
|
||||
size_t type_a = a & 3;
|
||||
size_t type_b = b & 3;
|
||||
|
||||
if (type_a != type_b) {
|
||||
return type_a < type_b;
|
||||
} else if (is_prop_id_attr (a)) {
|
||||
return properties_id_less (prop_id_from_attr (a), prop_id_from_attr (b));
|
||||
} else if (is_text_ref_attr (a)) {
|
||||
return strcmp (text_from_attr (a), text_from_attr (b)) < 0;
|
||||
} else if (is_global_net_id_attr (a)) {
|
||||
return global_net_id (a) < global_net_id (b);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
local_cluster<T>::local_cluster (size_t id)
|
||||
: m_id (id), m_needs_update (false), m_size (0)
|
||||
|
|
@ -1398,9 +1419,6 @@ struct attr_accessor<db::NetShape>
|
|||
{
|
||||
size_t operator() (const db::Shape &shape) const
|
||||
{
|
||||
// NOTE: the attribute is
|
||||
// * odd: a StringRef pointer's value
|
||||
// * even: a Property ID times 2
|
||||
if (shape.type () == db::Shape::TextRef) {
|
||||
return db::text_ref_to_attr (&shape.text_ref ().obj ());
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -277,12 +277,18 @@ public:
|
|||
typedef db::unstable_box_tree<box_type, T, db::box_convert<T> > tree_type;
|
||||
typedef typename tree_type::flat_iterator shape_iterator;
|
||||
typedef size_t attr_id;
|
||||
typedef std::set<attr_id> attr_set;
|
||||
typedef attr_set::const_iterator attr_iterator;
|
||||
typedef size_t global_net_id;
|
||||
typedef std::set<global_net_id> global_nets;
|
||||
typedef global_nets::const_iterator global_nets_iterator;
|
||||
|
||||
struct AttrCompare
|
||||
{
|
||||
bool operator() (attr_id a, attr_id b) const;
|
||||
};
|
||||
|
||||
typedef std::set<attr_id, AttrCompare> attr_set;
|
||||
typedef typename attr_set::const_iterator attr_iterator;
|
||||
|
||||
/**
|
||||
* @brief Creates an empty cluster
|
||||
*/
|
||||
|
|
@ -1709,7 +1715,9 @@ private:
|
|||
*/
|
||||
inline size_t prop_id_to_attr (db::properties_id_type id)
|
||||
{
|
||||
return size_t (id) * 4;
|
||||
// NOTE: properties ID are pointers, hence 32 bit aligned.
|
||||
tl_assert ((id & 3) == 0);
|
||||
return size_t (id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1725,7 +1733,7 @@ inline bool is_prop_id_attr (size_t attr)
|
|||
*/
|
||||
inline db::properties_id_type prop_id_from_attr (size_t attr)
|
||||
{
|
||||
return attr / 4;
|
||||
return attr;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ subtract (std::unordered_set<db::PolygonRefWithProperties> &res, const std::unor
|
|||
std::unordered_set<db::PolygonRefWithProperties> first;
|
||||
first.swap (res);
|
||||
|
||||
std::map<db::properties_id_type, std::pair<std::vector<const db::PolygonRefWithProperties *>, std::vector<const db::PolygonRefWithProperties *> > > by_prop_id;
|
||||
std::map<db::properties_id_type, std::pair<std::vector<const db::PolygonRefWithProperties *>, std::vector<const db::PolygonRefWithProperties *> >, ComparePropertiesIds> by_prop_id;
|
||||
for (auto i = first.begin (); i != first.end (); ++i) {
|
||||
by_prop_id [i->properties_id ()].first.push_back (i.operator-> ());
|
||||
}
|
||||
|
|
@ -325,7 +325,7 @@ subtract (std::unordered_set<db::EdgeWithProperties> &res, const std::unordered_
|
|||
std::unordered_set<db::EdgeWithProperties> first;
|
||||
first.swap (res);
|
||||
|
||||
std::map<db::properties_id_type, std::pair<std::vector<const db::EdgeWithProperties *>, std::vector<const db::EdgeWithProperties *> > > by_prop_id;
|
||||
std::map<db::properties_id_type, std::pair<std::vector<const db::EdgeWithProperties *>, std::vector<const db::EdgeWithProperties *> >, ComparePropertiesIds> by_prop_id;
|
||||
for (auto i = first.begin (); i != first.end (); ++i) {
|
||||
by_prop_id [i->properties_id ()].first.push_back (i.operator-> ());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ namespace db
|
|||
|
||||
class ArrayRepository;
|
||||
|
||||
DB_PUBLIC bool properties_id_less (properties_id_type a, properties_id_type b);
|
||||
|
||||
/**
|
||||
* @brief A object with properties template
|
||||
*
|
||||
|
|
@ -157,7 +159,7 @@ public:
|
|||
if (! Obj::operator== (d)) {
|
||||
return Obj::operator< (d);
|
||||
}
|
||||
return m_id < d.m_id;
|
||||
return db::properties_id_less (m_id, d.m_id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "tlException.h"
|
||||
#include "tlString.h"
|
||||
#include "tlAssert.h"
|
||||
#include "tlHash.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
|
@ -78,23 +79,48 @@ db::properties_id_type properties_id (const PropertiesSet &ps)
|
|||
return PropertiesRepository::instance ().properties_id (ps);
|
||||
}
|
||||
|
||||
size_t hash_for_properties_id (properties_id_type id)
|
||||
{
|
||||
return id == 0 ? 0 : db::properties (id).hash ();
|
||||
}
|
||||
|
||||
bool properties_id_less (properties_id_type a, properties_id_type b)
|
||||
{
|
||||
if (a == b) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a == 0 || b == 0) {
|
||||
return a < b;
|
||||
}
|
||||
|
||||
size_t ha = hash_for_properties_id (a);
|
||||
size_t hb = hash_for_properties_id (b);
|
||||
if (ha != hb) {
|
||||
return ha < hb;
|
||||
}
|
||||
|
||||
// This is the unlikely case of identical hash, but different value
|
||||
return db::properties (a).to_map () < db::properties (b).to_map ();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// PropertiesSet implementation
|
||||
|
||||
PropertiesSet::PropertiesSet ()
|
||||
: m_map ()
|
||||
: m_map (), m_hash (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
PropertiesSet::PropertiesSet (const PropertiesSet &other)
|
||||
: m_map (other.m_map)
|
||||
: m_map (other.m_map), m_hash (other.m_hash)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
PropertiesSet::PropertiesSet (const PropertiesSet &&other)
|
||||
: m_map (std::move (other.m_map))
|
||||
: m_map (std::move (other.m_map)), m_hash (other.m_hash)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -103,6 +129,7 @@ PropertiesSet &
|
|||
PropertiesSet::operator= (const PropertiesSet &other)
|
||||
{
|
||||
m_map = other.m_map;
|
||||
m_hash = other.m_hash;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -110,6 +137,7 @@ PropertiesSet &
|
|||
PropertiesSet::operator= (const PropertiesSet &&other)
|
||||
{
|
||||
m_map = std::move (other.m_map);
|
||||
m_hash = other.m_hash;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -255,6 +283,31 @@ PropertiesSet::to_list_var () const
|
|||
return var;
|
||||
}
|
||||
|
||||
size_t
|
||||
PropertiesSet::hash () const
|
||||
{
|
||||
if (empty ()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (! m_hash) {
|
||||
|
||||
static tl::Mutex lock;
|
||||
tl::MutexLocker locker (&lock);
|
||||
|
||||
if (! m_hash) {
|
||||
m_hash = std::hfunc (to_map ());
|
||||
if (! m_hash) {
|
||||
// avoid 0 value as this is reserved for "not computed yet"
|
||||
m_hash = size_t (1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return m_hash;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// PropertiesRepository implementation
|
||||
|
||||
|
|
|
|||
|
|
@ -59,6 +59,26 @@ DB_PUBLIC const tl::Variant &property_value (db::property_values_id_type id);
|
|||
*/
|
||||
DB_PUBLIC db::property_values_id_type property_values_id (const tl::Variant &pv);
|
||||
|
||||
/**
|
||||
* @brief Computes the hash value for a properties_id
|
||||
*/
|
||||
DB_PUBLIC size_t hash_for_properties_id (properties_id_type id);
|
||||
|
||||
/**
|
||||
* @brief A less compare function implementation that compares the properties IDs by value
|
||||
*/
|
||||
DB_PUBLIC bool properties_id_less (properties_id_type a, properties_id_type b);
|
||||
|
||||
/**
|
||||
* @brief A compare function for property IDs
|
||||
*/
|
||||
struct ComparePropertiesIds
|
||||
{
|
||||
bool operator() (properties_id_type a, properties_id_type b) const
|
||||
{
|
||||
return properties_id_less (a, b);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A properties set
|
||||
|
|
@ -258,8 +278,14 @@ public:
|
|||
return m_map.find (name_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the hash value for the properties ID set
|
||||
*/
|
||||
size_t hash () const;
|
||||
|
||||
private:
|
||||
map_type m_map;
|
||||
mutable size_t m_hash;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1651,7 +1651,7 @@ bool_and_or_not_local_operation_with_properties<TS, TI, TR>::do_compute_local (d
|
|||
|
||||
db::EdgeProcessor ep;
|
||||
|
||||
std::map<db::properties_id_type, std::pair<tl::slist<TS>, std::set<TI> > > by_prop_id;
|
||||
std::map<db::properties_id_type, std::pair<tl::slist<TS>, std::set<TI> >, ComparePropertiesIds> by_prop_id;
|
||||
|
||||
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
|
||||
|
|
@ -1841,7 +1841,7 @@ two_bool_and_not_local_operation_with_properties<TS, TI, TR>::do_compute_local (
|
|||
|
||||
db::EdgeProcessor ep;
|
||||
|
||||
std::map<db::properties_id_type, std::pair<tl::slist<TS>, std::set<TI> > > by_prop_id;
|
||||
std::map<db::properties_id_type, std::pair<tl::slist<TS>, std::set<TI> >, ComparePropertiesIds> by_prop_id;
|
||||
|
||||
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
|
||||
|
|
|
|||
|
|
@ -451,3 +451,24 @@ TEST(PropertyIdsByNameAndValue)
|
|||
EXPECT_EQ (ps2s (res), ps2s (ref));
|
||||
}
|
||||
|
||||
TEST(PropertiesSetHash)
|
||||
{
|
||||
db::PropertiesRepository rp;
|
||||
|
||||
db::PropertiesSet ps;
|
||||
EXPECT_EQ (ps.hash (), size_t (0));
|
||||
EXPECT_EQ (db::hash_for_properties_id (0), size_t (0));
|
||||
|
||||
ps.insert_by_id (rp.prop_name_id (1), rp.prop_value_id ("A"));
|
||||
ps.insert_by_id (rp.prop_name_id (2), rp.prop_value_id ("B"));
|
||||
|
||||
size_t h1 = ps.hash ();
|
||||
EXPECT_EQ (db::hash_for_properties_id (rp.properties_id (ps)), h1);
|
||||
|
||||
db::PropertiesSet ps2;
|
||||
ps2.insert_by_id (rp.prop_name_id (2), rp.prop_value_id ("B"));
|
||||
ps2.insert_by_id (rp.prop_name_id (1), rp.prop_value_id ("A"));
|
||||
|
||||
EXPECT_EQ (ps2.hash (), h1);
|
||||
EXPECT_EQ (db::hash_for_properties_id (rp.properties_id (ps2)), h1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2027,58 +2027,53 @@ TEST(40_with_holes)
|
|||
EXPECT_EQ (r.filtered (db::HoleCountFilter (3, 5, true)).to_string (), "(0,0;0,200;100,200;100,0/10,10;20,10;20,20;10,20/30,30;40,30;40,40;30,40)");
|
||||
}
|
||||
|
||||
template <class Iter>
|
||||
static std::string sip2s (const Iter &si)
|
||||
{
|
||||
std::vector<std::string> pmap;
|
||||
|
||||
for (Iter s = si; ! s.at_end (); ++s) {
|
||||
pmap.push_back (std::string (db::properties (s.prop_id ()).to_dict_var ().to_string ()) + ":" + s->to_string ());
|
||||
}
|
||||
|
||||
std::sort (pmap.begin (), pmap.end ());
|
||||
return tl::join (pmap, "\n");
|
||||
}
|
||||
|
||||
TEST(50_PropertiesFlat)
|
||||
{
|
||||
db::Region r;
|
||||
|
||||
db::PropertiesSet ps;
|
||||
|
||||
ps.insert (tl::Variant ("id"), 1);
|
||||
db::properties_id_type pid1 = db::properties_id (ps);
|
||||
|
||||
ps.clear ();
|
||||
ps.insert (tl::Variant ("id"), 42);
|
||||
db::properties_id_type pid42 = db::properties_id (ps);
|
||||
|
||||
// Fill flat region with parts with properties
|
||||
|
||||
r.insert (db::Box (0, 0, 100, 200));
|
||||
r.insert (db::BoxWithProperties (db::Box (1, 2, 101, 202), 1));
|
||||
r.insert (db::BoxWithProperties (db::Box (1, 2, 101, 202), pid1));
|
||||
r.insert (db::Box (10, 20, 110, 220));
|
||||
r.insert (db::BoxWithProperties (db::Box (11, 12, 111, 212), 42));
|
||||
r.insert (db::BoxWithProperties (db::Box (11, 12, 111, 212), pid42));
|
||||
|
||||
EXPECT_EQ (r.count (), size_t (4));
|
||||
|
||||
db::Region::const_iterator s = r.begin ();
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (0));
|
||||
EXPECT_EQ (s->to_string (), "(0,0;0,200;100,200;100,0)");
|
||||
++s;
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (0));
|
||||
EXPECT_EQ (s->to_string (), "(10,20;10,220;110,220;110,20)");
|
||||
++s;
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (1));
|
||||
EXPECT_EQ (s->to_string (), "(1,2;1,202;101,202;101,2)");
|
||||
++s;
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (42));
|
||||
EXPECT_EQ (s->to_string (), "(11,12;11,212;111,212;111,12)");
|
||||
++s;
|
||||
EXPECT_EQ (s.at_end (), true);
|
||||
EXPECT_EQ (sip2s (r.begin ()),
|
||||
"{id=>1}:(1,2;1,202;101,202;101,2)\n"
|
||||
"{id=>42}:(11,12;11,212;111,212;111,12)\n"
|
||||
"{}:(0,0;0,200;100,200;100,0)\n"
|
||||
"{}:(10,20;10,220;110,220;110,20)"
|
||||
);
|
||||
|
||||
s = r.begin_merged ();
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (0));
|
||||
// property #0 elements are merged
|
||||
EXPECT_EQ (s->to_string (), "(0,0;0,200;10,200;10,220;110,220;110,20;100,20;100,0)");
|
||||
++s;
|
||||
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (1));
|
||||
// a single property #1 element
|
||||
EXPECT_EQ (s->to_string (), "(1,2;1,202;101,202;101,2)");
|
||||
++s;
|
||||
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (42));
|
||||
// a single property #42 element
|
||||
EXPECT_EQ (s->to_string (), "(11,12;11,212;111,212;111,12)");
|
||||
++s;
|
||||
|
||||
EXPECT_EQ (s.at_end (), true);
|
||||
EXPECT_EQ (sip2s (r.begin_merged ()),
|
||||
"{id=>1}:(1,2;1,202;101,202;101,2)\n"
|
||||
"{id=>42}:(11,12;11,212;111,212;111,12)\n"
|
||||
"{}:(0,0;0,200;10,200;10,220;110,220;110,20;100,20;100,0)"
|
||||
);
|
||||
}
|
||||
|
||||
// "+" operator with properties (issue #1373)
|
||||
|
|
@ -2086,9 +2081,14 @@ TEST(50b_PropertiesFlat)
|
|||
{
|
||||
db::Region r, rr;
|
||||
|
||||
db::PropertiesSet ps;
|
||||
|
||||
ps.insert (tl::Variant ("id"), 1);
|
||||
db::properties_id_type pid1 = db::properties_id (ps);
|
||||
|
||||
r.insert (db::Box (0, 0, 10, 20));
|
||||
rr.insert (db::Box (0, 0, 100, 200));
|
||||
rr.insert (db::BoxWithProperties (db::Box (1, 2, 101, 202), 1));
|
||||
rr.insert (db::BoxWithProperties (db::Box (1, 2, 101, 202), pid1));
|
||||
|
||||
EXPECT_EQ ((db::Region () + rr).to_string (), "(0,0;0,200;100,200;100,0);(1,2;1,202;101,202;101,2)");
|
||||
EXPECT_EQ ((rr + db::Region ()).to_string (), "(0,0;0,200;100,200;100,0);(1,2;1,202;101,202;101,2)");
|
||||
|
|
@ -2101,15 +2101,24 @@ TEST(50b_PropertiesFlat)
|
|||
|
||||
TEST(51_PropertiesFlatFromLayout)
|
||||
{
|
||||
db::PropertiesSet ps;
|
||||
|
||||
ps.insert (tl::Variant ("id"), 1);
|
||||
db::properties_id_type pid1 = db::properties_id (ps);
|
||||
|
||||
ps.clear ();
|
||||
ps.insert (tl::Variant ("id"), 42);
|
||||
db::properties_id_type pid42 = db::properties_id (ps);
|
||||
|
||||
db::Layout ly;
|
||||
unsigned int li = ly.insert_layer ();
|
||||
db::Cell &top = ly.cell (ly.add_cell ("TOP"));
|
||||
|
||||
db::Shapes &si = top.shapes (li);
|
||||
si.insert (db::Box (0, 0, 100, 200));
|
||||
si.insert (db::BoxWithProperties (db::Box (1, 2, 101, 202), 1));
|
||||
si.insert (db::BoxWithProperties (db::Box (1, 2, 101, 202), pid1));
|
||||
si.insert (db::Box (10, 20, 110, 220));
|
||||
si.insert (db::BoxWithProperties (db::Box (11, 12, 111, 212), 42));
|
||||
si.insert (db::BoxWithProperties (db::Box (11, 12, 111, 212), pid42));
|
||||
|
||||
// NOTE: without specific "property only" selector -> properties are ignored.
|
||||
|
||||
|
|
@ -2117,58 +2126,30 @@ TEST(51_PropertiesFlatFromLayout)
|
|||
|
||||
EXPECT_EQ (r.count (), size_t (4));
|
||||
|
||||
db::Region::const_iterator s = r.begin ();
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (0));
|
||||
EXPECT_EQ (s->to_string (), "(0,0;0,200;100,200;100,0)");
|
||||
++s;
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (0));
|
||||
EXPECT_EQ (s->to_string (), "(10,20;10,220;110,220;110,20)");
|
||||
++s;
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (0));
|
||||
EXPECT_EQ (s->to_string (), "(1,2;1,202;101,202;101,2)");
|
||||
++s;
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (0));
|
||||
EXPECT_EQ (s->to_string (), "(11,12;11,212;111,212;111,12)");
|
||||
++s;
|
||||
EXPECT_EQ (s.at_end (), true);
|
||||
EXPECT_EQ (sip2s (r.begin ()),
|
||||
"{}:(0,0;0,200;100,200;100,0)\n"
|
||||
"{}:(1,2;1,202;101,202;101,2)\n"
|
||||
"{}:(10,20;10,220;110,220;110,20)\n"
|
||||
"{}:(11,12;11,212;111,212;111,12)"
|
||||
);
|
||||
|
||||
s = r.begin_merged ();
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (0));
|
||||
// property #0 elements are merged
|
||||
EXPECT_EQ (s->to_string (), "(0,0;0,200;1,200;1,202;10,202;10,220;110,220;110,212;111,212;111,12;101,12;101,2;100,2;100,0)");
|
||||
++s;
|
||||
|
||||
EXPECT_EQ (s.at_end (), true);
|
||||
EXPECT_EQ (sip2s (r.begin_merged ()),
|
||||
"{}:(0,0;0,200;1,200;1,202;10,202;10,220;110,220;110,212;111,212;111,12;101,12;101,2;100,2;100,0)"
|
||||
);
|
||||
|
||||
// NOTE: now with explicit propertly-only source
|
||||
db::RecursiveShapeIterator rsi (ly, top, li);
|
||||
rsi.shape_flags (db::ShapeIterator::AllWithProperties);
|
||||
r = db::Region (rsi);
|
||||
|
||||
EXPECT_EQ (r.count (), size_t (2));
|
||||
EXPECT_EQ (sip2s (r.begin ()),
|
||||
"{}:(1,2;1,202;101,202;101,2)\n"
|
||||
"{}:(11,12;11,212;111,212;111,12)"
|
||||
);
|
||||
|
||||
s = r.begin ();
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (0));
|
||||
EXPECT_EQ (s->to_string (), "(1,2;1,202;101,202;101,2)");
|
||||
++s;
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (0));
|
||||
EXPECT_EQ (s->to_string (), "(11,12;11,212;111,212;111,12)");
|
||||
++s;
|
||||
EXPECT_EQ (s.at_end (), true);
|
||||
|
||||
s = r.begin_merged ();
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (0));
|
||||
// property #0 elements are merged
|
||||
EXPECT_EQ (s->to_string (), "(1,2;1,202;11,202;11,212;111,212;111,12;101,12;101,2)");
|
||||
++s;
|
||||
EXPECT_EQ (sip2s (r.begin_merged ()),
|
||||
"{}:(1,2;1,202;11,202;11,212;111,212;111,12;101,12;101,2)"
|
||||
);
|
||||
|
||||
// NOTE: now with regarding properties
|
||||
rsi = db::RecursiveShapeIterator (ly, top, li);
|
||||
|
|
@ -2177,58 +2158,40 @@ TEST(51_PropertiesFlatFromLayout)
|
|||
|
||||
EXPECT_EQ (r.count (), size_t (4));
|
||||
|
||||
s = r.begin ();
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (0));
|
||||
EXPECT_EQ (s->to_string (), "(0,0;0,200;100,200;100,0)");
|
||||
++s;
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (0));
|
||||
EXPECT_EQ (s->to_string (), "(10,20;10,220;110,220;110,20)");
|
||||
++s;
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (1));
|
||||
EXPECT_EQ (s->to_string (), "(1,2;1,202;101,202;101,2)");
|
||||
++s;
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (42));
|
||||
EXPECT_EQ (s->to_string (), "(11,12;11,212;111,212;111,12)");
|
||||
++s;
|
||||
EXPECT_EQ (s.at_end (), true);
|
||||
EXPECT_EQ (sip2s (r.begin ()),
|
||||
"{id=>1}:(1,2;1,202;101,202;101,2)\n"
|
||||
"{id=>42}:(11,12;11,212;111,212;111,12)\n"
|
||||
"{}:(0,0;0,200;100,200;100,0)\n"
|
||||
"{}:(10,20;10,220;110,220;110,20)"
|
||||
);
|
||||
|
||||
s = r.begin_merged ();
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (0));
|
||||
// property #0 elements are merged
|
||||
EXPECT_EQ (s->to_string (), "(0,0;0,200;10,200;10,220;110,220;110,20;100,20;100,0)");
|
||||
++s;
|
||||
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (1));
|
||||
// a single property #1 element
|
||||
EXPECT_EQ (s->to_string (), "(1,2;1,202;101,202;101,2)");
|
||||
++s;
|
||||
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (42));
|
||||
// a single property #42 element
|
||||
EXPECT_EQ (s->to_string (), "(11,12;11,212;111,212;111,12)");
|
||||
++s;
|
||||
|
||||
EXPECT_EQ (s.at_end (), true);
|
||||
EXPECT_EQ (sip2s (r.begin_merged ()),
|
||||
"{id=>1}:(1,2;1,202;101,202;101,2)\n"
|
||||
"{id=>42}:(11,12;11,212;111,212;111,12)\n"
|
||||
"{}:(0,0;0,200;10,200;10,220;110,220;110,20;100,20;100,0)"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(52_PropertiesDeep)
|
||||
{
|
||||
db::PropertiesSet ps;
|
||||
|
||||
ps.insert (tl::Variant ("id"), 1);
|
||||
db::properties_id_type pid1 = db::properties_id (ps);
|
||||
|
||||
ps.clear ();
|
||||
ps.insert (tl::Variant ("id"), 42);
|
||||
db::properties_id_type pid42 = db::properties_id (ps);
|
||||
|
||||
db::DeepShapeStore dss ("TOP", 0.001);
|
||||
db::Region r (dss);
|
||||
|
||||
// Fill flat region with parts with properties
|
||||
|
||||
r.insert (db::Box (0, 0, 100, 200));
|
||||
r.insert (db::BoxWithProperties (db::Box (1, 2, 101, 202), 1));
|
||||
r.insert (db::BoxWithProperties (db::Box (1, 2, 101, 202), pid1));
|
||||
r.insert (db::Box (10, 20, 110, 220));
|
||||
r.insert (db::BoxWithProperties (db::Box (11, 12, 111, 212), 42));
|
||||
r.insert (db::BoxWithProperties (db::Box (11, 12, 111, 212), pid42));
|
||||
|
||||
EXPECT_EQ (r.count (), size_t (4));
|
||||
|
||||
|
|
@ -2242,11 +2205,11 @@ TEST(52_PropertiesDeep)
|
|||
EXPECT_EQ (s->to_string (), "(10,20;10,220;110,220;110,20)");
|
||||
++s;
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (1));
|
||||
EXPECT_EQ (s.prop_id (), pid1);
|
||||
EXPECT_EQ (s->to_string (), "(1,2;1,202;101,202;101,2)");
|
||||
++s;
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (42));
|
||||
EXPECT_EQ (s.prop_id (), pid42);
|
||||
EXPECT_EQ (s->to_string (), "(11,12;11,212;111,212;111,12)");
|
||||
++s;
|
||||
EXPECT_EQ (s.at_end (), true);
|
||||
|
|
@ -2259,13 +2222,13 @@ TEST(52_PropertiesDeep)
|
|||
++s;
|
||||
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (1));
|
||||
EXPECT_EQ (s.prop_id (), pid1);
|
||||
// a single property #1 element
|
||||
EXPECT_EQ (s->to_string (), "(1,2;1,202;101,202;101,2)");
|
||||
++s;
|
||||
|
||||
EXPECT_EQ (s.at_end (), false);
|
||||
EXPECT_EQ (s.prop_id (), db::properties_id_type (42));
|
||||
EXPECT_EQ (s.prop_id (), pid42);
|
||||
// a single property #42 element
|
||||
EXPECT_EQ (s->to_string (), "(11,12;11,212;111,212;111,12)");
|
||||
++s;
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ HEADERS = \
|
|||
tlEvents.h \
|
||||
tlFixedVector.h \
|
||||
tlGlobPattern.h \
|
||||
tlHash.h \
|
||||
tlHeap.h \
|
||||
tlHttpStream.h \
|
||||
tlInclude.h \
|
||||
|
|
|
|||
|
|
@ -0,0 +1,347 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2024 Matthias Koefferlein
|
||||
|
||||
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, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HDR_tlHash
|
||||
#define HDR_tlHash
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <functional>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "tlSList.h"
|
||||
|
||||
/**
|
||||
* This header defines some generic hash functions
|
||||
* for use with std::unordered_map and std::unordered_set
|
||||
*/
|
||||
|
||||
namespace std
|
||||
{
|
||||
inline size_t hcombine (size_t h1, size_t h2)
|
||||
{
|
||||
return (h1 << 4) ^ (h1 >> 4) ^ h2;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline size_t hfunc (const T &t)
|
||||
{
|
||||
hash <T> hf;
|
||||
return hf (t);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline size_t hfunc (const T &t, size_t h)
|
||||
{
|
||||
hash <T> hf;
|
||||
return hcombine (h, hf (t));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
size_t hfunc_iterable (const T &o, size_t h)
|
||||
{
|
||||
for (auto i = o.begin (); i != o.end (); ++i) {
|
||||
h = hfunc (*i, h);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generic hash for a pair of objects
|
||||
*/
|
||||
|
||||
template <class T1, class T2>
|
||||
size_t hfunc (const std::pair <T1, T2> &o, size_t h)
|
||||
{
|
||||
return hfunc (o.first, hfunc (o.second, h));
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
size_t hfunc (const std::pair <T1, T2> &o)
|
||||
{
|
||||
return hfunc (o.first, hfunc (o.second));
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
struct hash <std::pair <T1, T2> >
|
||||
{
|
||||
size_t operator() (const std::pair<T1, T2> &o) const
|
||||
{
|
||||
return hfunc (o);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Generic hash for an unordered set
|
||||
*/
|
||||
|
||||
template <class T>
|
||||
size_t hfunc (const std::unordered_set <T> &o, size_t h)
|
||||
{
|
||||
return hfunc_iterable (o, h);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
size_t hfunc (const std::unordered_set <T> &o)
|
||||
{
|
||||
return hfunc (o, size_t (0));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct hash <std::unordered_set <T> >
|
||||
{
|
||||
size_t operator() (const std::unordered_set<T> &o) const
|
||||
{
|
||||
return hfunc (o);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Generic hash for a vector
|
||||
*/
|
||||
|
||||
template <class T>
|
||||
size_t hfunc (const std::vector <T> &o, size_t h)
|
||||
{
|
||||
return hfunc_iterable (o, h);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
size_t hfunc (const std::vector <T> &o)
|
||||
{
|
||||
return hfunc (o, size_t (0));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct hash <std::vector <T> >
|
||||
{
|
||||
size_t operator() (const std::vector<T> &o) const
|
||||
{
|
||||
return hfunc (o);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Generic hash for a list
|
||||
*/
|
||||
|
||||
template <class T>
|
||||
size_t hfunc (const std::list <T> &o, size_t h)
|
||||
{
|
||||
return hfunc_iterable (o, h);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
size_t hfunc (const std::list <T> &o)
|
||||
{
|
||||
return hfunc (o, size_t (0));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct hash <std::list <T> >
|
||||
{
|
||||
size_t operator() (const std::list<T> &o) const
|
||||
{
|
||||
return hfunc (o);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Generic hash for a tl::slist
|
||||
*/
|
||||
|
||||
template <class T>
|
||||
size_t hfunc (const tl::slist <T> &o, size_t h)
|
||||
{
|
||||
return hfunc_iterable (o, h);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
size_t hfunc (const tl::slist <T> &o)
|
||||
{
|
||||
return hfunc (o, size_t (0));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct hash <tl::slist <T> >
|
||||
{
|
||||
size_t operator() (const tl::slist<T> &o) const
|
||||
{
|
||||
return hfunc (o);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Generic hash for an ordered set
|
||||
*/
|
||||
|
||||
template <class T>
|
||||
size_t hfunc (const std::set <T> &o, size_t h)
|
||||
{
|
||||
return hfunc_iterable (o, h);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
size_t hfunc (const std::set <T> &o)
|
||||
{
|
||||
return hfunc (o, size_t (0));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct hash <std::set <T> >
|
||||
{
|
||||
size_t operator() (const std::set<T> &o) const
|
||||
{
|
||||
return hfunc (o);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Generic hash for std::multiset
|
||||
*/
|
||||
|
||||
template <class T>
|
||||
size_t hfunc (const std::multiset <T> &o, size_t h)
|
||||
{
|
||||
return hfunc_iterable (o, h);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
size_t hfunc (const std::multiset <T> &o)
|
||||
{
|
||||
return hfunc (o, size_t (0));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct hash <std::multiset <T> >
|
||||
{
|
||||
size_t operator() (const std::multiset<T> &o) const
|
||||
{
|
||||
return hfunc (o);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Generic hash for an unordered map
|
||||
*/
|
||||
|
||||
template <class T1, class T2>
|
||||
size_t hfunc (const std::unordered_map<T1, T2> &o, size_t h)
|
||||
{
|
||||
for (typename std::unordered_map<T1, T2>::const_iterator i = o.begin (); i != o.end (); ++i) {
|
||||
h = hfunc (i->first, hfunc (i->second, h));
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
size_t hfunc (const std::unordered_map<T1, T2> &o)
|
||||
{
|
||||
return hfunc (o, size_t (0));
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
struct hash <std::unordered_map<T1, T2> >
|
||||
{
|
||||
size_t operator() (const std::unordered_map<T1, T2> &o) const
|
||||
{
|
||||
return hfunc (o);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Generic hash for an ordered map
|
||||
*/
|
||||
|
||||
template <class T1, class T2>
|
||||
size_t hfunc (const std::map<T1, T2> &o, size_t h)
|
||||
{
|
||||
for (typename std::map<T1, T2>::const_iterator i = o.begin (); i != o.end (); ++i) {
|
||||
h = hfunc (i->first, hfunc (i->second, h));
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
size_t hfunc (const std::map<T1, T2> &o)
|
||||
{
|
||||
return hfunc (o, size_t (0));
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
struct hash <std::map<T1, T2> >
|
||||
{
|
||||
size_t operator() (const std::map<T1, T2> &o) const
|
||||
{
|
||||
return hfunc (o);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Generic hash for std::multimap
|
||||
*/
|
||||
|
||||
template <class T1, class T2>
|
||||
size_t hfunc (const std::multimap<T1, T2> &o, size_t h)
|
||||
{
|
||||
for (typename std::multimap<T1, T2>::const_iterator i = o.begin (); i != o.end (); ++i) {
|
||||
h = hfunc (i->first, hfunc (i->second, h));
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
size_t hfunc (const std::multimap<T1, T2> &o)
|
||||
{
|
||||
return hfunc (o, size_t (0));
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
struct hash <std::multimap<T1, T2> >
|
||||
{
|
||||
size_t operator() (const std::multimap<T1, T2> &o) const
|
||||
{
|
||||
return hfunc (o);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a pointer hash from the pointer's value
|
||||
*/
|
||||
template <class X>
|
||||
struct ptr_hash_from_value
|
||||
{
|
||||
size_t operator() (const X *ptr) const
|
||||
{
|
||||
return ptr ? hash<X> () (*ptr) : 0;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
#include "tlVariant.h"
|
||||
#include "tlInternational.h"
|
||||
#include "tlString.h"
|
||||
#include "tlHash.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <limits>
|
||||
|
|
@ -985,6 +986,74 @@ Variant::operator= (const Variant &v)
|
|||
return *this;
|
||||
}
|
||||
|
||||
size_t
|
||||
Variant::hash () const
|
||||
{
|
||||
size_t h = 0;
|
||||
|
||||
if (m_type == t_double) {
|
||||
h = std::hfunc (m_var.m_double);
|
||||
} else if (m_type == t_float) {
|
||||
h = std::hfunc (m_var.m_float);
|
||||
} else if (m_type == t_bool) {
|
||||
h = std::hfunc (m_var.m_bool);
|
||||
} else if (m_type == t_uchar) {
|
||||
h = std::hfunc (m_var.m_uchar);
|
||||
} else if (m_type == t_schar) {
|
||||
h = std::hfunc (m_var.m_schar);
|
||||
} else if (m_type == t_char) {
|
||||
h = std::hfunc (m_var.m_char);
|
||||
} else if (m_type == t_ushort) {
|
||||
h = std::hfunc (m_var.m_ushort);
|
||||
} else if (m_type == t_short) {
|
||||
h = std::hfunc (m_var.m_short);
|
||||
} else if (m_type == t_uint) {
|
||||
h = std::hfunc (m_var.m_uint);
|
||||
} else if (m_type == t_int) {
|
||||
h = std::hfunc (m_var.m_int);
|
||||
} else if (m_type == t_ulong) {
|
||||
h = std::hfunc (m_var.m_ulong);
|
||||
} else if (m_type == t_long) {
|
||||
h = std::hfunc (m_var.m_long);
|
||||
} else if (m_type == t_longlong) {
|
||||
h = std::hfunc (m_var.m_longlong);
|
||||
} else if (m_type == t_ulonglong) {
|
||||
h = std::hfunc (m_var.m_ulonglong);
|
||||
#if defined(HAVE_64BIT_COORD)
|
||||
} else if (m_type == t_int128) {
|
||||
h = std::hfunc (m_var.m_int128);
|
||||
#endif
|
||||
} else if (m_type == t_id) {
|
||||
h = std::hfunc (m_var.m_id);
|
||||
} else if (m_type == t_bytearray) {
|
||||
h = std::hfunc (*m_var.m_bytearray);
|
||||
#if defined(HAVE_QT)
|
||||
} else if (m_type == t_qstring) {
|
||||
h = std::hfunc (*m_var.m_qstring);
|
||||
} else if (m_type == t_qbytearray) {
|
||||
h = std::hfunc (*m_var.m_qbytearray);
|
||||
#endif
|
||||
} else if (m_type == t_stdstring) {
|
||||
h = std::hfunc (*m_var.m_stdstring);
|
||||
} else if (m_type == t_string) {
|
||||
for (const char *cp = m_string; *cp; ++cp) {
|
||||
h = std::hfunc (*cp, h);
|
||||
}
|
||||
} else if (m_type == t_list) {
|
||||
h = std::hfunc (*m_var.m_list);
|
||||
} else if (m_type == t_array) {
|
||||
h = std::hfunc (*m_var.m_array);
|
||||
} else if (m_type == t_user) {
|
||||
// NOTE: this involves pointers ...
|
||||
h = std::hfunc (m_var.mp_user.object, std::hfunc (m_var.mp_user.cls, 0));
|
||||
} else if (m_type == t_user_ref) {
|
||||
const WeakOrSharedPtr *ptr = reinterpret_cast<const WeakOrSharedPtr *> (m_var.mp_user_ref.ptr);
|
||||
h = std::hfunc (ptr->get (), std::hfunc (m_var.mp_user_ref.cls, 0));
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
inline bool
|
||||
is_integer_type (Variant::type type)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1675,6 +1675,11 @@ public:
|
|||
*/
|
||||
std::string to_parsable_string () const;
|
||||
|
||||
/**
|
||||
* @brief Gets a hash value for the variant
|
||||
*/
|
||||
size_t hash () const;
|
||||
|
||||
private:
|
||||
type m_type;
|
||||
|
||||
|
|
@ -1815,5 +1820,20 @@ template<> TL_PUBLIC bool test_extractor_impl<Variant> (tl::Extractor &ex, Varia
|
|||
|
||||
} // namespace tl
|
||||
|
||||
namespace std
|
||||
{
|
||||
/**
|
||||
* @brief That hash function for tl::Variant
|
||||
*/
|
||||
template <>
|
||||
struct hash <tl::Variant>
|
||||
{
|
||||
size_t operator() (const tl::Variant &o) const
|
||||
{
|
||||
return o.hash ();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue