<commit_before>#pragma once
#include <vector>
#include "augs/ensure.h"

#include "augs/build_settings/setting_empty_bases.h"

#include "augs/misc/pool_handle.h"
#include "augs/misc/subscript_operator_for_get_handle_mixin.h"

namespace augs {
	template<class T>
	class EMPTY_BASES pool : public subscript_operator_for_get_handle_mixin<pool<T>> {
	public:
		using id_type = pooled_object_id<T>;
		using unversioned_id_type = unversioned_id<T>;
		using handle_type = handle_for_pool_container<false, pool<T>, T>;
		using const_handle_type = handle_for_pool_container<true, pool<T>, T>;

		using pooled_container_type = std::vector<T>;

		using element_type = T;
	
	protected:
		struct metadata {
			std::size_t pointing_indirector = -1;
		};

		struct indirector {
			unsigned real_index = 0;
			unsigned version = 1;
		};

		pooled_container_type pooled;
		std::vector<metadata> slots;
		std::vector<indirector> indirectors;
		std::vector<std::size_t> free_indirectors;

	public:
		pool(const std::size_t slot_count = 0u) {
			reserve(slot_count);
		}

		/* right now that call overwrites of free_indirectors */
		void reserve(const std::size_t slot_count) {
			pooled.clear();
			indirectors.clear();
			slots.clear();
			free_indirectors.clear();

			pooled.reserve(slot_count);
			slots.reserve(slot_count);

			indirectors.resize(slot_count);

			free_indirectors.resize(slot_count);

			for (std::size_t i = 0; i < slot_count; ++i) {
				free_indirectors[i] = i;
			}
		}

		template <typename... Args>
		id_type allocate(Args&&... args) {
			if (free_indirectors.empty()) {
				throw std::runtime_error("Pool is full!");
			}

			const auto next_free_indirector = free_indirectors.back();
			free_indirectors.pop_back();

			indirector& indirector = indirectors[next_free_indirector];

			const std::size_t new_slot_index = size();

			metadata new_slot;
			new_slot.pointing_indirector = next_free_indirector;
			indirector.real_index = new_slot_index;

			id_type allocated_id;
			allocated_id.version = indirector.version;
			allocated_id.indirection_index = next_free_indirector;

			slots.push_back(new_slot);
			pooled.emplace_back(std::forward<Args>(args)...);

			return allocated_id;
		}

		bool free(const id_type object) {
			if (!alive(object)) {
				return false;
			}

			const auto dead_index = get_real_index(object);

			// add dead object's indirector to the list of free indirectors
			free_indirectors.push_back(slots[dead_index].pointing_indirector);

			// therefore we must increase version of the dead indirector
			++indirectors[object.indirection_index].version;

			if (dead_index != size() - 1) {
				const auto indirector_of_last_element = slots[size() - 1].pointing_indirector;

				// change last element's indirector - set it to the dead element's index
				indirectors[indirector_of_last_element].real_index = dead_index;

				slots[dead_index] = std::move(slots[size() - 1]);
				pooled[dead_index] = std::move(pooled[size() - 1]);
			}

			slots.pop_back();
			pooled.pop_back();

			return true;
		}<commit_msg>Optimize out lookup during object freeing from pool<commit_after>#pragma once
#include <vector>
#include "augs/ensure.h"

#include "augs/build_settings/setting_empty_bases.h"

#include "augs/misc/pool_handle.h"
#include "augs/misc/subscript_operator_for_get_handle_mixin.h"

namespace augs {
	template<class T>
	class EMPTY_BASES pool : public subscript_operator_for_get_handle_mixin<pool<T>> {
	public:
		using id_type = pooled_object_id<T>;
		using unversioned_id_type = unversioned_id<T>;
		using handle_type = handle_for_pool_container<false, pool<T>, T>;
		using const_handle_type = handle_for_pool_container<true, pool<T>, T>;

		using pooled_container_type = std::vector<T>;

		using element_type = T;
	
	protected:
		struct metadata {
			std::size_t pointing_indirector = -1;
		};

		struct indirector {
			unsigned real_index = 0;
			unsigned version = 1;
		};

		pooled_container_type pooled;
		std::vector<metadata> slots;
		std::vector<indirector> indirectors;
		std::vector<std::size_t> free_indirectors;

	public:
		pool(const std::size_t slot_count = 0u) {
			reserve(slot_count);
		}

		/* right now that call overwrites of free_indirectors */
		void reserve(const std::size_t slot_count) {
			pooled.clear();
			indirectors.clear();
			slots.clear();
			free_indirectors.clear();

			pooled.reserve(slot_count);
			slots.reserve(slot_count);

			indirectors.resize(slot_count);

			free_indirectors.resize(slot_count);

			for (std::size_t i = 0; i < slot_count; ++i) {
				free_indirectors[i] = i;
			}
		}

		template <typename... Args>
		id_type allocate(Args&&... args) {
			if (free_indirectors.empty()) {
				throw std::runtime_error("Pool is full!");
			}

			const auto next_free_indirector = free_indirectors.back();
			free_indirectors.pop_back();

			indirector& indirector = indirectors[next_free_indirector];

			const std::size_t new_slot_index = size();

			metadata new_slot;
			new_slot.pointing_indirector = next_free_indirector;
			indirector.real_index = new_slot_index;

			id_type allocated_id;
			allocated_id.version = indirector.version;
			allocated_id.indirection_index = next_free_indirector;

			slots.push_back(new_slot);
			pooled.emplace_back(std::forward<Args>(args)...);

			return allocated_id;
		}

		bool free(const id_type object) {
			if (!alive(object)) {
				return false;
			}

			const auto dead_index = get_real_index(object);

			// add dead object's indirector to the list of free indirectors
			free_indirectors.push_back(object.indirection_index);

			// therefore we must increase version of the dead indirector
			++indirectors[object.indirection_index].version;

			if (dead_index != size() - 1) {
				const auto indirector_of_last_element = slots[size() - 1].pointing_indirector;

				// change last element's indirector - set it to the dead element's index
				indirectors[indirector_of_last_element].real_index = dead_index;

				slots[dead_index] = std::move(slots[size() - 1]);
				pooled[dead_index] = std::move(pooled[size() - 1]);
			}

			slots.pop_back();
			pooled.pop_back();

			return true;
		}
{'fraction_non_alphanumeric': 0.11522768075730373, 'fraction_numerical': 0.002937816223274033, 'mean_word_length': 4.403880070546737, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 35, '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': '6233709', 'n_tokens_mistral': 2474, 'n_tokens_neox': 2098, 'n_words': 417}