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 ©) 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