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