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