Skip to content

Commit afaae7a

Browse files
committed
tlsf: migrate to nova::parameter
1 parent 8f615ae commit afaae7a

3 files changed

Lines changed: 63 additions & 193 deletions

File tree

CMakeLists.txt

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,16 @@ if (PROJECT_IS_TOP_LEVEL AND NOT CMAKE_MSVC_DEBUG_INFORMATION_FORMAT)
1111
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "Embedded")
1212
endif()
1313

14-
add_custom_target(nova_memoryresource_project_files SOURCES
15-
.clang-tidy
16-
.pre-commit-config.yaml
17-
_clang-format
18-
README.md
19-
LICENSE
20-
.github/workflows/ci.yml
21-
)
14+
if(PROJECT_IS_TOP_LEVEL)
15+
add_custom_target(nova_memoryresource_project_files SOURCES
16+
.clang-tidy
17+
.pre-commit-config.yaml
18+
_clang-format
19+
README.md
20+
LICENSE
21+
.github/workflows/ci.yml
22+
)
23+
endif()
2224

2325
function(nova_mr_install_pmr)
2426
if (NOT COMMAND CPMAddPackage)
@@ -79,9 +81,19 @@ if (NOVA_MR_TLSF AND NOT TARGET tlsf)
7981
endif()
8082
endif()
8183

82-
# Project layout
84+
if (NOT TARGET nova::parameter)
85+
nova_mr_install_pmr()
86+
87+
CPMAddPackage(
88+
NAME nova_parameter
89+
GITHUB_REPOSITORY timblechmann/nova_parameter
90+
GIT_TAG 82a89446de72d2bec8dff295f8156f6f57b2a99c
91+
)
92+
endif()
93+
8394
add_library(nova_memoryresource INTERFACE)
8495
add_library(nova::memoryresource ALIAS nova_memoryresource)
96+
target_link_libraries(nova_memoryresource INTERFACE nova::parameter)
8597

8698
target_sources(nova_memoryresource PUBLIC FILE_SET HEADERS BASE_DIRS include)
8799

include/nova/pmr/tlsf_memory_resource.hpp

Lines changed: 42 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
#include <memory>
1111
#include <memory_resource>
1212
#include <mutex>
13-
#include <optional>
1413
#include <span>
1514
#include <tlsf.h>
1615

16+
#include <nova/parameter/parameter.hpp>
1717
#include <nova/pmr/detail/memlock.hpp>
1818

1919
#ifdef NOVA_MR_HAS_TLSF
@@ -24,21 +24,26 @@ namespace nova::pmr {
2424
//
2525
// policies
2626

27+
namespace detail {
28+
struct static_size_tag
29+
{};
30+
struct lock_memory_tag
31+
{};
32+
struct use_mutex_tag
33+
{};
34+
35+
using tlsf_allowed_tags = std::tuple< static_size_tag, lock_memory_tag, use_mutex_tag >;
36+
} // namespace detail
37+
2738
/// @brief Policy tag: statically sized memory pool embedded in the object.
2839
/// @tparam Size The size of the pool in bytes.
2940
template < std::size_t Size >
30-
struct static_size
31-
{
32-
static constexpr std::size_t size = Size;
33-
};
41+
using static_size = parameter::size_param< struct detail::static_size_tag, Size >;
3442

3543
/// @brief Policy tag: enable thread-safe locking with the given mutex type.
3644
/// @tparam MutexType The mutex type to use; defaults to `std::mutex`.
3745
template < typename MutexType = std::mutex >
38-
struct use_mutex
39-
{
40-
using mutex_type = MutexType;
41-
};
46+
using use_mutex = parameter::type_param< struct detail::use_mutex_tag, MutexType >;
4247

4348
/// @brief Policy tag: lock the pool buffer into physical memory (`mlock`/`VirtualLock`),
4449
/// preventing it from being swapped out by the OS.
@@ -52,8 +57,7 @@ struct use_mutex
5257
/// nova::pmr::lock_memory > mr;
5358
/// assert( mr.is_memory_locked() ); // Usually true (unless OS refused lock)
5459
/// ```
55-
struct lock_memory
56-
{};
60+
using lock_memory = parameter::flag_param< struct detail::lock_memory_tag >;
5761

5862
/// @brief Tag type for runtime memory locking via constructor argument.
5963
///
@@ -73,57 +77,14 @@ inline constexpr enable_memory_locking_t enable_memory_locking {};
7377

7478
namespace detail {
7579

76-
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
77-
// storage
7880

79-
template < typename T >
80-
struct is_static_size : std::false_type
81-
{};
82-
83-
template < size_t Size >
84-
struct is_static_size< static_size< Size > > : std::true_type
85-
{};
86-
87-
template < typename... Policies >
88-
constexpr bool has_static_size()
89-
{
90-
constexpr auto accumulation = ( int( is_static_size< Policies >::value ) + ... + 0 );
91-
switch ( accumulation ) {
92-
case 0: return false;
93-
case 1: return true;
94-
default: static_assert( accumulation <= 1, "Multiple static_size policies provided" ); return false;
95-
}
96-
}
97-
98-
template < typename Policy, typename... Policies >
99-
constexpr std::optional< size_t > get_static_size()
100-
{
101-
if constexpr ( is_static_size< Policy >::value )
102-
return Policy::size;
103-
else if constexpr ( sizeof...( Policies ) > 0 )
104-
return get_static_size< Policies... >();
105-
else
106-
return std::nullopt;
107-
}
108-
109-
} // namespace detail
110-
111-
namespace detail {
112-
113-
template < typename Tag >
114-
struct tlsf_storage;
115-
116-
struct dynamic_pool_tag
117-
{};
118-
119-
template <>
120-
struct tlsf_storage< dynamic_pool_tag >
81+
struct tlsf_heap_storage
12182
{
12283
std::unique_ptr< std::byte[] > buffer;
12384
std::size_t size_;
12485
bool memory_locked {};
12586

126-
explicit tlsf_storage( std::size_t size, bool lock_memory = false ) :
87+
explicit tlsf_heap_storage( std::size_t size, bool lock_memory = false ) :
12788
buffer( new std::byte[ size ] ),
12889
size_( size )
12990
{
@@ -132,7 +93,7 @@ struct tlsf_storage< dynamic_pool_tag >
13293
std::ranges::fill( bytes(), std::byte {} );
13394
}
13495

135-
~tlsf_storage()
96+
~tlsf_heap_storage()
13697
{
13798
if ( memory_locked )
13899
unlock_memory( bytes() );
@@ -156,19 +117,23 @@ struct tlsf_storage< dynamic_pool_tag >
156117
};
157118

158119
template < std::size_t Size >
159-
struct tlsf_storage< static_size< Size > >
120+
struct tlsf_sized_storage
160121
{
122+
static_assert( Size > 1024,
123+
"TLSF pool size must be large enough to hold internal structures; 1 KB is a reasonable lower "
124+
"bound." );
125+
161126
std::array< std::byte, Size > buffer;
162127
bool memory_locked = false;
163128

164-
explicit tlsf_storage( bool lock_memory = false )
129+
explicit tlsf_sized_storage( bool lock_memory = false )
165130
{
166131
memory_locked = lock_memory ? try_lock_memory( bytes() ) : false;
167132
if ( memory_locked )
168133
std::ranges::fill( bytes(), std::byte {} );
169134
}
170135

171-
~tlsf_storage()
136+
~tlsf_sized_storage()
172137
{
173138
if ( memory_locked )
174139
unlock_memory( bytes() );
@@ -190,23 +155,6 @@ struct tlsf_storage< static_size< Size > >
190155
}
191156
};
192157

193-
template < typename... Policies >
194-
struct select_storage
195-
{
196-
static constexpr bool static_sized = has_static_size< Policies... >();
197-
198-
static constexpr std::size_t safe_size = [] {
199-
if constexpr ( static_sized )
200-
return get_static_size< Policies... >().value();
201-
else
202-
return std::size_t { 0 };
203-
}();
204-
205-
using type = std::conditional_t< static_sized,
206-
tlsf_storage< nova::pmr::static_size< safe_size > >,
207-
tlsf_storage< dynamic_pool_tag > >;
208-
};
209-
210158
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
211159
// locking
212160

@@ -222,74 +170,6 @@ struct dummy_mutex
222170
}
223171
};
224172

225-
template < typename T >
226-
struct is_use_mutex : std::false_type
227-
{};
228-
229-
template < typename MutexType >
230-
struct is_use_mutex< nova::pmr::use_mutex< MutexType > > : std::true_type
231-
{};
232-
233-
template < typename... Policies >
234-
constexpr bool has_use_mutex()
235-
{
236-
constexpr auto accumulation = ( int( is_use_mutex< Policies >::value ) + ... + 0 );
237-
switch ( accumulation ) {
238-
case 0: return false;
239-
case 1: return true;
240-
default: static_assert( accumulation <= 1, "Multiple use_mutex policies provided" ); return false;
241-
}
242-
}
243-
244-
245-
template < typename Policy >
246-
struct extract_mutex_type
247-
{
248-
using type = dummy_mutex;
249-
};
250-
251-
template < typename MutexType >
252-
struct extract_mutex_type< nova::pmr::use_mutex< MutexType > >
253-
{
254-
using type = MutexType;
255-
};
256-
257-
template < typename... Policies >
258-
struct get_mutex_type
259-
{
260-
using type = dummy_mutex;
261-
};
262-
263-
template < typename Policy, typename... Rest >
264-
struct get_mutex_type< Policy, Rest... >
265-
{
266-
using type = std::conditional_t< is_use_mutex< Policy >::value,
267-
typename extract_mutex_type< Policy >::type,
268-
typename get_mutex_type< Rest... >::type >;
269-
};
270-
271-
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
272-
// memory locking
273-
274-
template < typename T >
275-
struct is_enable_memory_locking : std::false_type
276-
{};
277-
278-
template <>
279-
struct is_enable_memory_locking< nova::pmr::lock_memory > : std::true_type
280-
{};
281-
282-
template < typename... Policies >
283-
constexpr bool has_enable_memory_locking()
284-
{
285-
constexpr auto accumulation = ( int( is_enable_memory_locking< Policies >::value ) + ... + 0 );
286-
switch ( accumulation ) {
287-
case 0: return false;
288-
case 1: return true;
289-
default: static_assert( accumulation <= 1, "Multiple lock_memory policies provided" ); return false;
290-
}
291-
}
292-
293173
} // namespace detail
294174

295175
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -334,16 +214,19 @@ constexpr bool has_enable_memory_locking()
334214
/// nova::pmr::tlsf_memory_resource< nova::pmr::static_size< 65536 > > mr( nova::pmr::enable_memory_locking );
335215
/// ```
336216
template < typename... Policies >
217+
requires( parameter::valid_parameters< detail::tlsf_allowed_tags, Policies... > )
337218
class tlsf_memory_resource final : public std::pmr::memory_resource
338219
{
339-
using storage_selector = detail::select_storage< Policies... >;
340-
static constexpr bool static_sized = storage_selector::static_sized;
341-
using storage_type = typename storage_selector::type;
220+
static constexpr bool static_sized = parameter::has_parameter_v< detail::static_size_tag, Policies... >;
221+
static constexpr bool compile_time_locking = parameter::has_parameter_v< detail::lock_memory_tag, Policies... >;
342222

343-
static constexpr bool compile_time_locking = detail::has_enable_memory_locking< Policies... >();
223+
using storage_type = std::conditional_t<
224+
static_sized,
225+
detail::tlsf_sized_storage< parameter::extract_integral_v< detail::static_size_tag, std::size_t, 0, Policies... > >,
226+
detail::tlsf_heap_storage >;
344227

345228
public:
346-
using mutex_type = typename detail::get_mutex_type< Policies... >::type;
229+
using mutex_type = parameter::extract_t< detail::use_mutex_tag, detail::dummy_mutex, Policies... >;
347230

348231
private:
349232
alignas( alignof( std::max_align_t ) ) storage_type storage_;
@@ -355,26 +238,26 @@ class tlsf_memory_resource final : public std::pmr::memory_resource
355238
public:
356239
/// @brief Construct a dynamically-sized pool of \p size bytes.
357240
/// Only available when no `static_size` policy is present.
358-
template < typename T = std::bool_constant< static_sized > >
359-
requires std::same_as< T, std::false_type >
360-
explicit tlsf_memory_resource( std::size_t size ) :
241+
explicit tlsf_memory_resource( std::size_t size )
242+
requires( !static_sized )
243+
:
361244
storage_( size, compile_time_locking )
362245
{}
363246

364247
/// @brief Construct a dynamically-sized pool of \p size bytes and lock it into physical memory.
365248
/// Only available when no `static_size` policy and no compile-time
366249
/// `lock_memory` policy are present — use one or the other, not both.
367-
template < typename T = std::bool_constant< static_sized || compile_time_locking > >
368-
requires std::same_as< T, std::false_type >
369-
tlsf_memory_resource( std::size_t size, enable_memory_locking_t ) :
250+
tlsf_memory_resource( std::size_t size, enable_memory_locking_t )
251+
requires( !static_sized && !compile_time_locking )
252+
:
370253
storage_( size, true )
371254
{}
372255

373256
/// @brief Default-construct using the embedded static pool.
374257
/// Only available when a `static_size` policy is present.
375-
template < typename T = std::bool_constant< !static_sized > >
376-
requires std::same_as< T, std::false_type >
377-
tlsf_memory_resource() :
258+
tlsf_memory_resource()
259+
requires( static_sized )
260+
:
378261
storage_( false )
379262
{}
380263

tests/test_memory_resource.cpp

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,31 +13,6 @@
1313

1414
#include <cstdint>
1515

16-
TEST_CASE( "policies" )
17-
{
18-
static_assert( nova::pmr::detail::has_static_size< nova::pmr::static_size< 1024 > >() );
19-
static_assert( !nova::pmr::detail::has_static_size< int >() );
20-
21-
static_assert( !nova::pmr::detail::has_use_mutex< nova::pmr::static_size< 1024 > >() );
22-
static_assert( nova::pmr::detail::has_use_mutex< nova::pmr::use_mutex<> >() );
23-
24-
static_assert( std::is_same< nova::pmr::detail::get_mutex_type< nova::pmr::use_mutex<> >::type, std::mutex >::value );
25-
static_assert( std::is_same< nova::pmr::detail::get_mutex_type<>::type, nova::pmr::detail::dummy_mutex >::value );
26-
27-
static_assert( !nova::pmr::detail::has_enable_memory_locking< nova::pmr::static_size< 1024 > >() );
28-
static_assert( !nova::pmr::detail::has_enable_memory_locking< nova::pmr::use_mutex<> >() );
29-
static_assert( nova::pmr::detail::has_enable_memory_locking< nova::pmr::lock_memory >() );
30-
static_assert(
31-
nova::pmr::detail::has_enable_memory_locking< nova::pmr::static_size< 1024 >, nova::pmr::lock_memory >() );
32-
33-
#if 0 // multiple keyword arguments should statically assert
34-
nova::pmr::detail::has_static_size< nova::pmr::static_size< 512 >, nova::pmr::static_size< 1022 > >();
35-
nova::pmr::detail::has_use_mutex< nova::pmr::use_mutex<>, nova::pmr::use_mutex<> >();
36-
nova::pmr::detail::has_enable_memory_locking< nova::pmr::lock_memory, nova::pmr::lock_memory >();
37-
#endif
38-
}
39-
40-
4116
TEST_CASE( "memory resource instantiation" )
4217
{
4318
#ifdef NOVA_MR_HAS_TLSF

0 commit comments

Comments
 (0)