sparrow 0.9.0
Loading...
Searching...
No Matches
memory.hpp
Go to the documentation of this file.
1// Copyright 2024 Man Group Operations Limited
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or mplied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#pragma once
16
17#include <compare>
18#include <concepts>
19#include <cstddef>
20#include <memory>
21#include <type_traits>
22
24
25namespace sparrow
26{
34 template <class T>
36 {
37 using internal_pointer = std::unique_ptr<T>;
38
39 public:
40
42 using pointer = typename internal_pointer::pointer;
43 using element_type = typename internal_pointer::element_type;
44
45 // Value semantic
46
47 constexpr value_ptr() noexcept = default;
48 constexpr value_ptr(std::nullptr_t) noexcept;
49 constexpr explicit value_ptr(T value);
50 constexpr explicit value_ptr(T* value);
51
52 ~value_ptr() = default;
53
54 constexpr value_ptr(const value_ptr& other);
55 constexpr value_ptr(value_ptr&& other) noexcept = default;
56
57 constexpr value_ptr& operator=(const value_ptr& other);
58 constexpr value_ptr& operator=(value_ptr&& other) noexcept = default;
59
60 constexpr value_ptr& operator=(std::nullptr_t) noexcept;
61
62 // Modifiers
63
64 constexpr void reset() noexcept;
65
66 // Observers
67
68 [[nodiscard]] constexpr T* get() noexcept;
69 [[nodiscard]] constexpr const T* get() const noexcept;
70
71 constexpr explicit operator bool() const noexcept;
72 [[nodiscard]] constexpr bool has_value() const noexcept;
73
74 [[nodiscard]] constexpr T& operator*();
75 [[nodiscard]] constexpr const T& operator*() const;
76
77 [[nodiscard]] constexpr T* operator->();
78 [[nodiscard]] constexpr const T* operator->() const;
79
80 private:
81
82 internal_pointer value_;
83 };
84
85 namespace detail
86 {
87 template <class T>
88 struct is_unique_ptr : std::false_type
89 {
90 };
91
92 template <class T, class D>
93 struct is_unique_ptr<std::unique_ptr<T, D>> : std::true_type
94 {
95 };
96
97 template <class T>
99 }
108 template <class T>
109 concept clonable = std::derived_from<T, std::decay_t<decltype(*std::declval<T*>()->clone())>>
110 && detail::is_unique_ptr_v<decltype(std::declval<T*>()->clone())>;
111
124 template <clonable T>
126 {
127 using internal_pointer = std::unique_ptr<T>;
128
129 public:
130
132 using pointer = typename internal_pointer::pointer;
133 using element_type = typename internal_pointer::element_type;
134
135 // Value semantic
136
137 constexpr cloning_ptr() noexcept = default;
138 constexpr cloning_ptr(std::nullptr_t) noexcept;
139 explicit constexpr cloning_ptr(pointer p) noexcept;
140
141 constexpr ~cloning_ptr() = default;
142
143 constexpr cloning_ptr(const self_type& rhs) noexcept;
144 constexpr cloning_ptr(self_type&& rhs) noexcept = default;
145
146
147 template <clonable U>
148 requires std::convertible_to<U*, T*>
149 constexpr cloning_ptr(const cloning_ptr<U>& rhs) noexcept;
150
151 template <clonable U>
152 requires std::convertible_to<U*, T*>
153 constexpr cloning_ptr(cloning_ptr<U>&& rhs) noexcept;
154
155 constexpr self_type& operator=(const self_type&) noexcept;
156 constexpr self_type& operator=(self_type&&) noexcept = default;
157 constexpr self_type& operator=(std::nullptr_t) noexcept;
158
159 template <clonable U>
160 requires std::convertible_to<U*, T*>
161 constexpr self_type& operator=(const cloning_ptr<U>& rhs) noexcept;
162
163 template <clonable U>
164 requires std::convertible_to<U*, T*>
165 constexpr self_type& operator=(cloning_ptr<U>&& rhs) noexcept;
166
167 // Modifiers
168
169 constexpr pointer release() noexcept;
170 constexpr void reset(pointer ptr = pointer()) noexcept;
171 void swap(self_type&) noexcept;
172
173 // Observers
174
175 [[nodiscard]] constexpr pointer get() const noexcept;
176
177 constexpr explicit operator bool() const noexcept;
178
179 [[nodiscard]] constexpr std::add_lvalue_reference_t<T>
180 operator*() const noexcept(noexcept(*std::declval<pointer>()));
181
182 [[nodiscard]] constexpr pointer operator->() const noexcept;
183
184 private:
185
186 [[nodiscard]] constexpr internal_pointer& ptr_impl() noexcept;
187 [[nodiscard]] constexpr const internal_pointer& ptr_impl() const noexcept;
188
189 internal_pointer m_data;
190 };
191
192 template <class T>
193 void swap(cloning_ptr<T>& lhs, cloning_ptr<T>& rhs) noexcept;
194
195 template <class T1, class T2>
196 requires std::equality_comparable_with<typename cloning_ptr<T1>::pointer, typename cloning_ptr<T2>::pointer>
197 constexpr bool operator==(const cloning_ptr<T1>& lhs, const cloning_ptr<T2>& rhs) noexcept;
198
199 template <class T1, class T2>
200 requires std::three_way_comparable_with<typename cloning_ptr<T1>::pointer, typename cloning_ptr<T2>::pointer>
201 constexpr std::compare_three_way_result_t<typename cloning_ptr<T1>::pointer, typename cloning_ptr<T2>::pointer>
202 operator<=>(const cloning_ptr<T1>& lhs, const cloning_ptr<T2>& rhs) noexcept;
203
204 template <class T>
205 constexpr bool operator==(const cloning_ptr<T>& lhs, std::nullptr_t) noexcept;
206
207 template <class T>
208 requires std::three_way_comparable<typename cloning_ptr<T>::pointer>
209 constexpr std::compare_three_way_result_t<typename cloning_ptr<T>::pointer>
210 operator<=>(const cloning_ptr<T>& lhs, std::nullptr_t) noexcept;
211
212 template <class T, class... Args>
213 cloning_ptr<T> make_cloning_ptr(Args&&... args);
214
215 /****************************
216 * value_ptr implementation *
217 ****************************/
218
219 template <class T>
220 constexpr value_ptr<T>::value_ptr(std::nullptr_t) noexcept
221 {
222 }
223
224 template <class T>
225 constexpr value_ptr<T>::value_ptr(T value)
226 : value_(std::make_unique<T>(std::move(value)))
227 {
228 }
229
230 template <class T>
231 constexpr value_ptr<T>::value_ptr(T* value)
232 : value_(value != nullptr ? std::make_unique<T>(*value) : std::unique_ptr<T>())
233 {
234 }
235
236 template <class T>
237 constexpr value_ptr<T>::value_ptr(const value_ptr& other)
238 : value_(other.value_ ? std::make_unique<T>(*other.value_) : std::unique_ptr<T>())
239 {
240 }
241
242 template <class T>
244 {
245 if (other.has_value())
246 {
247 if (value_)
248 {
249 *value_ = *other.value_;
250 }
251 else
252 {
253 value_ = std::make_unique<T>(*other.value_);
254 }
255 }
256 else
257 {
258 value_.reset();
259 }
260 return *this;
261 }
262
263 template <class T>
264 constexpr value_ptr<T>& value_ptr<T>::operator=(std::nullptr_t) noexcept
265 {
266 reset();
267 return *this;
268 }
269
270 template <class T>
271 constexpr void value_ptr<T>::reset() noexcept
272 {
273 value_.reset();
274 }
275
276 template <class T>
277 constexpr T* value_ptr<T>::get() noexcept
278 {
279 return value_.get();
280 }
281
282 template <class T>
283 constexpr const T* value_ptr<T>::get() const noexcept
284 {
285 return value_.get();
286 }
287
288 template <class T>
289 constexpr value_ptr<T>::operator bool() const noexcept
290 {
291 return has_value();
292 }
293
294 template <class T>
295 constexpr bool value_ptr<T>::has_value() const noexcept
296 {
297 return bool(value_);
298 }
299
300 template <class T>
302 {
303 SPARROW_ASSERT_TRUE(value_);
304 return *value_;
305 }
306
307 template <class T>
308 constexpr const T& value_ptr<T>::operator*() const
309 {
310 SPARROW_ASSERT_TRUE(value_);
311 return *value_;
312 }
313
314 template <class T>
316 {
317 SPARROW_ASSERT_TRUE(value_);
318 return &*value_;
319 }
320
321 template <class T>
322 constexpr const T* value_ptr<T>::operator->() const
323 {
324 SPARROW_ASSERT_TRUE(value_);
325 return &*value_;
326 }
327
328 /******************************
329 * cloning_ptr implementation *
330 ******************************/
331
332 template <clonable T>
333 constexpr cloning_ptr<T>::cloning_ptr(std::nullptr_t) noexcept
334 : m_data(nullptr)
335 {
336 }
337
338 template <clonable T>
340 : m_data(p)
341 {
342 }
343
344 template <clonable T>
345 constexpr cloning_ptr<T>::cloning_ptr(const cloning_ptr& rhs) noexcept
346 : m_data(rhs ? rhs->clone() : nullptr)
347 {
348 }
349
350 template <clonable T>
351 template <clonable U>
352 requires std::convertible_to<U*, T*>
353 constexpr cloning_ptr<T>::cloning_ptr(const cloning_ptr<U>& rhs) noexcept
354 : m_data(rhs ? rhs->clone() : nullptr)
355 {
356 }
357
358 template <clonable T>
359 template <clonable U>
360 requires std::convertible_to<U*, T*>
362 : m_data(rhs.release())
363 {
364 }
365
366 template <clonable T>
367 constexpr auto cloning_ptr<T>::operator=(const self_type& rhs) noexcept -> self_type&
368 {
369 m_data = rhs ? rhs->clone() : nullptr;
370 return *this;
371 }
372
373 template <clonable T>
374 constexpr auto cloning_ptr<T>::operator=(std::nullptr_t) noexcept -> self_type&
375 {
376 reset(nullptr);
377 return *this;
378 }
379
380 template <clonable T>
381 template <clonable U>
382 requires std::convertible_to<U*, T*>
383 constexpr auto cloning_ptr<T>::operator=(const cloning_ptr<U>& rhs) noexcept -> self_type&
384 {
385 m_data = rhs ? rhs->clone() : nullptr;
386 return *this;
387 }
388
389 template <clonable T>
390 template <clonable U>
391 requires std::convertible_to<U*, T*>
392 constexpr auto cloning_ptr<T>::operator=(cloning_ptr<U>&& rhs) noexcept -> self_type&
393 {
394 reset(rhs.release());
395 return *this;
396 }
397
398 template <clonable T>
399 constexpr auto cloning_ptr<T>::release() noexcept -> pointer
400 {
401 return ptr_impl().release();
402 }
403
404 template <clonable T>
405 constexpr void cloning_ptr<T>::reset(pointer ptr) noexcept
406 {
407 ptr_impl().reset(ptr);
408 }
409
410 template <clonable T>
411 void cloning_ptr<T>::swap(self_type& other) noexcept
412 {
413 using std::swap;
414 swap(ptr_impl(), other.ptr_impl());
415 }
416
417 template <clonable T>
418 constexpr auto cloning_ptr<T>::get() const noexcept -> pointer
419 {
420 return ptr_impl().get();
421 }
422
423 template <clonable T>
424 constexpr cloning_ptr<T>::operator bool() const noexcept
425 {
426 return bool(ptr_impl());
427 }
428
429 template <clonable T>
430 constexpr std::add_lvalue_reference_t<T>
431 cloning_ptr<T>::operator*() const noexcept(noexcept(*std::declval<pointer>()))
432 {
433 return *get();
434 }
435
436 template <clonable T>
437 constexpr auto cloning_ptr<T>::operator->() const noexcept -> pointer
438 {
439 return get();
440 }
441
442 template <clonable T>
443 constexpr auto cloning_ptr<T>::ptr_impl() noexcept -> internal_pointer&
444 {
445 return m_data;
446 }
447
448 template <clonable T>
449 constexpr auto cloning_ptr<T>::ptr_impl() const noexcept -> const internal_pointer&
450 {
451 return m_data;
452 }
453
454 /*********************************
455 * Free functions implementation *
456 *********************************/
457
458 template <class T>
459 void swap(cloning_ptr<T>& lhs, cloning_ptr<T>& rhs) noexcept
460 {
461 lhs.swap(rhs);
462 }
463
464 template <class T1, class T2>
465 requires std::equality_comparable_with<typename cloning_ptr<T1>::pointer, typename cloning_ptr<T2>::pointer>
466 constexpr bool operator==(const cloning_ptr<T1>& lhs, const cloning_ptr<T2>& rhs) noexcept
467 {
468 return lhs.get() == rhs.get();
469 }
470
471 template <class T1, class T2>
472 requires std::three_way_comparable_with<typename cloning_ptr<T1>::pointer, typename cloning_ptr<T2>::pointer>
473 constexpr std::compare_three_way_result_t<typename cloning_ptr<T1>::pointer, typename cloning_ptr<T2>::pointer>
474 operator<=>(const cloning_ptr<T1>& lhs, const cloning_ptr<T2>& rhs) noexcept
475 {
476 return lhs.get() <=> rhs.get();
477 }
478
479 template <class T>
480 constexpr bool operator==(const cloning_ptr<T>& lhs, std::nullptr_t) noexcept
481 {
482 return !lhs;
483 }
484
485 template <class T>
486 requires std::three_way_comparable<typename cloning_ptr<T>::pointer>
487 constexpr std::compare_three_way_result_t<typename cloning_ptr<T>::pointer>
488 operator<=>(const cloning_ptr<T>& lhs, std::nullptr_t) noexcept
489 {
490 using pointer = typename cloning_ptr<T>::pointer;
491 return lhs.get() <=> static_cast<pointer>(nullptr);
492 }
493
494 template <class T, class... Args>
496 {
497 return cloning_ptr<T>(new T(std::forward<Args>(args)...));
498 }
499}
Smart pointer behaving like a copiable std::unique_ptr.
Definition memory.hpp:126
constexpr pointer operator->() const noexcept
Definition memory.hpp:437
typename internal_pointer::element_type element_type
Definition memory.hpp:133
constexpr pointer get() const noexcept
constexpr cloning_ptr() noexcept=default
constexpr self_type & operator=(const self_type &) noexcept
Definition memory.hpp:367
constexpr void reset(pointer ptr=pointer()) noexcept
constexpr std::add_lvalue_reference_t< T > operator*() const noexcept(noexcept(*std::declval< pointer >()))
Definition memory.hpp:431
void swap(self_type &) noexcept
constexpr pointer release() noexcept
typename internal_pointer::pointer pointer
Definition memory.hpp:132
constexpr bool has_value() const noexcept
Definition memory.hpp:295
constexpr T * get() noexcept
Definition memory.hpp:277
typename internal_pointer::element_type element_type
Definition memory.hpp:43
typename internal_pointer::pointer pointer
Definition memory.hpp:42
constexpr value_ptr & operator=(const value_ptr &other)
Definition memory.hpp:243
constexpr T & operator*()
Definition memory.hpp:301
constexpr void reset() noexcept
Definition memory.hpp:271
constexpr T * operator->()
Definition memory.hpp:315
value_ptr< T > self_type
Definition memory.hpp:41
constexpr value_ptr() noexcept=default
Matches types that provide a clone method.
Definition memory.hpp:109
#define SPARROW_ASSERT_TRUE(expr__)
constexpr bool is_unique_ptr_v
Definition memory.hpp:98
constexpr std::compare_three_way_result_t< typename cloning_ptr< T1 >::pointer, typename cloning_ptr< T2 >::pointer > operator<=>(const cloning_ptr< T1 > &lhs, const cloning_ptr< T2 > &rhs) noexcept
Definition memory.hpp:474
SPARROW_API bool operator==(const array &lhs, const array &rhs)
Compares the content of two arrays.
SPARROW_API void swap(ArrowArray &lhs, ArrowArray &rhs)
Swaps the contents of the two ArrowArray objects.
cloning_ptr< T > make_cloning_ptr(Args &&... args)
Definition memory.hpp:495