Merge remote-tracking branch 'origin/BGL-use_iterator_adaptor-GF'

Bug-fix branch for the BGL API.

Approved by the Release Manager.
Tested in CGAL-4.6-Ic-132.
This commit is contained in:
Laurent Rineau 2015-02-19 17:40:32 +01:00
commit 518368e470
4 changed files with 241 additions and 82 deletions

View File

@ -0,0 +1,31 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <iostream>
#include <fstream>
#include <boost/graph/connected_components.hpp>
#include <boost/foreach.hpp>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_3 Point;
typedef CGAL::Surface_mesh<Point> Mesh;
typedef boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
int main(int argc, char* argv[])
{
Mesh sm;
std::ifstream in((argc>1)?argv[1]:"data/prim.off");
in >> sm;
Mesh::Property_map<vertex_descriptor,int> ccmap;
ccmap = sm.add_property_map<vertex_descriptor,int>("v:CC").first;
int num = connected_components(sm, ccmap);
std::cout << num << " connected components" << std::endl;
BOOST_FOREACH(vertex_descriptor v, vertices(sm)){
std::cout << v << " is in component " << ccmap[v] << std::endl;
}
return 0;
}

View File

@ -1,5 +1,5 @@
OFF
8 7 0
11 7 0
# vertices
-1 -1 1
-1 1 1
@ -9,6 +9,10 @@ OFF
-1 1 -1
1 1 -1
1 -1 -1
2 2 2
3 2 2
3 3 3
# facets
3 3 2 1
3 3 1 0
@ -17,3 +21,4 @@ OFF
4 3 7 6 2
4 4 7 3 0
4 4 5 6 7
3 8 9 10

View File

@ -23,7 +23,7 @@
#include <stdexcept>
#include <boost/graph/graph_traits.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/iterator/iterator_adaptor.hpp>
#include <CGAL/Iterator_range.h>
#include <CGAL/assertions.h>
@ -478,11 +478,18 @@ class Halfedge_around_target_circulator;
template <typename Graph>
class Halfedge_around_source_circulator
#ifndef DOXYGEN_RUNNING
: public boost::transform_iterator<internal::OppositeHalfedge<Graph>, Halfedge_around_target_circulator<Graph> >
: public boost::iterator_adaptor<
Halfedge_around_source_circulator<Graph> // Derived
, Halfedge_around_target_circulator<Graph> // Base
, typename boost::graph_traits<Graph>::halfedge_descriptor // Value
, Bidirectional_circulator_tag // CategoryOrTraversal
, typename boost::graph_traits<Graph>::halfedge_descriptor // Reference
>
#endif
{
private:
internal::OppositeHalfedge<Graph> opp;
#ifndef DOXYGEN_RUNNING
typedef boost::transform_iterator<internal::OppositeHalfedge<Graph>, Halfedge_around_target_circulator<Graph> > Base;
typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
#endif
@ -490,7 +497,6 @@ class Halfedge_around_source_circulator
public:
#ifndef DOXYGEN_RUNNING
typedef Bidirectional_circulator_tag iterator_category;
typedef std::size_t size_type;
#endif
@ -498,12 +504,32 @@ public:
{}
Halfedge_around_source_circulator(halfedge_descriptor hd, const Graph& g)
: Base(Halfedge_around_target_circulator<Graph>(hd,g), internal::OppositeHalfedge<Graph>(g))
: Halfedge_around_source_circulator::iterator_adaptor_(Halfedge_around_target_circulator<Graph>(hd,g)), opp(g)
{}
Halfedge_around_source_circulator(vertex_descriptor vd, const Graph& g)
: Base(Halfedge_around_target_circulator<Graph>(halfedge(vd,g),g), internal::OppositeHalfedge<Graph>(g))
: Halfedge_around_source_circulator::iterator_adaptor_(Halfedge_around_target_circulator<Graph>(halfedge(vd,g),g)), opp(g)
{}
// design patter: "safe bool"
// will be replaced by explicit operator bool with C++11
typedef void (Halfedge_around_source_circulator::*bool_type)() const;
void this_type_does_not_support_comparisons() const {}
operator bool_type() const
{
return (! (this->base_reference() == NULL)) ?
&Halfedge_around_source_circulator::this_type_does_not_support_comparisons : 0;
}
bool operator== (void*) const
{
return this->base_reference() == NULL;
}
private:
friend class boost::iterator_core_access;
typename boost::graph_traits<Graph>::halfedge_descriptor dereference() const { return opp(*this->base_reference()); }
};
@ -519,11 +545,17 @@ public:
template <typename Graph>
class Face_around_target_circulator
#ifndef DOXYGEN_RUNNING
: public boost::transform_iterator<internal::Face<Graph>, Halfedge_around_target_circulator<Graph> >
: public boost::iterator_adaptor<
Face_around_target_circulator<Graph> // Derived
, Halfedge_around_target_circulator<Graph> // Base
, typename boost::graph_traits<Graph>::face_descriptor // Value
, Bidirectional_circulator_tag // CategoryOrTraversal
, typename boost::graph_traits<Graph>::face_descriptor // Reference
>
#endif
{
typedef boost::transform_iterator<internal::Face<Graph>, Halfedge_around_target_circulator<Graph> > Base;
typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
internal::Face<Graph> fct;
public:
@ -531,10 +563,9 @@ public:
{}
Face_around_target_circulator(halfedge_descriptor hd, const Graph& g)
: Base(Halfedge_around_target_circulator<Graph>(hd,g), internal::Face<Graph>(g))
: Face_around_target_circulator::iterator_adaptor_(Halfedge_around_target_circulator<Graph>(hd,g)), fct(g)
{}
#ifndef DOXYGEN_RUNNING
typedef Bidirectional_circulator_tag iterator_category;
typedef std::size_t size_type;
// design patter: "safe bool"
@ -545,14 +576,19 @@ public:
operator bool_type() const
{
return (! (this->base() == NULL)) ?
return (! (this->base_reference() == NULL)) ?
&Face_around_target_circulator::this_type_does_not_support_comparisons : 0;
}
bool operator== (void*) const
{
return this->base() == NULL;
return this->base_reference() == NULL;
}
private:
friend class boost::iterator_core_access;
typename boost::graph_traits<Graph>::face_descriptor dereference() const { return fct(*this->base_reference()); }
#endif
};
@ -712,7 +748,7 @@ public:
operator bool_type() const
{
return (! (this->base() == NULL)) ?
return (! (g == NULL)) ?
&Halfedge_around_face_circulator::this_type_does_not_support_comparisons : 0;
}
@ -820,23 +856,28 @@ halfedges_around_face(typename boost::graph_traits<Graph>::halfedge_descriptor h
template <typename Graph>
class Face_around_face_iterator
#ifndef DOXYGEN_RUNNING
: public boost::transform_iterator<internal::Face<Graph>, Halfedge_around_face_iterator<Graph> >
: public boost::iterator_adaptor<
Face_around_face_iterator<Graph> // Derived
, Halfedge_around_face_iterator<Graph> // Base
, typename boost::graph_traits<Graph>::face_descriptor // Value
, std::bidirectional_iterator_tag // CategoryOrTraversal
, typename boost::graph_traits<Graph>::face_descriptor // Reference
>
#endif
{
typedef boost::transform_iterator<internal::Face<Graph>, Halfedge_around_face_iterator<Graph> > Base;
typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
internal::Face<Graph> fct;
public:
#ifndef DOXYGEN_RUNNING
typedef std::bidirectional_iterator_tag iterator_category;
#endif
Face_around_face_iterator()
{}
Face_around_face_iterator(halfedge_descriptor h, const Graph& g, int n = 0)
: Base(Halfedge_around_face_iterator<Graph>(h,g,(h==halfedge_descriptor())?1:n), internal::Face<Graph>(g))
: Face_around_face_iterator::iterator_adaptor_(Halfedge_around_face_iterator<Graph>(h,g,(h==halfedge_descriptor())?1:n)), fct(g)
{}
private:
friend class boost::iterator_core_access;
typename boost::graph_traits<Graph>::face_descriptor dereference() const { return fct(*this->base_reference()); }
};
@ -861,23 +902,31 @@ class Face_around_face_circulator
template <typename Graph>
class Face_around_target_iterator
#ifndef DOXYGEN_RUNNING
: public boost::transform_iterator<internal::Face<Graph>, Halfedge_around_target_iterator<Graph> >
: public boost::iterator_adaptor<
Face_around_target_iterator<Graph> // Derived
, Halfedge_around_target_iterator<Graph> // Base
, typename boost::graph_traits<Graph>::face_descriptor // Value
, std::bidirectional_iterator_tag // CategoryOrTraversal
, typename boost::graph_traits<Graph>::face_descriptor // Reference
>
#endif
{
typedef boost::transform_iterator<internal::Face<Graph>, Halfedge_around_target_iterator<Graph> > Base;
typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
internal::Face<Graph> fct;
public:
#ifndef DOXYGEN_RUNNING
typedef std::bidirectional_iterator_tag iterator_category;
#endif
Face_around_target_iterator()
{}
Face_around_target_iterator(halfedge_descriptor h, const Graph& g, int n = 0)
: Base(Halfedge_around_target_iterator<Graph>(h,g,(h==halfedge_descriptor())?1:n), internal::Face<Graph>(g))
: Face_around_target_iterator::iterator_adaptor_(Halfedge_around_target_iterator<Graph>(h,g,(h==halfedge_descriptor())?1:n)), fct(g)
{}
private:
friend class boost::iterator_core_access;
typename boost::graph_traits<Graph>::face_descriptor dereference() const { return fct(*this->base_reference()); }
};
/**
@ -907,15 +956,20 @@ faces_around_face(typename boost::graph_traits<Graph>::halfedge_descriptor h, co
template <typename Graph>
class Vertex_around_face_circulator
#ifndef DOXYGEN_RUNNING
: public boost::transform_iterator<internal::Target<Graph>, Halfedge_around_face_circulator<Graph> >
: public boost::iterator_adaptor<
Vertex_around_face_circulator<Graph> // Derived
, Halfedge_around_face_circulator<Graph> // Base
, typename boost::graph_traits<Graph>::vertex_descriptor // Value
, Bidirectional_circulator_tag // CategoryOrTraversal
, typename boost::graph_traits<Graph>::vertex_descriptor // Reference
>
#endif
{
typedef boost::transform_iterator<internal::Target<Graph>, Halfedge_around_face_circulator<Graph> > Base;
internal::Target<Graph> fct;
typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
public:
#ifndef DOXYGEN_RUNNING
typedef Bidirectional_circulator_tag iterator_category;
typedef std::size_t size_type;
#endif
@ -923,7 +977,7 @@ public:
{}
Vertex_around_face_circulator(halfedge_descriptor h, const Graph& g)
: Base(Halfedge_around_face_circulator<Graph>(h,g), internal::Target<Graph>(g))
: Vertex_around_face_circulator::iterator_adaptor_(Halfedge_around_face_circulator<Graph>(h,g)), fct(g)
{}
#ifndef DOXYGEN_RUNNING
@ -935,36 +989,42 @@ public:
operator bool_type() const
{
return (! (this->base() == NULL)) ?
return (! (this->base_reference() == NULL)) ?
&Vertex_around_face_circulator::this_type_does_not_support_comparisons : 0;
}
bool operator== (void*) const
{
return this->base()== NULL;
return this->base_reference()== NULL;
}
private:
friend class boost::iterator_core_access;
typename boost::graph_traits<Graph>::vertex_descriptor dereference() const { return fct(*this->base_reference()); }
#endif
};
template <typename Graph>
class Vertex_around_face_iterator
#ifndef DOXYGEN_RUNNING
: public boost::transform_iterator<internal::Target<Graph>, Halfedge_around_face_iterator<Graph> >
: public boost::iterator_adaptor<
Vertex_around_face_iterator<Graph> // Derived
, Halfedge_around_face_iterator<Graph> // Base
, typename boost::graph_traits<Graph>::vertex_descriptor // Value
, std::bidirectional_iterator_tag // CategoryOrTraversal
, typename boost::graph_traits<Graph>::vertex_descriptor // Reference
>
#endif
{
typedef boost::transform_iterator<internal::Target<Graph>, Halfedge_around_face_iterator<Graph> > Base;
typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
internal::Target<Graph> fct;
public:
#ifndef DOXYGEN_RUNNING
typedef std::bidirectional_iterator_tag iterator_category;
#endif
Vertex_around_face_iterator()
{}
Vertex_around_face_iterator(halfedge_descriptor h, const Graph& g, int n = 0)
: Base(Halfedge_around_face_iterator<Graph>(h,g,(h==halfedge_descriptor())?1:n), internal::Target<Graph>(g))
: Vertex_around_face_iterator::iterator_adaptor_(Halfedge_around_face_iterator<Graph>(h,g,(h==halfedge_descriptor())?1:n)), fct(g)
{}
#ifndef DOXYGEN_RUNNING
@ -976,14 +1036,17 @@ public:
operator bool_type() const
{
return (! (this->base() == NULL)) ?
return (! (this->base_reference() == NULL)) ?
&Vertex_around_face_iterator::this_type_does_not_support_comparisons : 0;
}
bool operator== (void*) const
{
return this->base()== NULL;
return this->base_reference()== NULL;
}
private:
friend class boost::iterator_core_access;
typename boost::graph_traits<Graph>::vertex_descriptor dereference() const { return fct(*this->base_reference()); }
#endif
};
@ -1000,15 +1063,19 @@ public:
template <typename Graph>
class Vertex_around_target_circulator
#ifndef DOXYGEN_RUNNING
: public boost::transform_iterator<internal::Source<Graph>, Halfedge_around_target_circulator<Graph> >
: public boost::iterator_adaptor<
Vertex_around_target_circulator<Graph> // Derived
, Halfedge_around_target_circulator<Graph> // Base
, typename boost::graph_traits<Graph>::vertex_descriptor // Value
, Bidirectional_circulator_tag // CategoryOrTraversal
, typename boost::graph_traits<Graph>::vertex_descriptor // Reference
>
#endif
{
typedef boost::transform_iterator<internal::Source<Graph>, Halfedge_around_target_circulator<Graph> > Base;
internal::Source<Graph> fct;
public:
#ifndef DOXYGEN_RUNNING
typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
typedef Bidirectional_circulator_tag iterator_category;
typedef std::size_t size_type;
#endif
@ -1016,7 +1083,7 @@ public:
{}
Vertex_around_target_circulator(halfedge_descriptor h, const Graph& g)
: Base(Halfedge_around_target_circulator<Graph>(h,g), internal::Source<Graph>(g))
: Vertex_around_target_circulator::iterator_adaptor_(Halfedge_around_target_circulator<Graph>(h,g)), fct(g)
{}
#ifndef DOXYGEN_RUNNING
@ -1028,9 +1095,18 @@ public:
operator bool_type() const
{
return (! (this->base() == NULL)) ?
return (! (this->base_reference() == NULL)) ?
&Vertex_around_target_circulator::this_type_does_not_support_comparisons : 0;
}
bool operator== (void*) const
{
return this->base_reference()== NULL;
}
private:
friend class boost::iterator_core_access;
typename boost::graph_traits<Graph>::vertex_descriptor dereference() const { return fct(*this->base_reference()); }
#endif
};
@ -1040,20 +1116,25 @@ public:
template <typename Graph>
class Vertex_around_target_iterator
#ifndef DOXYGEN_RUNNING
: public boost::transform_iterator<internal::Source<Graph>, Halfedge_around_target_iterator<Graph> >
: public boost::iterator_adaptor<
Vertex_around_target_iterator<Graph> // Derived
, Halfedge_around_target_iterator<Graph> // Base
, typename boost::graph_traits<Graph>::vertex_descriptor // Value
, std::bidirectional_iterator_tag // CategoryOrTraversal
, typename boost::graph_traits<Graph>::vertex_descriptor // Reference
>
#endif
{
typedef boost::transform_iterator<internal::Source<Graph>, Halfedge_around_target_iterator<Graph> > Base;
typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
internal::Source<Graph> fct;
public:
typedef std::bidirectional_iterator_tag iterator_category;
Vertex_around_target_iterator()
{}
Vertex_around_target_iterator(halfedge_descriptor h, const Graph& g, int n = 0)
: Base(Halfedge_around_target_iterator<Graph>(h,g,(h==halfedge_descriptor())?1:n), internal::Source<Graph>(g))
: Vertex_around_target_iterator::iterator_adaptor_(Halfedge_around_target_iterator<Graph>(h,g,(h==halfedge_descriptor())?1:n)), fct(g)
{}
#ifndef DOXYGEN_RUNNING
@ -1065,9 +1146,12 @@ public:
operator bool_type() const
{
return (! (this->base() == NULL)) ?
return (! (this->base_reference() == NULL)) ?
&Vertex_around_target_iterator::this_type_does_not_support_comparisons : 0;
}
private:
friend class boost::iterator_core_access;
typename boost::graph_traits<Graph>::vertex_descriptor dereference() const { return fct(*this->base_reference()); }
#endif
};
@ -1120,23 +1204,26 @@ vertices_around_face(typename boost::graph_traits<Graph>::halfedge_descriptor h,
return make_range(I(h,g), I(h,g,1));
}
template <typename Graph>
template <class Graph>
class Out_edge_iterator
: public boost::transform_iterator<internal::OppositeEdge<Graph>, Halfedge_around_target_iterator<Graph> >
: public boost::iterator_adaptor<
Out_edge_iterator<Graph> // Derived
, Halfedge_around_target_iterator<Graph> // Base
, typename boost::graph_traits<Graph>::edge_descriptor // Value
, std::bidirectional_iterator_tag // CategoryOrTraversal
, typename boost::graph_traits<Graph>::edge_descriptor // Reference
>
{
typedef boost::transform_iterator<internal::OppositeEdge<Graph>, Halfedge_around_target_iterator<Graph> > Base;
typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
private:
internal::OppositeEdge<Graph> opp;
public:
typedef std::bidirectional_iterator_tag iterator_category;
Out_edge_iterator()
{}
Out_edge_iterator(halfedge_descriptor h, const Graph& g, int n = 0)
: Base(Halfedge_around_target_iterator<Graph>(h,g,(h==halfedge_descriptor())?1:n), internal::OppositeEdge<Graph>(g))
{}
: Out_edge_iterator::iterator_adaptor_(Halfedge_around_target_iterator<Graph>(h,g,(h==halfedge_descriptor())?1:n)), opp(g) {}
// design patter: "safe bool"
// will be replaced by explicit operator bool with C++11
@ -1146,31 +1233,40 @@ public:
operator bool_type() const
{
return (! (this->base() == NULL)) ?
return (! (this->base_reference() == NULL)) ?
&Out_edge_iterator::this_type_does_not_support_comparisons : 0;
}
private:
friend class boost::iterator_core_access;
typename boost::graph_traits<Graph>::edge_descriptor dereference() const { return opp(*this->base_reference()); }
};
template <typename Graph>
template <class Graph>
class In_edge_iterator
: public boost::transform_iterator<internal::Edge<Graph>, Halfedge_around_target_iterator<Graph> >
: public boost::iterator_adaptor<
In_edge_iterator<Graph> // Derived
, Halfedge_around_target_iterator<Graph> // Base
, typename boost::graph_traits<Graph>::edge_descriptor // Value
, std::bidirectional_iterator_tag // CategoryOrTraversal
, typename boost::graph_traits<Graph>::edge_descriptor // Reference
>
{
typedef boost::transform_iterator<internal::Edge<Graph>, Halfedge_around_target_iterator<Graph> > Base;
typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
private:
internal::Edge<Graph> fct;
public:
typedef std::bidirectional_iterator_tag iterator_category;
In_edge_iterator()
{}
In_edge_iterator(halfedge_descriptor h, const Graph& g, int n = 0)
: Base(Halfedge_around_target_iterator<Graph>(h,g,(h==halfedge_descriptor())?1:n), internal::Edge<Graph>(g))
: In_edge_iterator::iterator_adaptor_(Halfedge_around_target_iterator<Graph>(h,g,(h==halfedge_descriptor())?1:n)), fct(g)
{}
// design patter: "safe bool"
// will be replaced by explicit operator bool with C++11
typedef void (In_edge_iterator::*bool_type)() const;
@ -1179,14 +1275,20 @@ public:
operator bool_type() const
{
return (! (this->base() == NULL)) ?
return (! (this->base_reference() == NULL)) ?
&In_edge_iterator::this_type_does_not_support_comparisons : 0;
}
private:
friend class boost::iterator_core_access;
typename boost::graph_traits<Graph>::edge_descriptor dereference() const { return fct(*this->base_reference()); }
};
} // CGAL

View File

@ -5,6 +5,8 @@
#include <CGAL/boost/graph/iterator.h>
#include <boost/foreach.hpp>
#include <boost/concept/assert.hpp>
#include <CGAL/Circulator/Circulator_concepts.h>
#include <iostream>
#include <fstream>
@ -17,6 +19,7 @@ typedef GraphTraits::vertex_descriptor vertex_descriptor;
typedef GraphTraits::halfedge_descriptor halfedge_descriptor;
typedef GraphTraits::edge_descriptor edge_descriptor;
typedef GraphTraits::out_edge_iterator out_edge_iterator;
typedef GraphTraits::in_edge_iterator in_edge_iterator;
typedef CGAL::Halfedge_around_face_circulator<Polyhedron> halfedge_around_face_circulator;
typedef CGAL::Halfedge_around_target_circulator<Polyhedron> halfedge_around_target_circulator;
@ -27,9 +30,27 @@ typedef CGAL::Halfedge_around_source_circulator<Polyhedron> halfedge_around_sour
typedef CGAL::Halfedge_around_target_iterator<Polyhedron> halfedge_around_target_iterator;
typedef CGAL::Halfedge_around_face_iterator<Polyhedron> halfedge_around_face_iterator;
typedef CGAL::Face_around_face_iterator<Polyhedron> face_around_face_iterator;
typedef CGAL::Vertex_around_target_iterator<Polyhedron> vertex_around_target_iterator;
int main(int, char* argv[])
{
BOOST_CONCEPT_ASSERT((CGAL::Concepts::BidirectionalCirculator<halfedge_around_face_circulator>)) CGAL_UNUSED;
BOOST_CONCEPT_ASSERT((CGAL::Concepts::BidirectionalCirculator<halfedge_around_target_circulator>)) CGAL_UNUSED;
BOOST_CONCEPT_ASSERT((CGAL::Concepts::BidirectionalCirculator<vertex_around_target_circulator>)) CGAL_UNUSED;
BOOST_CONCEPT_ASSERT((CGAL::Concepts::BidirectionalCirculator<face_around_target_circulator>)) CGAL_UNUSED;
BOOST_CONCEPT_ASSERT((CGAL::Concepts::BidirectionalCirculator<halfedge_around_source_circulator>)) CGAL_UNUSED;
BOOST_CONCEPT_ASSERT((CGAL::Concepts::BidirectionalCirculator<halfedge_around_source_circulator>)) CGAL_UNUSED;
BOOST_CONCEPT_ASSERT((boost::BidirectionalIterator<face_around_face_iterator>));
BOOST_CONCEPT_ASSERT((boost::BidirectionalIterator<halfedge_around_face_iterator>));
BOOST_CONCEPT_ASSERT((boost::BidirectionalIterator<halfedge_around_target_iterator>));
BOOST_CONCEPT_ASSERT((boost::BidirectionalIterator<vertex_around_target_iterator>));
BOOST_CONCEPT_ASSERT((boost::BidirectionalIterator<in_edge_iterator>));
BOOST_CONCEPT_ASSERT((boost::BidirectionalIterator<out_edge_iterator>));
std::ifstream in(argv[1]);
Polyhedron P;
in >> P;