Skip to content

Commit 64209d5

Browse files
Cleaning up polyfill namespace for memory.hpp (#49)
* cleaning up array resource design * added true array resource and renamed existing to buffer resource * refactor of array memory resources * fixing MemoryResourceDeleter design * fixing formatting errors * fixing MISRA warnings * fixing coverage and a bug in reallocate * fixing examples build * fixing up some MISRA code smells
1 parent 8b0a3b9 commit 64209d5

28 files changed

+1265
-536
lines changed

cetlvast/include/cetlvast/helpers_gtest_memory_resource.hpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
/// Copyright Amazon.com Inc. or its affiliates.
77
/// SPDX-License-Identifier: MIT
88
///
9-
// cSpell: words pocca pocma soccc
9+
// cSpell: words soccc
1010

1111
#ifndef CETLVAST_HELPERS_GTEST_MEMORY_RESOURCE_H_INCLUDED
1212
#define CETLVAST_HELPERS_GTEST_MEMORY_RESOURCE_H_INCLUDED
@@ -32,6 +32,9 @@ class MockPf17MemoryResource : public cetl::pf17::pmr::memory_resource
3232
MOCK_METHOD(void*, do_allocate, (std::size_t size_bytes, std::size_t alignment));
3333
MOCK_METHOD(void, do_deallocate, (void* p, std::size_t size_bytes, std::size_t alignment));
3434
MOCK_METHOD(bool, do_is_equal, (const cetl::pf17::pmr::memory_resource& rhs), (const, noexcept));
35+
MOCK_METHOD(void*,
36+
do_reallocate,
37+
(void* p, std::size_t old_size_bytes, std::size_t new_size_bytes, std::size_t new_alignment));
3538

3639
static constexpr bool ReturnsNullWhenFNoExceptions = true;
3740

@@ -41,6 +44,15 @@ class MockPf17MemoryResource : public cetl::pf17::pmr::memory_resource
4144
}
4245
};
4346

47+
/// No-type memory resource that looks like std::pmr::memory_resource.
48+
class MockMemoryResource
49+
{
50+
public:
51+
MOCK_METHOD(void*, allocate, (std::size_t size_bytes, std::size_t alignment));
52+
MOCK_METHOD(void, deallocate, (void* p, std::size_t size_bytes, std::size_t alignment));
53+
MOCK_METHOD(bool, is_equal, (const MockMemoryResource& rhs), (const, noexcept));
54+
};
55+
4456
#if (__cplusplus >= CETL_CPP_STANDARD_17)
4557
/// Std Mock of memory_resource.
4658
class MockStdMemoryResource : public std::pmr::memory_resource

cetlvast/suites/docs/examples/example_03_memory_resource.cpp

Lines changed: 19 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,10 @@
1010
/// SPDX-License-Identifier: MIT
1111
///
1212
#include "cetl/cetl.hpp"
13+
#include "cetl/pmr/memory.hpp"
1314
#include "cetl/pf17/sys/memory_resource.hpp"
14-
15-
#if (__cplusplus >= CETL_CPP_STANDARD_17 && !defined(CETL_DOXYGEN))
16-
#include <memory_resource>
1715
#include "cetl/pf17/byte.hpp"
16+
1817
#include <iostream>
1918
#include <memory>
2019
#include <algorithm>
@@ -23,15 +22,14 @@
2322

2423
#include <gtest/gtest.h>
2524

26-
2725
namespace cetl
2826
{
2927
namespace pf17
3028
{
3129

3230
/// Implements a memory resource that over-allocates memory from an upstream memory resource to support
3331
/// over-aligning allocations without C++17 or platform-specific system calls.
34-
class OverAlignedMemoryResource : public pmr::memory_resource
32+
class OverAlignedMemoryResource : public cetl::pf17::pmr::memory_resource
3533
{
3634
/// A control-block, of sorts.
3735
/// The MemoryBlock provides a map between the system aligned memory returned by the
@@ -113,7 +111,7 @@ class OverAlignedMemoryResource : public pmr::memory_resource
113111
// std::pmr::monotonic_buffer_resource.
114112
if (nullptr == upstream_)
115113
{
116-
#if __cpp_exceptions
114+
#if defined(__cpp_exceptions)
117115
throw std::bad_alloc();
118116
#endif
119117
return nullptr;
@@ -165,7 +163,7 @@ class OverAlignedMemoryResource : public pmr::memory_resource
165163
// is just example code we haven't rigorously proven that it will always be correct. UMMV.
166164
if (nullptr == aligned_memory || max_aligned_memory_size < size_bytes)
167165
{
168-
#if __cpp_exceptions
166+
#if defined(__cpp_exceptions)
169167
throw std::bad_alloc();
170168
#endif
171169
return nullptr;
@@ -321,37 +319,19 @@ class FakeDmaTransfer
321319
};
322320

323321
template <typename T>
324-
struct MemoryResourceDeleter
325-
{
326-
MemoryResourceDeleter(pmr::memory_resource* resource, std::size_t allocation_size, std::size_t buffer_alignment)
327-
: resource_(resource)
328-
, allocation_size_(allocation_size)
329-
, buffer_alignment_(buffer_alignment)
330-
{
331-
}
332-
333-
void operator()(T* p)
334-
{
335-
CETL_DEBUG_ASSERT(nullptr != resource_, "null memory_resource stored in MemoryResourceDeleter!");
336-
resource_->deallocate(p, allocation_size_, buffer_alignment_);
337-
};
338-
339-
private:
340-
pmr::memory_resource* resource_;
341-
std::size_t allocation_size_;
342-
std::size_t buffer_alignment_;
343-
};
344-
345-
template <typename T>
346-
std::unique_ptr<T, MemoryResourceDeleter<T>> allocate_buffer(pmr::memory_resource& allocator,
347-
std::size_t buffer_size,
348-
std::size_t buffer_alignment)
322+
std::unique_ptr<T, cetl::pmr::MemoryResourceDeleter<cetl::pf17::pmr::memory_resource>> allocate_buffer(
323+
pmr::memory_resource& allocator,
324+
std::size_t buffer_size,
325+
std::size_t buffer_alignment)
349326
{
350-
return std::unique_ptr<T, MemoryResourceDeleter<T>>{static_cast<T*>(
351-
allocator.allocate(buffer_size, buffer_alignment)),
352-
MemoryResourceDeleter<T>{&allocator,
353-
buffer_size,
354-
buffer_alignment}};
327+
return std::unique_ptr<
328+
T,
329+
cetl::pmr::MemoryResourceDeleter<
330+
cetl::pf17::pmr::memory_resource>>{static_cast<T*>(allocator.allocate(buffer_size, buffer_alignment)),
331+
cetl::pmr::MemoryResourceDeleter<
332+
cetl::pf17::pmr::memory_resource>{&allocator,
333+
buffer_size,
334+
buffer_alignment}};
355335
}
356336

357337
// +--------------------------------------------------------------------------+
@@ -360,7 +340,7 @@ std::unique_ptr<T, MemoryResourceDeleter<T>> allocate_buffer(pmr::memory_resourc
360340

361341
TEST(example_03_memory_resource, main)
362342
{
363-
//! [main]
343+
//! [main]
364344
cetl::pf17::OverAlignedMemoryResource over_aligned_new_delete_resource{};
365345

366346
// let's pretend we have dma that must be aligned to a 128-byte (1024-bit) boundary:
@@ -386,7 +366,5 @@ TEST(example_03_memory_resource, main)
386366
// Do remember that memory_resource does not construct and delete objects. That is the job of allocators like
387367
// cetl::pf17::pmr::polymorphic_allocator. Because this example only used trivially constructable, copyable, and
388368
// destructible types we didn't have to build that machinery.
389-
//! [main]
369+
//! [main]
390370
}
391-
392-
#endif

cetlvast/suites/docs/examples/example_04_array_memory_resource_array.cpp renamed to cetlvast/suites/docs/examples/example_04_buffer_memory_resource.cpp

Lines changed: 26 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,43 @@
11
/// @file
2-
/// Example of using the cetl::pmr::UnsynchronizedArrayMemoryResource in cetl/pmr/array_memory_resource.hpp.
2+
/// Example of using the cetl::pf17::pmr::UnsynchronizedArrayMemoryResource in cetl/pf17/array_memory_resource.hpp.
33
///
44
/// @copyright
55
/// Copyright (C) OpenCyphal Development Team <opencyphal.org>
66
/// Copyright Amazon.com Inc. or its affiliates.
77
/// SPDX-License-Identifier: MIT
88
///
99

10-
//![example_include]
11-
#include "cetl/pmr/array_memory_resource.hpp"
12-
#include "cetl/pf17/cetlpf.hpp"
13-
//![example_include]
10+
#include "cetl/pf17/sys/memory_resource.hpp"
11+
#include "cetl/pf17/buffer_memory_resource.hpp"
1412

1513
#include <gtest/gtest.h>
1614
#include <gmock/gmock.h>
1715

1816
#include <vector>
1917
#include <iostream>
2018

21-
//![example_setup]
2219
struct Message
2320
{
24-
explicit Message(const cetl::pmr::polymorphic_allocator<std::uint64_t>& allocator)
21+
explicit Message(const cetl::pf17::pmr::polymorphic_allocator<std::uint64_t>& allocator)
2522
: data{allocator}
2623
{
2724
}
28-
std::vector<std::uint64_t, cetl::pmr::polymorphic_allocator<std::uint64_t>> data;
25+
std::vector<std::uint64_t, cetl::pf17::pmr::polymorphic_allocator<std::uint64_t>> data;
2926
};
3027

3128
// Let's say we have a data structure that contains a Message with variable-length data in it.
3229
// We can use UnsynchronizedArrayMemoryResource to allocate a buffer large enough to hold all of this data at once
3330
// but if there is less data the std::vector in the message will return the size() of that data (i.e. where an
3431
// std::array would not).
3532
static constexpr std::size_t SmallMessageSizeBytes = 64 * 8;
36-
static cetl::byte small_message_buffer_[SmallMessageSizeBytes];
33+
static cetl::pf17::byte small_message_buffer_[SmallMessageSizeBytes];
3734

38-
//![example_setup]
39-
40-
TEST(example_04_array_memory_resource_array, example_a)
35+
TEST(example_04_buffer_memory_resource, example_a)
4136
{
4237
//![example_a]
43-
cetl::pmr::UnsynchronizedArrayMemoryResource<cetl::pmr::memory_resource>
44-
aResource{small_message_buffer_, SmallMessageSizeBytes, cetl::pmr::null_memory_resource(), 0};
45-
cetl::pmr::polymorphic_allocator<std::uint64_t> aAlloc{&aResource};
46-
Message a{aAlloc};
38+
cetl::pf17::pmr::UnsynchronizedBufferMemoryResource aResource{small_message_buffer_, SmallMessageSizeBytes};
39+
cetl::pf17::pmr::polymorphic_allocator<std::uint64_t> aAlloc{&aResource};
40+
Message a{aAlloc};
4741

4842
// The big "gotcha" when using UnsynchronizedArrayMemoryResource with STL containers is that you must reserve
4943
// the size needed before you insert data into them. This is because UnsynchronizedArrayMemoryResource only
@@ -63,21 +57,20 @@ TEST(example_04_array_memory_resource_array, example_a)
6357
//![example_a]
6458
}
6559

66-
TEST(example_04_array_memory_resource_array, example_b)
60+
TEST(example_04_buffer_memory_resource, example_b)
6761
{
6862
//![example_b]
6963
// BUT WAIT! THERE'S MORE! The UnsynchronizedArrayMemoryResource both slices and dices! That is, you can provide
7064
// an upstream allocator to turn this into a "small buffer optimization" resource where the internal allocation
7165
// is the small buffer and the upstream allocator becomes the larger allocator.
7266

73-
cetl::pmr::UnsynchronizedArrayMemoryResource<cetl::pmr::memory_resource>
74-
bResource{small_message_buffer_,
75-
SmallMessageSizeBytes,
76-
cetl::pmr::new_delete_resource(),
77-
std::numeric_limits<std::size_t>::max()};
67+
cetl::pf17::pmr::UnsynchronizedBufferMemoryResource bResource{small_message_buffer_,
68+
SmallMessageSizeBytes,
69+
cetl::pf17::pmr::new_delete_resource(),
70+
std::numeric_limits<std::size_t>::max()};
7871

79-
cetl::pmr::polymorphic_allocator<std::uint64_t> bAlloc{&bResource};
80-
Message b{bAlloc};
72+
cetl::pf17::pmr::polymorphic_allocator<std::uint64_t> bAlloc{&bResource};
73+
Message b{bAlloc};
8174

8275
// This time we won't reserve which should cause vector to do multiple allocations. We'll also insert
8376
// a bunch more items than there is space in the small message buffer.
@@ -93,22 +86,20 @@ TEST(example_04_array_memory_resource_array, example_b)
9386
//![example_b]
9487
}
9588

96-
TEST(example_04_array_memory_resource_array, example_c)
89+
TEST(example_04_buffer_memory_resource, example_c)
9790
{
9891
//![example_c]
9992
// One more example: by using another UnsynchronizedArrayMemoryResource as an upstream for another
10093
// UnsynchronizedArrayMemoryResource with the same-sized buffer you can use vector push_back without reserve up
10194
// to the size of these buffers.
102-
static cetl::byte upstream_buffer[SmallMessageSizeBytes];
103-
cetl::pmr::UnsynchronizedArrayMemoryResource<cetl::pmr::memory_resource>
104-
cUpstreamResource{&upstream_buffer, SmallMessageSizeBytes, cetl::pmr::null_memory_resource(), 0};
105-
cetl::pmr::UnsynchronizedArrayMemoryResource<cetl::pmr::memory_resource>
106-
cResource{small_message_buffer_,
107-
SmallMessageSizeBytes,
108-
&cUpstreamResource,
109-
std::numeric_limits<std::size_t>::max()};
110-
cetl::pmr::polymorphic_allocator<std::uint64_t> cAlloc{&cResource};
111-
Message c{cAlloc};
95+
static cetl::pf17::byte upstream_buffer[SmallMessageSizeBytes];
96+
cetl::pf17::pmr::UnsynchronizedBufferMemoryResource cUpstreamResource{&upstream_buffer, SmallMessageSizeBytes};
97+
cetl::pf17::pmr::UnsynchronizedBufferMemoryResource cResource{small_message_buffer_,
98+
SmallMessageSizeBytes,
99+
&cUpstreamResource,
100+
std::numeric_limits<std::size_t>::max()};
101+
cetl::pf17::pmr::polymorphic_allocator<std::uint64_t> cAlloc{&cResource};
102+
Message c{cAlloc};
112103

113104
// We also won't reserve in this example which should cause vector to do multiple allocations. We'll insert
114105
// exactly the number of items that will fit in the small message buffer. Because containers like vector use a
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/// @file
2+
/// Demonstration of memory alignment when using the cetl::pf17::pmr::UnsynchronizedArrayMemoryResource in
3+
/// cetl/pf17/array_memory_resource.hpp.
4+
///
5+
/// @copyright
6+
/// Copyright (C) OpenCyphal Development Team <opencyphal.org>
7+
/// Copyright Amazon.com Inc. or its affiliates.
8+
/// SPDX-License-Identifier: MIT
9+
///
10+
11+
#include <iostream>
12+
13+
#include <gtest/gtest.h>
14+
15+
#include "cetl/pf17/array_memory_resource.hpp"
16+
#include "cetl/pf17/byte.hpp"
17+
18+
TEST(example_05_array_memory_resource, example_0)
19+
{
20+
static_assert(alignof(std::max_align_t) < 128, "Wow, what hardware are you running on?");
21+
//![example_0]
22+
constexpr std::size_t BufferSizeBytes = 64;
23+
cetl::pf17::pmr::UnsynchronizedArrayMemoryResource<BufferSizeBytes> resource{};
24+
25+
// let's say we have a buffer that must be aligned to a 128-byte (1024-bit) boundary. If we tried to use
26+
// UnsynchronizedArrayMemoryResource with a 64-byte internal array, on a typical system, the allocation would fail.
27+
28+
void* r = nullptr;
29+
#if defined(__cpp_exceptions)
30+
try
31+
{
32+
#endif
33+
r = resource.allocate(64, 128);
34+
#if defined(__cpp_exceptions)
35+
} catch (const std::bad_alloc&)
36+
{
37+
// This is expected.
38+
}
39+
#endif
40+
std::cout << "Over-aligned attempt failed: " << r << std::endl;
41+
42+
//![example_0]
43+
}
44+
45+
TEST(example_05_array_memory_resource, example_1)
46+
{
47+
//![example_1]
48+
// By over-provisioning the buffer you can now get the alignment you want:
49+
constexpr std::size_t BufferSizeBytes = 64 + 128;
50+
cetl::pf17::pmr::UnsynchronizedArrayMemoryResource<BufferSizeBytes> resource{};
51+
52+
void* r = resource.allocate(64, 128);
53+
54+
std::cout << "Over-aligned address at: " << r << std::endl;
55+
56+
resource.deallocate(r, 64, 128);
57+
//![example_1]
58+
}

0 commit comments

Comments
 (0)