#pragma once
#include <concepts>
namespace zstd {
	template<std::move_constructible T>
	class pool {
		using NewFn = std::function<T()>;
	protected:
		int m_tail;
		int m_head;
		int m_size;
		T* m_buf;
		NewFn newT;
	public:
		~pool() {
			reset();
			free(m_buf);
		}
		pool(NewFn newT, int size = 1) : newT(newT), m_tail(0), m_head(0), m_buf((T*)malloc(sizeof(T)* size)), m_size(size) {}
		int head() {
			return m_head;
		}
		int tail() {
			return m_tail;
		}
		int count() {
			return m_head - m_tail;
		}
		void reset() {
			for (int i = m_tail; i < m_head; i++) {
				std::destroy_at(m_buf + (m_tail % m_size));
			}
			m_tail = 0;
			m_head = 0;
		}
		template<typename... Args>
		void release(Args... args) {
			if (m_head >= m_tail + m_size) {
				return;
			}
			std::construct_at(m_buf + m_head % m_size, std::forward<Args>(args)...);
			m_head++;
		};
		T acquire() {
			if (m_tail == m_head) {
				return newT();
			}
			int tail = m_tail % m_size;
			m_tail++;
			return std::move(*(m_buf + tail));
		};
	};
}