CDT_3: fix for Epeck

This commit is contained in:
Laurent Rineau 2025-10-28 11:22:48 +01:00
parent edbc32959d
commit 07e0ea785d
6 changed files with 228 additions and 109 deletions

View File

@ -696,7 +696,13 @@ public:
halfedge_descriptor halfedge;
int count;
};
CGAL::unordered_flat_map<Point, Point_info> points_to_halfedge;
using Point_to_point_info_map = std::conditional_t<
CGAL::is_hashable_v<Point>,
CGAL::unordered_flat_map<Point, Point_info>,
std::map<Point, Point_info>>;
Point_to_point_info_map points_to_halfedge;
auto visited_halfedges = get(CGAL::dynamic_halfedge_property_t<bool>(), mesh);
for(const auto h : halfedges(mesh)) {

View File

@ -1,4 +1,4 @@
// Copyright (c) 2019
// Copyright (c) 2019,2025
// GeometryFactory (France)
//
// This file is part of CGAL (www.cgal.org)
@ -9,6 +9,8 @@
//
//
// Author(s) : Simon Giraudot
//
// Test file: test/Kernel_23/test_hash_functions.cpp
#ifndef CGAL_KERNEL_HASH_FUNCTIONS_H
#define CGAL_KERNEL_HASH_FUNCTIONS_H
@ -16,19 +18,72 @@
#include <boost/functional/hash.hpp>
#include <type_traits>
#include <CGAL/representation_tags.h>
#include <CGAL/Aff_transformation_2.h>
#include <CGAL/Aff_transformation_3.h>
#include <CGAL/Bbox_2.h>
#include <CGAL/Bbox_3.h>
#include <CGAL/Circle_2.h>
#include <CGAL/Iso_rectangle_2.h>
#include <CGAL/Iso_cuboid_3.h>
#include <CGAL/Point_2.h>
#include <CGAL/Point_3.h>
#include <CGAL/Segment_2.h>
#include <CGAL/Segment_3.h>
#include <CGAL/Sphere_3.h>
#include <CGAL/Vector_2.h>
#include <CGAL/Vector_3.h>
#include <CGAL/Weighted_point_2.h>
#include <CGAL/Weighted_point_3.h>
namespace CGAL
{
using boost::hash_value;
template <typename K, typename = void>
inline constexpr bool has_rep_tag_v = false;
template <typename K>
inline std::enable_if_t<std::is_same<typename K::Rep_tag, Cartesian_tag>::value, std::size_t>
inline constexpr bool has_rep_tag_v<K, std::void_t<typename K::Rep_tag>> = true;
template <typename K, typename = void>
struct Rep_tag {
using type = void;
};
template <typename K>
struct Rep_tag<K, std::enable_if_t<has_rep_tag_v<K>>> {
using type = typename K::Rep_tag;
};
template <typename K>
using Rep_tag_t = typename Rep_tag<K>::type;
template <typename K>
inline constexpr bool is_Cartesian_v = std::is_same<Rep_tag_t<K>, Cartesian_tag>::value;
template <typename K, typename = void>
struct Is_kernel_hashable : public std::false_type {};
template <typename K>
struct Is_kernel_hashable<K, std::void_t<decltype(hash_value(std::declval<typename K::FT>()))>> : public std::true_type {};
template <typename K>
inline constexpr bool is_kernel_hashable_v = Is_kernel_hashable<K>::value;
template <typename K, typename T>
using enable_if_Cartesian_and_hashable_t =
std::enable_if_t<is_Cartesian_v<K> && is_kernel_hashable_v<K>, T>;
template <typename K>
inline enable_if_Cartesian_and_hashable_t<K, std::size_t>
hash_value (const Aff_transformation_2<K>& transform)
{
std::size_t result = hash_value(transform.cartesian(0,0));
for(int i=0; i < 3; ++i)
for(int j = 0; j < 3; ++j)
if (!(i == 0 && j == 0))
for(int j = (i == 0 ? 1 : 0); j < 3; ++j)
boost::hash_combine(result, hash_value(transform.cartesian(i,j)));
return result;
}
@ -44,7 +99,7 @@ hash_value (const Bbox_2& bbox)
}
template <typename K>
inline std::enable_if_t<std::is_same<typename K::Rep_tag, Cartesian_tag>::value, std::size_t>
inline enable_if_Cartesian_and_hashable_t<K, std::size_t>
hash_value (const Circle_2<K>& circle)
{
std::size_t result = hash_value(circle.center());
@ -54,7 +109,7 @@ hash_value (const Circle_2<K>& circle)
}
template <typename K>
inline std::enable_if_t<std::is_same<typename K::Rep_tag, Cartesian_tag>::value, std::size_t>
inline enable_if_Cartesian_and_hashable_t<K, std::size_t>
hash_value (const Iso_rectangle_2<K>& iso_rectangle)
{
std::size_t result = hash_value((iso_rectangle.min)());
@ -63,7 +118,7 @@ hash_value (const Iso_rectangle_2<K>& iso_rectangle)
}
template <typename K>
inline std::enable_if_t<std::is_same<typename K::Rep_tag, Cartesian_tag>::value, std::size_t>
inline enable_if_Cartesian_and_hashable_t<K, std::size_t>
hash_value (const Point_2<K>& point)
{
std::size_t result = hash_value(point.x());
@ -72,7 +127,7 @@ hash_value (const Point_2<K>& point)
}
template <typename K>
inline std::enable_if_t<std::is_same<typename K::Rep_tag, Cartesian_tag>::value, std::size_t>
inline enable_if_Cartesian_and_hashable_t<K, std::size_t>
hash_value (const Segment_2<K>& segment)
{
std::size_t result = hash_value(segment.source());
@ -81,7 +136,7 @@ hash_value (const Segment_2<K>& segment)
}
template <typename K>
inline std::enable_if_t<std::is_same<typename K::Rep_tag, Cartesian_tag>::value, std::size_t>
inline enable_if_Cartesian_and_hashable_t<K, std::size_t>
hash_value (const Vector_2<K>& vector)
{
std::size_t result = hash_value(vector.x());
@ -90,7 +145,7 @@ hash_value (const Vector_2<K>& vector)
}
template <typename K>
inline std::enable_if_t<std::is_same<typename K::Rep_tag, Cartesian_tag>::value, std::size_t>
inline enable_if_Cartesian_and_hashable_t<K, std::size_t>
hash_value (const Weighted_point_2<K>& weighed_point)
{
std::size_t result = hash_value(weighed_point.point());
@ -99,13 +154,12 @@ hash_value (const Weighted_point_2<K>& weighed_point)
}
template <typename K>
inline std::enable_if_t<std::is_same<typename K::Rep_tag, Cartesian_tag>::value, std::size_t>
inline enable_if_Cartesian_and_hashable_t<K, std::size_t>
hash_value (const Aff_transformation_3<K>& transform)
{
std::size_t result = hash_value(transform.cartesian(0,0));
for(int i = 0; i < 3; ++i)
for(int j = 0; j < 4; ++j)
if (!(i == 0 && j == 0))
for(int j = (i == 0 ? 1 : 0); j < 4; ++j)
boost::hash_combine(result, hash_value(transform.cartesian(i,j)));
return result;
}
@ -123,7 +177,7 @@ hash_value (const Bbox_3& bbox)
}
template <typename K>
inline std::enable_if_t<std::is_same<typename K::Rep_tag, Cartesian_tag>::value, std::size_t>
inline enable_if_Cartesian_and_hashable_t<K, std::size_t>
hash_value (const Iso_cuboid_3<K>& iso_cuboid)
{
std::size_t result = hash_value((iso_cuboid.min)());
@ -132,7 +186,7 @@ hash_value (const Iso_cuboid_3<K>& iso_cuboid)
}
template <typename K>
inline std::enable_if_t<std::is_same<typename K::Rep_tag, Cartesian_tag>::value, std::size_t>
inline enable_if_Cartesian_and_hashable_t<K, std::size_t>
hash_value (const Point_3<K>& point)
{
std::size_t result = hash_value(point.x());
@ -142,7 +196,7 @@ hash_value (const Point_3<K>& point)
}
template <typename K>
inline std::enable_if_t<std::is_same<typename K::Rep_tag, Cartesian_tag>::value, std::size_t>
inline enable_if_Cartesian_and_hashable_t<K, std::size_t>
hash_value (const Segment_3<K>& segment)
{
std::size_t result = hash_value(segment.source());
@ -151,7 +205,7 @@ hash_value (const Segment_3<K>& segment)
}
template <typename K>
inline std::enable_if_t<std::is_same<typename K::Rep_tag, Cartesian_tag>::value, std::size_t>
inline enable_if_Cartesian_and_hashable_t<K, std::size_t>
hash_value (const Sphere_3<K>& sphere)
{
std::size_t result = hash_value(sphere.center());
@ -161,7 +215,7 @@ hash_value (const Sphere_3<K>& sphere)
}
template <typename K>
inline std::enable_if_t<std::is_same<typename K::Rep_tag, Cartesian_tag>::value, std::size_t>
inline enable_if_Cartesian_and_hashable_t<K, std::size_t>
hash_value (const Vector_3<K>& vector)
{
std::size_t result = hash_value(vector.x());
@ -171,7 +225,7 @@ hash_value (const Vector_3<K>& vector)
}
template <typename K>
inline std::enable_if_t<std::is_same<typename K::Rep_tag, Cartesian_tag>::value, std::size_t>
inline enable_if_Cartesian_and_hashable_t<K, std::size_t>
hash_value (const Weighted_point_3<K>& weighed_point)
{
std::size_t result = hash_value(weighed_point.point());
@ -179,93 +233,46 @@ hash_value (const Weighted_point_3<K>& weighed_point)
return result;
}
struct Forward_to_hash_value {
template <typename T>
std::size_t operator()(T&& t) const {
using boost::hash_value;
return hash_value(std::forward<T>(t));
}
};
template <typename K, typename = void>
struct Maybe_forward_to_hash_value {
Maybe_forward_to_hash_value() = delete;
Maybe_forward_to_hash_value(const Maybe_forward_to_hash_value&) = delete;
};
template <typename K>
struct Maybe_forward_to_hash_value<K, std::enable_if_t<is_kernel_hashable_v<K>>>
: public Forward_to_hash_value {};
} //namespace CGAL
// overloads of std::hash used for using std::unordered_[set/map] on CGAL Kernel objects
namespace std
{
namespace std {
template <typename K> struct hash<CGAL::Aff_transformation_2<K>> : CGAL::Maybe_forward_to_hash_value<K> {};
template <typename K> struct hash<CGAL::Circle_2<K>> : CGAL::Maybe_forward_to_hash_value<K> {};
template <typename K> struct hash<CGAL::Iso_rectangle_2<K>> : CGAL::Maybe_forward_to_hash_value<K> {};
template <typename K> struct hash<CGAL::Point_2<K>> : CGAL::Maybe_forward_to_hash_value<K> {};
template <typename K> struct hash<CGAL::Segment_2<K>> : CGAL::Maybe_forward_to_hash_value<K> {};
template <typename K> struct hash<CGAL::Vector_2<K>> : CGAL::Maybe_forward_to_hash_value<K> {};
template <typename K> struct hash<CGAL::Weighted_point_2<K>> : CGAL::Maybe_forward_to_hash_value<K> {};
template <> struct hash<CGAL::Bbox_2> : CGAL::Forward_to_hash_value {};
template <typename K> struct hash<CGAL::Aff_transformation_3<K>> : CGAL::Maybe_forward_to_hash_value<K> {};
template <typename K> struct hash<CGAL::Iso_cuboid_3<K>> : CGAL::Maybe_forward_to_hash_value<K> {};
template <typename K> struct hash<CGAL::Point_3<K>> : CGAL::Maybe_forward_to_hash_value<K> {};
template <typename K> struct hash<CGAL::Segment_3<K>> : CGAL::Maybe_forward_to_hash_value<K> {};
template <typename K> struct hash<CGAL::Sphere_3<K>> : CGAL::Maybe_forward_to_hash_value<K> {};
template <typename K> struct hash<CGAL::Vector_3<K>> : CGAL::Maybe_forward_to_hash_value<K> {};
template <typename K> struct hash<CGAL::Weighted_point_3<K>> : CGAL::Maybe_forward_to_hash_value<K> {};
template <> struct hash<CGAL::Bbox_3> : CGAL::Forward_to_hash_value {};
} // namespace std
template <typename K> struct hash<CGAL::Aff_transformation_2<K> > {
std::size_t operator() (const CGAL::Aff_transformation_2<K>& transform) const {
return CGAL::hash_value<K> (transform);
}
};
template <> struct hash<CGAL::Bbox_2> {
std::size_t operator() (const CGAL::Bbox_2& bbox) const {
return CGAL::hash_value (bbox);
}
};
template <typename K> struct hash<CGAL::Circle_2<K> > {
std::size_t operator() (const CGAL::Circle_2<K>& circle) const {
return CGAL::hash_value<K> (circle);
}
};
template <typename K> struct hash<CGAL::Iso_rectangle_2<K> > {
std::size_t operator() (const CGAL::Iso_rectangle_2<K>& iso_rectangle) const {
return CGAL::hash_value<K> (iso_rectangle);
}
};
template <typename K> struct hash<CGAL::Point_2<K> > {
std::size_t operator() (const CGAL::Point_2<K>& point) const {
return CGAL::hash_value<K> (point);
}
};
template <typename K> struct hash<CGAL::Segment_2<K> > {
std::size_t operator() (const CGAL::Segment_2<K>& segment) const {
return CGAL::hash_value<K> (segment);
}
};
template <typename K> struct hash<CGAL::Vector_2<K> > {
std::size_t operator() (const CGAL::Vector_2<K>& vector) const {
return CGAL::hash_value<K> (vector);
}
};
template <typename K> struct hash<CGAL::Weighted_point_2<K> > {
std::size_t operator() (const CGAL::Weighted_point_2<K>& weighted_point) const {
return CGAL::hash_value<K> (weighted_point);
}
};
template <typename K> struct hash<CGAL::Aff_transformation_3<K> > {
std::size_t operator() (const CGAL::Aff_transformation_3<K>& transform) const {
return CGAL::hash_value<K> (transform);
}
};
template <> struct hash<CGAL::Bbox_3> {
std::size_t operator() (const CGAL::Bbox_3& bbox) const {
return CGAL::hash_value (bbox);
}
};
template <typename K> struct hash<CGAL::Iso_cuboid_3<K> > {
std::size_t operator() (const CGAL::Iso_cuboid_3<K>& iso_cuboid) const {
return CGAL::hash_value<K> (iso_cuboid);
}
};
template <typename K> struct hash<CGAL::Point_3<K> > {
std::size_t operator() (const CGAL::Point_3<K>& point) const {
return CGAL::hash_value<K> (point);
}
};
template <typename K> struct hash<CGAL::Segment_3<K> > {
std::size_t operator() (const CGAL::Segment_3<K>& segment) const {
return CGAL::hash_value<K> (segment);
}
};
template <typename K> struct hash<CGAL::Sphere_3<K> > {
std::size_t operator() (const CGAL::Sphere_3<K>& sphere) const {
return CGAL::hash_value<K> (sphere);
}
};
template <typename K> struct hash<CGAL::Vector_3<K> > {
std::size_t operator() (const CGAL::Vector_3<K>& vector) const {
return CGAL::hash_value<K> (vector);
}
};
template <typename K> struct hash<CGAL::Weighted_point_3<K> > {
std::size_t operator() (const CGAL::Weighted_point_3<K>& weighted_point) const {
return CGAL::hash_value<K> (weighted_point);
}
};
}
#endif // CGAL_KERNEL_HASH_FUNCTIONS_H

View File

@ -1,13 +1,18 @@
// test partially generated by Github Copilot
#include <unordered_set>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Bbox_2.h>
#include <CGAL/Bbox_3.h>
typedef CGAL::Simple_cartesian<double> SC;
typedef CGAL::Exact_predicates_inexact_constructions_kernel Epick;
static_assert(CGAL::is_kernel_hashable_v<SC>);
static_assert(CGAL::is_kernel_hashable_v<Epick>);
template <typename Object>
void test (const Object& obj)
{
@ -67,5 +72,3 @@ int main()
return 0;
}

View File

@ -38,6 +38,22 @@
namespace CGAL {
namespace internal_is_hashable {
using boost::hash_value;
template <typename T, typename = void>
struct Has_hash_value : std::false_type {};
template <typename T>
struct Has_hash_value<T, std::void_t<decltype(hash_value(std::declval<T>()))>>
: std::is_convertible<decltype(hash_value(std::declval<T>())), std::size_t>
{};
}
template <typename T>
inline constexpr bool is_hashable_v =
internal_is_hashable::Has_hash_value<T>::value && std::is_default_constructible_v<std::hash<T>>;
template <
typename Key,
typename T,

View File

@ -28,6 +28,7 @@ create_single_source_cgal_program("test_dispatch_output.cpp")
create_single_source_cgal_program("test_Flattening_iterator.cpp")
create_single_source_cgal_program("test_Handle_with_policy.cpp")
create_single_source_cgal_program("test_In_place_list.cpp")
create_single_source_cgal_program("test_is_hashable.cpp")
create_single_source_cgal_program("test_is_iterator.cpp")
create_single_source_cgal_program("test_is_streamable.cpp")
create_single_source_cgal_program("test_lexcompare_outputrange.cpp")

View File

@ -0,0 +1,86 @@
// test partially generated by Github Copilot
#include <CGAL/unordered_flat_map.h>
#include <CGAL/Point_2.h>
#include <CGAL/Point_3.h>
#include <CGAL/Vector_2.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <string>
#include <utility> // std::pair
// Test types without hash support
struct No_hash {};
struct No_default_constructible_hash {};
// Provide boost::hash_value for No_default_constructible_hash
namespace boost {
std::size_t hash_value(const No_default_constructible_hash&) { return 42; }
}
// But make std::hash not default constructible
namespace std {
template <>
struct hash<No_default_constructible_hash> {
hash() = delete; // Not default constructible
std::size_t operator()(const No_default_constructible_hash&) const { return 42; }
};
}
int main() {
using CGAL::is_hashable_v;
using SC = CGAL::Simple_cartesian<double>;
using Epick = CGAL::Exact_predicates_inexact_constructions_kernel;
using Epeck = CGAL::Exact_predicates_exact_constructions_kernel;
// Built-in types should be hashable
static_assert(is_hashable_v<int>);
static_assert(is_hashable_v<double>);
static_assert(is_hashable_v<float>);
static_assert(is_hashable_v<long>);
static_assert(is_hashable_v<std::string>);
// Types without hash support should not be hashable
static_assert(!is_hashable_v<No_hash>);
// Types with hash_value but non-default-constructible std::hash should not be hashable
static_assert(!is_hashable_v<No_default_constructible_hash>);
// CGAL kernel objects should be hashable (with Cartesian kernels)
static_assert(is_hashable_v<SC::Point_2>);
static_assert(is_hashable_v<SC::Point_3>);
static_assert(is_hashable_v<SC::Vector_2>);
static_assert(is_hashable_v<SC::Vector_3>);
static_assert(is_hashable_v<SC::Segment_2>);
static_assert(is_hashable_v<SC::Segment_3>);
static_assert(is_hashable_v<SC::Aff_transformation_2>);
static_assert(is_hashable_v<SC::Aff_transformation_3>);
static_assert(is_hashable_v<SC::Circle_2>);
static_assert(is_hashable_v<SC::Sphere_3>);
static_assert(is_hashable_v<SC::Iso_rectangle_2>);
static_assert(is_hashable_v<SC::Iso_cuboid_3>);
static_assert(is_hashable_v<SC::Weighted_point_2>);
static_assert(is_hashable_v<SC::Weighted_point_3>);
// Test with Epick kernel
static_assert(is_hashable_v<Epick::Point_2>);
static_assert(is_hashable_v<Epick::Point_3>);
static_assert(is_hashable_v<Epick::Vector_2>);
static_assert(is_hashable_v<Epick::Vector_3>);
// Test with Epeck kernel
static_assert(!is_hashable_v<Epeck::Point_2>);
static_assert(!is_hashable_v<Epeck::Point_3>);
static_assert(!is_hashable_v<Epeck::Vector_2>);
static_assert(!is_hashable_v<Epeck::Vector_3>);
// Bbox types should be hashable
static_assert(is_hashable_v<CGAL::Bbox_2>);
static_assert(is_hashable_v<CGAL::Bbox_3>);
// std::pair should not be hashable (no std::hash specialization in standard)
static_assert(!is_hashable_v<std::pair<int, int>>);
return 0;
}