<commit_before>#include"../header/CThreadPool.hpp"
#include<memory>	//make_unique
#include<mutex>
#include<vector>
#include<unordered_map>
#include"../../lib/header/thread/CThread_forward_list.hpp"
#include"../../lib/header/thread/CThreadRingBuf.hpp"
#include"../header/CThreadPoolCommun.hpp"
#include"../header/CThreadPoolItem.hpp"
#include"../header/IThreadPoolItemExecutor.hpp"
using namespace std;

namespace nThread
{
	struct CThreadPool::Impl
	{
		unordered_map<thread_id,bool> is_joinable;
		mutex join_all_mut;	//only for join_all
		CThread_forward_list<CThreadPoolItem*> join_anyList;
		mutex wait_until_all_available_mut;	//only for wait_until_all_available
		CThreadRingBuf<CThreadPoolItem*> waiting_buf;
		unordered_map<thread_id,CThreadPoolItem> thr;
		Impl(CThreadPool::size_type);
		thread_id add(function<void()> &&);
		void add_and_detach(function<void()> &&);
		inline void join(const thread_id id)
		{
			thr[id].wait();
		}
		void join_all();
		bool joinable(thread_id) const noexcept;
		void wait_until_all_available();
	};

	CThreadPool::Impl::Impl(CThreadPool::size_type size)
		:is_joinable{size},waiting_buf{size},thr{size}
	{
		while(size--)
		{
			//because the key_type of thr is thread_id, and thread_id is returned by CThreadPoolItem
			//so, you have to create a CThreadPoolItem first, and emplace get_id to thr
			CThreadPoolItem item;
			const auto id{item.get_id()};
			//it means "not joinable"
			is_joinable.emplace(id,false);
			//thr.emplace(item.get_id(),move(item)); is wrong
			//you cannot guarantee item.get_id() will execute prior to move(item)
			waiting_buf.write(&thr.emplace(id,move(item)).first->second);
		}
	}

	CThreadPool::thread_id CThreadPool::Impl::add(function<void()> &&func)
	{
		auto temp{waiting_buf.read()};
		is_joinable[temp->get_id()]=true;
		temp->assign(make_unique<CThreadPoolItemExecutorJoin>(CThreadPoolCommunJoin{temp,&join_anyList,&waiting_buf},move(func)));
		return temp->get_id();
	}

	void CThreadPool::Impl::add_and_detach(function<void()> &&func)
	{
		auto temp{waiting_buf.read()};
		is_joinable[temp->get_id()]=false;
		temp->assign(make_unique<CThreadPoolItemExecutorDetach>(CThreadPoolCommunDetach{temp,&waiting_buf},move(func)));
	}
<commit_msg>fix exception safety<commit_after>#include"../header/CThreadPool.hpp"
#include<memory>	//make_unique
#include<mutex>
#include<vector>
#include<unordered_map>
#include"../../lib/header/thread/CThread_forward_list.hpp"
#include"../../lib/header/thread/CThreadRingBuf.hpp"
#include"../header/CThreadPoolCommun.hpp"
#include"../header/CThreadPoolItem.hpp"
#include"../header/IThreadPoolItemExecutor.hpp"
using namespace std;

namespace nThread
{
	struct CThreadPool::Impl
	{
		unordered_map<thread_id,bool> is_joinable;
		mutex join_all_mut;	//only for join_all
		CThread_forward_list<CThreadPoolItem*> join_anyList;
		mutex wait_until_all_available_mut;	//only for wait_until_all_available
		CThreadRingBuf<CThreadPoolItem*> waiting_buf;
		unordered_map<thread_id,CThreadPoolItem> thr;
		Impl(CThreadPool::size_type);
		thread_id add(function<void()> &&);
		void add_and_detach(function<void()> &&);
		inline void join(const thread_id id)
		{
			thr[id].wait();
		}
		void join_all();
		bool joinable(thread_id) const noexcept;
		void wait_until_all_available();
	};

	CThreadPool::Impl::Impl(CThreadPool::size_type size)
		:is_joinable{size},waiting_buf{size},thr{size}
	{
		while(size--)
		{
			//because the key_type of thr is thread_id, and thread_id is returned by CThreadPoolItem
			//so, you have to create a CThreadPoolItem first, and emplace get_id to thr
			CThreadPoolItem item;
			const auto id{item.get_id()};
			//it means "not joinable"
			is_joinable.emplace(id,false);
			//thr.emplace(item.get_id(),move(item)); is wrong
			//you cannot guarantee item.get_id() will execute prior to move(item)
			waiting_buf.write(&thr.emplace(id,move(item)).first->second);
		}
	}

	CThreadPool::thread_id CThreadPool::Impl::add(function<void()> &&func)
	{
		auto temp{waiting_buf.read()};
		is_joinable[temp->get_id()]=true;
		try
		{
			temp->assign(make_unique<CThreadPoolItemExecutorJoin>(CThreadPoolCommunJoin{temp,&join_anyList,&waiting_buf},move(func)));
		}catch(...)
		{
			waiting_buf.write(temp);
			throw ;
		}
		return temp->get_id();
	}

	void CThreadPool::Impl::add_and_detach(function<void()> &&func)
	{
		auto temp{waiting_buf.read()};
		is_joinable[temp->get_id()]=false;
		try
		{
			temp->assign(make_unique<CThreadPoolItemExecutorDetach>(CThreadPoolCommunDetach{temp,&waiting_buf},move(func)));
		}catch(...)
		{
			waiting_buf.write(temp);
			throw ;
		}
	}

{'fraction_non_alphanumeric': 0.14666955955738772, 'fraction_numerical': 0.0, 'mean_word_length': 5.7299270072992705, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1833201', 'n_tokens_mistral': 1791, 'n_tokens_neox': 1662, 'n_words': 260}