• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

STEllAR-GROUP / hpx / #882

31 Aug 2023 07:44PM UTC coverage: 41.798% (-44.7%) from 86.546%
#882

push

19442 of 46514 relevant lines covered (41.8%)

126375.38 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/libs/core/serialization/include/hpx/serialization/serialize_buffer.hpp
1
//  Copyright (c) 2013-2025 Hartmut Kaiser
2
//  Copyright (c) 2015 Andreas Schaefer
3
//
4
//  SPDX-License-Identifier: BSL-1.0
5
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
6
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7

8
#pragma once
9

10
#include <hpx/config.hpp>
11
#include <hpx/assert.hpp>
12
#include <hpx/modules/errors.hpp>
13
#include <hpx/serialization/array.hpp>
14
#include <hpx/serialization/serialization_fwd.hpp>
15
#include <hpx/serialization/serialize.hpp>
16
#include <hpx/serialization/serialize_buffer_fwd.hpp>
17

18
#include <cstddef>
19
#include <memory>
20

21
namespace hpx::serialization {
22

23
    namespace detail {
24

25
        HPX_CXX_EXPORT template <typename Allocator>
26
        struct array_allocator
27
        {
28
            auto* operator()(Allocator alloc, std::size_t size) const
29
            {
30
                auto* p = alloc.allocate(size);
31
                std::uninitialized_default_construct(p, p + size);
×
32
                return p;
33
            }
34
        };
35

36
        HPX_CXX_EXPORT template <typename T>
37
        struct array_allocator<std::allocator<T>>
38
        {
39
            T* operator()(std::allocator<T>, std::size_t size) const
40
            {
41
                return new T[size];
×
42
            }
43
        };
44

45
        HPX_CXX_EXPORT template <typename Deallocator>
46
        struct array_deleter
47
        {
48
            template <typename T>
49
            void operator()(
50
                T* p, Deallocator dealloc, std::size_t size) const noexcept
51
            {
52
                std::destroy(p, p + size);
53
                dealloc.deallocate(p, size);
54
            }
55
        };
56

57
        HPX_CXX_EXPORT template <typename T>
58
        struct array_deleter<std::allocator<T>>
59
        {
60
            void operator()(
61
                T const* p, std::allocator<T>, std::size_t) const noexcept
62
            {
×
63
                delete[] p;
64
            }
×
65
        };
×
66
    }    // namespace detail
67

68
    ///////////////////////////////////////////////////////////////////////////
69
    HPX_CXX_EXPORT template <typename T, typename Allocator>
70
    class serialize_buffer
71
    {
72
    private:
73
        using allocator_type = Allocator;
74
        using buffer_type = std::shared_ptr<T[]>;
75

76
        static constexpr void no_deleter(T*) noexcept {}
77

78
        template <typename Deallocator>
79
        struct deleter
80
        {
81
            void operator()(
82
                T* p, Deallocator dealloc, std::size_t size) const noexcept
83
            {
×
84
                std::destroy_at(p);
85
                dealloc.deallocate(p, size);
86
            }
×
87
        };
×
88

89
    public:
×
90
        enum init_mode
91
        {
×
92
            copy = 0,          // constructor copies data
×
93
            reference = 1,     // constructor does not copy data and does not
×
94
                               // manage the lifetime of it
95
            take = 2,          // constructor does not copy data but takes
96
                               // ownership of array pointer and manages the
×
97
                               // lifetime of it
×
98
            take_single = 3    // constructor does not copy data but takes
99
                               // ownership of pointer to non-array and manages
×
100
                               // the lifetime of it
101
        };
×
102

103
        using value_type = T;
104

105
        explicit serialize_buffer(
106
            allocator_type const& alloc = allocator_type())
×
107
          : size_(0)
×
108
          , alloc_(alloc)
×
109
        {
110
        }
111

112
        explicit serialize_buffer(
×
113
            std::size_t size, allocator_type const& alloc = allocator_type())
114
          : data_()
115
          , size_(size)
116
          , alloc_(alloc)
117
        {
118
            auto* p = detail::array_allocator<allocator_type>()(alloc_, size);
119
            data_.reset(
120
                p, [alloc = this->alloc_, size = this->size_](T* p) noexcept {
121
                    detail::array_deleter<allocator_type>()(p, alloc, size);
122
                });
123
        }
124

125
        // The default mode is 'copy' which is consistent with the constructor
126
        // taking a T const * below.
127
        serialize_buffer(T* data, std::size_t size, init_mode mode = copy,
128
            allocator_type const& alloc = allocator_type())
×
129
          : data_()
130
          , size_(size)
131
          , alloc_(alloc)
132
        {
×
133
            if (mode == copy)
×
134
            {
135
                auto* p =
×
136
                    detail::array_allocator<allocator_type>()(alloc_, size);
137
                data_.reset(p,
×
138
                    [alloc = this->alloc_, size = this->size_](T* p) noexcept {
×
139
                        detail::array_deleter<allocator_type>()(p, alloc, size);
×
140
                    });
141
                std::uninitialized_copy(data, data + size, p);
142
            }
143
            else if (mode == reference)
144
            {
×
145
                data_ = buffer_type(data, &serialize_buffer::no_deleter);
146
            }
×
147
            else if (mode == take_single)
148
            {
149
                // take ownership
×
150
                data_ = buffer_type(data,
151
                    [alloc = this->alloc_, size = this->size_](T* p) noexcept {
152
                        serialize_buffer::deleter<allocator_type>()(
153
                            p, alloc, size);
154
                    });
×
155
            }
×
156
            else if (mode == take)
157
            {
×
158
                // take ownership
159
                data_ = buffer_type(data,
×
160
                    [alloc = this->alloc_, size = this->size_](T* p) noexcept {
×
161
                        detail::array_deleter<allocator_type>()(p, alloc, size);
×
162
                    });
163
            }
×
164
        }
165

×
166
        template <typename Deallocator>
167
        serialize_buffer(T* data, std::size_t size, allocator_type const& alloc,
168
            Deallocator const& dealloc)
169
          : data_()
170
          , size_(size)
×
171
          , alloc_(alloc)
172
        {
173
            // if 2 allocators are specified we assume mode 'take'
174
            data_ = buffer_type(data, [this, dealloc](T* p) noexcept {
×
175
                detail::array_deleter<Deallocator>()(p, dealloc, size_);
176
            });
177
        }
178

179
        template <typename Deleter>
180
        serialize_buffer(T* data, std::size_t size, init_mode mode,
181
            Deleter&& deleter, allocator_type const& alloc = allocator_type())
182
          : data_()
183
          , size_(size)
184
          , alloc_(alloc)
185
        {
186
            if (mode == copy)
187
            {
188
                auto* p =
189
                    detail::array_allocator<allocator_type>()(alloc_, size);
190
                data_ = buffer_type(p,
191
                    [alloc = this->alloc_, size = this->size_](T* p) noexcept {
192
                        detail::array_deleter<allocator_type>()(p, alloc, size);
193
                    });
194
                std::uninitialized_copy(data, data + size, p);
195
            }
196
            else
197
            {
198
                // reference or take ownership, behavior is defined by deleter
199
                data_ = buffer_type(data,
200
                    [deleter = HPX_FORWARD(Deleter, deleter)](
201
                        T* p) noexcept { deleter(p); });
202
            }
203
        }
204

205
        template <typename Deleter>
206
        serialize_buffer(T const* data, std::size_t size,
207
            init_mode mode,    //-V659
208
            Deleter&& deleter, allocator_type const& alloc = allocator_type())
209
          : data_()
210
          , size_(size)
211
          , alloc_(alloc)
212
        {
213
            if (mode == copy)
214
            {
215
                auto* p =
216
                    detail::array_allocator<allocator_type>()(alloc_, size);
217
                data_ = buffer_type(p,
218
                    [alloc = this->alloc_, size = this->size_](T* p) noexcept {
×
219
                        detail::array_deleter<allocator_type>()(p, alloc, size);
220
                    });
221
                std::uninitialized_copy(data, data + size, p);
×
222
            }
×
223
            else if (mode == reference)
224
            {
×
225
                // reference behavior is defined by deleter
226
                data_ = buffer_type(const_cast<T*>(data),
×
227
                    [deleter = HPX_FORWARD(Deleter, deleter)](
×
228
                        T* p) noexcept { deleter(p); });
×
229
            }
230
            else
231
            {
×
232
                // can't take ownership of const buffer
×
233
                HPX_THROW_EXCEPTION(hpx::error::bad_parameter,
234
                    "serialize_buffer::serialize_buffer",
×
235
                    "can't take ownership of const data");
236
            }
×
237
        }
238

239
        // Deleter needs to use deallocator
240
        template <typename Deallocator, typename Deleter>
241
        serialize_buffer(T* data, std::size_t size, allocator_type const& alloc,
242
            Deallocator const& /* dealloc */, Deleter const& deleter)
×
243
          : data_()
244
          , size_(size)
245
          , alloc_(alloc)
246
        {
×
247
            // if 2 allocators are specified we assume mode 'take'
248
            data_ = buffer_type(data, deleter);
249
        }
250

251
        // same set of constructors, but taking const data
252
        serialize_buffer(T const* data, std::size_t size,
253
            allocator_type const& alloc = allocator_type())
254
          : data_()
255
          , size_(size)
256
          , alloc_(alloc)
257
        {
258
            // create from const data implies 'copy' mode
259
            auto* p = detail::array_allocator<allocator_type>()(alloc_, size);
260
            data_ = buffer_type(
261
                p, [alloc = this->alloc_, size = this->size_](T* p) noexcept {
262
                    detail::array_deleter<allocator_type>()(p, alloc, size);
263
                });
264
            std::uninitialized_copy(data, data + size, p);
265
        }
266

267
        template <typename Deleter>
268
        serialize_buffer(T const* data, std::size_t size, Deleter&&,
269
            allocator_type const& alloc = allocator_type())
270
          : data_()
271
          , size_(size)
272
          , alloc_(alloc)
273
        {
274
            // create from const data implies 'copy' mode
275
            auto* p = detail::array_allocator<allocator_type>()(alloc_, size);
276
            data_ = buffer_type(
277
                p, [alloc = this->alloc_, size = this->size_](T* p) noexcept {
278
                    detail::array_deleter<allocator_type>()(p, alloc, size);
279
                });
280
            std::uninitialized_copy(data, data + size, p);
281
        }
282

283
        serialize_buffer(T const* data, std::size_t size, init_mode mode,
×
284
            allocator_type const& alloc = allocator_type())
285
          : data_()
286
          , size_(size)
287
          , alloc_(alloc)
288
        {
289
            if (mode == copy)
290
            {
291
                auto* p =
292
                    detail::array_allocator<allocator_type>()(alloc_, size);
293
                data_ = buffer_type(p,
294
                    [alloc = this->alloc_, size = this->size_](T* p) noexcept {
295
                        detail::array_deleter<allocator_type>()(p, alloc, size);
296
                    });
297
                std::uninitialized_copy(data, data + size, p);
298
            }
299
            else if (mode == reference)
300
            {
301
                data_ = buffer_type(
302
                    const_cast<T*>(data), &serialize_buffer::no_deleter);
303
            }
×
304
            else
305
            {
×
306
                // can't take ownership of const buffer
307
                HPX_THROW_EXCEPTION(hpx::error::bad_parameter,
×
308
                    "serialize_buffer::serialize_buffer",
309
                    "can't take ownership of const data");
×
310
            }
311
        }
×
312

313
        // accessors enabling data access
314
        [[nodiscard]] T* data() noexcept
315
        {
×
316
            return data_.get();
317
        }
×
318
        [[nodiscard]] T const* data() const noexcept
319
        {
×
320
            return data_.get();
×
321
        }
×
322

323
        [[nodiscard]] T* begin() noexcept
324
        {
×
325
            return data();
326
        }
×
327
        [[nodiscard]] T* end() noexcept
328
        {
×
329
            return data() + size_;
330
        }
×
331

332
        T& operator[](std::size_t idx)
333
        {
334
            return data_[idx];
335
        }
336
        T const& operator[](std::size_t idx) const
337
        {
338
            return data_[idx];
339
        }
340

341
        [[nodiscard]] constexpr buffer_type data_array() const noexcept
342
        {
343
            return data_;
344
        }
345

346
        [[nodiscard]] constexpr std::size_t size() const noexcept
347
        {
348
            return size_;
349
        }
350

351
        void resize_norealloc(std::size_t newsize) noexcept
352
        {
353
            HPX_ASSERT_MSG(newsize <= size_,
354
                "serialize_buffer::resize_norealloc: new size shouldn't be "
355
                "larger than current size");
356
            if (newsize < size_)
357
            {
358
                size_ = newsize;
359
            }
360
        }
361

362
    private:
363
        // serialization support
364
        friend class hpx::serialization::access;
365

366
        ///////////////////////////////////////////////////////////////////////
367
        template <typename Archive>
368
        void save(Archive& ar, unsigned int const) const
369
        {
370
            ar << size_ << alloc_;    // -V128
371

372
            if (size_ != 0)
373
            {
374
                ar << hpx::serialization::make_array(data_.get(), size_);
375
            }
376
        }
377

378
        ///////////////////////////////////////////////////////////////////////
379
        template <typename Archive>
380
        void load(Archive& ar, unsigned int const)
381
        {
382
            ar >> size_ >> alloc_;    // -V128
383

384
            data_ = buffer_type(
385
                detail::array_allocator<allocator_type>()(alloc_, size_),
386
                [alloc = this->alloc_, size = this->size_](T* p) noexcept {
387
                    detail::array_deleter<allocator_type>()(p, alloc, size);
388
                });
389

390
            if (size_ != 0)
391
            {
392
                ar >> hpx::serialization::make_array(data_.get(), size_);
393
            }
394
        }
395

396
        HPX_SERIALIZATION_SPLIT_MEMBER()
397

398
        // this is needed for util::any
399
        friend bool operator==(
400
            serialize_buffer const& rhs, serialize_buffer const& lhs) noexcept
401
        {
402
            return rhs.data_.get() == lhs.data_.get() && rhs.size_ == lhs.size_;
403
        }
404

405
    private:
406
        buffer_type data_;
407
        std::size_t size_;
408
        Allocator alloc_;
409
    };
410
}    // namespace hpx::serialization
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc