view include/unique-ptr.h @ 158:494b0b89df80 default tip

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 18:13:55 +0900
parents 1830386684a0
children
line wrap: on
line source

/* gnu::unique_ptr, a simple std::unique_ptr replacement for C++03.

   Copyright (C) 2007-2020 Free Software Foundation, Inc.

   This file is part of GCC.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

/* gnu::unique_ptr defines a C++ owning smart pointer that exposes a
   subset of the std::unique_ptr API.

   In fact, when compiled with a C++11 compiler, gnu::unique_ptr
   actually _is_ std::unique_ptr.  When compiled with a C++03 compiler
   OTOH, it's an hand coded std::unique_ptr emulation that assumes
   code is correct and doesn't try to be too smart.

   This supports custom deleters, but not _stateful_ deleters, so you
   can't use those in C++11 mode either.  Only the managed pointer is
   stored in the smart pointer.  That could be changed; it simply
   wasn't found necessary.

   At the end of the file you'll find a gnu::unique_ptr partial
   specialization that uses a custom (stateless) deleter:
   gnu::unique_xmalloc_ptr.  That is used to manage pointers to
   objects allocated with xmalloc.

   The C++03 version was originally based on GCC 7.0's std::auto_ptr
   and then heavily customized to behave more like C++11's
   std::unique_ptr, but at this point, it no longer shares much at all
   with the original file.  But, that's the history and the reason for
   the copyright's starting year.

   The C++03 version lets you shoot yourself in the foot, since
   similarly to std::auto_ptr, the copy constructor and assignment
   operators actually move.  Also, in the name of simplicity, no
   effort is spent on using SFINAE to prevent invalid conversions,
   etc.  This is not really a problem, because the goal here is to
   allow code that would be correct using std::unique_ptr to be
   equally correct in C++03 mode, and, just as efficient.  If client
   code compiles correctly with a C++11 (or newer) compiler, we know
   we're not doing anything invalid by mistake.

   Usage notes:

   - Putting gnu::unique_ptr in standard containers is not supported,
     since C++03 containers are not move-aware (and our emulation
     relies on copy actually moving).

   - Since there's no nullptr in C++03, gnu::unique_ptr allows
     implicit initialization and assignment from NULL instead.

   - To check whether there's an associated managed object, all these
     work as expected:

      if (ptr)
      if (!ptr)
      if (ptr != NULL)
      if (ptr == NULL)
      if (NULL != ptr)
      if (NULL == ptr)
*/

#ifndef GNU_UNIQUE_PTR_H
#define GNU_UNIQUE_PTR_H 1

#if __cplusplus >= 201103
# include <memory>
#endif

namespace gnu
{

#if __cplusplus >= 201103

/* In C++11 mode, all we need is import the standard
   std::unique_ptr.  */
template<typename T> using unique_ptr = std::unique_ptr<T>;

/* Pull in move as well.  */
using std::move;

#else /* C++11 */

/* Default destruction policy used by gnu::unique_ptr when no deleter
   is specified.  Uses delete.  */

template<typename T>
struct default_delete
{
  void operator () (T *ptr) const { delete ptr; }
};

/* Specialization for arrays.  Uses delete[].  */

template<typename T>
struct default_delete<T[]>
{
  void operator () (T *ptr) const { delete [] ptr; }
};

namespace detail
{
/* Type used to support implicit construction from NULL:

     gnu::unique_ptr<foo> func (....)
     {
     return NULL;
     }

   and assignment from NULL:

     gnu::unique_ptr<foo> ptr (....);
     ...
     ptr = NULL;

  It is intentionally not defined anywhere.  */
struct nullptr_t;

/* Base class of our unique_ptr emulation.  Contains code common to
   both unique_ptr<T, D> and unique_ptr<T[], D>.  */

template<typename T, typename D>
class unique_ptr_base
{
public:
  typedef T *pointer;
  typedef T element_type;
  typedef D deleter_type;

  /* Takes ownership of a pointer.  P is a pointer to an object of
     element_type type.  Defaults to NULL.  */
  explicit unique_ptr_base (element_type *p = NULL) throw () : m_ptr (p) {}

  /* The "move" constructor.  Really a copy constructor that actually
     moves.  Even though std::unique_ptr is not copyable, our little
     simpler emulation allows it, because:

       - There are no rvalue references in C++03.  Our move emulation
       instead relies on copy/assignment moving, like std::auto_ptr.
       - RVO/NRVO requires an accessible copy constructor
  */
  unique_ptr_base (const unique_ptr_base &other) throw ()
    : m_ptr (const_cast<unique_ptr_base &> (other).release ()) {}

  /* Converting "move" constructor.  Really an lvalue ref converting
     constructor that actually moves.  This allows constructs such as:

      unique_ptr<Derived> func_returning_unique_ptr (.....);
      ...
      unique_ptr<Base> ptr = func_returning_unique_ptr (.....);
  */
  template<typename T1, typename D1>
  unique_ptr_base (const unique_ptr_base<T1, D1> &other) throw ()
    : m_ptr (const_cast<unique_ptr_base<T1, D1> &> (other).release ()) {}

  /* The "move" assignment operator.  Really an lvalue ref copy
     assignment operator that actually moves.  See comments above.  */
  unique_ptr_base &operator= (const unique_ptr_base &other) throw ()
  {
    reset (const_cast<unique_ptr_base &> (other).release ());
    return *this;
  }

  /* Converting "move" assignment.  Really an lvalue ref converting
     copy assignment operator that moves.  See comments above.  */
  template<typename T1, typename D1>
  unique_ptr_base &operator= (const unique_ptr_base<T1, D1> &other) throw ()
  {
    reset (const_cast<unique_ptr_base<T1, D1> &> (other).release ());
    return *this;
  }

  /* std::unique_ptr does not allow assignment, except from nullptr.
     nullptr doesn't exist in C++03, so we allow assignment from NULL
     instead [ptr = NULL;].
  */
  unique_ptr_base &operator= (detail::nullptr_t *) throw ()
  {
    reset ();
    return *this;
  }

  ~unique_ptr_base () { call_deleter (); }

  /* "explicit operator bool ()" emulation using the safe bool
     idiom.  */
private:
  typedef void (unique_ptr_base::*explicit_operator_bool) () const;
  void this_type_does_not_support_comparisons () const {}

public:
  operator explicit_operator_bool () const
  {
    return (m_ptr != NULL
	    ? &unique_ptr_base::this_type_does_not_support_comparisons
	    : 0);
  }

  element_type *get () const throw () { return m_ptr; }

  element_type *release () throw ()
  {
    pointer tmp = m_ptr;
    m_ptr = NULL;
    return tmp;
  }

  void reset (element_type *p = NULL) throw ()
  {
    if (p != m_ptr)
      {
	call_deleter ();
	m_ptr = p;
      }
  }

private:

  /* Call the deleter.  Note we assume the deleter is "stateless".  */
  void call_deleter ()
  {
    D d;

    d (m_ptr);
  }

  element_type *m_ptr;
};

} /* namespace detail */

/* Macro used to create a unique_ptr_base "partial specialization" --
   a subclass that uses a specific deleter.  Basically this re-defines
   the necessary constructors.  This is necessary because C++03
   doesn't support inheriting constructors with "using".  While at it,
   we inherit the assignment operator.  TYPE is the name of the type
   being defined.  Assumes that 'base_type' is a typedef of the
   baseclass TYPE is inheriting from.  */
#define DEFINE_GNU_UNIQUE_PTR(TYPE)						\
public:									\
  explicit TYPE (T *p = NULL) throw ()					\
    : base_type (p) {}							\
									\
  TYPE (const TYPE &other) throw () : base_type (other) {}		\
									\
  TYPE (detail::nullptr_t *) throw () : base_type (NULL) {}		\
									\
  template<typename T1, typename D1>					\
  TYPE (const detail::unique_ptr_base<T1, D1> &other) throw ()		\
    : base_type (other) {}						\
									\
  using base_type::operator=;

/* Define single-object gnu::unique_ptr.  */

template <typename T, typename D = default_delete<T> >
class unique_ptr : public detail::unique_ptr_base<T, D>
{
  typedef detail::unique_ptr_base<T, D> base_type;

  DEFINE_GNU_UNIQUE_PTR (unique_ptr)

public:
  /* Dereferencing.  */
  T &operator* () const throw () { return *this->get (); }
  T *operator-> () const throw () { return this->get (); }
};

/* Define gnu::unique_ptr specialization for T[].  */

template <typename T, typename D>
class unique_ptr<T[], D> : public detail::unique_ptr_base<T, D>
{
  typedef detail::unique_ptr_base<T, D> base_type;

  DEFINE_GNU_UNIQUE_PTR (unique_ptr)

public:
  /* Indexing operator.  */
  T &operator[] (size_t i) const { return this->get ()[i]; }
};

/* Comparison operators.  */

template <typename T, typename D,
	  typename U, typename E>
inline bool
operator== (const detail::unique_ptr_base<T, D> &x,
	    const detail::unique_ptr_base<U, E> &y)
{ return x.get() == y.get(); }

template <typename T, typename D,
	  typename U, typename E>
inline bool
operator!= (const detail::unique_ptr_base<T, D> &x,
	    const detail::unique_ptr_base<U, E> &y)
{ return x.get() != y.get(); }

template<typename T, typename D,
	 typename U, typename E>
inline bool
operator< (const detail::unique_ptr_base<T, D> &x,
	   const detail::unique_ptr_base<U, E> &y)
{ return x.get() < y.get (); }

template<typename T, typename D,
	 typename U, typename E>
inline bool
operator<= (const detail::unique_ptr_base<T, D> &x,
	    const detail::unique_ptr_base<U, E> &y)
{ return !(y < x); }

template<typename T, typename D,
	 typename U, typename E>
inline bool
operator> (const detail::unique_ptr_base<T, D> &x,
	   const detail::unique_ptr_base<U, E> &y)
{ return y < x; }

template<typename T, typename D,
	 typename U, typename E>
inline bool
operator>= (const detail::unique_ptr_base<T, D> &x,
	    const detail::unique_ptr_base<U, E> &y)
{ return !(x < y); }

/* std::move "emulation".  This is as simple as it can be -- no
   attempt is made to emulate rvalue references.  This relies on T
   having move semantics like std::auto_ptr.
   I.e., copy/assignment actually moves.  */

template<typename T>
const T&
move (T& v)
{
  return v;
}

#endif /* C++11 */

/* Define gnu::unique_xmalloc_ptr, a gnu::unique_ptr that manages
   xmalloc'ed memory.  */

/* The deleter for gnu::unique_xmalloc_ptr.  Uses free.  */
template <typename T>
struct xmalloc_deleter
{
  void operator() (T *ptr) const { free (ptr); }
};

/* Same, for arrays.  */
template <typename T>
struct xmalloc_deleter<T[]>
{
  void operator() (T *ptr) const { free (ptr); }
};

#if __cplusplus >= 201103

/* In C++11, we just import the standard unique_ptr to our namespace
   with a custom deleter.  */

template<typename T> using unique_xmalloc_ptr
  = std::unique_ptr<T, xmalloc_deleter<T>>;

#else /* C++11 */

/* In C++03, we don't have template aliases, so we need to define a
   subclass instead, and re-define the constructors, because C++03
   doesn't support inheriting constructors either.  */

template <typename T>
class unique_xmalloc_ptr : public unique_ptr<T, xmalloc_deleter<T> >
{
  typedef unique_ptr<T, xmalloc_deleter<T> > base_type;

  DEFINE_GNU_UNIQUE_PTR (unique_xmalloc_ptr)
};

/* Define gnu::unique_xmalloc_ptr specialization for T[].  */

template <typename T>
class unique_xmalloc_ptr<T[]> : public unique_ptr<T[], xmalloc_deleter<T[]> >
{
  typedef unique_ptr<T[], xmalloc_deleter<T[]> > base_type;

  DEFINE_GNU_UNIQUE_PTR (unique_xmalloc_ptr)
};

#endif /* C++11 */

} /* namespace gnu */

#endif /* GNU_UNIQUE_PTR_H */