flatten 20260225
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
.DS_Store
|
||||||
|
*.pyc
|
||||||
|
xcuserdata
|
||||||
|
.bin
|
||||||
476
Core_Allocator.xcodeproj/project.pbxproj
Normal file
476
Core_Allocator.xcodeproj/project.pbxproj
Normal file
@@ -0,0 +1,476 @@
|
|||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 56;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
F65B59D92C6C53BF00059339 /* Registry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F65B59AD2C6C511800059339 /* Registry.cpp */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
F61F9C022C6EF32D00F79137 /* Makefile.project */ = {isa = PBXFileReference; lastKnownFileType = text; path = Makefile.project; sourceTree = "<group>"; };
|
||||||
|
F61F9C032C6EF34A00F79137 /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
|
||||||
|
F65B59A32C6C511800059339 /* Averaging.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Averaging.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59A42C6C511800059339 /* None.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = None.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59A62C6C511800059339 /* Data.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Data.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59A72C6C511800059339 /* Executor.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Executor.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59A82C6C511800059339 /* ExecutorManual.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ExecutorManual.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59A92C6C511800059339 /* ExecutorThreaded.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ExecutorThreaded.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59AA2C6C511800059339 /* Prunable.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Prunable.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59AB2C6C511800059339 /* Pruning.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Pruning.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59AC2C6C511800059339 /* Pruning.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Pruning.cpp; sourceTree = "<group>"; };
|
||||||
|
F65B59AD2C6C511800059339 /* Registry.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Registry.cpp; sourceTree = "<group>"; };
|
||||||
|
F65B59AE2C6C511800059339 /* Registry.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Registry.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59B02C6C511800059339 /* SizeAllocatorPool_locking.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = SizeAllocatorPool_locking.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59B22C6C511800059339 /* AllocatorBoilerPlateC++11.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "AllocatorBoilerPlateC++11.h"; sourceTree = "<group>"; };
|
||||||
|
F65B59B32C6C511800059339 /* AllocatorFunctions.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AllocatorFunctions.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59B42C6C511800059339 /* AllocatorPool.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AllocatorPool.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59B52C6C511800059339 /* AllocatorPool.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AllocatorPool.cpp; sourceTree = "<group>"; };
|
||||||
|
F65B59B62C6C511800059339 /* ClassAllocatorPool.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ClassAllocatorPool.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59B72C6C511800059339 /* ClassAllocatorPool.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ClassAllocatorPool.cpp; sourceTree = "<group>"; };
|
||||||
|
F65B59B82C6C511800059339 /* IOAllocator.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = IOAllocator.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59B92C6C511800059339 /* MapAllocator.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MapAllocator.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59BA2C6C511800059339 /* SFINAE.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = SFINAE.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59BB2C6C511800059339 /* Size.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Size.h; sourceTree = "<group>"; };
|
||||||
|
F65B59BC2C6C511800059339 /* Size.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Size.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59BD2C6C511800059339 /* SizeAllocatorPool.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = SizeAllocatorPool.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59BE2C6C511800059339 /* SizeAllocatorPool.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SizeAllocatorPool.cpp; sourceTree = "<group>"; };
|
||||||
|
F65B59BF2C6C511800059339 /* Stack_lockfree.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Stack_lockfree.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59C02C6C511800059339 /* Stack_locking.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Stack_locking.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59C12C6C511800059339 /* Stack.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Stack.cpp; sourceTree = "<group>"; };
|
||||||
|
F65B59C22C6C511800059339 /* StackAllocatorPool.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StackAllocatorPool.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59C32C6C511800059339 /* StackNode.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StackNode.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59C42C6C511800059339 /* StaticAllocator.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StaticAllocator.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59C52C6C511800059339 /* StaticAllocatorPool.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StaticAllocatorPool.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59C62C6C511800059339 /* StaticAllocatorPoolOf.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StaticAllocatorPoolOf.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59C72C6C511800059339 /* StrongAllocator.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StrongAllocator.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59C82C6C511800059339 /* VectorPool.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = VectorPool.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59C92C6C511800059339 /* VectorPool.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = VectorPool.cpp; sourceTree = "<group>"; };
|
||||||
|
F65B59CC2C6C516C00059339 /* Makefile.project */ = {isa = PBXFileReference; lastKnownFileType = text; path = Makefile.project; sourceTree = "<group>"; };
|
||||||
|
F65B59CD2C6C516C00059339 /* Makefile.def */ = {isa = PBXFileReference; lastKnownFileType = text; path = Makefile.def; sourceTree = "<group>"; };
|
||||||
|
F65B59CE2C6C51A500059339 /* Precompile.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Precompile.pch; sourceTree = "<group>"; };
|
||||||
|
F65B59CF2C6C51DF00059339 /* StrongAllocator.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StrongAllocator.hpp; sourceTree = "<group>"; };
|
||||||
|
F65B59D42C6C53A400059339 /* libCore_Allocator.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCore_Allocator.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
F6BF9BE12E3900B9002E6AF0 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
F65B59D22C6C53A400059339 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
F61D7C3D2E381620002A1AED /* tjp */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F65B59CB2C6C511800059339 /* core */,
|
||||||
|
);
|
||||||
|
path = tjp;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F61F9BBD2C6DA69C00F79137 /* _tests */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F65B59C12C6C511800059339 /* Stack.cpp */,
|
||||||
|
F65B59C92C6C511800059339 /* VectorPool.cpp */,
|
||||||
|
F65B59CF2C6C51DF00059339 /* StrongAllocator.hpp */,
|
||||||
|
F65B59BE2C6C511800059339 /* SizeAllocatorPool.cpp */,
|
||||||
|
F65B59B72C6C511800059339 /* ClassAllocatorPool.cpp */,
|
||||||
|
F65B59B52C6C511800059339 /* AllocatorPool.cpp */,
|
||||||
|
);
|
||||||
|
path = _tests;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F61F9BFB2C6EEB4200F79137 /* _tests */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F65B59AC2C6C511800059339 /* Pruning.cpp */,
|
||||||
|
);
|
||||||
|
path = _tests;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F61F9C012C6EF32700F79137 /* tests */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F61F9C032C6EF34A00F79137 /* main.cpp */,
|
||||||
|
F61F9C022C6EF32D00F79137 /* Makefile.project */,
|
||||||
|
);
|
||||||
|
path = tests;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F65B599C2C6C50C300059339 = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F6BF9BE12E3900B9002E6AF0 /* Makefile */,
|
||||||
|
F65B59CD2C6C516C00059339 /* Makefile.def */,
|
||||||
|
F65B59CC2C6C516C00059339 /* Makefile.project */,
|
||||||
|
F65B59D52C6C53A400059339 /* Products */,
|
||||||
|
F61F9C012C6EF32700F79137 /* tests */,
|
||||||
|
F61D7C3D2E381620002A1AED /* tjp */,
|
||||||
|
);
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F65B59A52C6C511800059339 /* algorithm */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F65B59A32C6C511800059339 /* Averaging.hpp */,
|
||||||
|
F65B59A42C6C511800059339 /* None.hpp */,
|
||||||
|
);
|
||||||
|
path = algorithm;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F65B59AF2C6C511800059339 /* prune */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F61F9BFB2C6EEB4200F79137 /* _tests */,
|
||||||
|
F65B59A52C6C511800059339 /* algorithm */,
|
||||||
|
F65B59A62C6C511800059339 /* Data.hpp */,
|
||||||
|
F65B59A72C6C511800059339 /* Executor.hpp */,
|
||||||
|
F65B59A82C6C511800059339 /* ExecutorManual.hpp */,
|
||||||
|
F65B59A92C6C511800059339 /* ExecutorThreaded.hpp */,
|
||||||
|
F65B59AA2C6C511800059339 /* Prunable.hpp */,
|
||||||
|
F65B59AB2C6C511800059339 /* Pruning.hpp */,
|
||||||
|
F65B59AD2C6C511800059339 /* Registry.cpp */,
|
||||||
|
F65B59AE2C6C511800059339 /* Registry.hpp */,
|
||||||
|
);
|
||||||
|
path = prune;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F65B59B12C6C511800059339 /* remove */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F65B59B02C6C511800059339 /* SizeAllocatorPool_locking.hpp */,
|
||||||
|
);
|
||||||
|
path = remove;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F65B59CA2C6C511800059339 /* allocator */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F61F9BBD2C6DA69C00F79137 /* _tests */,
|
||||||
|
F65B59AF2C6C511800059339 /* prune */,
|
||||||
|
F65B59B12C6C511800059339 /* remove */,
|
||||||
|
F65B59B22C6C511800059339 /* AllocatorBoilerPlateC++11.h */,
|
||||||
|
F65B59B32C6C511800059339 /* AllocatorFunctions.hpp */,
|
||||||
|
F65B59B42C6C511800059339 /* AllocatorPool.hpp */,
|
||||||
|
F65B59B62C6C511800059339 /* ClassAllocatorPool.hpp */,
|
||||||
|
F65B59B82C6C511800059339 /* IOAllocator.hpp */,
|
||||||
|
F65B59B92C6C511800059339 /* MapAllocator.hpp */,
|
||||||
|
F65B59BA2C6C511800059339 /* SFINAE.hpp */,
|
||||||
|
F65B59BB2C6C511800059339 /* Size.h */,
|
||||||
|
F65B59BC2C6C511800059339 /* Size.hpp */,
|
||||||
|
F65B59BD2C6C511800059339 /* SizeAllocatorPool.hpp */,
|
||||||
|
F65B59BF2C6C511800059339 /* Stack_lockfree.hpp */,
|
||||||
|
F65B59C02C6C511800059339 /* Stack_locking.hpp */,
|
||||||
|
F65B59C22C6C511800059339 /* StackAllocatorPool.hpp */,
|
||||||
|
F65B59C32C6C511800059339 /* StackNode.hpp */,
|
||||||
|
F65B59C42C6C511800059339 /* StaticAllocator.hpp */,
|
||||||
|
F65B59C52C6C511800059339 /* StaticAllocatorPool.hpp */,
|
||||||
|
F65B59C62C6C511800059339 /* StaticAllocatorPoolOf.hpp */,
|
||||||
|
F65B59C72C6C511800059339 /* StrongAllocator.hpp */,
|
||||||
|
F65B59C82C6C511800059339 /* VectorPool.hpp */,
|
||||||
|
);
|
||||||
|
path = allocator;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F65B59CB2C6C511800059339 /* core */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F65B59CE2C6C51A500059339 /* Precompile.pch */,
|
||||||
|
F65B59CA2C6C511800059339 /* allocator */,
|
||||||
|
);
|
||||||
|
path = core;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
F65B59D52C6C53A400059339 /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
F65B59D42C6C53A400059339 /* libCore_Allocator.a */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXHeadersBuildPhase section */
|
||||||
|
F65B59D02C6C53A400059339 /* Headers */ = {
|
||||||
|
isa = PBXHeadersBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXHeadersBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
F65B59D32C6C53A400059339 /* Core_Allocator */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = F65B59D62C6C53A400059339 /* Build configuration list for PBXNativeTarget "Core_Allocator" */;
|
||||||
|
buildPhases = (
|
||||||
|
F65B59D02C6C53A400059339 /* Headers */,
|
||||||
|
F65B59D12C6C53A400059339 /* Sources */,
|
||||||
|
F65B59D22C6C53A400059339 /* Frameworks */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = Core_Allocator;
|
||||||
|
productName = Core_Allocator;
|
||||||
|
productReference = F65B59D42C6C53A400059339 /* libCore_Allocator.a */;
|
||||||
|
productType = "com.apple.product-type.library.static";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
F65B599D2C6C50C300059339 /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
BuildIndependentTargetsInParallel = 1;
|
||||||
|
LastUpgradeCheck = 1530;
|
||||||
|
TargetAttributes = {
|
||||||
|
F65B59D32C6C53A400059339 = {
|
||||||
|
CreatedOnToolsVersion = 15.3;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
buildConfigurationList = F65B59A02C6C50C300059339 /* Build configuration list for PBXProject "Core_Allocator" */;
|
||||||
|
compatibilityVersion = "Xcode 14.0";
|
||||||
|
developmentRegion = en;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
Base,
|
||||||
|
);
|
||||||
|
mainGroup = F65B599C2C6C50C300059339;
|
||||||
|
productRefGroup = F65B59D52C6C53A400059339 /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
F65B59D32C6C53A400059339 /* Core_Allocator */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
F65B59D12C6C53A400059339 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
F65B59D92C6C53BF00059339 /* Registry.cpp in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
F65B59A12C6C50C300059339 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
HEADER_SEARCH_PATHS = (
|
||||||
|
../Core_Zero,
|
||||||
|
../Core_Future,
|
||||||
|
../Libraries/sdk/Darwin/include,
|
||||||
|
);
|
||||||
|
LIBRARY_SEARCH_PATHS = "";
|
||||||
|
"LIBRARY_SEARCH_PATHS[sdk=iphoneos*][arch=arm64]" = (
|
||||||
|
"../Libraries/sdk/Darwin/lib/Debug.iOS-arm64",
|
||||||
|
"../Libraries/project/Debug.iOS-arm64",
|
||||||
|
);
|
||||||
|
"LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]" = (
|
||||||
|
"../Libraries/sdk/Darwin/lib/Debug.iOS-sim",
|
||||||
|
"../Libraries/project/Debug.iOS-sim",
|
||||||
|
);
|
||||||
|
"LIBRARY_SEARCH_PATHS[sdk=macosx*][arch=arm64]" = (
|
||||||
|
"../Libraries/sdk/Darwin/lib/Debug.Darwin-arm64",
|
||||||
|
"../Libraries/project/Debug.Darwin-arm64",
|
||||||
|
);
|
||||||
|
USE_HEADERMAP = NO;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
F65B59A22C6C50C300059339 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
HEADER_SEARCH_PATHS = (
|
||||||
|
../Core_Zero,
|
||||||
|
../Core_Future,
|
||||||
|
../Libraries/sdk/Darwin/include,
|
||||||
|
);
|
||||||
|
LIBRARY_SEARCH_PATHS = "";
|
||||||
|
"LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = (
|
||||||
|
"../Libraries/sdk/Darwin/lib/Release.iOS-arm64",
|
||||||
|
"../Libraries/project/Release.iOS-arm64",
|
||||||
|
);
|
||||||
|
"LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]" = (
|
||||||
|
"../Libraries/sdk/Darwin/lib/Release.iOS-sim",
|
||||||
|
"../Libraries/project/Release.iOS-sim",
|
||||||
|
);
|
||||||
|
"LIBRARY_SEARCH_PATHS[sdk=macosx*][arch=arm64]" = (
|
||||||
|
"../Libraries/sdk/Darwin/lib/Release.Darwin-arm64",
|
||||||
|
"../Libraries/project/Release.Darwin-arm64",
|
||||||
|
);
|
||||||
|
USE_HEADERMAP = NO;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
F65B59D72C6C53A400059339 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
DEVELOPMENT_TEAM = T2M28D3T75;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
EXECUTABLE_PREFIX = lib;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 14.4;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SDKROOT = macosx;
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
F65B59D82C6C53A400059339 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
DEVELOPMENT_TEAM = T2M28D3T75;
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
EXECUTABLE_PREFIX = lib;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 14.4;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SDKROOT = macosx;
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
F65B59A02C6C50C300059339 /* Build configuration list for PBXProject "Core_Allocator" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
F65B59A12C6C50C300059339 /* Debug */,
|
||||||
|
F65B59A22C6C50C300059339 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
F65B59D62C6C53A400059339 /* Build configuration list for PBXNativeTarget "Core_Allocator" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
F65B59D72C6C53A400059339 /* Debug */,
|
||||||
|
F65B59D82C6C53A400059339 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
};
|
||||||
|
rootObject = F65B599D2C6C50C300059339 /* Project object */;
|
||||||
|
}
|
||||||
2
Makefile
Normal file
2
Makefile
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ROOTDIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))..)
|
||||||
|
include $(ROOTDIR)/Core_Make/tjp/Make/Makefile
|
||||||
7
Makefile.def
Executable file
7
Makefile.def
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
timprepscius.core_allocator.include := -I $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||||
|
timprepscius.core_allocator.link := -L $(dir $(realpath $(lastword $(MAKEFILE_LIST))))/.bin/$(OBJDIR)
|
||||||
|
|
||||||
|
timprepscius.core.include := $(timprepscius.core.include) $(timprepscius.core_allocator.include)
|
||||||
|
timprepscius.core.link := $(timprepscius.core.link) $(timprepscius.core_allocator.link)
|
||||||
|
|
||||||
|
|
||||||
18
Makefile.project
Executable file
18
Makefile.project
Executable file
@@ -0,0 +1,18 @@
|
|||||||
|
include $(MAKEDIR)/Makefile.base
|
||||||
|
|
||||||
|
# use: ls -d core/*/ core/*/*/ | rev | cut -c 2- | rev | sed 's/$/ \\/'
|
||||||
|
|
||||||
|
PROJECTS := \
|
||||||
|
tjp/core/allocator \
|
||||||
|
tjp/core/allocator/prune \
|
||||||
|
|
||||||
|
SRC_PCH := tjp/core/Precompile.pch
|
||||||
|
INCPATH := \
|
||||||
|
$(timprepscius.libraries.cpp.include) \
|
||||||
|
$(timprepscius.core.include)
|
||||||
|
|
||||||
|
LIBFILE := libCore_Allocator.a
|
||||||
|
|
||||||
|
COPYTO := $(LIBRARIES_PROJECT)
|
||||||
|
|
||||||
|
include $(MAKEDIR)/Makefile.lib
|
||||||
1
tests/Makefile
Symbolic link
1
tests/Makefile
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../../Make/Makefile
|
||||||
31
tests/Makefile.project
Executable file
31
tests/Makefile.project
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
include $(MAKEDIR)/Makefile.base
|
||||||
|
|
||||||
|
# use: ls -d core/*/ core/*/*/ | rev | cut -c 2- | rev | sed 's/$/ \\/'
|
||||||
|
|
||||||
|
PROJECTS := \
|
||||||
|
. \
|
||||||
|
../core/allocator/_tests \
|
||||||
|
../core/allocator/prune/_tests
|
||||||
|
|
||||||
|
INCPATH := \
|
||||||
|
$(timprepscius.libraries.cpp.include) \
|
||||||
|
$(timprepscius.core.include)
|
||||||
|
|
||||||
|
LDPATH := $(timprepscius.libraries.cpp.link)
|
||||||
|
|
||||||
|
LIBS := \
|
||||||
|
-lCore_Zero \
|
||||||
|
-lCore_Misc \
|
||||||
|
-lCore_Allocator \
|
||||||
|
-lz_
|
||||||
|
|
||||||
|
EXEFILE := Core_Allocator_Tests.exe
|
||||||
|
|
||||||
|
#COPYTO := $(ROOTDIR)/.bin
|
||||||
|
|
||||||
|
ifeq (Darwin,$(SYS_NAME))
|
||||||
|
LIBS += -lc++
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
include $(MAKEDIR)/Makefile.bin
|
||||||
17
tests/main.cpp
Executable file
17
tests/main.cpp
Executable file
@@ -0,0 +1,17 @@
|
|||||||
|
#define CATCH_CONFIG_RUNNER
|
||||||
|
#include <tjp/core/testing/catch.hpp>
|
||||||
|
|
||||||
|
#include <tjp/core/log/Log.h>
|
||||||
|
|
||||||
|
using namespace tjp;
|
||||||
|
using namespace core;
|
||||||
|
|
||||||
|
int main( int argc, char* argv[] )
|
||||||
|
{
|
||||||
|
xLogInitialize("Core_Allocator_Tests.txt");
|
||||||
|
xLogActivateStory("testing");
|
||||||
|
xLogActivateStory("debug");
|
||||||
|
|
||||||
|
int result = Catch::Session().run( argc, argv );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
25
tjp/core/Precompile.pch
Normal file
25
tjp/core/Precompile.pch
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#define USE_PRECOMPILED_HEADERS
|
||||||
|
#ifdef USE_PRECOMPILED_HEADERS
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <shared_mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
87
tjp/core/allocator/AllocatorBoilerPlateC++11.h
Normal file
87
tjp/core/allocator/AllocatorBoilerPlateC++11.h
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class allocator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using value_type = T;
|
||||||
|
|
||||||
|
// using pointer = value_type*;
|
||||||
|
// using const_pointer = typename std::pointer_traits<pointer>::template
|
||||||
|
// rebind<value_type const>;
|
||||||
|
// using void_pointer = typename std::pointer_traits<pointer>::template
|
||||||
|
// rebind<void>;
|
||||||
|
// using const_void_pointer = typename std::pointer_traits<pointer>::template
|
||||||
|
// rebind<const void>;
|
||||||
|
|
||||||
|
// using difference_type = typename std::pointer_traits<pointer>::difference_type;
|
||||||
|
// using size_type = std::make_unsigned_t<difference_type>;
|
||||||
|
|
||||||
|
// template <class U> struct rebind {typedef allocator<U> other;};
|
||||||
|
|
||||||
|
allocator() noexcept {} // not required, unless used
|
||||||
|
template <class U> allocator(allocator<U> const&) noexcept {}
|
||||||
|
|
||||||
|
value_type* // Use pointer if pointer is not a value_type*
|
||||||
|
allocate(std::size_t n)
|
||||||
|
{
|
||||||
|
return static_cast<value_type*>(::operator new (n*sizeof(value_type)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
deallocate(value_type* p, std::size_t) noexcept // Use pointer if pointer is not a value_type*
|
||||||
|
{
|
||||||
|
::operator delete(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// value_type*
|
||||||
|
// allocate(std::size_t n, const_void_pointer)
|
||||||
|
// {
|
||||||
|
// return allocate(n);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// template <class U, class ...Args>
|
||||||
|
// void
|
||||||
|
// construct(U* p, Args&& ...args)
|
||||||
|
// {
|
||||||
|
// ::new(p) U(std::forward<Args>(args)...);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// template <class U>
|
||||||
|
// void
|
||||||
|
// destroy(U* p) noexcept
|
||||||
|
// {
|
||||||
|
// p->~U();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// std::size_t
|
||||||
|
// max_size() const noexcept
|
||||||
|
// {
|
||||||
|
// return std::numeric_limits<size_type>::max();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// allocator
|
||||||
|
// select_on_container_copy_construction() const
|
||||||
|
// {
|
||||||
|
// return *this;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// using propagate_on_container_copy_assignment = std::false_type;
|
||||||
|
// using propagate_on_container_move_assignment = std::false_type;
|
||||||
|
// using propagate_on_container_swap = std::false_type;
|
||||||
|
// using is_always_equal = std::is_empty<allocator>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T, class U>
|
||||||
|
bool
|
||||||
|
operator==(allocator<T> const&, allocator<U> const&) noexcept
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T, class U>
|
||||||
|
bool
|
||||||
|
operator!=(allocator<T> const& x, allocator<U> const& y) noexcept
|
||||||
|
{
|
||||||
|
return !(x == y);
|
||||||
|
}
|
||||||
32
tjp/core/allocator/AllocatorFunctions.hpp
Executable file
32
tjp/core/allocator/AllocatorFunctions.hpp
Executable file
@@ -0,0 +1,32 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace tjp::core {
|
||||||
|
|
||||||
|
struct AllocatorFunctions
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
static void construct(T *__p)
|
||||||
|
{
|
||||||
|
::new((void*)__p) T();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U, typename... Args>
|
||||||
|
static void construct(U* p, Args&&... args)
|
||||||
|
{
|
||||||
|
::new((void*)p) U(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static void destroy(T *p)
|
||||||
|
{
|
||||||
|
p->~T();
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
88
tjp/core/allocator/AllocatorPool.hpp
Executable file
88
tjp/core/allocator/AllocatorPool.hpp
Executable file
@@ -0,0 +1,88 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "StaticAllocatorPoolOf.hpp"
|
||||||
|
|
||||||
|
namespace tjp::core {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class AllocatorPool
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef size_t size_type;
|
||||||
|
typedef std::ptrdiff_t difference_type;
|
||||||
|
typedef T* pointer;
|
||||||
|
typedef const T* const_pointer;
|
||||||
|
typedef T& reference;
|
||||||
|
typedef const T& const_reference;
|
||||||
|
typedef T value_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<typename _Tp1> struct rebind {
|
||||||
|
typedef AllocatorPool<_Tp1> other;
|
||||||
|
};
|
||||||
|
|
||||||
|
using Pool = StaticAllocatorPoolOf<T>;
|
||||||
|
Pool pool;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AllocatorPool() {}
|
||||||
|
AllocatorPool (const AllocatorPool &) {}
|
||||||
|
~AllocatorPool () {}
|
||||||
|
|
||||||
|
template <class _Up>
|
||||||
|
AllocatorPool (const _Up &) { }
|
||||||
|
|
||||||
|
pointer allocate (size_t size)
|
||||||
|
{
|
||||||
|
debug_assert(size == 1);
|
||||||
|
|
||||||
|
auto t = pool.allocate();
|
||||||
|
return (pointer)t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate(T *o, size_t size)
|
||||||
|
{
|
||||||
|
debug_assert(size == 1);
|
||||||
|
pool.deallocate(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
void construct(pointer __p)
|
||||||
|
{
|
||||||
|
AllocatorFunctions::construct(__p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U, typename... Args>
|
||||||
|
void construct(U* p, Args&&... args)
|
||||||
|
{
|
||||||
|
AllocatorFunctions::construct(p, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy(pointer p)
|
||||||
|
{
|
||||||
|
AllocatorFunctions::destroy(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U>
|
||||||
|
void destroy(U* p)
|
||||||
|
{
|
||||||
|
AllocatorFunctions::destroy(p);
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
template<class T, class U>
|
||||||
|
bool operator ==(const AllocatorPool<T> &lhs, const AllocatorPool<U> &rhs) noexcept
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, class U>
|
||||||
|
bool operator !=(const AllocatorPool<T> &lhs, const AllocatorPool<U> &rhs) noexcept
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
77
tjp/core/allocator/ClassAllocatorPool.hpp
Executable file
77
tjp/core/allocator/ClassAllocatorPool.hpp
Executable file
@@ -0,0 +1,77 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "SizeAllocatorPool.hpp"
|
||||||
|
|
||||||
|
namespace tjp::core {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct ClassAllocatorPool
|
||||||
|
{
|
||||||
|
using Allocator = SizeAllocatorPool<sizeof(T), alignof(T)>;
|
||||||
|
|
||||||
|
Allocator allocator;
|
||||||
|
typedef T value_type;
|
||||||
|
|
||||||
|
template<typename _Tp1> struct rebind { typedef ClassAllocatorPool<_Tp1> other; };
|
||||||
|
|
||||||
|
template<typename ...Args>
|
||||||
|
ClassAllocatorPool(Args&& ...args) {}
|
||||||
|
|
||||||
|
T *allocate ()
|
||||||
|
{
|
||||||
|
return (T *)allocator.allocate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate (T *t)
|
||||||
|
{
|
||||||
|
return allocator.deallocate(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &getSize()
|
||||||
|
{
|
||||||
|
return allocator.getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void prune ()
|
||||||
|
{
|
||||||
|
allocator.prune();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct ClassAllocatorPoolPartitioned
|
||||||
|
{
|
||||||
|
SizeAllocatorPool<sizeof(T), alignof(T), T> allocator;
|
||||||
|
typedef T value_type;
|
||||||
|
|
||||||
|
template<typename _Tp1> struct rebind { typedef ClassAllocatorPoolPartitioned<_Tp1> other; };
|
||||||
|
|
||||||
|
template<typename ...Args>
|
||||||
|
ClassAllocatorPoolPartitioned(Args&& ...args) {}
|
||||||
|
|
||||||
|
T *allocate ()
|
||||||
|
{
|
||||||
|
return (T *)allocator.allocate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate (T *t)
|
||||||
|
{
|
||||||
|
return allocator.deallocate(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &getSize()
|
||||||
|
{
|
||||||
|
return allocator.getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void prune ()
|
||||||
|
{
|
||||||
|
allocator.prune();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
18
tjp/core/allocator/IOAllocator.hpp
Normal file
18
tjp/core/allocator/IOAllocator.hpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "StrongAllocator.hpp"
|
||||||
|
|
||||||
|
namespace tjp::core::allocators {
|
||||||
|
|
||||||
|
struct IOAllocator : StrongAllocator
|
||||||
|
{
|
||||||
|
template<typename IO, typename T>
|
||||||
|
void allocate(IO &io, StrongPtr<T> &t)
|
||||||
|
{
|
||||||
|
t = this->strong<T>();
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
14
tjp/core/allocator/MapAllocator.hpp
Executable file
14
tjp/core/allocator/MapAllocator.hpp
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AllocatorPool.hpp"
|
||||||
|
|
||||||
|
namespace tjp::core {
|
||||||
|
|
||||||
|
template<typename K, typename V>
|
||||||
|
using MapAllocator = AllocatorPool<std::pair<const K, V>>;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
59
tjp/core/allocator/SFINAE.hpp
Normal file
59
tjp/core/allocator/SFINAE.hpp
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <tjp/core/sfinae/if_or.hpp>
|
||||||
|
|
||||||
|
namespace tjp::core::allocators {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class has_allocator
|
||||||
|
{
|
||||||
|
typedef char yes;
|
||||||
|
struct no {char x[2];};
|
||||||
|
template<typename C> static yes test(typename C::Allocator*);
|
||||||
|
template<typename C> static no test(...);
|
||||||
|
public:
|
||||||
|
enum { value = sizeof(test<T>(0)) == sizeof (char)};
|
||||||
|
};
|
||||||
|
|
||||||
|
// This should use invocable, but I haven't figured it out yet
|
||||||
|
template<typename T> struct is_strong_allocator : std::false_type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class has_strong_allocator_flag
|
||||||
|
{
|
||||||
|
typedef char yes;
|
||||||
|
struct no { char x[2];};
|
||||||
|
template<typename C> static yes test(typename C::is_strong_allocator*);
|
||||||
|
template<typename C> static no test(...);
|
||||||
|
public:
|
||||||
|
enum { value = sizeof(test<T>(0)) == sizeof (char)};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename T,
|
||||||
|
typename T2=void
|
||||||
|
// typename std::enable_if<!has_allocator<T>::value, char>::type
|
||||||
|
>
|
||||||
|
struct has_strong_allocator {
|
||||||
|
enum { value = false };
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct has_strong_allocator<
|
||||||
|
T,
|
||||||
|
typename std::enable_if<has_allocator<T>::value>::type
|
||||||
|
>
|
||||||
|
{
|
||||||
|
typedef typename sfinae::if_or<
|
||||||
|
has_strong_allocator_flag<typename T::Allocator>::value,
|
||||||
|
std::true_type,
|
||||||
|
std::false_type>::type type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr bool value = type::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
11
tjp/core/allocator/Size.h
Executable file
11
tjp/core/allocator/Size.h
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace tjp::core::allocator_pool {
|
||||||
|
|
||||||
|
struct Size;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
16
tjp/core/allocator/Size.hpp
Executable file
16
tjp/core/allocator/Size.hpp
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <tjp/core/threads/Atomic.hpp>
|
||||||
|
|
||||||
|
namespace tjp::core::allocator_pool {
|
||||||
|
|
||||||
|
struct Size {
|
||||||
|
Atomic<size_t> used = 0;
|
||||||
|
Atomic<size_t> freed = 0;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
45
tjp/core/allocator/SizeAllocatorPool.hpp
Executable file
45
tjp/core/allocator/SizeAllocatorPool.hpp
Executable file
@@ -0,0 +1,45 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Stack_locking.hpp"
|
||||||
|
#include "Stack_lockfree.hpp"
|
||||||
|
#include "StackAllocatorPool.hpp"
|
||||||
|
#include <tjp/core/threads/SpinMutex.hpp>
|
||||||
|
|
||||||
|
namespace tjp::core {
|
||||||
|
|
||||||
|
template<size_t size, size_t alignment, typename C=void>
|
||||||
|
using SizeAllocatorPool_lockfree =
|
||||||
|
allocator_pool::StackAllocatorPool<
|
||||||
|
allocator_pool::Stack_lockfree<
|
||||||
|
allocator_pool::Allocation<size, alignment>
|
||||||
|
>,
|
||||||
|
C
|
||||||
|
>;
|
||||||
|
|
||||||
|
template<size_t size, size_t alignment, typename C=void>
|
||||||
|
using SizeAllocatorPool_locking =
|
||||||
|
allocator_pool::StackAllocatorPool<
|
||||||
|
allocator_pool::Stack_locking<
|
||||||
|
allocator_pool::Allocation<size, alignment>
|
||||||
|
>,
|
||||||
|
C
|
||||||
|
>;
|
||||||
|
|
||||||
|
template<size_t size, size_t alignment, typename C=void>
|
||||||
|
using SizeAllocatorPool_locking_spinlock =
|
||||||
|
allocator_pool::StackAllocatorPool<
|
||||||
|
allocator_pool::Stack_locking<
|
||||||
|
allocator_pool::Allocation<size, alignment>,
|
||||||
|
SpinMutex
|
||||||
|
>,
|
||||||
|
C
|
||||||
|
>;
|
||||||
|
|
||||||
|
template<size_t size, size_t alignment, typename C=void>
|
||||||
|
using SizeAllocatorPool = SizeAllocatorPool_locking_spinlock<size, alignment, C>;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
160
tjp/core/allocator/StackAllocatorPool.hpp
Executable file
160
tjp/core/allocator/StackAllocatorPool.hpp
Executable file
@@ -0,0 +1,160 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <tjp/core/threads/Lock.hpp>
|
||||||
|
#include <tjp/core/threads/Atomic.hpp>
|
||||||
|
|
||||||
|
#include <tjp/core/debug/Debug.h>
|
||||||
|
#include "Size.hpp"
|
||||||
|
|
||||||
|
namespace tjp::core::allocator_pool {
|
||||||
|
|
||||||
|
template<size_t size_, size_t alignment_>
|
||||||
|
struct Allocation
|
||||||
|
{
|
||||||
|
static constexpr size_t size = size_;
|
||||||
|
static constexpr size_t alignment = alignment_;
|
||||||
|
|
||||||
|
char t[size_];
|
||||||
|
} __attribute__ ((aligned(alignment_)));
|
||||||
|
|
||||||
|
template<typename T, typename C=void>
|
||||||
|
class StackAllocatorPool_Real
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
using Stack = T;
|
||||||
|
using Node = typename T::node_type;
|
||||||
|
|
||||||
|
Stack stack;
|
||||||
|
Size size;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = void;
|
||||||
|
|
||||||
|
public:
|
||||||
|
~StackAllocatorPool_Real ()
|
||||||
|
{
|
||||||
|
while (!stack.empty())
|
||||||
|
prune();
|
||||||
|
}
|
||||||
|
|
||||||
|
void *allocate ()
|
||||||
|
{
|
||||||
|
auto node = stack.pop();
|
||||||
|
if (node)
|
||||||
|
{
|
||||||
|
size.freed--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node = new Node();
|
||||||
|
}
|
||||||
|
|
||||||
|
size.used++;
|
||||||
|
return &node->t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate(void *v)
|
||||||
|
{
|
||||||
|
if (!v)
|
||||||
|
return;
|
||||||
|
|
||||||
|
static_assert(offsetof(Node, t) == 0);
|
||||||
|
constexpr size_t offset_t = offsetof(Node, t);
|
||||||
|
|
||||||
|
Node *node;
|
||||||
|
if constexpr(offset_t == 0)
|
||||||
|
node = (Node *)v;
|
||||||
|
else
|
||||||
|
node = (Node *)((char *)v - offset_t);
|
||||||
|
|
||||||
|
stack.push(node);
|
||||||
|
|
||||||
|
size.used--;
|
||||||
|
size.freed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Size &getSize ()
|
||||||
|
{
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void prune()
|
||||||
|
{
|
||||||
|
auto node = stack.pop();
|
||||||
|
if (node)
|
||||||
|
{
|
||||||
|
delete node;
|
||||||
|
|
||||||
|
size.freed--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
template<typename T=void>
|
||||||
|
struct StackAllocatorPool_Fake_Debug_Variables_ {
|
||||||
|
static bool use_real_pool;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool StackAllocatorPool_Fake_Debug_Variables_<T>::use_real_pool = false;
|
||||||
|
|
||||||
|
using StackAllocatorPool_Fake_Debug_Variables = StackAllocatorPool_Fake_Debug_Variables_<void>;
|
||||||
|
|
||||||
|
template<typename T_, typename C=void>
|
||||||
|
struct StackAllocatorPool_Fake
|
||||||
|
{
|
||||||
|
using T = T_;
|
||||||
|
Size size;
|
||||||
|
|
||||||
|
using value_type = void;
|
||||||
|
|
||||||
|
using RealPool = StackAllocatorPool_Real<T_, C>;
|
||||||
|
RealPool pool;
|
||||||
|
|
||||||
|
void *allocate ()
|
||||||
|
{
|
||||||
|
if (StackAllocatorPool_Fake_Debug_Variables::use_real_pool)
|
||||||
|
return pool.allocate();
|
||||||
|
|
||||||
|
size.used += T::Type::size;
|
||||||
|
auto alignment = T::Type::alignment;
|
||||||
|
(void)alignment;
|
||||||
|
|
||||||
|
auto size = T::Type::size;
|
||||||
|
auto result = malloc(size);
|
||||||
|
// auto result = std::aligned_alloc(alignment, size);
|
||||||
|
debug_assert(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate(void *v)
|
||||||
|
{
|
||||||
|
if (StackAllocatorPool_Fake_Debug_Variables::use_real_pool)
|
||||||
|
return pool.deallocate(v);
|
||||||
|
|
||||||
|
std::free(v);
|
||||||
|
size.used -= T::Type::size;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Size &getSize ()
|
||||||
|
{
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void prune()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
template<typename T, typename C=void>
|
||||||
|
using StackAllocatorPool = StackAllocatorPool_Fake<T, C>;
|
||||||
|
|
||||||
|
//template<typename T, typename C=void>
|
||||||
|
//using StackAllocatorPool = StackAllocatorPool_Real<T, C>;
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
26
tjp/core/allocator/StackNode.hpp
Executable file
26
tjp/core/allocator/StackNode.hpp
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <tjp/core/threads/Atomic.hpp>
|
||||||
|
|
||||||
|
namespace tjp::core::allocator_pool {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct StackNode {
|
||||||
|
using value_type = T;
|
||||||
|
|
||||||
|
T t;
|
||||||
|
StackNode *next;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct StackNode<void> {
|
||||||
|
using value_type = void;
|
||||||
|
|
||||||
|
StackNode *next;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
81
tjp/core/allocator/Stack_lockfree.hpp
Executable file
81
tjp/core/allocator/Stack_lockfree.hpp
Executable file
@@ -0,0 +1,81 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <tjp/core/assert/debug_assert.h>
|
||||||
|
#include <tjp/core/threads/Atomic.hpp>
|
||||||
|
#include "StackNode.hpp"
|
||||||
|
|
||||||
|
namespace tjp::core::allocator_pool {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class Stack_lockfree
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Type = T;
|
||||||
|
using Node = StackNode<T>;
|
||||||
|
using node_type = Node;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Atomic<Node *> head = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Node *pop()
|
||||||
|
{
|
||||||
|
// this method DOES NOT WORK
|
||||||
|
// because:
|
||||||
|
// thread A:
|
||||||
|
// next = top->next (Y)
|
||||||
|
// thread B:
|
||||||
|
// X = pop top, Y = pop top
|
||||||
|
// push X
|
||||||
|
// thread A:
|
||||||
|
// exchange pop X
|
||||||
|
// now top == Y, even though Y is not there
|
||||||
|
// there has to be a double test, for instance, is(top == head and top->next still equal to next)
|
||||||
|
|
||||||
|
debug_assert(false);
|
||||||
|
Node *top = head.load();
|
||||||
|
while (top != nullptr)
|
||||||
|
{
|
||||||
|
Node *next = top->next;
|
||||||
|
if (head.compare_exchange_weak(top, next))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return top;
|
||||||
|
}
|
||||||
|
|
||||||
|
void push(Node *node)
|
||||||
|
{
|
||||||
|
Node *expected_head = head.load();
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
node->next = expected_head;
|
||||||
|
}
|
||||||
|
while(!head.compare_exchange_weak(expected_head, node));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return head == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size_not_thread_safe() const
|
||||||
|
{
|
||||||
|
size_t result = 0;
|
||||||
|
Node *node = head;
|
||||||
|
while (node)
|
||||||
|
{
|
||||||
|
result++;
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
65
tjp/core/allocator/Stack_locking.hpp
Executable file
65
tjp/core/allocator/Stack_locking.hpp
Executable file
@@ -0,0 +1,65 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <tjp/core/threads/Lock.hpp>
|
||||||
|
#include "StackNode.hpp"
|
||||||
|
|
||||||
|
namespace tjp::core::allocator_pool {
|
||||||
|
|
||||||
|
template<typename T, typename M=Mutex>
|
||||||
|
class Stack_locking
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Type = T;
|
||||||
|
using Node = StackNode<T>;
|
||||||
|
using node_type = Node;
|
||||||
|
using mutex_type = M;
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable M mutex;
|
||||||
|
Node *head = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Node *pop()
|
||||||
|
{
|
||||||
|
auto lock = lock_of(mutex);
|
||||||
|
|
||||||
|
auto *a = head;
|
||||||
|
if (a != nullptr)
|
||||||
|
head = a->next;
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void push(Node *a)
|
||||||
|
{
|
||||||
|
auto lock = lock_of(mutex);
|
||||||
|
|
||||||
|
a->next = head;
|
||||||
|
head = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
auto lock = lock_of(mutex);
|
||||||
|
return head == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size_not_thread_safe() const
|
||||||
|
{
|
||||||
|
size_t result = 0;
|
||||||
|
Node *node = head;
|
||||||
|
while (node)
|
||||||
|
{
|
||||||
|
result++;
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
19
tjp/core/allocator/StaticAllocator.hpp
Executable file
19
tjp/core/allocator/StaticAllocator.hpp
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace tjp::core {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class StaticAllocator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef T Allocator;
|
||||||
|
static Allocator allocator;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
template<typename T> typename StaticAllocator<T>::Allocator StaticAllocator<T>::allocator;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
37
tjp/core/allocator/StaticAllocatorPool.hpp
Executable file
37
tjp/core/allocator/StaticAllocatorPool.hpp
Executable file
@@ -0,0 +1,37 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace tjp {
|
||||||
|
namespace core {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class StaticAllocatorPool
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef T Allocator;
|
||||||
|
static Allocator allocator;
|
||||||
|
|
||||||
|
static auto allocate ()
|
||||||
|
{
|
||||||
|
return allocator.allocate();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U>
|
||||||
|
static void deallocate(U *o)
|
||||||
|
{
|
||||||
|
allocator.deallocate(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prune()
|
||||||
|
{
|
||||||
|
allocator.prune();
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
template<typename T> typename StaticAllocatorPool<T>::Allocator StaticAllocatorPool<T>::allocator;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
70
tjp/core/allocator/StaticAllocatorPoolOf.hpp
Executable file
70
tjp/core/allocator/StaticAllocatorPoolOf.hpp
Executable file
@@ -0,0 +1,70 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "StaticAllocatorPool.hpp"
|
||||||
|
#include "AllocatorFunctions.hpp"
|
||||||
|
#include "SizeAllocatorPool.hpp"
|
||||||
|
#include "prune/Pruning.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace tjp::core {
|
||||||
|
|
||||||
|
template<size_t size, size_t alignment, typename C=void>
|
||||||
|
struct StaticAllocatorPoolOf_ {
|
||||||
|
|
||||||
|
using SizeAllocator = SizeAllocatorPool<size, alignment, C>;
|
||||||
|
using Allocator = allocator_pool::prune::Pruning<SizeAllocator>;
|
||||||
|
|
||||||
|
static Allocator allocator;
|
||||||
|
|
||||||
|
static auto allocate ()
|
||||||
|
{
|
||||||
|
return allocator.allocate();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U>
|
||||||
|
static void deallocate(U *o)
|
||||||
|
{
|
||||||
|
allocator.deallocate(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prune()
|
||||||
|
{
|
||||||
|
allocator.prune();
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
template<size_t size, size_t alignment, typename C> typename
|
||||||
|
StaticAllocatorPoolOf_<size, alignment, C>::Allocator StaticAllocatorPoolOf_<size, alignment, C>::allocator;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class StaticAllocatorPoolOf
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Allocator = StaticAllocatorPoolOf_<sizeof(T), alignof(T)>;
|
||||||
|
Allocator allocator;
|
||||||
|
|
||||||
|
using value_type = T;
|
||||||
|
|
||||||
|
auto allocate ()
|
||||||
|
{
|
||||||
|
return (T *)allocator.allocate();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U>
|
||||||
|
void deallocate(U *o)
|
||||||
|
{
|
||||||
|
allocator.deallocate(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
void prune()
|
||||||
|
{
|
||||||
|
allocator.prune();
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
25
tjp/core/allocator/StrongAllocator.hpp
Normal file
25
tjp/core/allocator/StrongAllocator.hpp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AllocatorPool.hpp"
|
||||||
|
|
||||||
|
#include <tjp/core/ptr/Ptr.hpp>
|
||||||
|
|
||||||
|
namespace tjp::core::allocators {
|
||||||
|
|
||||||
|
struct StrongAllocator
|
||||||
|
{
|
||||||
|
typedef void is_strong_allocator;
|
||||||
|
|
||||||
|
template<typename T, typename ... Args>
|
||||||
|
auto strong(Args && ...args)
|
||||||
|
{
|
||||||
|
return strong_with_allocator<T>(
|
||||||
|
core::AllocatorPool<T>(),
|
||||||
|
std::forward<Args>(args)...
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
159
tjp/core/allocator/VectorPool.hpp
Executable file
159
tjp/core/allocator/VectorPool.hpp
Executable file
@@ -0,0 +1,159 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "../allocator/StaticAllocator.hpp"
|
||||||
|
#include "../allocator/SizeAllocatorPool.hpp"
|
||||||
|
|
||||||
|
#include <tjp/core/log/Log.h>
|
||||||
|
#include <tjp/core/log/LogOf.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace tjp::core {
|
||||||
|
namespace vectorpool {
|
||||||
|
|
||||||
|
//https://stackoverflow.com/questions/994593/how-to-do-an-integer-log2-in-c
|
||||||
|
inline
|
||||||
|
int uint64_log2(uint64_t n)
|
||||||
|
{
|
||||||
|
#define S(k) if (n >= (UINT64_C(1) << k)) { i += k; n >>= k; }
|
||||||
|
int i = -(n == 0); S(32); S(16); S(8); S(4); S(2); S(1); return i;
|
||||||
|
#undef S
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
int scale(uint64_t n)
|
||||||
|
{
|
||||||
|
return n ?
|
||||||
|
uint64_log2(n-1)+2 :
|
||||||
|
0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
constexpr size_t unscale(int n)
|
||||||
|
{
|
||||||
|
return n ?
|
||||||
|
1 << (n-1) :
|
||||||
|
0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
constexpr size_t unscale(int n)
|
||||||
|
{
|
||||||
|
return unscale(n) * sizeof(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T, typename DefaultAllocator=std::allocator<T>>
|
||||||
|
class Allocator {
|
||||||
|
public:
|
||||||
|
// The type definitions required for an allocator
|
||||||
|
using value_type = T;
|
||||||
|
using pointer = value_type*;
|
||||||
|
using const_pointer =
|
||||||
|
typename std::pointer_traits<pointer>::template
|
||||||
|
rebind<value_type const>;
|
||||||
|
|
||||||
|
using void_pointer =
|
||||||
|
typename std::pointer_traits<pointer>::template
|
||||||
|
rebind<void>;
|
||||||
|
|
||||||
|
using const_void_pointer =
|
||||||
|
typename std::pointer_traits<pointer>::template
|
||||||
|
rebind<const void>;
|
||||||
|
|
||||||
|
using difference_type = typename std::pointer_traits<pointer>::difference_type;
|
||||||
|
using size_type = std::make_unsigned_t<difference_type>;
|
||||||
|
|
||||||
|
using propagate_on_container_move_assignment = std::true_type;
|
||||||
|
|
||||||
|
[[no_unique_address]]
|
||||||
|
DefaultAllocator defaultAllocator;
|
||||||
|
|
||||||
|
// Default constructor (no state to maintain in this basic example)
|
||||||
|
Allocator() noexcept {}
|
||||||
|
|
||||||
|
// Allocate memory for n objects of type T
|
||||||
|
T* allocate(std::size_t n)
|
||||||
|
{
|
||||||
|
auto s = scale(n);
|
||||||
|
|
||||||
|
sLogDebug("core::vectorpool", logVar(n) << logVar(s) << logVar(unscale(s)) << logVar(unscale<T>(s)));
|
||||||
|
|
||||||
|
void *result = nullptr;
|
||||||
|
switch(s) {
|
||||||
|
case 0: result = nullptr;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: result = StaticAllocator<SizeAllocatorPool<unscale<T>(1),alignof(T)>>::allocator.allocate();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: result = StaticAllocator<SizeAllocatorPool<unscale<T>(2),alignof(T)>>::allocator.allocate();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: result = StaticAllocator<SizeAllocatorPool<unscale<T>(3),alignof(T)>>::allocator.allocate();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4: result = StaticAllocator<SizeAllocatorPool<unscale<T>(4),alignof(T)>>::allocator.allocate();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: result = defaultAllocator.allocate(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<T *>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deallocate memory for n objects of type T
|
||||||
|
void deallocate(T* p, std::size_t n)
|
||||||
|
{
|
||||||
|
auto s = scale(n);
|
||||||
|
|
||||||
|
sLogDebug("core::vectorpool", logVar(n) << logVar(s) << logVar(unscale(s)) << logVar(unscale<T>(s)));
|
||||||
|
|
||||||
|
switch(s) {
|
||||||
|
case 0: return;
|
||||||
|
case 1: return StaticAllocator<SizeAllocatorPool<unscale<T>(1),alignof(T)>>::allocator.deallocate(p);
|
||||||
|
case 2: return StaticAllocator<SizeAllocatorPool<unscale<T>(2),alignof(T)>>::allocator.deallocate(p);
|
||||||
|
case 3: return StaticAllocator<SizeAllocatorPool<unscale<T>(3),alignof(T)>>::allocator.deallocate(p);
|
||||||
|
case 4: return StaticAllocator<SizeAllocatorPool<unscale<T>(4),alignof(T)>>::allocator.deallocate(p);
|
||||||
|
default: return defaultAllocator.deallocate(p, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy constructor (not strictly needed for std::vector)
|
||||||
|
template <typename U>
|
||||||
|
Allocator(const Allocator<U>&) noexcept {}
|
||||||
|
|
||||||
|
// Move constructor (not strictly needed for std::vector)
|
||||||
|
template <typename U>
|
||||||
|
Allocator(Allocator<U>&&) noexcept {}
|
||||||
|
|
||||||
|
// Copy assignment (not strictly needed for std::vector)
|
||||||
|
template <typename U>
|
||||||
|
Allocator& operator=(const Allocator<U>&) noexcept { return *this; }
|
||||||
|
|
||||||
|
// Move assignment (not strictly needed for std::vector)
|
||||||
|
template <typename U>
|
||||||
|
Allocator& operator=(Allocator<U>&&) noexcept { return *this; }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, class U, class V, class W>
|
||||||
|
bool operator ==(const Allocator<T, U> &lhs, const Allocator<V, W> &rhs) noexcept
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, class U, class V, class W>
|
||||||
|
bool operator !=(const Allocator<T, U> &lhs, const Allocator<V, W> &rhs) noexcept
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
template <typename T, typename DefaultAllocator=std::allocator<T>>
|
||||||
|
using VectorPool = vectorpool::Allocator<T,DefaultAllocator>;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
23
tjp/core/allocator/_tests/AllocatorPool.cpp
Executable file
23
tjp/core/allocator/_tests/AllocatorPool.cpp
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
#include <tjp/core/allocator/AllocatorPool.hpp>
|
||||||
|
#include <tjp/core/testing/catch.hpp>
|
||||||
|
|
||||||
|
namespace tjp::core {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
|
||||||
|
SCENARIO("core::allocator")
|
||||||
|
{
|
||||||
|
GIVEN("two allocators")
|
||||||
|
{
|
||||||
|
AllocatorPool<char> a;
|
||||||
|
AllocatorPool<int> b;
|
||||||
|
|
||||||
|
REQUIRE(a == b);
|
||||||
|
REQUIRE((a != b) == false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace
|
||||||
72
tjp/core/allocator/_tests/ClassAllocatorPool.cpp
Executable file
72
tjp/core/allocator/_tests/ClassAllocatorPool.cpp
Executable file
@@ -0,0 +1,72 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
#include <tjp/core/allocator/ClassAllocatorPool.hpp>
|
||||||
|
#include <tjp/core/testing/catch.hpp>
|
||||||
|
|
||||||
|
#include <tjp/core/iterators/range.hpp>
|
||||||
|
#include <tjp/core/algorithm/unused.hpp>
|
||||||
|
#include <tjp/core/containers/Set.hpp>
|
||||||
|
|
||||||
|
namespace tjp::core::allocator {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
SCENARIO("ClassAllocatorPool")
|
||||||
|
{
|
||||||
|
GIVEN("allocator")
|
||||||
|
{
|
||||||
|
ClassAllocatorPool<int> p;
|
||||||
|
|
||||||
|
auto num = 10;
|
||||||
|
|
||||||
|
std::set<int *> a0;
|
||||||
|
for (auto i : range(num))
|
||||||
|
{
|
||||||
|
unused(i);
|
||||||
|
|
||||||
|
int *a = p.allocate();
|
||||||
|
a0.insert(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(p.getSize().freed == 0);
|
||||||
|
REQUIRE(p.getSize().used == num);
|
||||||
|
|
||||||
|
for (auto *a : a0)
|
||||||
|
p.deallocate(a);
|
||||||
|
|
||||||
|
|
||||||
|
REQUIRE(p.getSize().freed == num);
|
||||||
|
REQUIRE(p.getSize().used == 0);
|
||||||
|
|
||||||
|
std::set<int *> a1;
|
||||||
|
|
||||||
|
for (auto i : range(num))
|
||||||
|
{
|
||||||
|
unused(i);
|
||||||
|
|
||||||
|
int *a = p.allocate();
|
||||||
|
a1.insert(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(p.getSize().freed == 0);
|
||||||
|
REQUIRE(p.getSize().used == num);
|
||||||
|
|
||||||
|
REQUIRE(a0 == a1);
|
||||||
|
|
||||||
|
for (auto *a : a1)
|
||||||
|
p.deallocate(a);
|
||||||
|
|
||||||
|
REQUIRE(p.getSize().freed == num);
|
||||||
|
REQUIRE(p.getSize().used == 0);
|
||||||
|
|
||||||
|
for (auto i : range(num))
|
||||||
|
{
|
||||||
|
p.prune();
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(p.getSize().freed == 0);
|
||||||
|
REQUIRE(p.getSize().used == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace
|
||||||
150
tjp/core/allocator/_tests/SizeAllocatorPool.cpp
Executable file
150
tjp/core/allocator/_tests/SizeAllocatorPool.cpp
Executable file
@@ -0,0 +1,150 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
#include <tjp/core/allocator/SizeAllocatorPool.hpp>
|
||||||
|
#include <tjp/core/testing/catch.hpp>
|
||||||
|
#include <tjp/core/testing/NO_WHEN.h>
|
||||||
|
|
||||||
|
#include <tjp/core/iterators/range.hpp>
|
||||||
|
#include <tjp/core/containers/Set.hpp>
|
||||||
|
#include <tjp/core/algorithm/unused.hpp>
|
||||||
|
|
||||||
|
#include <tjp/core/containers/Vector.hpp>
|
||||||
|
|
||||||
|
namespace tjp::core::allocator {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
|
||||||
|
SCENARIO("SizeAllocatorPool")
|
||||||
|
{
|
||||||
|
GIVEN("allocator locking")
|
||||||
|
{
|
||||||
|
SizeAllocatorPool_locking_spinlock<1, 1> p;
|
||||||
|
|
||||||
|
WHEN("allocate a deallocate and allocate again")
|
||||||
|
{
|
||||||
|
auto num = 10;
|
||||||
|
|
||||||
|
std::set<void *> a0;
|
||||||
|
for (auto i : range(num))
|
||||||
|
{
|
||||||
|
unused(i);
|
||||||
|
a0.insert(p.allocate());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto *a : a0)
|
||||||
|
p.deallocate(a);
|
||||||
|
|
||||||
|
Set<void *> a1;
|
||||||
|
|
||||||
|
for (auto i : range(num))
|
||||||
|
{
|
||||||
|
unused(i);
|
||||||
|
a1.insert(p.allocate());
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(a0 == a1);
|
||||||
|
}
|
||||||
|
|
||||||
|
WHEN("allocate and deallocate with threads")
|
||||||
|
{
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
|
Vector<std::thread> threads;
|
||||||
|
auto numThreads = 128;
|
||||||
|
threads.reserve(numThreads);
|
||||||
|
auto numNodesPerThread = 2048;
|
||||||
|
|
||||||
|
const std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
|
||||||
|
auto future = now + 200ms;
|
||||||
|
|
||||||
|
for (auto threadID : range(numThreads))
|
||||||
|
{
|
||||||
|
threads.emplace_back(
|
||||||
|
[&]() {
|
||||||
|
std::this_thread::sleep_until(future);
|
||||||
|
|
||||||
|
for (auto i: range(numNodesPerThread))
|
||||||
|
{
|
||||||
|
auto *a = p.allocate();
|
||||||
|
if (!a)
|
||||||
|
abort();
|
||||||
|
|
||||||
|
p.deallocate(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &thread: threads)
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NO_GIVEN("allocator lockfree")
|
||||||
|
{
|
||||||
|
SizeAllocatorPool_lockfree<1, 1> p;
|
||||||
|
|
||||||
|
NO_WHEN("allocate a deallocate and allocate again")
|
||||||
|
{
|
||||||
|
auto num = 10;
|
||||||
|
|
||||||
|
std::set<void *> a0;
|
||||||
|
for (auto i : range(num))
|
||||||
|
{
|
||||||
|
unused(i);
|
||||||
|
a0.insert(p.allocate());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto *a : a0)
|
||||||
|
p.deallocate(a);
|
||||||
|
|
||||||
|
Set<void *> a1;
|
||||||
|
|
||||||
|
for (auto i : range(num))
|
||||||
|
{
|
||||||
|
unused(i);
|
||||||
|
a1.insert(p.allocate());
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(a0 == a1);
|
||||||
|
}
|
||||||
|
|
||||||
|
WHEN("allocate and deallocate with threads")
|
||||||
|
{
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
|
Vector<std::thread> threads;
|
||||||
|
auto numThreads = 128;
|
||||||
|
threads.reserve(numThreads);
|
||||||
|
auto numNodesPerThread = 2048;
|
||||||
|
|
||||||
|
const std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
|
||||||
|
auto future = now + 200ms;
|
||||||
|
|
||||||
|
for (auto threadID : range(numThreads))
|
||||||
|
{
|
||||||
|
threads.emplace_back(
|
||||||
|
[&]() {
|
||||||
|
std::this_thread::sleep_until(future);
|
||||||
|
|
||||||
|
for (auto i: range(numNodesPerThread))
|
||||||
|
{
|
||||||
|
auto *a = p.allocate();
|
||||||
|
if (!a)
|
||||||
|
abort();
|
||||||
|
|
||||||
|
p.deallocate(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &thread: threads)
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace
|
||||||
207
tjp/core/allocator/_tests/Stack.cpp
Executable file
207
tjp/core/allocator/_tests/Stack.cpp
Executable file
@@ -0,0 +1,207 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
#include <tjp/core/allocator/SizeAllocatorPool.hpp>
|
||||||
|
#include <tjp/core/testing/catch.hpp>
|
||||||
|
#include <tjp/core/testing/NO_WHEN.h>
|
||||||
|
|
||||||
|
#include <tjp/core/iterators/range.hpp>
|
||||||
|
#include <tjp/core/containers/Set.hpp>
|
||||||
|
#include <tjp/core/algorithm/unused.hpp>
|
||||||
|
|
||||||
|
#include <tjp/core/containers/Vector.hpp>
|
||||||
|
|
||||||
|
namespace tjp::core::allocator_pool {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
SCENARIO("allocator_pool::Stack")
|
||||||
|
{
|
||||||
|
GIVEN("locking")
|
||||||
|
{
|
||||||
|
using Stack = Stack_locking<void>;
|
||||||
|
using Node = Stack::node_type;
|
||||||
|
Stack p;
|
||||||
|
|
||||||
|
WHEN("allocate and deallocate with threads")
|
||||||
|
{
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
|
Vector<std::thread> threads;
|
||||||
|
threads.reserve(128);
|
||||||
|
|
||||||
|
const std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
|
||||||
|
auto futurePush = now + 200ms;
|
||||||
|
|
||||||
|
auto numThreads = 512;
|
||||||
|
auto numNodesPerThread = 1024;
|
||||||
|
auto totalNodes = numThreads * numNodesPerThread;
|
||||||
|
Vector<Node> memory(totalNodes);
|
||||||
|
|
||||||
|
Atomic<size_t> numPushed = 0;
|
||||||
|
|
||||||
|
for (auto threadID : range(numThreads))
|
||||||
|
{
|
||||||
|
threads.emplace_back(
|
||||||
|
[&, id=threadID]() {
|
||||||
|
Node *nodes = memory.data() + (id * numNodesPerThread);
|
||||||
|
|
||||||
|
std::this_thread::sleep_until(futurePush);
|
||||||
|
|
||||||
|
for (auto i: range(numNodesPerThread))
|
||||||
|
{
|
||||||
|
p.push(&nodes[i]);
|
||||||
|
numPushed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &thread: threads)
|
||||||
|
thread.join();
|
||||||
|
|
||||||
|
threads.clear();
|
||||||
|
|
||||||
|
auto size = p.size_not_thread_safe();
|
||||||
|
REQUIRE(numPushed == size);
|
||||||
|
REQUIRE(size == totalNodes);
|
||||||
|
|
||||||
|
WHEN("the nodes are popped")
|
||||||
|
{
|
||||||
|
const std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
|
||||||
|
auto futurePop = now + 200ms;
|
||||||
|
Atomic<size_t> numPopped = 0;
|
||||||
|
|
||||||
|
Vector<Node *> popped(totalNodes);
|
||||||
|
|
||||||
|
for (auto threadID : range(numThreads))
|
||||||
|
{
|
||||||
|
threads.emplace_back(
|
||||||
|
[&, id=threadID]() {
|
||||||
|
Node **popped_ = popped.data () + (id * numNodesPerThread);
|
||||||
|
|
||||||
|
std::this_thread::sleep_until(futurePop);
|
||||||
|
|
||||||
|
for (auto i : range(numNodesPerThread))
|
||||||
|
{
|
||||||
|
popped_[i] = p.pop();
|
||||||
|
numPopped++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &thread: threads)
|
||||||
|
thread.join();
|
||||||
|
|
||||||
|
threads.clear();
|
||||||
|
|
||||||
|
auto size = p.size_not_thread_safe();
|
||||||
|
REQUIRE(numPopped == totalNodes);
|
||||||
|
REQUIRE(size == 0);
|
||||||
|
|
||||||
|
THEN("the number of unique nodes matches")
|
||||||
|
{
|
||||||
|
Set<Node *> unique(popped.begin(), popped.end());
|
||||||
|
|
||||||
|
REQUIRE(unique.size() == totalNodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NO_GIVEN("allocator lockfree")
|
||||||
|
{
|
||||||
|
using Stack = Stack_lockfree<void>;
|
||||||
|
using Node = Stack::node_type;
|
||||||
|
Stack p;
|
||||||
|
|
||||||
|
WHEN("allocate and deallocate with threads")
|
||||||
|
{
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
|
Vector<std::thread> threads;
|
||||||
|
threads.reserve(128);
|
||||||
|
|
||||||
|
const std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
|
||||||
|
auto futurePush = now + 200ms;
|
||||||
|
|
||||||
|
auto numThreads = 512;
|
||||||
|
auto numNodesPerThread = 1024;
|
||||||
|
auto totalNodes = numThreads * numNodesPerThread;
|
||||||
|
Vector<Node> memory(totalNodes);
|
||||||
|
|
||||||
|
Atomic<size_t> numPushed = 0;
|
||||||
|
|
||||||
|
for (auto threadID : range(numThreads))
|
||||||
|
{
|
||||||
|
threads.emplace_back(
|
||||||
|
[&, id=threadID]() {
|
||||||
|
Node *nodes = memory.data() + (id * numNodesPerThread);
|
||||||
|
|
||||||
|
std::this_thread::sleep_until(futurePush);
|
||||||
|
|
||||||
|
for (auto i: range(numNodesPerThread))
|
||||||
|
{
|
||||||
|
p.push(&nodes[i]);
|
||||||
|
numPushed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &thread: threads)
|
||||||
|
thread.join();
|
||||||
|
|
||||||
|
threads.clear();
|
||||||
|
|
||||||
|
auto size = p.size_not_thread_safe();
|
||||||
|
REQUIRE(numPushed == size);
|
||||||
|
REQUIRE(size == totalNodes);
|
||||||
|
|
||||||
|
WHEN("the nodes are popped")
|
||||||
|
{
|
||||||
|
const std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
|
||||||
|
auto futurePop = now + 200ms;
|
||||||
|
Atomic<size_t> numPopped = 0;
|
||||||
|
|
||||||
|
Vector<Node *> popped(totalNodes);
|
||||||
|
|
||||||
|
for (auto threadID : range(numThreads))
|
||||||
|
{
|
||||||
|
threads.emplace_back(
|
||||||
|
[&, id=threadID]() {
|
||||||
|
Node **popped_ = popped.data () + (id * numNodesPerThread);
|
||||||
|
|
||||||
|
std::this_thread::sleep_until(futurePop);
|
||||||
|
|
||||||
|
for (auto i : range(numNodesPerThread))
|
||||||
|
{
|
||||||
|
popped_[i] = p.pop();
|
||||||
|
numPopped++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &thread: threads)
|
||||||
|
thread.join();
|
||||||
|
|
||||||
|
threads.clear();
|
||||||
|
|
||||||
|
auto size = p.size_not_thread_safe();
|
||||||
|
REQUIRE(numPopped == totalNodes);
|
||||||
|
REQUIRE(size == 0);
|
||||||
|
|
||||||
|
THEN("the number of unique nodes matches")
|
||||||
|
{
|
||||||
|
Set<Node *> unique(popped.begin(), popped.end());
|
||||||
|
|
||||||
|
REQUIRE(unique.size() == totalNodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace
|
||||||
179
tjp/core/allocator/_tests/StrongAllocator.hpp
Normal file
179
tjp/core/allocator/_tests/StrongAllocator.hpp
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
#include <tjp/core/ptr/Ptr.hpp>
|
||||||
|
#include <tjp/core/ptr/Ptr+IO.h>
|
||||||
|
|
||||||
|
#include <tjp/core/testing/catch.hpp>
|
||||||
|
#include <tjp/core/testing/NO_WHEN.h>
|
||||||
|
|
||||||
|
//#include "std/CustomControlBlock.h"
|
||||||
|
#include <tjp/core/allocator/StrongAllocator.hpp>
|
||||||
|
|
||||||
|
namespace tjp::core::allocator {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct A
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
~A ()
|
||||||
|
{
|
||||||
|
i = 2;
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
struct B
|
||||||
|
{
|
||||||
|
static int allocations;
|
||||||
|
int x = 5;
|
||||||
|
B () {
|
||||||
|
allocations++;
|
||||||
|
}
|
||||||
|
~B () {
|
||||||
|
allocations--;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int B::allocations = 0;
|
||||||
|
|
||||||
|
int num_c_deallocations = 0;
|
||||||
|
int num_c_destroys = 0;
|
||||||
|
|
||||||
|
struct C
|
||||||
|
{
|
||||||
|
int x= 5;
|
||||||
|
|
||||||
|
~C ()
|
||||||
|
{
|
||||||
|
num_c_destroys++;
|
||||||
|
x = 2;
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
void on_deallocate(C *p)
|
||||||
|
{
|
||||||
|
num_c_deallocations++;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CustomDeleter : StrongThis<CustomDeleter>
|
||||||
|
{
|
||||||
|
int called = 0;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void deallocate(T *t)
|
||||||
|
{
|
||||||
|
called++;
|
||||||
|
delete t;
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
SCENARIO("core::allocator::ptr")
|
||||||
|
{
|
||||||
|
GIVEN("a ptr to normal")
|
||||||
|
{
|
||||||
|
WHEN("a ptr is created normal")
|
||||||
|
{
|
||||||
|
B::allocations = 0;
|
||||||
|
|
||||||
|
auto ptr = strong<B>();
|
||||||
|
REQUIRE(B::allocations == 1);
|
||||||
|
ptr = nullptr;
|
||||||
|
|
||||||
|
REQUIRE(B::allocations == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
GIVEN("a ptr")
|
||||||
|
{
|
||||||
|
WHEN("a ptr is created normal")
|
||||||
|
{
|
||||||
|
num_c_deallocations = num_c_destroys = 0;
|
||||||
|
|
||||||
|
auto ptr = strong<C>();
|
||||||
|
ptr = nullptr;
|
||||||
|
|
||||||
|
REQUIRE(num_c_deallocations == 1);
|
||||||
|
REQUIRE(num_c_destroys == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
WHEN("a ptr is created with a custom deleter")
|
||||||
|
{
|
||||||
|
CustomDeleter deleter;
|
||||||
|
|
||||||
|
num_c_deallocations = num_c_destroys = 0;
|
||||||
|
|
||||||
|
auto ptr = strong_with_delete<C>(
|
||||||
|
new C(), [&](C *t) { deleter.deallocate(t); }
|
||||||
|
);
|
||||||
|
ptr = nullptr;
|
||||||
|
|
||||||
|
REQUIRE(num_c_deallocations == 1);
|
||||||
|
REQUIRE(num_c_destroys == 1);
|
||||||
|
REQUIRE(deleter.called == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
WHEN("create a pointer with custom allcoator")
|
||||||
|
{
|
||||||
|
typedef AllocatorPool<C> Allocator;
|
||||||
|
|
||||||
|
num_c_deallocations = num_c_destroys = 0;
|
||||||
|
|
||||||
|
auto ptr = strong_with_allocator<C>(Allocator());
|
||||||
|
ptr = nullptr;
|
||||||
|
|
||||||
|
REQUIRE(num_c_deallocations == 1);
|
||||||
|
REQUIRE(num_c_destroys == 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GIVEN("a ptr with a custom deleter")
|
||||||
|
{
|
||||||
|
CustomDeleter deleter;
|
||||||
|
|
||||||
|
WHEN("create a pointer")
|
||||||
|
{
|
||||||
|
auto a = strong_with_delete<A>(
|
||||||
|
new A(), [&](A *t) { deleter.deallocate(t); }
|
||||||
|
);
|
||||||
|
|
||||||
|
WHEN("transfer the pointer elsewherez")
|
||||||
|
{
|
||||||
|
auto b = a;
|
||||||
|
a = nullptr;
|
||||||
|
|
||||||
|
WHEN("nullify the pointer")
|
||||||
|
{
|
||||||
|
b = nullptr;
|
||||||
|
|
||||||
|
REQUIRE(deleter.called == 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GIVEN("a ptr with an allocator")
|
||||||
|
{
|
||||||
|
WHEN("create a pointer")
|
||||||
|
{
|
||||||
|
typedef AllocatorPool<A> Allocator;
|
||||||
|
|
||||||
|
auto a = strong_with_allocator<A>(Allocator());
|
||||||
|
|
||||||
|
WHEN("transfer the pointer elsewherez")
|
||||||
|
{
|
||||||
|
auto b = a;
|
||||||
|
a = nullptr;
|
||||||
|
|
||||||
|
WHEN("nullify the pointer")
|
||||||
|
{
|
||||||
|
b = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace
|
||||||
55
tjp/core/allocator/_tests/VectorPool.cpp
Executable file
55
tjp/core/allocator/_tests/VectorPool.cpp
Executable file
@@ -0,0 +1,55 @@
|
|||||||
|
// TJP COPYRIGHT HEADER
|
||||||
|
|
||||||
|
#include <tjp/core/allocator/VectorPool.hpp>
|
||||||
|
#include <tjp/core/testing/catch.hpp>
|
||||||
|
#include <tjp/core/iterators/range.hpp>
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#include <tjp/core/log/Log.h>
|
||||||
|
#include <tjp/core/log/LogOf.h>
|
||||||
|
|
||||||
|
namespace tjp::core::vectorpool {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using MyVector = std::vector<T, Allocator<T>>;
|
||||||
|
|
||||||
|
SCENARIO("vectorpool" )
|
||||||
|
{
|
||||||
|
xLogActivateStory("core::vectorpool");
|
||||||
|
|
||||||
|
MyVector<int> myVec;
|
||||||
|
|
||||||
|
GIVEN("scales")
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 256; ++i) {
|
||||||
|
sLogTest("testing", logVar(i) << logVar(scale(i)) << logVar(unscale(scale(i))));
|
||||||
|
|
||||||
|
auto s = scale(i);
|
||||||
|
auto u = unscale(s);
|
||||||
|
|
||||||
|
// REQUIRE(u >= i);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
GIVEN("some numbers")
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 1024; ++i) {
|
||||||
|
myVec.push_back(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
sLogDebug("testing", logVar(myVec));
|
||||||
|
}
|
||||||
|
|
||||||
|
GIVEN("a move")
|
||||||
|
{
|
||||||
|
MyVector<int> b;
|
||||||
|
b = std::move(myVec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace
|
||||||
20
tjp/core/allocator/prune/Data.hpp
Executable file
20
tjp/core/allocator/prune/Data.hpp
Executable file
@@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* legal header
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <tjp/core/types/Types.h>
|
||||||
|
|
||||||
|
namespace tjp::core::allocator_pool {
|
||||||
|
namespace prune {
|
||||||
|
|
||||||
|
struct Data
|
||||||
|
{
|
||||||
|
size_t id = 0;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
20
tjp/core/allocator/prune/Executor.hpp
Executable file
20
tjp/core/allocator/prune/Executor.hpp
Executable file
@@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* legal header
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace tjp::core::allocator_pool::prune {
|
||||||
|
|
||||||
|
struct Registry;
|
||||||
|
|
||||||
|
struct Executor
|
||||||
|
{
|
||||||
|
virtual ~Executor() {}
|
||||||
|
virtual void start(Registry *) {}
|
||||||
|
virtual void stop(Registry *) {}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
49
tjp/core/allocator/prune/ExecutorManual.hpp
Executable file
49
tjp/core/allocator/prune/ExecutorManual.hpp
Executable file
@@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* legal header
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Registry.hpp"
|
||||||
|
#include "Executor.hpp"
|
||||||
|
#include <tjp/core/assert/debug_assert.h>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
namespace tjp::core::allocator_pool::prune {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct ExecutorManual : Executor
|
||||||
|
{
|
||||||
|
T algorithm;
|
||||||
|
Registry *registry = nullptr;
|
||||||
|
|
||||||
|
template<typename ...Args>
|
||||||
|
ExecutorManual(Args&& ...args) :
|
||||||
|
algorithm(std::forward<Args>(args)...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void start(Registry *registry_) override
|
||||||
|
{
|
||||||
|
registry = registry_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop(Registry *registry_) override
|
||||||
|
{
|
||||||
|
debug_assert(registry == registry_);
|
||||||
|
registry = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cycle ()
|
||||||
|
{
|
||||||
|
auto lock = lock_of(registry->mutex);
|
||||||
|
for (auto prunable : registry->prunables)
|
||||||
|
{
|
||||||
|
algorithm.cycle(prunable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
71
tjp/core/allocator/prune/ExecutorThreaded.hpp
Executable file
71
tjp/core/allocator/prune/ExecutorThreaded.hpp
Executable file
@@ -0,0 +1,71 @@
|
|||||||
|
/**
|
||||||
|
* legal header
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Registry.hpp"
|
||||||
|
#include "Executor.hpp"
|
||||||
|
#include <tjp/core/assert/debug_assert.h>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
namespace tjp::core::allocator_pool::prune {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct ExecutorThreaded : Executor
|
||||||
|
{
|
||||||
|
T algorithm;
|
||||||
|
Registry *registry = nullptr;
|
||||||
|
|
||||||
|
template<typename ...Args>
|
||||||
|
ExecutorThreaded(Args&& ...args) :
|
||||||
|
algorithm(std::forward<Args>(args)...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void start(Registry *registry_) override
|
||||||
|
{
|
||||||
|
ended = false;
|
||||||
|
|
||||||
|
registry = registry_;
|
||||||
|
executor = std::thread([this]() {
|
||||||
|
run();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop(Registry *registry_) override
|
||||||
|
{
|
||||||
|
ended = true;
|
||||||
|
|
||||||
|
debug_assert(registry == registry_);
|
||||||
|
registry = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::thread executor;
|
||||||
|
bool ended = false;
|
||||||
|
int delayMS = 1000;
|
||||||
|
|
||||||
|
void run()
|
||||||
|
{
|
||||||
|
while (!ended)
|
||||||
|
{
|
||||||
|
if (registry)
|
||||||
|
cycle();
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(delayMS));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cycle ()
|
||||||
|
{
|
||||||
|
auto lock = lock_of(registry->mutex);
|
||||||
|
for (auto prunable : registry->prunables)
|
||||||
|
{
|
||||||
|
algorithm.cycle(prunable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
24
tjp/core/allocator/prune/Prunable.hpp
Executable file
24
tjp/core/allocator/prune/Prunable.hpp
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* legal header
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Data.hpp"
|
||||||
|
#include "../Size.h"
|
||||||
|
|
||||||
|
namespace tjp::core::allocator_pool {
|
||||||
|
namespace prune {
|
||||||
|
|
||||||
|
struct Prunable
|
||||||
|
{
|
||||||
|
Data *pruneData = nullptr;
|
||||||
|
|
||||||
|
virtual const Size &getSize() = 0;
|
||||||
|
virtual void prune() = 0;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
60
tjp/core/allocator/prune/Pruning.hpp
Executable file
60
tjp/core/allocator/prune/Pruning.hpp
Executable file
@@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* legal header
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Prunable.hpp"
|
||||||
|
#include "Registry.hpp"
|
||||||
|
#include <tjp/core/threads/Lock.hpp>
|
||||||
|
#include <tjp/core/algorithm/vector_erase_if_value.hpp>
|
||||||
|
|
||||||
|
namespace tjp::core::allocator_pool {
|
||||||
|
namespace prune {
|
||||||
|
|
||||||
|
template<typename A>
|
||||||
|
struct Pruning : Prunable
|
||||||
|
{
|
||||||
|
A allocator;
|
||||||
|
using value_type = typename A::value_type;
|
||||||
|
|
||||||
|
template<typename _Tp1> struct rebind { typedef Pruning<_Tp1> other; };
|
||||||
|
|
||||||
|
template<typename ...Args>
|
||||||
|
Pruning(Args&& ...args) :
|
||||||
|
allocator(std::forward<Args>(args)...)
|
||||||
|
{
|
||||||
|
Registry::shared()->insert(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~Pruning()
|
||||||
|
{
|
||||||
|
Registry::shared()->erase(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
value_type *allocate ()
|
||||||
|
{
|
||||||
|
return allocator.allocate();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U>
|
||||||
|
void deallocate (U *t)
|
||||||
|
{
|
||||||
|
return allocator.deallocate(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Size &getSize() override
|
||||||
|
{
|
||||||
|
return allocator.getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void prune() override
|
||||||
|
{
|
||||||
|
allocator.prune();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
19
tjp/core/allocator/prune/Registry.cpp
Executable file
19
tjp/core/allocator/prune/Registry.cpp
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* legal header
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Registry.hpp"
|
||||||
|
|
||||||
|
namespace tjp::core::allocator_pool {
|
||||||
|
namespace prune {
|
||||||
|
|
||||||
|
Registry *Registry::shared()
|
||||||
|
{
|
||||||
|
static Registry *registry = new Registry();
|
||||||
|
return registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
52
tjp/core/allocator/prune/Registry.hpp
Executable file
52
tjp/core/allocator/prune/Registry.hpp
Executable file
@@ -0,0 +1,52 @@
|
|||||||
|
/**
|
||||||
|
* legal header
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Prunable.hpp"
|
||||||
|
#include "Executor.hpp"
|
||||||
|
|
||||||
|
#include <tjp/core/threads/Lock.hpp>
|
||||||
|
#include <tjp/core/algorithm/vector_erase_if_value.hpp>
|
||||||
|
#include <tjp/core/containers/Vector.h>
|
||||||
|
|
||||||
|
namespace tjp::core::allocator_pool {
|
||||||
|
namespace prune {
|
||||||
|
|
||||||
|
struct Registry
|
||||||
|
{
|
||||||
|
Executor *executor = nullptr;
|
||||||
|
|
||||||
|
Mutex mutex;
|
||||||
|
Vector<Prunable *> prunables;
|
||||||
|
|
||||||
|
void insert(Prunable *p)
|
||||||
|
{
|
||||||
|
auto lock = lock_of(mutex);
|
||||||
|
prunables.push_back(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void erase(Prunable *p)
|
||||||
|
{
|
||||||
|
auto lock = lock_of(mutex);
|
||||||
|
vector_erase_if_value(prunables, [p](auto *v) { return v == p; });
|
||||||
|
}
|
||||||
|
|
||||||
|
void setAlgorithm(Executor *executor_)
|
||||||
|
{
|
||||||
|
if (executor)
|
||||||
|
executor->stop(this);
|
||||||
|
|
||||||
|
executor = executor_;
|
||||||
|
executor->start(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Registry *shared();
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
64
tjp/core/allocator/prune/_tests/Pruning.cpp
Executable file
64
tjp/core/allocator/prune/_tests/Pruning.cpp
Executable file
@@ -0,0 +1,64 @@
|
|||||||
|
/**
|
||||||
|
* legal header
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <tjp/core/allocator/prune/Pruning.hpp>
|
||||||
|
#include <tjp/core/allocator/prune/Registry.hpp>
|
||||||
|
#include <tjp/core/allocator/prune/ExecutorManual.hpp>
|
||||||
|
#include <tjp/core/allocator/prune/algorithm/Averaging.hpp>
|
||||||
|
#include <tjp/core/testing/catch.hpp>
|
||||||
|
|
||||||
|
#include <tjp/core/iterators/range.hpp>
|
||||||
|
#include <tjp/core/containers/Set.hpp>
|
||||||
|
#include <tjp/core/algorithm/unused.hpp>
|
||||||
|
#include <tjp/core/allocator/ClassAllocatorPool.hpp>
|
||||||
|
|
||||||
|
namespace tjp::core::allocator_pool::prune {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
|
||||||
|
SCENARIO("core::allocator_pool::prune::Pruning")
|
||||||
|
{
|
||||||
|
GIVEN("allocator")
|
||||||
|
{
|
||||||
|
auto *pruneExecutor = new ExecutorManual<algorithm::Averaging>(50, 1.4);
|
||||||
|
Registry::shared()->setAlgorithm(pruneExecutor);
|
||||||
|
|
||||||
|
Pruning<ClassAllocatorPool<int>> p;
|
||||||
|
auto &size = p.getSize();
|
||||||
|
|
||||||
|
WHEN("allocate a deallocate and allocate again")
|
||||||
|
{
|
||||||
|
auto num = 100;
|
||||||
|
|
||||||
|
std::set<int *> a0;
|
||||||
|
for (auto i : range(num))
|
||||||
|
{
|
||||||
|
unused(i);
|
||||||
|
a0.insert(p.allocate());
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(size.freed == 0);
|
||||||
|
REQUIRE(size.used == num);
|
||||||
|
|
||||||
|
for (auto _: range(100))
|
||||||
|
pruneExecutor->cycle();
|
||||||
|
|
||||||
|
for (auto *a : a0)
|
||||||
|
p.deallocate(a);
|
||||||
|
|
||||||
|
REQUIRE(size.used == 0);
|
||||||
|
REQUIRE(size.freed == num);
|
||||||
|
|
||||||
|
|
||||||
|
for (auto _: range(100))
|
||||||
|
pruneExecutor->cycle();
|
||||||
|
|
||||||
|
REQUIRE(size.used == 0);
|
||||||
|
REQUIRE(size.freed < num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace
|
||||||
96
tjp/core/allocator/prune/algorithm/Averaging.hpp
Executable file
96
tjp/core/allocator/prune/algorithm/Averaging.hpp
Executable file
@@ -0,0 +1,96 @@
|
|||||||
|
/**
|
||||||
|
* legal header
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../Data.hpp"
|
||||||
|
#include "../../Size.hpp"
|
||||||
|
|
||||||
|
#include <tjp/core/log/Log.h>
|
||||||
|
#include <tjp/core/log/LogOf.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace tjp::core::allocator_pool::prune::algorithm {
|
||||||
|
|
||||||
|
struct AverageData : Data
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Real = double;
|
||||||
|
Real windowSize;
|
||||||
|
Real m;
|
||||||
|
|
||||||
|
Real averageUsed = 0;
|
||||||
|
size_t threshold = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const size_t ID = 0xABCD;
|
||||||
|
|
||||||
|
AverageData(size_t windowSize_, float m_) :
|
||||||
|
windowSize(windowSize_),
|
||||||
|
m(m_)
|
||||||
|
{
|
||||||
|
id = ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sample (size_t freed, size_t used)
|
||||||
|
{
|
||||||
|
if (used > averageUsed)
|
||||||
|
averageUsed = used;
|
||||||
|
else
|
||||||
|
averageUsed -= (averageUsed - used) / windowSize;
|
||||||
|
|
||||||
|
threshold = std::max((size_t)averageUsed, used);
|
||||||
|
threshold = std::round(m * threshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool shouldPrune(size_t freed, size_t used)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
freed > 0 &&
|
||||||
|
used + freed > threshold;
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
struct Averaging
|
||||||
|
{
|
||||||
|
using Real = double;
|
||||||
|
|
||||||
|
size_t windowSize;
|
||||||
|
Real m;
|
||||||
|
|
||||||
|
Averaging(size_t windowSize_, Real m_) :
|
||||||
|
windowSize(windowSize_),
|
||||||
|
m(m_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void cycle(Prunable *pool)
|
||||||
|
{
|
||||||
|
if (!pool->pruneData || pool->pruneData->id != AverageData::ID)
|
||||||
|
{
|
||||||
|
delete pool->pruneData;
|
||||||
|
pool->pruneData = new AverageData(windowSize, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto data = (AverageData *)pool->pruneData;
|
||||||
|
|
||||||
|
auto &size = pool->getSize();
|
||||||
|
data->sample(size.freed, size.used);
|
||||||
|
|
||||||
|
auto pruned = 0;
|
||||||
|
while (data->shouldPrune(size.freed, size.used))
|
||||||
|
{
|
||||||
|
pool->prune();
|
||||||
|
pruned++;
|
||||||
|
}
|
||||||
|
|
||||||
|
sLogDebugIf((size.freed + size.used > 0), "core::allocator_pool", logVar(pool) << logVar(size.freed) << logVar(size.used) << logVar(data->averageUsed) << logVar(data->threshold) << logVar(pruned));
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
23
tjp/core/allocator/prune/algorithm/None.hpp
Executable file
23
tjp/core/allocator/prune/algorithm/None.hpp
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* legal header
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AllocatorPoolPrunable.hpp"
|
||||||
|
|
||||||
|
namespace tjp::core::allocator_pool {
|
||||||
|
namespace algorithm {
|
||||||
|
|
||||||
|
struct None
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void cycle(AllocatorPoolPrunable *)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
129
tjp/core/allocator/remove/SizeAllocatorPool_locking.hpp
Executable file
129
tjp/core/allocator/remove/SizeAllocatorPool_locking.hpp
Executable file
@@ -0,0 +1,129 @@
|
|||||||
|
/**
|
||||||
|
* legal header
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../threads/Lock.hpp"
|
||||||
|
#include "Size.hpp"
|
||||||
|
|
||||||
|
namespace tjp::core::allocator_pool {
|
||||||
|
namespace sizeallocatorpool_locking {
|
||||||
|
|
||||||
|
template<size_t allocationSize, size_t alignment, typename C=void>
|
||||||
|
class SizeAllocatorPool
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Allocation
|
||||||
|
{
|
||||||
|
char t[allocationSize];
|
||||||
|
Allocation *next;
|
||||||
|
} __attribute__ ((aligned(alignment)));
|
||||||
|
|
||||||
|
typedef Mutex MutexT;
|
||||||
|
static constexpr size_t multiples = 1;
|
||||||
|
|
||||||
|
private:
|
||||||
|
MutexT mutex;
|
||||||
|
Allocation *head = nullptr;
|
||||||
|
|
||||||
|
Size size;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SizeAllocatorPool ()
|
||||||
|
{
|
||||||
|
static_assert(offsetof(Allocation, t) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
~SizeAllocatorPool ()
|
||||||
|
{
|
||||||
|
while (head)
|
||||||
|
{
|
||||||
|
auto a = pop();
|
||||||
|
|
||||||
|
if (a)
|
||||||
|
delete a;
|
||||||
|
}
|
||||||
|
|
||||||
|
size.used = size.freed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Allocation *pop()
|
||||||
|
{
|
||||||
|
auto lock = lock_of(mutex);
|
||||||
|
|
||||||
|
Allocation *a = head;
|
||||||
|
if (a != nullptr)
|
||||||
|
head = a->next;
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void push(Allocation *a)
|
||||||
|
{
|
||||||
|
auto lock = lock_of(mutex);
|
||||||
|
|
||||||
|
a->next = head;
|
||||||
|
head = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *allocate ()
|
||||||
|
{
|
||||||
|
// sLogDebug("debug", logVar(allocationSize) << logVar(alignment));
|
||||||
|
|
||||||
|
auto a = pop();
|
||||||
|
if (a)
|
||||||
|
{
|
||||||
|
size.used++;
|
||||||
|
size.freed--;
|
||||||
|
|
||||||
|
return (void *)&a->t;
|
||||||
|
}
|
||||||
|
|
||||||
|
size.used++;
|
||||||
|
|
||||||
|
auto allocation = new Allocation();
|
||||||
|
return &allocation->t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate(void *o)
|
||||||
|
{
|
||||||
|
// sLogDebug("debug", logVar(allocationSize) << logVar(alignment));
|
||||||
|
|
||||||
|
if (!o)
|
||||||
|
return;
|
||||||
|
|
||||||
|
static_assert(offsetof(Allocation, t) == 0);
|
||||||
|
|
||||||
|
auto allocation = (Allocation *)o;
|
||||||
|
|
||||||
|
push(allocation);
|
||||||
|
|
||||||
|
size.used--;
|
||||||
|
size.freed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Size &getSize ()
|
||||||
|
{
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void prune()
|
||||||
|
{
|
||||||
|
auto lock = lock_of(mutex);
|
||||||
|
|
||||||
|
if (head)
|
||||||
|
{
|
||||||
|
auto next = head->next;
|
||||||
|
delete head;
|
||||||
|
|
||||||
|
head = next;
|
||||||
|
size.freed--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user