diff --git a/NewKernel_d/include/CGAL/NewKernel_d/Lazy_cartesian.h b/NewKernel_d/include/CGAL/NewKernel_d/Lazy_cartesian.h index 02ff98ac303..0fa5fa99d43 100644 --- a/NewKernel_d/include/CGAL/NewKernel_d/Lazy_cartesian.h +++ b/NewKernel_d/include/CGAL/NewKernel_d/Lazy_cartesian.h @@ -62,6 +62,99 @@ namespace internal { }; } +// Whenever a construction takes iterator pairs as input, whether they point to double of Lazy objects, copy the ranges inside the lazy result so they are available for update_exact(). We analyze the input to try and guess where iterator pairs are. I would prefer if each functor had a specific signature (no overload in this layer) so we wouldn't have to guess. +// FIXME: Lazy_construct_nt is also a construction and needs the same treatment. +namespace Lazy_internal { +templatestruct typelist{}; +templatestruct arg_i{}; +templatestruct arg_i_begin{}; +templatestruct arg_i_end{}; +templatestruct arg_i_ip1_range{}; +templatestruct analyze_args; +templatestruct analyze_args> { + typedef T creator; + typedef U reader; +}; +template +struct analyze_args,typelist,typelist,std::enable_if_t::value>> : +analyze_args>,typelist>,typelist> {}; +template +struct analyze_args,typelist,typelist,std::enable_if_t::value>> : +analyze_args>,typelist,arg_i_end>,typelist> {}; +template using analyze_args_for_lazy = analyze_args,typelist<>,typelist>; +templatestruct extract1; +templatestruct extract1,T>:std::tuple_element{}; +templatestruct extract1,T>{ + typedef std::tuple_element_t E; + typedef std::remove_cv_t> It; + typedef typename std::iterator_traits::value_type element_type; + // TODO: find a way to use an array of the right size, at least for the most frequent constructions + typedef std::vector type; +}; +templatedecltype(auto) +do_extract(arg_i,std::tupleconst&t) +{return std::get(t);} +templatedecltype(auto) +do_extract(arg_i_begin,std::tupleconst&t) +{return std::begin(std::get(t));} +templatedecltype(auto) +do_extract(arg_i_end,std::tupleconst&t) +{return std::end(std::get(t));} +templatedecltype(auto) +do_extract(arg_i_ip1_range,std::tupleconst&t) +{ + typedef std::tuple L; + typedef std::tuple_element_t E; + typedef std::remove_cv_t> It; + typedef typename std::iterator_traits::value_type element_type; + typedef std::vector type; + return type(std::get(t),std::get(t)); +} +templatestruct data_from_input; +templatestruct data_from_input,U> { + typedef std::tuple::type...> type; +}; +} +template +class Lazy_rep_XXX : + public Lazy_rep< AT, ET, E2A >, private EC +{ + // Lazy_rep_0 does not inherit from EC or take a parameter AC. It has different constructors. + static_assert(sizeof...(L)>0, "Use Lazy_rep_0 instead"); + template friend class Lazy_kernel_base; + typedef Lazy_internal::analyze_args_for_lazy Args; + // How to go from l to Lazy_rep's data + typedef typename Args::creator Creator; + // How to go back + typedef typename Args::reader Reader; + // what Lazy_rep should store + typedef typename Lazy_internal::data_from_input>::type LL; + mutable LL l; // L...l; is not yet allowed. + const EC& ec() const { return *this; } + template + void update_exact_helper(Lazy_internal::typelist) const { + this->et = new ET(ec()( CGAL::exact( Lazy_internal::do_extract(T{},l) ) ... ) ); + this->at = E2A()(*(this->et)); + l = LL(); // There should be a nicer way to clear. Destruction for instance. With this->et as a witness of whether l has already been destructed. + } + public: + void update_exact() const { + update_exact_helper(Reader{}); + } + template + Lazy_rep_XXX(const AC& ac, const EC& ec, LL const&...ll) : + Lazy_rep_XXX(Creator{},ac,ec,std::forward_as_tuple(ll...),ll...){}; + private: + // Currently we construct the vectors, then move them into the tuple. It would be nicer to construct them in their final destination, because eventually we will also have arrays instead of vectors. + template + Lazy_rep_XXX(Lazy_internal::typelist, const AC& ac, const EC& ec, LLL const&lll, LL const&...ll) : + Lazy_rep(ac(CGAL::approx(ll)...)), EC(ec), l(Lazy_internal::do_extract(T{},lll)...) + { + //this->set_depth(std::max({ -1, (int)CGAL::depth(ll)...}) + 1); + this->set_depth(1); // FIXME: now that we have ranges, we could actually compute the depth if we cared... + } + // TODO: print_dag needs a specific implementation for Lazy_rep_XXX +}; template struct Lazy_construction2 { static const bool Protection = true; @@ -87,7 +180,7 @@ struct Lazy_construction2 { CGAL_BRANCH_PROFILER(std::string(" failures/calls to : ") + std::string(CGAL_PRETTY_FUNCTION), tmp); Protect_FPU_rounding P; try { - return new Lazy_rep_n(ac, ec, l...); + return new Lazy_rep_XXX(ac, ec, l...); } catch (Uncertain_conversion_exception&) { CGAL_BRANCH_PROFILER_BRANCH(tmp); Protect_FPU_rounding P2(CGAL_FE_TONEAREST); @@ -95,108 +188,12 @@ struct Lazy_construction2 { } } // FIXME: this forces us to have default constructors for all types, try to make its instantiation lazier + // Actually, that may be the clearing in update_exact(). result_type operator()() const { return new Lazy_rep_0(); } }; -#if 0 -// Experiment how we can store ranges -template -class Lazy_rep_XXX : - public Lazy_rep< AT, ET, E2A >, private EC -{ - int ld; - mutable std::vector lr; - const EC& ec() const { return *this; } - public: - void update_exact() const { - this->et = new ET(ec()(ld, CGAL::exact(std::begin(lr)), CGAL::exact(std::end(lr)))); - this->at = E2A()(*(this->et)); - lr = std::vector(); // lr.clear(); lr.shrink_to_fit(); generates worse code - } - template - Lazy_rep_XXX(const AC& ac, const EC& ec, int d, Iter const& f, Iter const& e) : - Lazy_rep(ac(d, CGAL::approx(f), CGAL::approx(e))), EC(ec), ld(d), lr(f, e) - { - this->set_depth(1); // ??? Who cares - } -}; -template -class Lazy_rep_YYY : - public Lazy_rep< AT, ET, E2A >, private EC -{ - mutable std::vector lr; - mutable L l; - const EC& ec() const { return *this; } - public: - void update_exact() const { - this->et = new ET(ec()(CGAL::exact(std::begin(lr)), CGAL::exact(std::end(lr)), CGAL::exact(l))); - this->at = E2A()(*(this->et)); - lr = std::vector(); // lr.clear(); lr.shrink_to_fit(); generates worse code - l = L(); - } - template - Lazy_rep_YYY(const AC& ac, const EC& ec, Iter const& f, Iter const& e, L const& ll) : - Lazy_rep(ac(CGAL::approx(f), CGAL::approx(e), CGAL::approx(ll))), EC(ec), lr(f, e), l(ll) - { - this->set_depth(1); // ??? Who cares - } -}; -template -struct Lazy_construction2, LK> { - static const bool Protection = true; - typedef Construct_ttag T; - typedef typename LK::Approximate_kernel AK; - typedef typename LK::Exact_kernel EK; - typedef typename LK::E2A E2A; - typedef typename Get_functor::type AC; - typedef typename Get_functor::type EC; - typedef typename map_result_tag::type result_tag; - typedef typename Get_type::type AT; - typedef typename Get_type::type ET; - typedef typename Get_type::type result_type; - // same as Handle = Lazy< AT, ET, E2A> - typedef typename Get_type::type FT; - - Lazy_construction2(){} - Lazy_construction2(LK const&k):ac(k.approximate_kernel()),ec(k.exact_kernel()){} - CGAL_NO_UNIQUE_ADDRESS AC ac; - CGAL_NO_UNIQUE_ADDRESS EC ec; - - template - std::enable_if_t<(sizeof...(L)>0&&Constructible_from_each::value), result_type> operator()(L const&...l) const { - CGAL_BRANCH_PROFILER(std::string(" failures/calls to : ") + std::string(CGAL_PRETTY_FUNCTION), tmp); - Protect_FPU_rounding P; - try { - return new Lazy_rep_n(ac, ec, l...); - } catch (Uncertain_conversion_exception&) { - CGAL_BRANCH_PROFILER_BRANCH(tmp); - Protect_FPU_rounding P2(CGAL_FE_TONEAREST); - return new Lazy_rep_0(ec(CGAL::exact(l)...)); - } - } - template - std::enable_if_t::value,result_type> operator()(int d, Iter const& f, Iter const& e) const { - typedef typename std::iterator_traits::value_type TT; - return new Lazy_rep_XXX(ac, ec, d, f, e); - } - template - std::enable_if_t::value,result_type> operator()(Iter const& f, Iter const& e, L const&l) const { - typedef typename std::iterator_traits::value_type TT; - return new Lazy_rep_YYY(ac, ec, f, e, l); - } - template - std::enable_if_t::value,result_type> operator()(Iter const& f, Iter const& e) const { - return operator()(std::distance(f, e), f, e); - } - // FIXME: this forces us to have default constructors for all types, try to make its instantiation lazier - result_type operator()() const - { - return new Lazy_rep_0(); - } -}; -#endif template struct Lazy_cartesian_types diff --git a/NewKernel_d/test/NewKernel_d/Epick_d.cpp b/NewKernel_d/test/NewKernel_d/Epick_d.cpp index 3bd63caf614..a088a6d263f 100644 --- a/NewKernel_d/test/NewKernel_d/Epick_d.cpp +++ b/NewKernel_d/test/NewKernel_d/Epick_d.cpp @@ -367,20 +367,6 @@ void test2(){ assert(abs(cent1[0]-2)<.0001); assert(abs(cent1[1]+3)<.0001); assert(abs(sp.squared_radius()-25)<.0001); -#if 1 - // Fails for an exact kernel - typedef typename K1::Point_of_sphere_d PS; - PS ps Kinit(point_of_sphere_d_object); - P psp0=ps(sp,0); - P psp1=ps(sp,1); - P psp2=ps(sp,2); - assert(!ed(psp0,psp1)); - assert(!ed(psp0,psp2)); - assert(!ed(psp2,psp1)); - assert(abs(sd(cent0,psp0)-25)<.0001); - assert(abs(sd(cent0,psp1)-25)<.0001); - assert(abs(sd(cent0,psp2)-25)<.0001); -#endif P x2py1 = tp(x2,y1); assert(x2py1[1]==-2); WP tw[]={cwp(cp(5,0),1.5),cwp(cp(2,std::sqrt(3)),1),cwp(cp(2,-std::sqrt(3)),1)}; @@ -416,6 +402,46 @@ void test2(){ D un10; CGAL_USE(un10); } +// Fails for an exact kernel, so I split it here +template +void test2i(){ + typedef Ker K1; + typedef typename K1::Point_d P; + typedef typename K1::Sphere_d Sp; + typedef typename K1::Point_of_sphere_d PS; + typedef typename K1::Construct_point_d CP; + typedef typename K1::Construct_sphere_d CSp; + typedef typename K1::Equal_d E; + typedef typename K1::Squared_distance_d SD; + typedef typename K1::Center_of_sphere_d COS; + Ker k +#if 0 + (2) +#endif + ; + CP cp Kinit(construct_point_d_object); + PS ps Kinit(point_of_sphere_d_object); + CSp csp Kinit(construct_sphere_d_object); + E ed Kinit(equal_d_object); + SD sd Kinit(squared_distance_d_object); + COS cos Kinit(center_of_sphere_d_object); + P z0=cp( 0+2,5-3); + P z1=cp(-5+2,0-3); + P z2=cp( 3+2,4-3); + P tabz[]={z0,z1,z2}; + Sp sp = csp(tabz+0,tabz+3); + P cent0=cos(sp); + P psp0=ps(sp,0); + P psp1=ps(sp,1); + P psp2=ps(sp,2); + assert(!ed(psp0,psp1)); + assert(!ed(psp0,psp2)); + assert(!ed(psp2,psp1)); + assert(abs(sd(cent0,psp0)-25)<.0001); + assert(abs(sd(cent0,psp1)-25)<.0001); + assert(abs(sd(cent0,psp2)-25)<.0001); +} + #if defined(BOOST_MSVC) # pragma warning(push) # pragma warning(disable: 4512) @@ -426,15 +452,12 @@ template struct Construct_point3_helper { Construct_point3_helper(CP const& x) : cp(x) {} template typename CP::result_type operator()(T1 const&t1, T2 const&t2, T3 const&t3)const{ - //double tab[]={(double)t1,(double)t2,(double)t3}; - // The lazy kernel stores iterators, not a vector, so the array must stay alive until update_exact()! For the tests I am keeping the memory leak for now, it is more convenient. - double*tab=new double[3]{(double)t1,(double)t2,(double)t3}; + double tab[]={(double)t1,(double)t2,(double)t3}; return cp(tab+0,tab+3); } template typename CP::result_type operator()(T1 const&t1, T2 const&t2, T3 const&t3, T4 const&t4)const{ - // Same discussion as above - double*tab=new double[3]{(double)t1,(double)t2,(double)t3}; + double tab[]={(double)t1,(double)t2,(double)t3}; return cp(tab+0,tab+3,t4); } }; @@ -693,12 +716,12 @@ CGAL_static_assertion((boost::is_same,CGAL::Ambient_dimen int main(){ //Broken with Linear_base_d (output iterator) //test2 >(); - test2(); + test2(); test2i(); test3(); test3(); - //test2>>(); - //test3>>(); - //test3>(); + test2>>(); + test3>>(); + test3>(); } #endif