mirror of https://github.com/CGAL/cgal
309 lines
6.6 KiB
C++
309 lines
6.6 KiB
C++
// Copyright (c) 1999,2001,2003 Utrecht University (The Netherlands),
|
|
// ETH Zurich (Switzerland), Freie Universitaet Berlin (Germany),
|
|
// INRIA Sophia-Antipolis (France), Martin-Luther-University Halle-Wittenberg
|
|
// (Germany), Max-Planck-Institute Saarbruecken (Germany), RISC Linz (Austria),
|
|
// and Tel-Aviv University (Israel). All rights reserved.
|
|
//
|
|
// This file is part of CGAL (www.cgal.org); you can redistribute it and/or
|
|
// modify it under the terms of the GNU Lesser General Public License as
|
|
// published by the Free Software Foundation; version 2.1 of the License.
|
|
// See the file LICENSE.LGPL distributed with CGAL.
|
|
//
|
|
// Licensees holding a valid commercial license may use this file in
|
|
// accordance with the commercial license agreement provided with the software.
|
|
//
|
|
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
|
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// $URL$
|
|
// $Id$
|
|
//
|
|
//
|
|
// Author(s) : Stefan Schirra, Sylvain Pion
|
|
|
|
#ifndef CGAL_HANDLE_FOR_H
|
|
#define CGAL_HANDLE_FOR_H
|
|
|
|
#include <CGAL/memory.h>
|
|
#include <algorithm>
|
|
|
|
CGAL_BEGIN_NAMESPACE
|
|
|
|
template <class T, class Alloc = CGAL_ALLOCATOR(T) >
|
|
class Handle_for
|
|
{
|
|
// Wrapper that adds the reference counter.
|
|
struct RefCounted {
|
|
T t;
|
|
unsigned int count;
|
|
};
|
|
|
|
typedef typename Alloc::template rebind<RefCounted>::other Allocator;
|
|
typedef typename Allocator::pointer pointer;
|
|
|
|
static Allocator allocator;
|
|
pointer ptr_;
|
|
|
|
public:
|
|
|
|
typedef T element_type;
|
|
|
|
Handle_for()
|
|
: ptr_(allocator.allocate(1))
|
|
{
|
|
new (&(ptr_->t)) T();
|
|
ptr_->count = 1;
|
|
}
|
|
|
|
Handle_for(const T& t)
|
|
: ptr_(allocator.allocate(1))
|
|
{
|
|
new (&(ptr_->t)) T(t);
|
|
ptr_->count = 1;
|
|
}
|
|
|
|
#ifndef CGAL_CFG_NO_CPP0X_RVALUE_REFERENCE
|
|
Handle_for(T && t)
|
|
: ptr_(allocator.allocate(1))
|
|
{
|
|
new (&(ptr_->t)) T(std::move(t));
|
|
ptr_->count = 1;
|
|
}
|
|
#endif
|
|
|
|
/* I comment this one for now, since it's preventing the automatic conversions
|
|
to take place. We'll see if it's a problem later.
|
|
template < typename T1 >
|
|
Handle_for(const T1& t1)
|
|
: ptr_(allocator.allocate(1))
|
|
{
|
|
new (&(ptr_->t)) T(t1);
|
|
ptr_->count = 1;
|
|
}
|
|
*/
|
|
|
|
#if !defined CGAL_CFG_NO_CPP0X_VARIADIC_TEMPLATES && !defined CGAL_CFG_NO_CPP0X_RVALUE_REFERENCE
|
|
template < typename T1, typename T2, typename... Args >
|
|
Handle_for(T1 && t1, T2 && t2, Args && ... args)
|
|
: ptr_(allocator.allocate(1))
|
|
{
|
|
new (&(ptr_->t)) T(std::forward<T1>(t1), std::forward<T2>(t2), std::forward<Args>(args)...);
|
|
ptr_->count = 1;
|
|
}
|
|
#else
|
|
template < typename T1, typename T2 >
|
|
Handle_for(const T1& t1, const T2& t2)
|
|
: ptr_(allocator.allocate(1))
|
|
{
|
|
new (&(ptr_->t)) T(t1, t2);
|
|
ptr_->count = 1;
|
|
}
|
|
|
|
template < typename T1, typename T2, typename T3 >
|
|
Handle_for(const T1& t1, const T2& t2, const T3& t3)
|
|
: ptr_(allocator.allocate(1))
|
|
{
|
|
new (&(ptr_->t)) T(t1, t2, t3);
|
|
ptr_->count = 1;
|
|
}
|
|
|
|
template < typename T1, typename T2, typename T3, typename T4 >
|
|
Handle_for(const T1& t1, const T2& t2, const T3& t3, const T4& t4)
|
|
: ptr_(allocator.allocate(1))
|
|
{
|
|
new (&(ptr_->t)) T(t1, t2, t3, t4);
|
|
ptr_->count = 1;
|
|
}
|
|
#endif // CGAL_CFG_NO_CPP0X_VARIADIC_TEMPLATES
|
|
|
|
Handle_for(const Handle_for& h)
|
|
: ptr_(h.ptr_)
|
|
{
|
|
++(ptr_->count);
|
|
}
|
|
|
|
Handle_for&
|
|
operator=(const Handle_for& h)
|
|
{
|
|
Handle_for tmp = h;
|
|
swap(tmp);
|
|
return *this;
|
|
}
|
|
|
|
Handle_for&
|
|
operator=(const T &t)
|
|
{
|
|
if (is_shared())
|
|
*this = Handle_for(t);
|
|
else
|
|
ptr_->t = t;
|
|
|
|
return *this;
|
|
}
|
|
|
|
#ifndef CGAL_CFG_NO_CPP0X_RVALUE_REFERENCE
|
|
// Note : I don't see a way to make a useful move constructor, apart
|
|
// from e.g. using NULL as a ptr value, but this is drastic.
|
|
|
|
Handle_for&
|
|
operator=(Handle_for && h)
|
|
{
|
|
swap(h);
|
|
return *this;
|
|
}
|
|
|
|
Handle_for&
|
|
operator=(T && t)
|
|
{
|
|
if (is_shared())
|
|
*this = Handle_for(std::move(t));
|
|
else
|
|
ptr_->t = std::move(t);
|
|
|
|
return *this;
|
|
}
|
|
#endif
|
|
|
|
~Handle_for()
|
|
{
|
|
if (! is_shared() ) {
|
|
allocator.destroy( ptr_);
|
|
allocator.deallocate( ptr_, 1);
|
|
}
|
|
else
|
|
--(ptr_->count);
|
|
}
|
|
|
|
void
|
|
initialize_with(const T& t)
|
|
{
|
|
// kept for backward compatibility. Use operator=(t) instead.
|
|
*this = t;
|
|
}
|
|
|
|
bool
|
|
identical(const Handle_for& h) const
|
|
{ return ptr_ == h.ptr_; }
|
|
|
|
long int
|
|
id() const
|
|
{ return reinterpret_cast<long int>(&*ptr_); }
|
|
|
|
// Ptr() is the "public" access to the pointer to the object.
|
|
// The non-const version asserts that the instance is not shared.
|
|
const T *
|
|
Ptr() const
|
|
{
|
|
return &(ptr_->t);
|
|
}
|
|
|
|
/*
|
|
// The assertion triggers in a couple of places, so I comment it for now.
|
|
T *
|
|
Ptr()
|
|
{
|
|
CGAL_assertion(!is_shared());
|
|
return &(ptr_->t);
|
|
}
|
|
*/
|
|
|
|
bool
|
|
is_shared() const
|
|
{
|
|
return ptr_->count > 1;
|
|
}
|
|
|
|
bool
|
|
unique() const
|
|
{
|
|
return !is_shared();
|
|
}
|
|
|
|
long
|
|
use_count() const
|
|
{
|
|
return ptr_->count;
|
|
}
|
|
|
|
void
|
|
swap(Handle_for& h)
|
|
{
|
|
std::swap(ptr_, h.ptr_);
|
|
}
|
|
|
|
protected:
|
|
|
|
void
|
|
copy_on_write()
|
|
{
|
|
if ( is_shared() )
|
|
{
|
|
pointer tmp_ptr = allocator.allocate(1);
|
|
new (&(tmp_ptr->t)) T(ptr_->t);
|
|
tmp_ptr->count = 1;
|
|
--(ptr_->count);
|
|
ptr_ = tmp_ptr;
|
|
}
|
|
}
|
|
|
|
// ptr() is the protected access to the pointer. Both const and non-const.
|
|
// Redundant with Ptr().
|
|
T *
|
|
ptr()
|
|
{ return &(ptr_->t); }
|
|
|
|
const T *
|
|
ptr() const
|
|
{ return &(ptr_->t); }
|
|
};
|
|
|
|
|
|
template <class T, class Allocator>
|
|
typename Handle_for<T, Allocator>::Allocator
|
|
Handle_for<T, Allocator>::allocator;
|
|
|
|
template <class T, class Allocator>
|
|
inline
|
|
void
|
|
swap(Handle_for<T, Allocator> &h1, Handle_for<T, Allocator> &h2)
|
|
{
|
|
h1.swap(h2);
|
|
}
|
|
|
|
template <class T, class Allocator>
|
|
inline
|
|
bool
|
|
identical(const Handle_for<T, Allocator> &h1,
|
|
const Handle_for<T, Allocator> &h2)
|
|
{
|
|
return h1.identical(h2);
|
|
}
|
|
|
|
template <class T>
|
|
inline
|
|
bool
|
|
identical(const T &t1, const T &t2)
|
|
{
|
|
return &t1 == &t2;
|
|
}
|
|
|
|
template <class T, class Allocator>
|
|
inline
|
|
const T&
|
|
get(const Handle_for<T, Allocator> &h)
|
|
{
|
|
return *(h.Ptr());
|
|
}
|
|
|
|
template <class T>
|
|
inline
|
|
const T&
|
|
get(const T &t)
|
|
{
|
|
return t;
|
|
}
|
|
|
|
CGAL_END_NAMESPACE
|
|
|
|
#endif // CGAL_HANDLE_FOR_H
|