Merge pull request #179 from afabri/CGAL-add_hash-GF

Add boost::hash and std::hash

https://cgal.geometryfactory.com/CGAL/Members/wiki/Features/Small_Features/hash

Conflicts:
	Installation/changes.html
This commit is contained in:
Laurent Rineau 2015-07-17 15:39:18 +02:00
commit 08666dce25
29 changed files with 1686 additions and 151 deletions

View File

@ -370,6 +370,10 @@ counterparts. `Vertex_iterator`, `Halfedge_iterator`, and
the handles appear in function parameter lists, the respective
iterators can be passed as well.
All handles are model of `LessThanComparable` and `Hashable`,
that is they can be used as keys in containers such as `std::map`
and `boost::unordered_map`.
*/
/// @{

View File

@ -21,6 +21,8 @@
#ifndef CGAL_ARRANGEMENT_2_ITERATORS_H
#define CGAL_ARRANGEMENT_2_ITERATORS_H
#include <functional>
/*! \file
* Definitions of auxiliary iterator adaptors.
*/
@ -340,6 +342,11 @@ public:
return !(*this == it);
}
bool operator< (const Self& it) const
{
return &(**this) < (&*it);
}
/*! Dereferencing operators. */
reference operator*() const
{
@ -495,6 +502,11 @@ public:
return !(*this == it);
}
bool operator< (const Self& it) const
{
return &(**this) < (&*it);
}
/*! Dereferencing operators. */
reference operator*() const
{
@ -545,4 +557,104 @@ public:
} //namespace CGAL
namespace std {
#if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4099) // For VC10 it is class hash
#endif
template < class T>
struct hash;
template <class CIterator_, class Filter_, class MIterator_,
class Value_, class Diff_, class Category_>
struct hash<CGAL::I_Filtered_const_iterator<CIterator_,
Filter_,
MIterator_,
Value_,
Diff_,
Category_> > {
typedef CGAL::I_Filtered_const_iterator<CIterator_,
Filter_,
MIterator_,
Value_,
Diff_,
Category_> I;
std::size_t operator()(const I& i) const
{
return reinterpret_cast<std::size_t>(&*i) / sizeof(Value_);
}
};
template <class Iterator_, class Filter_,
class Value_, class Diff_, class Category_>
struct hash<CGAL::I_Filtered_iterator<Iterator_,
Filter_,
Value_,
Diff_,
Category_> > {
typedef CGAL::I_Filtered_iterator<Iterator_,
Filter_,
Value_,
Diff_,
Category_> I;
std::size_t operator()(const I& i) const
{
return reinterpret_cast<std::size_t>(&*i) / sizeof(typename I::value_type);
}
};
}
namespace boost {
template <typename T> struct hash;
template <class CIterator_, class Filter_, class MIterator_,
class Value_, class Diff_, class Category_>
struct hash<CGAL::I_Filtered_const_iterator<CIterator_,
Filter_,
MIterator_,
Value_,
Diff_,
Category_> > {
typedef CGAL::I_Filtered_const_iterator<CIterator_,
Filter_,
MIterator_,
Value_,
Diff_,
Category_> I;
std::size_t operator()(const I& i) const
{
return reinterpret_cast<std::size_t>(&*i) / sizeof(Value_);
}
};
template <class Iterator_, class Filter_,
class Value_, class Diff_, class Category_>
struct hash<CGAL::I_Filtered_iterator<Iterator_,
Filter_,
Value_,
Diff_,
Category_> > {
typedef CGAL::I_Filtered_iterator<Iterator_,
Filter_,
Value_,
Diff_,
Category_> I;
std::size_t operator()(const I& i) const
{
return reinterpret_cast<std::size_t>(&*i) / sizeof(typename I::value_type);
}
};
#if defined(BOOST_MSVC)
# pragma warning(pop)
#endif
}
#endif

View File

@ -20,6 +20,8 @@
#ifndef CGAL_BOOST_GRAPH_GRAPH_TRAITS_HALFEDGEDS_H
#define CGAL_BOOST_GRAPH_GRAPH_TRAITS_HALFEDGEDS_H
#include <functional>
#include <boost/config.hpp>
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/iterator/transform_iterator.hpp>
@ -30,7 +32,6 @@
#include <CGAL/basic.h>
#include <CGAL/boost/graph/iterator.h>
#include <CGAL/Handle_hash_function.h>
#ifndef CGAL_NO_DEPRECATED_CODE
@ -217,4 +218,31 @@ public:
} //namespace CGAL
namespace std {
#if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4099) // For VC10 it is class hash
#endif
template < class T>
struct hash;
template <typename H>
struct hash<CGAL::internal::HDS_edge<H> > {
std::size_t operator()(const CGAL::internal::HDS_edge<H>& e) const
{
std::cerr << "HDS_edge HashFct" << std::endl;
std::hash<H> fct;
return fct(e.halfedge());
}
};
#if defined(BOOST_MSVC)
# pragma warning(pop)
#endif
}
#endif // CGAL_BOOST_GRAPH_GRAPH_TRAITS_HALFEDGEDS_H

View File

@ -20,6 +20,8 @@
#ifndef CGAL_GRAPH_TRAITS_TRIANGULATION_2_H
#define CGAL_GRAPH_TRAITS_TRIANGULATION_2_H
#include <functional>
#include <boost/config.hpp>
#include <boost/iterator_adaptors.hpp>
#include <boost/graph/graph_traits.hpp>
@ -40,8 +42,9 @@ namespace CGAL {
template < class T, class EdgeBase >
class Edge : public EdgeBase {
public:
typedef typename T::Face_handle Face_handle ;
public:
Edge()
{}
@ -64,7 +67,12 @@ class Edge : public EdgeBase {
this->first = e.first;
this->second = e.second;
return *this;
}
}
friend std::size_t hash_value(const Edge& e)
{
return hash_value(e.first);
}
bool operator==(const Edge& other) const
{
@ -247,6 +255,49 @@ public:
}
};
template <typename Tr>
struct T2_halfedge_descriptor
{
typedef typename Tr::Face_handle face_descriptor;
face_descriptor first;
int second;
operator std::pair<face_descriptor, int>() { return std::make_pair(first,second); }
T2_halfedge_descriptor()
{}
T2_halfedge_descriptor(const typename Tr::Edge& e)
: first(e.first), second(e.second)
{}
T2_halfedge_descriptor(face_descriptor fd, int i)
: first(fd), second(i)
{}
friend std::size_t hash_value(const T2_halfedge_descriptor& h)
{
return hash_value(h.first);
}
bool operator==(const T2_halfedge_descriptor& other) const
{
return (first == other.first) && (second == other.second);
}
bool operator!=(const T2_halfedge_descriptor& other) const
{
return (first != other.first) || (second != other.second);
}
bool operator<(const T2_halfedge_descriptor& other) const
{
if(first < other.first) return true;
if(first > other.first) return false;
return second < other.second;
}
};
} // namespace detail
} // namespace CGAL
@ -270,41 +321,7 @@ namespace boost {
typedef typename CGAL::Triangulation_2<GT,TDS>::All_edges_iterator edge_iterator;
// with just a typedef to Edge VC++ has ambiguities for function `next()`
struct halfedge_descriptor
{
face_descriptor first;
int second;
operator std::pair<face_descriptor, int>() { return std::make_pair(first,second); }
halfedge_descriptor()
{}
halfedge_descriptor(const typename Triangulation::Edge& e)
: first(e.first), second(e.second)
{}
halfedge_descriptor(face_descriptor fd, int i)
: first(fd), second(i)
{}
bool operator==(const halfedge_descriptor& other) const
{
return (first == other.first) && (second == other.second);
}
bool operator!=(const halfedge_descriptor& other) const
{
return (first != other.first) || (second != other.second);
}
bool operator<(const halfedge_descriptor& other) const
{
if(first < other.first) return true;
if(first > other.first) return false;
return second < other.second;
}
};
typedef CGAL::detail::T2_halfedge_descriptor<Triangulation> halfedge_descriptor;
typedef typename CGAL::Triangulation_2<GT,TDS>::All_halfedges_iterator halfedge_iterator;
@ -811,6 +828,42 @@ namespace boost {
};
} // namespace boost
namespace std {
#if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4099) // For VC10 it is class hash
#endif
template < class T>
struct hash;
template < class T, class EdgeBase>
struct hash<CGAL::detail::Edge<T,EdgeBase> > {
std::size_t operator()(const CGAL::detail::Edge<T,EdgeBase>& e) const
{
std::cerr << "Triangulation_2::Edge HashFct" << std::endl;
return hash_value(e);
}
};
template < class Tr>
struct hash<CGAL::detail::T2_halfedge_descriptor<Tr> > {
std::size_t operator()(const CGAL::detail::T2_halfedge_descriptor<Tr>& e) const
{
std::cerr << "Triangulation_2::halfedge_descriptor HashFct" << std::endl;
return hash_value(e);
}
};
#if defined(BOOST_MSVC)
# pragma warning(pop)
#endif
} // namespace std
//#include <CGAL/graph_traits_Delaunay_triangulation_2.h>
#endif // CGAL_GRAPH_TRAITS_TRIANGULATION_2_H

View File

@ -579,10 +579,15 @@ Section \ref ssecattributes "Cell Attributes").
Users can customize a combinatorial map thanks to an items class (see
Section \ref ssecitem "Combinatorial Map Items"), which defines the dart type and the
attribute types. These types may be different for different
dimensions, and they may also be void. The darts and attributes are
dimensions, and they may also be void.
The darts and attributes are
accessed through <I>handles</I>. A handle is a model of the
`Handle` concept, thus supporting the two dereference operators
`operator*` and `operator->`.
All handles are model of `LessThanComparable` and `Hashable`,
that is they can be used as keys in containers such as `std::map`
and `boost::unordered_map`.
\cgalFigureBegin{figdiagram_class,Diagramme_class.png}
UML diagram of the main classes of the package. k is the number of non void attributes.

View File

@ -0,0 +1,67 @@
# Created by the script cgal_create_CMakeLists
# This is the CMake script for compiling a set of CGAL applications.
project( Hash_map )
cmake_minimum_required(VERSION 2.6.2)
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_GREATER 2.6)
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_GREATER 2.8.3)
cmake_policy(VERSION 2.8.4)
else()
cmake_policy(VERSION 2.6)
endif()
endif()
set( CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true )
if ( COMMAND cmake_policy )
cmake_policy( SET CMP0003 NEW )
endif()
# CGAL and its components
find_package( CGAL QUIET COMPONENTS )
if ( NOT CGAL_FOUND )
message(STATUS "This project requires the CGAL library, and will not be compiled.")
return()
endif()
# include helper file
include( ${CGAL_USE_FILE} )
# Boost and its components
find_package( Boost REQUIRED )
if ( NOT Boost_FOUND )
message(STATUS "This project requires the Boost library, and will not be compiled.")
return()
endif()
# include for local directory
# include for local package
include_directories( BEFORE ../../include )
# Creating entries for all .cpp/.C files with "main" routine
# ##########################################################
include( CGAL_CreateSingleSourceCGALProgram )
create_single_source_cgal_program( "hm.cpp" )
create_single_source_cgal_program( "foreach.cpp" )
create_single_source_cgal_program( "triangulation.cpp" )
create_single_source_cgal_program( "polyhedron.cpp" )
create_single_source_cgal_program( "surface_mesh.cpp" )
create_single_source_cgal_program( "arrangement.cpp" )

View File

@ -0,0 +1,40 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Arr_segment_traits_2.h>
#include <CGAL/Arrangement_2.h>
#include <boost/unordered_map.hpp>
#include <unordered_map>
typedef int Number_type;
typedef CGAL::Simple_cartesian<Number_type> Kernel;
typedef CGAL::Arr_segment_traits_2<Kernel> Traits_2;
typedef Traits_2::Point_2 Point_2;
typedef Traits_2::X_monotone_curve_2 Segment_2;
typedef CGAL::Arrangement_2<Traits_2> Arrangement_2;
typedef Arrangement_2::Vertex_handle Vertex_handle;
typedef Arrangement_2::Halfedge_handle Halfedge_handle;
int main()
{
Arrangement_2 arr;
Segment_2 s1(Point_2(1, 3), Point_2(3, 5));
Segment_2 s2(Point_2(3, 5), Point_2(5, 3));
Segment_2 s3(Point_2(5, 3), Point_2(3, 1));
Segment_2 s4(Point_2(3, 1), Point_2(1, 3));
Segment_2 s5(Point_2(1, 3), Point_2(5, 3));
Halfedge_handle e1 = arr.insert_in_face_interior(s1, arr.unbounded_face());
Vertex_handle v1 = e1->source();
std::map<Vertex_handle,int> sm;
sm[v1]= 1;
std::unordered_map<Vertex_handle,int> sum;
sum[v1]= 1;
boost::unordered_map<Vertex_handle,int> bum;
bum[v1]= 1;
return 0;
}

View File

@ -0,0 +1,6 @@
OFF
3 1 0
0 0 0
1 0 0
0 1 0
3 0 1 2

View File

@ -0,0 +1,43 @@
#include <iostream>
#include <vector>
#include<boost/range/iterator_range.hpp>
#include <boost/foreach.hpp>
#include <CGAL/Iterator_range.h>
#include <CGAL/Timer.h>
#include <CGAL/Simple_cartesian.h>
typedef CGAL::Timer Timer;
int main()
{
int N = 100000;
std::vector<int> V(N), V2(N);
Timer t;
t.start();
for(int k=0; k < N; k++){
boost::iterator_range<std::vector<int>::iterator> bir(V.begin(), V.end());
int j = 0;
BOOST_FOREACH(int i, bir){
V2[j++] = i;
}
}
t.stop();
std::cerr << "boost::iterator_range: " << t.time() << "sec.\n";
t.reset();
t.start();
for(int k=0; k < N; k++){
int j = 0;
BOOST_FOREACH(int i, CGAL::make_range(V.begin(), V.end())){
V2[j++] = i;
}
}
t.stop();
std::cerr << "CGAL::iterator_range: " << t.time() << "sec.\n";
return 0;
}

View File

@ -0,0 +1,271 @@
#define NOHASH 1
#include <iostream>
#include <fstream>
#include <map>
#include <algorithm>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <CGAL/boost/graph/graph_traits_Surface_mesh.h>
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
#include <CGAL/boost/graph/properties_Polyhedron_3.h>
#include <CGAL/boost/graph/helpers.h>
#include <CGAL/Timer.h>
#include<boost/range/iterator_range.hpp>
#include <boost/unordered_map.hpp>
#include <unordered_map>
#include <boost/random/random_number_generator.hpp>
#include <boost/random/linear_congruential.hpp>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_3 Point_3;
typedef Kernel::Vector_3 Vector_3;
typedef CGAL::Timer Timer;
template <typename G, typename Map>
void
run(const G& g)
{
typedef typename boost::graph_traits<G>::vertex_descriptor vertex_descriptor;
typedef typename boost::property_map<G,CGAL::vertex_point_t>::const_type VPM;
VPM vpm = get(CGAL::vertex_point,g);
std::vector<vertex_descriptor> V, V2;
std::vector<Point_3> P1, P2;
BOOST_FOREACH(vertex_descriptor vd, vertices(g)){
V.push_back(vd);
V2.push_back(vd);
}
boost::rand48 random;
boost::random_number_generator<boost::rand48> rng(random);
std::random_shuffle(V.begin(), V.end(), rng);
Timer t;
#if 0
t.start();
Map vm;
BOOST_FOREACH(vertex_descriptor vd, V){
vm[vd] = get(vpm,vd);
}
t.stop(); std::cerr << "Insertion: " << t.time() << " sec. " << std::endl;
#endif
Vector_3 v(0,0,0);
std::size_t st=0;
#if 0
std::cerr << "BOOST_FOREACH std::vector<vertex_descriptor)\n";
t.reset(); t.start();
for(int i=0; i<100; i++){
BOOST_FOREACH(vertex_descriptor vd, V2){
#ifdef NOHASH
st += std::size_t(vd);
#else
typename Map::iterator it = vm.find(vd);
v = v + ((*it).second - CGAL::ORIGIN);
#endif
}
}
t.stop(); std::cerr << " " <<t.time() << " sec. " << std::endl;
#endif
#if 1
std::cerr << "BOOST_FOREACH boost::iterator_range r = vertices(g))\n";
t.reset(); t.start();
for(int i=0; i<100; i++){
boost::iterator_range<typename boost::graph_traits<G>::vertex_iterator> r = vertices(g);
BOOST_FOREACH(vertex_descriptor vd, r) {
#ifdef NOHASH
st += std::size_t(vd);
// v = v + (get(vpm,vd) - CGAL::ORIGIN);
#else
typename Map::iterator it = vm.find(vd);
v = v + ((*it).second - CGAL::ORIGIN);
#endif
}
}
t.stop(); std::cerr << " " <<t.time() << " sec. " << std::endl;
#endif
#if 1
std::cerr << "BOOST_FOREACH CGAL::Iterator_range r = vertices(g))\n";
t.reset(); t.start();
for(int i=0; i<100; i++){
CGAL::Iterator_range<typename boost::graph_traits<G>::vertex_iterator> ir = vertices(g);
BOOST_FOREACH(vertex_descriptor vd, ir) {
#ifdef NOHASH
st += std::size_t(vd);
//v = v + (get(vpm,vd) - CGAL::ORIGIN);
#else
typename Map::iterator it = vm.find(vd);
v = v + ((*it).second - CGAL::ORIGIN);
#endif
}
}
t.stop(); std::cerr << " " <<t.time() << " sec. " << std::endl;
#endif
#if 1
std::cerr << "BOOST_FOREACH vertices(g))\n";
t.reset(); t.start();
for(int i=0; i<100; i++){
BOOST_FOREACH(vertex_descriptor vd, vertices(g)) {
#ifdef NOHASH
st += std::size_t(vd);
//v = v + (get(vpm,vd) - CGAL::ORIGIN);
#else
typename Map::iterator it = vm.find(vd);
v = v + ((*it).second - CGAL::ORIGIN);
#endif
}
}
t.stop(); std::cerr << " " <<t.time() << " sec. " << std::endl;
#endif
#if 1
std::cerr << "for vertices(g))\n";
t.reset(); t.start();
for(int i=0; i<100; i++){
for(vertex_descriptor vd : vertices(g)) {
#ifdef NOHASH
st += std::size_t(vd);
//v = v + (get(vpm,vd) - CGAL::ORIGIN);
#else
typename Map::iterator it = vm.find(vd);
v = v + ((*it).second - CGAL::ORIGIN);
#endif
}
}
t.stop(); std::cerr << " " <<t.time() << " sec. " << std::endl;
#endif
#if 0
std::cerr << "boost::tie(vb,ve) = vertices(g);\n";
t.reset(); t.start();
for(int i=0; i<100; i++){
typename boost::graph_traits<G>::vertex_iterator vb, ve;
boost::tie(vb,ve) = vertices(g);
for(; vb != ve; ++vb) {
vertex_descriptor vd = *vb;
#ifdef NOHASH
st += std::size_t(vd);
//v = v + (get(vpm,vd) - CGAL::ORIGIN);
#else
typename Map::iterator it = vm.find(vd);
v = v + ((*it).second - CGAL::ORIGIN);
#endif
}
}
t.stop(); std::cerr << " " <<t.time() << " sec. " << std::endl;
#endif
std::cerr << "v = " << v << " " << st << std::endl;
}
struct blob {
int a, b, c, d, e, f, g;
};
int main(int , char* argv[])
{
{
typedef CGAL::Surface_mesh<Point_3> Mesh;
typedef boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
typedef std::map<vertex_descriptor,Point_3> SM;
typedef std::unordered_map<vertex_descriptor,Point_3> SUM;
typedef boost::unordered_map<vertex_descriptor,Point_3> BUM;
Mesh m;
std::ifstream input(argv[1]);
input >> m;
std::cerr << num_vertices(m) << " items\n";
std::cerr << "\nSurface_mesh std::map"<< std::endl;
run<Mesh,SM>(m);
#if 0
std::cerr << "\nSurface_mesh std::unordered_map"<< std::endl;
run<Mesh,SUM>(m);
std::cerr << "\nSurface_mesh boost::unordered_map"<< std::endl;
run<Mesh,BUM>(m);
#endif
}
#if 0
{
typedef CGAL::Polyhedron_3<Kernel> Mesh;
typedef boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
typedef std::map<vertex_descriptor,Point_3> SM;
typedef std::unordered_map<vertex_descriptor,Point_3> SUM;
typedef boost::unordered_map<vertex_descriptor,Point_3> BUM;
Mesh m;
std::ifstream input(argv[1]);
input >> m;
std::cerr << "\nPolyhedron_3 std::map" << std::endl;
run<Mesh,SM>(m);
std::cerr << "\nPolyhedron_3 std::unordered_map"<< std::endl;
run<Mesh,SUM>(m);
std::cerr << "\nPolyhedron_3 boost::unordered_map"<< std::endl;
run<Mesh,BUM>(m);
}
{
const int N = 3165798;
std::cerr << "\nHashing "<< N << " pointers\n";
std::vector<int> ints(N);
std::vector<blob> data(N);
for(int i =0; i <N ; i++){
ints[i]=i;
}
std::random_shuffle(ints.begin(), ints.end());
{
boost::unordered_map<blob*,int> um;
Timer t;
t.start();
for(int i= 0; i < N; i++){
um[& (data[ints[i]])] = i;
}
t.stop();
std::cerr << " boost::unordered_map: " << t.time() << " sec.\n";
}
{
std::unordered_map<blob*,int> um;
Timer t;
t.start();
for(int i= 0; i < N; i++){
um[& (data[ints[i]])] = i;
}
t.stop();
std::cerr << " std::unordered_map: " << t.time() << " sec.\n";
}
}
#endif
return 0;
}

View File

@ -0,0 +1,152 @@
#include <iostream>
#include <fstream>
#include <map>
#include <algorithm>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
#include <CGAL/boost/graph/properties_Polyhedron_3.h>
#include <CGAL/Unique_hash_map.h>
#include <CGAL/Timer.h>
#include<boost/range/iterator_range.hpp>
#include <boost/unordered_map.hpp>
#include <unordered_map>
#include <boost/random/random_number_generator.hpp>
#include <boost/random/linear_congruential.hpp>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_3 Point_3;
typedef Kernel::Vector_3 Vector_3;
typedef CGAL::Polyhedron_3<Kernel> Mesh;
typedef boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
typedef CGAL::Timer Timer;
void fct(int ii, int jj)
{
typedef std::map<vertex_descriptor,Point_3> SM;
typedef std::unordered_map<vertex_descriptor,Point_3> SUM;
typedef boost::unordered_map<vertex_descriptor,Point_3> BUM;
typedef CGAL::Unique_hash_map<vertex_descriptor, Point_3> UHM;
Mesh mesh;
typedef boost::property_map<Mesh,CGAL::vertex_point_t>::type VPM;
VPM vpm = get(CGAL::vertex_point,mesh);
Vector_3 v(0,0,0);
for(int i =0; i < ii; i++){
vertex_descriptor vd = add_vertex(mesh);
put(vpm,vd, Point_3(i,0,0));
}
std::vector<vertex_descriptor> V;
for(vertex_descriptor vd : vertices(mesh)){
V.push_back(vd);
}
random_shuffle(V.begin(), V.end());
Timer tsmc, tsumc, tbumc, tuhmc;
Timer tsmq, tsumq, tbumq, tuhmq;
for(int j=0; j <jj; j++){
{
tsmc.start();
SM sm;
for(vertex_descriptor vh : V){
sm[vh] = get(vpm,vh);
}
tsmc.stop();
tsmq.start();
for(vertex_descriptor vh : V){
v = v + (sm[vh] - CGAL::ORIGIN);
}
tsmq.stop();
}
{
tsumc.start();
SUM sm;
for(vertex_descriptor vh : V){
sm[vh] = get(vpm,vh);
}
tsumc.stop();
tsumq.start();
for(vertex_descriptor vh : V){
v = v + (sm[vh] - CGAL::ORIGIN);
}
tsumq.stop();
}
{
tbumc.start();
BUM sm;
for(vertex_descriptor vh : V){
sm[vh] = get(vpm,vh);
}
tbumc.stop();
tbumq.start();
for(vertex_descriptor vh : V){
v = v + (sm[vh] - CGAL::ORIGIN);
}
tbumq.stop();
}
{
tuhmc.start();
UHM sm;
for(vertex_descriptor vh : V){
sm[vh] = get(vpm,vh);
}
tuhmc.stop();
tuhmq.start();
for(vertex_descriptor vh : V){
v = v + (sm[vh] - CGAL::ORIGIN);
}
tuhmq.stop();
}
}
std::cerr << ii << " items and queries (repeated " << jj << " times)" << std::endl;
std::cerr << "std::map construction : "<< tsmc.time() << " sec." << std::endl;
std::cerr << "std::map queries : "<< tsmq.time() << " sec." << std::endl;
std::cerr << "std::unordered_map construction : "<< tsumc.time() << " sec." << std::endl;
std::cerr << "std::unordered_map queries : "<< tsumq.time() << " sec." << std::endl;
std::cerr << "boost::unordered_map construction : "<< tbumc.time() << " sec." << std::endl;
std::cerr << "boost::unordered_map queries : "<< tbumq.time() << " sec.\n" << std::endl;
std::cerr << "Unique_hash_map construction : "<< tuhmc.time() << " sec." << std::endl;
std::cerr << "Unique_hash_map queries : "<< tuhmq.time() << " sec.\n" << std::endl;
}
int main(int , char* argv[])
{
fct(1000000, 10);
fct(100000, 100);
fct(10000, 1000);
fct(1000, 10000);
fct(500, 20000);
fct(250, 40000);
fct(100, 100000);
return 0;
}

View File

@ -0,0 +1,131 @@
#include <iostream>
#include <fstream>
#include <map>
#include <algorithm>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <CGAL/boost/graph/graph_traits_Surface_mesh.h>
#include <CGAL/boost/graph/properties_Surface_mesh.h>
#include <CGAL/Timer.h>
#include<boost/range/iterator_range.hpp>
#include <boost/unordered_map.hpp>
#include <unordered_map>
#include <boost/random/random_number_generator.hpp>
#include <boost/random/linear_congruential.hpp>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_3 Point_3;
typedef Kernel::Vector_3 Vector_3;
typedef CGAL::Surface_mesh<Point_3> Mesh;
typedef boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
typedef CGAL::Timer Timer;
void fct(int ii, int jj)
{
typedef std::map<vertex_descriptor,Point_3> SM;
typedef std::unordered_map<vertex_descriptor,Point_3> SUM;
typedef boost::unordered_map<vertex_descriptor,Point_3> BUM;
Mesh mesh;
typedef boost::property_map<Mesh,CGAL::vertex_point_t>::type VPM;
VPM vpm = get(CGAL::vertex_point,mesh);
Vector_3 v(0,0,0);
for(int i =0; i < ii; i++){
vertex_descriptor vd = add_vertex(mesh);
put(vpm,vd, Point_3(i,0,0));
}
std::vector<vertex_descriptor> V;
for(vertex_descriptor vd : vertices(mesh)){
V.push_back(vd);
}
random_shuffle(V.begin(), V.end());
Timer tsmc, tsumc, tbumc;
Timer tsmq, tsumq, tbumq;
for(int j=0; j <jj; j++){
{
tsmc.start();
SM sm;
for(vertex_descriptor vh : V){
sm[vh] = get(vpm,vh);
}
tsmc.stop();
tsmq.start();
for(vertex_descriptor vh : V){
v = v + (sm[vh] - CGAL::ORIGIN);
}
tsmq.stop();
}
{
tsumc.start();
SUM sm;
for(vertex_descriptor vh : V){
sm[vh] = get(vpm,vh);
}
tsumc.stop();
tsumq.start();
for(vertex_descriptor vh : V){
v = v + (sm[vh] - CGAL::ORIGIN);
}
tsumq.stop();
}
{
tbumc.start();
BUM sm;
for(vertex_descriptor vh : V){
sm[vh] = get(vpm,vh);
}
tbumc.stop();
tbumq.start();
for(vertex_descriptor vh : V){
v = v + (sm[vh] - CGAL::ORIGIN);
}
tbumq.stop();
}
}
std::cerr << ii << " items and queries (repeated " << jj << " times)" << std::endl;
std::cerr << "std::map construction : "<< tsmc.time() << " sec." << std::endl;
std::cerr << "std::map queries : "<< tsmq.time() << " sec." << std::endl;
std::cerr << "std::unordered_map construction : "<< tsumc.time() << " sec." << std::endl;
std::cerr << "std::unordered_map queries : "<< tsumq.time() << " sec." << std::endl;
std::cerr << "boost::unordered_map construction : "<< tbumc.time() << " sec." << std::endl;
std::cerr << "boost::unordered_map queries : "<< tbumq.time() << " sec.\n" << std::endl;
}
int main(int , char* argv[])
{
fct(1000000, 10);
fct(100000, 100);
fct(10000, 1000);
fct(1000, 10000);
fct(500, 20000);
fct(250, 40000);
fct(100, 100000);
return 0;
}

View File

@ -0,0 +1,129 @@
#include <iostream>
#include <fstream>
#include <map>
#include <algorithm>
#include <CGAL/Delaunay_triangulation_2.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/point_generators_2.h>
#include <CGAL/Timer.h>
#include<boost/range/iterator_range.hpp>
#include <boost/unordered_map.hpp>
#include <unordered_map>
#include <boost/random/random_number_generator.hpp>
#include <boost/random/linear_congruential.hpp>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_2 Point_2;
typedef Kernel::Vector_2 Vector_2;
typedef CGAL::Creator_uniform_2<double,Point_2> Pt_creator;
typedef CGAL::Random_points_in_disc_2<Point_2,Pt_creator> Random_points;;
typedef CGAL::Delaunay_triangulation_2<Kernel> Dt;
typedef Dt::Vertex_handle Vertex_handle;
typedef Dt::Finite_vertices_iterator Finite_vertices_iterator;
typedef CGAL::Timer Timer;
void fct(int ii, int jj)
{
typedef std::map<Vertex_handle,Point_2> SM;
typedef std::unordered_map<Vertex_handle,Point_2> SUM;
typedef boost::unordered_map<Vertex_handle,Point_2> BUM;
Dt dt;
Vector_2 v(0,0);
Random_points rp( 250);
std::vector<Point_2> points;
for(int i =0; i < ii; i++){
Point_2 p = *rp++;
points.push_back(p);
}
dt.insert(points.begin(), points.end());
std::vector<Vertex_handle> vertices;
Finite_vertices_iterator b = dt.finite_vertices_begin(), e = dt.finite_vertices_end();
for(; b!=e; ++b){
vertices.push_back(b);
}
random_shuffle(vertices.begin(), vertices.end());
Timer tsmc, tsumc, tbumc;
Timer tsmq, tsumq, tbumq;
for(int j=0; j <jj; j++){
{
tsmc.start();
SM sm;
for(Vertex_handle vh : vertices){
sm[vh] = vh->point();
}
tsmc.stop();
tsmq.start();
for(Vertex_handle vh : vertices){
v = v + (sm[vh] - CGAL::ORIGIN);
}
tsmq.stop();
}
{
tsumc.start();
SUM sm;
for(Vertex_handle vh : vertices){
sm[vh] = vh->point();
}
tsumc.stop();
tsumq.start();
for(Vertex_handle vh : vertices){
v = v + (sm[vh] - CGAL::ORIGIN);
}
tsumq.stop();
}
{
tbumc.start();
BUM sm;
for(Vertex_handle vh : vertices){
sm[vh] = vh->point();
}
tbumc.stop();
tbumq.start();
for(Vertex_handle vh : vertices){
v = v + (sm[vh] - CGAL::ORIGIN);
}
tbumq.stop();
}
}
std::cerr << ii << " items and queries (repeated " << jj << " times)" << std::endl;
std::cerr << "std::map construction : "<< tsmc.time() << " sec." << std::endl;
std::cerr << "std::map queries : "<< tsmq.time() << " sec." << std::endl;
std::cerr << "std::unordered_map construction : "<< tsumc.time() << " sec." << std::endl;
std::cerr << "std::unordered_map queries : "<< tsumq.time() << " sec." << std::endl;
std::cerr << "boost::unordered_map construction : "<< tbumc.time() << " sec." << std::endl;
std::cerr << "boost::unordered_map queries : "<< tbumq.time() << " sec.\n" << std::endl;
}
int main(int , char* argv[])
{
fct(1000000, 10);
fct(100000, 100);
fct(10000, 1000);
fct(1000, 10000);
fct(500, 20000);
fct(250, 40000);
fct(100, 100000);
return 0;
}

View File

@ -0,0 +1,81 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Arr_segment_traits_2.h>
#include <CGAL/Arrangement_2.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Triangulation_2.h>
#include <CGAL/Linear_cell_complex.h>
#include <CGAL/boost/graph/graph_traits_Arrangement_2.h>
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
#include <CGAL/boost/graph/graph_traits_Triangulation_2.h>
#include <map>
#include <boost/unordered_map.hpp>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef CGAL::Arr_segment_traits_2<Kernel> Arrangement_traits_2;
typedef CGAL::Arrangement_2<Arrangement_traits_2> Arrangement_2;
typedef CGAL::Polyhedron_3<Kernel> Polyhedron;
typedef CGAL::Surface_mesh<Kernel::Point_3> Surface_mesh;
typedef CGAL::Triangulation_2<Kernel> Triangulation_2;
typedef CGAL::Linear_cell_complex<3, 3> Linear_cell_complex_3;
template <typename P>
void
fct(const P& )
{
typedef typename boost::graph_traits<P>::vertex_descriptor vertex_descriptor;
std::map<vertex_descriptor,int> M;
vertex_descriptor vd;
M.find(vd);
boost::unordered_map<vertex_descriptor, int> U;
U[vd] = 12;
}
void fct2()
{
typedef Linear_cell_complex_3::Dart_handle dh;
typedef Linear_cell_complex_3::Vertex_attribute_handle vh;
{ // For dart handle
std::map<dh, int> M;
dh e;
M.find(e);
boost::unordered_map<dh, int> U;
U[e] = 12;
}
{ // For vertex attribute handle
std::map<vh, int> M;
vh e;
M.find(e);
boost::unordered_map<vh, int> U;
U[e] = 12;
}
}
int main()
{
Arrangement_2 A;
fct(A);
Polyhedron P;
fct(P);
Surface_mesh S;
fct(S);
Triangulation_2 T;
fct(T);
fct2();
return 0;
}

View File

@ -128,6 +128,13 @@ and <code>src/</code> directories).
<li>The code of the 3D demos now use modern OpenGL, with shaders,
instead of the fixed pipeline API of OpenGL-1.</li>
</ul>
<h3>General</h3>
<ul>
<li>Support for unordered sets and maps of the stdlib and of boost for
handle and index classes.
</li>
</ul>
<!-- New packages -->
<!-- sdglinf-philaris begin-->

View File

@ -837,6 +837,11 @@ public:
convenience, the `Point_iterator` enumerates all points in the polyhedral
surface in the same order as the `Vertex_iterator`, but with the
value type `Point`. Similarly, a `Plane_iterator` is provided.
All handles are model of `LessThanComparable` and `Hashable`,
that is they can be used as keys in containers such as `std::map`
and `boost::unordered_map`.
*/
/// @{

View File

@ -834,4 +834,12 @@ static void * & pointer(T &t);
}; /* end Compact_container_traits */
/*!
returns a hash value for the pointee of `i`.
\relates Compact_container
*/
template <class T, class A>
std::size_t hash_value(const Compact_container<T,A>::iterator i);
} /* end namespace CGAL */

View File

@ -762,4 +762,22 @@ void sort();
}; /* end In_place_list */
/*!
returns a hash value for the pointee of `i`.
\relates In_place_list
*/
template <class T, bool>
std::size_t hash_value(const In_place_list<T,bool>::iterator i);
/*!
returns a hash value for the pointee of `i`.
\relates In_place_list
*/
template <class T, class bool>
std::size_t hash_value(const In_place_list<T,bool>::const_iterator i);
} /* end namespace CGAL */

View File

@ -0,0 +1,23 @@
/*!
\ingroup PkgStlExtensionConcepts
\cgalConcept
A type `Key` is a model of the concept `Hashable` if the
specializations `boost::hash<Key>` and `std::hash<Key>` exist.
\cgalHasModel All handles and indices of \cgal data structures.
\sa `CGAL::Unique_hash_map<Key,Mapped,Hash>`
\sa <A HREF="http://www.cplusplus.com/reference/unordered_set/unordered_set/">`std::unordered_set`</a>
\sa <A HREF="http://www.cplusplus.com/reference/unordered_set/unordered_map/">`std::unordered_map`</a>
\sa <A HREF="http://www.boost.org/doc/libs/release/doc/html/boost/unordered_set.html">`boost::unordered_set`</a>
\sa <A HREF="http://www.boost.org/doc/libs/release/doc/html/boost/unordered_map.html">`boost::unordered_map`</a>
*/
class Hashable {
};

View File

@ -130,6 +130,13 @@ looking up keys whose type may differ from `Type`, as long as users supply
a comparison functor `CompareKey`, between the keys and set elements;
and catenating and splitting sets.
\section stl_hash Hashing
For handles and indices of vertices, halfedges, faces, etc., we provide specializations of `boost::hash<T>` and `std::hash<T>`, so that they can be used with classes such as `boost::unordered_map`.
\cgalExample{STL_Extension/unordered_map.cpp}
\section stl_polyobject Polymorphic Object
The class `Object` can store an object of whatever other type.

View File

@ -2,3 +2,5 @@ Manual
Circulator
Number_types
Kernel_23
Miscellany
Surface_mesh

View File

@ -3,4 +3,5 @@
\example STL_Extension/in_place_list_prog.cpp
\example STL_Extension/min_element_if_example.cpp
\example STL_Extension/min_max_element_example.cpp
\example STL_Extension/unordered_map.cpp
*/

View File

@ -0,0 +1,19 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <boost/unordered_map.hpp>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_3 Point_3;
typedef CGAL::Surface_mesh<Point_3> Mesh;
typedef boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
int main()
{
boost::unordered_map<vertex_descriptor, int> bum;
Mesh mesh;
vertex_descriptor vd = mesh.add_vertex();
bum[vd] = 7812;
return 0;
}

View File

@ -28,6 +28,7 @@
#include <algorithm>
#include <vector>
#include <cstring>
#include <functional>
#include <CGAL/memory.h>
#include <CGAL/iterator.h>
@ -1167,8 +1168,39 @@ namespace internal {
return rhs.operator->() != NULL;
}
template <class DSC, bool Const>
std::size_t hash_value(const CC_iterator<DSC, Const>& i)
{
return reinterpret_cast<std::size_t>(&*i) / sizeof(typename DSC::value_type);
}
} // namespace internal
} //namespace CGAL
namespace std {
#if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4099) // For VC10 it is class hash
#endif
template < class T>
struct hash;
template < class DSC, bool Const >
struct hash<CGAL::internal::CC_iterator<DSC, Const> >
: public std::unary_function<CGAL::internal::CC_iterator<DSC, Const>, std::size_t> {
std::size_t operator()(const CGAL::internal::CC_iterator<DSC, Const>& i) const
{
return reinterpret_cast<std::size_t>(&*i) / sizeof(typename DSC::value_type);
}
};
#if defined(BOOST_MSVC)
# pragma warning(pop)
#endif
}
#endif // CGAL_COMPACT_CONTAINER_H

View File

@ -33,6 +33,7 @@
#include <functional>
#include <algorithm>
#include <CGAL/memory.h>
#include <boost/functional/hash.hpp>
namespace CGAL {
@ -170,6 +171,24 @@ namespace internal {
return In_place_list_iterator<T,Alloc>(const_cast<T*>(node));
}
};
template <class T, class Alloc>
std::size_t hash_value(const In_place_list_iterator<T,Alloc>& i)
{
T* ptr = &*i;
return reinterpret_cast<std::size_t>(ptr)/ sizeof(T);
}
template <class T, class Alloc>
std::size_t hash_value(const In_place_list_const_iterator<T,Alloc>& i)
{
T* ptr = &*i;
return reinterpret_cast<std::size_t>(ptr)/ sizeof(T);
}
}
@ -752,4 +771,41 @@ void In_place_list<T,managed,Alloc>::sort() {
} //namespace CGAL
namespace std {
#if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4099) // For VC10 it is class hash
#endif
template < class T>
struct hash;
template < class T, class Alloc >
struct hash<CGAL::internal::In_place_list_iterator<T, Alloc> >
: public std::unary_function<CGAL::internal::In_place_list_iterator<T, Alloc>, std::size_t> {
std::size_t operator()(const CGAL::internal::In_place_list_iterator<T, Alloc>& i) const
{
const T* ptr = &*i;
return reinterpret_cast<std::size_t>(ptr)/ sizeof(T);
}
};
template < class T, class Alloc >
struct hash<CGAL::internal::In_place_list_const_iterator<T, Alloc> >
: public std::unary_function<CGAL::internal::In_place_list_const_iterator<T, Alloc>, std::size_t> {
std::size_t operator()(const CGAL::internal::In_place_list_const_iterator<T, Alloc>& i) const
{
const T* ptr = &*i;
return reinterpret_cast<std::size_t>(ptr)/ sizeof(T);
}
};
#if defined(BOOST_MSVC)
# pragma warning(pop)
#endif
}
#endif // CGAL_IN_PLACE_LIST_H

View File

@ -22,7 +22,7 @@
#include <CGAL/tuple.h>
#include <utility>
#include <boost/foreach.hpp>
namespace CGAL {
@ -45,6 +45,11 @@ namespace CGAL {
: Base(b,e)
{}
// Iterator_range(const Iterator_range& ip)
// : Base(ip)
// {}
Iterator_range(const std::pair<I,I>& ip)
: Base(ip)
{}
@ -74,29 +79,23 @@ namespace CGAL {
return Iterator_range<T>(b,e);
}
template<typename T>
inline T range_begin( Iterator_range<T> & x )
{
return x.first;
}
template<typename T>
inline T range_end( Iterator_range<T> & x )
{
return x.second;
}
template<typename T>
inline T range_begin(const Iterator_range<T>& x )
{
return x.first;
}
template<typename T>
inline T range_end(const Iterator_range<T>& x )
{
return x.second;
}
} // namespace CGAL
// At global scope...
template<typename T>
inline boost::mpl::true_ *
boost_foreach_is_lightweight_proxy( CGAL::Iterator_range<T> *&, boost::foreach::tag )
{
return 0;
}
namespace boost { namespace foreach
{
template<typename T>
struct is_lightweight_proxy< CGAL::Iterator_range<T> >
: mpl::true_
{
};
}}
#endif // CGAL_ITERATOR_RANGE_H

View File

@ -27,6 +27,7 @@
#include <vector>
#include <string>
#include <typeinfo>
#include <functional>
#include <boost/cstdint.hpp>
#include <boost/array.hpp>
@ -49,12 +50,213 @@
#include <CGAL/boost/graph/Euler_operations.h>
namespace CGAL {
#ifndef DOXYGEN_RUNNING
/// Base class for vertex, halfedge, edge, and face index.
///
/// \attention Note that `Index` is not a model of the concept `Handle`,
/// because it cannot be dereferenced.
/// \sa `Vertex_index`, `Halfedge_index`, `Edge_index`, `Face_index`.
template<typename T>
class SM_Index
{
public:
typedef boost::uint32_t size_type;
/// Constructor. %Default construction creates an invalid index.
/// We write -1, which is <a href="http://en.cppreference.com/w/cpp/concept/numeric_limits">
/// <tt>std::numeric_limits<size_type>::max()</tt></a>
/// as `size_type` is an unsigned type.
explicit SM_Index(size_type _idx=-1) : idx_(_idx) {}
/// Get the underlying index of this index
operator size_type() const { return idx_; }
/// reset index to be invalid (index=-1)
void reset() { idx_=-1; }
/// return whether the index is valid, i.e., the index is not equal to -1.
bool is_valid() const {
size_type inf = -1;
return idx_ != inf;
}
/// are two indices equal?
bool operator==(const T& _rhs) const {
return idx_ == _rhs.idx_;
}
/// are two indices different?
bool operator!=(const T& _rhs) const {
return idx_ != _rhs.idx_;
}
/// Comparison by index.
bool operator<(const T& _rhs) const {
return idx_ < _rhs.idx_;
}
/// increments the internal index. This operation does not
/// guarantee that the index is valid or undeleted after the
/// increment.
SM_Index& operator++() { ++idx_; return *this; }
/// decrements the internal index. This operation does not
/// guarantee that the index is valid or undeleted after the
/// decrement.
SM_Index& operator--() { --idx_; return *this; }
/// increments the internal index. This operation does not
/// guarantee that the index is valid or undeleted after the
/// increment.
SM_Index operator++(int) { SM_Index tmp(*this); ++idx_; return tmp; }
/// decrements the internal index. This operation does not
/// guarantee that the index is valid or undeleted after the
/// decrement.
SM_Index operator--(int) { SM_Index tmp(*this); --idx_; return tmp; }
private:
size_type idx_;
};
template <class T>
std::size_t hash_value(const SM_Index<T>& i)
{
std::size_t ret = i;
return ret;
}
// Implementation for Surface_mesh::Vertex_index
class SM_Vertex_index
: public SM_Index<SM_Vertex_index>
{
public:
SM_Vertex_index() : SM_Index<SM_Vertex_index>(-1) {}
explicit SM_Vertex_index(size_type _idx) : SM_Index<SM_Vertex_index>(_idx) {}
friend std::ostream& operator<<(std::ostream& os, SM_Vertex_index const& v)
{
return (os << 'v' << (size_type)v );
}
};
// Implementation of Surface_mesh::Halfedge_index
class SM_Halfedge_index
: public SM_Index<SM_Halfedge_index>
{
public:
SM_Halfedge_index() : SM_Index<SM_Halfedge_index>(-1) {}
explicit SM_Halfedge_index(size_type _idx) : SM_Index<SM_Halfedge_index>(_idx) {}
friend std::ostream& operator<<(std::ostream& os, SM_Halfedge_index const& h)
{
return (os << 'h' << (size_type)h );
}
};
/// Implementation of Surfae_mesh::Face_index
class SM_Face_index
: public SM_Index<SM_Face_index>
{
public:
SM_Face_index() : SM_Index<SM_Face_index>(-1) {}
explicit SM_Face_index(size_type _idx) : SM_Index<SM_Face_index>(_idx) {}
friend std::ostream& operator<<(std::ostream& os, SM_Face_index const& f)
{
return (os << 'f' << (size_type)f );
}
};
/// Implementation of Surface_mesh::Edge_index
class SM_Edge_index
{
public:
typedef boost::uint32_t size_type;
SM_Edge_index() : halfedge_(-1) { }
SM_Edge_index(size_type idx) : halfedge_(idx * 2) { }
SM_Edge_index(SM_Halfedge_index he) : halfedge_(he) { }
// returns the internal halfedge.
SM_Halfedge_index halfedge() const { return halfedge_; }
// returns the underlying index of this index.
operator size_type() const { return (size_type)halfedge_ / 2; }
// resets index to be invalid (index=-1)
void reset() { halfedge_.reset(); }
// returns whether the index is valid, i.e., the index is not equal to -1.
bool is_valid() const { return halfedge_.is_valid(); }
// Are two indices equal?
bool operator==(const SM_Edge_index& other) const { return (size_type)(*this) == (size_type)other; }
// Are two indices different?
bool operator!=(const SM_Edge_index& other) const { return (size_type)(*this) != (size_type)other; }
// compares by index.
bool operator<(const SM_Edge_index& other) const { return (size_type)(*this) < (size_type)other;}
// decrements the internal index. This operation does not
// guarantee that the index is valid or undeleted after the
// decrement.
SM_Edge_index& operator--() { halfedge_ = SM_Halfedge_index((size_type)halfedge_ - 2); return *this; }
// increments the internal index. This operation does not
// guarantee that the index is valid or undeleted after the
// increment.
SM_Edge_index& operator++() { halfedge_ = SM_Halfedge_index((size_type)halfedge_ + 2); return *this; }
// decrements internal index. This operation does not
// guarantee that the index is valid or undeleted after the
// decrement.
SM_Edge_index operator--(int) { SM_Edge_index tmp(*this); halfedge_ = SM_Halfedge_index((size_type)halfedge_ - 2); return tmp; }
// increments internal index. This operation does not
// guarantee that the index is valid or undeleted after the
// increment.
SM_Edge_index operator++(int) { SM_Edge_index tmp(*this); halfedge_ = SM_Halfedge_index((size_type)halfedge_ + 2); return tmp; }
// prints the index and a short identification string to an ostream.
friend std::ostream& operator<<(std::ostream& os, SM_Edge_index const& e)
{
return (os << 'e' << (size_type)e << " on " << e.halfedge());
}
friend std::size_t hash_value(const SM_Edge_index& i)
{
return i;
}
private:
SM_Halfedge_index halfedge_;
};
#endif
/// \ingroup PkgSurface_mesh
/// This class is a data structure that can be used as halfedge data structure or polyhedral
/// surface. It is an alternative to the classes `HalfedgeDS` and `Polyhedron_3`
/// defined in the packages \ref PkgHDSSummary and \ref PkgPolyhedronSummary.
/// The main difference is that it is indexed based and not pointer based,
/// and that the mechanism for adding information to vertices, halfedges,
/// and that the mechanism for adding information to vertices, halfedges, edges,
/// and faces is much simpler and done at runtime and not at compile time.
/// When elements are removed, they are only marked as removed, and a garbage
/// collection function must be called to really remove them.
@ -575,85 +777,21 @@ private:
///
///@{
#ifndef DOXYGEN_RUNNING
/// Base class for vertex, halfedge, edge, and face index.
///
/// \attention Note that `Index` is not a model of the concept `Handle`,
/// because it cannot be dereferenced.
/// \sa `Vertex_index`, `Halfedge_index`, `Edge_index`, `Face_index`.
template<typename T>
class Index
{
public:
/// Constructor. %Default construction creates an invalid index.
/// We write -1, which is <a href="http://en.cppreference.com/w/cpp/concept/numeric_limits">
/// <tt>std::numeric_limits<size_type>::max()</tt></a>
/// as `size_type` is an unsigned type.
explicit Index(size_type _idx=-1) : idx_(_idx) {}
/// Get the underlying index of this index
operator size_type() const { return idx_; }
/// reset index to be invalid (index=-1)
void reset() { idx_=-1; }
/// return whether the index is valid, i.e., the index is not equal to -1.
bool is_valid() const {
size_type inf = -1;
return idx_ != inf;
}
/// are two indices equal?
bool operator==(const T& _rhs) const {
return idx_ == _rhs.idx_;
}
/// are two indices different?
bool operator!=(const T& _rhs) const {
return idx_ != _rhs.idx_;
}
/// Comparison by index.
bool operator<(const T& _rhs) const {
return idx_ < _rhs.idx_;
}
/// increments the internal index. This operation does not
/// guarantee that the index is valid or undeleted after the
/// increment.
Index& operator++() { ++idx_; return *this; }
/// decrements the internal index. This operation does not
/// guarantee that the index is valid or undeleted after the
/// decrement.
Index& operator--() { --idx_; return *this; }
/// increments the internal index. This operation does not
/// guarantee that the index is valid or undeleted after the
/// increment.
Index operator++(int) { Index tmp(*this); ++idx_; return tmp; }
/// decrements the internal index. This operation does not
/// guarantee that the index is valid or undeleted after the
/// decrement.
Index operator--(int) { Index tmp(*this); --idx_; return tmp; }
private:
size_type idx_;
};
#endif
#ifdef DOXYGEN_RUNNING
/// This class represents a vertex.
/// \cgalModels `Index`
/// \cgalModels `LessThanComparable`
/// \cgalModels `Hashable`
/// \sa `Halfedge_index`, `Edge_index`, `Face_index`
class Vertex_index
#ifndef DOXYGEN_RUNNING
: public Index<Vertex_index>
#endif
{
public:
/// %Default constructor.
Vertex_index() : Index<Vertex_index>(-1) {}
Vertex_index() : SM_Index<Vertex_index>(-1) {}
explicit Vertex_index(size_type _idx) : Index<Vertex_index>(_idx) {}
explicit Vertex_index(size_type _idx) : SM_Index<Vertex_index>(_idx) {}
/// prints the index and a short identification string to an ostream.
friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Vertex_index const& v)
@ -661,20 +799,24 @@ private:
return (os << 'v' << (size_type)v );
}
};
#else
typedef SM_Vertex_index Vertex_index;
#endif
#ifdef DOXYGEN_RUNNING
/// This class represents a halfedge.
/// \cgalModels `Index`
/// \cgalModels `LessThanComparable`
/// \cgalModels `Hashable`
/// \sa `Vertex_index`, `Edge_index`, `Face_index`
class Halfedge_index
#ifndef DOXYGEN_RUNNING
: public Index<Halfedge_index>
#endif
{
public:
/// %Default constructor
Halfedge_index() : Index<Halfedge_index>(-1) {}
Halfedge_index() : SM_Index<Halfedge_index>(-1) {}
explicit Halfedge_index(size_type _idx) : Index<Halfedge_index>(_idx) {}
explicit Halfedge_index(size_type _idx) : SM_Index<Halfedge_index>(_idx) {}
/// prints the index and a short identification string to an ostream.
friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Halfedge_index const& h)
@ -683,20 +825,23 @@ private:
}
};
#else
typedef SM_Halfedge_index Halfedge_index;
#endif
#ifdef DOXYGEN_RUNNING
/// This class represents a face
/// \cgalModels `Index`
/// \cgalModels `LessThanComparable`
/// \cgalModels `Hashable`
/// \sa `Vertex_index`, `Halfedge_index`, `Edge_index`
class Face_index
#ifndef DOXYGEN_RUNNING
: public Index<Face_index>
#endif
{
public:
/// %Default constructor
Face_index() : Index<Face_index>(-1) {}
Face_index() : SM_Index<Face_index>(-1) {}
explicit Face_index(size_type _idx) : Index<Face_index>(_idx) {}
explicit Face_index(size_type _idx) : SM_Index<Face_index>(_idx) {}
/// prints the index and a short identification string to an ostream.
friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Face_index const& f)
@ -704,9 +849,15 @@ private:
return (os << 'f' << (size_type)f );
}
};
#else
typedef SM_Face_index Face_index;
#endif
#ifdef DOXYGEN_RUNNING
/// This class represents an edge.
/// \cgalModels `Index`
/// \cgalModels `LessThanComparable`
/// \cgalModels `Hashable`
/// \sa `Vertex_index`, `Halfedge_index`, `Face_index`
class Edge_index
{
@ -770,7 +921,9 @@ private:
private:
Halfedge_index halfedge_;
};
#else
typedef SM_Edge_index Edge_index;
#endif
///@}
@ -824,8 +977,9 @@ private: //------------------------------------------------------ iterator types
Index_iterator() : hnd_(), mesh_(NULL) {}
Index_iterator(const Index_& h, const Surface_mesh* m)
: hnd_(h), mesh_(m) {
if (mesh_ && mesh_->has_garbage())
if (mesh_ && mesh_->has_garbage()){
while (mesh_->has_valid_index(hnd_) && mesh_->is_removed(hnd_)) ++hnd_;
}
}
private:
friend class boost::iterator_core_access;
@ -833,14 +987,17 @@ private: //------------------------------------------------------ iterator types
{
++hnd_;
CGAL_assertion(mesh_ != NULL);
while (mesh_->has_garbage() && mesh_->has_valid_index(hnd_) && mesh_->is_removed(hnd_)) ++hnd_;
}
if(mesh_->has_garbage())
while ( mesh_->has_valid_index(hnd_) && mesh_->is_removed(hnd_)) ++hnd_;
}
void decrement()
{
--hnd_;
CGAL_assertion(mesh_ != NULL);
while (mesh_->has_garbage() && mesh_->has_valid_index(hnd_) && mesh_->is_removed(hnd_)) --hnd_;
if(mesh_->has_garbage())
while ( mesh_->has_valid_index(hnd_) && mesh_->is_removed(hnd_)) --hnd_;
}
bool equal(const Index_iterator& other) const
@ -852,6 +1009,7 @@ private: //------------------------------------------------------ iterator types
Index_ hnd_;
const Surface_mesh* mesh_;
};
public:
/// \name Range Types
@ -1606,7 +1764,8 @@ public:
bool has_valid_index(Vertex_index v) const
{
return ((size_type)v < num_vertices());
}
}
/// returns whether the index of halfedge `h` is valid, that is within the current array bounds.
bool has_valid_index(Halfedge_index h) const
{
@ -2310,6 +2469,7 @@ private: //------------------------------------------------------- private data
}
/// @cond CGAL_DOCUMENT_INTERNALS
inline std::istream& sm_skip_comments( std::istream& in) {
char c;
in >> c;
@ -2778,7 +2938,78 @@ collect_garbage()
garbage_ = false;
}
} // CGAL
namespace std {
#if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable:4099) // For VC10 it is class hash
#endif
#ifndef DOXYGEN_RUNNING
template < class T>
struct hash;
#endif
template <>
struct hash<CGAL::SM_Halfedge_index >
: public std::unary_function<CGAL::SM_Halfedge_index, std::size_t> {
std::size_t operator()(const CGAL::SM_Halfedge_index& i) const
{
return i;
}
};
template <>
struct hash<CGAL::SM_Vertex_index >
: public std::unary_function<CGAL::SM_Vertex_index, std::size_t> {
std::size_t operator()(const CGAL::SM_Vertex_index& i) const
{
return i;
}
};
template <>
struct hash<CGAL::SM_Face_index >
: public std::unary_function<CGAL::SM_Face_index, std::size_t> {
std::size_t operator()(const CGAL::SM_Face_index& i) const
{
return i;
}
};
template <>
struct hash<CGAL::SM_Edge_index >
: public std::unary_function<CGAL::SM_Edge_index, std::size_t> {
std::size_t operator()(const CGAL::SM_Edge_index& i) const
{
return i;
}
};
}
namespace boost {
template <>
struct hash<CGAL::SM_Vertex_index > {
std::size_t operator()(const CGAL::SM_Vertex_index& i) const
{
return i;
}
};
#if defined(BOOST_MSVC)
# pragma warning(pop)
#endif
}
#endif /* CGAL_SURFACE_MESH_H */

View File

@ -229,7 +229,10 @@ typedef Tds::difference_type difference_type;
/// The vertices and faces of the triangulations are accessed through
/// handles, iterators and circulators. The handles are models
/// of the concept `Handle` which basically offers the two dereference
/// operators and `->`. The iterators and circulators are all
/// operators and `->`. The handles are also model of the concepts
/// `LessThanComparable` and `Hashable`, that is they can be used as keys
/// in containers such as `std::map` and `boost::unordered_map`.
/// The iterators and circulators are all
/// bidirectional and non-mutable. The circulators and iterators are
/// convertible to handles with the same value type, so that whenever
/// a handle appear in the parameter list of a function, an

View File

@ -126,7 +126,9 @@ non-mutable. The edges and facets of the triangulation can also be
visited through iterators and circulators which are bidirectional and
non-mutable. Iterators and circulators are convertible to the
corresponding handles, thus the user can pass them directly as
arguments to the functions.
arguments to the functions. The handles are also model of the concepts
`LessThanComparable` and `Hashable`, that is they can be used as keys
in containers such as `std::map` and `boost::unordered_map`.
*/
/// @{