#pragma once
#include <condition_variable>
#include <semaphore>
#include <concepts>
namespace zstd {
	template<size_t T>
	struct static_buffer {
		char data[T];
	};
	template<std::move_constructible T, size_t T_capacity = 1>
	class channel_static {
		static_assert(T_capacity != 0);
	protected:
		int m_tail;
		int m_head;
		static_buffer<sizeof(T)> m_buf[T_capacity];
		std::mutex m_mtx;
		std::condition_variable m_cv;
	public:
		~channel_static() {
			reset();
		}
		channel_static() : m_tail(0), m_head(0), m_buf() {}
		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((T*)(m_buf + m_tail % T_capacity));
			}
			m_tail = 0;
			m_head = 0;
		}
		template<typename... Args>
		void release(Args... args) {
			std::unique_lock<std::mutex> lck(m_mtx);
			while (m_head >= m_tail + T_capacity) {
				m_cv.wait(lck);
			}
			std::construct_at((T*)(m_buf + m_head % T_capacity), std::forward<Args>(args)...);
			if (m_head++ == m_tail)
				m_cv.notify_one();
		};
		T acquire() {
			std::unique_lock<std::mutex> lck(m_mtx);
			while (m_tail >= m_head) {
				m_cv.wait(lck);
			}
			int tail = m_tail % T_capacity;
			if (m_tail++ == m_head - T_capacity)
				m_cv.notify_one();
			return std::move(*(T*)(m_buf + tail));
		};
	};
}