きままにブログ

プログラミングを主とした私のメモ帳です。寂しいのでコメントください笑

メモリプールの修正

インナークラスを使って定義すると、その内部のクラスを呼び出すときに、あるクラスがそのクラスのポインタを保持しようとすると実体化できないとエラーになるので修正しました。

namespace mytools {
	template <typename T, size_t SIZE>
	class Pool {
	protected:
		template <typename T>
		class Storage {
		public:
			Storage()
				: next { nullptr } {}
			T& operator[](int no) {
				return *reinterpret_cast<T*>(&buffer[no]);
			}
			Storage* makeNext() {
				next = new Storage {};
				return next;
			}
			~Storage() {
				delete next;
			}
		private:
			std::aligned_storage_t<sizeof(T)> buffer[SIZE];
			Storage* next;
		};

		template <typename T>
		class StorageManager {
		public:
			StorageManager() : position { 0 } {
				last_storage = &storage;
			}

			template <typename ...Args>
			T* make(Args&& ...args) {
				T* ret;

				if (free_list.empty()) {
					ret = &(*last_storage)[position];

					++position;

					if (position >= SIZE) {
						last_storage = storage.makeNext();
						position = 0;
					}
					new(ret)T { std::forward<Args>(args)... };
				}
				else {
					ret = free_list.top();
					new(ret)T { std::forward<Args>(args)... };
					free_list.pop();
				}

				return ret;
			}
			void free(T* it) {
				it->~T();
				free_list.push(it);
			}

		private:
			Storage<T> storage;
			Storage<T>* last_storage;
			std::stack<T*> free_list;
			size_t position;
		};
	};

	template <typename T, size_t SIZE>
	class SharedPool;
	template <typename T, size_t SIZE>
	class DataAndReference;

	template <typename T, size_t SIZE>
	class Reference {
	public:
		Reference()
			: counter { 1 } {}

		void increment() {
			++counter;
		}
		void decrement() {
			--counter;
		}
		void release(SharedPool<T, SIZE>* pool, DataAndReference<T, SIZE>* pointer) {
			if (counter == 0) {
				pool->free(pointer);
			}
		}
	private:
		size_t counter;
	};

	template <typename T, size_t SIZE>
	class DataAndReference {
	public:
		template <typename... Ts>
		DataAndReference(Reference<T, SIZE> reference, Ts&&... ts)
			: reference { reference } {
			new (&data) T { std::forward<Ts>(ts)... };
		}
		DataAndReference() {}

		T& operator*() {
			return *this->get();
		}
		T const& operator*() const {
			return *this->get();
		}
		T* operator->() {
			return this->get();
		}
		T const* operator->() const {
			return this->get();
		}
		T* get() {
			return static_cast<T*>(static_cast<void*>(&data));
		}
		T const* get() const {
			return static_cast<T const*>(static_cast<void*>(&data));
		}

		~DataAndReference() {
			static_cast<T*>(static_cast<void*>(&data))->~T();
		}

		Reference<T, SIZE> reference;
		std::aligned_storage_t<sizeof(T)> data;
	};

	template <typename T, size_t SIZE = 128>
	class SharedPtr {
	public:
		SharedPtr(SharedPool<T, SIZE>* pool, DataAndReference<T, SIZE>* dar)
			: pool { pool }, dar { dar } { }
		SharedPtr()
			: pool { nullptr }, dar { nullptr } {}

		SharedPtr(SharedPtr const& it)
			: pool { it.pool }, dar { it.dar } {
			dar->reference.increment();
		}

		SharedPtr(SharedPtr&& it)
			: pool { it.pool }, dar { it.dar } {
			it.dar = nullptr;
		}

		SharedPtr& operator=(SharedPtr const& it) {
			this->~SharedPtr();
			return *new(this) SharedPtr { it };
		}

		SharedPtr& operator=(SharedPtr&& it) {
			this->~SharedPtr();
			return *new(this) SharedPtr { std::forward<SharedPtr>(it) };
		}

		~SharedPtr() {
			if (dar != nullptr) {
				dar->reference.decrement();
				dar->reference.release(pool, dar);
			}
		}

		T& operator*() {
			return *dar->get();
		}
		T const& operator*() const {
			return *dar->get();
		}
		T* operator->() {
			return dar->get();
		}
		T const* operator->() const {
			return dar->get();
		}

		T* data() {
			return dar->get();
		}

		T const* data() const {
			return dar->get();
		}
	private:
		SharedPool<T, SIZE>* pool;
		DataAndReference<T, SIZE>* dar;
	};

	template <typename T, size_t SIZE = 128>
	class SharedPool : Pool<T, SIZE> {
	public:
		using SharedPtr = SharedPtr<T, SIZE>;

		template <typename ...Args>
		auto makeShared(Args&& ...args) {
			return SharedPtr { this, make(std::forward<Args>(args)...) };
		}

		template <typename ...Args>
		DataAndReference<T, SIZE>* make(Args&& ...args) {
			return storage_manager.make(Reference<T, SIZE> { }, std::forward<Args>(args)...);
		}

		void free(DataAndReference<T, SIZE>* it) {
			storage_manager.free(it);
		}
	private:
		StorageManager<DataAndReference<T, SIZE>> storage_manager;
	};
	
	template <typename T, size_t SIZE>
	class UniquePool;

	template <typename T, size_t SIZE = 128>
	class UniquePtr {
	public:
		UniquePtr(UniquePool<T, SIZE>* pool, T* pointer)
			: pool { pool }, pointer { pointer } { }
		UniquePtr() : UniquePtr { nullptr, nullptr } {}

		UniquePtr(UniquePtr const& it) = delete;

		UniquePtr(UniquePtr&& it) : pool { it.pool }, pointer { it.pointer } {
			it.pointer = nullptr;
		}

		UniquePtr& operator=(UniquePtr const& it) = delete;

		UniquePtr& operator=(UniquePtr&& it) {
			this->~UniquePtr();
			return *new(this) UniquePtr { std::move(it) };
		}

		~UniquePtr() {
			if (pointer != nullptr) {
				pool->free(pointer);
			}
		}

		T& operator*() {
			return *pointer;
		}
		T const& operator*() const {
			return *pointer;
		}

		T* operator->() {
			return pointer;
		}
		T const* operator->() const {
			return pointer;
		}

		T* data() {
			return pointer;
		}

		T const* data() const {
			return pointer;
		}

	private:
		UniquePool<T, SIZE>* pool;
		T* pointer;
	};

	template <typename T, size_t SIZE = 128>
	class UniquePool : Pool<T, SIZE> {
	public:
		using UniquePtr = UniquePtr<T, SIZE>;

		template <typename ...Args>
		auto makeUnique(Args&& ...args) {
			return UniquePtr { this, make(std::forward<Args>(args)...) };
		}

		template <typename ...Args>
		T* make(Args&& ...args) {
			return storage_manager.make(std::forward<Args>(args)...);
		}

		void free(T* it) {
			storage_manager.free(it);
		}

	private:
		StorageManager<T> storage_manager;
	};
}