1259698Sdim//===- llvm/ADT/polymorphic_ptr.h - Smart copyable owned ptr ----*- C++ -*-===//
2259698Sdim//
3259698Sdim//                     The LLVM Compiler Infrastructure
4259698Sdim//
5259698Sdim// This file is distributed under the University of Illinois Open Source
6259698Sdim// License. See LICENSE.TXT for details.
7259698Sdim//
8259698Sdim//===----------------------------------------------------------------------===//
9259698Sdim/// \file
10259698Sdim/// This file provides a polymorphic_ptr class template. See the class comments
11259698Sdim/// for details about this API, its intended use cases, etc.
12259698Sdim///
13259698Sdim/// The primary motivation here is to work around the necessity of copy
14259698Sdim/// semantics in C++98. This is typically used where any actual copies are
15259698Sdim/// incidental or unnecessary. As a consequence, it is expected to cease to be
16259698Sdim/// useful and be removed when we can directly rely on move-only types.
17259698Sdim///
18259698Sdim//===----------------------------------------------------------------------===//
19259698Sdim
20259698Sdim#ifndef LLVM_ADT_POLYMORPHIC_PTR_H
21259698Sdim#define LLVM_ADT_POLYMORPHIC_PTR_H
22259698Sdim
23259698Sdim#include "llvm/Support/Compiler.h"
24259698Sdim
25259698Sdimnamespace llvm {
26259698Sdim
27259698Sdim/// \brief An owning, copyable polymorphic smart pointer.
28259698Sdim///
29259698Sdim/// This pointer exists to provide copyable owned smart pointer. Rather than
30259698Sdim/// shared ownership semantics, it has unique ownership semantics and deep copy
31259698Sdim/// semantics. It is copyable by requiring that the underlying type exposes
32259698Sdim/// a method which can produce a (heap allocated) clone.
33259698Sdim///
34259698Sdim/// Note that in almost all scenarios use of this could be avoided if we could
35259698Sdim/// build move-only containers of a std::unique_ptr, but until then this
36259698Sdim/// provides an effective way to place polymorphic objects in a container.
37259698Sdimtemplate <typename T> class polymorphic_ptr {
38259698Sdim  T *ptr;
39259698Sdim
40259698Sdimpublic:
41259698Sdim  polymorphic_ptr(T *ptr = 0) : ptr(ptr) {}
42259698Sdim  polymorphic_ptr(const polymorphic_ptr &arg) : ptr(arg ? arg->clone() : 0) {}
43259698Sdim#if LLVM_HAS_RVALUE_REFERENCES
44259698Sdim  polymorphic_ptr(polymorphic_ptr &&arg) : ptr(arg.take()) {}
45259698Sdim#endif
46259698Sdim  ~polymorphic_ptr() { delete ptr; }
47259698Sdim
48259698Sdim  polymorphic_ptr &operator=(polymorphic_ptr arg) {
49259698Sdim    swap(arg);
50259698Sdim    return *this;
51259698Sdim  }
52259698Sdim  polymorphic_ptr &operator=(T *arg) {
53259698Sdim    if (arg != ptr) {
54259698Sdim      delete ptr;
55259698Sdim      ptr = arg;
56259698Sdim    }
57259698Sdim    return *this;
58259698Sdim  }
59259698Sdim
60259698Sdim  T &operator*() const { return *ptr; }
61259698Sdim  T *operator->() const { return ptr; }
62259698Sdim  LLVM_EXPLICIT operator bool() const { return ptr != 0; }
63259698Sdim  bool operator!() const { return ptr == 0; }
64259698Sdim
65259698Sdim  T *get() const { return ptr; }
66259698Sdim
67259698Sdim  T *take() {
68259698Sdim    T *tmp = ptr;
69259698Sdim    ptr = 0;
70259698Sdim    return tmp;
71259698Sdim  }
72259698Sdim
73259698Sdim  void swap(polymorphic_ptr &arg) {
74259698Sdim    T *tmp = ptr;
75259698Sdim    ptr = arg.ptr;
76259698Sdim    arg.ptr = tmp;
77259698Sdim  }
78259698Sdim};
79259698Sdim
80259698Sdimtemplate <typename T>
81259698Sdimvoid swap(polymorphic_ptr<T> &lhs, polymorphic_ptr<T> &rhs) {
82259698Sdim  lhs.swap(rhs);
83259698Sdim}
84259698Sdim
85259698Sdimtemplate <typename T, typename U>
86259698Sdimbool operator==(const polymorphic_ptr<T> &lhs, const polymorphic_ptr<U> &rhs) {
87259698Sdim  return lhs.get() == rhs.get();
88259698Sdim}
89259698Sdim
90259698Sdimtemplate <typename T, typename U>
91259698Sdimbool operator!=(const polymorphic_ptr<T> &lhs, const polymorphic_ptr<U> &rhs) {
92259698Sdim  return lhs.get() != rhs.get();
93259698Sdim}
94259698Sdim
95259698Sdimtemplate <typename T, typename U>
96259698Sdimbool operator==(const polymorphic_ptr<T> &lhs, U *rhs) {
97259698Sdim  return lhs.get() == rhs;
98259698Sdim}
99259698Sdim
100259698Sdimtemplate <typename T, typename U>
101259698Sdimbool operator!=(const polymorphic_ptr<T> &lhs, U *rhs) {
102259698Sdim  return lhs.get() != rhs;
103259698Sdim}
104259698Sdim
105259698Sdimtemplate <typename T, typename U>
106259698Sdimbool operator==(T *lhs, const polymorphic_ptr<U> &rhs) {
107259698Sdim  return lhs == rhs.get();
108259698Sdim}
109259698Sdim
110259698Sdimtemplate <typename T, typename U>
111259698Sdimbool operator!=(T *lhs, const polymorphic_ptr<U> &rhs) {
112259698Sdim  return lhs != rhs.get();
113259698Sdim}
114259698Sdim
115259698Sdim}
116259698Sdim
117259698Sdim#endif
118