mirror of
https://github.com/verilator/verilator.git
synced 2025-04-30 12:36:53 +00:00
Internals: Rename templated types to be T_*. Use Euler hashing.
This commit is contained in:
parent
5187096bf9
commit
dddc51b75c
@ -67,7 +67,7 @@ inline size_t vl_hash_bytes(const void* vbufp, size_t nbytes) {
|
|||||||
|
|
||||||
template <> inline size_t
|
template <> inline size_t
|
||||||
vl_hash<unsigned int>::operator()(const unsigned int& k) const {
|
vl_hash<unsigned int>::operator()(const unsigned int& k) const {
|
||||||
return vl_hash_bytes(&k, sizeof(k));
|
return k;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> inline bool
|
template <> inline bool
|
||||||
@ -93,7 +93,9 @@ vl_equal_to<std::string>::operator()(const std::string& a,
|
|||||||
|
|
||||||
template <typename T> struct vl_hash<T*> {
|
template <typename T> struct vl_hash<T*> {
|
||||||
size_t operator()(T* kp) const {
|
size_t operator()(T* kp) const {
|
||||||
return vl_hash_bytes(&kp, sizeof(kp));
|
return ((sizeof(size_t) == sizeof(kp))
|
||||||
|
? reinterpret_cast<size_t>(kp)
|
||||||
|
: vl_hash_bytes(&kp, sizeof(kp)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -106,13 +108,13 @@ template <typename T> struct vl_equal_to<T*> {
|
|||||||
//===================================================================
|
//===================================================================
|
||||||
//
|
//
|
||||||
/// Functional clone of the std::unordered_set hash table.
|
/// Functional clone of the std::unordered_set hash table.
|
||||||
template <class Key,
|
template <class T_Key,
|
||||||
class Hash = vl_hash<Key>,
|
class T_Hash = vl_hash<T_Key>,
|
||||||
class Equal = vl_equal_to<Key> > class vl_unordered_set {
|
class T_Equal = vl_equal_to<T_Key> >
|
||||||
|
class vl_unordered_set {
|
||||||
public:
|
public:
|
||||||
// TYPES
|
// TYPES
|
||||||
typedef std::list<Key> Bucket;
|
typedef std::list<T_Key> Bucket;
|
||||||
typedef vluint64_t size_type;
|
|
||||||
enum RehashType {GROW, SHRINK};
|
enum RehashType {GROW, SHRINK};
|
||||||
|
|
||||||
template <class KK, class VV,
|
template <class KK, class VV,
|
||||||
@ -121,26 +123,26 @@ public:
|
|||||||
class iterator {
|
class iterator {
|
||||||
protected:
|
protected:
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
size_type m_bucketIdx; // Bucket this iterator points into.
|
size_t m_bucketIdx; // Bucket this iterator points into.
|
||||||
typename Bucket::iterator m_bit; // Bucket-local iterator.
|
typename Bucket::iterator m_bit; // Bucket-local iterator.
|
||||||
const vl_unordered_set* m_setp; // The containing set.
|
const vl_unordered_set* m_setp; // The containing set.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
iterator(size_type bucketIdx, typename Bucket::iterator bit,
|
iterator(size_t bucketIdx, typename Bucket::iterator bit,
|
||||||
const vl_unordered_set* setp)
|
const vl_unordered_set* setp)
|
||||||
: m_bucketIdx(bucketIdx), m_bit(bit), m_setp(setp) {}
|
: m_bucketIdx(bucketIdx), m_bit(bit), m_setp(setp) {}
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
const Key& operator*() const {
|
const T_Key& operator*() const {
|
||||||
return *m_bit;
|
return *m_bit;
|
||||||
}
|
}
|
||||||
// This should really be 'const Key*' type for unordered_set,
|
// This should really be 'const T_Key*' type for unordered_set,
|
||||||
// however this iterator is shared with unordered_map whose
|
// however this iterator is shared with unordered_map whose
|
||||||
// operator-> returns a non-const value_type*, so keep this
|
// operator-> returns a non-const ValueType*, so keep this
|
||||||
// non-const to avoid having to define a whole separate iterator
|
// non-const to avoid having to define a whole separate iterator
|
||||||
// for unordered_map.
|
// for unordered_map.
|
||||||
Key* operator->() const {
|
T_Key* operator->() const {
|
||||||
return &(*m_bit);
|
return &(*m_bit);
|
||||||
}
|
}
|
||||||
bool operator==(const iterator& other) const {
|
bool operator==(const iterator& other) const {
|
||||||
@ -180,14 +182,14 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
size_type m_numElements; // Number of entries present.
|
size_t m_numElements; // Number of entries present.
|
||||||
size_type m_log2Buckets; // Log-base-2 of the number of buckets.
|
size_t m_log2Buckets; // Log-base-2 of the number of buckets.
|
||||||
mutable Bucket* m_bucketsp; // Hash table buckets. May be NULL;
|
mutable Bucket* m_bucketsp; // Hash table buckets. May be NULL;
|
||||||
// // we'll allocate it on the fly when
|
// // we'll allocate it on the fly when
|
||||||
// // the first entries are created.
|
// // the first entries are created.
|
||||||
Bucket m_emptyBucket; // A fake bucket, used to construct end().
|
Bucket m_emptyBucket; // A fake bucket, used to construct end().
|
||||||
Hash m_hash; // Hash function provider.
|
T_Hash m_hash; // Hash function provider.
|
||||||
Equal m_equal; // Equal-to function provider.
|
T_Equal m_equal; // Equal-to function provider.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
@ -206,7 +208,7 @@ public:
|
|||||||
, m_equal() {
|
, m_equal() {
|
||||||
if (other.m_bucketsp) {
|
if (other.m_bucketsp) {
|
||||||
m_bucketsp = new Bucket[numBuckets()];
|
m_bucketsp = new Bucket[numBuckets()];
|
||||||
for (size_type i = 0; i < numBuckets(); i++) {
|
for (size_t i = 0; i < numBuckets(); i++) {
|
||||||
m_bucketsp[i] = other.m_bucketsp[i];
|
m_bucketsp[i] = other.m_bucketsp[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -220,7 +222,7 @@ public:
|
|||||||
m_log2Buckets = other.m_log2Buckets;
|
m_log2Buckets = other.m_log2Buckets;
|
||||||
if (other.m_bucketsp) {
|
if (other.m_bucketsp) {
|
||||||
m_bucketsp = new Bucket[numBuckets()];
|
m_bucketsp = new Bucket[numBuckets()];
|
||||||
for (size_type i = 0; i < numBuckets(); i++) {
|
for (size_t i = 0; i < numBuckets(); i++) {
|
||||||
m_bucketsp[i] = other.m_bucketsp[i];
|
m_bucketsp[i] = other.m_bucketsp[i];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -262,20 +264,43 @@ public:
|
|||||||
|
|
||||||
bool empty() const { return m_numElements == 0; }
|
bool empty() const { return m_numElements == 0; }
|
||||||
|
|
||||||
size_type size() const { return m_numElements; }
|
size_t size() const { return m_numElements; }
|
||||||
|
|
||||||
size_type count(const Key& key) const {
|
size_t count(const T_Key& key) const {
|
||||||
return (find(key) == end()) ? 0 : 1;
|
return (find(key) == end()) ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator find_internal(const Key& key, size_type& bucketIdxOut) {
|
size_t hashToBucket(size_t hashVal) const {
|
||||||
size_type hash = m_hash.operator()(key);
|
return hashToBucket(hashVal, m_log2Buckets);
|
||||||
bucketIdxOut = hash & ((VL_ULL(1) << m_log2Buckets) - 1);
|
}
|
||||||
|
static size_t hashToBucket(size_t hashVal, unsigned log2Buckets) {
|
||||||
|
// Fibonacci hashing
|
||||||
|
// See https://probablydance.com/2018/06/16/fibonacci-hashing-the-optimization-that-the-world-forgot-or-a-better-alternative-to-integer-modulo/
|
||||||
|
//
|
||||||
|
// * The magic numbers below are UINT_MAX/phi where phi is the
|
||||||
|
// golden ratio number (1.618...) for either 64- or 32-bit
|
||||||
|
// values of UINT_MAX.
|
||||||
|
//
|
||||||
|
// * Fibonacci hashing mixes the result of the client's hash
|
||||||
|
// function further. This permits the use of very fast client
|
||||||
|
// hash funcs (like just returning the int or pointer value as
|
||||||
|
// is!) and tolerates crappy client hash functions pretty well.
|
||||||
|
size_t mult = hashVal * ((sizeof(size_t) == 8)
|
||||||
|
? VL_ULL(11400714819323198485)
|
||||||
|
: 2654435769lu);
|
||||||
|
size_t result = (mult >> (((sizeof(size_t) == 8)
|
||||||
|
? 64 : 32) - log2Buckets));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator find_internal(const T_Key& key, size_t& bucketIdxOut) {
|
||||||
|
size_t hash = m_hash.operator()(key);
|
||||||
|
bucketIdxOut = hashToBucket(hash);
|
||||||
initBuckets();
|
initBuckets();
|
||||||
Bucket* bucketp = &m_bucketsp[bucketIdxOut];
|
Bucket* bucketp = &m_bucketsp[bucketIdxOut];
|
||||||
|
|
||||||
for (typename Bucket::iterator it = bucketp->begin();
|
for (typename Bucket::iterator it = bucketp->begin();
|
||||||
it != bucketp->end(); ++it) {
|
it != bucketp->end(); ++it) {
|
||||||
if (m_equal.operator()(*it, key)) {
|
if (m_equal.operator()(*it, key)) {
|
||||||
return iterator(bucketIdxOut, it, this);
|
return iterator(bucketIdxOut, it, this);
|
||||||
}
|
}
|
||||||
@ -283,19 +308,19 @@ public:
|
|||||||
return end();
|
return end();
|
||||||
}
|
}
|
||||||
|
|
||||||
const_iterator find(const Key& key) const {
|
const_iterator find(const T_Key& key) const {
|
||||||
size_type bucketIdx;
|
size_t bucketIdx;
|
||||||
return const_cast<vl_unordered_set*>(this)->find_internal(key,
|
return const_cast<vl_unordered_set*>(this)->find_internal(key,
|
||||||
bucketIdx);
|
bucketIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator find(const Key& key) {
|
iterator find(const T_Key& key) {
|
||||||
size_type bucketIdx;
|
size_t bucketIdx;
|
||||||
return find_internal(key, bucketIdx);
|
return find_internal(key, bucketIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<iterator, bool> insert(const Key &val) {
|
std::pair<iterator, bool> insert(const T_Key &val) {
|
||||||
size_type bucketIdx;
|
size_t bucketIdx;
|
||||||
iterator existIt = find_internal(val, bucketIdx);
|
iterator existIt = find_internal(val, bucketIdx);
|
||||||
if (existIt != end()) {
|
if (existIt != end()) {
|
||||||
// Collision with existing element.
|
// Collision with existing element.
|
||||||
@ -330,8 +355,8 @@ public:
|
|||||||
return next_it;
|
return next_it;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type erase(const Key &key) {
|
size_t erase(const T_Key &key) {
|
||||||
size_type bucketIdx;
|
size_t bucketIdx;
|
||||||
iterator it = find_internal(key, bucketIdx);
|
iterator it = find_internal(key, bucketIdx);
|
||||||
if (it != end()) {
|
if (it != end()) {
|
||||||
m_bucketsp[bucketIdx].erase(it.bit());
|
m_bucketsp[bucketIdx].erase(it.bit());
|
||||||
@ -357,9 +382,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_type numBuckets() const { return (VL_ULL(1) << m_log2Buckets); }
|
size_t numBuckets() const { return (VL_ULL(1) << m_log2Buckets); }
|
||||||
|
|
||||||
Bucket* getBucket(size_type idx) {
|
Bucket* getBucket(size_t idx) {
|
||||||
initBuckets();
|
initBuckets();
|
||||||
return &m_bucketsp[idx];
|
return &m_bucketsp[idx];
|
||||||
}
|
}
|
||||||
@ -377,7 +402,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void rehash(RehashType rt) {
|
void rehash(RehashType rt) {
|
||||||
size_type new_log2Buckets;
|
size_t new_log2Buckets;
|
||||||
if (rt == GROW) {
|
if (rt == GROW) {
|
||||||
new_log2Buckets = m_log2Buckets + 2;
|
new_log2Buckets = m_log2Buckets + 2;
|
||||||
} else {
|
} else {
|
||||||
@ -390,14 +415,14 @@ private:
|
|||||||
new_log2Buckets = m_log2Buckets - 2;
|
new_log2Buckets = m_log2Buckets - 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type new_num_buckets = VL_ULL(1) << new_log2Buckets;
|
size_t new_num_buckets = VL_ULL(1) << new_log2Buckets;
|
||||||
Bucket* new_bucketsp = new Bucket[new_num_buckets];
|
Bucket* new_bucketsp = new Bucket[new_num_buckets];
|
||||||
|
|
||||||
for (size_type i=0; i<numBuckets(); i++) {
|
for (size_t i=0; i<numBuckets(); i++) {
|
||||||
while (!m_bucketsp[i].empty()) {
|
while (!m_bucketsp[i].empty()) {
|
||||||
typename Bucket::iterator bit = m_bucketsp[i].begin();
|
typename Bucket::iterator bit = m_bucketsp[i].begin();
|
||||||
size_type hash = m_hash.operator()(*bit);
|
size_t hash = m_hash.operator()(*bit);
|
||||||
size_type new_idx = hash & ((VL_ULL(1) << new_log2Buckets) - 1);
|
size_t new_idx = hashToBucket(hash, new_log2Buckets);
|
||||||
// Avoid mallocing one list elem and freeing another;
|
// Avoid mallocing one list elem and freeing another;
|
||||||
// splice just moves it over.
|
// splice just moves it over.
|
||||||
new_bucketsp[new_idx].splice(new_bucketsp[new_idx].begin(),
|
new_bucketsp[new_idx].splice(new_bucketsp[new_idx].begin(),
|
||||||
@ -414,40 +439,40 @@ private:
|
|||||||
//===================================================================
|
//===================================================================
|
||||||
//
|
//
|
||||||
/// Functional clone of the std::unordered_map hash table.
|
/// Functional clone of the std::unordered_map hash table.
|
||||||
template <class Key,
|
template <class T_Key,
|
||||||
class Value,
|
class T_Value,
|
||||||
class Hash = vl_hash<Key>,
|
class T_Hash = vl_hash<T_Key>,
|
||||||
class Equal = vl_equal_to<Key> > class vl_unordered_map {
|
class T_Equal = vl_equal_to<T_Key> >
|
||||||
private:
|
class vl_unordered_map {
|
||||||
|
private:
|
||||||
// TYPES
|
// TYPES
|
||||||
typedef vluint64_t size_type;
|
typedef std::pair<T_Key, T_Value> KeyValPair;
|
||||||
typedef std::pair<Key, Value> value_type;
|
|
||||||
|
|
||||||
class KeyHash {
|
class KeyHash {
|
||||||
private:
|
private:
|
||||||
Hash key_hash;
|
T_Hash key_hash;
|
||||||
public:
|
public:
|
||||||
KeyHash() {}
|
KeyHash() {}
|
||||||
size_t operator()(const value_type& kv_pair) const {
|
size_t operator()(const KeyValPair& kv_pair) const {
|
||||||
return key_hash.operator()(kv_pair.first);
|
return key_hash.operator()(kv_pair.first);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class KeyEqual {
|
class KeyEqual {
|
||||||
private:
|
private:
|
||||||
Equal key_eq;
|
T_Equal key_eq;
|
||||||
public:
|
public:
|
||||||
KeyEqual() {}
|
KeyEqual() {}
|
||||||
bool operator()(const value_type& kv_a, const value_type& kv_b) const {
|
bool operator()(const KeyValPair& kv_a, const KeyValPair& kv_b) const {
|
||||||
return key_eq.operator()(kv_a.first, kv_b.first);
|
return key_eq.operator()(kv_a.first, kv_b.first);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
typedef vl_unordered_set<value_type, KeyHash, KeyEqual> MapSet;
|
typedef vl_unordered_set<KeyValPair, KeyHash, KeyEqual> MapSet;
|
||||||
MapSet m_set; // Wrap this vl_unordered_set which holds all state.
|
MapSet m_set; // Wrap this vl_unordered_set which holds all state.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
vl_unordered_map() {}
|
vl_unordered_map() {}
|
||||||
~vl_unordered_map() {}
|
~vl_unordered_map() {}
|
||||||
@ -460,43 +485,43 @@ template <class Key,
|
|||||||
const_iterator begin() const { return m_set.begin(); }
|
const_iterator begin() const { return m_set.begin(); }
|
||||||
const_iterator end() const { return m_set.end(); }
|
const_iterator end() const { return m_set.end(); }
|
||||||
bool empty() const { return m_set.empty(); }
|
bool empty() const { return m_set.empty(); }
|
||||||
iterator find(const Key& k) {
|
iterator find(const T_Key& k) {
|
||||||
// We can't assume that Value() is defined.
|
// We can't assume that T_Value() is defined.
|
||||||
// ie, this does not work:
|
// ie, this does not work:
|
||||||
// return m_set.find(std::make_pair(k, Value()));
|
// return m_set.find(std::make_pair(k, T_Value()));
|
||||||
|
|
||||||
// So, do this instead:
|
// So, do this instead:
|
||||||
Hash mapHash;
|
T_Hash mapHash;
|
||||||
Equal mapEq;
|
T_Equal mapEq;
|
||||||
size_type hash = mapHash.operator()(k);
|
size_t hash = mapHash.operator()(k);
|
||||||
size_type bucketIdxOut = hash & (m_set.numBuckets() - 1);
|
size_t bucketIdxOut = m_set.hashToBucket(hash);
|
||||||
typename MapSet::Bucket* bucketp = m_set.getBucket(bucketIdxOut);
|
typename MapSet::Bucket* bucketp = m_set.getBucket(bucketIdxOut);
|
||||||
|
|
||||||
for (typename MapSet::Bucket::iterator it = bucketp->begin();
|
for (typename MapSet::Bucket::iterator it = bucketp->begin();
|
||||||
it != bucketp->end(); ++it) {
|
it != bucketp->end(); ++it) {
|
||||||
if (mapEq.operator()(it->first, k)) {
|
if (mapEq.operator()(it->first, k)) {
|
||||||
return iterator(bucketIdxOut, it, &m_set);
|
return iterator(bucketIdxOut, it, &m_set);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return end();
|
return end();
|
||||||
}
|
}
|
||||||
const_iterator find(const Key& k) const {
|
const_iterator find(const T_Key& k) const {
|
||||||
return const_cast<vl_unordered_map*>(this)->find(k);
|
return const_cast<vl_unordered_map*>(this)->find(k);
|
||||||
}
|
}
|
||||||
std::pair<iterator, bool> insert(const value_type& val) {
|
std::pair<iterator, bool> insert(const KeyValPair& val) {
|
||||||
return m_set.insert(val);
|
return m_set.insert(val);
|
||||||
}
|
}
|
||||||
iterator erase(iterator it) { return m_set.erase(it); }
|
iterator erase(iterator it) { return m_set.erase(it); }
|
||||||
size_type erase(const Key& k) {
|
size_t erase(const T_Key& k) {
|
||||||
iterator it = find(k);
|
iterator it = find(k);
|
||||||
if (it == end()) { return 0; }
|
if (it == end()) { return 0; }
|
||||||
m_set.erase(it);
|
m_set.erase(it);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
Value& operator[](const Key& k) {
|
T_Value& operator[](const T_Key& k) {
|
||||||
// Here we can assume Value() is defined, as
|
// Here we can assume T_Value() is defined, as
|
||||||
// std::unordered_map::operator[] relies on it too.
|
// std::unordered_map::operator[] relies on it too.
|
||||||
value_type dummy = std::make_pair(k, Value());
|
KeyValPair dummy = std::make_pair(k, T_Value());
|
||||||
iterator it = m_set.find(dummy);
|
iterator it = m_set.find(dummy);
|
||||||
if (it == m_set.end()) {
|
if (it == m_set.end()) {
|
||||||
it = m_set.insert(dummy).first;
|
it = m_set.insert(dummy).first;
|
||||||
@ -506,18 +531,18 @@ template <class Key,
|
|||||||
// it's safe to modify the value field and we can allow it:
|
// it's safe to modify the value field and we can allow it:
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
Value& at(const Key& k) {
|
T_Value& at(const T_Key& k) {
|
||||||
iterator it = find(k);
|
iterator it = find(k);
|
||||||
if (it == end()) { throw std::out_of_range("sorry"); }
|
if (it == end()) { throw std::out_of_range("sorry"); }
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
const Value& at(const Key& k) const {
|
const T_Value& at(const T_Key& k) const {
|
||||||
iterator it = find(k);
|
iterator it = find(k);
|
||||||
if (it == end()) { throw std::out_of_range("sorry"); }
|
if (it == end()) { throw std::out_of_range("sorry"); }
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
void clear() { m_set.clear(); }
|
void clear() { m_set.clear(); }
|
||||||
size_type size() const { return m_set.size(); }
|
size_t size() const { return m_set.size(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -61,37 +61,37 @@ namespace V3TSP {
|
|||||||
} // namespace V3TSP
|
} // namespace V3TSP
|
||||||
|
|
||||||
// Vertex that tracks a per-vertex key
|
// Vertex that tracks a per-vertex key
|
||||||
template <typename Key>
|
template <typename T_Key>
|
||||||
class TspVertexTmpl : public V3GraphVertex {
|
class TspVertexTmpl : public V3GraphVertex {
|
||||||
private:
|
private:
|
||||||
Key m_key;
|
T_Key m_key;
|
||||||
public:
|
public:
|
||||||
TspVertexTmpl(V3Graph* graphp, const Key& k)
|
TspVertexTmpl(V3Graph* graphp, const T_Key& k)
|
||||||
: V3GraphVertex(graphp), m_key(k) {}
|
: V3GraphVertex(graphp), m_key(k) {}
|
||||||
virtual ~TspVertexTmpl() {}
|
virtual ~TspVertexTmpl() {}
|
||||||
const Key& key() const { return m_key; }
|
const T_Key& key() const { return m_key; }
|
||||||
private:
|
private:
|
||||||
VL_UNCOPYABLE(TspVertexTmpl);
|
VL_UNCOPYABLE(TspVertexTmpl);
|
||||||
};
|
};
|
||||||
|
|
||||||
// TspGraphTmpl represents a complete graph, templatized to work with
|
// TspGraphTmpl represents a complete graph, templatized to work with
|
||||||
// different Key types.
|
// different T_Key types.
|
||||||
template <typename Key>
|
template <typename T_Key>
|
||||||
class TspGraphTmpl : public V3Graph {
|
class TspGraphTmpl : public V3Graph {
|
||||||
public:
|
public:
|
||||||
// TYPES
|
// TYPES
|
||||||
typedef TspVertexTmpl<Key> Vertex;
|
typedef TspVertexTmpl<T_Key> Vertex;
|
||||||
|
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
typedef vl_unordered_map<Key, Vertex*> VMap;
|
typedef vl_unordered_map<T_Key, Vertex*> VMap;
|
||||||
VMap m_vertices; // Key to Vertex lookup map
|
VMap m_vertices; // T_Key to Vertex lookup map
|
||||||
|
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
TspGraphTmpl() : V3Graph() {}
|
TspGraphTmpl() : V3Graph() {}
|
||||||
virtual ~TspGraphTmpl() {}
|
virtual ~TspGraphTmpl() {}
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
void addVertex(const Key &key) {
|
void addVertex(const T_Key &key) {
|
||||||
typename VMap::iterator itr = m_vertices.find(key);
|
typename VMap::iterator itr = m_vertices.find(key);
|
||||||
UASSERT(itr == m_vertices.end(), "Vertex already exists with same key");
|
UASSERT(itr == m_vertices.end(), "Vertex already exists with same key");
|
||||||
Vertex *v = new Vertex(this, key);
|
Vertex *v = new Vertex(this, key);
|
||||||
@ -102,7 +102,7 @@ public:
|
|||||||
// Map that onto the normally-directional V3Graph by creating
|
// Map that onto the normally-directional V3Graph by creating
|
||||||
// a matched pairs of opposite-directional edges to represent
|
// a matched pairs of opposite-directional edges to represent
|
||||||
// each non-directional edge:
|
// each non-directional edge:
|
||||||
void addEdge(const Key& from, const Key& to, int cost) {
|
void addEdge(const T_Key& from, const T_Key& to, int cost) {
|
||||||
UASSERT(from != to, "Adding edge would form a loop");
|
UASSERT(from != to, "Adding edge would form a loop");
|
||||||
Vertex* fp = findVertex(from);
|
Vertex* fp = findVertex(from);
|
||||||
Vertex* tp = findVertex(to);
|
Vertex* tp = findVertex(to);
|
||||||
@ -121,7 +121,7 @@ public:
|
|||||||
|
|
||||||
bool empty() const { return m_vertices.empty(); }
|
bool empty() const { return m_vertices.empty(); }
|
||||||
|
|
||||||
std::list<Vertex*> keysToVertexList(const std::vector<Key>& odds) {
|
std::list<Vertex*> keysToVertexList(const std::vector<T_Key>& odds) {
|
||||||
std::list<Vertex*> vertices;
|
std::list<Vertex*> vertices;
|
||||||
for(unsigned i = 0; i < odds.size(); ++i) {
|
for(unsigned i = 0; i < odds.size(); ++i) {
|
||||||
vertices.push_back(findVertex(odds.at(i)));
|
vertices.push_back(findVertex(odds.at(i)));
|
||||||
@ -231,7 +231,7 @@ public:
|
|||||||
|
|
||||||
// Populate *outp with a minimal perfect matching of *this.
|
// Populate *outp with a minimal perfect matching of *this.
|
||||||
// *outp must be initially empty.
|
// *outp must be initially empty.
|
||||||
void perfectMatching(const std::vector<Key>& oddKeys,
|
void perfectMatching(const std::vector<T_Key>& oddKeys,
|
||||||
TspGraphTmpl* outp) {
|
TspGraphTmpl* outp) {
|
||||||
UASSERT(outp->empty(), "Output graph must start empty");
|
UASSERT(outp->empty(), "Output graph must start empty");
|
||||||
|
|
||||||
@ -305,7 +305,7 @@ public:
|
|||||||
|
|
||||||
void findEulerTourRecurse(vl_unordered_set<unsigned>* markedEdgesp,
|
void findEulerTourRecurse(vl_unordered_set<unsigned>* markedEdgesp,
|
||||||
Vertex* startp,
|
Vertex* startp,
|
||||||
std::vector<Key>* sortedOutp) {
|
std::vector<T_Key>* sortedOutp) {
|
||||||
Vertex* cur_vertexp = startp;
|
Vertex* cur_vertexp = startp;
|
||||||
|
|
||||||
// Go on a random tour. Fun!
|
// Go on a random tour. Fun!
|
||||||
@ -390,7 +390,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void findEulerTour(std::vector<Key>* sortedOutp) {
|
void findEulerTour(std::vector<T_Key>* sortedOutp) {
|
||||||
UASSERT(sortedOutp->empty(), "Output graph must start empty");
|
UASSERT(sortedOutp->empty(), "Output graph must start empty");
|
||||||
if (debug() >= 6) dumpDotFilePrefixed("findEulerTour");
|
if (debug() >= 6) dumpDotFilePrefixed("findEulerTour");
|
||||||
vl_unordered_set<unsigned /*edgeID*/> markedEdges;
|
vl_unordered_set<unsigned /*edgeID*/> markedEdges;
|
||||||
@ -399,8 +399,8 @@ public:
|
|||||||
findEulerTourRecurse(&markedEdges, start_vertexp, sortedOutp);
|
findEulerTourRecurse(&markedEdges, start_vertexp, sortedOutp);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Key> getOddDegreeKeys() const {
|
std::vector<T_Key> getOddDegreeKeys() const {
|
||||||
std::vector<Key> result;
|
std::vector<T_Key> result;
|
||||||
for (V3GraphVertex* vxp = verticesBeginp(); vxp; vxp = vxp->verticesNextp()) {
|
for (V3GraphVertex* vxp = verticesBeginp(); vxp; vxp = vxp->verticesNextp()) {
|
||||||
Vertex* tspvp = castVertexp(vxp);
|
Vertex* tspvp = castVertexp(vxp);
|
||||||
vluint32_t degree = 0;
|
vluint32_t degree = 0;
|
||||||
@ -415,7 +415,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Vertex* findVertex(const Key& key) const {
|
Vertex* findVertex(const T_Key& key) const {
|
||||||
typename VMap::const_iterator it = m_vertices.find(key);
|
typename VMap::const_iterator it = m_vertices.find(key);
|
||||||
UASSERT(it != m_vertices.end(), "Vertex not found");
|
UASSERT(it != m_vertices.end(), "Vertex not found");
|
||||||
return it->second;
|
return it->second;
|
||||||
|
Loading…
Reference in New Issue
Block a user