@@ -26,133 +26,43 @@ namespace mem {
2626class  LIBIPC_EXPORT  block_collector {
2727public: 
2828  virtual  ~block_collector () noexcept  = default ;
29-   virtual  void  recycle (void  */*p*/) noexcept {} 
29+   virtual  void  *allocate (std::size_t  /* bytes*/ noexcept  = 0;
30+   virtual  void  deallocate (void  */*p*/, std::size_t /*bytes*/) noexcept = 0; 
3031};
3132
32- #if  defined(LIBIPC_CPP_17)
33- using  recycle_t  = void  (*)(void  *p, void  *o) noexcept ;
34- #else 
35- using  recycle_t  = void  (*)(void  *p, void  *o);
36- #endif 
37- 
38- static  constexpr  std::size_t  regular_head_size
39-     = round_up(sizeof (recycle_t ), alignof(std::max_align_t ));
40- 
41- // / \brief Select the incremental level based on the size.
42- constexpr  inline  std::size_t  regular_level (std::size_t  s) noexcept  {
43-   return  (s <= 128   ) ? 0  :
44-          (s <= 1024  ) ? 1  :
45-          (s <= 8192  ) ? 2  :
46-          (s <= 65536 ) ? 3  : 4 ;
47- }
33+ // / \brief Matches the appropriate memory block resource based on a specified size.
34+ LIBIPC_EXPORT block_collector &get_regular_resource (std::size_t  s) noexcept ;
4835
49- // / \brief Calculates the appropriate memory block size based on the increment level and size.
50- constexpr  inline  std::size_t  regular_sizeof_impl (std::size_t  l, std::size_t  s) noexcept  {
51-   return  (l == 0 ) ? round_up<std::size_t >(s, regular_head_size) :
52-          (l == 1 ) ? round_up<std::size_t >(s, 128  ) :
53-          (l == 2 ) ? round_up<std::size_t >(s, 1024 ) :
54-          (l == 3 ) ? round_up<std::size_t >(s, 8192 ) : (std::numeric_limits<std::size_t >::max)();
55- }
56- 
57- // / \brief Calculates the appropriate memory block size based on the size.
58- constexpr  inline  std::size_t  regular_sizeof_impl (std::size_t  s) noexcept  {
59-   return  regular_sizeof_impl (regular_level (s), s);
60- }
61- 
62- // / \brief Calculates the appropriate memory block size based on the specific type.
63- constexpr  inline  std::size_t  regular_sizeof (std::size_t  s) noexcept  {
64-   return  regular_sizeof_impl (regular_head_size + s);
65- }
66- template  <typename  T, std::size_t  S = sizeof (T)>
67- constexpr  inline  std::size_t  regular_sizeof () noexcept  {
68-   return  regular_sizeof (S);
69- }
36+ // / \brief Allocates storage with a size of at least bytes bytes.
37+ LIBIPC_EXPORT void  *alloc (std::size_t  bytes) noexcept ;
38+ LIBIPC_EXPORT void   free  (void  *p, std::size_t  bytes) noexcept ;
7039
71- // / \brief Use block pools to handle memory less than 64K.
72- template  <std::size_t  BlockSize, std::size_t  BlockPoolExpansion>
73- class  block_resource_base  : public  block_pool <BlockSize, BlockPoolExpansion> {
74- public: 
75-   void  *allocate (std::size_t  /* bytes*/ size_t  /* alignment*/ noexcept  {
76-     return  block_pool<BlockSize, BlockPoolExpansion>::allocate ();
77-   }
78- 
79-   void  deallocate (void  *p) noexcept  {
80-     block_pool<BlockSize, BlockPoolExpansion>::deallocate (p);
81-   }
82- };
83- 
84- // / \brief Use `new`/`delete` to handle memory larger than 64K.
85- template  <std::size_t  BlockSize>
86- class  block_resource_base <BlockSize, 0 > : public new_delete_resource {
87- public: 
88-   void  *allocate (std::size_t  bytes, std::size_t  alignment) noexcept  {
89-     return  new_delete_resource::allocate (regular_head_size + bytes, alignment);
90-   }
91- 
92-   void  deallocate (void  *p) noexcept  {
93-     new_delete_resource::deallocate (p, regular_head_size);
94-   }
95- };
96- 
97- // / \brief Defines block pool memory resource based on block pool.
98- template  <std::size_t  BlockSize, std::size_t  BlockPoolExpansion>
99- class  block_pool_resource  : public  block_resource_base <BlockSize, BlockPoolExpansion>
100-                           , public block_collector {
101- 
102-   using  base_t  = block_resource_base<BlockSize, BlockPoolExpansion>;
103- 
104-   void  recycle (void  *p) noexcept  override  {
105-     base_t::deallocate (p);
106-   }
107- 
108- public: 
109-   static  block_collector *get () noexcept  {
110-     thread_local  block_pool_resource instance;
111-     return  &instance;
112-   }
113- 
114-   template  <typename  T>
115-   void  *allocate (std::size_t  bytes, std::size_t  alignment = alignof (std::max_align_t )) noexcept  {
116-     void  *b = base_t::allocate (bytes, alignment);
117-     *static_cast <recycle_t  *>(b)
118-       = [](void  *b, void  *p) noexcept  {
119-           std::ignore = destroy (static_cast <T *>(p));
120-           get ()->recycle (b);
121-         };
122-     return  static_cast <byte *>(b) + regular_head_size;
123-   }
124- };
40+ namespace  detail_new  {
12541
126- // / \brief Different increment levels match different chunk sizes.
127- // /        512 means that 512 consecutive memory blocks are allocated at a time.
128- template  <std::size_t  L>
129- constexpr  std::size_t  block_pool_expansion = 0 ;
130- 
131- template  <> constexpr  std::size_t  block_pool_expansion<0 > = 512 ;
132- template  <> constexpr  std::size_t  block_pool_expansion<1 > = 256 ;
133- template  <> constexpr  std::size_t  block_pool_expansion<2 > = 128 ;
134- template  <> constexpr  std::size_t  block_pool_expansion<3 > = 64 ;
135- 
136- // / \brief Matches the appropriate memory block resource based on the specified type.
137- template  <typename  T, std::size_t  N = regular_sizeof<T>(), std::size_t  L = regular_level(N)>
138- auto  *get_regular_resource () noexcept  {
139-   using  block_poll_resource_t  = block_pool_resource<N, block_pool_expansion<L>>;
140-   return  dynamic_cast <block_poll_resource_t  *>(block_poll_resource_t::get ());
141- }
142- template  <typename  T, std::enable_if_t <std::is_void<T>::value, bool > = true >
143- auto  *get_regular_resource () noexcept  {
144-   using  block_poll_resource_t  = block_pool_resource<0 , 0 >;
145-   return  dynamic_cast <block_poll_resource_t  *>(block_poll_resource_t::get ());
146- }
42+ #if  defined(LIBIPC_CPP_17)
43+ using  recycle_t  = void  (*)(void  *p) noexcept ;
44+ #else 
45+ using  recycle_t  = void  (*)(void  *p);
46+ #endif 
14747
148- namespace  detail_new  {
48+ static  constexpr  std::size_t  recycler_size     = round_up(sizeof (recycle_t ), alignof (std::size_t ));
49+ static  constexpr  std::size_t  allocated_size    = sizeof (std::size_t );
50+ static  constexpr  std::size_t  regular_head_size = round_up(recycler_size + allocated_size, alignof (std::max_align_t ));
14951
15052template  <typename  T>
15153struct  do_allocate  {
152-   template  <typename  R, typename ... A>
153-   static  T *apply (R *res, A &&... args) noexcept  {
54+   template  <typename ... A>
55+   static  T *apply (A &&... args) noexcept  {
56+     void  *b = mem::alloc (regular_head_size + sizeof (T));
57+     auto  *p = static_cast <byte *>(b) + regular_head_size;
15458    LIBIPC_TRY {
155-       return  construct<T>(res->template  allocate <T>(sizeof (T), alignof (T)), std::forward<A>(args)...);
59+       T *t = construct<T>(p, std::forward<A>(args)...);
60+       *reinterpret_cast <recycle_t  *>(b)
61+         = [](void  *p) noexcept  {
62+             mem::free (static_cast <byte *>(destroy (static_cast <T *>(p))) - regular_head_size
63+                     , regular_head_size + sizeof (T));
64+           };
65+       return  t;
15666    } LIBIPC_CATCH (...) {
15767      return  nullptr ;
15868    }
@@ -161,10 +71,18 @@ struct do_allocate {
16171
16272template  <>
16373struct  do_allocate <void > {
164-   template  <typename  R>
165-   static  void  *apply (R *res, std::size_t  bytes) noexcept  {
74+   static  void  *apply (std::size_t  bytes) noexcept  {
16675    if  (bytes == 0 ) return  nullptr ;
167-     return  res->template  allocate <void >(bytes);
76+     std::size_t  rbz = regular_head_size + bytes;
77+     void  *b = mem::alloc (rbz);
78+     *reinterpret_cast <recycle_t  *>(b)
79+       = [](void  *p) noexcept  {
80+           auto  *b = static_cast <byte *>(p) - regular_head_size;
81+           mem::free (b, *reinterpret_cast <std::size_t  *>(b + recycler_size));
82+         };
83+     auto  *z = static_cast <byte *>(b) + recycler_size;
84+     *reinterpret_cast <std::size_t  *>(z) = rbz;
85+     return  static_cast <byte *>(b) + regular_head_size;
16886  }
16987};
17088
@@ -174,19 +92,16 @@ struct do_allocate<void> {
17492// / \note This function is thread-safe.
17593template  <typename  T, typename ... A>
17694T *$new (A &&... args) noexcept  {
177-   auto  *res = get_regular_resource<T>();
178-   if  (res == nullptr ) return  nullptr ;
179-   return  detail_new::do_allocate<T>::apply (res, std::forward<A>(args)...);
95+   return  detail_new::do_allocate<T>::apply (std::forward<A>(args)...);
18096}
18197
18298// / \brief Destroys object previously allocated by the `$new` and releases obtained memory area.
18399// / \note This function is thread-safe. If the pointer type passed in is different from `$new`, 
184100// /       additional performance penalties may be incurred.
185101inline  void  $delete (void  *p) noexcept  {
186102  if  (p == nullptr ) return ;
187-   auto  *b = reinterpret_cast <byte *>(p) - regular_head_size;
188-   auto  *r = reinterpret_cast <recycle_t  *>(b);
189-   (*r)(b, p);
103+   auto  *r = reinterpret_cast <detail_new::recycle_t  *>(static_cast <byte *>(p) - detail_new::regular_head_size);
104+   (*r)(p);
190105}
191106
192107// / \brief The destruction policy used by std::unique_ptr.
0 commit comments