allocPool: First commit

This commit is contained in:
Timothée Leclaire-Fournier 2024-03-01 14:21:52 -05:00
commit 0af20178b8
7 changed files with 205 additions and 0 deletions

66
.clang-format Normal file
View File

@ -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

8
.idea/.gitignore vendored Normal file
View File

@ -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

8
CMakeLists.txt Normal file
View File

@ -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)

13
README.md Normal file
View File

@ -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.

71
allocPool.cpp Normal file
View File

@ -0,0 +1,71 @@
#include "allocPool.hpp"
template<class T>
requires std::default_initializable<T> && resetable<T>
allocPool<T>::allocPool(size_t defaultAllocNumbers)
: vec(defaultAllocNumbers), pivot{defaultAllocNumbers} {
memset(&(vec[0]), 0, sizeof(vec[0]) * vec.size());
initArray(defaultAllocNumbers);
}
template<class T>
requires std::default_initializable<T> && resetable<T>
T *allocPool<T>::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<class T>
requires std::default_initializable<T> && resetable<T>
void allocPool<T>::returnPtr(T *ptr) {
size_t pos = positionMap[ptr];
vec[pos].reset();
std::swap(vec[pos], vec[pivot]);
pivot++;
}
template<class T>
requires std::default_initializable<T> && resetable<T>
void allocPool<T>::initArray(size_t amount) {
const auto amountOfThreads{std::thread::hardware_concurrency()};
assert(amountOfThreads);
const auto amountPerThreads{amount / amountOfThreads};
std::vector<std::thread> 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<class T>
requires std::default_initializable<T> && resetable<T>
void allocPool<T>::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<class T>
requires std::default_initializable<T> && resetable<T>
void allocPool<T>::resizeVec() {
size_t size{vec.size()};
vec.resize(2 * size);
memcpy(&(vec[size]), &(vec[0]), size);
initArray(size);
}

34
allocPool.hpp Normal file
View File

@ -0,0 +1,34 @@
#pragma once
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstring>
#include <exception>
#include <thread>
#include <unordered_map>
#include <vector>
template<class T>
concept resetable = requires(T val) {
val.reset();
};
template<class T>
requires std::default_initializable<T> && resetable<T>
class allocPool {
public:
explicit allocPool(size_t defaultAllocNumbers = 1000);
T *getPtr();
void returnPtr(T *ptr);
private:
std::vector<T *> vec;
std::unordered_map<T *, size_t> positionMap;
size_t pivot;
void initArray(size_t amount);
void initObjects(size_t startIdx, size_t amount);
void resizeVec();
};

5
main.cpp Normal file
View File

@ -0,0 +1,5 @@
#include <iostream>
int main() {
return 0;
}