sparrow 0.3.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{
35 template <class T>
37 {
38 using internal_pointer = std::unique_ptr<T>;
39
40 public:
41
43 using pointer = typename internal_pointer::pointer;
44 using element_type = typename internal_pointer::element_type;
45
46 // Value semantic
47
48 constexpr value_ptr() noexcept = default;
49 constexpr value_ptr(std::nullptr_t) noexcept;
50 explicit value_ptr(T value);
51 explicit value_ptr(T* value);
52
53 ~value_ptr() = default;
54
55 value_ptr(const value_ptr& other);
56 value_ptr(value_ptr&& other) noexcept = default;
57
58 value_ptr& operator=(const value_ptr& other);
59 value_ptr& operator=(value_ptr&& other) noexcept = default;
60
61 value_ptr& operator=(std::nullptr_t) noexcept;
62
63 // Modifiers
64
65 void reset() noexcept;
66
67 // Observers
68
69 [[nodiscard]] T* get() noexcept;
70 [[nodiscard]] const T* get() const noexcept;
71
72 explicit operator bool() const noexcept;
73 [[nodiscard]] bool has_value() const noexcept;
74
75 [[nodiscard]] T& operator*();
76 [[nodiscard]] const T& operator*() const;
77
78 [[nodiscard]] T* operator->();
79 [[nodiscard]] const T* operator->() const;
80
81 private:
82
83 internal_pointer value_;
84 };
85
86 namespace detail
87 {
88 template <class T>
89 struct is_unique_ptr : std::false_type
90 {
91 };
92
93 template <class T, class D>
94 struct is_unique_ptr<std::unique_ptr<T, D>> : std::true_type
95 {
96 };
97
98 template <class T>
100 }
109 template <class T>
110 concept clonable = std::derived_from<T, std::decay_t<decltype(*std::declval<T*>()->clone())>>
111 && detail::is_unique_ptr_v<decltype(std::declval<T*>()->clone())>;
112
125 template <clonable T>
127 {
128 using internal_pointer = std::unique_ptr<T>;
129
130 public:
131
133 using pointer = typename internal_pointer::pointer;
134 using element_type = typename internal_pointer::element_type;
135
136 // Value semantic
137
138 constexpr cloning_ptr() noexcept = default;
139 constexpr cloning_ptr(std::nullptr_t) noexcept;
140 explicit constexpr cloning_ptr(pointer p) noexcept;
141
142 constexpr ~cloning_ptr() = default;
143
144 constexpr cloning_ptr(const self_type& rhs) noexcept;
145 constexpr cloning_ptr(self_type&& rhs) noexcept = default;
146
147
148 template <clonable U>
149 requires std::convertible_to<U*, T*>
150 constexpr cloning_ptr(const cloning_ptr<U>& rhs) noexcept;
151
152 template <clonable U>
153 requires std::convertible_to<U*, T*>
154 constexpr cloning_ptr(cloning_ptr<U>&& rhs) noexcept;
155
156 constexpr self_type& operator=(const self_type&) noexcept;
157 constexpr self_type& operator=(self_type&&) noexcept = default;
158 constexpr self_type& operator=(std::nullptr_t) noexcept;
159
160 template <clonable U>
161 requires std::convertible_to<U*, T*>
162 constexpr self_type& operator=(const cloning_ptr<U>& rhs) noexcept;
163
164 template <clonable U>
165 requires std::convertible_to<U*, T*>
166 constexpr self_type& operator=(cloning_ptr<U>&& rhs) noexcept;
167
168 // Modifiers
169
170 constexpr pointer release() noexcept;
171 constexpr void reset(pointer ptr = pointer()) noexcept;
172 void swap(self_type&) noexcept;
173
174 // Observers
175
176 [[nodiscard]] constexpr pointer get() const noexcept;
177
178 constexpr explicit operator bool() const noexcept;
179
180 [[nodiscard]] constexpr std::add_lvalue_reference_t<T> operator*() const
181 noexcept(noexcept(*std::declval<pointer>()));
182
183 [[nodiscard]] constexpr pointer operator->() const noexcept;
184
185 private:
186
187 [[nodiscard]] constexpr internal_pointer& ptr_impl() noexcept;
188 [[nodiscard]] constexpr const internal_pointer& ptr_impl() const noexcept;
189
190 internal_pointer m_data;
191 };
192
193 template <class T>
194 void swap(cloning_ptr<T>& lhs, cloning_ptr<T>& rhs) noexcept;
195
196 template <class T1, class T2>
197 requires std::equality_comparable_with<typename cloning_ptr<T1>::pointer, typename cloning_ptr<T2>::pointer>
198 constexpr bool operator==(const cloning_ptr<T1>& lhs, const cloning_ptr<T2>& rhs) noexcept;
199
200 template <class T1, class T2>
201 requires std::three_way_comparable_with<typename cloning_ptr<T1>::pointer, typename cloning_ptr<T2>::pointer>
202 constexpr std::compare_three_way_result_t<typename cloning_ptr<T1>::pointer, typename cloning_ptr<T2>::pointer>
203 operator<=>(const cloning_ptr<T1>& lhs, const cloning_ptr<T2>& rhs) noexcept;
204
205 template <class T>
206 constexpr bool operator==(const cloning_ptr<T>& lhs, std::nullptr_t) noexcept;
207
208 template <class T>
209 requires std::three_way_comparable<typename cloning_ptr<T>::pointer>
210 constexpr std::compare_three_way_result_t<typename cloning_ptr<T>::pointer>
211 operator<=>(const cloning_ptr<T>& lhs, std::nullptr_t) noexcept;
212
213 template <class T, class... Args>
214 cloning_ptr<T> make_cloning_ptr(Args&&... args);
215
216 /****************************
217 * value_ptr implementation *
218 ****************************/
219
220 template <class T>
221 constexpr value_ptr<T>::value_ptr(std::nullptr_t) noexcept
222 {
223 }
224
225 template <class T>
227 : value_(std::make_unique<T>(std::move(value)))
228 {
229 }
230
231 template <class T>
233 : value_(value != nullptr ? std::make_unique<T>(*value) : std::unique_ptr<T>())
234 {
235 }
236
237 template <class T>
239 : value_(other.value_ ? std::make_unique<T>(*other.value_) : std::unique_ptr<T>())
240 {
241 }
242
243 template <class T>
245 {
246 if (other.has_value())
247 {
248 if (value_)
249 {
250 *value_ = *other.value_;
251 }
252 else
253 {
254 value_ = std::make_unique<T>(*other.value_);
255 }
256 }
257 else
258 {
259 value_.reset();
260 }
261 return *this;
262 }
263
264 template <class T>
265 value_ptr<T>& value_ptr<T>::operator=(std::nullptr_t) noexcept
266 {
267 reset();
268 return *this;
269 }
270
271 template <class T>
272 void value_ptr<T>::reset() noexcept
273 {
274 value_.reset();
275 }
276
277 template <class T>
278 T* value_ptr<T>::get() noexcept
279 {
280 return value_.get();
281 }
282
283 template <class T>
284 const T* value_ptr<T>::get() const noexcept
285 {
286 return value_.get();
287 }
288
289 template <class T>
290 value_ptr<T>::operator bool() const noexcept
291 {
292 return has_value();
293 }
294
295 template <class T>
296 bool value_ptr<T>::has_value() const noexcept
297 {
298 return bool(value_);
299 }
300
301 template <class T>
303 {
304 SPARROW_ASSERT_TRUE(value_);
305 return *value_;
306 }
307
308 template <class T>
309 const T& value_ptr<T>::operator*() const
310 {
311 SPARROW_ASSERT_TRUE(value_);
312 return *value_;
313 }
314
315 template <class T>
317 {
318 SPARROW_ASSERT_TRUE(value_);
319 return &*value_;
320 }
321
322 template <class T>
324 {
325 SPARROW_ASSERT_TRUE(value_);
326 return &*value_;
327 }
328
329 /******************************
330 * cloning_ptr implementation *
331 ******************************/
332
333 template <clonable T>
334 constexpr cloning_ptr<T>::cloning_ptr(std::nullptr_t) noexcept
335 : m_data(nullptr)
336 {
337 }
338
339 template <clonable T>
341 : m_data(p)
342 {
343 }
344
345 template <clonable T>
346 constexpr cloning_ptr<T>::cloning_ptr(const cloning_ptr& rhs) noexcept
347 : m_data(rhs ? rhs->clone() : nullptr)
348 {
349 }
350
351 template <clonable T>
352 template <clonable U>
353 requires std::convertible_to<U*, T*>
354 constexpr cloning_ptr<T>::cloning_ptr(const cloning_ptr<U>& rhs) noexcept
355 : m_data(rhs ? rhs->clone() : nullptr)
356 {
357 }
358
359 template <clonable T>
360 template <clonable U>
361 requires std::convertible_to<U*, T*>
363 : m_data(rhs.release())
364 {
365 }
366
367 template <clonable T>
368 constexpr auto cloning_ptr<T>::operator=(const self_type& rhs) noexcept -> self_type&
369 {
370 m_data = rhs ? rhs->clone() : nullptr;
371 return *this;
372 }
373
374 template <clonable T>
375 constexpr auto cloning_ptr<T>::operator=(std::nullptr_t) noexcept -> self_type&
376 {
377 reset(nullptr);
378 return *this;
379 }
380
381 template <clonable T>
382 template <clonable U>
383 requires std::convertible_to<U*, T*>
384 constexpr auto cloning_ptr<T>::operator=(const cloning_ptr<U>& rhs) noexcept -> self_type&
385 {
386 m_data = rhs ? rhs->clone() : nullptr;
387 return *this;
388 }
389
390 template <clonable T>
391 template <clonable U>
392 requires std::convertible_to<U*, T*>
393 constexpr auto cloning_ptr<T>::operator=(cloning_ptr<U>&& rhs) noexcept -> self_type&
394 {
395 reset(rhs.release());
396 return *this;
397 }
398
399 template <clonable T>
400 constexpr auto cloning_ptr<T>::release() noexcept -> pointer
401 {
402 return ptr_impl().release();
403 }
404
405 template <clonable T>
406 constexpr void cloning_ptr<T>::reset(pointer ptr) noexcept
407 {
408 ptr_impl().reset(ptr);
409 }
410
411 template <clonable T>
412 void cloning_ptr<T>::swap(self_type& other) noexcept
413 {
414 using std::swap;
415 swap(ptr_impl(), other.ptr_impl());
416 }
417
418 template <clonable T>
419 constexpr auto cloning_ptr<T>::get() const noexcept -> pointer
420 {
421 return ptr_impl().get();
422 }
423
424 template <clonable T>
425 constexpr cloning_ptr<T>::operator bool() const noexcept
426 {
427 return bool(ptr_impl());
428 }
429
430 template <clonable T>
431 constexpr std::add_lvalue_reference_t<T> cloning_ptr<T>::operator*() const
432 noexcept(noexcept(*std::declval<pointer>()))
433 {
434 return *get();
435 }
436
437 template <clonable T>
438 constexpr auto cloning_ptr<T>::operator->() const noexcept -> pointer
439 {
440 return get();
441 }
442
443 template <clonable T>
444 constexpr auto cloning_ptr<T>::ptr_impl() noexcept -> internal_pointer&
445 {
446 return m_data;
447 }
448
449 template <clonable T>
450 constexpr auto cloning_ptr<T>::ptr_impl() const noexcept -> const internal_pointer&
451 {
452 return m_data;
453 }
454
455 /*********************************
456 * Free functions implementation *
457 *********************************/
458
459 template <class T>
460 void swap(cloning_ptr<T>& lhs, cloning_ptr<T>& rhs) noexcept
461 {
462 lhs.swap(rhs);
463 }
464
465 template <class T1, class T2>
466 requires std::equality_comparable_with<typename cloning_ptr<T1>::pointer, typename cloning_ptr<T2>::pointer>
467 constexpr bool operator==(const cloning_ptr<T1>& lhs, const cloning_ptr<T2>& rhs) noexcept
468 {
469 return lhs.get() == rhs.get();
470 }
471
472 template <class T1, class T2>
473 requires std::three_way_comparable_with<typename cloning_ptr<T1>::pointer, typename cloning_ptr<T2>::pointer>
474 constexpr std::compare_three_way_result_t<typename cloning_ptr<T1>::pointer, typename cloning_ptr<T2>::pointer>
475 operator<=>(const cloning_ptr<T1>& lhs, const cloning_ptr<T2>& rhs) noexcept
476 {
477 return lhs.get() <=> rhs.get();
478 }
479
480 template <class T>
481 constexpr bool operator==(const cloning_ptr<T>& lhs, std::nullptr_t) noexcept
482 {
483 return !lhs;
484 }
485
486 template <class T>
487 requires std::three_way_comparable<typename cloning_ptr<T>::pointer>
488 constexpr std::compare_three_way_result_t<typename cloning_ptr<T>::pointer>
489 operator<=>(const cloning_ptr<T>& lhs, std::nullptr_t) noexcept
490 {
491 using pointer = typename cloning_ptr<T>::pointer;
492 return lhs.get() <=> static_cast<pointer>(nullptr);
493 }
494
495 template <class T, class... Args>
497 {
498 return cloning_ptr<T>(new T(std::forward<Args>(args)...));
499 }
500}
Smart pointer behaving like a copiable std::unique_ptr.
Definition memory.hpp:127
constexpr pointer operator->() const noexcept
Definition memory.hpp:438
typename internal_pointer::element_type element_type
Definition memory.hpp:134
constexpr pointer get() const noexcept
constexpr cloning_ptr() noexcept=default
constexpr self_type & operator=(const self_type &) noexcept
Definition memory.hpp:368
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:133
typename internal_pointer::element_type element_type
Definition memory.hpp:44
typename internal_pointer::pointer pointer
Definition memory.hpp:43
void reset() noexcept
Definition memory.hpp:272
value_ptr & operator=(const value_ptr &other)
Definition memory.hpp:244
value_ptr< T > self_type
Definition memory.hpp:42
constexpr value_ptr() noexcept=default
T * get() noexcept
Definition memory.hpp:278
bool has_value() const noexcept
Definition memory.hpp:296
Matches types that provide a clone method.
Definition memory.hpp:110
#define SPARROW_ASSERT_TRUE(expr__)
constexpr bool is_unique_ptr_v
Definition memory.hpp:99
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:475
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:496