23 virtual void do_allocate(
void* ptr_to_array_of_resources,
size_t size) = 0;
24 virtual void do_free(
void const* ptr_to_array_of_resources,
size_t size) = 0;
27 template<
typename ResourceType,
size_t size>
28 [[gnu::always_inline]]
void allocate(std::array<ResourceType, size>& resources_out)
30 do_allocate(resources_out.data(), resources_out.size());
33 template<
typename ResourceType>
34 [[gnu::always_inline]]
void allocate(std::vector<ResourceType>& resources_out)
36 do_allocate(resources_out.data(), resources_out.size());
39 template<
typename ResourceType,
size_t size>
40 [[gnu::always_inline]]
void free(std::array<ResourceType, size>
const& resources)
42 do_free(resources.data(), resources.size());
45 template<
typename ResourceType>
46 [[gnu::always_inline]]
void free(std::vector<ResourceType>
const& resources)
48 do_free(resources.data(), resources.size());
53concept ConceptResourceFactory = std::is_base_of_v<ResourceFactory, T> && std::is_constructible_v<typename T::resource_type>;
57template<ConceptResourceFactory RF>
61 using resource_factory_type = RF;
62 using resource_type =
typename resource_factory_type::resource_type;
63 using free_list_type = std::deque<resource_type, utils::DequeAllocator<resource_type>>;
68 int m_number_of_needed_resources;
72 m_task(task), m_number_of_needed_resources(number_of_needed_resources), m_condition(condition) { }
74 using event_requests_container_type = std::vector<EventRequest>;
75 using event_requests_type = aithreadsafe::Wrapper<event_requests_container_type, aithreadsafe::policy::Primitive<std::mutex>>;
78 size_t m_max_allocations;
81 resource_factory_type m_factory;
82 typename free_list_type::allocator_type& m_allocator_ref;
83 free_list_type m_free_list;
84 event_requests_type m_event_requests;
90 template<
typename T,
typename... Args>
91 ResourcePool(
size_t max_allocations, utils::DequeAllocator<T>& allocator, Args
const&... factory_args) :
92 m_max_allocations(max_allocations), m_allocations(0), m_acquires(0), m_factory(factory_args...), m_allocator_ref(allocator), m_free_list(allocator)
94 static_assert(
sizeof(T) ==
sizeof(resource_type),
"The allocation passed must allocate chunks of the right size.");
98 resource_factory_type
const& factory()
const {
return m_factory; }
102 [[nodiscard]]
size_t acquire(resource_type* resources,
size_t const size);
105 void release(resource_type
const* resources,
size_t size);
107 template<
size_t size>
108 [[nodiscard, gnu::always_inline]]
size_t acquire(std::array<resource_type, size>& resources_out)
110 return acquire(resources_out.data(), resources_out.size());
113 [[nodiscard, gnu::always_inline]]
size_t acquire(std::vector<resource_type>& resources_out)
115 return acquire(resources_out.data(), resources_out.size());
118 template<
size_t size>
119 [[gnu::always_inline]]
void release(std::array<resource_type, size>
const& resources)
121 release(resources.data(), resources.size());
124 [[gnu::always_inline]]
void release(std::vector<resource_type>
const& resources)
126 release(resources.data(), resources.size());
139template<ConceptResourceFactory RF>
140size_t ResourcePool<RF>::acquire(resource_type* resources,
size_t const size)
142 DoutEntering(dc::notice|continued_cf,
"ResourcePool<" << type_info_of<RF>().demangled_name() <<
">::acquire(resources (" << resources <<
"), " << size <<
") = ");
144 size_t const in_pool = m_free_list.size();
150 auto resource = m_free_list.begin();
152 while (index < std::min(in_pool, size))
154 Dout(dc::notice,
"resources[" << index <<
"] = " << *resource <<
" (from m_free_list)");
155 resources[index++] = *resource++;
158 m_free_list.erase(m_free_list.begin(), resource);
166 size_t to_allocate = std::min(size - index, std::max(m_max_allocations, m_allocations) - m_allocations);
169 m_factory.do_allocate(&resources[index], to_allocate);
171 for (
int j = 0; j < to_allocate; ++j)
172 Dout(dc::notice,
"resources[" << (index + j) <<
"] = " << resources[index + j] <<
" (from m_factory)");
174 index += to_allocate;
175 m_allocations += to_allocate;
179 Dout(dc::finish, index);
183template<ConceptResourceFactory RF>
184void ResourcePool<RF>::release(resource_type
const* resources,
size_t size)
186 DoutEntering(dc::notice,
"ResourcePool<" << type_info_of<RF>().demangled_name() <<
">::release(resources (" << resources <<
"), " << size <<
")");
188 if (AI_UNLIKELY(m_allocations > m_max_allocations))
191 size_t to_free = std::min(size, m_allocations - m_max_allocations);
195 for (
int j = 0; j < to_free; ++j)
196 Dout(dc::notice, resources[j] <<
" is returned to m_factory.");
198 m_factory.do_free(resources, to_free);
200 m_allocations -= to_free;
202 resources += to_free;
208 Dout(dc::notice, resources[index] <<
" put back on m_free_list.");
209 m_free_list.push_back(resources[index++]);
212 std::vector<EventRequest> must_be_notified;
214 typename event_requests_type::wat event_requests_w(m_event_requests);
215 if (AI_LIKELY(event_requests_w->empty()))
217 size_t available_resources = m_max_allocations - m_allocations + m_free_list.size();
219 typename event_requests_container_type::iterator event_request = event_requests_w->begin();
220 while (event_request != event_requests_w->end())
222 if (event_request->m_number_of_needed_resources > available_resources)
224 must_be_notified.push_back(*event_request);
225 available_resources -= event_request->m_number_of_needed_resources;
229 event_requests_w->erase(event_requests_w->begin(), event_request);
232 for (
auto const& event_request : must_be_notified)
233 event_request.m_task->signal(event_request.m_condition);
236template<ConceptResourceFactory RF>
239 typename event_requests_type::wat event_requests_w(m_event_requests);
240 typename event_requests_container_type::iterator iter = event_requests_w->begin();
242 while (iter != event_requests_w->end())
243 if (iter->m_task == task)
245 if (AI_UNLIKELY(n > iter->m_number_of_needed_resources))
246 iter->m_number_of_needed_resources = n;
249 event_requests_w->emplace_back(task, n, condition);
Declaration of base class AIStatefulTask.
Definition: AIStatefulTask.h:96
uint32_t condition_type
The type of the skip_wait and idle bit masks.
Definition: AIStatefulTask.h:99
Definition: ResourcePool.h:20
Definition: ResourcePool.h:59
Tasks defined by the library project are put into this namespace.
Definition: AIStatefulTask.h:857
Definition: ResourcePool.h:66