#pragma once
#include <atomic>
#include <memory>
#include "concurrentqueue/concurrentqueue.h"
#include "logger.h"
namespace flower {
template <typename T>
class object_pool {
using object_ptr = std::shared_ptr<T>;
public:
object_pool() = default;
virtual ~object_pool() = default;
template <typename... Args>
void start(uint32_t init_count, uint32_t max_count, Args&&... args) {
max_count_ = max_count;
object_ptr object;
for (uint32_t i = 0; i < init_count; ++i) {
object = create(std::forward<Args>(args)...);
if (!object) {
LOG_ERROR("object_pool::start object is nullptr");
return;
}
if (queue_.enqueue(object)) {
++cur_count_;
}
}
}
void stop() {
max_count_ = 0;
object_ptr object;
while (queue_.try_dequeue(object)) {
--cur_count_;
}
}
template <typename... Args>
object_ptr pop(Args&&... args) {
object_ptr object;
if (!queue_.try_dequeue(object)) {
object = create(std::forward<Args>(args)...);
if (!object) {
LOG_ERROR("object_pool::pop object is nullptr");
return object;
}
return object;
}
--cur_count_;
return object;
}
private:
template <typename... Args>
object_ptr create(Args&&... args) {
return {new T(std::forward<Args>(args)...), [this](T* object) {
recovery(object);
}};
}
void recovery(T* object) {
if (cur_count_ < max_count_) {
object->reset();
if (queue_.enqueue({object, [this](T* object) {
recovery(object);
}})) {
++cur_count_;
return;
}
}
object->~T();
}
private:
moodycamel::ConcurrentQueue<object_ptr> queue_{};
std::atomic_uint32_t max_count_{};
std::atomic_uint32_t cur_count_{};
};
} // namespace flower