cpp-msgpack-rpc 0.2.0
An RPC library implementing MessagePack RPC.
Loading...
Searching...
No Matches
shared_objects.h
Go to the documentation of this file.
1/*
2 * Copyright 2024 MusicScience37 (Kenta Kabashima)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
20#pragma once
21
22#include <atomic>
23#include <memory>
24#include <new>
25#include <optional>
26#include <utility>
27#include <vector>
28
30
36template <typename T>
38public:
42 SharedObjectBuffer() noexcept = default;
43
50 [[nodiscard]] bool try_start_use() noexcept {
51 int empty = -1;
52 constexpr int initial = 1;
53 return reference_count_.compare_exchange_strong(empty, initial,
54 std::memory_order_acquire, std::memory_order_relaxed);
55 }
56
65 template <typename... Args>
66 void emplace(Args&&... args) {
67 buffer_.emplace(std::forward<Args>(args)...);
68 }
69
73 void add_reference() noexcept {
74 reference_count_.fetch_add(1, std::memory_order_relaxed);
75 }
76
80 void release() noexcept {
81 const int reference_count =
82 reference_count_.fetch_sub(1, std::memory_order_acq_rel);
83 if (reference_count == 1) {
84 buffer_.reset();
85 const int empty = -1;
86 reference_count_.store(empty, std::memory_order_release);
87 }
88 }
89
95 [[nodiscard]] T* get() noexcept {
96 return &(*buffer_); // NOLINT
97 }
98
99private:
101 std::atomic<int> reference_count_{-1};
102
104 std::optional<T> buffer_{};
105};
106
107template <typename T>
108class SharedObjectMemoryPool;
109
115template <typename T>
117public:
121 SharedObject() noexcept = default;
122
129 explicit SharedObject(SharedObjectBuffer<T>* buffer,
130 std::shared_ptr<SharedObjectMemoryPool<T>> memory_pool) noexcept
131 : buffer_(buffer), memory_pool_(std::move(memory_pool)) {}
132
138 SharedObject(const SharedObject& other) noexcept
139 : buffer_(other.buffer_), memory_pool_(other.memory_pool_) {
140 if (buffer_ != nullptr) {
141 buffer_->add_reference();
142 }
143 }
144
150 SharedObject(SharedObject&& other) noexcept
151 : buffer_(std::exchange(other.buffer_, nullptr)),
152 memory_pool_(std::exchange(other.memory_pool_,
153 std::shared_ptr<SharedObjectMemoryPool<T>>())) {}
154
161 SharedObject& operator=(const SharedObject& other) noexcept {
162 if (this == &other) {
163 return *this;
164 }
165 reset();
166 buffer_ = other.buffer_;
167 memory_pool_ = other.memory_pool_;
168 if (buffer_ != nullptr) {
169 buffer_->add_reference();
170 }
171 return *this;
172 }
173
181 reset();
182 buffer_ = std::exchange(other.buffer_, nullptr);
183 memory_pool_ = std::exchange(
184 other.memory_pool_, std::shared_ptr<SharedObjectMemoryPool<T>>());
185 return *this;
186 }
187
191 ~SharedObject() noexcept { reset(); }
192
196 void reset() noexcept {
197 if (buffer_ != nullptr) {
198 buffer_->release();
199 buffer_ = nullptr;
200 memory_pool_.reset();
201 }
202 }
203
204private:
207
209 std::shared_ptr<SharedObjectMemoryPool<T>> memory_pool_{};
210};
211
217template <typename T>
219 : public std::enable_shared_from_this<SharedObjectMemoryPool<T>> {
220public:
227 static std::shared_ptr<SharedObjectMemoryPool<T>> create(
228 std::size_t num_buffers) {
229 return std::make_shared<SharedObjectMemoryPool<T>>(num_buffers);
230 }
231
237 explicit SharedObjectMemoryPool(std::size_t num_buffers)
238 : buffers_(num_buffers) {}
239
242 SharedObjectMemoryPool& operator=(const SharedObjectMemoryPool&) = delete;
243 SharedObjectMemoryPool& operator=(SharedObjectMemoryPool&&) = delete;
244
249
257 template <typename... Args>
258 [[nodiscard]] SharedObject<T> create(Args&&... args) {
259 const std::size_t initial_buffer_index = next_buffer_index_;
260 while (true) {
261 const std::size_t buffer_index = next_buffer_index_++;
263 SharedObjectBuffer<T>& buffer = buffers_[buffer_index];
264 if (!buffer.try_start_use()) {
265 if (next_buffer_index_ == initial_buffer_index) {
266 throw std::bad_alloc();
267 }
268 continue;
269 }
270
271 try {
272 buffer.emplace(std::forward<Args>(args)...);
273 return SharedObject<T>(&buffer, this->shared_from_this());
274 } catch (...) {
275 buffer.release();
276 throw;
277 }
278 }
279 }
280
281private:
283 std::vector<SharedObjectBuffer<T>> buffers_;
284
286 std::size_t next_buffer_index_{0};
287};
288
289} // namespace msgpack_rpc::util::impl
Class of buffers of shared objects.
T * get() noexcept
Access the object.
void add_reference() noexcept
Increase the reference count.
SharedObjectBuffer() noexcept=default
Constructor.
std::atomic< int > reference_count_
Reference count. (-1 for unused buffer.)
bool try_start_use() noexcept
Try to start to use.
void emplace(Args &&... args)
Construct an object.
void release() noexcept
Decrease the reference count and destruct the object if needed.
Class of memory pools of shared objects.
SharedObjectMemoryPool(std::size_t num_buffers)
Constructor.
std::vector< SharedObjectBuffer< T > > buffers_
Buffers.
std::size_t next_buffer_index_
Index of the next buffer.
static std::shared_ptr< SharedObjectMemoryPool< T > > create(std::size_t num_buffers)
Create a memory pool.
SharedObject< T > create(Args &&... args)
Create a shared object.
Class to hold shared objects.
SharedObject(SharedObject &&other) noexcept
Move constructor.
SharedObject & operator=(const SharedObject &other) noexcept
Copy assignment operator.
void reset() noexcept
Remove the buffer.
SharedObject(const SharedObject &other) noexcept
Copy constructor.
SharedObject & operator=(SharedObject &&other) noexcept
Move assignment operator.
SharedObject() noexcept=default
Constructor.
SharedObjectBuffer< T > * buffer_
Buffer of the shared object.
std::shared_ptr< SharedObjectMemoryPool< T > > memory_pool_
Memory pool.
Namespace of internal implementations.
STL namespace.