Replace CGAL::Open_hash by boost::unordered_set

This commit is contained in:
Andreas Fabri 2017-11-20 17:12:55 +00:00 committed by Sébastien Loriot
parent 9fe73a801e
commit 0625e73722
5 changed files with 14 additions and 839 deletions

View File

@ -1,808 +0,0 @@
// Copyright (c) 2005,2006,2007,2009,2010,2011 Tel-Aviv University (Israel).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// 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 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0+
//
//
// Author(s) : Ron Wein <wein@post.tau.ac.il>
#ifndef CGAL_OPEN_HASH_H
#define CGAL_OPEN_HASH_H
#include <CGAL/license/Arrangement_on_surface_2.h>
/*! \file
* Definition of the Open_hash and the Hash_map class-templates.
*/
#include <vector>
#include <list>
namespace CGAL {
/*! \class
* A default equality functor.
* The parameter Type must support the equality operator.
*/
template <class Type>
class Default_is_equal_functor
{
public:
bool operator() (const Type& t1, const Type& t2) const
{
return (t1 == t2);
}
};
/*! \class
* An implementation of an open-addressing hash.
*/
template <class Key_,
class Hash_functor_,
class EqualKey_ = Default_is_equal_functor<Key_> >
class Open_hash
{
public:
// Type definitions (for STL compatibility):
typedef Key_ value_type;
typedef Key_ key_type;
typedef Hash_functor_ hasher;
typedef EqualKey_ key_equal;
typedef value_type* pointer;
typedef value_type& reference;
typedef const value_type* const_pointer;
typedef const value_type& const_reference;
typedef size_t size_type;
typedef size_t difference_type;
protected:
enum
{
DEFAULT_NUMBER_OF_BUCKETS = 1000
};
typedef std::list<Key_> Bucket;
typedef typename Bucket::iterator Bucket_iterator;
typedef typename Bucket::const_iterator Bucket_const_iterator;
size_type n_buckets; // Number of buckets in the hash.
size_type n_objects; // Number of objects stored in the hash.
std::vector<Bucket> buckets; // The buckets (linked lists of objects).
hasher hash_func; // The hashing functor.
key_equal equal_func; // The equality functor.
private:
// Copy constructor and assignment operator - not supported.
Open_hash (const Open_hash& );
Open_hash& operator= (const Open_hash& );
public:
/// \name Construction and destruction methods.
//@{
/*! Default constructor. */
Open_hash () :
n_objects (0),
buckets (DEFAULT_NUMBER_OF_BUCKETS),
hash_func (),
equal_func ()
{
n_buckets = buckets.size();
}
/*! Constructor with an initial number of buckets. */
Open_hash (size_type n,
hasher hash_f = hasher(),
key_equal equal_f = key_equal()) :
n_objects (0),
buckets (n),
hash_func (hash_f),
equal_func (equal_f)
{
n_buckets = buckets.size();
}
/*! Destructor. */
virtual ~Open_hash ()
{}
//@}
/// \number Access the hash properties.
//@{
/*! Get the number of buckets in the hash. */
size_type bucket_count () const
{
return (n_buckets);
}
/*! Get the number of objects stored in the hash. */
size_type size () const
{
return (n_objects);
}
/*! Check whether the hash is empty. */
bool empty () const
{
return (n_objects == 0);
}
/*! Get the hasher object used by the hash. */
const hasher& hash_funct () const
{
return (hash_func);
}
/*! Get the key_equal object used by the hash. */
const key_equal& key_eq () const
{
return (equal_func);
}
//@}
/*! \class
* An iterator for the open-addressing hash.
*/
class iterator
{
friend class Open_hash<Key_, Hash_functor_, EqualKey_>;
private:
Open_hash<Key_, Hash_functor_, EqualKey_> *p_hash; // The scanned hash.
int index; // The index of the current bucket.
Bucket_iterator iter; // Iterator for the current bucket.
/*! Private constructor. */
iterator (const Open_hash<Key_, Hash_functor_, EqualKey_>& hash,
size_type ind) :
p_hash (const_cast<Open_hash<Key_,Hash_functor_,EqualKey_>* >(&hash))
{
// Find the next non-empty bucket and get an iterator for it.
index = p_hash->_next_non_empty_bucket (static_cast<int> (ind));
if (index < static_cast<int>(p_hash->n_buckets))
iter = (p_hash->buckets[index]).begin();
}
/*! Private constructor. */
iterator (const Open_hash<Key_, Hash_functor_, EqualKey_>& hash,
size_type ind,
Bucket_iterator it) :
p_hash (const_cast<Open_hash<Key_,Hash_functor_,EqualKey_>* >(&hash)),
index (static_cast<int> (ind)),
iter (it)
{}
public:
/*! Default constructor. */
iterator () :
p_hash (NULL),
index (0)
{}
/*! Equality operator. */
bool operator== (const iterator& it)
{
if (p_hash != it.p_hash)
return (false);
if (p_hash == NULL)
return (true);
if ((index < 0 || index >= static_cast<int>(p_hash->n_buckets)) &&
(it.index < 0 || it.index >= static_cast<int>(p_hash->n_buckets)))
return (true);
return (index == it.index && iter == it.iter);
}
/*! Inequality operator. */
bool operator!= (const iterator& it)
{
return (! (*this == it));
}
/*! Get the current object the iterator points on. */
const_reference operator* () const
{
CGAL_precondition (p_hash != NULL &&
index >= 0 && index < static_cast<int>(p_hash->n_buckets));
return (*iter);
}
/*! Get a pointer for the current object the iterator points on. */
const_pointer operator-> () const
{
CGAL_precondition (p_hash != NULL &&
index >= 0 && index < static_cast<int>(p_hash->n_buckets));
return (&(*iter));
}
/* Increment the iterator (prefix notation). */
iterator& operator++ ()
{
// Check end conditions.
CGAL_precondition (p_hash != NULL);
if (index >= static_cast<int>(p_hash->n_buckets))
return (*this);
if (index < 0)
{
// Find the first non-empty bucket and get an iterator for it.
index = p_hash->_next_non_empty_bucket (0);
if (index < static_cast<int>(p_hash->n_buckets))
iter = (p_hash->buckets[index]).begin();
return (*this);
}
// Try to increment the current list iterator.
++iter;
if (iter == (p_hash->buckets[index]).end())
{
// Find the next non-empty bucket and get an iterator for it.
index = p_hash->_next_non_empty_bucket (index + 1);
if (index < static_cast<int>(p_hash->n_buckets))
iter = (p_hash->buckets[index]).begin();
}
return (*this);
}
/* Increment the iterator (postfix notation). */
iterator operator++ (int )
{
iterator temp = *this;
++(*this);
return (temp);
}
/* Decrement the iterator (prefix notation). */
iterator& operator-- ()
{
// Check end conditions.
CGAL_precondition (p_hash != NULL);
if (index >= static_cast<int>(p_hash->n_buckets))
{
// Find the last non-empty bucket and get an iterator for it.
index = p_hash->_prev_non_empty_bucket
(static_cast<int>(p_hash->n_buckets) - 1);
if (index >= 0)
{
iter = (p_hash->buckets[index]).end();
--iter;
}
return (*this);
}
if (index < 0)
return (*this);
// Try to decrement the current list iterator.
if (iter != (p_hash->buckets[index]).begin())
{
--iter;
}
else
{
// Find the nprevious non-empty bucket and get an iterator for it.
index = p_hash->_prev_non_empty_bucket (index - 1);
if (index >= 0)
{
iter = (p_hash->buckets[index]).end();
--iter;
}
}
return (*this);
}
/* Decrement the iterator (postfix notation). */
iterator operator-- (int )
{
iterator temp = *this;
--(*this);
return (temp);
}
};
friend class iterator;
/// \name Scan the objects in the hash.
//@{
/*! Get an iterator for the first object in the hash. */
iterator begin () const
{
return (iterator (*this, 0));
}
/*! Get a past-the end iterator for the objects. */
iterator end () const
{
return (iterator (*this, n_buckets));
}
//@}
/// \name Hash operations.
//@{
/*!
* Check if an object with the given key exists in the map.
* \param ket The key to look for.
* \return An iterator for an objects having the given key,
* or a past-the-end iterator if no such object was found.
*/
iterator find (const key_type& key) const
{
// Look for the object in the approriate bucket.
const size_type index = hash_func (key) % n_buckets;
Bucket& my_bucket = const_cast<Bucket&>(buckets[index]);
Bucket_iterator bucket_it = _find_in_bucket (index, key);
if (bucket_it == my_bucket.end())
// The object was not found.
return (end());
// Create an iterator pointing to the object.
return (iterator (*this, index, bucket_it));
}
/*!
* Insert an object into the hash.
* \param val The object to insert.
* \return A pair comprised of an iterator for the inserted object,
* and a flag indicating whether the insertion tool place
* (false if the object had already existed in the hash).
*/
std::pair<iterator,bool> insert (const value_type& val)
{
// Look for the object in the approriate bucket.
const size_type index = hash_func (val) % n_buckets;
Bucket_iterator bucket_it = _find_in_bucket (index, val);
std::pair<iterator,bool> res;
// Check if the object already exists.
if (bucket_it != buckets[index].end())
{
// In case the object already exists:
res.first = iterator (*this, index, bucket_it);
res.second = false;
}
else
{
// Insert a new object to the approriate bucket.
buckets[index].push_front (val);
n_objects++;
res.first = iterator (*this, index, buckets[index].begin());
res.second = true;
}
return (res);
}
/*!
* Erase an object given an iterator pointing to it.
* \param pos An iterator pointing at the object to be erased.
*/
void erase (iterator pos)
{
// Erase the object from the approriate bucket.
CGAL_precondition (pos.p_hash == this);
const int index = pos.index;
Bucket_iterator bucket_it = pos.iter;
CGAL_assertion (index >= 0 && index < static_cast<int>(n_buckets));
buckets[index].erase (bucket_it);
n_objects--;
return;
}
/*!
* Erase an object with the given key.
* \param key The key to delete.
* \return Whether an object has been found and erased.
*/
bool erase (const key_type& key)
{
// Look for the object in the approriate bucket.
const size_type index = hash_func (key) % n_buckets;
Bucket_iterator bucket_it = _find_in_bucket (index, key);
if (bucket_it == buckets[index].end())
// The object was not found.
return (false);
// Erase the object from the approriate bucket.
buckets[index].erase (bucket_it);
n_objects--;
return (true);
}
/*!
* Clear the contents of the hash.
*/
void clear ()
{
// Clear all buckets.
typename std::vector<Bucket>::iterator it;
for (it = buckets.begin(); it != buckets.end(); ++it)
(*it).clear();
n_objects = 0;
return;
}
//@}
/// \name Re-arranging the hash structure.
//@{
/*!
* Resize the hash (takes time proporsional to the number of objects
* stored in the hash).
* \param n The new number of buckets.
*/
void resize (size_type n)
{
rehash (n, hash_func);
};
/*! Rehash the structure.
* \param n The new number of buckets.
* \param hash_f The new hashing functor.
*/
void rehash (size_type n, hasher hash_f)
{
// Set the hashing functor.
hash_func = hash_f;
// Rehash the structure.
std::vector<Bucket> new_buckets (n);
typename std::vector<Bucket>::iterator it;
Bucket_iterator bucket_it;
size_type index;
for (it = buckets.begin(); it != buckets.end(); ++it)
{
for (bucket_it = (*it).begin(); bucket_it != (*it).end(); ++bucket_it)
{
const value_type& val = *bucket_it;
index = hash_func (val) % n;
new_buckets[index].push_back (val);
}
}
// Set the new buckets.
buckets = new_buckets;
n_buckets = n;
return;
}
//@}
private:
/*! Get the index of the previous non-empty bucket. */
int _prev_non_empty_bucket (int index) const
{
while (index >= 0 && buckets[index].empty())
index--;
return (index);
}
/*! Get the index of the next non-empty bucket. */
int _next_non_empty_bucket (int index) const
{
while (index < static_cast<int>(n_buckets) && buckets[index].empty())
index++;
return (index);
}
/*! Find the given object in the given bucket. */
Bucket_iterator _find_in_bucket (std::size_t index,
const value_type& val) const
{
Bucket& my_bucket = const_cast<Bucket&>(buckets[index]);
Bucket_iterator iter = my_bucket.begin();
while (iter != my_bucket.end() && ! equal_func (val, *iter))
++iter;
return (iter);
}
};
/*! \class
* An implementation of a hash-based map.
*/
template <class Key_, class Data_,
class Hash_functor_,
class EqualKey_ = Default_is_equal_functor<Key_> >
class Hash_map
{
public:
// Type definitions (for STL compatibility):
typedef Key_ key_type;
typedef Data_ data_type;
typedef std::pair<Key_,Data_> value_type;
typedef Hash_functor_ hasher;
typedef EqualKey_ key_equal;
typedef value_type* pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef size_t size_type;
typedef size_t difference_type;
protected:
/*! \class
* A functor for the value_type pair.
*/
class Value_type_hash_functor
{
private:
Hash_functor_ hash_func;
public:
Value_type_hash_functor () :
hash_func ()
{}
Value_type_hash_functor (Hash_functor_ func) :
hash_func (func)
{}
size_type operator() (const value_type& vt) const
{
return (hash_func (vt.first));
}
};
/*! \class
* A functor for comparing value_type pairs.
*/
class Value_type_equal
{
private:
EqualKey_ equal_func;
public:
Value_type_equal () :
equal_func ()
{}
Value_type_equal (EqualKey_ func) :
equal_func (func)
{}
bool operator() (const value_type& vt1, const value_type& vt2) const
{
return (equal_func (vt1.first, vt2.first));
}
};
typedef Open_hash<value_type,
Value_type_hash_functor, Value_type_equal> Hash;
Value_type_hash_functor vt_hash_func;
Value_type_equal vt_equal_func;
Hash hash;
public:
/// \name Construction and destruction methods.
//@{
/*! Default constructor. */
Hash_map () :
vt_hash_func (hasher()),
vt_equal_func (key_equal()),
hash ()
{}
/*! Constructor with an initial number of buckets. */
Hash_map (size_type n,
hasher hash_f = hasher(),
key_equal equal_f = key_equal()) :
vt_hash_func (hash_f),
vt_equal_func (equal_f),
hash (n, vt_hash_func, vt_equal_func)
{}
/*! Destructor. */
virtual ~Hash_map ()
{}
//@}
/// \number Access the hash properties.
//@{
/*! Get the number of buckets in the hash map. */
size_type bucket_count () const
{
return (hash.bucket_count());
}
/*! Get the number of objects stored in the hash map. */
size_type size () const
{
return (hash.size());
}
/*! Check whether the hash map is empty. */
bool empty () const
{
return (hash.empty());
}
//@}
typedef typename Hash::iterator iterator;
/// \name Scan the objects in the hash.
//@{
/*! Get an iterator for the first object in the hash map. */
iterator begin () const
{
return (hash.begin());
}
/*! Get a past-the end iterator for the objects map. */
iterator end () const
{
return (hash.end());
}
//@}
/// \name Hash-map operations.
//@{
/*!
* Check if an object with the given key exists in the map.
* \param ket The key to look for.
* \return An iterator for an objects having the given key,
* or a past-the-end iterator if no such object was found.
*/
iterator find (const key_type& key) const
{
value_type vt (key, data_type());
return (hash.find (vt));
}
/*!
* Returns a reference to the object that is associated with the given key.
* If the hash map does not contain such an object, it inserts an entry
* corresponding to the given key.
* \param key The key.
* \return The data associated with this key.
*/
data_type& operator[] (const key_type& key)
{
value_type vt (key, data_type());
std::pair<iterator, bool> res = hash.insert (vt);
return (const_cast<data_type&> ((*(res.first)).second));
}
/*!
* Insert an object into the hash.
* \param val The object to insert.
* \return A pair comprised of an iterator for the inserted object,
* and a flag indicating whether the insertion tool place
* (false if the object had already existed in the hash).
*/
std::pair<iterator,bool> insert (const value_type& val)
{
return (hash.insert (val));
}
/*!
* Erase an object given an iterator pointing to it.
* \param pos An iterator pointing at the object to be erased.
*/
void erase (iterator pos)
{
hash.erase (pos);
return;
}
/*!
* Erase an object with the given key.
* \param key The key to delete.
* \return Whether an object has been found and erased.
*/
bool erase (const key_type& key)
{
value_type vt (key, data_type());
return (hash.erase (vt));
}
/*!
* Clear the contents of the hash map.
*/
void clear ()
{
hash.clear();
}
//@}
/// \name Re-arranging the hash structure.
//@{
/*!
* Resize the hash map (takes time proporsional to the number of objects
* stored in the hash).
* \param n The new number of buckets.
*/
void resize (size_type n)
{
hash.resize (n);
};
/*! Rehash the structure.
* \param n The new number of buckets.
* \param hash_f The new hashing functor.
*/
void rehash (size_type n, hasher hash_f)
{
vt_hash_func = Value_type_hash_functor (hash_f);
hash.rehash (n, vt_hash_func);
}
//@}
};
} //namespace CGAL
#endif

View File

@ -98,7 +98,6 @@ public:
this->m_subCurves =
this->m_subCurveAlloc.allocate(this->m_num_of_subCurves);
this->m_curves_pair_set.resize(2 * this->m_num_of_subCurves);
// Initialize the event queue using the vertices vectors. Note that these
// vertices are already sorted, we simply have to merge them

View File

@ -36,7 +36,7 @@
#include <CGAL/Object.h>
#include <CGAL/No_intersection_surface_sweep_2.h>
#include <CGAL/Surface_sweep_2/Curve_pair.h>
#include <CGAL/Arrangement_2/Open_hash.h>
#include <boost/unordered_set.hpp>
#include <CGAL/algorithm.h>
namespace CGAL {
@ -111,12 +111,11 @@ public:
typedef typename Base::Status_line_iterator Status_line_iterator;
typedef CGAL::Surface_sweep_2::Curve_pair<Subcurve> Curve_pair;
typedef CGAL::Surface_sweep_2::Curve_pair_hasher<Subcurve>
Curve_pair_hasher;
typedef boost::hash<Curve_pair> Curve_pair_hasher;
typedef CGAL::Surface_sweep_2::Equal_curve_pair<Subcurve>
Equal_curve_pair;
typedef Open_hash<Curve_pair, Curve_pair_hasher, Equal_curve_pair>
Curve_pair_set;
typedef boost::unordered_set<Curve_pair, Curve_pair_hasher, Equal_curve_pair>
Curve_pair_set;
typedef std::vector<Object> Object_vector;
typedef random_access_input_iterator<Object_vector> vector_inserter;

View File

@ -61,6 +61,11 @@ public:
/*! Obtain the second subcurve. */
Subcurve* second() const { return m_pair.second; }
std::pair<Subcurve*, Subcurve*> pair() const
{
return m_pair;
}
};
/*! \struct
@ -80,22 +85,11 @@ struct Less_curve_pair {
}
};
/*! \struct
* A hash functor for curve pairs.
*/
template <typename Subcurve_>
struct Curve_pair_hasher {
typedef Subcurve_ Subcurve;
typedef class Curve_pair<Subcurve> Curve_pair;
size_t operator()(const Curve_pair& pair) const
{
const size_t half_n_bits = sizeof(size_t) * 8 / 2;
const size_t val1 = reinterpret_cast<size_t>(pair.first());
const size_t val2 = reinterpret_cast<size_t>(pair.second());
return (((val1 << half_n_bits) | (val1 >> half_n_bits)) ^ val2);
}
};
template <class Subcurve_>
std::size_t hash_value(const Curve_pair<Subcurve_>& cp)
{
return boost::hash<std::pair<Subcurve_*, Subcurve_*> >()(cp.pair());
}
/*! \struct
* Equaility functor for curve pairs.

View File

@ -41,9 +41,6 @@ void Surface_sweep_2<Vis>::_init_structures()
{
// Initailize the structures maintained by the base sweep-line class.
Base::_init_structures();
// Resize the hash to be O(2*n), where n is the number of input curves.
m_curves_pair_set.resize(2 * this->m_num_of_subCurves);
}
//-----------------------------------------------------------------------------
@ -421,12 +418,6 @@ template <typename Vis>
return; //the curves have already been checked for intersection
}
float load_factor = static_cast<float>(m_curves_pair_set.size()) /
m_curves_pair_set.bucket_count();
// after lot of benchemarks, keeping load_factor<=6 is optimal
if (load_factor > 6.0f)
m_curves_pair_set.resize(m_curves_pair_set.size() * 6);
// handle overlapping curves with common ancesters
Subcurve_vector all_leaves_diff;
Subcurve* first_parent=NULL;