summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@gcc.gnu.org>2017-10-16 20:50:40 +0000
committerDavid Malcolm <dmalcolm@gcc.gnu.org>2017-10-16 20:50:40 +0000
commit46d2b77d71c3c9a2ea326ae9c3a89a19de3254ca (patch)
treee11b3eda93410442b9c1c59e85c5147392d1728b /include
parent2de3d3c6a62ac4299e9f5a310e4bf8ff28dbd47f (diff)
Add gnu::unique_ptr
This is a version of the patch posted by Trevor Saunders on 2017-07-31, for which he wrote: > For most of the history of this see > https://sourceware.org/ml/gdb-patches/2016-10/msg00223.html > The changes are mostly s/gdb/gtl/g This version was updated by me (dmalcolm) adding these changes: - renaming of "gtl" to "gnu" (3 letters, and one of the ones Richi proposed, and not a match for "*tl") - renaming of DEFINE_GDB_UNIQUE_PTR to DEFINE_GNU_UNIQUE_PTR - renaming of xfree_deleter to xmalloc_deleter, and making it use "free" rather than "xfree" (which doesn't exist) - added a gcc/unique-ptr-tests.cc - implement unique_xmalloc_ptr<T[]> (taken from gdb, but changing "xfree" to "free", and adding support for pre-C++-11) gcc/ChangeLog: David Malcolm <dmalcolm@redhat.com> * Makefile.in (OBJS): Add unique-ptr-tests.o. * selftest-run-tests.c (selftest::run_tests): Call selftest::unique_ptr_tests_cc_tests. * selftest.h (selftest::unique_ptr_tests_cc_tests): New decl. * unique-ptr-tests.cc: New file. include/ChangeLog: Trevor Saunders <tbsaunde+gcc@tbsaunde.org> David Malcolm <dmalcolm@redhat.com> * unique-ptr.h: New file. From-SVN: r253797
Diffstat (limited to 'include')
-rw-r--r--include/ChangeLog5
-rw-r--r--include/unique-ptr.h403
2 files changed, 408 insertions, 0 deletions
diff --git a/include/ChangeLog b/include/ChangeLog
index 0221586d778..805e81c0227 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,8 @@
+2017-10-16 Trevor Saunders <tbsaunde+gcc@tbsaunde.org>
+ David Malcolm <dmalcolm@redhat.com>
+
+ * unique-ptr.h: New file.
+
2017-09-15 Yao Qi <yao.qi@linaro.org>
Pedro Alves <palves@redhat.com>
diff --git a/include/unique-ptr.h b/include/unique-ptr.h
new file mode 100644
index 00000000000..c5ca031c284
--- /dev/null
+++ b/include/unique-ptr.h
@@ -0,0 +1,403 @@
+/* gnu::unique_ptr, a simple std::unique_ptr replacement for C++03.
+
+ Copyright (C) 2007-2016 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
+
+#include <memory>
+
+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. Instead relies on
+ the fact that gnu::unique_ptr has move semantics like
+ std::auto_ptr. I.e., copy/assignment actually moves. */
+
+template<typename T, typename D>
+unique_ptr<T, D>
+move (unique_ptr<T, D> 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 */