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.
2940template < 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`.
3745template < 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
7478namespace 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
158119template < 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// / ```
336216template < typename ... Policies >
217+ requires ( parameter::valid_parameters< detail::tlsf_allowed_tags, Policies... > )
337218class 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
345228public:
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
348231private:
349232 alignas ( alignof ( std::max_align_t ) ) storage_type storage_;
@@ -355,26 +238,26 @@ class tlsf_memory_resource final : public std::pmr::memory_resource
355238public:
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
0 commit comments