// Copyright (c) 2014 // INRIA Saclay-Ile de France (France) // // This file is part of CGAL (www.cgal.org) // // $URL: https://github.com/CGAL/cgal/blob/v5.1/NewKernel_d/include/CGAL/NewKernel_d/Lazy_cartesian.h $ // $Id: Lazy_cartesian.h 822bc55 2020-03-27T08:28:48+01:00 Sébastien Loriot // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial // // Author(s) : Marc Glisse #ifndef CGAL_KERNEL_D_LAZY_CARTESIAN_H #define CGAL_KERNEL_D_LAZY_CARTESIAN_H #include #include #include #include #include #include #include #include namespace CGAL { template struct Nth_iterator_element : private Store_kernel { Nth_iterator_element(){} Nth_iterator_element(K const&k):Store_kernel(k){} typedef typename Get_type::value_tag>::type result_type; template result_type operator()(U&& u, int i) const { typename Get_functor >::type ci(this->kernel()); return *std::next(ci(std::forward(u),Begin_tag()),i); } }; //typedef typename Functor::nth_element>::type nth_elem; template::has_nth_element> struct Select_nth_element_functor { typedef Nth_iterator_element type; }; template struct Select_nth_element_functor : Get_functor::nth_element> {}; namespace internal { template struct Lazy_construction_maybe_nt { typedef Lazy_construction type; }; template struct Lazy_construction_maybe_nt { typedef Lazy_construction_nt type; }; } // 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. 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 { // `default_construct()` is the same as `T{}`. But, this is a // workaround to a MSVC-2015 bug (fixed in MSVC-2017): its parser // seemed confused by `T{}` somewhere below. template static T default_construct() { return T(); } // 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(default_construct(),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 }; templatestruct Select_converter { typedef typename LK::E2A type; }; templatestruct Select_converter { typedef To_interval type; }; template struct Lazy_construction2 { static const bool Protection = true; typedef typename LK::Approximate_kernel AK; typedef typename LK::Exact_kernel EK; 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 Select_converter::type, LK, ET>::type E2A; 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), 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_XXX(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)...)); } } // 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(); } }; template struct Lazy_cartesian_types { typedef typename typeset_intersection< typename AK_::Object_list, typename EK_::Object_list >::type Object_list; typedef typename typeset_intersection< typename AK_::Iterator_list, typename EK_::Iterator_list >::type Iterator_list; template ::type> struct Type {}; template struct Type { typedef Lazy< typename Get_type::type, typename Get_type::type, E2A_> type; }; template struct Type { typedef CGAL::Lazy_exact_nt::type> type; }; template struct Iterator { typedef typename iterator_tag_traits::value_tag Vt; typedef typename Type::type V; typedef typename Select_nth_element_functor::type AF; typedef typename Select_nth_element_functor::type EF; // TODO: we should use Lazy_construction2, but this seems ok for now, we never construct iterators from iterators. typedef typename internal::Lazy_construction_maybe_nt< Kernel_, AF, EF, is_NT_tag::value >::type nth_elem; typedef Iterator_from_indices< const typename Type::container>::type, const V, V, nth_elem > type; }; }; template struct Lazy_cartesian : Lazy_cartesian_types > { constexpr Lazy_cartesian(){} constexpr Lazy_cartesian(int d):ak(d),ek(d){} //TODO: Do we want to store an AK and an EK? Or just references? //FIXME: references would be better I guess. //TODO: In any case, make sure that we don't end up storing this kernel for //nothing (it is not empty but references empty kernels or something) CGAL_NO_UNIQUE_ADDRESS AK_ ak; CGAL_NO_UNIQUE_ADDRESS EK_ ek; AK_ const& approximate_kernel()const{return ak;} EK_ const& exact_kernel()const{return ek;} int dimension()const{return ak.dimension();} void set_dimension(int dim){ak.set_dimension(dim);ek.set_dimension(dim);} // For compilers that do not handle [[no_unique_address]] typedef boost::mpl::and_< internal::Do_not_store_kernel, internal::Do_not_store_kernel > Do_not_store_kernel; typedef typename EK_::Dimension Dimension; // ? typedef Lazy_cartesian Self; typedef Lazy_cartesian_types Base; //typedef typename Default::Get::type Kernel; typedef Self Kernel; typedef AK_ Approximate_kernel; typedef EK_ Exact_kernel; typedef E2A_ E2A; //typedef Approx_converter C2A; //typedef Exact_converter C2E; struct C2A { C2A(){} C2A(Kernel const&, Approximate_kernel const&){} templatedecltype(auto)operator()(T const&t)const{return CGAL::approx(t);} }; struct C2E { C2E(){} C2E(Kernel const&, Exact_kernel const&){} templatedecltype(auto)operator()(T const&t)const{return CGAL::exact(t);} }; typedef typename Exact_kernel::Rep_tag Rep_tag; typedef typename Exact_kernel::Kernel_tag Kernel_tag; typedef typename Exact_kernel::Default_ambient_dimension Default_ambient_dimension; typedef typename Exact_kernel::Max_ambient_dimension Max_ambient_dimension; //typedef typename Exact_kernel::Flat_orientation Flat_orientation; // Check that Approximate_kernel agrees with all that... template::type> struct Functor { typedef Null_functor type; }; //FIXME: what do we do with D here? template struct Functor { typedef typename Get_functor::type FA; typedef typename Get_functor::type FE; typedef Filtered_predicate2 type; }; template struct Functor { typedef Lazy_construction2 type; }; template struct Functor { typedef Lazy_construction2 type; }; template struct Functor { typedef typename Get_functor::type FA; struct type { FA fa; type(){} type(Kernel const&k):fa(k.approximate_kernel()){} template int operator()(P const&p)const{return fa(CGAL::approx(p));} }; }; template struct Functor { typedef typename Get_functor::type FA; struct type { FA fa; type(){} type(Kernel const&k):fa(k.approximate_kernel()){} template int operator()(V const&v)const{return fa(CGAL::approx(v));} }; }; template struct Functor { // Don't filter that one, as there is no guarantee that the interval // basis would be in any way related to the exact basis, the most obvious // difference being the order of the vectors. // Don't try to be generic until we have more than just this one. typedef typename Get_functor::type FE; typedef typename Get_type::type AT; typedef typename Get_type::type ET; typedef typename Base::template Type::type V; // Lazy struct type { FE fe; type(){} type(Kernel const&k):fe(k.exact_kernel()){} template void operator()(Iter i, Iter e, Oter o)const{ fe(CGAL::exact(i), CGAL::exact(e), boost::make_function_output_iterator( [&o](ET const&v){ *o++ = V(new Lazy_rep_0(v)); } ) ); } }; }; typedef typename Base::template Iterator::type Point_cartesian_const_iterator; typedef typename Base::template Iterator::type Vector_cartesian_const_iterator; // This is really specific to point/vector coordinate iterators template struct Construct_iter : private Store_kernel { Construct_iter(){} Construct_iter(Kernel const&k):Store_kernel(k){} //FIXME: pass the kernel to the functor in the iterator typedef U result_type; template result_type operator()(T const& t,Begin_tag)const{ return result_type(t,0,this->kernel()); } template result_type operator()(T const& t,End_tag)const{ typedef typename Get_functor::type PD; return result_type(t,PD(this->kernel().approximate_kernel())(CGAL::approx(t)),this->kernel()); } }; template struct Functor { typedef Construct_iter::type>::type> type; }; //TODO: what about other functors of the Misc category? // for Point_dimension, we should apply it to the approximate point // for printing, we should??? just not do printing this way? }; } //namespace CGAL #endif // CGAL_KERNEL_D_LAZY_CARTESIAN_H