blob: c0279284c0aa984bc9c508fb58d95f8ceca6cdfa [file] [log] [blame]
SiCong Lib63b1192022-01-28 18:24:39 +00001/*
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
27namespace arm_compute
28{
29namespace utils
30{
31namespace memory
32{
33namespace
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 */
40template <typename Base, typename Derived>
41Base *default_polymorphic_copy(const Base *ptr)
42{
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010043 static_assert(std::is_base_of<Base, Derived>::value, "Derived is not a specialization of Base");
44 if (ptr == nullptr)
SiCong Lib63b1192022-01-28 18:24:39 +000045 {
46 return nullptr;
47 }
48 return new Derived(*static_cast<const Derived *>(ptr));
49}
50} // namespace
51
52/** A deep-copying unique pointer that also supports polymorphic cloning behavior
53 *
54 * @note The == operator compares the dereferenced value instead of the pointer itself.
55 *
56 * @tparam Base Base type
57 */
58template <typename Base>
59class deep_unique_ptr
60{
61public:
62 using CopyFunc = std::function<Base *(const Base *)>;
63
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010064 deep_unique_ptr(std::nullptr_t val = nullptr) noexcept : _val{val}, _copy{}
SiCong Lib63b1192022-01-28 18:24:39 +000065 {
66 }
67 template <typename Derived, typename CopyFuncDerived>
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010068 deep_unique_ptr(Derived *value, const CopyFuncDerived &copy) noexcept : _val{value}, _copy{std::move(copy)}
SiCong Lib63b1192022-01-28 18:24:39 +000069 {
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010070 static_assert(std::is_base_of<Base, Derived>::value, "Derived is not a specialization of Base");
71 static_assert(std::is_constructible<CopyFunc, CopyFuncDerived>::value,
72 "CopyFuncDerived is not valid for a copy functor");
SiCong Lib63b1192022-01-28 18:24:39 +000073 }
74
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010075 deep_unique_ptr(const deep_unique_ptr<Base> &ptr) : deep_unique_ptr(ptr.clone())
SiCong Lib63b1192022-01-28 18:24:39 +000076 {
77 }
78 deep_unique_ptr &operator=(const deep_unique_ptr<Base> &ptr)
79 {
80 deep_unique_ptr<Base> tmp(ptr);
81 swap(*this, tmp);
82 return *this;
83 }
84
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010085 deep_unique_ptr(deep_unique_ptr<Base> &&ptr) = default;
SiCong Lib63b1192022-01-28 18:24:39 +000086 deep_unique_ptr &operator=(deep_unique_ptr<Base> &&ptr) = default;
87 ~deep_unique_ptr() = default;
88 friend void swap(deep_unique_ptr &ptr0, deep_unique_ptr<Base> &ptr1) noexcept
89 {
90 using std::swap;
91 swap(ptr0._val, ptr1._val);
92 swap(ptr0._copy, ptr1._copy);
93 }
94 Base &operator*() noexcept
95 {
96 return *_val;
97 }
98
99 const Base &operator*() const noexcept
100 {
101 return *_val;
102 }
103
104 Base *operator->() noexcept
105 {
106 return _val.operator->();
107 }
108
109 const Base *operator->() const noexcept
110 {
111 return _val.operator->();
112 }
113
114 Base *get() noexcept
115 {
116 return _val.get();
117 }
118 const Base *get() const noexcept
119 {
120 return _val.get();
121 }
122
123 explicit operator bool() const noexcept
124 {
125 return static_cast<bool>(_val);
126 }
127
128 bool operator==(const deep_unique_ptr<Base> &rhs) const
129 {
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100130 if (rhs.get() == nullptr && _val == nullptr)
SiCong Lib63b1192022-01-28 18:24:39 +0000131 {
132 return true;
133 }
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100134 else if (rhs.get() == nullptr || _val == nullptr)
SiCong Lib63b1192022-01-28 18:24:39 +0000135 {
136 return false;
137 }
138 else
139 {
140 return (*_val == *rhs);
141 }
142 }
143
144private:
145 deep_unique_ptr clone() const
146 {
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100147 return {_copy(_val.get()), CopyFunc(_copy)};
SiCong Lib63b1192022-01-28 18:24:39 +0000148 }
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100149 std::unique_ptr<Base> _val{nullptr};
SiCong Lib63b1192022-01-28 18:24:39 +0000150 CopyFunc _copy{};
151};
152
153/** Utility function to create a polymorphic deep-copying unique pointer
154 *
155 * @tparam Base
156 * @tparam Derived
157 * @tparam CopyFunc
158 * @param temp
159 * @param copy
160 * @return deep_unique_ptr<Base>
161 */
162template <typename Base, typename Derived, typename CopyFunc>
163deep_unique_ptr<Base> make_deep_unique(Derived &&temp, CopyFunc copy)
164{
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100165 return {new Derived(std::move(temp)), CopyFunc{std::move(copy)}};
SiCong Lib63b1192022-01-28 18:24:39 +0000166}
167
168template <typename Base, typename Derived>
169deep_unique_ptr<Base> make_deep_unique(Derived &&temp)
170{
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100171 static_assert(std::is_base_of<Base, Derived>::value, "Derived is not a specialization of Base");
SiCong Lib63b1192022-01-28 18:24:39 +0000172
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100173 return make_deep_unique<Base, Derived>(std::move(temp), default_polymorphic_copy<Base, Derived>);
SiCong Lib63b1192022-01-28 18:24:39 +0000174}
175
176template <typename Base, typename Derived, typename... Args>
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100177deep_unique_ptr<Base> make_deep_unique(Args &&...args)
SiCong Lib63b1192022-01-28 18:24:39 +0000178{
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100179 static_assert(std::is_constructible<Derived, Args...>::value, "Cannot instantiate Derived from arguments");
SiCong Lib63b1192022-01-28 18:24:39 +0000180
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100181 return make_deep_unique<Base, Derived>(std::move(Derived{std::forward<Args>(args)...}));
SiCong Lib63b1192022-01-28 18:24:39 +0000182}
183
184} // namespace memory
185} // namespace utils
186} // namespace arm_compute
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100187#endif // ARM_COMPUTE_MISC_ITERABLE_H