Cuda battery library
Loading...
Searching...
No Matches
root_ptr.hpp
Go to the documentation of this file.
1// Copyright 2024 Pierre Talbot
2
3#ifndef CUDA_BATTERY_ROOT_PTR_HPP
4#define CUDA_BATTERY_ROOT_PTR_HPP
5
6#include "utility.hpp"
7#include "allocator.hpp"
8
9/** \file root_ptr.hpp
10 This smart pointer is a variant of shared_ptr where only the first instance has the ownership of the object.
11 This is intended to be used with hierarchical data structures where the root of the hierarchy is the owner of the data, and the root is deleted after the children.
12 A use-case in GPU programming is to distribute shared data over blocks; using shared_ptr would lead to data races since the class is not thread-safe; with root_ptr, only one block is responsible for the deletion.
13*/
14
15namespace battery {
16
17template <class T, class Allocator = standard_allocator>
18class root_ptr {
19public:
20 using element_type = T;
21 using pointer = T*;
22 using allocator_type = Allocator;
24private:
25 Allocator allocator;
26 T* ptr;
27 bool root;
28
29 template<class U, class Alloc>
30 friend class root_ptr;
31public:
33 : allocator(allocator), ptr(nullptr), root(true) {}
34 CUDA root_ptr(std::nullptr_t, const allocator_type& allocator = allocator_type())
35 : allocator(allocator), ptr(nullptr), root(true) {}
36
37 // `ptr` must have been allocated using `allocator_type`.
38 CUDA explicit root_ptr(pointer ptr, const allocator_type& allocator = allocator_type())
39 : allocator(allocator), ptr(ptr), root(true) {}
40
41 CUDA root_ptr(this_type&& from) : ptr(from.ptr), allocator(from.allocator), root(from.root) {
42 from.ptr = nullptr;
43 }
44
45 template<class U>
47 : ptr(static_cast<T*>(from.ptr)), allocator(from.allocator), root(from.root)
48 {
49 from.ptr = nullptr;
50 }
51
52 CUDA root_ptr(const this_type& other)
53 : ptr(other.ptr), allocator(other.allocator), root(false)
54 {}
55
57 if(root && ptr != nullptr) {
58 ptr->~T();
59 allocator.deallocate(ptr);
60 ptr = nullptr;
61 }
62 }
63
64 CUDA void swap(root_ptr& other) {
65 ::battery::swap(ptr, other.ptr);
66 ::battery::swap(allocator, other.allocator);
67 ::battery::swap(root, other.root);
68 }
69
71 this_type(std::move(r)).swap(*this);
72 return *this;
73 }
74
76 this_type(r).swap(*this);
77 root = false;
78 return *this;
79 }
80
81 template<class U>
83 this_type(std::move(r)).swap(*this);
84 return *this;
85 }
86
87 CUDA root_ptr& operator=(std::nullptr_t) {
88 this_type(allocator).swap(*this);
89 return *this;
90 }
91
93 pointer p = ptr;
94 ptr = nullptr;
95 root = true;
96 return p;
97 }
98
99 CUDA void reset(pointer ptr = pointer()) {
100 this_type(ptr, allocator).swap(*this);
101 }
102
103 CUDA pointer get() const {
104 return ptr;
105 }
106
108 return allocator;
109 }
110
111 CUDA bool is_root() const {
112 return root;
113 }
114
115 CUDA explicit operator bool() const {
116 return ptr != nullptr;
117 }
118
119 CUDA T& operator*() const {
120 assert(bool(ptr));
121 return *ptr;
122 }
123
125 assert(bool(ptr));
126 return ptr;
127 }
128};
129
130template<class T, class Alloc, class... Args>
131CUDA NI root_ptr<T, Alloc> allocate_root(const Alloc& alloc, Args&&... args) {
132 Alloc allocator(alloc);
133 T* ptr = static_cast<T*>(allocator.allocate(sizeof(T)));
134 assert(ptr != nullptr);
135 if constexpr(std::is_constructible<T, Args&&..., const Alloc&>{}) {
136 new(ptr) T(std::forward<Args>(args)..., allocator);
137 }
138 else {
139 new(ptr) T(std::forward<Args>(args)...);
140 }
141 return root_ptr<T, Alloc>(ptr, allocator);
142}
143
144/** Similar to `allocate_root` but with an default-constructed allocator. */
145template<class T, class Alloc, class... Args>
147 return allocate_root<T>(Alloc(), std::forward<Args>(args)...);
148}
149
150}
151#endif
Definition root_ptr.hpp:18
CUDA root_ptr & operator=(std::nullptr_t)
Definition root_ptr.hpp:87
CUDA allocator_type get_allocator() const
Definition root_ptr.hpp:107
CUDA root_ptr(std::nullptr_t, const allocator_type &allocator=allocator_type())
Definition root_ptr.hpp:34
T element_type
Definition root_ptr.hpp:20
CUDA root_ptr & operator=(const root_ptr &r)
Definition root_ptr.hpp:75
CUDA root_ptr(root_ptr< U, Allocator > &&from)
Definition root_ptr.hpp:46
CUDA bool is_root() const
Definition root_ptr.hpp:111
root_ptr< element_type, allocator_type > this_type
Definition root_ptr.hpp:23
CUDA NI ~root_ptr()
Definition root_ptr.hpp:56
CUDA root_ptr(pointer ptr, const allocator_type &allocator=allocator_type())
Definition root_ptr.hpp:38
T * pointer
Definition root_ptr.hpp:21
CUDA void reset(pointer ptr=pointer())
Definition root_ptr.hpp:99
CUDA root_ptr(const this_type &other)
Definition root_ptr.hpp:52
CUDA root_ptr & operator=(root_ptr &&r)
Definition root_ptr.hpp:70
CUDA pointer release()
Definition root_ptr.hpp:92
Allocator allocator_type
Definition root_ptr.hpp:22
CUDA root_ptr(const allocator_type &allocator=allocator_type())
Definition root_ptr.hpp:32
CUDA pointer get() const
Definition root_ptr.hpp:103
CUDA T & operator*() const
Definition root_ptr.hpp:119
CUDA root_ptr(this_type &&from)
Definition root_ptr.hpp:41
CUDA void swap(root_ptr &other)
Definition root_ptr.hpp:64
CUDA pointer operator->() const
Definition root_ptr.hpp:124
CUDA root_ptr & operator=(root_ptr< U, Allocator > &&r)
Definition root_ptr.hpp:82
Definition algorithm.hpp:10
CUDA NI root_ptr< T, Alloc > allocate_root(const Alloc &alloc, Args &&... args)
Definition root_ptr.hpp:131
CUDA constexpr void swap(T &a, T &b)
Definition utility.hpp:91
CUDA root_ptr< T, Alloc > make_root(Args &&... args)
Definition root_ptr.hpp:146
#define CUDA
Definition utility.hpp:59
#define NI
Definition utility.hpp:62