Skip to content

Commit 096bc8c

Browse files
authored
Add std::allocator compatible memory allocator wrapper (#1637)
1 parent 09935e5 commit 096bc8c

File tree

6 files changed

+301
-5
lines changed

6 files changed

+301
-5
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* Added Castable class: [#1634](https://github.com/dartsim/dart/pull/1634)
88
* Added spdlog support as underlying logging framework: [#1633](https://github.com/dartsim/dart/pull/1633)
99
* Added MemoryAllocator and CAllocator: [#1636](https://github.com/dartsim/dart/pull/1636)
10+
* Added std::allocator compatible memory allocator wrapper: [#1637](https://github.com/dartsim/dart/pull/1637)
1011

1112
* Dynamics
1213

dart/common/CAllocator.cpp

+14-5
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
#include "dart/common/CAllocator.hpp"
3434

35+
#include "dart/common/Console.hpp"
3536
#include "dart/common/Logging.hpp"
3637

3738
namespace dart::common {
@@ -55,9 +56,15 @@ CAllocator::~CAllocator()
5556
void* pointer = it.first;
5657
size_t size = it.second;
5758
total_size += size;
58-
DART_FATAL("Found memory leak of {} bytes at {}!", size, pointer);
59+
dterr << "Found memory leak of " << size << " bytes at " << pointer
60+
<< "\n";
61+
// TODO(JS): Change to DART_FATAL once the issue of calling spdlog in
62+
// destructor is resolved.
5963
}
60-
DART_FATAL("Found potential memory leak of total {} bytes!", total_size);
64+
dterr << "Found potential memory leak of total " << total_size
65+
<< " bytes!\n";
66+
// TODO(JS): Change to DART_FATAL once the issue of calling spdlog in
67+
// destructor is resolved.
6168
}
6269
#endif
6370
}
@@ -99,12 +106,14 @@ void CAllocator::deallocate(void* pointer, size_t size)
99106
if (size != allocated_size)
100107
{
101108
DART_FATAL(
102-
"Cannot deallocated memory {} because the deallocating size {} is "
103-
"different from the allocated size {}.",
109+
"Attempting to deallocate memory at {} of {} bytes that is different "
110+
"from the allocated size {}, which is a critical bug. Deallocating "
111+
"{} bytes.",
104112
pointer,
105113
size,
114+
allocated_size,
106115
allocated_size);
107-
return;
116+
size = allocated_size;
108117
}
109118
m_size -= size;
110119
m_map_pointer_to_size.erase(it);

dart/common/StlAllocator.hpp

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
* Copyright (c) 2011-2021, The DART development contributors
3+
* All rights reserved.
4+
*
5+
* The list of contributors can be found at:
6+
* https://github.com/dartsim/dart/blob/master/LICENSE
7+
*
8+
* This file is provided under the following "BSD-style" License:
9+
* Redistribution and use in source and binary forms, with or
10+
* without modification, are permitted provided that the following
11+
* conditions are met:
12+
* * Redistributions of source code must retain the above copyright
13+
* notice, this list of conditions and the following disclaimer.
14+
* * Redistributions in binary form must reproduce the above
15+
* copyright notice, this list of conditions and the following
16+
* disclaimer in the documentation and/or other materials provided
17+
* with the distribution.
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19+
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20+
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21+
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23+
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26+
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27+
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28+
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29+
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30+
* POSSIBILITY OF SUCH DAMAGE.
31+
*/
32+
33+
#ifndef DART_COMMON_STLALLOCATOR_HPP_
34+
#define DART_COMMON_STLALLOCATOR_HPP_
35+
36+
#include <memory>
37+
38+
#include "dart/common/MemoryAllocator.hpp"
39+
40+
namespace dart::common {
41+
42+
/// Wrapper class for MemoryAllocator to be compatible with std::allocator
43+
template <typename T>
44+
class StlAllocator : public std::allocator<T>
45+
{
46+
public:
47+
// Type aliases
48+
using Base = std::allocator<T>;
49+
using value_type = typename std::allocator_traits<Base>::value_type;
50+
using size_type = typename std::allocator_traits<Base>::size_type;
51+
using pointer = typename std::allocator_traits<Base>::pointer;
52+
using const_pointer = typename std::allocator_traits<Base>::const_pointer;
53+
54+
template <typename U>
55+
struct rebind
56+
{
57+
using other = StlAllocator<U>;
58+
};
59+
60+
/// Default constructor
61+
explicit StlAllocator(
62+
MemoryAllocator& base_allocator = MemoryAllocator::GetDefault()) noexcept;
63+
64+
/// Copy constructor
65+
StlAllocator(const StlAllocator& other) throw();
66+
67+
/// Copy constructor
68+
template <class U>
69+
StlAllocator(const StlAllocator<U>& other) throw();
70+
71+
/// Destructor
72+
~StlAllocator() = default;
73+
74+
/// Allocates n * sizeof(T) bytes of uninitialized storage.
75+
///
76+
/// @param[in] n: The number of objects to allocate sotrage for.
77+
/// @param[in] hint: Point to a nearby memory location.
78+
/// @return On success, the pointer to the beginning of newly allocated
79+
/// memory.
80+
/// @return On failure, a null pointer
81+
[[nodiscard]] pointer allocate(size_type n, const void* hint = 0);
82+
83+
/// Deallocates the storage referenced by the pointer @c p, which must be a
84+
/// pointer obtained by an earlier cal to allocate().
85+
///
86+
/// @param[in] pointer: Pointer obtained from allocate().
87+
/// @param[in] n: Number of objects earlier passed to allocate().
88+
void deallocate(pointer pointer, size_type n);
89+
// TODO(JS): Make this constexpr once migrated to C++20
90+
91+
// TODO(JS): Add size_type max_size() const noexcept;
92+
93+
/// Prints state of the memory allocator
94+
void print(std::ostream& os = std::cout, int indent = 0) const;
95+
96+
/// Prints state of the memory allocator
97+
template <typename U>
98+
friend std::ostream& operator<<(
99+
std::ostream& os, const StlAllocator<U>& allocator);
100+
101+
private:
102+
template <typename U>
103+
friend class StlAllocator;
104+
MemoryAllocator& m_base_allocator;
105+
};
106+
107+
} // namespace dart::common
108+
109+
#include "dart/common/detail/StlAllocator-impl.hpp"
110+
111+
#endif // DART_COMMON_STLALLOCATOR_HPP_
+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Copyright (c) 2011-2021, The DART development contributors
3+
* All rights reserved.
4+
*
5+
* The list of contributors can be found at:
6+
* https://github.com/dartsim/dart/blob/master/LICENSE
7+
*
8+
* This file is provided under the following "BSD-style" License:
9+
* Redistribution and use in source and binary forms, with or
10+
* without modification, are permitted provided that the following
11+
* conditions are met:
12+
* * Redistributions of source code must retain the above copyright
13+
* notice, this list of conditions and the following disclaimer.
14+
* * Redistributions in binary form must reproduce the above
15+
* copyright notice, this list of conditions and the following
16+
* disclaimer in the documentation and/or other materials provided
17+
* with the distribution.
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19+
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20+
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21+
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23+
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26+
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27+
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28+
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29+
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30+
* POSSIBILITY OF SUCH DAMAGE.
31+
*/
32+
33+
#include "dart/common/Logging.hpp"
34+
#include "dart/common/StlAllocator.hpp"
35+
36+
namespace dart::common {
37+
38+
//==============================================================================
39+
template <typename T>
40+
StlAllocator<T>::StlAllocator(MemoryAllocator& base_allocator) noexcept
41+
: m_base_allocator(base_allocator)
42+
{
43+
// Do nothing
44+
}
45+
46+
//==============================================================================
47+
template <typename T>
48+
StlAllocator<T>::StlAllocator(const StlAllocator& other) throw()
49+
: std::allocator<T>(other), m_base_allocator(other.m_base_allocator)
50+
{
51+
// Do nothing
52+
}
53+
54+
//==============================================================================
55+
template <typename T>
56+
template <class U>
57+
StlAllocator<T>::StlAllocator(const StlAllocator<U>& other) throw()
58+
: std::allocator<T>(other), m_base_allocator(other.m_base_allocator)
59+
{
60+
// Do nothing
61+
}
62+
63+
//==============================================================================
64+
template <typename T>
65+
typename StlAllocator<T>::pointer StlAllocator<T>::allocate(
66+
size_type n, const void* hint)
67+
{
68+
(void)hint;
69+
pointer ptr
70+
= reinterpret_cast<pointer>(m_base_allocator.allocate(n * sizeof(T)));
71+
72+
// Throw std::bad_alloc to comply 23.10.9.1
73+
// Reference: https://stackoverflow.com/a/50326956/3122234
74+
if (!ptr)
75+
{
76+
throw std::bad_alloc();
77+
}
78+
79+
return ptr;
80+
}
81+
82+
//==============================================================================
83+
template <typename T>
84+
void StlAllocator<T>::deallocate(pointer pointer, size_type n)
85+
{
86+
m_base_allocator.deallocate(pointer, n * sizeof(T));
87+
}
88+
89+
//==============================================================================
90+
template <typename T>
91+
void StlAllocator<T>::print(std::ostream& os, int indent) const
92+
{
93+
if (indent == 0)
94+
{
95+
os << "[StlAllocator]\n";
96+
}
97+
const std::string spaces(indent, ' ');
98+
os << spaces << "base_allocator:\n";
99+
m_base_allocator.print(os, indent + 2);
100+
}
101+
102+
//==============================================================================
103+
template <typename T>
104+
std::ostream& operator<<(std::ostream& os, const StlAllocator<T>& allocator)
105+
{
106+
allocator.print(os);
107+
return os;
108+
}
109+
110+
} // namespace dart::common

unittests/unit/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ dart_add_test("unit" test_Optimizer)
2222
dart_add_test("unit" test_Random)
2323
dart_add_test("unit" test_ScrewJoint)
2424
dart_add_test("unit" test_Signal)
25+
dart_add_test("unit" test_StlAllocator)
2526
dart_add_test("unit" test_Subscriptions)
2627
dart_add_test("unit" test_TriMesh)
2728
dart_add_test("unit" test_Uri)

unittests/unit/test_StlAllocator.cpp

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright (c) 2011-2021, The DART development contributors
3+
* All rights reserved.
4+
*
5+
* The list of contributors can be found at:
6+
* https://github.com/dartsim/dart/blob/master/LICENSE
7+
*
8+
* This file is provided under the following "BSD-style" License:
9+
* Redistribution and use in source and binary forms, with or
10+
* without modification, are permitted provided that the following
11+
* conditions are met:
12+
* * Redistributions of source code must retain the above copyright
13+
* notice, this list of conditions and the following disclaimer.
14+
* * Redistributions in binary form must reproduce the above
15+
* copyright notice, this list of conditions and the following
16+
* disclaimer in the documentation and/or other materials provided
17+
* with the distribution.
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19+
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20+
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21+
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23+
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26+
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27+
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28+
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29+
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30+
* POSSIBILITY OF SUCH DAMAGE.
31+
*/
32+
33+
#include <dart/common/StlAllocator.hpp>
34+
#include <gtest/gtest.h>
35+
36+
#include "TestHelpers.hpp"
37+
38+
using namespace dart;
39+
using namespace common;
40+
41+
//==============================================================================
42+
TEST(StlAllocatorTest, Basics)
43+
{
44+
auto a = StlAllocator<int>();
45+
auto o1 = a.allocate(1);
46+
auto o2 = a.allocate(1);
47+
EXPECT_TRUE(o1 != nullptr);
48+
EXPECT_TRUE(o2 != nullptr);
49+
a.deallocate(o1, 1);
50+
a.deallocate(o2, 1);
51+
a.print();
52+
}
53+
54+
//==============================================================================
55+
TEST(StlAllocatorTest, StdVector)
56+
{
57+
std::vector<int, StlAllocator<int>> vec;
58+
EXPECT_EQ(vec.capacity(), 0);
59+
vec.reserve(1);
60+
EXPECT_EQ(vec.capacity(), 1);
61+
vec.reserve(2);
62+
EXPECT_EQ(vec.capacity(), 2);
63+
vec.get_allocator().print();
64+
}

0 commit comments

Comments
 (0)