cpp-msgpack-rpc 0.2.0
An RPC library implementing MessagePack RPC.
Loading...
Searching...
No Matches
sharable_binary_header.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 <cassert>
24#include <cstddef>
25#include <cstdlib>
26#include <limits>
27#include <new>
28
30
32
37public:
39 std::size_t total_memory_size;
40
42 std::size_t binary_size;
43
45 std::size_t binary_capacity;
46
48 alignas(alignof(std::atomic<int>)) // NOLINTNEXTLINE
49 char reference_count_buffer[sizeof(std::atomic<int>)];
50
53};
54
56constexpr std::size_t SHARABLE_BINARY_ALIGNMENT = alignof(SharableBinaryHeader);
57
58// Assumption to use std::malloc, std::realloc, std::free.
59static_assert(SHARABLE_BINARY_ALIGNMENT <= alignof(std::max_align_t));
60
68 std::size_t binary_size) {
69 constexpr std::size_t header_size = sizeof(SharableBinaryHeader);
70 const std::size_t total_memory_size = header_size + binary_size;
71
72 void* raw_ptr = std::malloc(total_memory_size); // NOLINT(*-no-malloc)
73 if (raw_ptr == nullptr) {
74 // Since memory allocation has failed, the class of exceptions with
75 // memory allocation like MsgpackRPCException cannot be used.
76 throw std::bad_alloc();
77 }
78
79 auto* ptr = static_cast<SharableBinaryHeader*>(raw_ptr);
80 ptr->total_memory_size = total_memory_size;
81 ptr->binary_size = binary_size;
82 ptr->binary_capacity = binary_size;
83 ptr->is_reference_count_enabled = false;
84
85 return ptr;
86}
87
94 constexpr std::size_t header_size = sizeof(SharableBinaryHeader);
95 // This value is not tuned.
96 constexpr std::size_t total_memory_size = 128;
97 static_assert(total_memory_size > header_size);
98
99 void* raw_ptr = std::malloc(total_memory_size); // NOLINT(*-no-malloc)
100 if (raw_ptr == nullptr) {
101 // Since memory allocation has failed, the class of exceptions with
102 // memory allocation like MsgpackRPCException cannot be used.
103 throw std::bad_alloc();
104 }
105
106 auto* ptr = static_cast<SharableBinaryHeader*>(raw_ptr);
107 ptr->total_memory_size = total_memory_size;
108 ptr->binary_size = 0U;
109 ptr->binary_capacity = total_memory_size - header_size;
110 ptr->is_reference_count_enabled = false;
111
112 return ptr;
113}
114
123 SharableBinaryHeader* buffer, std::size_t required_size) {
124 // std::realloc is not safe when reference count (use of std::atomic<int>)
125 // is enabled.
126 assert(!buffer->is_reference_count_enabled);
127
128 std::size_t new_capacity = buffer->binary_capacity;
129 while (true) {
130 // TODO Prevent overflow.
131 new_capacity <<= 1U;
132 if (new_capacity >= required_size) {
133 break;
134 }
135 }
136 constexpr std::size_t header_size = sizeof(SharableBinaryHeader);
137 const std::size_t new_total_memory_size = header_size + new_capacity;
138
139 void* raw_ptr =
140 std::realloc(buffer, new_total_memory_size); // NOLINT(*-no-malloc)
141 if (raw_ptr == nullptr) {
142 // Since memory allocation has failed, the class of exceptions with
143 // memory allocation like MsgpackRPCException cannot be used.
144 throw std::bad_alloc();
145 }
146
147 auto* ptr = static_cast<SharableBinaryHeader*>(raw_ptr);
148 ptr->total_memory_size = new_total_memory_size;
149 ptr->binary_capacity = new_total_memory_size - header_size;
150
151 return ptr;
152}
153
160[[nodiscard]] inline std::atomic<int>& reference_count_of(
161 SharableBinaryHeader* buffer) noexcept {
162 assert(buffer->is_reference_count_enabled);
163 // NOLINTNEXTLINE(*-reinterpret-cast)
164 return *reinterpret_cast<std::atomic<int>*>(buffer->reference_count_buffer);
165}
166
173 if (buffer == nullptr) {
174 return;
175 }
176 if (buffer->is_reference_count_enabled) {
177 using AtomicType = std::atomic<int>;
178 reference_count_of(buffer).~AtomicType();
179 }
180 std::free(buffer); // NOLINT(*-no-malloc)
181}
182
189 SharableBinaryHeader* buffer) noexcept {
190 assert(!buffer->is_reference_count_enabled);
191 new (static_cast<void*>(buffer->reference_count_buffer))
192 std::atomic<int>(1);
193 buffer->is_reference_count_enabled = true;
194}
195
202 SharableBinaryHeader* buffer) noexcept {
203 reference_count_of(buffer).fetch_add(1, std::memory_order_relaxed);
204}
205
213 SharableBinaryHeader* buffer) noexcept {
214 const int reference_count_before =
215 reference_count_of(buffer).fetch_sub(1, std::memory_order_acq_rel);
216 if (reference_count_before == 1) {
218 }
219}
220
227inline char* binary_buffer_of(SharableBinaryHeader* buffer) noexcept {
228 // NOLINTNEXTLINE
229 return reinterpret_cast<char*>(buffer) + sizeof(SharableBinaryHeader);
230}
231
232} // namespace msgpack_rpc::messages::impl
Namespace of internal implementations.
void decrease_reference_count_of_sharable_binary(SharableBinaryHeader *buffer) noexcept
Decrease a reference count of a buffer of sharable binary data, and deallocate the buffer if possible...
char * binary_buffer_of(SharableBinaryHeader *buffer) noexcept
Get buffer of binary data from a buffer of sharable binary data.
SharableBinaryHeader * expand_sharable_binary(SharableBinaryHeader *buffer, std::size_t required_size)
Expand a buffer of sharable binary data.
void add_reference_count_of_sharable_binary(SharableBinaryHeader *buffer) noexcept
Add a reference count of a buffer of sharable binary data.
constexpr std::size_t SHARABLE_BINARY_ALIGNMENT
Alignment of sharable binary data.
void deallocate_sharable_binary(SharableBinaryHeader *buffer) noexcept
Deallocate a buffer of sharable binary data.
std::atomic< int > & reference_count_of(SharableBinaryHeader *buffer) noexcept
Access the reference count of a buffer of sharable binary data.
SharableBinaryHeader * allocate_shared_binary()
Allocate a buffer of sharable binary data with automatic initial size.
void enable_reference_count_of_sharable_binary(SharableBinaryHeader *buffer) noexcept
Enable reference count of a buffer of sharable binary data.
SharableBinaryHeader * allocate_sharable_binary(std::size_t binary_size)
Allocate a buffer of sharable binary data.
Declaration of SharableBinaryHeader struct.
Struct of headers of sharable binary data.
std::size_t binary_capacity
Capacity of the binary data.
std::size_t total_memory_size
Total size of the memory buffer allocated for the binary data.
bool is_reference_count_enabled
Whether reference count is enabled.
char reference_count_buffer[sizeof(std::atomic< int >)]
Buffer of the object of reference count.