From 9d10860b27d64e5002cd2d929b718d6a1241d562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 18 Dec 2024 12:01:04 +0100 Subject: [PATCH] Use a single Lazy_construction class Within the operator(), we do mostly what was done in separate functors before, but can now be done in the same function because even though the return type (deduced by decltype(auto)) is not the same for each 'if' block, the C++17 constexpr allows different return types in the different blocks. Not only we factorize code, but we do not have to use result_types anymore, and we can get the true result_type thanks to decltype() on the actual functor + parameters call. --- Filtered_kernel/include/CGAL/Lazy.h | 335 +++++++++++---------- Filtered_kernel/include/CGAL/Lazy_kernel.h | 21 +- 2 files changed, 194 insertions(+), 162 deletions(-) diff --git a/Filtered_kernel/include/CGAL/Lazy.h b/Filtered_kernel/include/CGAL/Lazy.h index 071a6f57241..8e5b22c3fa2 100644 --- a/Filtered_kernel/include/CGAL/Lazy.h +++ b/Filtered_kernel/include/CGAL/Lazy.h @@ -1333,8 +1333,6 @@ CGAL_Kernel_obj(Point_3) //____________________________________________________________ // The magic functor that has Lazy as result type. -// Two versions are distinguished: one that needs to fiddle -// with decltype and another that can forward the result types. namespace internal { BOOST_MPL_HAS_XXX_TRAIT_DEF(result_type) @@ -1436,142 +1434,24 @@ struct Fill_lazy_variant_visitor_0 : boost::static_visitor<> { } // internal -template -struct Lazy_construction_variant { - static const bool Protection = true; - - typedef typename LK::Approximate_kernel AK; - typedef typename LK::Exact_kernel EK; - typedef typename LK::E2A E2A; - - - template - struct result { - // this does not default, if you want to make a lazy lazy-kernel, - // you are on your own - }; - - template - struct result - { - typedef typename Type_mapper()(std::declval::type>()...)),AK,LK>::type type; - }; - - template - decltype(auto) - operator()(const L&... l) const - { - typedef typename result::type result_type; - - - // typedef decltype(std::declval()(std::declval::type>(), - // std::declval::type>())) AT; - // typedef decltype(std::declval()(std::declval::type>(), - // std::declval::type>())) ET; - - typedef decltype(std::declval()(CGAL::approx(l)...)) AT; - typedef decltype(std::declval()( CGAL::exact(l)...)) ET; - - CGAL_BRANCH_PROFILER(std::string(" failures/calls to : ") + std::string(CGAL_PRETTY_FUNCTION), tmp); - { - Protect_FPU_rounding P; - - try { - Lazy lazy(new Lazy_rep_n(AC(), EC(), l...)); - - // the approximate result requires the trait with types from the AK - AT approx_v = lazy.approx(); - // the result we build - result_type res; - - if(!approx_v) { - // empty - return res; - } - - // the static visitor fills the result_type with the correct unwrapped type - internal::Fill_lazy_variant_visitor_2< result_type, AK, LK, EK, Lazy > visitor(res, lazy); - boost::apply_visitor(visitor, *approx_v); - - return res; - } catch (Uncertain_conversion_exception&) {} - } - CGAL_BRANCH_PROFILER_BRANCH(tmp); - Protect_FPU_rounding P2(CGAL_FE_TONEAREST); - CGAL_expensive_assertion(FPU_get_cw() == CGAL_FE_TONEAREST); - ET exact_v = EC()(CGAL::exact(l)...); - result_type res; - - if(!exact_v) { - return res; - } - - internal::Fill_lazy_variant_visitor_0 visitor(res); - boost::apply_visitor(visitor, *exact_v); - return res; - } +template +struct Disable_lazy_pruning +{ + static const bool value = false; +}; +template +struct Disable_lazy_pruning +{ + static const bool value = true; +}; +template +struct Disable_lazy_pruning +{ + static const bool value = true; }; -template::value && internal::has_result_type::value > -struct Lazy_construction; - -template struct Disable_lazy_pruning { static const bool value = false; }; -template struct Disable_lazy_pruning { static const bool value = true; }; -template struct Disable_lazy_pruning { static const bool value = true; }; - -// we have a result type, low effort -template -struct Lazy_construction { - static const bool Protection = true; - - typedef typename LK::Approximate_kernel AK; - typedef typename LK::Exact_kernel EK; - typedef typename boost::remove_cv< - typename boost::remove_reference < typename AC::result_type >::type >::type AT; - typedef typename boost::remove_cv< - typename boost::remove_reference < typename EC::result_type >::type >::type ET; - - typedef typename Default::Get::type E2A; - - typedef typename Type_mapper::type result_type; - - static const bool noprune = Disable_lazy_pruning::value; - - CGAL_NO_UNIQUE_ADDRESS AC ac; - CGAL_NO_UNIQUE_ADDRESS EC ec; - - template - decltype(auto) - operator()(const L&... l) const { - typedef Lazy < AT, ET, E2A > Handle; - CGAL_BRANCH_PROFILER(std::string(" failures/calls to : ") + std::string(CGAL_PRETTY_FUNCTION), tmp); - { - Protect_FPU_rounding P; - try { - return result_type(Handle(new Lazy_rep_n< AT, ET, AC, EC, E2A, noprune, L...>(ac, ec, l...))); - } catch (Uncertain_conversion_exception&) {} - } - CGAL_BRANCH_PROFILER_BRANCH(tmp); - Protect_FPU_rounding P2(CGAL_FE_TONEAREST); - CGAL_expensive_assertion(FPU_get_cw() == CGAL_FE_TONEAREST); - return result_type(Handle(new Lazy_rep_0< AT, ET, E2A >(ec(CGAL::exact(l)...)))); - } - - - // nullary - decltype(auto) - operator()() const - { - typedef Lazy Handle; - return result_type( Handle() ); - } - -}; - - -template -struct Lazy_construction +template +struct Lazy_construction { static const bool Protection = true; @@ -1579,41 +1459,194 @@ struct Lazy_construction typedef typename LK::Exact_kernel EK; typedef typename Default::Get::type E2A; + CGAL_NO_UNIQUE_ADDRESS AC ac; + CGAL_NO_UNIQUE_ADDRESS EC ec; + + // to detect the return type of Intersection_[23]'s functors + template + struct is_optional_variant : std::false_type { }; + + template + struct is_optional_variant > > : std::true_type { }; + template struct result { // this does not default, if you want to make a lazy lazy-kernel, // you are on your own }; - static const bool noprune = Disable_lazy_pruning::value; - - CGAL_NO_UNIQUE_ADDRESS AC ac; - CGAL_NO_UNIQUE_ADDRESS EC ec; - template struct result { + // @todo why the Type_mapper, just for a std::decay? typedef typename Type_mapper()(std::declval::type>()...)),AK,LK>::type type; }; template decltype(auto) operator()(const L&... l) const { + // @todo why the Type_mapper, just for a std::decay? typedef typename Type_mapper()(std::declval::type>()...)),EK,EK>::type ET; typedef typename Type_mapper()(std::declval::type>()...)),AK,AK>::type AT; typedef Lazy Handle; - typedef typename result::type result_type; - CGAL_BRANCH_PROFILER(std::string(" failures/calls to : ") + std::string(CGAL_PRETTY_FUNCTION), tmp); + + // ----------------------- FT ----------------------- + if constexpr (std::is_same_v) { - Protect_FPU_rounding P; - try { - return result_type(Handle(new Lazy_rep_n (ac, ec, l...))); - } catch (Uncertain_conversion_exception&) {} + typedef Lazy_exact_nt>> result_type; + + CGAL_BRANCH_PROFILER(std::string(" failures/calls to : ") + std::string(CGAL_PRETTY_FUNCTION), tmp); + { + Protect_FPU_rounding P; + try { + return result_type(new Lazy_rep_n, false, L... >(ac, ec, l...)); + } catch (Uncertain_conversion_exception&) {} + } + CGAL_BRANCH_PROFILER_BRANCH(tmp); + Protect_FPU_rounding P2(CGAL_FE_TONEAREST); + CGAL_expensive_assertion(FPU_get_cw() == CGAL_FE_TONEAREST); + return result_type(new Lazy_rep_0 >(ec( CGAL::exact(l)... ))); + } + // ----------------------- Bounding boxes ----------------------- + else if constexpr (std::disjunction_v, + std::is_same >) + { + CGAL_BRANCH_PROFILER(std::string(" failures/calls to : ") + std::string(CGAL_PRETTY_FUNCTION), tmp); + { + // Protection is outside the try block as VC8 has the CGAL_CFG_FPU_ROUNDING_MODE_UNWINDING_VC_BUG + Protect_FPU_rounding P; + try { + return ac(CGAL::approx(l...)); + } catch (Uncertain_conversion_exception&) {} + } + CGAL_BRANCH_PROFILER_BRANCH(tmp); + Protect_FPU_rounding P2(CGAL_FE_TONEAREST); + CGAL_expensive_assertion(FPU_get_cw() == CGAL_FE_TONEAREST); + return ec(CGAL::exact(l...)); + } + // ----------------------- CGAL::Object ----------------------- + else if constexpr (std::is_same_v) + { + typedef CGAL::Object result_type; + typedef Lazy Lazy_object; + + CGAL_BRANCH_PROFILER(std::string(" failures/calls to : ") + std::string(CGAL_PRETTY_FUNCTION), tmp); + { + Protect_FPU_rounding P; + try { + Lazy_object lo(new Lazy_rep_n(ac, ec, l...)); + + if(lo.approx().is_empty()) + return Object(); + +# define CGAL_Kernel_obj(X) \ + if (object_cast(& (lo.approx()))) { \ + typedef Lazy_rep_n< typename AK::X, typename EK::X, Object_cast, Object_cast, E2A, false, Lazy_object> Lcr; \ + Lcr * lcr = new Lcr(Object_cast(), Object_cast(), lo); \ + return make_object(typename LK::X(lcr)); \ + } + +# include + + // We now check vector +# define CGAL_Kernel_obj(X) \ + { \ + const std::vector* v_ptr; \ + if ( (v_ptr = object_cast >(& (lo.approx()))) ) { \ + std::vector V; \ + V.resize(v_ptr->size()); \ + for (unsigned int i = 0; i < v_ptr->size(); i++) { \ + V[i] = typename LK::X(new Lazy_rep_n, \ + Ith_for_intersection, E2A, false, Lazy_object> \ + (Ith_for_intersection(i), Ith_for_intersection(i), lo)); \ + } \ + return make_object(V); \ + }\ + } + + CGAL_Kernel_obj(Point_2) + CGAL_Kernel_obj(Point_3) +# undef CGAL_Kernel_obj + + std::cerr << "object_cast inside Lazy_construction_rep::operator() failed. It needs more else if's (#1)" << std::endl; + std::cerr << "dynamic type of the Object : " << lo.approx().type().name() << std::endl; + + return Object(); + } catch (Uncertain_conversion_exception&) {} + } + CGAL_BRANCH_PROFILER_BRANCH(tmp); + Protect_FPU_rounding P2(CGAL_FE_TONEAREST); + CGAL_expensive_assertion(FPU_get_cw() == CGAL_FE_TONEAREST); + ET eto = ec(CGAL::exact(l)...); + return make_lazy(eto); + } + // boost::optional > (Intersection_23 result types) + else if constexpr (is_optional_variant::value) + { + typedef typename result::type result_type; + + // typedef decltype(std::declval()(std::declval::type>(), + // std::declval::type>())) AT; + // typedef decltype(std::declval()(std::declval::type>(), + // std::declval::type>())) ET; + + CGAL_BRANCH_PROFILER(std::string(" failures/calls to : ") + std::string(CGAL_PRETTY_FUNCTION), tmp); + { + Protect_FPU_rounding P; + + try { + Lazy lazy(new Lazy_rep_n(AC(), EC(), l...)); + + // the approximate result requires the trait with types from the AK + AT approx_v = lazy.approx(); + // the result we build + result_type res; + + if(!approx_v) { + // empty + return res; + } + + // the static visitor fills the result_type with the correct unwrapped type + internal::Fill_lazy_variant_visitor_2< result_type, AK, LK, EK, Lazy > visitor(res, lazy); + boost::apply_visitor(visitor, *approx_v); + + return res; + } catch (Uncertain_conversion_exception&) {} + } + CGAL_BRANCH_PROFILER_BRANCH(tmp); + Protect_FPU_rounding P2(CGAL_FE_TONEAREST); + CGAL_expensive_assertion(FPU_get_cw() == CGAL_FE_TONEAREST); + ET exact_v = EC()(CGAL::exact(l)...); + result_type res; + + if(!exact_v) { + return res; + } + + internal::Fill_lazy_variant_visitor_0 visitor(res); + boost::apply_visitor(visitor, *exact_v); + return res; + } + // ----------------------- GENERIC ----------------------- + else + { + typedef typename result::type result_type; + + static const bool noprune = Disable_lazy_pruning::value; + + CGAL_BRANCH_PROFILER(std::string(" failures/calls to : ") + std::string(CGAL_PRETTY_FUNCTION), tmp); + { + Protect_FPU_rounding P; + try { + return result_type(Handle(new Lazy_rep_n(ac, ec, l...))); + } catch (Uncertain_conversion_exception&) {} + } + CGAL_BRANCH_PROFILER_BRANCH(tmp); + Protect_FPU_rounding P2(CGAL_FE_TONEAREST); + CGAL_expensive_assertion(FPU_get_cw() == CGAL_FE_TONEAREST); + return result_type(Handle(new Lazy_rep_0 (ec(CGAL::exact(l)...)))); } - CGAL_BRANCH_PROFILER_BRANCH(tmp); - Protect_FPU_rounding P2(CGAL_FE_TONEAREST); - CGAL_expensive_assertion(FPU_get_cw() == CGAL_FE_TONEAREST); - return result_type(Handle(new Lazy_rep_0 (ec(CGAL::exact(l)...)))); } // nullary diff --git a/Filtered_kernel/include/CGAL/Lazy_kernel.h b/Filtered_kernel/include/CGAL/Lazy_kernel.h index 0cf7f4f2596..b4383a1e1c4 100644 --- a/Filtered_kernel/include/CGAL/Lazy_kernel.h +++ b/Filtered_kernel/include/CGAL/Lazy_kernel.h @@ -278,7 +278,7 @@ public: #endif #define CGAL_Kernel_cons(C, Cf) \ - typedef typename Select_wrapper::template apply::type C; \ + typedef Lazy_construction C; \ C Cf() const { return C(); } #include @@ -304,14 +304,17 @@ public: typedef CommonKernelFunctors::Assign_2 Assign_2; typedef CommonKernelFunctors::Assign_3 Assign_3; - typedef Lazy_construction_bbox Construct_bbox_2; - typedef Lazy_construction_bbox Construct_bbox_3; typedef Lazy_cartesian_const_iterator_2 Construct_cartesian_const_iterator_2; typedef Lazy_cartesian_const_iterator_3 Construct_cartesian_const_iterator_3; typedef CGAL::CartesianKernelFunctors::Compute_approximate_squared_length_3 Compute_approximate_squared_length_3; typedef CGAL::CartesianKernelFunctors::Compute_approximate_area_3 Compute_approximate_area_3; + typedef CGAL::Lazy_construction_optional_for_polyhedral_envelope< + Kernel, + typename Approximate_kernel::Intersect_point_3_for_polyhedral_envelope, + typename Exact_kernel::Intersect_point_3_for_polyhedral_envelope> Intersect_point_3_for_polyhedral_envelope; + // typedef void Compute_z_3; // to detect where .z() is called // typedef void Construct_point_3; // to detect where the ctor is called @@ -589,14 +592,6 @@ public: assign_3_object() const { return Assign_3(); } - Construct_bbox_2 - construct_bbox_2_object() const - { return Construct_bbox_2(); } - - Construct_bbox_3 - construct_bbox_3_object() const - { return Construct_bbox_3(); } - Construct_cartesian_const_iterator_2 construct_cartesian_const_iterator_2_object() const { return Construct_cartesian_const_iterator_2(); } @@ -613,6 +608,10 @@ public: compute_approximate_area_3_object() const { return Compute_approximate_area_3(); } + Intersect_point_3_for_polyhedral_envelope + intersect_point_3_for_polyhedral_envelope_object() const + { return Intersect_point_3_for_polyhedral_envelope(); } + Less_xyz_3 less_xyz_3_object() const { return Less_xyz_3(); }