Add move-semantic to CGAL (non-periodic) 3D triangulations

- For `Triangulation_3`, the rule-of-zero cannot be used, because of
  the infinite vertex. A special copy-constructor and copy-assignment
  operators are required. But one can `= default the move-constructor
  and move-assignment operator, as well as the destructor.
- For `Delaunay_triangulation_3`, the rule-of-zero is
  sufficient. Nothing to do.
- For `Regular_triangulation_3`, the `hidden_point_visitor` data
  member is a function that is constructed with the `this` pointer, so
  the rule-of-zero cannot be used. Probably the move-constructor
  and move-assignment operator could be explicitly defaulted.
This commit is contained in:
Laurent Rineau 2020-01-31 11:23:37 +01:00
parent 3b564a20f8
commit b56cdcb743
6 changed files with 70 additions and 12 deletions

View File

@ -63,6 +63,13 @@ public:
: Cb(c), circumcenter_(c.circumcenter_ != nullptr ? new Point(*(c.circumcenter_)) : nullptr) : Cb(c), circumcenter_(c.circumcenter_ != nullptr ? new Point(*(c.circumcenter_)) : nullptr)
{} {}
Delaunay_triangulation_cell_base_with_circumcenter_3
(Delaunay_triangulation_cell_base_with_circumcenter_3 &&c)
: Cb(std::move(c)), circumcenter_(nullptr)
{
std::swap(circumcenter_, c.circumcenter_);
}
Delaunay_triangulation_cell_base_with_circumcenter_3& Delaunay_triangulation_cell_base_with_circumcenter_3&
operator=(const Delaunay_triangulation_cell_base_with_circumcenter_3 &c) operator=(const Delaunay_triangulation_cell_base_with_circumcenter_3 &c)
{ {
@ -71,6 +78,14 @@ public:
return *this; return *this;
} }
Delaunay_triangulation_cell_base_with_circumcenter_3&
operator=(Delaunay_triangulation_cell_base_with_circumcenter_3 &&c)
{
Delaunay_triangulation_cell_base_with_circumcenter_3 tmp=std::move(c);
std::swap(tmp, *this);
return *this;
}
Delaunay_triangulation_cell_base_with_circumcenter_3( Delaunay_triangulation_cell_base_with_circumcenter_3(
Vertex_handle v0, Vertex_handle v1, Vertex_handle v0, Vertex_handle v1,
Vertex_handle v2, Vertex_handle v3) Vertex_handle v2, Vertex_handle v3)

View File

@ -193,21 +193,42 @@ public:
CGAL_triangulation_postcondition(is_valid()); CGAL_triangulation_postcondition(is_valid());
} }
Regular_triangulation_3(Regular_triangulation_3&& rt)
noexcept(noexcept(Tr_Base(std::move(rt))))
: Tr_Base(std::move(rt)), hidden_point_visitor(this)
{
CGAL_triangulation_postcondition(is_valid());
}
~Regular_triangulation_3() = default;
void swap(Regular_triangulation_3& tr) void swap(Regular_triangulation_3& tr)
noexcept(noexcept(this->Tr_Base::swap(tr)))
{ {
// The 'vertices' and 'hidden_points' members of 'hidden_point_visitor' should be empty // The 'vertices' and 'hidden_points' members of 'hidden_point_visitor' should be empty
// as they are only filled (and cleared) during the insertion of a point. // as they are only filled (and cleared) during the insertion of a point.
// Hidden points are not stored there, but rather in cells. Thus, the only thing that must be set // Hidden points are not stored there, but rather in cells. Thus, the only thing that must be set
// is the triangulation pointer. // is the triangulation pointer.
Hidden_point_visitor<Concurrency_tag> new_hpv(this); Hidden_point_visitor<Concurrency_tag> new_hpv(this);
std::swap(hidden_point_visitor, new_hpv); using std::swap;
swap(hidden_point_visitor, new_hpv);
Tr_Base::swap(tr); Tr_Base::swap(tr);
} }
Regular_triangulation_3& operator=(Regular_triangulation_3 tr) Regular_triangulation_3& operator=(const Regular_triangulation_3& tr)
{ {
swap(tr); Regular_triangulation_3 copy(tr);
copy.swap(*this);
return *this;
}
Regular_triangulation_3& operator=(Regular_triangulation_3&& tr)
noexcept(noexcept(Regular_triangulation_3(std::move(tr))) &&
noexcept(std::declval<Regular_triangulation_3>().swap(*this)))
{
Regular_triangulation_3 copy(std::move(tr));
copy.swap(*this);
return *this; return *this;
} }

View File

@ -728,6 +728,9 @@ public:
CGAL_triangulation_expensive_postcondition(*this == tr); CGAL_triangulation_expensive_postcondition(*this == tr);
} }
Triangulation_3(Triangulation_3&& tr) = default;
~Triangulation_3() = default;
template < typename InputIterator > template < typename InputIterator >
Triangulation_3(InputIterator first, InputIterator last, Triangulation_3(InputIterator first, InputIterator last,
const GT& gt = GT(), Lock_data_structure *lock_ds = nullptr) const GT& gt = GT(), Lock_data_structure *lock_ds = nullptr)
@ -754,21 +757,21 @@ public:
init_tds(); init_tds();
} }
Triangulation_3& operator=(Triangulation_3 tr) Triangulation_3& operator=(const Triangulation_3& tr)
{ {
// Because the parameter tr is passed by value, the triangulation passed Triangulation_3 copy(tr);
// as argument has been copied. swap(copy);
// The following 'swap' consumes the *copy* and the original triangulation
// is left untouched.
swap(tr);
return *this; return *this;
} }
Triangulation_3& operator=(Triangulation_3&& tr) = default;
// HELPING FUNCTIONS // HELPING FUNCTIONS
void swap(Triangulation_3& tr) void swap(Triangulation_3& tr) noexcept
{ {
std::swap(tr._gt, _gt); using std::swap;
std::swap(tr.infinite, infinite); swap(tr._gt, _gt);
swap(tr.infinite, infinite);
_tds.swap(tr._tds); _tds.swap(tr._tds);
Base::swap(tr); Base::swap(tr);
} }

View File

@ -19,6 +19,7 @@
#include <fstream> #include <fstream>
#include <list> #include <list>
#include <vector> #include <vector>
#include <type_traits>
#include <boost/mpl/identity.hpp> #include <boost/mpl/identity.hpp>
#include <boost/mpl/if.hpp> #include <boost/mpl/if.hpp>
@ -170,6 +171,11 @@ _test_cls_delaunay_3(const Triangulation &)
{ {
typedef Triangulation Cls; typedef Triangulation Cls;
static_assert(std::is_nothrow_move_constructible<Cls>::value,
"move cstr is missing");
static_assert(std::is_nothrow_move_assignable<Cls>::value,
"move assignment is missing");
typedef typename Test_location_policy<Cls>::Location_policy Location_policy; typedef typename Test_location_policy<Cls>::Location_policy Location_policy;
// We assume the traits class has been tested already // We assume the traits class has been tested already

View File

@ -15,12 +15,19 @@
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <list> #include <list>
#include <type_traits>
#include <CGAL/use.h> #include <CGAL/use.h>
template <class Triangulation> template <class Triangulation>
void void
_test_cls_regular_3(const Triangulation &) _test_cls_regular_3(const Triangulation &)
{ {
typedef Triangulation Cls; typedef Triangulation Cls;
static_assert(std::is_nothrow_move_constructible<Cls>::value,
"move cstr is missing");
static_assert(std::is_nothrow_move_assignable<Cls>::value,
"move assignment is missing");
typedef typename Triangulation::Geom_traits Gt; typedef typename Triangulation::Geom_traits Gt;
CGAL_USE_TYPE(Gt); CGAL_USE_TYPE(Gt);

View File

@ -15,6 +15,7 @@
#include <fstream> #include <fstream>
#include <list> #include <list>
#include <vector> #include <vector>
#include <type_traits>
#include "_test_cls_iterator.h" #include "_test_cls_iterator.h"
#include "_test_cls_circulator.h" #include "_test_cls_circulator.h"
@ -79,6 +80,11 @@ _test_cls_triangulation_3(const Triangulation &)
{ {
typedef Triangulation Cls; typedef Triangulation Cls;
static_assert(std::is_nothrow_move_constructible<Cls>::value,
"move cstr is missing");
static_assert(std::is_nothrow_move_assignable<Cls>::value,
"move assignment is missing");
// We assume the traits class has been tested already // We assume the traits class has been tested already
// actually, any traits is good if it has been tested // actually, any traits is good if it has been tested