From 0af20178b83879d405d73fd76e31177adcad391a Mon Sep 17 00:00:00 2001 From: Timothee Leclaire-Fournier Date: Fri, 1 Mar 2024 14:21:52 -0500 Subject: [PATCH] allocPool: First commit --- .clang-format | 66 ++++++++++++++++++++++++++++++++++++++++++++ .idea/.gitignore | 8 ++++++ CMakeLists.txt | 8 ++++++ README.md | 13 +++++++++ allocPool.cpp | 71 ++++++++++++++++++++++++++++++++++++++++++++++++ allocPool.hpp | 34 +++++++++++++++++++++++ main.cpp | 5 ++++ 7 files changed, 205 insertions(+) create mode 100644 .clang-format create mode 100644 .idea/.gitignore create mode 100644 CMakeLists.txt create mode 100644 README.md create mode 100644 allocPool.cpp create mode 100644 allocPool.hpp create mode 100644 main.cpp diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..f170fa6 --- /dev/null +++ b/.clang-format @@ -0,0 +1,66 @@ +# Generated from CLion C/C++ Code Style settings +BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: None +AlignOperands: Align +AllowAllArgumentsOnNextLine: false +AllowAllConstructorInitializersOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Always +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Always +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterReturnType: None +AlwaysBreakTemplateDeclarations: Yes +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: true +BreakBeforeBinaryOperators: None +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +ColumnLimit: 0 +CompactNamespaces: false +ContinuationIndentWidth: 8 +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 4 +KeepEmptyLinesAtTheStartOfBlocks: true +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: All +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PointerAlignment: Right +ReflowComments: false +SpaceAfterCStyleCast: true +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 0 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +TabWidth: 4 +UseTab: Never diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..9c1c223 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.27) +project(allocPool) + +set(CMAKE_CXX_STANDARD 23) + +add_executable(allocPool main.cpp + allocPool.cpp + allocPool.hpp) diff --git a/README.md b/README.md new file mode 100644 index 0000000..3838321 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# allocPool - A simple & high performance object pool using modern C++ + +This is allocPool, a pool of objects that allow you to avoid expensive allocations +during runtime. This preallocates objects in the constructor (with threads) then +offers you two functions: getPtr() and returnPtr(ptr). + +Using C++ concepts, we can use templates and require the class given to have a +default constructor and to have a .reset() function. It will be used to clean the +objects before giving them to another caller. + +This pool uses a hashmap and a pivot to make returnPtr(ptr) extremely fast. + +It will automatically grow when the max capacity is reached. \ No newline at end of file diff --git a/allocPool.cpp b/allocPool.cpp new file mode 100644 index 0000000..6e21ddd --- /dev/null +++ b/allocPool.cpp @@ -0,0 +1,71 @@ +#include "allocPool.hpp" + +template + requires std::default_initializable && resetable +allocPool::allocPool(size_t defaultAllocNumbers) + : vec(defaultAllocNumbers), pivot{defaultAllocNumbers} { + memset(&(vec[0]), 0, sizeof(vec[0]) * vec.size()); + initArray(defaultAllocNumbers); +} + +template + requires std::default_initializable && resetable +T *allocPool::getPtr() { + if (pivot == 0) + resizeVec(); + + auto *ptrToReturn{vec[0]}; + std::swap(vec[0], vec[pivot - 1]); + positionMap[vec[0]] = 0; + positionMap[vec[pivot - 1]] = pivot - 1; + pivot--; + return ptrToReturn; +} + +template + requires std::default_initializable && resetable +void allocPool::returnPtr(T *ptr) { + size_t pos = positionMap[ptr]; + vec[pos].reset(); + std::swap(vec[pos], vec[pivot]); + pivot++; +} + +template + requires std::default_initializable && resetable +void allocPool::initArray(size_t amount) { + const auto amountOfThreads{std::thread::hardware_concurrency()}; + assert(amountOfThreads); + const auto amountPerThreads{amount / amountOfThreads}; + + std::vector threads; + threads.reserve(amountOfThreads); + + for (size_t i{}; i < amountOfThreads; i++) + threads.emplace_back(&allocPool::initObjects, this, i, amountPerThreads); + + for (auto &t: threads) + t.join(); + + // Remainder + initObjects(vec[vec.size() - (amount % amountOfThreads)], amount % amountOfThreads); +} + +template + requires std::default_initializable && resetable +void allocPool::initObjects(size_t startIdx, size_t amount) { + for (size_t i{}; i < amount; i++) { + // TODO: Be more cache friendly by making a vector per thread, then doing memcpy into the original vector. + vec[startIdx + i] = new T; + positionMap[startIdx + i] = i; + } +} + +template + requires std::default_initializable && resetable +void allocPool::resizeVec() { + size_t size{vec.size()}; + vec.resize(2 * size); + memcpy(&(vec[size]), &(vec[0]), size); + initArray(size); +} \ No newline at end of file diff --git a/allocPool.hpp b/allocPool.hpp new file mode 100644 index 0000000..6ffc8c2 --- /dev/null +++ b/allocPool.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +template +concept resetable = requires(T val) { + val.reset(); +}; + +template + requires std::default_initializable && resetable +class allocPool { +public: + explicit allocPool(size_t defaultAllocNumbers = 1000); + + T *getPtr(); + void returnPtr(T *ptr); + +private: + std::vector vec; + std::unordered_map positionMap; + size_t pivot; + + void initArray(size_t amount); + void initObjects(size_t startIdx, size_t amount); + void resizeVec(); +}; diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..1ac82fd --- /dev/null +++ b/main.cpp @@ -0,0 +1,5 @@ +#include + +int main() { + return 0; +}