xref: /aosp_15_r20/external/ComputeLibrary/support/DeepCopy.h (revision c217d954acce2dbc11938adb493fc0abd69584f3)
1 /*
2  * Copyright (c) 2022 Arm Limited.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 
25 #ifndef ARM_COMPUTE_MISC_ITERABLE_H
26 #define ARM_COMPUTE_MISC_ITERABLE_H
27 namespace arm_compute
28 {
29 namespace utils
30 {
31 namespace memory
32 {
33 namespace
34 {
35 /**  Default polymorphic deep copy function, used by deep_unique_ptr
36  *
37  * @param ptr  Potentially polymorphic object to be deep copied
38  * @return template <typename Base, typename Derived>*
39  */
40 template <typename Base, typename Derived>
default_polymorphic_copy(const Base * ptr)41 Base *default_polymorphic_copy(const Base *ptr)
42 {
43     static_assert(std::is_base_of<Base, Derived>::value,
44                   "Derived is not a specialization of Base");
45     if(ptr == nullptr)
46     {
47         return nullptr;
48     }
49     return new Derived(*static_cast<const Derived *>(ptr));
50 }
51 } // namespace
52 
53 /** A deep-copying unique pointer that also supports polymorphic cloning behavior
54  *
55  * @note The == operator compares the dereferenced value instead of the pointer itself.
56  *
57  * @tparam Base Base type
58  */
59 template <typename Base>
60 class deep_unique_ptr
61 {
62 public:
63     using CopyFunc = std::function<Base *(const Base *)>;
64 
65     deep_unique_ptr(std::nullptr_t val = nullptr) noexcept
66         : _val{ val },
67     _copy{}
68     {
69     }
70     template <typename Derived, typename CopyFuncDerived>
deep_unique_ptr(Derived * value,const CopyFuncDerived & copy)71     deep_unique_ptr(Derived *value, const CopyFuncDerived &copy) noexcept
72         : _val{ value },
73     _copy{ std::move(copy) }
74     {
75         static_assert(std::is_base_of<Base, Derived>::value,
76                       "Derived is not a specialization of Base");
77         static_assert(
78             std::is_constructible<CopyFunc, CopyFuncDerived>::value,
79             "CopyFuncDerived is not valid for a copy functor");
80     }
81 
deep_unique_ptr(const deep_unique_ptr<Base> & ptr)82     deep_unique_ptr(const deep_unique_ptr<Base> &ptr)
83         : deep_unique_ptr(ptr.clone())
84     {
85     }
86     deep_unique_ptr &operator=(const deep_unique_ptr<Base> &ptr)
87     {
88         deep_unique_ptr<Base> tmp(ptr);
89         swap(*this, tmp);
90         return *this;
91     }
92 
93     deep_unique_ptr(deep_unique_ptr<Base> &&ptr) = default;
94     deep_unique_ptr &operator=(deep_unique_ptr<Base> &&ptr) = default;
95     ~deep_unique_ptr()                                      = default;
swap(deep_unique_ptr & ptr0,deep_unique_ptr<Base> & ptr1)96     friend void swap(deep_unique_ptr &ptr0, deep_unique_ptr<Base> &ptr1) noexcept
97     {
98         using std::swap;
99         swap(ptr0._val, ptr1._val);
100         swap(ptr0._copy, ptr1._copy);
101     }
102     Base &operator*() noexcept
103     {
104         return *_val;
105     }
106 
107     const Base &operator*() const noexcept
108     {
109         return *_val;
110     }
111 
112     Base *operator->() noexcept
113     {
114         return _val.operator->();
115     }
116 
117     const Base *operator->() const noexcept
118     {
119         return _val.operator->();
120     }
121 
get()122     Base *get() noexcept
123     {
124         return _val.get();
125     }
get()126     const Base *get() const noexcept
127     {
128         return _val.get();
129     }
130 
131     explicit operator bool() const noexcept
132     {
133         return static_cast<bool>(_val);
134     }
135 
136     bool operator==(const deep_unique_ptr<Base> &rhs) const
137     {
138         if(rhs.get() == nullptr && _val == nullptr)
139         {
140             return true;
141         }
142         else if(rhs.get() == nullptr || _val == nullptr)
143         {
144             return false;
145         }
146         else
147         {
148             return (*_val == *rhs);
149         }
150     }
151 
152 private:
clone()153     deep_unique_ptr clone() const
154     {
155         return { _copy(_val.get()), CopyFunc(_copy) };
156     }
157     std::unique_ptr<Base> _val{ nullptr };
158     CopyFunc              _copy{};
159 };
160 
161 /** Utility function to create a polymorphic deep-copying unique pointer
162  *
163  * @tparam Base
164  * @tparam Derived
165  * @tparam CopyFunc
166  * @param temp
167  * @param copy
168  * @return deep_unique_ptr<Base>
169  */
170 template <typename Base, typename Derived, typename CopyFunc>
make_deep_unique(Derived && temp,CopyFunc copy)171 deep_unique_ptr<Base> make_deep_unique(Derived &&temp, CopyFunc copy)
172 {
173     return
174     {
175         new Derived(std::move(temp)),
176         CopyFunc{ std::move(copy) }
177     };
178 }
179 
180 template <typename Base, typename Derived>
make_deep_unique(Derived && temp)181 deep_unique_ptr<Base> make_deep_unique(Derived &&temp)
182 {
183     static_assert(std::is_base_of<Base, Derived>::value,
184                   "Derived is not a specialization of Base");
185 
186     return make_deep_unique<Base, Derived>(
187                std::move(temp), default_polymorphic_copy<Base, Derived>);
188 }
189 
190 template <typename Base, typename Derived, typename... Args>
make_deep_unique(Args &&...args)191 deep_unique_ptr<Base> make_deep_unique(Args &&... args)
192 {
193     static_assert(std::is_constructible<Derived, Args...>::value,
194                   "Cannot instantiate Derived from arguments");
195 
196     return make_deep_unique<Base, Derived>(
197                std::move(Derived{ std::forward<Args>(args)... }));
198 }
199 
200 } // namespace memory
201 } // namespace utils
202 } // namespace arm_compute
203 #endif // ARM_COMPUTE_MISC_ITERABLE_H