• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef INCLUDE_PERFETTO_PROTOZERO_COPYABLE_PTR_H_
18 #define INCLUDE_PERFETTO_PROTOZERO_COPYABLE_PTR_H_
19 
20 #include <memory>
21 #include <utility>
22 
23 namespace protozero {
24 
25 // This class is essentially a std::vector<T> of fixed size = 1.
26 // It's a pointer wrapper with deep copying and deep equality comparison.
27 // At all effects this wrapper behaves like the underlying T, with the exception
28 // of the heap indirection.
29 // Conversely to a std::unique_ptr, the pointer will be always valid, never
30 // null. The problem it solves is the following: when generating C++ classes
31 // from proto files, we want to keep each header hermetic (i.e. not #include
32 // headers of dependent types). As such we can't directly instantiate T
33 // field members but we can instead rely on pointers, so only the .cc file needs
34 // to see the actual definition of T. If the generated classes were move-only we
35 // could just use a unique_ptr there. But they aren't, hence this wrapper.
36 // Converesely to unique_ptr, this wrapper:
37 // - Default constructs the T instance in its constructor.
38 // - Implements deep comparison in operator== instead of pointer comparison.
39 template <typename T>
40 class CopyablePtr {
41  public:
CopyablePtr()42   CopyablePtr() : ptr_(new T()) {}
43   ~CopyablePtr() = default;
44 
45   // Copy operators.
CopyablePtr(const CopyablePtr & other)46   CopyablePtr(const CopyablePtr& other) : ptr_(new T(*other.ptr_)) {}
47   CopyablePtr& operator=(const CopyablePtr& other) {
48     *ptr_ = *other.ptr_;
49     return *this;
50   }
51 
52   // Move operators.
CopyablePtr(CopyablePtr && other)53   CopyablePtr(CopyablePtr&& other) noexcept : ptr_(std::move(other.ptr_)) {
54     other.ptr_.reset(new T());
55   }
56 
57   CopyablePtr& operator=(CopyablePtr&& other) {
58     ptr_ = std::move(other.ptr_);
59     other.ptr_.reset(new T());
60     return *this;
61   }
62 
get()63   T* get() { return ptr_.get(); }
get()64   const T* get() const { return ptr_.get(); }
65 
66   T* operator->() { return ptr_.get(); }
67   const T* operator->() const { return ptr_.get(); }
68 
69   T& operator*() { return *ptr_; }
70   const T& operator*() const { return *ptr_; }
71 
72   friend bool operator==(const CopyablePtr& lhs, const CopyablePtr& rhs) {
73     return *lhs == *rhs;
74   }
75 
76   friend bool operator!=(const CopyablePtr& lhs, const CopyablePtr& rhs) {
77     // In theory the underlying type might have a special operator!=
78     // implementation which is not just !(x == y). Respect that.
79     return *lhs != *rhs;
80   }
81 
82  private:
83   std::unique_ptr<T> ptr_;
84 };
85 
86 }  // namespace protozero
87 
88 #endif  // INCLUDE_PERFETTO_PROTOZERO_COPYABLE_PTR_H_
89