<commit_before>/*
 *	author: <NAME> <<EMAIL>>
 *
 *	Use of this source code is governed by the MIT license that can be
 *	found in the LICENSE file.
 */

#include "muggle/cpp/memory_pool/thread_safe_memory_pool.h"
#include <malloc.h>
#include <exception>
#include <new>

NS_MUGGLE_BEGIN

ThreadSafeMemoryPool::ThreadSafeMemoryPool(unsigned int init_capacity, unsigned int block_size)
	: data_bufs_(nullptr)
	, ptr_buf_(nullptr)
	, alloc_index_(0)
	, free_index_(0)
	, used_(0)
	, capacity_(0)
	, block_size_(0)
#if MUGGLE_DEBUG
	, peak_(0)
#endif
{
	data_bufs_ = (void*)malloc(block_size * init_capacity);
	if (data_bufs_ == nullptr)
	{
		throw std::bad_alloc();
	}

	ptr_buf_ = (void**)malloc(sizeof(void*) * init_capacity);
	if (ptr_buf_ == nullptr)
	{
		throw std::bad_alloc();
	}

	capacity_ = init_capacity == 0 ? 8 : init_capacity;
	block_size_ = block_size;

	for (unsigned int i = 0; i < init_capacity; ++i)
	{
		ptr_buf_[i] = ((char*)data_bufs_) + i * block_size_;
	}
}
ThreadSafeMemoryPool::~ThreadSafeMemoryPool()
{
	free(data_bufs_);
	free(ptr_buf_);
}

void* ThreadSafeMemoryPool::alloc()
{
	unsigned int used = used_.fetch_add(1);
	if (used >= capacity_)
	{
		used_.fetch_sub(1);
		return nullptr;
	}

#if MUGGLE_DEBUG
	if (used_ > peak_)
	{
		peak_ = used_;
	}
#endif

	unsigned int pos = alloc_index_.load();
	unsigned int next_pos = pos + 1;
	while (next_pos >= capacity_)
	{
		next_pos -= capacity_;
	}

	while (!alloc_index_.compare_exchange_weak(pos, next_pos))
	{
		pos = alloc_index_.load();
		unsigned int next_pos = pos + 1;
		while (next_pos >= capacity_)
		{
			next_pos -= capacity_;
		}
	}

	return ptr_buf_[pos];
}
void ThreadSafeMemoryPool::recycle(void *p)
{
	unsigned int pos = free_index_.load();
	unsigned int next_pos = pos + 1;
	while (next_pos >= capacity_)
	{
		next_pos -= capacity_;
	}

	while (!free_index_.compare_exchange_weak(pos, next_pos))
	{
		unsigned int pos = free_index_.load();
		unsigned int next_pos = pos + 1;
		while (next_pos >= capacity_)
		{
			next_pos -= capacity_;
		}
	}

	ptr_buf_[pos] = p;

	used_.fetch_sub(1);
}

unsigned int ThreadSafeMemoryPool::capacity()
{
	return capacity_;
}
unsigned int ThreadSafeMemoryPool::blockSize()
{
	return block_size_;
}
unsigned int ThreadSafeMemoryPool::inUsedNum()
{
	return used_.load();
}

NS_MUGGLE_END<commit_msg>update thread safe pool alloc and recycle method<commit_after>/*
 *	author: <NAME> <<EMAIL>>
 *
 *	Use of this source code is governed by the MIT license that can be
 *	found in the LICENSE file.
 */

#include "muggle/cpp/memory_pool/thread_safe_memory_pool.h"
#include <malloc.h>
#include <exception>
#include <new>

NS_MUGGLE_BEGIN

ThreadSafeMemoryPool::ThreadSafeMemoryPool(unsigned int init_capacity, unsigned int block_size)
	: data_bufs_(nullptr)
	, ptr_buf_(nullptr)
	, alloc_index_(0)
	, free_index_(0)
	, used_(0)
	, capacity_(0)
	, block_size_(0)
#if MUGGLE_DEBUG
	, peak_(0)
#endif
{
	data_bufs_ = (void*)malloc(block_size * init_capacity);
	if (data_bufs_ == nullptr)
	{
		throw std::bad_alloc();
	}

	ptr_buf_ = (void**)malloc(sizeof(void*) * init_capacity);
	if (ptr_buf_ == nullptr)
	{
		throw std::bad_alloc();
	}

	capacity_ = init_capacity == 0 ? 8 : init_capacity;
	block_size_ = block_size;

	for (unsigned int i = 0; i < init_capacity; ++i)
	{
		ptr_buf_[i] = ((char*)data_bufs_) + i * block_size_;
	}
}
ThreadSafeMemoryPool::~ThreadSafeMemoryPool()
{
	free(data_bufs_);
	free(ptr_buf_);
}

void* ThreadSafeMemoryPool::alloc()
{
	unsigned int used = used_.fetch_add(1);
	if (used >= capacity_)
	{
		used_.fetch_sub(1);
		return nullptr;
	}

#if MUGGLE_DEBUG
	if (used_ > peak_)
	{
		peak_ = used_;
	}
#endif

	/*
	unsigned int pos = alloc_index_.load();
	unsigned int next_pos = pos + 1;
	while (next_pos >= capacity_)
	{
		next_pos -= capacity_;
	}

	while (!alloc_index_.compare_exchange_weak(pos, next_pos))
	{
		pos = alloc_index_.load();
		unsigned int next_pos = pos + 1;
		while (next_pos >= capacity_)
		{
			next_pos -= capacity_;
		}
	}
	*/

	// if this step is first step cause alloc_index_ > capacity, then have 
	// responsible for setting alloc_index_ to correct position, so I can 
	// keep only one thread need to loop and fix position
	unsigned int pos = alloc_index_.fetch_add(1);
	if (pos == capacity_)
	{
		unsigned int tmp = alloc_index_.load();
		unsigned int correct_pos = tmp % capacity_;
		while (!alloc_index_.compare_exchange_weak(tmp, correct_pos))
		{
			correct_pos = tmp % capacity_;
		}
	}
	if (pos >= capacity_)
	{
		pos %= capacity_;
	}

	return ptr_buf_[pos];
}
void ThreadSafeMemoryPool::recycle(void *p)
{
	/*
	unsigned int pos = free_index_.load();
	unsigned int next_pos = pos + 1;
	while (next_pos >= capacity_)
	{
		next_pos -= capacity_;
	}

	while (!free_index_.compare_exchange_weak(pos, next_pos))
	{
		unsigned int pos = free_index_.load();
		unsigned int next_pos = pos + 1;
		while (next_pos >= capacity_)
		{
			next_pos -= capacity_;
		}
	}
	*/

	unsigned int pos = free_index_.fetch_add(1);
	if (pos == capacity_)
	{
		unsigned int tmp = free_index_.load();
		unsigned int correct_pos = tmp % capacity_;
		while (!free_index_.compare_exchange_weak(tmp, correct_pos))
		{
			correct_pos = tmp % capacity_;
		}
	}
	if (pos >= capacity_)
	{
		pos %= capacity_;
	}

	ptr_buf_[pos] = p;

	used_.fetch_sub(1);
}

unsigned int ThreadSafeMemoryPool::capacity()
{
	return capacity_;
}
unsigned int ThreadSafeMemoryPool::blockSize()
{
	return block_size_;
}
unsigned int ThreadSafeMemoryPool::inUsedNum()
{
	return used_.load();
}

NS_MUGGLE_END
{'fraction_non_alphanumeric': 0.13078871201157743, 'fraction_numerical': 0.006150506512301013, 'mean_word_length': 4.336872586872587, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 30, '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': '7583601', 'n_tokens_mistral': 2148, 'n_tokens_neox': 2039, 'n_words': 473}