aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2024-02-14 14:10:27 -0500
committerLibravatar vnugent <public@vaughnnugent.com>2024-02-14 14:10:27 -0500
commit2b1314c1475e7e1831c691cf349cb89c66fa320c (patch)
tree091fc132a2bee2e79a68d8c6d5eb20f1d989a3d2 /lib
parentf4e4db7c5320976406feb252ae8f8bdbe9b3e351 (diff)
Squashed commit of the following:
commit ddd8a651b6eb43cfdd49d84056f8b9c34b543992 Author: vnugent <public@vaughnnugent.com> Date: Wed Feb 14 00:15:50 2024 -0500 ci: reduce output noise and update Argon2 build commit cf942959ff2feea03d3eda2ff2a263bdac4d6bc6 Author: vnugent <public@vaughnnugent.com> Date: Mon Feb 12 18:39:18 2024 -0500 chore: update packages and minor fixes commit ab506af9e2de2876b11bb45b3c7e787616c80155 Author: vnugent <public@vaughnnugent.com> Date: Fri Feb 9 21:27:24 2024 -0500 fix: patch and update core runtime service injection commit 7ed5e8b19164c28d3a238bd56878d2161fbea2e4 Author: vnugent <public@vaughnnugent.com> Date: Thu Feb 8 18:26:11 2024 -0500 fork dotnetplugins and make some intial updates/upgrades commit f4cab88d67be5da0953b14bd46fc972d4acc8606 Author: vnugent <public@vaughnnugent.com> Date: Thu Feb 8 12:16:13 2024 -0500 update some heap api functions commit 6035bf7ed8412f1da361cc5feddd860abfaf4fc1 Author: vnugent <public@vaughnnugent.com> Date: Wed Feb 7 22:09:11 2024 -0500 working file-watcher notifications/rework commit 698f8edf694ad9700ee2ce2220e692b496448ff9 Author: vnugent <public@vaughnnugent.com> Date: Wed Feb 7 20:37:28 2024 -0500 remove mem-template and add file-watcher utility commit b17591e0fb363222fcd7d93c2bad4ab1b102385f Author: vnugent <public@vaughnnugent.com> Date: Wed Feb 7 18:28:21 2024 -0500 add small memmove support for known small blocks commit 631be4d4b27fdbcd4b0526e17a128bb0d86911eb Author: vnugent <public@vaughnnugent.com> Date: Wed Feb 7 18:08:02 2024 -0500 setup some readonly ref arguments and convert copy apis to readonly refs commit 2ba8dec68d5cb192e61ad0141d4b460076d3f90a Author: vnugent <public@vaughnnugent.com> Date: Mon Feb 5 18:30:38 2024 -0500 restructure internal memmove strategies commit 25cf02872da980893ad7fb51d4eccc932380582b Author: vnugent <public@vaughnnugent.com> Date: Sun Feb 4 01:29:18 2024 -0500 add http stream interface, profiling -> file read updates commit 757668c44e78864dc69d5713a2cfba6db2ed9a2a Author: vnugent <public@vaughnnugent.com> Date: Fri Feb 2 14:27:04 2024 -0500 streamline data-copy api with proper large block support and net8 feature updates commit f22c1765fd72ab40a10d8ec92a8cb6d9ec1b1a04 Author: vnugent <public@vaughnnugent.com> Date: Mon Jan 29 16:16:23 2024 -0500 check for compression lib updates to close #2 and fix some ci build stuff commit f974bfdef6a795b4a1c04602502ef506ef2587a9 Author: vnugent <public@vaughnnugent.com> Date: Tue Jan 23 17:36:17 2024 -0500 switch allocator libs to lgpl2.1 commit 1fe5e01b329cd27b675000f1a557b784d3c88b56 Author: vnugent <public@vaughnnugent.com> Date: Tue Jan 23 17:05:59 2024 -0500 consolidate allocator packages and close #1 commit 74e1107e522f00b670526193396217f40a6bade7 Author: vnugent <public@vaughnnugent.com> Date: Tue Jan 23 15:43:40 2024 -0500 cache extension api tweaks commit 96ca2b0388a6326b9bb74f3ab2f62eaede6681e0 Author: vnugent <public@vaughnnugent.com> Date: Mon Jan 22 17:54:23 2024 -0500 explicit tcp server args reuse
Diffstat (limited to 'lib')
-rw-r--r--lib/Hashing.Portable/src/IdentityUtility/HashingExtensions.cs61
-rw-r--r--lib/Hashing.Portable/src/IdentityUtility/JsonWebKey.cs4
-rw-r--r--lib/Hashing.Portable/src/IdentityUtility/JsonWebToken.cs81
-rw-r--r--lib/Hashing.Portable/src/IdentityUtility/JwtExtensions.cs71
-rw-r--r--lib/Hashing.Portable/src/IdentityUtility/ReadOnlyJsonWebKey.cs2
-rw-r--r--lib/Hashing.Portable/src/ManagedHash.cs36
-rw-r--r--lib/Hashing.Portable/src/Native/MonoCypher/IHashStream.cs4
-rw-r--r--lib/Hashing.Portable/src/Native/MonoCypher/IHmacStream.cs4
-rw-r--r--lib/Hashing.Portable/src/Native/MonoCypher/MCBlake2Module.cs39
-rw-r--r--lib/Hashing.Portable/src/Native/MonoCypher/MCHashingStreamExtensions.cs73
-rw-r--r--lib/Hashing.Portable/src/Native/MonoCypher/MCPasswordModule.cs20
-rw-r--r--lib/Hashing.Portable/src/Native/MonoCypher/MonoCypherLibrary.cs14
-rw-r--r--lib/Hashing.Portable/tests/ManagedHashTests.cs31
-rw-r--r--lib/Hashing.Portable/tests/VNLib.Hashing.PortableTests.csproj6
-rw-r--r--lib/Net.Compression/VNLib.Net.Compression/LibraryWrapper.cs16
-rw-r--r--lib/Net.Compression/VNLib.Net.CompressionTests/VNLib.Net.CompressionTests.csproj6
-rw-r--r--lib/Net.Compression/vnlib_compress/CMakeLists.txt3
-rw-r--r--lib/Net.Compression/vnlib_compress/Taskfile.yaml54
-rw-r--r--lib/Net.Compression/vnlib_compress/compression.c22
-rw-r--r--lib/Net.Compression/vnlib_compress/compression.h69
-rw-r--r--lib/Net.Compression/vnlib_compress/feature_brotli.c8
-rw-r--r--lib/Net.Compression/vnlib_compress/feature_zlib.c6
-rw-r--r--lib/Net.Compression/vnlib_compress/util.h91
-rw-r--r--lib/Net.Http/src/Core/Buffering/HttpBufferElement.cs16
-rw-r--r--lib/Net.Http/src/Core/HttpEncodedSegment.cs9
-rw-r--r--lib/Net.Http/src/Core/HttpEvent.cs34
-rw-r--r--lib/Net.Http/src/Core/InitDataBuffer.cs24
-rw-r--r--lib/Net.Http/src/Core/Response/ChunkDataAccumulator.cs30
-rw-r--r--lib/Net.Http/src/Core/Response/ResponseWriter.cs253
-rw-r--r--lib/Net.Http/src/Core/TransportReader.cs49
-rw-r--r--lib/Net.Http/src/IHttpEvent.cs14
-rw-r--r--lib/Net.Http/src/IHttpStreamResponse.cs44
-rw-r--r--lib/Net.Messaging.FBM/src/Client/FBMBuffer.cs21
-rw-r--r--lib/Net.Messaging.FBM/src/Client/FBMClient.cs18
-rw-r--r--lib/Net.Messaging.FBM/src/Client/FBMRequest.cs26
-rw-r--r--lib/Net.Messaging.FBM/src/Client/FBMResponse.cs4
-rw-r--r--lib/Net.Messaging.FBM/src/FBMMessageHeader.cs13
-rw-r--r--lib/Net.Messaging.FBM/src/Server/FBMListener.cs47
-rw-r--r--lib/Net.Transport.SimpleTCP/src/AwaitableAsyncServerSocket.cs27
-rw-r--r--lib/Net.Transport.SimpleTCP/src/SocketPipeLineWorker.cs18
-rw-r--r--lib/Net.Transport.SimpleTCP/src/TcpServer.cs22
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/HttpServiceStackBuilder.cs2
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/IAccountSecUpdateable.cs44
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/IRuntimeServiceInjection.cs49
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/SsBuilderExtensions.cs169
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/HttpServiceStack.cs9
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/PluginExtensions.cs11
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/PluginManager.cs23
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/PluginRutimeEventHandler.cs (renamed from lib/Plugins.Essentials.ServiceStack/src/PluginLoadEventListener.cs)10
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/PluginStackInitializer.cs30
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/ServiceDomain.cs9
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/ServiceGroup.cs29
-rw-r--r--lib/Plugins.Essentials/src/Accounts/AccountUtils.cs43
-rw-r--r--lib/Plugins.Essentials/src/Content/DirectFileStream.cs120
-rw-r--r--lib/Plugins.Essentials/src/EventProcessor.cs386
-rw-r--r--lib/Plugins.Essentials/src/EventProcessorConfig.cs93
-rw-r--r--lib/Plugins.Essentials/src/Extensions/ConnectionInfoExtensions.cs18
-rw-r--r--lib/Plugins.Essentials/src/Extensions/EssentialHttpEventExtensions.cs4
-rw-r--r--lib/Plugins.Essentials/src/HttpEntity.cs43
-rw-r--r--lib/Plugins.Essentials/src/IWebProcessorInfo.cs14
-rw-r--r--lib/Plugins.Essentials/src/Middleware/IHttpMiddlewareChain.cs4
-rw-r--r--lib/Plugins.Essentials/src/Middleware/SemiConistentMiddlewareChain.cs13
-rw-r--r--lib/Plugins.Essentials/src/Users/IUserManager.cs4
-rw-r--r--lib/Plugins.Runtime/src/LoaderExtensions.cs18
-rw-r--r--lib/Plugins.Runtime/src/PluginController.cs30
-rw-r--r--lib/Plugins.Runtime/src/RuntimePluginLoader.cs19
-rw-r--r--lib/Plugins.Runtime/src/Services/PluginServiceExport.cs20
-rw-r--r--lib/Utils.Cryptography/argon2/Taskfile.yaml28
-rw-r--r--lib/Utils.Cryptography/monocypher/Taskfile.yaml26
-rw-r--r--lib/Utils.Memory/NativeHeapApi/LICENSE664
-rw-r--r--lib/Utils.Memory/NativeHeapApi/src/NativeHeapApi.h88
-rw-r--r--lib/Utils.Memory/mimalloc/bin/mimalloc-redirect.dllbin68096 -> 0 bytes
-rw-r--r--lib/Utils.Memory/mimalloc/bin/mimalloc-redirect.libbin2874 -> 0 bytes
-rw-r--r--lib/Utils.Memory/mimalloc/bin/mimalloc-redirect32.dllbin41984 -> 0 bytes
-rw-r--r--lib/Utils.Memory/mimalloc/bin/mimalloc-redirect32.libbin2928 -> 0 bytes
-rw-r--r--lib/Utils.Memory/mimalloc/bin/minject.exebin20992 -> 0 bytes
-rw-r--r--lib/Utils.Memory/mimalloc/bin/minject32.exebin18432 -> 0 bytes
-rw-r--r--lib/Utils.Memory/rpmalloc/malloc.c488
-rw-r--r--lib/Utils.Memory/rpmalloc/rpnew.h111
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/CMakeLists.txt11
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/LICENSE605
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/NativeHeapApi.h164
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/Taskfile.yaml57
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/.gitattributes (renamed from lib/Utils.Memory/mimalloc/.gitattributes)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/.gitignore (renamed from lib/Utils.Memory/mimalloc/.gitignore)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/CMakeLists.txt (renamed from lib/Utils.Memory/mimalloc/CMakeLists.txt)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/LICENSE (renamed from lib/Utils.Memory/mimalloc/LICENSE)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/SECURITY.md (renamed from lib/Utils.Memory/mimalloc/SECURITY.md)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/azure-pipelines.yml (renamed from lib/Utils.Memory/mimalloc/azure-pipelines.yml)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/cmake/JoinPaths.cmake (renamed from lib/Utils.Memory/mimalloc/cmake/JoinPaths.cmake)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/cmake/mimalloc-config-version.cmake (renamed from lib/Utils.Memory/mimalloc/cmake/mimalloc-config-version.cmake)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/cmake/mimalloc-config.cmake (renamed from lib/Utils.Memory/mimalloc/cmake/mimalloc-config.cmake)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-c5-18xlarge-2020-01-20-a.svg (renamed from lib/Utils.Memory/mimalloc/doc/bench-2020/bench-c5-18xlarge-2020-01-20-a.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-c5-18xlarge-2020-01-20-b.svg (renamed from lib/Utils.Memory/mimalloc/doc/bench-2020/bench-c5-18xlarge-2020-01-20-b.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-c5-18xlarge-2020-01-20-rss-a.svg (renamed from lib/Utils.Memory/mimalloc/doc/bench-2020/bench-c5-18xlarge-2020-01-20-rss-a.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-c5-18xlarge-2020-01-20-rss-b.svg (renamed from lib/Utils.Memory/mimalloc/doc/bench-2020/bench-c5-18xlarge-2020-01-20-rss-b.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-r5a-1.svg (renamed from lib/Utils.Memory/mimalloc/doc/bench-2020/bench-r5a-1.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-r5a-12xlarge-2020-01-16-a.svg (renamed from lib/Utils.Memory/mimalloc/doc/bench-2020/bench-r5a-12xlarge-2020-01-16-a.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-r5a-12xlarge-2020-01-16-b.svg (renamed from lib/Utils.Memory/mimalloc/doc/bench-2020/bench-r5a-12xlarge-2020-01-16-b.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-r5a-2.svg (renamed from lib/Utils.Memory/mimalloc/doc/bench-2020/bench-r5a-2.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-r5a-rss-1.svg (renamed from lib/Utils.Memory/mimalloc/doc/bench-2020/bench-r5a-rss-1.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-r5a-rss-2.svg (renamed from lib/Utils.Memory/mimalloc/doc/bench-2020/bench-r5a-rss-2.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-spec-rss.svg (renamed from lib/Utils.Memory/mimalloc/doc/bench-2020/bench-spec-rss.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-spec.svg (renamed from lib/Utils.Memory/mimalloc/doc/bench-2020/bench-spec.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-z4-1.svg (renamed from lib/Utils.Memory/mimalloc/doc/bench-2020/bench-z4-1.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-z4-2.svg (renamed from lib/Utils.Memory/mimalloc/doc/bench-2020/bench-z4-2.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-z4-rss-1.svg (renamed from lib/Utils.Memory/mimalloc/doc/bench-2020/bench-z4-rss-1.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-z4-rss-2.svg (renamed from lib/Utils.Memory/mimalloc/doc/bench-2020/bench-z4-rss-2.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2021/bench-amd5950x-2021-01-30-a.svg (renamed from lib/Utils.Memory/mimalloc/doc/bench-2021/bench-amd5950x-2021-01-30-a.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2021/bench-amd5950x-2021-01-30-b.svg (renamed from lib/Utils.Memory/mimalloc/doc/bench-2021/bench-amd5950x-2021-01-30-b.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2021/bench-c5-18xlarge-2021-01-30-a.svg (renamed from lib/Utils.Memory/mimalloc/doc/bench-2021/bench-c5-18xlarge-2021-01-30-a.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2021/bench-c5-18xlarge-2021-01-30-b.svg (renamed from lib/Utils.Memory/mimalloc/doc/bench-2021/bench-c5-18xlarge-2021-01-30-b.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2021/bench-c5-18xlarge-2021-01-30-rss-a.svg (renamed from lib/Utils.Memory/mimalloc/doc/bench-2021/bench-c5-18xlarge-2021-01-30-rss-a.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2021/bench-c5-18xlarge-2021-01-30-rss-b.svg (renamed from lib/Utils.Memory/mimalloc/doc/bench-2021/bench-c5-18xlarge-2021-01-30-rss-b.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2021/bench-macmini-2021-01-30.svg (renamed from lib/Utils.Memory/mimalloc/doc/bench-2021/bench-macmini-2021-01-30.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/doxyfile (renamed from lib/Utils.Memory/mimalloc/doc/doxyfile)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/ds-logo.jpg (renamed from lib/Utils.Memory/mimalloc/doc/ds-logo.jpg)bin181497 -> 181497 bytes
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/ds-logo.png (renamed from lib/Utils.Memory/mimalloc/doc/ds-logo.png)bin121150 -> 121150 bytes
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/mimalloc-doc.h (renamed from lib/Utils.Memory/mimalloc/doc/mimalloc-doc.h)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/mimalloc-doxygen.css (renamed from lib/Utils.Memory/mimalloc/doc/mimalloc-doxygen.css)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/mimalloc-logo-100.png (renamed from lib/Utils.Memory/mimalloc/doc/mimalloc-logo-100.png)bin3532 -> 3532 bytes
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/mimalloc-logo.png (renamed from lib/Utils.Memory/mimalloc/doc/mimalloc-logo.png)bin73097 -> 73097 bytes
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/mimalloc-logo.svg (renamed from lib/Utils.Memory/mimalloc/doc/mimalloc-logo.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/spades-logo.png (renamed from lib/Utils.Memory/mimalloc/doc/spades-logo.png)bin34583 -> 34583 bytes
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/doc/unreal-logo.svg (renamed from lib/Utils.Memory/mimalloc/doc/unreal-logo.svg)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2017/mimalloc-override-test.vcxproj (renamed from lib/Utils.Memory/mimalloc/ide/vs2017/mimalloc-override-test.vcxproj)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2017/mimalloc-override.vcxproj (renamed from lib/Utils.Memory/mimalloc/ide/vs2017/mimalloc-override.vcxproj)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2017/mimalloc-test-stress.vcxproj (renamed from lib/Utils.Memory/mimalloc/ide/vs2017/mimalloc-test-stress.vcxproj)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2017/mimalloc-test.vcxproj (renamed from lib/Utils.Memory/mimalloc/ide/vs2017/mimalloc-test.vcxproj)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2017/mimalloc.sln (renamed from lib/Utils.Memory/mimalloc/ide/vs2017/mimalloc.sln)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2017/mimalloc.vcxproj (renamed from lib/Utils.Memory/mimalloc/ide/vs2017/mimalloc.vcxproj)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2019/mimalloc-override-test.vcxproj (renamed from lib/Utils.Memory/mimalloc/ide/vs2019/mimalloc-override-test.vcxproj)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2019/mimalloc-override.vcxproj (renamed from lib/Utils.Memory/mimalloc/ide/vs2019/mimalloc-override.vcxproj)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2019/mimalloc-test-api.vcxproj (renamed from lib/Utils.Memory/mimalloc/ide/vs2019/mimalloc-test-api.vcxproj)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2019/mimalloc-test-stress.vcxproj (renamed from lib/Utils.Memory/mimalloc/ide/vs2019/mimalloc-test-stress.vcxproj)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2019/mimalloc-test.vcxproj (renamed from lib/Utils.Memory/mimalloc/ide/vs2019/mimalloc-test.vcxproj)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2019/mimalloc.sln (renamed from lib/Utils.Memory/mimalloc/ide/vs2019/mimalloc.sln)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2019/mimalloc.vcxproj (renamed from lib/Utils.Memory/mimalloc/ide/vs2019/mimalloc.vcxproj)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2022/mimalloc-override-test.vcxproj (renamed from lib/Utils.Memory/mimalloc/ide/vs2022/mimalloc-override-test.vcxproj)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2022/mimalloc-override.vcxproj (renamed from lib/Utils.Memory/mimalloc/ide/vs2022/mimalloc-override.vcxproj)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2022/mimalloc-test-api.vcxproj (renamed from lib/Utils.Memory/mimalloc/ide/vs2022/mimalloc-test-api.vcxproj)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2022/mimalloc-test-stress.vcxproj (renamed from lib/Utils.Memory/mimalloc/ide/vs2022/mimalloc-test-stress.vcxproj)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2022/mimalloc-test.vcxproj (renamed from lib/Utils.Memory/mimalloc/ide/vs2022/mimalloc-test.vcxproj)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2022/mimalloc.sln (renamed from lib/Utils.Memory/mimalloc/ide/vs2022/mimalloc.sln)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2022/mimalloc.vcxproj (renamed from lib/Utils.Memory/mimalloc/ide/vs2022/mimalloc.vcxproj)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/include/mimalloc-new-delete.h (renamed from lib/Utils.Memory/mimalloc/include/mimalloc-new-delete.h)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/include/mimalloc-override.h (renamed from lib/Utils.Memory/mimalloc/include/mimalloc-override.h)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/include/mimalloc.h (renamed from lib/Utils.Memory/mimalloc/include/mimalloc.h)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/include/mimalloc/atomic.h (renamed from lib/Utils.Memory/mimalloc/include/mimalloc/atomic.h)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/include/mimalloc/internal.h (renamed from lib/Utils.Memory/mimalloc/include/mimalloc/internal.h)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/include/mimalloc/prim.h (renamed from lib/Utils.Memory/mimalloc/include/mimalloc/prim.h)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/include/mimalloc/track.h (renamed from lib/Utils.Memory/mimalloc/include/mimalloc/track.h)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/include/mimalloc/types.h (renamed from lib/Utils.Memory/mimalloc/include/mimalloc/types.h)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/mimalloc.pc.in (renamed from lib/Utils.Memory/mimalloc/mimalloc.pc.in)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/readme.md (renamed from lib/Utils.Memory/mimalloc/readme.md)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/alloc-aligned.c (renamed from lib/Utils.Memory/mimalloc/src/alloc-aligned.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/alloc-override.c (renamed from lib/Utils.Memory/mimalloc/src/alloc-override.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/alloc-posix.c (renamed from lib/Utils.Memory/mimalloc/src/alloc-posix.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/alloc.c (renamed from lib/Utils.Memory/mimalloc/src/alloc.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/arena.c (renamed from lib/Utils.Memory/mimalloc/src/arena.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/bitmap.c (renamed from lib/Utils.Memory/mimalloc/src/bitmap.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/bitmap.h (renamed from lib/Utils.Memory/mimalloc/src/bitmap.h)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/heap.c (renamed from lib/Utils.Memory/mimalloc/src/heap.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/init.c (renamed from lib/Utils.Memory/mimalloc/src/init.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/options.c (renamed from lib/Utils.Memory/mimalloc/src/options.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/os.c (renamed from lib/Utils.Memory/mimalloc/src/os.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/page-queue.c (renamed from lib/Utils.Memory/mimalloc/src/page-queue.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/page.c (renamed from lib/Utils.Memory/mimalloc/src/page.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/osx/alloc-override-zone.c (renamed from lib/Utils.Memory/mimalloc/src/prim/osx/alloc-override-zone.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/osx/prim.c (renamed from lib/Utils.Memory/mimalloc/src/prim/osx/prim.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/prim.c (renamed from lib/Utils.Memory/mimalloc/src/prim/prim.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/readme.md (renamed from lib/Utils.Memory/mimalloc/src/prim/readme.md)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/unix/prim.c (renamed from lib/Utils.Memory/mimalloc/src/prim/unix/prim.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/wasi/prim.c (renamed from lib/Utils.Memory/mimalloc/src/prim/wasi/prim.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/windows/etw-mimalloc.wprp (renamed from lib/Utils.Memory/mimalloc/src/prim/windows/etw-mimalloc.wprp)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/windows/etw.h (renamed from lib/Utils.Memory/mimalloc/src/prim/windows/etw.h)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/windows/etw.man (renamed from lib/Utils.Memory/mimalloc/src/prim/windows/etw.man)bin3926 -> 3926 bytes
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/windows/prim.c (renamed from lib/Utils.Memory/mimalloc/src/prim/windows/prim.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/windows/readme.md (renamed from lib/Utils.Memory/mimalloc/src/prim/windows/readme.md)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/random.c (renamed from lib/Utils.Memory/mimalloc/src/random.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/segment-map.c (renamed from lib/Utils.Memory/mimalloc/src/segment-map.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/segment.c (renamed from lib/Utils.Memory/mimalloc/src/segment.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/static.c (renamed from lib/Utils.Memory/mimalloc/src/static.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/src/stats.c (renamed from lib/Utils.Memory/mimalloc/src/stats.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/test/CMakeLists.txt (renamed from lib/Utils.Memory/mimalloc/test/CMakeLists.txt)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/test/main-override-static.c (renamed from lib/Utils.Memory/mimalloc/test/main-override-static.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/test/main-override.c (renamed from lib/Utils.Memory/mimalloc/test/main-override.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/test/main-override.cpp (renamed from lib/Utils.Memory/mimalloc/test/main-override.cpp)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/test/main.c (renamed from lib/Utils.Memory/mimalloc/test/main.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/test/readme.md (renamed from lib/Utils.Memory/mimalloc/test/readme.md)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/test/test-api-fill.c (renamed from lib/Utils.Memory/mimalloc/test/test-api-fill.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/test/test-api.c (renamed from lib/Utils.Memory/mimalloc/test/test-api.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/test/test-stress.c (renamed from lib/Utils.Memory/mimalloc/test/test-stress.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/test/test-wrong.c (renamed from lib/Utils.Memory/mimalloc/test/test-wrong.c)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vendor/test/testhelper.h (renamed from lib/Utils.Memory/mimalloc/test/testhelper.h)0
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vnlib_mimalloc.c40
-rw-r--r--lib/Utils.Memory/vnlib_mimalloc/vnlib_mimalloc.vcxitems3
-rw-r--r--lib/Utils.Memory/vnlib_rpmalloc/CMakeLists.txt5
-rw-r--r--lib/Utils.Memory/vnlib_rpmalloc/LICENSE605
-rw-r--r--lib/Utils.Memory/vnlib_rpmalloc/NativeHeapApi.h164
-rw-r--r--lib/Utils.Memory/vnlib_rpmalloc/Taskfile.yaml43
-rw-r--r--lib/Utils.Memory/vnlib_rpmalloc/vendor/LICENSE (renamed from lib/Utils.Memory/rpmalloc/LICENSE)0
-rw-r--r--lib/Utils.Memory/vnlib_rpmalloc/vendor/rpmalloc.c (renamed from lib/Utils.Memory/rpmalloc/rpmalloc.c)0
-rw-r--r--lib/Utils.Memory/vnlib_rpmalloc/vendor/rpmalloc.h (renamed from lib/Utils.Memory/rpmalloc/rpmalloc.h)0
-rw-r--r--lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.c42
-rw-r--r--lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.vcxitems2
-rw-r--r--lib/Utils/src/Extensions/CollectionExtensions.cs48
-rw-r--r--lib/Utils/src/Extensions/IoExtensions.cs80
-rw-r--r--lib/Utils/src/Extensions/JsonExtensions.cs5
-rw-r--r--lib/Utils/src/Extensions/SafeLibraryExtensions.cs42
-rw-r--r--lib/Utils/src/IO/FileWatcher.cs171
-rw-r--r--lib/Utils/src/IO/IFSChangeHandler.cs40
-rw-r--r--lib/Utils/src/IO/InMemoryTemplate.cs196
-rw-r--r--lib/Utils/src/IO/VnMemoryStream.cs7
-rw-r--r--lib/Utils/src/IO/VnStreamWriter.cs18
-rw-r--r--lib/Utils/src/Memory/Caching/LRUCache.cs6
-rw-r--r--lib/Utils/src/Memory/Caching/LRUCollection.cs (renamed from lib/Utils/src/Memory/Caching/LRUDataStore.cs)34
-rw-r--r--lib/Utils/src/Memory/MemoryHandle.cs2
-rw-r--r--lib/Utils/src/Memory/MemoryUtil.CopyUtilCore.cs313
-rw-r--r--lib/Utils/src/Memory/MemoryUtil.cs691
-rw-r--r--lib/Utils/src/Memory/NativeHeap.cs64
-rw-r--r--lib/Utils/src/Memory/PrivateString.cs4
-rw-r--r--lib/Utils/src/Memory/PrivateStringManager.cs16
-rw-r--r--lib/Utils/src/Memory/SubSequence.cs30
-rw-r--r--lib/Utils/src/Memory/UnmanagedHeapBase.cs39
-rw-r--r--lib/Utils/src/Memory/UnsafeMemoryHandle.cs2
-rw-r--r--lib/Utils/src/Native/SafeLibraryHandle.cs46
-rw-r--r--lib/Utils/src/VnEncoding.cs43
-rw-r--r--lib/Utils/tests/Memory/MemoryUtilTests.cs45
-rw-r--r--lib/Utils/tests/Memory/NativeHeapTests.cs26
-rw-r--r--lib/Utils/tests/VNLib.UtilsTests.csproj6
231 files changed, 4436 insertions, 3288 deletions
diff --git a/lib/Hashing.Portable/src/IdentityUtility/HashingExtensions.cs b/lib/Hashing.Portable/src/IdentityUtility/HashingExtensions.cs
index 65704df..2a18cfc 100644
--- a/lib/Hashing.Portable/src/IdentityUtility/HashingExtensions.cs
+++ b/lib/Hashing.Portable/src/IdentityUtility/HashingExtensions.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Hashing.Portable
@@ -24,6 +24,7 @@
using System;
using System.Text;
+using System.Diagnostics;
using System.Security.Cryptography;
using VNLib.Utils;
@@ -49,7 +50,7 @@ namespace VNLib.Hashing.IdentityUtility
/// <exception cref="ArgumentNullException"></exception>
public static string ComputeBase64Hash(this HMAC hmac, ReadOnlySpan<char> data, Encoding? encoding = null)
{
- _ = hmac ?? throw new ArgumentNullException(nameof(hmac));
+ ArgumentNullException.ThrowIfNull(hmac);
encoding ??= Encoding.UTF8;
@@ -64,10 +65,11 @@ namespace VNLib.Hashing.IdentityUtility
Span<byte> encBuffer = buffer.Span[0..encBufSize];
Span<byte> hashBuffer = buffer.Span[encBufSize..];
-
+
//Encode data
- _ = encoding.GetBytes(data, encBuffer);
-
+ int encoed = encoding.GetBytes(data, encBuffer);
+ Debug.Assert(encoed == encBufSize, "Encoder actual encoded bytes not equal to computed encoding size");
+
//compute hash
if (!hmac.TryComputeHash(encBuffer, hashBuffer, out int hashBytesWritten))
{
@@ -77,7 +79,7 @@ namespace VNLib.Hashing.IdentityUtility
//Convert to base64 string
return Convert.ToBase64String(hashBuffer[..hashBytesWritten]);
}
-
+
/// <summary>
/// Computes the hash of the raw data and compares the computed hash against
/// the specified base64hash
@@ -87,22 +89,15 @@ namespace VNLib.Hashing.IdentityUtility
/// <param name="base64Hmac">The base64 hash to verify against</param>
/// <param name="encoding">The encoding used to encode the raw data balue</param>
/// <returns>A value indicating if the hash values match</returns>
- /// <exception cref="ArgumentException"></exception>
/// <exception cref="OutOfMemoryException"></exception>
/// <exception cref="ArgumentNullException"></exception>
+ /// <exception cref="ArgumentOutOfRangeException"></exception>
public static bool VerifyBase64Hash(this HMAC hmac, ReadOnlySpan<char> base64Hmac, ReadOnlySpan<char> raw, Encoding? encoding = null)
{
- _ = hmac ?? throw new ArgumentNullException(nameof(hmac));
-
- if (raw.IsEmpty)
- {
- throw new ArgumentException("Raw data buffer must not be empty", nameof(raw));
- }
-
- if (base64Hmac.IsEmpty)
- {
- throw new ArgumentException("Hmac buffer must not be empty", nameof(base64Hmac));
- }
+ ArgumentNullException.ThrowIfNull(hmac);
+
+ ArgumentOutOfRangeException.ThrowIfZero(raw.Length, nameof(raw));
+ ArgumentOutOfRangeException.ThrowIfZero(base64Hmac.Length, nameof(base64Hmac));
encoding ??= Encoding.UTF8;
@@ -119,8 +114,9 @@ namespace VNLib.Hashing.IdentityUtility
Span<byte> base64Buf = buffer.Span[rawDataBufSize..];
//encode
- _ = encoding.GetBytes(raw, rawDataBuf);
-
+ int encoed = encoding.GetBytes(raw, rawDataBuf);
+ Debug.Assert(encoed == rawDataBufSize, "Encoder actual encoded bytes not equal to computed encoding size");
+
//Convert to binary
if(!Convert.TryFromBase64Chars(base64Hmac, base64Buf, out int base64Converted))
{
@@ -130,7 +126,7 @@ namespace VNLib.Hashing.IdentityUtility
//Compare hash buffers
return hmac.VerifyHash(base64Buf[0..base64Converted], rawDataBuf);
}
-
+
/// <summary>
/// Computes the hash of the raw data and compares the computed hash against
/// the specified hash
@@ -139,23 +135,15 @@ namespace VNLib.Hashing.IdentityUtility
/// <param name="raw">The raw data to verify the hash of</param>
/// <param name="hash">The hash to compare against the computed data</param>
/// <returns>A value indicating if the hash values match</returns>
- /// <exception cref="ArgumentException"></exception>
/// <exception cref="OutOfMemoryException"></exception>
/// <exception cref="ArgumentNullException"></exception>
+ /// <exception cref="ArgumentOutOfRangeException"></exception>
public static bool VerifyHash(this HMAC hmac, ReadOnlySpan<byte> hash, ReadOnlySpan<byte> raw)
{
- _ = hmac ?? throw new ArgumentNullException(nameof(hmac));
-
- if (raw.IsEmpty)
- {
- throw new ArgumentException("Raw data buffer must not be empty", nameof(raw));
- }
-
- if (hash.IsEmpty)
- {
- throw new ArgumentException("Hash buffer must not be empty", nameof(hash));
- }
-
+ ArgumentNullException.ThrowIfNull(hmac);
+ ArgumentOutOfRangeException.ThrowIfZero(raw.Length, nameof(raw));
+ ArgumentOutOfRangeException.ThrowIfZero(hash.Length, nameof(hash));
+
//Calc hashsize to alloc buffer
int hashBufSize = hmac.HashSize / 8;
@@ -187,7 +175,7 @@ namespace VNLib.Hashing.IdentityUtility
/// <exception cref="ObjectDisposedException"></exception>
public static ERRNO TryEncrypt(this RSA alg, ReadOnlySpan<char> data, Span<byte> output, RSAEncryptionPadding padding, Encoding? enc = null)
{
- _ = alg ?? throw new ArgumentNullException(nameof(alg));
+ ArgumentNullException.ThrowIfNull(alg);
//Default to UTF8 encoding
enc ??= Encoding.UTF8;
@@ -215,6 +203,9 @@ namespace VNLib.Hashing.IdentityUtility
{
return alg switch
{
+ HashAlg.SHA3_512 => HashAlgorithmName.SHA3_512,
+ HashAlg.SHA3_384 => HashAlgorithmName.SHA3_384,
+ HashAlg.SHA3_256 => HashAlgorithmName.SHA3_256,
HashAlg.SHA512 => HashAlgorithmName.SHA512,
HashAlg.SHA384 => HashAlgorithmName.SHA384,
HashAlg.SHA256 => HashAlgorithmName.SHA256,
diff --git a/lib/Hashing.Portable/src/IdentityUtility/JsonWebKey.cs b/lib/Hashing.Portable/src/IdentityUtility/JsonWebKey.cs
index 576c096..65f0837 100644
--- a/lib/Hashing.Portable/src/IdentityUtility/JsonWebKey.cs
+++ b/lib/Hashing.Portable/src/IdentityUtility/JsonWebKey.cs
@@ -96,6 +96,8 @@ namespace VNLib.Hashing.IdentityUtility
/// <exception cref="EncryptionTypeNotSupportedException"></exception>
public static bool VerifyFromJwk<TKey>(this JsonWebToken token, in TKey jwk) where TKey: notnull, IJsonWebKey
{
+ ArgumentNullException.ThrowIfNull(token);
+
//Use and alg are required here
if(jwk.KeyUse != JwkKeyUsage.Signature || jwk.Algorithm == null)
{
@@ -441,7 +443,7 @@ namespace VNLib.Hashing.IdentityUtility
}
else
{
- //bin buffer for temp decoding
+ //bin buffer for temp decoding with some extra space just incase
using UnsafeMemoryHandle<byte> binBuffer = MemoryUtil.UnsafeAlloc(base64.Length + 16, false);
//base64url decode
diff --git a/lib/Hashing.Portable/src/IdentityUtility/JsonWebToken.cs b/lib/Hashing.Portable/src/IdentityUtility/JsonWebToken.cs
index 158a1b8..27283c8 100644
--- a/lib/Hashing.Portable/src/IdentityUtility/JsonWebToken.cs
+++ b/lib/Hashing.Portable/src/IdentityUtility/JsonWebToken.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Hashing.Portable
@@ -42,6 +42,16 @@ namespace VNLib.Hashing.IdentityUtility
internal const byte SAEF_PERIOD = 0x2e;
internal const byte PADDING_BYTES = 0x3d;
+ private const int E_INVALID_DATA = 0;
+ private const int E_INVALID_HEADER = -1;
+ private const int E_INVALID_PAYLOAD = -2;
+
+ private static readonly string[] ERR_STRINGS = [
+ "The supplied data buffer is empty or malformatted",
+ "The supplied data is not a valid Json Web Token, header end symbol could not be found",
+ "The supplied data is not a valid Json Web Token, payload end symbol could not be found"
+ ];
+
/// <summary>
/// Parses a JWT from a Base64URL encoded character buffer
/// </summary>
@@ -57,10 +67,7 @@ namespace VNLib.Hashing.IdentityUtility
heap ??= MemoryUtil.Shared;
textEncoding ??= Encoding.UTF8;
- if (urlEncJwtString.IsEmpty)
- {
- throw new ArgumentException("The JWT string is empty", nameof(urlEncJwtString));
- }
+ ArgumentOutOfRangeException.ThrowIfZero(urlEncJwtString.Length, nameof(urlEncJwtString));
//Calculate the decoded size of the characters to alloc a buffer
int utf8Size = textEncoding.GetByteCount(urlEncJwtString);
@@ -74,39 +81,39 @@ namespace VNLib.Hashing.IdentityUtility
//Parse and return the jwt
return ParseRaw(binBuffer.Span[..utf8Size], heap);
}
-
+
/// <summary>
- /// Parses a buffer of UTF8 bytes of url encoded base64 characters
+ /// Attempts to parse a buffer of UTF8 bytes of url encoded base64 characters
/// </summary>
- /// <param name="utf8JWTData">The JWT data buffer</param>
- /// <param name="heap">An optional <see cref="IUnmangedHeap"/> instance to alloc buffers from</param>
- /// <returns>The parsed <see cref="JsonWebToken"/></returns>
- /// <exception cref="FormatException"></exception>
- /// <exception cref="ArgumentException"></exception>
+ /// <param name="utf8JWTData">The utf8 encoded data to parse</param>
+ /// <param name="jwt">The JWT output reference</param>
+ /// <param name="heap">The heap to allocate internal buffers from</param>
+ /// <returns>A positive ERRNO value, 0 or negative numbers if the parsing failed</returns>
/// <exception cref="OutOfMemoryException"></exception>
- public static JsonWebToken ParseRaw(ReadOnlySpan<byte> utf8JWTData, IUnmangedHeap? heap = null)
+ public static ERRNO TryParseRaw(ReadOnlySpan<byte> utf8JWTData, out JsonWebToken? jwt, IUnmangedHeap? heap = null)
{
- if (utf8JWTData.IsEmpty)
+ if(utf8JWTData.IsEmpty)
{
- throw new ArgumentException("JWT data may not be empty", nameof(utf8JWTData));
+ jwt = null;
+ return E_INVALID_DATA;
}
-
+
//Set default heap of non was specified
heap ??= MemoryUtil.Shared;
//Alloc the token and copy the supplied data to a new mem stream
- JsonWebToken jwt = new(heap, new (heap, utf8JWTData));
+ jwt = new(heap, new (heap, utf8JWTData));
try
{
ForwardOnlyReader<byte> reader = new(utf8JWTData);
-
+
//Search for the first period to indicate the end of the header section
jwt.HeaderEnd = reader.Window.IndexOf(SAEF_PERIOD);
//Make sure a '.' was found
if (jwt.HeaderEnd < 0)
{
- throw new FormatException("The supplied data is not a valid Json Web Token, header end symbol could not be found");
+ return E_INVALID_HEADER;
}
//Shift buffer window
@@ -118,18 +125,47 @@ namespace VNLib.Hashing.IdentityUtility
//Make sure a '.' was found
if (jwt.PayloadEnd < 0)
{
- throw new FormatException("The supplied data is not a valid Json Web Token, payload end symbol could not be found");
+ return E_INVALID_PAYLOAD;
}
//signature is set automatically
//return the new token
- return jwt;
+ return ERRNO.SUCCESS;
}
catch
{
jwt.Dispose();
+ jwt = null;
throw;
}
}
+
+ /// <summary>
+ /// Parses a buffer of UTF8 bytes of url encoded base64 characters
+ /// </summary>
+ /// <param name="utf8JWTData">The JWT data buffer</param>
+ /// <param name="heap">An optional <see cref="IUnmangedHeap"/> instance to alloc buffers from</param>
+ /// <returns>The parsed <see cref="JsonWebToken"/></returns>
+ /// <exception cref="FormatException"></exception>
+ /// <exception cref="ArgumentException"></exception>
+ /// <exception cref="OutOfMemoryException"></exception>
+ public static JsonWebToken ParseRaw(ReadOnlySpan<byte> utf8JWTData, IUnmangedHeap? heap = null)
+ {
+ int result = TryParseRaw(utf8JWTData, out JsonWebToken? jwt, heap);
+
+ //Raise exception if the parse failed
+ switch (result)
+ {
+ case 1:
+ break;
+ case 0:
+ throw new ArgumentException(ERR_STRINGS[result]);
+ default:
+ //Since error codes are negative, use the absolute value to index the error strings
+ throw new FormatException(ERR_STRINGS[Math.Abs(result)]);
+ }
+
+ return jwt!;
+ }
/// <summary>
@@ -158,6 +194,9 @@ namespace VNLib.Hashing.IdentityUtility
/// <param name="initialData">The initial data of the jwt</param>
protected JsonWebToken(IUnmangedHeap heap, VnMemoryStream initialData)
{
+ ArgumentNullException.ThrowIfNull(initialData);
+ ArgumentNullException.ThrowIfNull(heap);
+
Heap = heap;
DataStream = initialData;
diff --git a/lib/Hashing.Portable/src/IdentityUtility/JwtExtensions.cs b/lib/Hashing.Portable/src/IdentityUtility/JwtExtensions.cs
index 2177aac..ef6715b 100644
--- a/lib/Hashing.Portable/src/IdentityUtility/JwtExtensions.cs
+++ b/lib/Hashing.Portable/src/IdentityUtility/JwtExtensions.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Hashing.Portable
@@ -49,6 +49,8 @@ namespace VNLib.Hashing.IdentityUtility
/// <param name="jso">Optional serialize options</param>
public static void WriteHeader<T>(this JsonWebToken jwt, T header, JsonSerializerOptions? jso = null) where T: class
{
+ ArgumentNullException.ThrowIfNull(jwt);
+
byte[] data = JsonSerializer.SerializeToUtf8Bytes(header, jso);
jwt.WriteHeader(data);
}
@@ -62,6 +64,8 @@ namespace VNLib.Hashing.IdentityUtility
/// <param name="jso">Optional serialize options</param>
public static void WritePayload<T>(this JsonWebToken jwt, T payload, JsonSerializerOptions? jso = null)
{
+ ArgumentNullException.ThrowIfNull(jwt);
+
byte[] data = JsonSerializer.SerializeToUtf8Bytes(payload, jso);
jwt.WritePayload(data);
}
@@ -77,6 +81,8 @@ namespace VNLib.Hashing.IdentityUtility
/// <exception cref="ObjectDisposedException"></exception>
public static JsonDocument GetPayload(this JsonWebToken jwt)
{
+ ArgumentNullException.ThrowIfNull(jwt);
+
ReadOnlySpan<byte> payload = jwt.PayloadData;
if (payload.IsEmpty)
{
@@ -109,6 +115,8 @@ namespace VNLib.Hashing.IdentityUtility
/// <exception cref="ObjectDisposedException"></exception>
public static JsonDocument GetHeader(this JsonWebToken jwt)
{
+ ArgumentNullException.ThrowIfNull(jwt);
+
ReadOnlySpan<byte> header = jwt.HeaderData;
if (header.IsEmpty)
{
@@ -153,6 +161,8 @@ namespace VNLib.Hashing.IdentityUtility
/// <exception cref="ObjectDisposedException"></exception>
public static T? GetPayload<T>(this JsonWebToken jwt, JsonSerializerOptions? jso = null)
{
+ ArgumentNullException.ThrowIfNull(jwt);
+
ReadOnlySpan<byte> payload = jwt.PayloadData;
if (payload.IsEmpty)
{
@@ -192,7 +202,8 @@ namespace VNLib.Hashing.IdentityUtility
/// <exception cref="ObjectDisposedException"></exception>
public static void Sign(this JsonWebToken jwt, HashAlgorithm signatureAlgorithm)
{
- _ = signatureAlgorithm ?? throw new ArgumentNullException(nameof(signatureAlgorithm));
+ ArgumentNullException.ThrowIfNull(jwt);
+ ArgumentNullException.ThrowIfNull(signatureAlgorithm);
//Calculate the size of the buffer to use for the current algorithm
int bufferSize = signatureAlgorithm.HashSize / 8;
@@ -221,7 +232,9 @@ namespace VNLib.Hashing.IdentityUtility
/// <exception cref="ObjectDisposedException"></exception>
public static void Sign(this JsonWebToken jwt, RSA rsa, HashAlg alg, RSASignaturePadding padding)
{
- _ = rsa ?? throw new ArgumentNullException(nameof(rsa));
+ ArgumentNullException.ThrowIfNull(jwt);
+ ArgumentNullException.ThrowIfNull(rsa);
+ ArgumentNullException.ThrowIfNull(padding);
//Init new rsa provider
RSASignatureProvider sig = new(rsa, alg, padding);
@@ -242,7 +255,8 @@ namespace VNLib.Hashing.IdentityUtility
/// <exception cref="ObjectDisposedException"></exception>
public static void Sign(this JsonWebToken jwt, ECDsa alg, HashAlg hashAlg, DSASignatureFormat sigFormat = DSASignatureFormat.IeeeP1363FixedFieldConcatenation)
{
- _ = alg ?? throw new ArgumentNullException(nameof(alg));
+ ArgumentNullException.ThrowIfNull(jwt);
+ ArgumentNullException.ThrowIfNull(alg);
//Init new ec provider
ECDSASignatureProvider sig = new(alg, sigFormat);
@@ -333,8 +347,8 @@ namespace VNLib.Hashing.IdentityUtility
/// <exception cref="ObjectDisposedException"></exception>
public static bool Verify(this JsonWebToken jwt, HashAlgorithm verificationAlg)
{
- _ = jwt ?? throw new ArgumentNullException(nameof(jwt));
- _ = verificationAlg ?? throw new ArgumentNullException(nameof(verificationAlg));
+ ArgumentNullException.ThrowIfNull(jwt);
+ ArgumentNullException.ThrowIfNull(verificationAlg);
//Calculate the size of the buffer to use for the current algorithm and make sure it will include the utf8 encoding
int hashBufferSize = Base64.GetMaxEncodedToUtf8Length(verificationAlg.HashSize / 8);
@@ -369,9 +383,12 @@ namespace VNLib.Hashing.IdentityUtility
/// <param name="provider">The <see cref="IJwtSignatureVerifier"/> used to verify the message digest</param>
/// <param name="alg">The <see cref="HashAlg"/> used to compute the message digest</param>
/// <returns>True if the siganture matches the computed on, false otherwise</returns>
+ /// <exception cref="OutOfMemoryException"></exception>
/// <exception cref="InternalBufferTooSmallException"></exception>
- public static bool Verify<T>(this JsonWebToken jwt, in T provider, HashAlg alg) where T : IJwtSignatureVerifier
+ public static bool Verify<T>(this JsonWebToken jwt, ref readonly T provider, HashAlg alg) where T : IJwtSignatureVerifier
{
+ ArgumentNullException.ThrowIfNull(jwt);
+
ReadOnlySpan<byte> signature = jwt.SignatureData;
int sigBufSize = CalcPadding(signature.Length) + signature.Length;
@@ -421,6 +438,7 @@ namespace VNLib.Hashing.IdentityUtility
/// </returns>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ObjectDisposedException"></exception>
+ /// <exception cref="OutOfMemoryException"></exception>
/// <exception cref="InternalBufferTooSmallException"></exception>
public static bool Verify(this JsonWebToken jwt, ReadOnlySpan<byte> key, HashAlg alg)
{
@@ -466,8 +484,9 @@ namespace VNLib.Hashing.IdentityUtility
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static bool Verify(this JsonWebToken jwt, RSA alg, HashAlg hashAlg, RSASignaturePadding padding)
{
- _ = jwt ?? throw new ArgumentNullException(nameof(jwt));
- _ = alg ?? throw new ArgumentNullException(nameof(alg));
+ ArgumentNullException.ThrowIfNull(jwt);
+ ArgumentNullException.ThrowIfNull(alg);
+ ArgumentNullException.ThrowIfNull(padding);
//Inint verifier
RSASignatureVerifier verifier = new(alg, hashAlg, padding);
@@ -490,7 +509,8 @@ namespace VNLib.Hashing.IdentityUtility
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static bool Verify(this JsonWebToken jwt, ECDsa alg, HashAlg hashAlg, DSASignatureFormat signatureFormat = DSASignatureFormat.IeeeP1363FixedFieldConcatenation)
{
- _ = alg ?? throw new ArgumentNullException(nameof(alg));
+ ArgumentNullException.ThrowIfNull(jwt);
+ ArgumentNullException.ThrowIfNull(alg);
//Inint verifier
ECDSASignatureVerifier verifier = new(alg, signatureFormat);
@@ -501,44 +521,41 @@ namespace VNLib.Hashing.IdentityUtility
/*
* Simple ecdsa and rsa providers
*/
- private readonly record struct ECDSASignatureProvider(ECDsa SigAlg, DSASignatureFormat Format) : IJwtSignatureProvider
+ private readonly struct ECDSASignatureProvider(ECDsa SigAlg, DSASignatureFormat Format) : IJwtSignatureProvider
{
///<inheritdoc/>
public readonly int RequiredBufferSize { get; } = 512;
///<inheritdoc/>
- public readonly ERRNO ComputeSignatureFromHash(ReadOnlySpan<byte> hash, Span<byte> outputBuffer)
- {
- return SigAlg.TrySignHash(hash, outputBuffer, Format, out int written) ? written : ERRNO.E_FAIL;
- }
+ public readonly ERRNO ComputeSignatureFromHash(ReadOnlySpan<byte> hash, Span<byte> outputBuffer)
+ => SigAlg.TrySignHash(hash, outputBuffer, Format, out int written) ? written : ERRNO.E_FAIL;
}
- internal readonly record struct RSASignatureProvider(RSA SigAlg, HashAlg Slg, RSASignaturePadding Padding) : IJwtSignatureProvider
+ internal readonly struct RSASignatureProvider(RSA SigAlg, HashAlg Slg, RSASignaturePadding Padding) : IJwtSignatureProvider
{
///<inheritdoc/>
public readonly int RequiredBufferSize { get; } = 1024;
///<inheritdoc/>
- public readonly ERRNO ComputeSignatureFromHash(ReadOnlySpan<byte> hash, Span<byte> outputBuffer)
- {
- return !SigAlg.TrySignHash(hash, outputBuffer, Slg.GetAlgName(), Padding, out int written) ? written : ERRNO.E_FAIL;
- }
+ public readonly ERRNO ComputeSignatureFromHash(ReadOnlySpan<byte> hash, Span<byte> outputBuffer)
+ => !SigAlg.TrySignHash(hash, outputBuffer, Slg.GetAlgName(), Padding, out int written) ? written : ERRNO.E_FAIL;
}
/*
* ECDSA and rsa verifiers
*/
- internal readonly record struct ECDSASignatureVerifier(ECDsa Alg, DSASignatureFormat Format) : IJwtSignatureVerifier
+ internal readonly struct ECDSASignatureVerifier(ECDsa Alg, DSASignatureFormat Format) : IJwtSignatureVerifier
{
- public readonly bool Verify(ReadOnlySpan<byte> messageHash, ReadOnlySpan<byte> signature) => Alg.VerifyHash(messageHash, signature);
+ ///<inheritdoc/>
+ public readonly bool Verify(ReadOnlySpan<byte> messageHash, ReadOnlySpan<byte> signature)
+ => Alg.VerifyHash(messageHash, signature, Format);
}
- internal readonly record struct RSASignatureVerifier(RSA Alg, HashAlg HashAlg, RSASignaturePadding Padding) : IJwtSignatureVerifier
+ internal readonly struct RSASignatureVerifier(RSA Alg, HashAlg HashAlg, RSASignaturePadding Padding) : IJwtSignatureVerifier
{
- public readonly bool Verify(ReadOnlySpan<byte> messageHash, ReadOnlySpan<byte> signature)
- {
- return Alg.VerifyHash(messageHash, signature, HashAlg.GetAlgName(), Padding);
- }
+ ///<inheritdoc/>
+ public readonly bool Verify(ReadOnlySpan<byte> messageHash, ReadOnlySpan<byte> signature)
+ => Alg.VerifyHash(messageHash, signature, HashAlg.GetAlgName(), Padding);
}
}
}
diff --git a/lib/Hashing.Portable/src/IdentityUtility/ReadOnlyJsonWebKey.cs b/lib/Hashing.Portable/src/IdentityUtility/ReadOnlyJsonWebKey.cs
index a50836f..009d6bf 100644
--- a/lib/Hashing.Portable/src/IdentityUtility/ReadOnlyJsonWebKey.cs
+++ b/lib/Hashing.Portable/src/IdentityUtility/ReadOnlyJsonWebKey.cs
@@ -45,7 +45,7 @@ namespace VNLib.Hashing.IdentityUtility
/// This will call <see cref="JsonElement.Clone"/> on the element and store an internal copy
/// </summary>
/// <param name="keyElement">The <see cref="JsonElement"/> to create the <see cref="ReadOnlyJsonWebKey"/> from</param>
- public ReadOnlyJsonWebKey(in JsonElement keyElement)
+ public ReadOnlyJsonWebKey(ref readonly JsonElement keyElement)
{
_jwk = keyElement.Clone();
//Set initial values
diff --git a/lib/Hashing.Portable/src/ManagedHash.cs b/lib/Hashing.Portable/src/ManagedHash.cs
index 49a2f09..7791eed 100644
--- a/lib/Hashing.Portable/src/ManagedHash.cs
+++ b/lib/Hashing.Portable/src/ManagedHash.cs
@@ -90,21 +90,27 @@ namespace VNLib.Hashing
/// Gets a value that indicates whether the current platform supports the SHA3
/// hashing algorithm.
/// </summary>
- public static bool SupportsSha3
- {
- get
- {
- if (Sha3_512.IsSupported)
- {
- //Assume others are supported too
- Debug.Assert(Sha3_384.IsSupported);
- Debug.Assert(Sha3_256.IsSupported);
- return true;
- }
+ public static bool SupportsSha3 { get; } = IsAlgSupported(HashAlg.SHA3_512) && IsAlgSupported(HashAlg.SHA3_384) && IsAlgSupported(HashAlg.SHA3_256);
- return false;
- }
- }
+ /// <summary>
+ /// Determines if the specified hash algorithm is supported by
+ /// the current runtime.
+ /// </summary>
+ /// <param name="type">The algorithm to verify</param>
+ /// <returns>A value that indicates if the algorithm is supported</returns>
+ public static bool IsAlgSupported(HashAlg type) => type switch
+ {
+ HashAlg.SHA3_512 => Sha3_512.IsSupported,
+ HashAlg.SHA3_384 => Sha3_384.IsSupported,
+ HashAlg.SHA3_256 => Sha3_256.IsSupported,
+ HashAlg.BlAKE2B => SupportsBlake2b,
+ HashAlg.SHA512 => true,
+ HashAlg.SHA384 => true,
+ HashAlg.SHA256 => true,
+ HashAlg.SHA1 => true,
+ HashAlg.MD5 => true,
+ _ => false
+ };
/// <summary>
/// Uses the UTF8 character encoding to encode the string, then
@@ -367,7 +373,7 @@ namespace VNLib.Hashing
_ => throw new ArgumentException("Invalid hash algorithm", nameof(alg))
};
- static ERRNO computeHashInternal<T>(in T algorithm, ReadOnlySpan<byte> data, Span<byte> buffer, ReadOnlySpan<byte> key = default)
+ static ERRNO computeHashInternal<T>(ref readonly T algorithm, ReadOnlySpan<byte> data, Span<byte> buffer, ReadOnlySpan<byte> key = default)
where T : IHashAlgorithm
{
//hash the buffer or hmac if key is not empty
diff --git a/lib/Hashing.Portable/src/Native/MonoCypher/IHashStream.cs b/lib/Hashing.Portable/src/Native/MonoCypher/IHashStream.cs
index 29def42..914e498 100644
--- a/lib/Hashing.Portable/src/Native/MonoCypher/IHashStream.cs
+++ b/lib/Hashing.Portable/src/Native/MonoCypher/IHashStream.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Hashing.Portable
@@ -42,7 +42,7 @@ namespace VNLib.Hashing.Native.MonoCypher
/// </summary>
/// <param name="mRef">A reference to the first byte of the sequence</param>
/// <param name="mSize">The size of the sequence</param>
- void Update(ref byte mRef, uint mSize);
+ void Update(ref readonly byte mRef, uint mSize);
/// <summary>
/// Flushes the hash of this stream to the specified buffer
diff --git a/lib/Hashing.Portable/src/Native/MonoCypher/IHmacStream.cs b/lib/Hashing.Portable/src/Native/MonoCypher/IHmacStream.cs
index 0ddc236..6a63c81 100644
--- a/lib/Hashing.Portable/src/Native/MonoCypher/IHmacStream.cs
+++ b/lib/Hashing.Portable/src/Native/MonoCypher/IHmacStream.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Hashing.Portable
@@ -41,6 +41,6 @@ namespace VNLib.Hashing.Native.MonoCypher
/// <param name="key">A reference to the first byte of key data to import</param>
/// <param name="keySize">The size of the key buffer</param>
/// <exception cref="System.ArgumentException"></exception>
- void Initialize(ref byte key, byte keySize);
+ void Initialize(ref readonly byte key, byte keySize);
}
} \ No newline at end of file
diff --git a/lib/Hashing.Portable/src/Native/MonoCypher/MCBlake2Module.cs b/lib/Hashing.Portable/src/Native/MonoCypher/MCBlake2Module.cs
index e8f0156..6468389 100644
--- a/lib/Hashing.Portable/src/Native/MonoCypher/MCBlake2Module.cs
+++ b/lib/Hashing.Portable/src/Native/MonoCypher/MCBlake2Module.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Hashing.Portable
@@ -54,10 +54,21 @@ namespace VNLib.Hashing.Native.MonoCypher
[SafeMethodName("Blake2GetHashSize")]
internal delegate uint Blake2GetHashSize(IntPtr context);
-
+ /// <summary>
+ /// The maximum hash size (in bytes) the Blake2b algorithm supports
+ /// </summary>
public const int MaxHashSize = 64;
+ /// <summary>
+ /// The maximum key size (in bytes) the Blake2b algorithm supports
+ /// </summary>
public const int MaxKeySize = 64;
+ /// <summary>
+ /// The minimum suggested hash size (in bytes) for KDFs
+ /// </summary>
public const int MinSuggestedKDFHashSize = 32;
+ /// <summary>
+ /// The minimum suggested hash size (in bytes) for MACs
+ /// </summary>
public const int MinSuggestedMACHashSize = 16;
/// <summary>
@@ -265,6 +276,7 @@ namespace VNLib.Hashing.Native.MonoCypher
return output.Length;
}
+ //Error codes from the native library
const int ERR_NULL_PTR = -1;
const int ERR_HASH_LEN_INVLID = -16;
const int ERR_KEY_LEN_INVALID = -17;
@@ -272,6 +284,8 @@ namespace VNLib.Hashing.Native.MonoCypher
private static void ThrowOnBlake2Error(int result)
{
+#pragma warning disable CA2208 // Instantiate argument exceptions correctly
+
switch (result)
{
//Success
@@ -288,12 +302,13 @@ namespace VNLib.Hashing.Native.MonoCypher
throw new ArgumentOutOfRangeException("keyLen", "The key length is invalid");
case ERR_KEY_PTR_INVALID:
- throw new ArgumentException("The key pointer is null");
+ throw new ArgumentNullException("key","The key pointer is null");
default:
throw new Exception($"An unknown error occured while hashing: {result}");
}
+#pragma warning restore CA2208 // Instantiate argument exceptions correctly
}
private sealed class Blake2Stream : SafeHandle, IHashStream, IHmacStream
@@ -353,17 +368,14 @@ namespace VNLib.Hashing.Native.MonoCypher
}
///<inheritdoc/>
- public void Initialize(ref byte key, byte keySize)
+ public void Initialize(ref readonly byte key, byte keySize)
{
- if (Unsafe.IsNullRef(ref key))
+ if (Unsafe.IsNullRef(in key))
{
throw new ArgumentNullException(nameof(key));
}
- if(keySize > MaxKeySize)
- {
- throw new ArgumentOutOfRangeException(nameof(keySize), $"The key size must be between 1 and {MaxKeySize} inclusive bytes");
- }
+ ArgumentOutOfRangeException.ThrowIfGreaterThan(keySize, MaxKeySize);
//Make sure context is initialized
InitContextHandle();
@@ -377,11 +389,11 @@ namespace VNLib.Hashing.Native.MonoCypher
}
///<inheritdoc/>
- public void Update(ref byte mRef, uint mSize)
+ public void Update(ref readonly byte mRef, uint mSize)
{
this.ThrowIfClosed();
- if (Unsafe.IsNullRef(ref mRef))
+ if (Unsafe.IsNullRef(in mRef))
{
throw new ArgumentNullException(nameof(mRef));
}
@@ -401,10 +413,7 @@ namespace VNLib.Hashing.Native.MonoCypher
private void InitContextHandle()
{
- if (IsClosed)
- {
- throw new ObjectDisposedException(nameof(Blake2Stream));
- }
+ ObjectDisposedException.ThrowIf(IsClosed, this);
//alloc buffer on the heap if not allocated
if (handle == IntPtr.Zero)
diff --git a/lib/Hashing.Portable/src/Native/MonoCypher/MCHashingStreamExtensions.cs b/lib/Hashing.Portable/src/Native/MonoCypher/MCHashingStreamExtensions.cs
index 3f27539..1b1bde7 100644
--- a/lib/Hashing.Portable/src/Native/MonoCypher/MCHashingStreamExtensions.cs
+++ b/lib/Hashing.Portable/src/Native/MonoCypher/MCHashingStreamExtensions.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Hashing.Portable
@@ -55,15 +55,12 @@ namespace VNLib.Hashing.Native.MonoCypher
/// <exception cref="ArgumentNullException"></exception>
public static void Update(this IHashStream hashStream, void* message, uint mSize)
{
- if (message == null)
- {
- throw new ArgumentNullException(nameof(message));
- }
- _ = hashStream ?? throw new ArgumentNullException(nameof(hashStream));
+ ArgumentNullException.ThrowIfNull(message);
+ ArgumentNullException.ThrowIfNull(hashStream);
//get ref from pointer
ref byte mRef = ref Unsafe.AsRef<byte>(message);
- hashStream.Update(ref mRef, mSize);
+ hashStream.Update(in mRef, mSize);
}
/// <summary>
@@ -75,16 +72,15 @@ namespace VNLib.Hashing.Native.MonoCypher
/// <exception cref="ArgumentNullException"></exception>
public static void Update(this IHashStream hashStream, ReadOnlySpan<byte> message)
{
- _ = hashStream ?? throw new ArgumentNullException(nameof(hashStream));
-
- if(message.Length == 0)
+ ArgumentNullException.ThrowIfNull(hashStream);
+ if (message.Length == 0)
{
return;
}
//Marshal reference to span
ref byte mRef = ref MemoryMarshal.GetReference(message);
- hashStream.Update(ref mRef, (uint)message.Length);
+ hashStream.Update(in mRef, (uint)message.Length);
}
/// <summary>
@@ -96,7 +92,7 @@ namespace VNLib.Hashing.Native.MonoCypher
/// <exception cref="ArgumentNullException"></exception>
public static void Update(this IHashStream hashStream, ReadOnlyMemory<byte> message)
{
- _ = hashStream ?? throw new ArgumentNullException(nameof(hashStream));
+ ArgumentNullException.ThrowIfNull(hashStream);
if (message.Length == 0)
{
return;
@@ -130,11 +126,8 @@ namespace VNLib.Hashing.Native.MonoCypher
/// <exception cref="ArgumentNullException"></exception>
public static void Flush(this IHashStream hashStream, void* hashOut, byte hashSize)
{
- if (hashOut == null)
- {
- throw new ArgumentNullException(nameof(hashOut));
- }
- _ = hashStream ?? throw new ArgumentNullException(nameof(hashStream));
+ ArgumentNullException.ThrowIfNull(hashOut);
+ ArgumentNullException.ThrowIfNull(hashStream);
//get ref from pointer
ref byte hashOutRef = ref Unsafe.AsRef<byte>(hashOut);
@@ -151,12 +144,8 @@ namespace VNLib.Hashing.Native.MonoCypher
/// <exception cref="ArgumentNullException"></exception>
public static void Flush(this IHashStream hashStream, Span<byte> hashOut)
{
- _ = hashStream ?? throw new ArgumentNullException(nameof(hashStream));
-
- if (hashOut.Length != hashStream.HashSize)
- {
- throw new ArgumentException("The hash output must be the configured hash size", nameof(hashOut));
- }
+ ArgumentNullException.ThrowIfNull(hashStream);
+ ArgumentOutOfRangeException.ThrowIfNotEqual(hashOut.Length, hashStream.HashSize, nameof(hashOut));
//Marshal reference to span and flush
ref byte hashOutRef = ref MemoryMarshal.GetReference(hashOut);
@@ -173,12 +162,8 @@ namespace VNLib.Hashing.Native.MonoCypher
/// <exception cref="ArgumentNullException"></exception>
public static void Flush(this IHashStream hashStream, Memory<byte> hashOut)
{
- _ = hashStream ?? throw new ArgumentNullException(nameof(hashStream));
-
- if (hashOut.Length != hashStream.HashSize)
- {
- throw new ArgumentException("The hash output must be the configured hash size", nameof(hashOut));
- }
+ ArgumentNullException.ThrowIfNull(hashStream);
+ ArgumentOutOfRangeException.ThrowIfNotEqual(hashOut.Length, hashStream.HashSize, nameof(hashOut));
//Pin memory block instead of span marshalling
using MemoryHandle hashOutHandle = hashOut.Pin();
@@ -217,16 +202,10 @@ namespace VNLib.Hashing.Native.MonoCypher
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static void Initialize(this IHmacStream stream, byte* key, byte keySize)
{
- _ = stream ?? throw new ArgumentNullException(nameof(stream));
-
- if (key == null)
- {
- throw new ArgumentNullException(nameof(key));
- }
- if (keySize == 0 || keySize > stream.MaxKeySize)
- {
- throw new ArgumentOutOfRangeException(nameof(keySize), $"The key size must be between 1 and {stream.MaxKeySize} inclusive");
- }
+ ArgumentNullException.ThrowIfNull(stream);
+ ArgumentNullException.ThrowIfNull(key);
+ ArgumentOutOfRangeException.ThrowIfEqual(keySize, 0);
+ ArgumentOutOfRangeException.ThrowIfGreaterThan(keySize, stream.MaxKeySize);
//Get reference to key
ref byte asRef = ref Unsafe.AsRef<byte>(key);
@@ -248,12 +227,8 @@ namespace VNLib.Hashing.Native.MonoCypher
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static void Initialize(this IHmacStream stream, ReadOnlySpan<byte> key)
{
- _ = stream ?? throw new ArgumentNullException(nameof(stream));
-
- if (key.Length > stream.MaxKeySize)
- {
- throw new ArgumentOutOfRangeException(nameof(key), $"The hash size must be less than or equal to {stream.MaxKeySize}");
- }
+ ArgumentNullException.ThrowIfNull(stream);
+ ArgumentOutOfRangeException.ThrowIfGreaterThan(key.Length, stream.MaxKeySize, nameof(key));
//Get span ref and call interface method
ref byte asRef = ref MemoryMarshal.GetReference(key);
@@ -275,12 +250,8 @@ namespace VNLib.Hashing.Native.MonoCypher
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static void Initialize(this IHmacStream stream, ReadOnlyMemory<byte> key)
{
- _ = stream ?? throw new ArgumentNullException(nameof(stream));
-
- if (key.Length > stream.MaxKeySize)
- {
- throw new ArgumentOutOfRangeException(nameof(key), $"The hash size must be less than or equal to {stream.MaxKeySize}");
- }
+ ArgumentNullException.ThrowIfNull(stream);
+ ArgumentOutOfRangeException.ThrowIfGreaterThan(key.Length, stream.MaxKeySize, nameof(key));
//If key is default, then h.Pointer will be null, which is handled
using MemoryHandle h = key.Pin();
diff --git a/lib/Hashing.Portable/src/Native/MonoCypher/MCPasswordModule.cs b/lib/Hashing.Portable/src/Native/MonoCypher/MCPasswordModule.cs
index 9dbcb41..66e7726 100644
--- a/lib/Hashing.Portable/src/Native/MonoCypher/MCPasswordModule.cs
+++ b/lib/Hashing.Portable/src/Native/MonoCypher/MCPasswordModule.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Hashing.Portable
@@ -60,15 +60,15 @@ namespace VNLib.Hashing.Native.MonoCypher
public static IArgon2Library Argon2CreateLibrary(this MonoCypherLibrary Library, IUnmangedHeap heap)
{
//Validate arguments
- _ = Library ?? throw new ArgumentNullException(nameof(Library));
- _ = heap ?? throw new ArgumentNullException(nameof(heap));
+ ArgumentNullException.ThrowIfNull(Library);
+ ArgumentNullException.ThrowIfNull(heap);
return new Argon2HashLib(Library, heap);
}
private static void Hash(this MonoCypherLibrary library, IUnmangedHeap heap, Argon2Context* context)
{
- _ = library ?? throw new ArgumentNullException(nameof(library));
- _ = heap ?? throw new ArgumentNullException(nameof(heap));
+ ArgumentNullException.ThrowIfNull(library);
+ ArgumentNullException.ThrowIfNull(heap);
//Validate context
ValidateContext(context);
@@ -117,10 +117,7 @@ namespace VNLib.Hashing.Native.MonoCypher
private static void ValidateContext(Argon2Context* context)
{
- if(context == null)
- {
- throw new ArgumentNullException(nameof(context));
- }
+ ArgumentNullException.ThrowIfNull(context);
if (context->outptr == null || context->outlen == 0)
{
@@ -144,10 +141,7 @@ namespace VNLib.Hashing.Native.MonoCypher
///<inheritdoc/>
public int Argon2Hash(IntPtr context)
{
- if(context == IntPtr.Zero)
- {
- throw new ArgumentNullException(nameof(context), "");
- }
+ ArgumentNullException.ThrowIfNull((void*)context);
//Invoke hash with argon2 context pointer
Hash(Library, BufferHeap, (Argon2Context*)context);
diff --git a/lib/Hashing.Portable/src/Native/MonoCypher/MonoCypherLibrary.cs b/lib/Hashing.Portable/src/Native/MonoCypher/MonoCypherLibrary.cs
index ff517ef..11e524b 100644
--- a/lib/Hashing.Portable/src/Native/MonoCypher/MonoCypherLibrary.cs
+++ b/lib/Hashing.Portable/src/Native/MonoCypher/MonoCypherLibrary.cs
@@ -131,15 +131,15 @@ namespace VNLib.Hashing.Native.MonoCypher
functions = new FunctionTable
{
//Argon2
- Argon2Hash = library.DangerousGetMethod<MCPasswordModule.Argon2Hash>(),
- Argon2CalcWorkArea = library.DangerousGetMethod<MCPasswordModule.Argon2CalcWorkArea>(),
+ Argon2Hash = library.DangerousGetFunction<MCPasswordModule.Argon2Hash>(),
+ Argon2CalcWorkArea = library.DangerousGetFunction<MCPasswordModule.Argon2CalcWorkArea>(),
//Blake2b
- Blake2GetContextSize = library.DangerousGetMethod<MCBlake2Module.Blake2GetContextSize>(),
- Blake2Init = library.DangerousGetMethod<MCBlake2Module.Blake2Init>(),
- Blake2Update = library.DangerousGetMethod<MCBlake2Module.Blake2Update>(),
- Blake2Final = library.DangerousGetMethod<MCBlake2Module.Blake2Final>(),
- Blake2GethashSize = library.DangerousGetMethod<MCBlake2Module.Blake2GetHashSize>(),
+ Blake2GetContextSize = library.DangerousGetFunction<MCBlake2Module.Blake2GetContextSize>(),
+ Blake2Init = library.DangerousGetFunction<MCBlake2Module.Blake2Init>(),
+ Blake2Update = library.DangerousGetFunction<MCBlake2Module.Blake2Update>(),
+ Blake2Final = library.DangerousGetFunction<MCBlake2Module.Blake2Final>(),
+ Blake2GethashSize = library.DangerousGetFunction<MCBlake2Module.Blake2GetHashSize>(),
};
}
diff --git a/lib/Hashing.Portable/tests/ManagedHashTests.cs b/lib/Hashing.Portable/tests/ManagedHashTests.cs
index 8b2a3c3..a9fa467 100644
--- a/lib/Hashing.Portable/tests/ManagedHashTests.cs
+++ b/lib/Hashing.Portable/tests/ManagedHashTests.cs
@@ -1,11 +1,10 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Text;
-
-using VNLib.Utils.Memory;
-using VNLib.Utils;
using System.Diagnostics;
+using VNLib.Utils;
+using VNLib.Utils.Memory;
namespace VNLib.Hashing.Tests
{
@@ -27,18 +26,7 @@ namespace VNLib.Hashing.Tests
if (alg == HashAlg.None) continue;
//Skip unsupported algorithms
- if (alg == HashAlg.BlAKE2B && !ManagedHash.SupportsBlake2b) continue;
-
- if (!ManagedHash.SupportsSha3)
- {
- switch (alg)
- {
- case HashAlg.SHA3_256:
- case HashAlg.SHA3_384:
- case HashAlg.SHA3_512:
- continue;
- }
- }
+ if (!ManagedHash.IsAlgSupported(alg)) continue;
//Compute hash
ERRNO hashSize = ManagedHash.ComputeHash(testData, heapBuffer.Span, alg);
@@ -82,18 +70,7 @@ namespace VNLib.Hashing.Tests
if (alg == HashAlg.None) continue;
//Skip unsupported algorithms
- if (alg == HashAlg.BlAKE2B && !ManagedHash.SupportsBlake2b) continue;
-
- if (!ManagedHash.SupportsSha3)
- {
- switch (alg)
- {
- case HashAlg.SHA3_256:
- case HashAlg.SHA3_384:
- case HashAlg.SHA3_512:
- continue;
- }
- }
+ if (!ManagedHash.IsAlgSupported(alg)) continue;
//Compute hash
ERRNO hashSize = ManagedHash.ComputeHmac(testKey, testData, heapBuffer.Span, alg);
diff --git a/lib/Hashing.Portable/tests/VNLib.Hashing.PortableTests.csproj b/lib/Hashing.Portable/tests/VNLib.Hashing.PortableTests.csproj
index e68b1a2..e61aa95 100644
--- a/lib/Hashing.Portable/tests/VNLib.Hashing.PortableTests.csproj
+++ b/lib/Hashing.Portable/tests/VNLib.Hashing.PortableTests.csproj
@@ -14,9 +14,9 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
- <PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
- <PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
+ <PackageReference Include="MSTest.TestAdapter" Version="3.2.0" />
+ <PackageReference Include="MSTest.TestFramework" Version="3.2.0" />
<PackageReference Include="coverlet.collector" Version="6.0.0" />
</ItemGroup>
diff --git a/lib/Net.Compression/VNLib.Net.Compression/LibraryWrapper.cs b/lib/Net.Compression/VNLib.Net.Compression/LibraryWrapper.cs
index fe8fb5a..78cfd17 100644
--- a/lib/Net.Compression/VNLib.Net.Compression/LibraryWrapper.cs
+++ b/lib/Net.Compression/VNLib.Net.Compression/LibraryWrapper.cs
@@ -114,21 +114,21 @@ namespace VNLib.Net.Compression
//build the method table
MethodTable methods = new()
{
- GetMethods = lib.DangerousGetMethod<GetSupportedMethodsDelegate>(),
+ GetMethods = lib.DangerousGetFunction<GetSupportedMethodsDelegate>(),
- GetBlockSize = lib.DangerousGetMethod<GetBlockSizeDelegate>(),
+ GetBlockSize = lib.DangerousGetFunction<GetBlockSizeDelegate>(),
- GetCompType = lib.DangerousGetMethod<GetCompressorTypeDelegate>(),
+ GetCompType = lib.DangerousGetFunction<GetCompressorTypeDelegate>(),
- GetCompLevel = lib.DangerousGetMethod<GetCompressorLevelDelegate>(),
+ GetCompLevel = lib.DangerousGetFunction<GetCompressorLevelDelegate>(),
- Alloc = lib.DangerousGetMethod<AllocateCompressorDelegate>(),
+ Alloc = lib.DangerousGetFunction<AllocateCompressorDelegate>(),
- Free = lib.DangerousGetMethod<FreeCompressorDelegate>(),
+ Free = lib.DangerousGetFunction<FreeCompressorDelegate>(),
- GetOutputSize = lib.DangerousGetMethod<GetCompressedSizeDelegate>(),
+ GetOutputSize = lib.DangerousGetFunction<GetCompressedSizeDelegate>(),
- Compress = lib.DangerousGetMethod<CompressBlockDelegate>()
+ Compress = lib.DangerousGetFunction<CompressBlockDelegate>()
};
return new (lib, filePath, in methods);
diff --git a/lib/Net.Compression/VNLib.Net.CompressionTests/VNLib.Net.CompressionTests.csproj b/lib/Net.Compression/VNLib.Net.CompressionTests/VNLib.Net.CompressionTests.csproj
index 97549db..bf1c1a1 100644
--- a/lib/Net.Compression/VNLib.Net.CompressionTests/VNLib.Net.CompressionTests.csproj
+++ b/lib/Net.Compression/VNLib.Net.CompressionTests/VNLib.Net.CompressionTests.csproj
@@ -8,9 +8,9 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
- <PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
- <PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
+ <PackageReference Include="MSTest.TestAdapter" Version="3.2.0" />
+ <PackageReference Include="MSTest.TestFramework" Version="3.2.0" />
<PackageReference Include="coverlet.collector" Version="6.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
diff --git a/lib/Net.Compression/vnlib_compress/CMakeLists.txt b/lib/Net.Compression/vnlib_compress/CMakeLists.txt
index 2eb234e..17b01ca 100644
--- a/lib/Net.Compression/vnlib_compress/CMakeLists.txt
+++ b/lib/Net.Compression/vnlib_compress/CMakeLists.txt
@@ -44,6 +44,9 @@ set(CMAKE_C_STANDARD_REQUIRED ON)
#enable position independent code (for shared libraries with exports)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+#since were buildiing in tree, set the export defintiions
+add_definitions(-DVNLIB_EXPORTING)
+
message(STATUS "Build type is '${CMAKE_BUILD_TYPE}'")
#include checks for zlib and brotli
diff --git a/lib/Net.Compression/vnlib_compress/Taskfile.yaml b/lib/Net.Compression/vnlib_compress/Taskfile.yaml
index 74ab24a..5271061 100644
--- a/lib/Net.Compression/vnlib_compress/Taskfile.yaml
+++ b/lib/Net.Compression/vnlib_compress/Taskfile.yaml
@@ -18,32 +18,19 @@ tasks:
cmds:
- cmd: echo "Building vnlib_compress"
silent: true
+
+ #make third-party dir before cloning libs
+ - cmd: powershell -Command "mkdir '{{.THIRD_PARTY_DIR}}' -Force"
+ ignore_error: true
- #make dirs on non-win
- - cmd: mkdir {{.THIRD_PARTY_DIR}}
- platforms: ['linux', 'darwin']
-
- #make dirs on windows
- - cmd: powershell -Command "mkdir {{.THIRD_PARTY_DIR}} -Force"
- platforms: ['windows']
-
- #clone libs
- - cmd: cd {{.THIRD_PARTY_DIR}} && git clone https://github.com/cloudflare/zlib.git
- ignore_error: true
-
- - cmd: cd {{.THIRD_PARTY_DIR}} && git clone https://github.com/google/brotli.git
- ignore_error: true
+ - task: zlib
+ - task: brotli
#invoke cmake for build
- - cmake -B./build -DCMAKE_BUILD_TYPE=RELEASE {{.CMAKE_ARGS}}
+ - cmake -B./build {{.CMAKE_ARGS}}
- #build for Windows
- - cmd: cd build && msbuild {{.PROJECT_NAME}}.sln /p:Configuration=release {{.BUILD_FLAGS}}
- platforms: ['windows']
-
- #using make
- - cmd: cd build && make
- platforms: ['linux', 'darwin']
+ #build for platform
+ - cmake --build build/ --config Release
#when build succeeds, archive the output into a tgz
@@ -51,13 +38,28 @@ tasks:
cmds:
- cmd: powershell mkdir -Force './bin'
#copy source code to target
- - powershell -Command "tar --exclude build/* --exclude .vs/* --exclude bin/* -czvf bin/src.tgz ."
-
- postbuild_failed:
- cmds: []
+ - powershell -Command "tar --exclude build/* --exclude .vs/* --exclude bin/* -czf bin/src.tgz ."
#Remove the output dirs on clean
clean:
ignore_error: true
cmds:
- cmd: powershell Remove-Item -Recurse './bin'
+
+ #update or install the cloudflare fork of zlib library
+ zlib:
+ internal: true
+ status:
+ - cd {{.THIRD_PARTY_DIR}} && git clone https://github.com/cloudflare/zlib.git
+
+ cmds:
+ - cd {{.THIRD_PARTY_DIR}}/zlib && git pull
+
+ #update or install the google brotli library
+ brotli:
+ internal: true
+ status:
+ - cd {{.THIRD_PARTY_DIR}} && git clone https://github.com/google/brotli.git
+ cmds:
+ - cd {{.THIRD_PARTY_DIR}}/brotli && git pull
+ \ No newline at end of file
diff --git a/lib/Net.Compression/vnlib_compress/compression.c b/lib/Net.Compression/vnlib_compress/compression.c
index 56d9157..ffe280b 100644
--- a/lib/Net.Compression/vnlib_compress/compression.c
+++ b/lib/Net.Compression/vnlib_compress/compression.c
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: vnlib_compress
@@ -40,26 +40,6 @@
#include "feature_zlib.h"
#endif /* VNLIB_COMPRESSOR_GZIP_ENABLED */
-
-/*
-* Public API functions
-*/
-VNLIB_EXPORT CompressorType VNLIB_CC GetSupportedCompressors(void);
-
-VNLIB_EXPORT int64_t VNLIB_CC GetCompressorBlockSize(_In_ const void* compressor);
-
-VNLIB_EXPORT CompressorType VNLIB_CC GetCompressorType(_In_ const void* compressor);
-
-VNLIB_EXPORT CompressionLevel VNLIB_CC GetCompressorLevel(_In_ const void* compressor);
-
-VNLIB_EXPORT void* VNLIB_CC AllocateCompressor(CompressorType type, CompressionLevel level);
-
-VNLIB_EXPORT int VNLIB_CC FreeCompressor(_In_ void* compressor);
-
-VNLIB_EXPORT int64_t VNLIB_CC GetCompressedSize(_In_ const void* compressor, uint64_t inputLength, int32_t flush);
-
-VNLIB_EXPORT int VNLIB_CC CompressBlock(_In_ const void* compressor, CompressionOperation* operation);
-
/*
Gets the supported compressors, this is defined at compile time and is a convenience method for
the user to know what compressors are supported at runtime.
diff --git a/lib/Net.Compression/vnlib_compress/compression.h b/lib/Net.Compression/vnlib_compress/compression.h
index a4fc65f..ae3bb8f 100644
--- a/lib/Net.Compression/vnlib_compress/compression.h
+++ b/lib/Net.Compression/vnlib_compress/compression.h
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: vnlib_compress
@@ -154,4 +154,71 @@ typedef struct CompressionOperationStruct {
} CompressionOperation;
+/*
+* Public API functions
+*/
+VNLIB_EXPORT CompressorType VNLIB_CC GetSupportedCompressors(void);
+
+/*
+* Returns the suggested block size for the underlying compressor.
+*
+* @param compressor A pointer to the desired compressor instance to query.
+* @return The suggested block size for the underlying compressor in bytes
+*/
+VNLIB_EXPORT int64_t VNLIB_CC GetCompressorBlockSize(_In_ const void* compressor);
+
+/*
+* Gets the compressor type of the specified compressor instance.
+*
+* @param compressor A pointer to the desired compressor instance to query.
+* @return The type of the specified compressor instance.
+*/
+VNLIB_EXPORT CompressorType VNLIB_CC GetCompressorType(_In_ const void* compressor);
+
+/*
+* Gets the compression level of the specified compressor instance.
+*
+* @param compressor A pointer to the desired compressor instance to query.
+* @return The compression level of the specified compressor instance.
+*/
+VNLIB_EXPORT CompressionLevel VNLIB_CC GetCompressorLevel(_In_ const void* compressor);
+
+/*
+* Allocates a new compressor instance on the native heap of the desired compressor type.
+*
+* @param type The desired compressor type.
+* @param level The desired compression level.
+* @return A pointer to the newly allocated compressor instance. NULL if the compressor
+could not be allocated.
+*/
+VNLIB_EXPORT void* VNLIB_CC AllocateCompressor(CompressorType type, CompressionLevel level);
+
+/*
+* Frees a previously allocated compressor instance.
+*
+* @param compressor A pointer to the desired compressor instance to free.
+* @return The underlying compressor's native return code.
+*/
+VNLIB_EXPORT int VNLIB_CC FreeCompressor(_In_ void* compressor);
+
+/*
+* Computes the maximum compressed size of the specified input data. This is not supported
+ for all compression types.
+*
+* @param compressor A pointer to the initialized compressor instance to use.
+* @param inputLength The length of the input data in bytes.
+* @return The maximum compressed size of the specified input data in bytes.
+*/
+VNLIB_EXPORT int64_t VNLIB_CC GetCompressedSize(_In_ const void* compressor, uint64_t inputLength, int32_t flush);
+
+
+/*
+* Perform compression operation using the specified compressor instance.
+*
+* @param compressor A pointer to the initialized compressor instance to use.
+* @param operation A pointer to the compression operation structure
+* @return The underlying compressor's native return code
+*/
+VNLIB_EXPORT int VNLIB_CC CompressBlock(_In_ const void* compressor, CompressionOperation* operation);
+
#endif /* !VNLIB_COMPRESS_MAIN_H_ */ \ No newline at end of file
diff --git a/lib/Net.Compression/vnlib_compress/feature_brotli.c b/lib/Net.Compression/vnlib_compress/feature_brotli.c
index a300500..3a3e330 100644
--- a/lib/Net.Compression/vnlib_compress/feature_brotli.c
+++ b/lib/Net.Compression/vnlib_compress/feature_brotli.c
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: vnlib_compress
@@ -39,7 +39,7 @@ static void _brFreeCallback(void* opaque, void* address)
{
(void)opaque;
- //Brotli may pass a null address to the free callback
+ /*Brotli may pass a null address to the free callback*/
if (address)
{
vnfree(address);
@@ -51,6 +51,8 @@ int BrAllocCompressor(CompressorState* state)
{
BrotliEncoderState* comp;
+ assert(state != NULL);
+
/*
* Never allow no compression, it is not supported by the br encoder
*/
@@ -121,6 +123,8 @@ int BrAllocCompressor(CompressorState* state)
void BrFreeCompressor(CompressorState* state)
{
+ assert(state != NULL);
+
/*
* Free the compressor instance if it exists
*/
diff --git a/lib/Net.Compression/vnlib_compress/feature_zlib.c b/lib/Net.Compression/vnlib_compress/feature_zlib.c
index 5dbd7ad..9993b43 100644
--- a/lib/Net.Compression/vnlib_compress/feature_zlib.c
+++ b/lib/Net.Compression/vnlib_compress/feature_zlib.c
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: vnlib_compress
@@ -50,6 +50,8 @@ int DeflateAllocCompressor(CompressorState* state)
int result, compLevel;
z_stream* stream;
+ assert(state);
+
/*
* Allocate the z-stream state on the heap so we can
* store it in the compressor state
@@ -149,6 +151,8 @@ int DeflateFreeCompressor(CompressorState* state)
{
int result;
+ assert(state);
+
/*
* Free the z-stream state, only if the compressor is initialized
*/
diff --git a/lib/Net.Compression/vnlib_compress/util.h b/lib/Net.Compression/vnlib_compress/util.h
index 5d87c8f..344a28b 100644
--- a/lib/Net.Compression/vnlib_compress/util.h
+++ b/lib/Net.Compression/vnlib_compress/util.h
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: vnlib_compress
@@ -29,29 +29,77 @@
/*
* Stub missing types and constants for GCC
*/
-#if defined(__GNUC__)
-#define inline __inline__
-#define VNLIB_EXPORT __attribute__((visibility("default")))
-#define VNLIB_CC
-#elif defined(_MSC_VER)
-#define VNLIB_EXPORT __declspec(dllexport)
-#define VNLIB_CC __cdecl
-#endif /* WIN32 */
-#define ERR_INVALID_PTR -1
-#define ERR_OUT_OF_MEMORY -2
-
-#define TRUE 1
-#define FALSE 0
+#if defined(_MSC_VER) || defined(WIN32) || defined(_WIN32)
+ #define IS_WINDOWS
+#endif
+//Set api export calling convention (allow used to override)
+#ifndef VNLIB_CC
+ #ifdef IS_WINDOWS
+ //STD for importing to other languages such as .NET
+ #define VNLIB_CC __stdcall
+ #else
+ #define VNLIB_CC
+ #endif
+#endif // !VNLIB_CC
+
+#ifndef VNLIB_EXPORT //Allow users to disable the export/impoty macro if using source code directly
+ #ifdef VNLIB_EXPORTING
+ #ifdef IS_WINDOWS
+ #define VNLIB_EXPORT __declspec(dllexport)
+ #else
+ #define VNLIB_EXPORT __attribute__((visibility("default")))
+ #endif // IS_WINDOWS
+ #else
+ #ifdef IS_WINDOWS
+ #define VNLIB_EXPORT __declspec(dllimport)
+ #else
+ #define VNLIB_EXPORT
+ #endif // IS_WINDOWS
+ #endif // !VNLIB_EXPORTING
+#endif // !VNLIB_EXPORT
+
+
+/* If not Windows, define inline */
+#ifndef IS_WINDOWS
+ #ifndef inline
+ #define inline __inline__
+ #endif // !inline
+#endif // !IS_WINDOWS
+
+//NULL
#ifndef NULL
-#define NULL 0
-#endif /* !NULL */
+ #define NULL ((void*)0)
+#endif // !NULL
+
+#ifndef TRUE
+ #define TRUE 1
+#endif // !TRUE
+
+#ifndef FALSE
+ #define FALSE 0
+#endif // !FALSE
#ifndef _In_
-#define _In_
+ #define _In_
+#endif
+
+/*
+* Add debug runtime assertions
+*/
+#ifdef DEBUG
+ #include <assert.h>
+#else
+ #define assert(x) {}
#endif
+/*
+* ERRORS AND CONSTANTS
+*/
+#define ERR_INVALID_PTR -1
+#define ERR_OUT_OF_MEMORY -2
+
#if defined(VNLIB_CUSTOM_MALLOC_ENABLE)
/*
@@ -60,15 +108,6 @@
#include <NativeHeapApi.h>
-/*
-* Add debug runtime assertions
-*/
-#ifdef DEBUG
- #define NDEBUG
- #include <assert.h>
-#else
- #define assert(x)
-#endif
/*
* Add overrides for malloc, calloc, and free that use
diff --git a/lib/Net.Http/src/Core/Buffering/HttpBufferElement.cs b/lib/Net.Http/src/Core/Buffering/HttpBufferElement.cs
index 0d26017..774ed6a 100644
--- a/lib/Net.Http/src/Core/Buffering/HttpBufferElement.cs
+++ b/lib/Net.Http/src/Core/Buffering/HttpBufferElement.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Net.Http
@@ -63,16 +63,10 @@ namespace VNLib.Net.Http.Core.Buffering
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual ref byte DangerousGetBinRef(int offset)
{
- if (offset >= _handle.Size)
- {
- throw new ArgumentOutOfRangeException(nameof(offset));
- }
-
- //Get ref to pinned memory
- ref byte start = ref _handle.GetRef();
+ ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(offset, _handle.Size);
//Add offset to ref
- return ref Unsafe.Add(ref start, offset);
+ return ref Unsafe.Add(ref _handle.GetRef(), offset);
}
///<inheritdoc/>
@@ -85,9 +79,9 @@ namespace VNLib.Net.Http.Core.Buffering
=> (offset + size) < _handle.Size ? _handle.GetSpan(offset, size) : throw new ArgumentOutOfRangeException(nameof(offset));
- private readonly struct HandleState
+ private struct HandleState
{
- private readonly MemoryHandle _handle;
+ private MemoryHandle _handle;
private readonly IntPtr _pointer;
public readonly int Size;
diff --git a/lib/Net.Http/src/Core/HttpEncodedSegment.cs b/lib/Net.Http/src/Core/HttpEncodedSegment.cs
index 1103f83..bcb1f3b 100644
--- a/lib/Net.Http/src/Core/HttpEncodedSegment.cs
+++ b/lib/Net.Http/src/Core/HttpEncodedSegment.cs
@@ -39,7 +39,7 @@ namespace VNLib.Net.Http.Core
/// <param name="Buffer">The buffer containing the segment data</param>
/// <param name="Offset">The offset in the buffer to begin the segment at</param>
/// <param name="Length">The length of the segment</param>
- internal readonly record struct HttpEncodedSegment(byte[] Buffer, uint Offset, uint Length)
+ internal readonly record struct HttpEncodedSegment(byte[] Buffer, uint Offset, ushort Length)
{
/// <summary>
/// Validates the bounds of the array so calls to <see cref="DangerousCopyTo(Span{byte})"/>
@@ -88,8 +88,8 @@ namespace VNLib.Net.Http.Core
ref byte src = ref MemoryMarshal.GetArrayDataReference(Buffer);
//Call memmove with the buffer offset and desired length
- MemoryUtil.Memmove(ref src, Offset, ref output, 0, Length);
- return (int)Length;
+ MemoryUtil.SmallMemmove(ref src, Offset, ref output, 0, Length);
+ return Length;
}
/// <summary>
@@ -99,10 +99,11 @@ namespace VNLib.Net.Http.Core
/// <param name="data">The string data to encode</param>
/// <param name="enc">The encoder used to convert the character data to bytes</param>
/// <returns>The initalized <see cref="HttpEncodedSegment"/> structure</returns>
+ /// <exception cref="OverflowException"></exception>
public static HttpEncodedSegment FromString(string data, Encoding enc)
{
byte[] encoded = enc.GetBytes(data);
- return new HttpEncodedSegment(encoded, 0, (uint)encoded.Length);
+ return new HttpEncodedSegment(encoded, 0, checked((ushort)encoded.Length));
}
}
} \ No newline at end of file
diff --git a/lib/Net.Http/src/Core/HttpEvent.cs b/lib/Net.Http/src/Core/HttpEvent.cs
index a86bc20..e6f3b5b 100644
--- a/lib/Net.Http/src/Core/HttpEvent.cs
+++ b/lib/Net.Http/src/Core/HttpEvent.cs
@@ -98,6 +98,7 @@ namespace VNLib.Net.Http
//If stream is empty, ignore it, the server will default to 0 content length and avoid overhead
if (length == 0)
{
+ stream.Dispose();
return;
}
@@ -121,11 +122,12 @@ namespace VNLib.Net.Http
///<inheritdoc/>
void IHttpEvent.CloseResponse(HttpStatusCode code, ContentType type, IMemoryResponseReader entity)
{
- ArgumentNullException.ThrowIfNull(entity, nameof(entity));
+ ArgumentNullException.ThrowIfNull(entity);
//If stream is empty, ignore it, the server will default to 0 content length and avoid overhead
if (entity.Remaining == 0)
{
+ entity.Close();
return;
}
@@ -146,6 +148,36 @@ namespace VNLib.Net.Http
}
}
+ ///<inheritdoc/>
+ void IHttpEvent.CloseResponse(HttpStatusCode code, ContentType type, IHttpStreamResponse stream, long length)
+ {
+ ArgumentNullException.ThrowIfNull(stream);
+ ArgumentOutOfRangeException.ThrowIfNegative(length);
+
+ //If stream is empty, ignore it, the server will default to 0 content length and avoid overhead
+ if (length == 0)
+ {
+ stream.Dispose();
+ return;
+ }
+
+ //Set status code
+ Context.Response.SetStatusCode(code);
+
+ //Finally store the stream input
+ if (!Context.ResponseBody.TrySetResponseBody(stream, length))
+ {
+ throw new InvalidOperationException("A response body has already been set");
+ }
+
+ //User may want to set the content type header themselves
+ if (type != ContentType.NonSupported)
+ {
+ //Set content type header after body
+ Context.Response.Headers.Set(HttpResponseHeader.ContentType, HttpHelpers.GetContentTypeString(type));
+ }
+ }
+
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
internal void Clear()
{
diff --git a/lib/Net.Http/src/Core/InitDataBuffer.cs b/lib/Net.Http/src/Core/InitDataBuffer.cs
index 4d215d9..6a400bb 100644
--- a/lib/Net.Http/src/Core/InitDataBuffer.cs
+++ b/lib/Net.Http/src/Core/InitDataBuffer.cs
@@ -36,20 +36,14 @@ namespace VNLib.Net.Http.Core
/// A structure that buffers data remaining from an initial transport read. Stored
/// data will be read by copying.
/// </summary>
- internal readonly record struct InitDataBuffer
+ internal readonly struct InitDataBuffer(ArrayPool<byte> pool, byte[] buffer, int size)
{
const int POSITION_SEG_SIZE = sizeof(int);
- readonly int _dataSize;
- readonly byte[] _buffer;
- readonly ArrayPool<byte> _pool;
-
- InitDataBuffer(ArrayPool<byte> pool, byte[] buffer, int size)
- {
- _pool = pool;
- _buffer = buffer;
- _dataSize = size;
- }
+ readonly int _dataSize = size;
+ readonly byte[] _buffer = buffer;
+ readonly ArrayPool<byte> _pool = pool;
+
/// <summary>
/// Allocates the correct size buffer for the given data size
@@ -65,7 +59,7 @@ namespace VNLib.Net.Http.Core
return new(pool, buffer, dataSize);
}
- readonly Span<byte> _positionSegment
+ private readonly Span<byte> _positionSegment
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _buffer.AsSpan(0, POSITION_SEG_SIZE);
@@ -126,10 +120,6 @@ namespace VNLib.Net.Http.Core
/// Releases the internal buffer back to its pool
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal readonly void Release()
- {
- //Return buffer back to pool
- _pool.Return(_buffer);
- }
+ internal readonly void Release() => _pool.Return(_buffer);
}
}
diff --git a/lib/Net.Http/src/Core/Response/ChunkDataAccumulator.cs b/lib/Net.Http/src/Core/Response/ChunkDataAccumulator.cs
index 5e7be39..cacce4c 100644
--- a/lib/Net.Http/src/Core/Response/ChunkDataAccumulator.cs
+++ b/lib/Net.Http/src/Core/Response/ChunkDataAccumulator.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Net.Http
@@ -38,29 +38,20 @@ namespace VNLib.Net.Http.Core.Response
/// A specialized <see cref="IDataAccumulator{T}"/> for buffering data
/// in Http/1.1 chunks
/// </summary>
- internal readonly struct ChunkDataAccumulator
+ internal readonly struct ChunkDataAccumulator(IChunkAccumulatorBuffer Buffer, IHttpContextInformation Context)
{
/*
* The number of bytes to reserve at the beginning of the buffer
* for the chunk size segment. This is the maximum size of the
*/
public const int ReservedSize = 16;
-
- private readonly IHttpContextInformation Context;
- private readonly IChunkAccumulatorBuffer Buffer;
-
+
/*
* Must always leave enough room for trailing crlf at the end of
* the buffer
*/
private readonly int TotalMaxBufferSize => Buffer.Size - (int)Context.CrlfSegment.Length;
- public ChunkDataAccumulator(IChunkAccumulatorBuffer buffer, IHttpContextInformation context)
- {
- Context = context;
- Buffer = buffer;
- }
-
/// <summary>
/// Complets and returns the memory segment containing the chunk data to send
/// to the client. This also resets the accumulator.
@@ -128,10 +119,8 @@ namespace VNLib.Net.Http.Core.Response
* and use the memory range operator to get the segment from the reserved
* segment, to the actual end of the data segment.
*/
- private readonly Memory<byte> GetCompleteChunk(int reservedOffset, int accumulatedSize)
- {
- return Buffer.GetMemory()[reservedOffset..accumulatedSize];
- }
+ private readonly Memory<byte> GetCompleteChunk(int reservedOffset, int accumulatedSize)
+ => Buffer.GetMemory()[reservedOffset..accumulatedSize];
private static int GetPointerToEndOfUsedBuffer(int accumulatedSize) => accumulatedSize + ReservedSize;
@@ -195,7 +184,14 @@ namespace VNLib.Net.Http.Core.Response
ref byte reservedSegRef = ref buffer.DangerousGetBinRef(reservedOffset);
ref byte chunkSizeBufRef = ref MemoryMarshal.GetReference(chunkSizeBinBuffer);
- MemoryUtil.Memmove(ref chunkSizeBufRef, 0, ref reservedSegRef, 0, (uint)totalChunkBufferBytes);
+ //We know the block is super small
+ MemoryUtil.SmallMemmove(
+ ref chunkSizeBufRef,
+ 0,
+ ref reservedSegRef,
+ 0,
+ (ushort)totalChunkBufferBytes
+ );
return reservedOffset;
}
diff --git a/lib/Net.Http/src/Core/Response/ResponseWriter.cs b/lib/Net.Http/src/Core/Response/ResponseWriter.cs
index de46dce..b5a167c 100644
--- a/lib/Net.Http/src/Core/Response/ResponseWriter.cs
+++ b/lib/Net.Http/src/Core/Response/ResponseWriter.cs
@@ -51,7 +51,7 @@ namespace VNLib.Net.Http.Core.Response
//Buffering is required when a stream is set
///<inheritdoc/>
- public bool BufferRequired => _userState.Stream != null;
+ public bool BufferRequired => _userState.BufferRequired;
///<inheritdoc/>
public long Length => _userState.Legnth;
@@ -62,7 +62,7 @@ namespace VNLib.Net.Http.Core.Response
/// <param name="response">The stream response body to read</param>
/// <param name="length">Explicit length of the stream</param>
/// <returns>True if the response entity could be set, false if it has already been set</returns>
- internal bool TrySetResponseBody(Stream response, long length)
+ internal bool TrySetResponseBody(IHttpStreamResponse response, long length)
{
if (_userState.IsSet)
{
@@ -95,8 +95,28 @@ namespace VNLib.Net.Http.Core.Response
return true;
}
+ /// <summary>
+ /// Attempts to set the response entity
+ /// </summary>
+ /// <param name="rawStream">The raw stream response to set</param>
+ /// <param name="length">Explicit length of the raw stream</param>
+ /// <returns>True if the response entity could be set, false if it has already been set</returns>
+ internal bool TrySetResponseBody(Stream rawStream, long length)
+ {
+ if (_userState.IsSet)
+ {
+ return false;
+ }
+
+ Debug.Assert(rawStream != null, "Raw stream value is null, illegal operation");
+ Debug.Assert(length > -1, "explicit length passed a negative value, illegal operation");
+
+ //Assign user-state
+ _userState = new(rawStream, length);
+ return true;
+ }
+
private ReadOnlyMemory<byte> _readSegment;
- private ForwardOnlyMemoryReader<byte> _streamReader;
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
@@ -121,107 +141,68 @@ namespace VNLib.Net.Http.Core.Response
//Disposing of memory response can be deferred until the end of the request since its always syncrhonous
}
- else
+ else if(_userState.RawStream != null)
{
- /*
- * When streams are used, callers will submit an explict length value
- * which must be respected. This allows the stream size to differ from
- * the actual content length. This is useful for when the stream is
- * non-seekable, or does not have a known length
- */
-
- long total = 0;
- while (total < Length)
- {
- //get offset wrapper of the total buffer or remaining count
- Memory<byte> offset = buffer[..(int)Math.Min(buffer.Length, Length - total)];
-
- //read
- int read = await _userState.Stream!.ReadAsync(offset);
+ Debug.Assert(!buffer.IsEmpty, "Transfer buffer is required for streaming operations");
- //Guard
- if (read == 0)
- {
- break;
- }
-
- //write only the data that was read (slice)
- await dest.WriteAsync(offset[..read]);
+ await ProcessStreamDataAsync(_userState.GetRawStreamResponse(), dest, buffer);
+ }
+ else
+ {
+ Debug.Assert(!buffer.IsEmpty, "Transfer buffer is required for streaming operations");
- //Update total
- total += read;
- }
+ Debug.Assert(_userState.Stream != null, "Stream value is null, illegal operation");
- //Try to dispose the response stream asyncrhonously since we are done with it
- await _userState!.DisposeStreamAsync();
+ await ProcessStreamDataAsync(_userState.Stream!, dest, buffer);
}
}
///<inheritdoc/>
public async Task WriteEntityAsync<TComp>(TComp comp, IResponseDataWriter writer, Memory<byte> buffer) where TComp : IResponseCompressor
{
+ //try to clamp the buffer size to the compressor block size
+ int maxBufferSize = Math.Min(buffer.Length, comp.BlockSize);
+ if(maxBufferSize > 0)
+ {
+ buffer = buffer[..maxBufferSize];
+ }
+
+ ChunkedResponseWriter<TComp> output = new(writer, comp);
+
//Write a sliding window response
if (_userState.MemResponse != null)
{
while (_userState.MemResponse.Remaining > 0)
{
+ //Get next segment
+ _readSegment = comp.BlockSize > 0 ?
+ _userState.MemResponse.GetRemainingConstrained(comp.BlockSize)
+ : _userState.MemResponse.GetMemory();
+
//Commit output bytes
- if (CompressNextSegment(_userState.MemResponse, comp, writer))
- {
- //Time to flush
- await writer.FlushAsync(false);
- }
+ await output.WriteAsync(_readSegment);
+
+ //Advance by the written amount
+ _userState.MemResponse.Advance(_readSegment.Length);
}
//Disposing of memory response can be deferred until the end of the request since its always syncrhonous
}
- else
+ else if(_userState.RawStream != null)
{
- //Trim buffer to block size if it is set by the compressor
- if (comp.BlockSize > 0)
- {
- buffer = buffer[..comp.BlockSize];
- }
-
- long total = 0;
- while (total < Length) //If length was reached, break
- {
- //get offset wrapper of the total buffer or remaining count
- Memory<byte> offset = buffer[..(int)Math.Min(buffer.Length, Length - total)];
-
- //read
- int read = await _userState.Stream!.ReadAsync(offset, CancellationToken.None);
-
- //Guard
- if (read == 0)
- {
- break;
- }
-
- //Track read bytes and loop until all bytes are read
- _streamReader = new(offset[..read]);
-
- do
- {
- //Compress the buffered data and flush if required
- if (CompressNextSegment(ref _streamReader, comp, writer))
- {
- //Time to flush
- await writer.FlushAsync(false);
- }
-
- } while (_streamReader.WindowSize > 0);
+ Debug.Assert(!buffer.IsEmpty, "Transfer buffer is required for streaming operations");
- //Update total
- total += read;
- }
+ //Configure a raw stream response
+ await ProcessStreamDataAsync(_userState.GetRawStreamResponse(), output, buffer);
+ }
+ else
+ {
+ Debug.Assert(!buffer.IsEmpty, "Transfer buffer is required for streaming operations");
- /*
- * Try to dispose the response stream asyncrhonously since we can safley here
- * otherwise it will be deferred until the end of the request cleanup
- */
- await _userState.DisposeStreamAsync();
+ Debug.Assert(_userState.Stream != null, "Stream value is null, illegal operation");
+ await ProcessStreamDataAsync(_userState.Stream, output, buffer);
}
+
/*
* Once there is no more response data avialable to compress
@@ -231,11 +212,8 @@ namespace VNLib.Net.Http.Core.Response
do
{
- //Get output buffer
- Memory<byte> output = writer.GetMemory();
-
//Flush the compressor output
- int written = comp.Flush(output);
+ int written = comp.Flush(writer.GetMemory());
//No more data to buffer
if (written == 0)
@@ -254,23 +232,41 @@ namespace VNLib.Net.Http.Core.Response
} while (true);
}
- private static bool CompressNextSegment<TComp>(IMemoryResponseReader reader, TComp comp, IResponseDataWriter writer)
- where TComp: IResponseCompressor
+ private async Task ProcessStreamDataAsync<TStream, TWriter>(TStream stream, TWriter dest, Memory<byte> buffer)
+ where TStream: IHttpStreamResponse
+ where TWriter: IDirectResponsWriter
{
- //Read the next segment
- ReadOnlyMemory<byte> readSegment = comp.BlockSize > 0 ? reader.GetRemainingConstrained(comp.BlockSize) : reader.GetMemory();
+ /*
+ * When streams are used, callers will submit an explict length value
+ * which must be respected. This allows the stream size to differ from
+ * the actual content length. This is useful for when the stream is
+ * non-seekable, or does not have a known length
+ */
- //Get output buffer
- Memory<byte> output = writer.GetMemory();
+ long total = 0;
+ while (total < Length)
+ {
+ //get offset wrapper of the total buffer or remaining count
+ Memory<byte> offset = buffer[..(int)Math.Min(buffer.Length, Length - total)];
- //Compress the trimmed block
- CompressionResult res = comp.CompressBlock(readSegment, output);
- ValidateCompressionResult(in res);
+ //read
+ int read = await stream.ReadAsync(offset);
- //Commit input bytes
- reader.Advance(res.BytesRead);
+ //Guard
+ if (read == 0)
+ {
+ break;
+ }
- return writer.Advance(res.BytesWritten) == 0;
+ //write only the data that was read (slice)
+ await dest.WriteAsync(offset[..read]);
+
+ //Update total
+ total += read;
+ }
+
+ //Try to dispose the response stream asyncrhonously since we are done with it
+ await stream.DisposeAsync();
}
private static bool CompressNextSegment<TComp>(ref ForwardOnlyMemoryReader<byte> reader, TComp comp, IResponseDataWriter writer)
@@ -306,22 +302,26 @@ namespace VNLib.Net.Http.Core.Response
_userState = default;
_readSegment = default;
- _streamReader = default;
}
+
private readonly struct ResponsBodyDataState
{
+ public readonly bool IsSet;
+ public readonly bool BufferRequired;
public readonly long Legnth;
- public readonly Stream? Stream;
+ public readonly IHttpStreamResponse? Stream;
public readonly IMemoryResponseReader? MemResponse;
- public readonly bool IsSet;
+ public readonly Stream? RawStream;
- public ResponsBodyDataState(Stream stream, long length)
+ public ResponsBodyDataState(IHttpStreamResponse stream, long length)
{
Legnth = length;
Stream = stream;
MemResponse = null;
+ RawStream = null;
IsSet = true;
+ BufferRequired = true;
}
public ResponsBodyDataState(IMemoryResponseReader reader)
@@ -329,21 +329,62 @@ namespace VNLib.Net.Http.Core.Response
Legnth = reader.Remaining;
MemResponse = reader;
Stream = null;
+ RawStream = null;
IsSet = true;
+ BufferRequired = false;
}
- public readonly ValueTask DisposeStreamAsync()
+ public ResponsBodyDataState(Stream stream, long length)
{
- return Stream?.DisposeAsync() ?? default;
+ Legnth = length;
+ Stream = null;
+ MemResponse = null;
+ RawStream = stream;
+ IsSet = true;
+ BufferRequired = true;
}
+ public readonly HttpstreamResponse GetRawStreamResponse() => new(RawStream!);
+
public readonly void Dispose()
{
- if (IsSet)
+ Stream?.Dispose();
+ MemResponse?.Close();
+ RawStream?.Dispose();
+ }
+ }
+
+ private readonly struct HttpstreamResponse(Stream stream) : IHttpStreamResponse
+ {
+ ///<inheritdoc/>
+ public readonly void Dispose() => stream.Dispose();
+
+ ///<inheritdoc/>
+ public readonly ValueTask DisposeAsync() => stream.DisposeAsync();
+
+ ///<inheritdoc/>
+ public readonly ValueTask<int> ReadAsync(Memory<byte> buffer) => stream!.ReadAsync(buffer, CancellationToken.None);
+ }
+
+ private readonly struct ChunkedResponseWriter<TComp>(IResponseDataWriter writer, TComp comp) : IDirectResponsWriter
+ where TComp : IResponseCompressor
+ {
+
+ public readonly async ValueTask WriteAsync(ReadOnlyMemory<byte> buffer)
+ {
+ //Track read bytes and loop until all bytes are read
+ ForwardOnlyMemoryReader<byte> streamReader = new (buffer);
+
+ do
{
- Stream?.Dispose();
- MemResponse?.Close();
- }
+ //Compress the buffered data and flush if required
+ if (CompressNextSegment(ref streamReader, comp, writer))
+ {
+ //Time to flush
+ await writer.FlushAsync(false);
+ }
+
+ } while (streamReader.WindowSize > 0);
}
}
}
diff --git a/lib/Net.Http/src/Core/TransportReader.cs b/lib/Net.Http/src/Core/TransportReader.cs
index 7349387..0b38121 100644
--- a/lib/Net.Http/src/Core/TransportReader.cs
+++ b/lib/Net.Http/src/Core/TransportReader.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Net.Http
@@ -38,38 +38,27 @@ namespace VNLib.Net.Http.Core
/// <summary>
/// Structure implementation of <see cref="IVnTextReader"/>
/// </summary>
- internal struct TransportReader : IVnTextReader
+ /// <remarks>
+ /// Initializes a new <see cref="TransportReader"/> for reading text lines from the transport stream
+ /// </remarks>
+ /// <param name="transport">The transport stream to read data from</param>
+ /// <param name="buffer">The shared binary buffer</param>
+ /// <param name="encoding">The encoding to use when reading bianry</param>
+ /// <param name="lineTermination">The line delimiter to search for</param>
+ internal struct TransportReader(Stream transport, IHttpHeaderParseBuffer buffer, Encoding encoding, ReadOnlyMemory<byte> lineTermination) : IVnTextReader
{
///<inheritdoc/>
- public readonly Encoding Encoding { get; }
+ public readonly Encoding Encoding => encoding;
///<inheritdoc/>
- public readonly ReadOnlyMemory<byte> LineTermination { get; }
+ public readonly ReadOnlyMemory<byte> LineTermination => lineTermination;
///<inheritdoc/>
- public readonly Stream BaseStream { get; }
+ public readonly Stream BaseStream => transport;
+
+ private readonly uint MaxBufferSize = (uint)buffer.BinSize;
- private readonly IHttpHeaderParseBuffer Buffer;
- private readonly uint MaxBufferSize;
-
- private BufferPosition _position;
-
- /// <summary>
- /// Initializes a new <see cref="TransportReader"/> for reading text lines from the transport stream
- /// </summary>
- /// <param name="transport">The transport stream to read data from</param>
- /// <param name="buffer">The shared binary buffer</param>
- /// <param name="encoding">The encoding to use when reading bianry</param>
- /// <param name="lineTermination">The line delimiter to search for</param>
- public TransportReader(Stream transport, IHttpHeaderParseBuffer buffer, Encoding encoding, ReadOnlyMemory<byte> lineTermination)
- {
- Encoding = encoding;
- BaseStream = transport;
- LineTermination = lineTermination;
- Buffer = buffer;
- MaxBufferSize = (uint)buffer.BinSize;
- _position = default;
- }
+ private BufferPosition _position = default;
/// <summary>
@@ -77,9 +66,9 @@ namespace VNLib.Net.Http.Core
/// </summary>
/// <returns></returns>
private readonly Span<byte> GetDataSegment()
- => Buffer.GetBinSpan((int)_position.WindowStart, (int)_position.GetWindowSize());
+ => buffer.GetBinSpan((int)_position.WindowStart, (int)_position.GetWindowSize());
- private readonly Span<byte> GetRemainingSegment() => Buffer.GetBinSpan((int)_position.WindowEnd);
+ private readonly Span<byte> GetRemainingSegment() => buffer.GetBinSpan((int)_position.WindowEnd);
///<inheritdoc/>
public readonly int Available => (int)_position.GetWindowSize();
@@ -103,7 +92,7 @@ namespace VNLib.Net.Http.Core
public void FillBuffer()
{
//Read from stream into the remaining buffer segment
- int read = BaseStream.Read(GetRemainingSegment());
+ int read = transport.Read(GetRemainingSegment());
Debug.Assert(read > -1, "Read should never be negative");
//Update the end of the buffer window to the end of the read data
@@ -120,7 +109,7 @@ namespace VNLib.Net.Http.Core
if (_position.WindowStart > 0)
{
//Get a ref to the entire buffer segment, then do an in-place move to shift the data to the start of the buffer
- ref byte ptr = ref Buffer.DangerousGetBinRef(0);
+ ref byte ptr = ref buffer.DangerousGetBinRef(0);
MemoryUtil.Memmove(ref ptr, _position.WindowStart, ref ptr, 0, windowSize);
/*
diff --git a/lib/Net.Http/src/IHttpEvent.cs b/lib/Net.Http/src/IHttpEvent.cs
index ce98db6..917f959 100644
--- a/lib/Net.Http/src/IHttpEvent.cs
+++ b/lib/Net.Http/src/IHttpEvent.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Net.Http
@@ -94,6 +94,18 @@ namespace VNLib.Net.Http
void CloseResponse(HttpStatusCode code, ContentType type, IMemoryResponseReader entity);
/// <summary>
+ /// Responds to a client with an <see cref="IHttpStreamResponse"/> containing data to be sent
+ /// to user of a given contentType.
+ /// </summary>
+ /// <param name="code">The http status code</param>
+ /// <param name="type">The entity content type</param>
+ /// <param name="entity">The entity body to stream to the client</param>
+ /// <param name="length">The length in bytes of the stream data</param>
+ /// <exception cref="ArgumentNullException"></exception>
+ /// <exception cref="InvalidOperationException"></exception>
+ void CloseResponse(HttpStatusCode code, ContentType type, IHttpStreamResponse entity, long length);
+
+ /// <summary>
/// Configures the server to change protocols from HTTP to the specified
/// custom protocol handler.
/// </summary>
diff --git a/lib/Net.Http/src/IHttpStreamResponse.cs b/lib/Net.Http/src/IHttpStreamResponse.cs
new file mode 100644
index 0000000..fdf89f7
--- /dev/null
+++ b/lib/Net.Http/src/IHttpStreamResponse.cs
@@ -0,0 +1,44 @@
+/*
+* Copyright (c) 2024 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Net.Http
+* File: IHttpStreamResponse.cs
+*
+* IHttpStreamResponse.cs is part of VNLib.Net.Http which is part of the larger
+* VNLib collection of libraries and utilities.
+*
+* VNLib.Net.Http is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License as
+* published by the Free Software Foundation, either version 3 of the
+* License, or (at your option) any later version.
+*
+* VNLib.Net.Http is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+
+using System;
+using System.Threading.Tasks;
+
+namespace VNLib.Net.Http
+{
+ /// <summary>
+ /// Represents a stream of data to be sent to a client as an HTTP response.
+ /// </summary>
+ public interface IHttpStreamResponse : IDisposable, IAsyncDisposable
+ {
+ /// <summary>
+ /// Reads data from the stream into the buffer asynchronously
+ /// and returns the number of bytes read, or 0 if the end of the stream
+ /// has been reached.
+ /// </summary>
+ /// <param name="buffer">The output buffer to write data into</param>
+ /// <returns>The number of bytes read into the output buffer</returns>
+ ValueTask<int> ReadAsync(Memory<byte> buffer);
+ }
+} \ No newline at end of file
diff --git a/lib/Net.Messaging.FBM/src/Client/FBMBuffer.cs b/lib/Net.Messaging.FBM/src/Client/FBMBuffer.cs
index 698a98b..0b5d9c1 100644
--- a/lib/Net.Messaging.FBM/src/Client/FBMBuffer.cs
+++ b/lib/Net.Messaging.FBM/src/Client/FBMBuffer.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Net.Messaging.FBM
@@ -123,17 +123,8 @@ namespace VNLib.Net.Messaging.FBM.Client
Span<char> IFBMHeaderBuffer.GetSpan() => MemoryMarshal.Cast<byte, char>(Handle.GetSpan());
- private sealed class BinaryRequestAccumulator : IDataAccumulator<byte>
+ private sealed class BinaryRequestAccumulator(FBMBuffer Buffer, int Size) : IDataAccumulator<byte>
{
- private readonly int Size;
- private readonly FBMBuffer Buffer;
-
- internal BinaryRequestAccumulator(FBMBuffer buffer, int size)
- {
- Buffer = buffer;
- Size = size;
- }
-
///<inheritdoc/>
public int AccumulatedSize { get; private set; }
@@ -168,12 +159,8 @@ namespace VNLib.Net.Messaging.FBM.Client
* a finite amount of data to be written to the accumulator since
* it uses a fixed size internal buffer.
*/
- private sealed class BufferWriter : IBufferWriter<byte>
- {
- private readonly FBMBuffer Buffer;
-
- public BufferWriter(FBMBuffer buffer) => Buffer = buffer;
-
+ private sealed class BufferWriter(FBMBuffer Buffer) : IBufferWriter<byte>
+ {
///<inheritdoc/>
public void Advance(int count) => Buffer._requestAccumulator.Advance(count);
diff --git a/lib/Net.Messaging.FBM/src/Client/FBMClient.cs b/lib/Net.Messaging.FBM/src/Client/FBMClient.cs
index 9628313..d3b6b55 100644
--- a/lib/Net.Messaging.FBM/src/Client/FBMClient.cs
+++ b/lib/Net.Messaging.FBM/src/Client/FBMClient.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Net.Messaging.FBM
@@ -108,15 +108,15 @@ namespace VNLib.Net.Messaging.FBM.Client
/// <param name="websocket">The websocket instance used to comunicate with an FBMServer</param>
public FBMClient(in FBMClientConfig config, IFbmClientWebsocket websocket)
:this(in config, websocket, null)
- {
- }
+ { }
internal FBMClient(in FBMClientConfig config, IFbmClientWebsocket websocket, IObjectRental<FBMRequest>? requestRental)
{
+ ArgumentNullException.ThrowIfNull(websocket);
+ ArgumentNullException.ThrowIfNull(config.MemoryManager, nameof(config.MemoryManager));
+
_config = config;
- _socket = websocket ?? throw new ArgumentNullException(nameof(websocket));
-
- _ = config.MemoryManager ?? throw new ArgumentException("FBM memory manager is required", nameof(config));
+ _socket = websocket;
//Create new request rental if none supplied
if(requestRental is null)
@@ -218,7 +218,8 @@ namespace VNLib.Net.Messaging.FBM.Client
/// <exception cref="ObjectDisposedException"></exception>
/// <exception cref="InvalidOperationException"></exception>
/// <exception cref="FBMInvalidRequestException"></exception>
- public Task<FBMResponse> SendAsync(FBMRequest request, CancellationToken cancellationToken = default) => SendAsync(request, Config.RequestTimeout, cancellationToken);
+ public Task<FBMResponse> SendAsync(FBMRequest request, CancellationToken cancellationToken = default)
+ => SendAsync(request, Config.RequestTimeout, cancellationToken);
/// <summary>
/// Sends a <see cref="FBMRequest"/> to the connected server
@@ -311,7 +312,8 @@ namespace VNLib.Net.Messaging.FBM.Client
/// <exception cref="InvalidOperationException"></exception>
public async Task<FBMResponse> StreamDataAsync(FBMRequest request, Stream payload, ContentType contentType, TimeSpan timeout, CancellationToken cancellationToken = default)
{
- _ = payload ?? throw new ArgumentNullException(nameof(payload));
+ ArgumentNullException.ThrowIfNull(request);
+ ArgumentNullException.ThrowIfNull(payload);
Check();
diff --git a/lib/Net.Messaging.FBM/src/Client/FBMRequest.cs b/lib/Net.Messaging.FBM/src/Client/FBMRequest.cs
index 8432d27..1787941 100644
--- a/lib/Net.Messaging.FBM/src/Client/FBMRequest.cs
+++ b/lib/Net.Messaging.FBM/src/Client/FBMRequest.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Net.Messaging.FBM
@@ -97,7 +97,7 @@ namespace VNLib.Net.Messaging.FBM.Client
/// <param name="messageId">The custom message id</param>
/// <param name="config">The fbm client config storing required config variables</param>
public FBMRequest(int messageId, in FBMClientConfig config)
- :this(messageId, config.MemoryManager, config.MessageBufferSize, config.HeaderEncoding)
+ :this(messageId, config.MemoryManager, config.MessageBufferSize, config.HeaderEncoding)
{ }
/// <summary>
@@ -110,8 +110,10 @@ namespace VNLib.Net.Messaging.FBM.Client
public FBMRequest(int messageId, IFBMMemoryManager manager, int bufferSize, Encoding headerEncoding)
{
MessageId = messageId;
- HeaderEncoding = headerEncoding ?? throw new ArgumentNullException(nameof(headerEncoding));
- _ = manager ?? throw new ArgumentNullException(nameof(manager));
+ ArgumentNullException.ThrowIfNull(manager);
+ ArgumentNullException.ThrowIfNull(headerEncoding);
+
+ HeaderEncoding = headerEncoding;
//Configure waiter
Waiter = new FBMMessageWaiter(this);
@@ -283,15 +285,11 @@ namespace VNLib.Net.Messaging.FBM.Client
_request = request;
//Configure timer
- _timer = new(OnCancelled, this, Timeout.Infinite, Timeout.Infinite);
+ _timer = new(OnTimeout, this, Timeout.Infinite, Timeout.Infinite);
}
///<inheritdoc/>
- public void OnBeginRequest()
- {
- //Configure new tcs
- _tcs = new(TaskCreationOptions.None);
- }
+ public void OnBeginRequest() => _tcs = new(TaskCreationOptions.None);
///<inheritdoc/>
public void OnEndRequest()
@@ -360,7 +358,7 @@ namespace VNLib.Net.Messaging.FBM.Client
if (cancellation.CanBeCanceled)
{
//Register cancellation
- _token = cancellation.Register(OnCancelled, this);
+ _token = cancellation.Register(OnCancelled, this, false);
}
}
@@ -373,6 +371,12 @@ namespace VNLib.Net.Messaging.FBM.Client
//Set cancelled state if exists, the task may have already completed
private void OnCancelled(object? state) => _tcs?.TrySetCanceled();
+ private void OnTimeout(object? state)
+ {
+ TimeoutException to = new("A response was not received in the desired timeout period. Operation aborted");
+ _tcs?.TrySetException(to);
+ }
+
///<inheritdoc/>
public void Dispose()
{
diff --git a/lib/Net.Messaging.FBM/src/Client/FBMResponse.cs b/lib/Net.Messaging.FBM/src/Client/FBMResponse.cs
index f1148f1..ac75394 100644
--- a/lib/Net.Messaging.FBM/src/Client/FBMResponse.cs
+++ b/lib/Net.Messaging.FBM/src/Client/FBMResponse.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Net.Messaging.FBM
@@ -56,7 +56,7 @@ namespace VNLib.Net.Messaging.FBM.Client
/// <summary>
/// The body segment of the response message
/// </summary>
- public readonly ReadOnlySpan<byte> ResponseBody => IsSet ? Helpers.GetRemainingData(MessagePacket!) : ReadOnlySpan<byte>.Empty;
+ public readonly ReadOnlySpan<byte> ResponseBody => IsSet ? Helpers.GetRemainingData(MessagePacket!) : [];
/// <summary>
/// Initailzies a response message structure and parses response
diff --git a/lib/Net.Messaging.FBM/src/FBMMessageHeader.cs b/lib/Net.Messaging.FBM/src/FBMMessageHeader.cs
index 180ce7d..bb89e12 100644
--- a/lib/Net.Messaging.FBM/src/FBMMessageHeader.cs
+++ b/lib/Net.Messaging.FBM/src/FBMMessageHeader.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Net.Messaging.FBM
@@ -24,7 +24,6 @@
using System;
-
namespace VNLib.Net.Messaging.FBM
{
/// <summary>
@@ -97,7 +96,15 @@ namespace VNLib.Net.Messaging.FBM
/// </summary>
/// <param name="other">The other header to compare</param>
/// <returns>True if both headers have the same commad and value sequence</returns>
- public bool Equals(FBMMessageHeader other) => Header == other.Header && Value.SequenceEqual(other.Value);
+ public readonly bool Equals(FBMMessageHeader other) => Header == other.Header && Value.SequenceEqual(other.Value);
+
+ /// <summary>
+ /// Determines if a string value is equal to the current header value
+ /// </summary>
+ /// <param name="other">Value to test</param>
+ /// <param name="comparison">The string comparison type</param>
+ /// <returns>True if the values are equal, false otherwise</returns>
+ public readonly bool ValueEquals(ReadOnlySpan<char> other, StringComparison comparison) => Value.Equals(other, comparison);
/// <summary>
/// Gets a concatinated string of the current instance for debugging purposes
diff --git a/lib/Net.Messaging.FBM/src/Server/FBMListener.cs b/lib/Net.Messaging.FBM/src/Server/FBMListener.cs
index 30fa1ac..c248f9b 100644
--- a/lib/Net.Messaging.FBM/src/Server/FBMListener.cs
+++ b/lib/Net.Messaging.FBM/src/Server/FBMListener.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Net.Messaging.FBM
@@ -41,20 +41,18 @@ namespace VNLib.Net.Messaging.FBM.Server
/// A FBM protocol listener. Listens for messages on a <see cref="WebSocketSession"/>
/// and raises events on requests.
/// </summary>
- public class FBMListener
+ /// <remarks>
+ /// Creates a new <see cref="FBMListener"/> instance ready for
+ /// processing connections
+ /// </remarks>
+ /// <param name="heap">The heap to alloc buffers from</param>
+ /// <exception cref="ArgumentNullException"></exception>
+ public class FBMListener(IFBMMemoryManager heap)
{
public const int SEND_SEMAPHORE_TIMEOUT_MS = 10 * 1000;
- private readonly IFBMMemoryManager MemoryManger;
-
- /// <summary>
- /// Creates a new <see cref="FBMListener"/> instance ready for
- /// processing connections
- /// </summary>
- /// <param name="heap">The heap to alloc buffers from</param>
- /// <exception cref="ArgumentNullException"></exception>
- public FBMListener(IFBMMemoryManager heap) => MemoryManger = heap ?? throw new ArgumentNullException(nameof(heap));
+ private readonly IFBMMemoryManager MemoryManger = heap ?? throw new ArgumentNullException(nameof(heap));
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
@@ -68,8 +66,8 @@ namespace VNLib.Net.Messaging.FBM.Server
/// <returns>A <see cref="Task"/> that completes when the connection closes</returns>
public async Task ListenAsync(WebSocketSession wss, IFBMServerMessageHandler handler, FBMListenerSessionParams args)
{
- _ = wss ?? throw new ArgumentNullException(nameof(wss));
- _ = handler ?? throw new ArgumentNullException(nameof(handler));
+ ArgumentNullException.ThrowIfNull(wss);
+ ArgumentNullException.ThrowIfNull(handler);
ListeningSession session = new(wss, handler, in args, MemoryManger);
@@ -79,7 +77,9 @@ namespace VNLib.Net.Messaging.FBM.Server
//Start a task to process the queue
Task queueWorker = QueueWorkerDoWork(workQueue, session);
- //Alloc buffer
+ /*
+ * Alloc a top level receive buffer directly from the memory manager
+ */
IFBMMemoryHandle memHandle = MemoryManger.InitHandle();
MemoryManger.AllocBuffer(memHandle, args.RecvBufferSize);
@@ -232,7 +232,7 @@ namespace VNLib.Net.Messaging.FBM.Server
* WARNING!
* this code relies on the managed websocket impl that the websocket will read
* the entire buffer before returning. If this is not the case, this code will
- * overwrite the memory buffer on the next call to move next.
+ * overwrite the memory buffer on the next call to MoveNext().
*/
//Move to next segment
@@ -316,10 +316,12 @@ namespace VNLib.Net.Messaging.FBM.Server
Cancellation.Cancel();
//If dispose happens without any outstanding requests, we can dispose the session
- if (_counter == 0)
+ if (_pendingRequests == 0)
{
CleanupInternal();
}
+
+ //Internal data cannot be cleaned, because requests are still outstanding, fallback to reference counting
}
private void CleanupInternal()
@@ -331,7 +333,7 @@ namespace VNLib.Net.Messaging.FBM.Server
}
- private uint _counter;
+ private uint _pendingRequests;
/// <summary>
/// Rents a new <see cref="FBMContext"/> instance from the pool
@@ -341,15 +343,12 @@ namespace VNLib.Net.Messaging.FBM.Server
/// <exception cref="ObjectDisposedException"></exception>
public FBMContext RentContext()
{
- if (Cancellation.IsCancellationRequested)
- {
- throw new ObjectDisposedException("The instance has been disposed");
- }
+ ObjectDisposedException.ThrowIf(Cancellation.IsCancellationRequested, this);
//Rent context
FBMContext ctx = CtxStore.Rent();
- //Increment counter
- Interlocked.Increment(ref _counter);
+ //Increment reference count counter
+ Interlocked.Increment(ref _pendingRequests);
return ctx;
}
@@ -365,7 +364,7 @@ namespace VNLib.Net.Messaging.FBM.Server
//Return the context
CtxStore.Return(ctx);
- uint current = Interlocked.Decrement(ref _counter);
+ uint current = Interlocked.Decrement(ref _pendingRequests);
//No more contexts in use, dispose internals
if (Cancellation.IsCancellationRequested && current == 0)
diff --git a/lib/Net.Transport.SimpleTCP/src/AwaitableAsyncServerSocket.cs b/lib/Net.Transport.SimpleTCP/src/AwaitableAsyncServerSocket.cs
index e287d64..e830107 100644
--- a/lib/Net.Transport.SimpleTCP/src/AwaitableAsyncServerSocket.cs
+++ b/lib/Net.Transport.SimpleTCP/src/AwaitableAsyncServerSocket.cs
@@ -83,7 +83,10 @@ namespace VNLib.Net.Transport.Tcp
//Begin the accept
SocketError error = await _allArgs.AcceptAsync(serverSocket);
- if(error == SocketError.Success)
+ //Clear the buffer reference
+ _allArgs.SetBuffer(default);
+
+ if (error == SocketError.Success)
{
//Store socket on success
_socket = _allArgs.AcceptSocket!;
@@ -97,9 +100,8 @@ namespace VNLib.Net.Transport.Tcp
*/
_recvTask = SocketWorker.RecvDoWorkAsync(this, _allArgs.BytesTransferred, recvBuffSize);
}
-
- //Clear the buffer reference
- _allArgs.SetBuffer(default);
+
+ _allArgs.AcceptSocket = null;
return error;
}
@@ -126,6 +128,18 @@ namespace VNLib.Net.Transport.Tcp
//Wait for recv to complete
await _recvTask.ConfigureAwait(false);
+ /*
+ * Sockets are reused as much as possible on Windows. If the socket
+ * failes to disconnect cleanly, the release function won't clean it up
+ * so it needs to be cleaned up here so at least our args instance
+ * can be reused.
+ */
+ if(IsWindows && error != SocketError.Success)
+ {
+ _socket.Dispose();
+ _socket = null;
+ }
+
return error;
}
@@ -154,6 +168,8 @@ namespace VNLib.Net.Transport.Tcp
void IReusable.Prepare()
{
+ Debug.Assert(_socket == null || IsWindows, "Exepcted stale socket to be NULL on non-Windows platform");
+
_allArgs.Prepare();
_recvArgs.Prepare();
SocketWorker.Prepare();
@@ -168,7 +184,7 @@ namespace VNLib.Net.Transport.Tcp
_allArgs.Release();
_recvArgs.Release();
- //if the sockeet is connected (or not windows), dispose it and clear the accept socket
+ //if the socket is still 'connected' (or not windows), dispose it and clear the accept socket
if (_socket?.Connected == true || !IsWindows)
{
_socket?.Dispose();
@@ -304,7 +320,6 @@ namespace VNLib.Net.Transport.Tcp
{
//Async disconnect
return new ValueTask<SocketError>(this, AsyncTaskCore.Version);
-
}
return ValueTask.FromResult(SocketError);
diff --git a/lib/Net.Transport.SimpleTCP/src/SocketPipeLineWorker.cs b/lib/Net.Transport.SimpleTCP/src/SocketPipeLineWorker.cs
index 428ad1f..b6df58c 100644
--- a/lib/Net.Transport.SimpleTCP/src/SocketPipeLineWorker.cs
+++ b/lib/Net.Transport.SimpleTCP/src/SocketPipeLineWorker.cs
@@ -52,6 +52,8 @@ namespace VNLib.Net.Transport.Tcp
private readonly Timer SendTimer;
private readonly Stream RecvStream;
+ private bool _started;
+
/// <summary>
/// Initalizes a new reusable socket pipeline worker
/// </summary>
@@ -82,10 +84,16 @@ namespace VNLib.Net.Transport.Tcp
{
_sysSocketBufferSize = 0;
- //Reset pipes for use
- SendPipe.Reset();
- RecvPipe.Reset();
+ //Only reset pipeline if it was started
+ if (_started)
+ {
+ //Reset pipes for use
+ SendPipe.Reset();
+ RecvPipe.Reset();
+ }
+ //clear started flag
+ _started = false;
return true;
}
@@ -136,6 +144,8 @@ namespace VNLib.Net.Transport.Tcp
ReadOnlySequence<byte>.Enumerator enumerator;
ForwardOnlyMemoryReader<byte> segmentReader;
+ _started |= true;
+
try
{
_sysSocketBufferSize = sendBufferSize;
@@ -231,6 +241,8 @@ namespace VNLib.Net.Transport.Tcp
Exception? cause = null;
Memory<byte> buffer;
+ _started |= true;
+
try
{
//If initial data was buffered, it needs to be published to the reader
diff --git a/lib/Net.Transport.SimpleTCP/src/TcpServer.cs b/lib/Net.Transport.SimpleTCP/src/TcpServer.cs
index 67a1751..08625d2 100644
--- a/lib/Net.Transport.SimpleTCP/src/TcpServer.cs
+++ b/lib/Net.Transport.SimpleTCP/src/TcpServer.cs
@@ -278,8 +278,6 @@ namespace VNLib.Net.Transport.Tcp
/// <exception cref="InvalidOperationException"></exception>
public ValueTask<ITcpConnectionDescriptor> AcceptConnectionAsync(CancellationToken cancellation)
{
- _ = WaitingSockets ?? throw new InvalidOperationException("Server is not listening");
-
//Try get args from queue
if (WaitingSockets.TryDequeue(out ITcpConnectionDescriptor? args))
{
@@ -293,16 +291,18 @@ namespace VNLib.Net.Transport.Tcp
/// Cleanly closes an existing TCP connection obtained from <see cref="AcceptConnectionAsync(CancellationToken)"/>
/// and returns the instance to the pool for reuse.
/// <para>
- /// You should destroy all references to the
- /// connection descriptor and dispose the stream returned from <see cref="ITcpConnectionDescriptor.GetStream"/>
+ /// If you set <paramref name="reuse"/> to true, the server will attempt to reuse the descriptor instance, you
+ /// must ensure that all previous references to the descriptor are destroyed. If the value is false, resources
+ /// are freed and the instance is disposed.
/// </para>
/// </summary>
/// <param name="descriptor">The existing descriptor to close</param>
+ /// <param name="reuse">A value that indicates if the server can safley reuse the descriptor instance</param>
/// <returns>A task that represents the closing operations</returns>
/// <exception cref="ArgumentNullException"></exception>
- public async ValueTask CloseConnectionAsync(ITcpConnectionDescriptor descriptor)
+ public async ValueTask CloseConnectionAsync(ITcpConnectionDescriptor descriptor, bool reuse)
{
- ArgumentNullException.ThrowIfNull(descriptor, nameof(descriptor));
+ ArgumentNullException.ThrowIfNull(descriptor);
//Recover args
AwaitableAsyncServerSocket args = (AwaitableAsyncServerSocket)descriptor;
@@ -312,15 +312,21 @@ namespace VNLib.Net.Transport.Tcp
//Close the socket and cleanup resources
SocketError err = await args.CloseConnectionAsync();
- if (err == SocketError.Success)
+ if (err != SocketError.Success)
+ {
+ _config.Log.Verbose("Socket disconnect failed with error code {ec}.", err);
+ }
+
+ //See if we can reuse the args
+ if (reuse)
{
//Return to pool
SockAsyncArgPool.Return(args);
}
else
{
+ //Dispose
args.Dispose();
- _config.Log.Verbose("Socket disconnected failed with error code {ec}. Resources disposed", err);
}
}
diff --git a/lib/Plugins.Essentials.ServiceStack/src/Construction/HttpServiceStackBuilder.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/HttpServiceStackBuilder.cs
index f100c1d..3ae2183 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/Construction/HttpServiceStackBuilder.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/Construction/HttpServiceStackBuilder.cs
@@ -168,7 +168,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
private PluginStackInitializer GetPluginStack(ServiceDomain domain)
{
//Always init manual array
- manualPlugins ??= Array.Empty<IManualPlugin>();
+ manualPlugins ??= [];
//Only load plugins if the callback is configured
IPluginStack? plugins = _getPlugins?.Invoke();
diff --git a/lib/Plugins.Essentials.ServiceStack/src/Construction/IAccountSecUpdateable.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/IAccountSecUpdateable.cs
deleted file mode 100644
index eee7a2e..0000000
--- a/lib/Plugins.Essentials.ServiceStack/src/Construction/IAccountSecUpdateable.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-* Copyright (c) 2023 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Essentials.ServiceStack
-* File: IAccountSecUpdateable.cs
-*
-* IAccountSecUpdateable.cs is part of VNLib.Plugins.Essentials.ServiceStack which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* VNLib.Plugins.Essentials.ServiceStack is free software: you can redistribute it and/or modify
-* it under the terms of the GNU Affero General Public License as
-* published by the Free Software Foundation, either version 2 of the
-* License, or (at your option) any later version.
-*
-* VNLib.Plugins.Essentials.ServiceStack is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU Affero General Public License for more details.
-*
-* You should have received a copy of the GNU Affero General Public License
-* along with this program. If not, see https://www.gnu.org/licenses/.
-*/
-
-using VNLib.Plugins.Essentials.Accounts;
-
-
-namespace VNLib.Plugins.Essentials.ServiceStack.Construction
-{
- /// <summary>
- /// Adds functionality to event processors to allow them to be updated
- /// with a new <see cref="IAccountSecurityProvider"/> instance dynamically
- /// at runtime
- /// </summary>
- public interface IAccountSecUpdateable
- {
- /// <summary>
- /// Sets the <see cref="IAccountSecurityProvider"/> instance for the event processor
- /// may be null to remove a previous provider
- /// </summary>
- /// <param name="provider">The new <see cref="IAccountSecurityProvider"/> instance</param>
- void SetAccountSecProvider(IAccountSecurityProvider? provider);
- }
-}
diff --git a/lib/Plugins.Essentials.ServiceStack/src/Construction/IRuntimeServiceInjection.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/IRuntimeServiceInjection.cs
new file mode 100644
index 0000000..c18289e
--- /dev/null
+++ b/lib/Plugins.Essentials.ServiceStack/src/Construction/IRuntimeServiceInjection.cs
@@ -0,0 +1,49 @@
+/*
+* Copyright (c) 2024 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Plugins.Essentials.ServiceStack
+* File: IRuntimeServiceInjection.cs
+*
+* IRuntimeServiceInjection.cs is part of VNLib.Plugins.Essentials.ServiceStack which
+* is part of the larger VNLib collection of libraries and utilities.
+*
+* VNLib.Plugins.Essentials.ServiceStack is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License as
+* published by the Free Software Foundation, either version 2 of the
+* License, or (at your option) any later version.
+*
+* VNLib.Plugins.Essentials.ServiceStack is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+
+using System;
+
+namespace VNLib.Plugins.Essentials.ServiceStack.Construction
+{
+ /// <summary>
+ /// Adds functionality to event processors for runtime service injection
+ /// that can be used to add and remove services from the service provider
+ /// at runtime.
+ /// </summary>
+ public interface IRuntimeServiceInjection
+ {
+ /// <summary>
+ /// Adds a collection of services to event processors
+ /// that can be used.
+ /// </summary>
+ /// <param name="services">The collection of exported services</param>
+ void AddServices(IServiceProvider services);
+
+ /// <summary>
+ /// Removes a collection of services from event processors
+ /// </summary>
+ /// <param name="services">The service container that contains services to remove</param>
+ void RemoveServices(IServiceProvider services);
+ }
+}
diff --git a/lib/Plugins.Essentials.ServiceStack/src/Construction/SsBuilderExtensions.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/SsBuilderExtensions.cs
index d96809b..5512e49 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/Construction/SsBuilderExtensions.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/Construction/SsBuilderExtensions.cs
@@ -26,14 +26,14 @@ using System;
using System.IO;
using System.Net;
using System.Linq;
+using System.Collections.Frozen;
using System.Collections.Generic;
+using System.Runtime.CompilerServices;
using System.Security.Cryptography.X509Certificates;
using VNLib.Utils.Logging;
+using VNLib.Utils.Extensions;
using VNLib.Net.Http;
-using VNLib.Plugins.Essentials.Accounts;
-using VNLib.Plugins.Essentials.Content;
-using VNLib.Plugins.Essentials.Sessions;
using VNLib.Plugins.Essentials.Middleware;
namespace VNLib.Plugins.Essentials.ServiceStack.Construction
@@ -51,7 +51,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
/// </summary>
/// <param name="stack"></param>
/// <returns>The <see cref="IDomainBuilder"/> used to define your service domain</returns>
- public static IDomainBuilder WithDomain(this HttpServiceStackBuilder stack) => stack.WithDomain(p => new BasicVirtualHost(p.Clone()));
+ public static IDomainBuilder WithDomain(this HttpServiceStackBuilder stack) => WithDomain(stack, vhc => FromVirtualHostConfig(vhc.Clone()));
/// <summary>
/// Creates a new <see cref="IDomainBuilder"/> instance to define your
@@ -74,7 +74,8 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
/// <param name="stack"></param>
/// <param name="callback">The custom event processor type</param>
/// <returns></returns>
- public static IDomainBuilder WithDomain<T>(this HttpServiceStackBuilder stack, Func<VirtualHostConfiguration, T> callback) where T : EventProcessor, IAccountSecUpdateable
+ public static IDomainBuilder WithDomain<T>(this HttpServiceStackBuilder stack, Func<VirtualHostConfiguration, T> callback)
+ where T : EventProcessor, IRuntimeServiceInjection
{
List<VirtualHostConfiguration> configs = new();
DomainBuilder domains = new(configs, stack);
@@ -174,14 +175,54 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
return vhBuilder;
}
+ /// <summary>
+ /// Adds an array of IP addresses to the downstream server collection. This is a security
+ /// features that allows event handles to trust connections/ipaddresses that originate from
+ /// trusted downstream servers
+ /// </summary>
+ /// <param name="vhBuilder"></param>
+ /// <param name="addresses">The collection of IP addresses to set as trusted servers</param>
+ /// <returns></returns>
public static IVirtualHostBuilder WithDownstreamServers(this IVirtualHostBuilder vhBuilder, params IPAddress[] addresses)
{
vhBuilder.WithOption(c => c.DownStreamServers = new HashSet<IPAddress>(addresses));
return vhBuilder;
}
+ private static BasicVirtualHost FromVirtualHostConfig(VirtualHostConfiguration configuration)
+ {
+ /*
+ * Event processors configurations are considered immutable. That is,
+ * top-level elements are not allowed to be changed after the processor
+ * has been created. Some properties/containers are allowed to be modified
+ * such as middleware chains, and the service pool.
+ */
+
+ EventProcessorConfig conf = new(
+ configuration.RootDir.FullName,
+ configuration.Hostname,
+ configuration.LogProvider,
+ configuration)
+ {
+ AllowedAttributes = configuration.AllowedAttributes,
+ DissallowedAttributes = configuration.DissallowedAttributes,
+ DefaultFiles = configuration.DefaultFiles,
+ ExecutionTimeout = configuration.ExecutionTimeout,
+
+ //Frozen sets are required for the event processor, for performance reasons
+ DownStreamServers = configuration.DownStreamServers.ToFrozenSet(),
+ ExcludedExtensions = configuration.ExcludedExtensions.ToFrozenSet(),
+ };
+
+ //Add all pre-configured middleware to the chain
+ configuration.CustomMiddleware.ForEach(conf.MiddlewareChain.Add);
+
+ return new(configuration.EventHooks, conf);
+ }
+
- private static void AddHosts(this HttpServiceStackBuilder stack, Func<IServiceHost[]> hosts) => stack.WithDomain(p => Array.ForEach(hosts(), h => p.Add(h)));
+ private static void AddHosts(this HttpServiceStackBuilder stack, Func<IServiceHost[]> hosts)
+ => stack.WithDomain(p => Array.ForEach(hosts(), h => p.Add(h)));
private static void OnPluginServiceEvent<T>(this IManagedPlugin plugin, Action<T> loader)
{
@@ -193,7 +234,6 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
private sealed record class DomainBuilder(List<VirtualHostConfiguration> Configs, HttpServiceStackBuilder Stack) : IDomainBuilder
{
-
///<inheritdoc/>
public IVirtualHostBuilder WithVirtualHost(DirectoryInfo rootDirectory, IVirtualHostHooks hooks, ILogProvider logger)
{
@@ -217,6 +257,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
private sealed record class VHostBuilder(VirtualHostConfiguration Config) : IVirtualHostBuilder
{
+ ///<inheritdoc/>
public IVirtualHostBuilder WithOption(Action<VirtualHostConfiguration> configCallback)
{
configCallback(Config);
@@ -225,23 +266,9 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
}
}
- private sealed class CustomServiceHost<T> : IServiceHost where T : EventProcessor, IAccountSecUpdateable
+ private sealed class CustomServiceHost<T>(IHostTransportInfo Config, T Instance) : IServiceHost
+ where T : EventProcessor, IRuntimeServiceInjection
{
- private readonly VirtualHostConfiguration Config;
- private readonly T Instance;
-
- public CustomServiceHost(VirtualHostConfiguration Config, T Instance)
- {
- this.Config = Config;
- this.Instance = Instance;
-
- //Add middleware to the chain
- foreach (IHttpMiddleware mw in Config.CustomMiddleware)
- {
- Instance.MiddlewareChain.Add(mw);
- }
- }
-
///<inheritdoc/>
public IWebRoot Processor => Instance;
@@ -252,78 +279,90 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
void IServiceHost.OnRuntimeServiceAttach(IManagedPlugin plugin, IEndpoint[] endpoints)
{
//Add endpoints to service
- Instance.EndpointTable.AddEndpoint(endpoints);
-
- //Add all services
- plugin.OnPluginServiceEvent<ISessionProvider>(Instance.SetSessionProvider);
- plugin.OnPluginServiceEvent<IPageRouter>(Instance.SetPageRouter);
- plugin.OnPluginServiceEvent<IAccountSecurityProvider>(Instance.SetAccountSecProvider);
+ Instance.Options.EndpointTable.AddEndpoint(endpoints);
+
+ //Inject services into the event processor service pool
+ Instance.AddServices(plugin.Services);
- //Add all middleware to the chain
- plugin.OnPluginServiceEvent<IHttpMiddleware[]>(p => Array.ForEach(p, mw => Instance.MiddlewareChain.Add(mw)));
+ //Add all exposed middleware to the chain
+ plugin.OnPluginServiceEvent<ICollection<IHttpMiddleware>>(p => p.TryForeach(Instance.Options.MiddlewareChain.Add));
}
///<inheritdoc/>
void IServiceHost.OnRuntimeServiceDetach(IManagedPlugin plugin, IEndpoint[] endpoints)
{
//Remove endpoints
- Instance.EndpointTable.RemoveEndpoint(endpoints);
-
- //Remove all services
- plugin.OnPluginServiceEvent<ISessionProvider>(p => Instance.SetSessionProvider(null));
- plugin.OnPluginServiceEvent<IPageRouter>(p => Instance.SetPageRouter(null));
- plugin.OnPluginServiceEvent<IAccountSecurityProvider>(p => Instance.SetAccountSecProvider(null));
+ Instance.Options.EndpointTable.RemoveEndpoint(endpoints);
+ Instance.RemoveServices(plugin.Services);
//Remove all middleware from the chain
- plugin.OnPluginServiceEvent<IHttpMiddleware[]>(p => Array.ForEach(p, mw => Instance.MiddlewareChain.RemoveMiddleware(mw)));
+ plugin.OnPluginServiceEvent<ICollection<IHttpMiddleware>>(p => p.TryForeach(Instance.Options.MiddlewareChain.Remove));
}
}
- private sealed class BasicVirtualHost : EventProcessor, IAccountSecUpdateable
+ private sealed class BasicVirtualHost(IVirtualHostHooks Hooks, EventProcessorConfig config) : EventProcessor(config), IRuntimeServiceInjection
{
- private readonly VirtualHostConfiguration Config;
- private readonly IVirtualHostHooks Hooks;
-
- internal IAccountSecurityProvider? SecProvider;
-
- public BasicVirtualHost(VirtualHostConfiguration config)
- {
- Config = config;
- Hooks = config.EventHooks;
- Directory = config.RootDir.FullName;
- }
+ /*
+ * Runtime service injection can be tricky, at least in my architecture. If all we have
+ * is am IServiceProvider instance, we cannot trust that the services availabe are
+ * exactly the same as the ones initially provided. So we can store the known types
+ * that a given service container DID export, and then use that to remove the services
+ * when the service provider is removed.
+ */
+ private readonly ConditionalWeakTable<IServiceProvider, Type[]> _exposedTypes = new();
///<inheritdoc/>
- public override string Directory { get; }
+ public override bool ErrorHandler(HttpStatusCode errorCode, IHttpEvent entity) => Hooks.ErrorHandler(errorCode, entity);
///<inheritdoc/>
- public override string Hostname => Config.Hostname;
+ public override void PreProcessEntity(HttpEntity entity, out FileProcessArgs preProcArgs) => Hooks.PreProcessEntityAsync(entity, out preProcArgs);
///<inheritdoc/>
- public override IEpProcessingOptions Options => Config;
+ public override void PostProcessEntity(HttpEntity entity, ref FileProcessArgs chosenRoutine) => Hooks.PostProcessFile(entity, ref chosenRoutine);
///<inheritdoc/>
- public override IAccountSecurityProvider? AccountSecurity => SecProvider;
+ public override string TranslateResourcePath(string requestPath) => Hooks.TranslateResourcePath(requestPath);
///<inheritdoc/>
- protected override ILogProvider Log => Config.LogProvider;
+ public void AddServices(IServiceProvider services)
+ {
+ Type[] exposedForHandler = [];
- ///<inheritdoc/>
- public override bool ErrorHandler(HttpStatusCode errorCode, IHttpEvent entity) => Hooks.ErrorHandler(errorCode, entity);
+ foreach (Type type in ServicePool.Types)
+ {
+ //Get exported service by the desired type
+ object? service = services.GetService(type);
- ///<inheritdoc/>
- public override void PreProcessEntity(HttpEntity entity, out FileProcessArgs preProcArgs) => Hooks.PreProcessEntityAsync(entity, out preProcArgs);
+ //If its not null, then add it to the service pool
+ if (service is not null)
+ {
+ ServicePool.SetService(type, service);
- ///<inheritdoc/>
- public override void PostProcessEntity(HttpEntity entity, ref FileProcessArgs chosenRoutine) => Hooks.PostProcessFile(entity, ref chosenRoutine);
+ //Add to the exposed types list
+ exposedForHandler = [.. exposedForHandler, type];
+ }
+ }
- ///<inheritdoc/>
- public override string TranslateResourcePath(string requestPath) => Hooks.TranslateResourcePath(requestPath);
+ //Add to the exposed types table
+ _exposedTypes.Add(services, exposedForHandler);
+ }
///<inheritdoc/>
- public void SetAccountSecProvider(IAccountSecurityProvider? provider) => SecProvider = provider;
-
+ public void RemoveServices(IServiceProvider services)
+ {
+ //Get all exposed types for this service provider
+ if (_exposedTypes.TryGetValue(services, out Type[]? exposed))
+ {
+ foreach (Type type in exposed)
+ {
+ ServicePool.SetService(type, null);
+ }
+
+ //Remove from the exposed types table
+ _exposedTypes.Remove(services);
+ }
+ }
}
}
}
diff --git a/lib/Plugins.Essentials.ServiceStack/src/HttpServiceStack.cs b/lib/Plugins.Essentials.ServiceStack/src/HttpServiceStack.cs
index 16bc1a0..71db38f 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/HttpServiceStack.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/HttpServiceStack.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Plugins.Essentials.ServiceStack
@@ -29,6 +29,7 @@ using System.Collections.Generic;
using VNLib.Utils;
using VNLib.Net.Http;
+using VNLib.Utils.Logging;
namespace VNLib.Plugins.Essentials.ServiceStack
{
@@ -96,6 +97,12 @@ namespace VNLib.Plugins.Essentials.ServiceStack
}
/// <summary>
+ /// Loads all plugins into the service stack
+ /// </summary>
+ /// <param name="logProvider">A log provider for writing loading logs to</param>
+ public void LoadPlugins(ILogProvider logProvider) => _plugins.LoadPlugins(logProvider);
+
+ /// <summary>
/// Stops listening on all configured servers and returns a task that completes
/// when the service host has stopped all servers and unloaded resources
/// </summary>
diff --git a/lib/Plugins.Essentials.ServiceStack/src/PluginExtensions.cs b/lib/Plugins.Essentials.ServiceStack/src/PluginExtensions.cs
index d8cdf75..52377ee 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/PluginExtensions.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/PluginExtensions.cs
@@ -25,7 +25,6 @@
using System.Linq;
using System.Collections.Generic;
-using VNLib.Utils.Logging;
using VNLib.Plugins.Essentials.Runtime;
namespace VNLib.Plugins.Essentials.ServiceStack
@@ -53,14 +52,6 @@ namespace VNLib.Plugins.Essentials.ServiceStack
return Enumerable.Empty<IEndpoint>();
}
- /// <summary>
- /// Loads all plugins that implement <see cref="IWebPlugin"/> interface into the
- /// service stack
- /// </summary>
- /// <param name="stack"></param>
- /// <param name="logProvider">A log provider for writing loading logs to</param>
- public static void LoadPlugins(this HttpServiceStack stack, ILogProvider logProvider) => (stack.PluginManager as PluginManager)!.LoadPlugins(logProvider);
-
- internal static PluginLoadEventListener GetListener(this ServiceDomain domain) => new(domain);
+ internal static PluginRutimeEventHandler GetListener(this ServiceDomain domain) => new(domain);
}
}
diff --git a/lib/Plugins.Essentials.ServiceStack/src/PluginManager.cs b/lib/Plugins.Essentials.ServiceStack/src/PluginManager.cs
index f5f2abc..f43da78 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/PluginManager.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/PluginManager.cs
@@ -36,22 +36,15 @@ namespace VNLib.Plugins.Essentials.ServiceStack
/// A sealed type that manages the plugin interaction layer. Manages the lifetime of plugin
/// instances, exposes controls, and relays stateful plugin events.
/// </summary>
- internal sealed class PluginManager : VnDisposeable, IHttpPluginManager
+ internal sealed class PluginManager(IPluginInitializer stack) : VnDisposeable, IHttpPluginManager
{
- private readonly IPluginInitializer _stack;
/// <summary>
/// The collection of internal controllers
/// </summary>
public IEnumerable<IManagedPlugin> Plugins => _loadedPlugins;
- private IManagedPlugin[] _loadedPlugins;
-
- public PluginManager(IPluginInitializer stack)
- {
- _stack = stack;
- _loadedPlugins = Array.Empty<IManagedPlugin>();
- }
+ private IManagedPlugin[] _loadedPlugins = [];
/// <summary>
/// Configures the manager to capture and manage plugins within a plugin stack
@@ -61,12 +54,12 @@ namespace VNLib.Plugins.Essentials.ServiceStack
/// <exception cref="AggregateException"></exception>
public void LoadPlugins(ILogProvider debugLog)
{
- _ = _stack ?? throw new InvalidOperationException("Plugin stack has not been set.");
+ _ = stack ?? throw new InvalidOperationException("Plugin stack has not been set.");
Check();
//Initialize the plugin stack and store the loaded plugins
- _loadedPlugins = _stack.InitializePluginStack(debugLog);
+ _loadedPlugins = stack.InitializePluginStack(debugLog);
debugLog.Information("Plugin loading completed");
}
@@ -94,7 +87,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
Check();
//Reload all plugins, causing an event cascade
- _stack.ReloadPlugins();
+ stack.ReloadPlugins();
}
/// <inheritdoc/>
@@ -103,7 +96,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
Check();
//Unload all plugin controllers
- _stack.UnloadPlugins();
+ stack.UnloadPlugins();
/*
* All plugin instances must be destroyed because the
@@ -116,10 +109,10 @@ namespace VNLib.Plugins.Essentials.ServiceStack
protected override void Free()
{
//Clear plugin table
- _loadedPlugins = Array.Empty<IManagedPlugin>();
+ _loadedPlugins = [];
//Dispose the plugin stack
- _stack.Dispose();
+ stack.Dispose();
}
}
}
diff --git a/lib/Plugins.Essentials.ServiceStack/src/PluginLoadEventListener.cs b/lib/Plugins.Essentials.ServiceStack/src/PluginRutimeEventHandler.cs
index b24019b..f892823 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/PluginLoadEventListener.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/PluginRutimeEventHandler.cs
@@ -3,9 +3,9 @@
*
* Library: VNLib
* Package: VNLib.Plugins.Essentials.ServiceStack
-* File: PluginLoadEventListener.cs
+* File: PluginRutimeEventHandler.cs
*
-* PluginLoadEventListener.cs is part of VNLib.Plugins.Essentials.ServiceStack which
+* PluginRutimeEventHandler.cs is part of VNLib.Plugins.Essentials.ServiceStack which
* is part of the larger VNLib collection of libraries and utilities.
*
* VNLib.Plugins.Essentials.ServiceStack is free software: you can redistribute it and/or modify
@@ -30,7 +30,7 @@ using VNLib.Plugins.Runtime;
namespace VNLib.Plugins.Essentials.ServiceStack
{
- internal sealed record class PluginLoadEventListener(ServiceDomain Domain) : IPluginEventListener
+ internal sealed class PluginRutimeEventHandler(ServiceDomain Domain) : IPluginEventListener
{
///<inheritdoc/>
void IPluginEventListener.OnPluginLoaded(PluginController controller, object? state) => OnPluginLoaded((state as IManagedPlugin)!);
@@ -43,7 +43,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
/// should be put into service
/// </summary>
/// <param name="plugin">The plugin that was loaded</param>
- public void OnPluginLoaded(IManagedPlugin plugin)
+ internal void OnPluginLoaded(IManagedPlugin plugin)
{
//Run onload method before invoking other handlers
plugin.OnPluginLoaded();
@@ -60,7 +60,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
/// be removed from service.
/// </summary>
/// <param name="plugin">The plugin instance to unload</param>
- public void OnPluginUnloaded(IManagedPlugin plugin)
+ internal void OnPluginUnloaded(IManagedPlugin plugin)
{
try
{
diff --git a/lib/Plugins.Essentials.ServiceStack/src/PluginStackInitializer.cs b/lib/Plugins.Essentials.ServiceStack/src/PluginStackInitializer.cs
index e6489c9..5a33425 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/PluginStackInitializer.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/PluginStackInitializer.cs
@@ -39,7 +39,7 @@ using VNLib.Plugins.Runtime.Services;
namespace VNLib.Plugins.Essentials.ServiceStack
{
- internal sealed record class PluginStackInitializer(PluginLoadEventListener Listener, IPluginStack Stack, IManualPlugin[] ManualPlugins, bool ConcurrentLoad)
+ internal sealed class PluginStackInitializer(PluginRutimeEventHandler Listener, IPluginStack Stack, IManualPlugin[] ManualPlugins, bool ConcurrentLoad)
: IPluginInitializer
{
private readonly LinkedList<IManagedPlugin> _managedPlugins = new();
@@ -64,7 +64,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
Array.ForEach(wrapper, p => p.Plugin.Controller.Register(Listener, p));
//Add manual plugins to list of managed plugins
- Array.ForEach(ManualPlugins, p => _manualPlugins.AddLast(new ManualPluginWrapper(p)));
+ Array.ForEach(ManualPlugins, p => _manualPlugins.AddLast(new ManualPluginWrapper(Listener, p)));
}
///<inheritdoc/>
@@ -103,7 +103,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
_loadedPlugins.TryForeach(_loadedPlugins => LoadPlugin(_loadedPlugins, debugLog));
}
- return _loadedPlugins.ToArray();
+ return [.. _loadedPlugins];
}
///<inheritdoc/>
@@ -112,7 +112,6 @@ namespace VNLib.Plugins.Essentials.ServiceStack
Stack.UnloadAll();
//Unload manual plugins in listener
- _managedPlugins.TryForeach(mp => Listener.OnPluginUnloaded(mp));
_manualPlugins.TryForeach(static mp => mp.Unload());
}
@@ -121,13 +120,11 @@ namespace VNLib.Plugins.Essentials.ServiceStack
{
Stack.ReloadAll();
- //Unload manual plugins in listener, then call the unload method
- _managedPlugins.TryForeach(mp => Listener.OnPluginUnloaded(mp));
+ //Unload manual plugins in listener
_manualPlugins.TryForeach(static mp => mp.Unload());
//Load, then invoke on-loaded events
_manualPlugins.TryForeach(static mp => mp.Load());
- _managedPlugins.TryForeach(mp => Listener.OnPluginLoaded(mp));
}
///<inheritdoc/>
@@ -191,8 +188,6 @@ namespace VNLib.Plugins.Essentials.ServiceStack
else if (plugin is ManualPluginWrapper mpw)
{
mpw.Load();
- //Call the on-load event in listener explicitly
- Listener.OnPluginLoaded(plugin);
}
else
{
@@ -219,14 +214,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
private ServiceContainer? _services;
///<inheritdoc/>
- public IServiceContainer Services
- {
- get
- {
- _ = _services ?? throw new InvalidOperationException("The service container is not currently loaded");
- return _services!;
- }
- }
+ public IServiceContainer Services => _services ?? throw new InvalidOperationException("The service container is not currently loaded");
/*
* Automatically called after the plugin has successfully loaded
@@ -275,7 +263,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
public override string ToString() => Path.GetFileName(Plugin.Config.AssemblyFile);
}
- private sealed record class ManualPluginWrapper(IManualPlugin Plugin) : IManagedPlugin, IDisposable
+ private sealed record class ManualPluginWrapper(PluginRutimeEventHandler Listener, IManualPlugin Plugin) : IManagedPlugin, IDisposable
{
private ServiceContainer _container = new();
@@ -286,10 +274,16 @@ namespace VNLib.Plugins.Essentials.ServiceStack
{
Plugin.Load();
Plugin.GetAllExportedServices(Services);
+
+ //Finally notify of load
+ Listener.OnPluginLoaded(this);
}
public void Unload()
{
+ //Notify of unload
+ Listener.OnPluginUnloaded(this);
+
Plugin.Unload();
//Unload and re-init container
diff --git a/lib/Plugins.Essentials.ServiceStack/src/ServiceDomain.cs b/lib/Plugins.Essentials.ServiceStack/src/ServiceDomain.cs
index 4cff671..35bf65b 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/ServiceDomain.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/ServiceDomain.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Plugins.Essentials.ServiceStack
@@ -38,7 +38,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
/// </summary>
public sealed class ServiceDomain
{
- private readonly LinkedList<ServiceGroup> _serviceGroups;
+ private readonly LinkedList<ServiceGroup> _serviceGroups = new();
/// <summary>
/// Gets all service groups loaded in the service manager
@@ -46,11 +46,6 @@ namespace VNLib.Plugins.Essentials.ServiceStack
public IReadOnlyCollection<ServiceGroup> ServiceGroups => _serviceGroups;
/// <summary>
- /// Initializes a new empty <see cref="ServiceDomain"/>
- /// </summary>
- public ServiceDomain() => _serviceGroups = new();
-
- /// <summary>
/// Uses the supplied callback to get a collection of virtual hosts
/// to build the current domain with
/// </summary>
diff --git a/lib/Plugins.Essentials.ServiceStack/src/ServiceGroup.cs b/lib/Plugins.Essentials.ServiceStack/src/ServiceGroup.cs
index da34d54..29b9fdc 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/ServiceGroup.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/ServiceGroup.cs
@@ -37,15 +37,21 @@ namespace VNLib.Plugins.Essentials.ServiceStack
/// common transport (interface, port, and SSL status)
/// and may be loaded by a single server instance.
/// </summary>
- public sealed class ServiceGroup
+ /// <remarks>
+ /// Initalizes a new <see cref="ServiceGroup"/> of virtual hosts
+ /// with common transport
+ /// </remarks>
+ /// <param name="serviceEndpoint">The <see cref="IPEndPoint"/> to listen for connections on</param>
+ /// <param name="hosts">The hosts that share a common interface endpoint</param>
+ public sealed class ServiceGroup(IPEndPoint serviceEndpoint, IEnumerable<IServiceHost> hosts)
{
- private readonly LinkedList<IServiceHost> _vHosts;
- private readonly ConditionalWeakTable<IManagedPlugin, IEndpoint[]> _endpointsForPlugins;
+ private readonly LinkedList<IServiceHost> _vHosts = new(hosts);
+ private readonly ConditionalWeakTable<IManagedPlugin, IEndpoint[]> _endpointsForPlugins = new();
/// <summary>
/// The <see cref="IPEndPoint"/> transport endpoint for all loaded service hosts
/// </summary>
- public IPEndPoint ServiceEndpoint { get; }
+ public IPEndPoint ServiceEndpoint => serviceEndpoint;
/// <summary>
/// The collection of hosts that are loaded by this group
@@ -53,26 +59,13 @@ namespace VNLib.Plugins.Essentials.ServiceStack
public IReadOnlyCollection<IServiceHost> Hosts => _vHosts;
/// <summary>
- /// Initalizes a new <see cref="ServiceGroup"/> of virtual hosts
- /// with common transport
- /// </summary>
- /// <param name="serviceEndpoint">The <see cref="IPEndPoint"/> to listen for connections on</param>
- /// <param name="hosts">The hosts that share a common interface endpoint</param>
- public ServiceGroup(IPEndPoint serviceEndpoint, IEnumerable<IServiceHost> hosts)
- {
- _endpointsForPlugins = new();
- _vHosts = new(hosts);
- ServiceEndpoint = serviceEndpoint;
- }
-
- /// <summary>
/// Manually detatches runtime services and their loaded endpoints from all
/// endpoints.
/// </summary>
internal void UnloadAll()
{
//Remove all loaded endpoints
- _vHosts.TryForeach(v => _endpointsForPlugins.TryForeach(eps => v.OnRuntimeServiceDetach(eps.Key, eps.Value)));
+ _vHosts.TryForeach(v => _endpointsForPlugins.ForEach(eps => v.OnRuntimeServiceDetach(eps.Key, eps.Value)));
//Clear all hosts
_vHosts.Clear();
diff --git a/lib/Plugins.Essentials/src/Accounts/AccountUtils.cs b/lib/Plugins.Essentials/src/Accounts/AccountUtils.cs
index 396d496..38c62e0 100644
--- a/lib/Plugins.Essentials/src/Accounts/AccountUtils.cs
+++ b/lib/Plugins.Essentials/src/Accounts/AccountUtils.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Plugins.Essentials
@@ -26,7 +26,6 @@ using System;
using System.Threading;
using System.Threading.Tasks;
using System.Security.Cryptography;
-using System.Text.RegularExpressions;
using System.Runtime.CompilerServices;
using VNLib.Hashing;
@@ -81,12 +80,6 @@ namespace VNLib.Plugins.Essentials.Accounts
public const ulong MINIMUM_LEVEL = 0x0000000100000001L;
-
- /// <summary>
- /// Speical character regual expresion for basic checks
- /// </summary>
- public static readonly Regex SpecialCharacters = new(@"[\r\n\t\a\b\e\f#?!@$%^&*\+\-\~`|<>\{}]", RegexOptions.Compiled);
-
#region Password/User helper extensions
/// <summary>
@@ -101,8 +94,10 @@ namespace VNLib.Plugins.Essentials.Accounts
/// <returns>A value greater than 0 if successful, 0 or negative values if a failure occured</returns>
public static async Task<ERRNO> ValidatePasswordAsync(this IUserManager manager, IUser user, string password, PassValidateFlags flags, CancellationToken cancellation)
{
- _ = manager ?? throw new ArgumentNullException(nameof(manager));
- using PrivateString ps = new(password, false);
+ ArgumentNullException.ThrowIfNull(user);
+ ArgumentNullException.ThrowIfNull(manager);
+
+ using PrivateString ps = PrivateString.ToPrivateString(password, false);
return await manager.ValidatePasswordAsync(user, ps, flags, cancellation).ConfigureAwait(false);
}
@@ -118,8 +113,10 @@ namespace VNLib.Plugins.Essentials.Accounts
/// <returns>The result of the operation, the result should be 1 (aka true)</returns>
public static async Task<ERRNO> UpdatePasswordAsync(this IUserManager manager, IUser user, string password, CancellationToken cancellation = default)
{
- _ = manager ?? throw new ArgumentNullException(nameof(manager));
- using PrivateString ps = new(password, false);
+ ArgumentNullException.ThrowIfNull(user);
+ ArgumentNullException.ThrowIfNull(manager);
+
+ using PrivateString ps = PrivateString.ToPrivateString(password, false);
return await manager.UpdatePasswordAsync(user, ps, cancellation).ConfigureAwait(false);
}
@@ -140,6 +137,7 @@ namespace VNLib.Plugins.Essentials.Accounts
/// <returns>The origin of the account</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string GetAccountOrigin(this IUser ud) => ud[ACC_ORIGIN_ENTRY];
+
/// <summary>
/// If this account was created by any means other than a local account creation.
/// Implementors can use this method to specify the origin of the account. This field is not required
@@ -158,7 +156,7 @@ namespace VNLib.Plugins.Essentials.Accounts
/// <returns>A <see cref="PrivateString"/> that contains the new password hash</returns>
public static PrivateString GetRandomPassword(this IPasswordHashingProvider hashing, int size = RANDOM_PASS_SIZE)
{
- _ = hashing ?? throw new ArgumentNullException(nameof(hashing));
+ ArgumentNullException.ThrowIfNull(hashing);
//Get random bytes
using UnsafeMemoryHandle<byte> randBuffer = MemoryUtil.UnsafeAlloc(size);
@@ -175,7 +173,7 @@ namespace VNLib.Plugins.Essentials.Accounts
finally
{
//Zero the block and return to pool
- MemoryUtil.InitializeBlock(randBuffer.Span);
+ MemoryUtil.InitializeBlock(ref randBuffer.GetReference(), size);
}
}
@@ -190,10 +188,10 @@ namespace VNLib.Plugins.Essentials.Accounts
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Verify(this IPasswordHashingProvider provider, PrivateString passHash, PrivateString password)
{
- _ = provider ?? throw new ArgumentNullException(nameof(provider));
- _ = password ?? throw new ArgumentNullException(nameof(password));
- _ = passHash ?? throw new ArgumentNullException(nameof(passHash));
-
+ ArgumentNullException.ThrowIfNull(provider);
+ ArgumentNullException.ThrowIfNull(passHash);
+ ArgumentNullException.ThrowIfNull(password);
+
//Casting PrivateStrings to spans will reference the base string directly
return provider.Verify(passHash.ToReadOnlySpan(), password.ToReadOnlySpan());
}
@@ -208,8 +206,8 @@ namespace VNLib.Plugins.Essentials.Accounts
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static PrivateString Hash(this IPasswordHashingProvider provider, PrivateString password)
{
- _ = provider ?? throw new ArgumentNullException(nameof(provider));
- _ = password ?? throw new ArgumentNullException(nameof(password));
+ ArgumentNullException.ThrowIfNull(provider);
+ ArgumentNullException.ThrowIfNull(password);
return provider.Hash(password.ToReadOnlySpan());
}
@@ -255,7 +253,8 @@ namespace VNLib.Plugins.Essentials.Accounts
/// <exception cref="InvalidOperationException"></exception>
public static IClientAuthorization GenerateAuthorization(this HttpEntity entity, IClientSecInfo secInfo, IUser user)
{
- _ = secInfo ?? throw new ArgumentNullException(nameof(secInfo));
+ ArgumentNullException.ThrowIfNull(user);
+ ArgumentNullException.ThrowIfNull(secInfo);
if (!entity.Session.IsSet || entity.Session.SessionType != SessionType.Web)
{
@@ -383,7 +382,7 @@ namespace VNLib.Plugins.Essentials.Accounts
/// <exception cref="NotSupportedException"></exception>
public static ERRNO TryEncryptClientData(this HttpEntity entity, IClientSecInfo secInfo, ReadOnlySpan<byte> data, Span<byte> output)
{
- _ = secInfo ?? throw new ArgumentNullException(nameof(secInfo));
+ ArgumentNullException.ThrowIfNull(secInfo);
//Use the default sec provider
IAccountSecurityProvider prov = entity.GetSecProviderOrThrow();
diff --git a/lib/Plugins.Essentials/src/Content/DirectFileStream.cs b/lib/Plugins.Essentials/src/Content/DirectFileStream.cs
new file mode 100644
index 0000000..67a6524
--- /dev/null
+++ b/lib/Plugins.Essentials/src/Content/DirectFileStream.cs
@@ -0,0 +1,120 @@
+/*
+* Copyright (c) 2024 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Plugins.Essentials
+* File: DirectFileStream.cs
+*
+* DirectFileStream.cs is part of VNLib.Plugins.Essentials which is part of the larger
+* VNLib collection of libraries and utilities.
+*
+* VNLib.Plugins.Essentials is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License as
+* published by the Free Software Foundation, either version 3 of the
+* License, or (at your option) any later version.
+*
+* VNLib.Plugins.Essentials is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+
+using System;
+using System.IO;
+using System.Threading.Tasks;
+
+using Microsoft.Win32.SafeHandles;
+
+using VNLib.Utils;
+using VNLib.Net.Http;
+
+#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
+
+namespace VNLib.Plugins.Essentials.Content
+{
+
+ /*
+ * Why does this file exist? Well, in .NET streaming files is slow as crap.
+ * It is by-far the largest bottleneck in this framework.
+ *
+ * I wanted more direct control over file access for future file performance
+ * improvments. For now using the RandomAccess class bypasses the internal
+ * buffering used by the filestream class. I saw almost no difference in
+ * per-request performance but a slight reduction in processor usage across
+ * profiling sessions. This class also makes use of the new IHttpStreamResponse
+ * interface.
+ */
+
+ internal sealed class DirectFileStream(SafeFileHandle fileHandle) : VnDisposeable, IHttpStreamResponse
+ {
+ private long _position;
+
+ /// <summary>
+ /// Gets the current file pointer position
+ /// </summary>
+ public long Position => _position;
+
+ /// <summary>
+ /// Gets the length of the file
+ /// </summary>
+ public readonly long Length = RandomAccess.GetLength(fileHandle);
+
+ ///<inheritdoc/>
+ public async ValueTask<int> ReadAsync(Memory<byte> buffer)
+ {
+ //Read data from the file into the buffer, using the current position as the starting offset
+ long read = await RandomAccess.ReadAsync(fileHandle, buffer, _position, default);
+
+ _position += read;
+
+ return (int)read;
+ }
+
+ ///<inheritdoc/>
+ public ValueTask DisposeAsync()
+ {
+ //Interal dispose
+ Dispose();
+ return ValueTask.CompletedTask;
+ }
+
+ ///<inheritdoc/>
+ protected override void Free() => fileHandle.Dispose();
+
+ /// <summary>
+ /// Equivalent to <see cref="FileStream.Seek(long, SeekOrigin)"/> but for a
+ /// <see cref="DirectFileStream"/>
+ /// </summary>
+ /// <param name="offset">The number in bytes to see the stream position to</param>
+ /// <param name="origin">The offset origin</param>
+ public void Seek(long offset, SeekOrigin origin)
+ {
+ switch (origin)
+ {
+ case SeekOrigin.Begin:
+ ArgumentOutOfRangeException.ThrowIfNegative(offset);
+ _position = offset;
+ break;
+ case SeekOrigin.Current:
+ ArgumentOutOfRangeException.ThrowIfGreaterThan(_position + offset, Length);
+ _position += offset;
+ break;
+ case SeekOrigin.End:
+ ArgumentOutOfRangeException.ThrowIfGreaterThan(offset, 0);
+ _position = Length + offset;
+ break;
+ }
+ }
+
+ /// <summary>
+ /// Opens a file for direct access with default options
+ /// </summary>
+ /// <param name="fileName">The name of the file to open</param>
+ /// <returns>The new direct file-stream</returns>
+ public static DirectFileStream Open(string fileName)
+ => new(File.OpenHandle(fileName, options: FileOptions.SequentialScan | FileOptions.Asynchronous));
+ }
+} \ No newline at end of file
diff --git a/lib/Plugins.Essentials/src/EventProcessor.cs b/lib/Plugins.Essentials/src/EventProcessor.cs
index 861f318..61a9b64 100644
--- a/lib/Plugins.Essentials/src/EventProcessor.cs
+++ b/lib/Plugins.Essentials/src/EventProcessor.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Plugins.Essentials
@@ -29,6 +29,8 @@ using System.Threading;
using System.Net.Sockets;
using System.Threading.Tasks;
using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Runtime.CompilerServices;
using VNLib.Net.Http;
using VNLib.Utils.IO;
@@ -51,7 +53,7 @@ namespace VNLib.Plugins.Essentials
/// that breaks down simple processing procedures, routing, and session
/// loading.
/// </summary>
- public abstract class EventProcessor : IWebRoot, IWebProcessor
+ public abstract class EventProcessor(EventProcessorConfig config) : IWebRoot, IWebProcessor
{
private static readonly AsyncLocal<EventProcessor?> _currentProcessor = new();
@@ -61,24 +63,6 @@ namespace VNLib.Plugins.Essentials
public static EventProcessor? Current => _currentProcessor.Value;
/// <summary>
- /// The filesystem entrypoint path for the site
- /// </summary>
- public abstract string Directory { get; }
-
- ///<inheritdoc/>
- public abstract string Hostname { get; }
-
- /// <summary>
- /// Gets the EP processing options
- /// </summary>
- public abstract IEpProcessingOptions Options { get; }
-
- /// <summary>
- /// Event log provider
- /// </summary>
- protected abstract ILogProvider Log { get; }
-
- /// <summary>
/// <para>
/// Called when the server intends to process a file and requires translation from a
/// uri path to a usable filesystem path
@@ -125,73 +109,81 @@ namespace VNLib.Plugins.Essentials
public abstract void PostProcessEntity(HttpEntity entity, ref FileProcessArgs chosenRoutine);
///<inheritdoc/>
- public abstract IAccountSecurityProvider AccountSecurity { get; }
-
- /// <summary>
- /// The table of virtual endpoints that will be used to process requests
- /// </summary>
- /// <remarks>
- /// May be overriden to provide a custom endpoint table
- /// </remarks>
- public virtual IVirtualEndpointTable EndpointTable { get; } = new SemiConsistentVeTable();
-
- /// <summary>
- /// The middleware chain that will be used to process requests
- /// </summary>
- /// <remarks>
- /// If derrieved, may be overriden to provide a custom middleware chain
- /// </remarks>
- public virtual IHttpMiddlewareChain MiddlewareChain { get; } = new SemiConistentMiddlewareChain();
-
-
- /// <summary>
- /// An <see cref="ISessionProvider"/> that connects stateful sessions to
- /// HTTP connections
- /// </summary>
- private ISessionProvider? Sessions;
+ public virtual EventProcessorConfig Options => config;
+ ///<inheritdoc/>
+ public string Hostname => config.Hostname;
+
+
+ /*
+ * Okay. So this is suposed to be a stupid fast lookup table for lock-free
+ * service pool exchanges. The goal is for future runtime service expansion.
+ *
+ * The reason lookups must be unnoticabyly fast is because the should be
+ * VERY rarley changed and will be read on every request.
+ *
+ * The goal of this table specifially is to make sure requesting a desired
+ * service is extremely fast and does not require any locks or synchronization.
+ */
+ const int SESS_INDEX = 0;
+ const int ROUTER_INDEX = 1;
+ const int SEC_INDEX = 2;
+
/// <summary>
- /// Sets or resets the current <see cref="ISessionProvider"/>
- /// for all connections
+ /// The internal service pool for the processor
/// </summary>
- /// <param name="sp">The new <see cref="ISessionProvider"/></param>
- public void SetSessionProvider(ISessionProvider? sp) => _ = Interlocked.Exchange(ref Sessions, sp);
+ protected readonly HttpProcessorServicePool ServicePool = new([
+ typeof(ISessionProvider), //Order must match the indexes above
+ typeof(IPageRouter),
+ typeof(IAccountSecurityProvider)
+ ]);
+
+ /*
+ * Fields are not marked as volatile because they should not
+ * really be updated at all in production uses, and if hot-reload
+ * is used, I don't consider a dirty read to be a large enough
+ * problem here.
+ */
- /// <summary>
- /// An <see cref="IPageRouter"/> to route files to be processed
- /// </summary>
- private IPageRouter? Router;
-
- /// <summary>
- /// Sets or resets the current <see cref="IPageRouter"/>
- /// for all connections
- /// </summary>
- /// <param name="router"><see cref="IPageRouter"/> to route incomming connections</param>
- public void SetPageRouter(IPageRouter? router) => _ = Interlocked.Exchange(ref Router, router);
+ private IAccountSecurityProvider? _accountSec;
+ private ISessionProvider? _sessions;
+ private IPageRouter? _router;
+
+ ///<inheritdoc/>
+ public IAccountSecurityProvider? AccountSecurity
+ {
+ //Exchange the version of the account security provider
+ get => ServicePool.ExchangeVersion(ref _accountSec, SEC_INDEX);
+ }
///<inheritdoc/>
public virtual async ValueTask ClientConnectedAsync(IHttpEvent httpEvent)
{
- //read local ref to session provider and page router
- ISessionProvider? _sessions = Sessions;
- IPageRouter? router = Router;
+ /*
+ * read any "volatile" properties into local copies for the duration
+ * of the request processing. This is to ensure that the properties
+ * are not changed during the processing of the request.
+ */
+
+ ISessionProvider? sessions = ServicePool.ExchangeVersion(ref _sessions, SESS_INDEX);
+ IPageRouter? router = ServicePool.ExchangeVersion(ref _router, ROUTER_INDEX);
+
+ LinkedListNode<IHttpMiddleware>? mwNode = config.MiddlewareChain.GetCurrentHead();
//event cancellation token
HttpEntity entity = new(httpEvent, this);
-
- LinkedListNode<IHttpMiddleware>? mwNode;
//Set ambient processor context
- _currentProcessor.Value = this;
+ _currentProcessor.Value = this;
try
{
//If sessions are set, get a session for the current connection
- if (_sessions != null)
+ if (sessions != null)
{
//Get the session
- entity.EventSessionHandle = await _sessions.GetSessionAsync(httpEvent, entity.EventCancellation);
+ entity.EventSessionHandle = await sessions.GetSessionAsync(httpEvent, entity.EventCancellation);
//If the processor had an error recovering the session, return the result to the processor
if (entity.EventSessionHandle.EntityStatus != FileProcessArgs.Continue)
@@ -206,7 +198,6 @@ namespace VNLib.Plugins.Essentials
try
{
- //Pre-process entity
PreProcessEntity(entity, out entity.EventArgs);
//If preprocess returned a value, exit
@@ -215,9 +206,6 @@ namespace VNLib.Plugins.Essentials
goto RespondAndExit;
}
- //Handle middleware before file processing
- mwNode = MiddlewareChain.GetCurrentHead();
-
//Loop through nodes
while(mwNode != null)
{
@@ -236,12 +224,12 @@ namespace VNLib.Plugins.Essentials
}
mwNode = mwNode.Next;
- }
+ }
- if (!EndpointTable.IsEmpty)
+ if (!config.EndpointTable.IsEmpty)
{
//See if the virtual file is servicable
- if (EndpointTable.TryGetEndpoint(entity.Server.Path, out IVirtualEndpoint<HttpEntity>? vf))
+ if (config.EndpointTable.TryGetEndpoint(entity.Server.Path, out IVirtualEndpoint<HttpEntity>? vf))
{
//Invoke the page handler process method
VfReturnType rt = await vf.Process(entity);
@@ -283,7 +271,7 @@ namespace VNLib.Plugins.Essentials
}
catch (Exception ex)
{
- Log.Error(ex, "Exception raised while releasing the assocated session");
+ config.Log.Error(ex, "Exception raised while releasing the assocated session");
}
}
@@ -305,17 +293,17 @@ namespace VNLib.Plugins.Essentials
}
catch (ResourceUpdateFailedException ruf)
{
- Log.Warn(ruf);
+ config.Log.Warn(ruf);
CloseWithError(HttpStatusCode.ServiceUnavailable, httpEvent);
}
catch (SessionException se)
{
- Log.Warn(se, "An exception was raised while attempting to get or save a session");
+ config.Log.Warn(se, "An exception was raised while attempting to get or save a session");
CloseWithError(HttpStatusCode.ServiceUnavailable, httpEvent);
}
catch (OperationCanceledException oce)
{
- Log.Warn(oce, "Request execution time exceeded, connection terminated");
+ config.Log.Warn(oce, "Request execution time exceeded, connection terminated");
CloseWithError(HttpStatusCode.ServiceUnavailable, httpEvent);
}
catch (IOException ioe) when (ioe.InnerException is SocketException)
@@ -324,7 +312,7 @@ namespace VNLib.Plugins.Essentials
}
catch (Exception ex)
{
- Log.Warn(ex, "Unhandled exception during application code execution.");
+ config.Log.Warn(ex, "Unhandled exception during application code execution.");
//Invoke the root error handler
CloseWithError(HttpStatusCode.InternalServerError, httpEvent);
}
@@ -341,7 +329,7 @@ namespace VNLib.Plugins.Essentials
/// </summary>
/// <param name="entity">The entity to process the file for</param>
/// <param name="args">The selected <see cref="FileProcessArgs"/> to determine what file to process</param>
- protected virtual void ProcessFile(IHttpEvent entity, in FileProcessArgs args)
+ protected virtual void ProcessFile(IHttpEvent entity, ref readonly FileProcessArgs args)
{
try
{
@@ -414,7 +402,7 @@ namespace VNLib.Plugins.Essentials
//See if the last modifed header was set
DateTimeOffset? ifModifedSince = entity.Server.LastModified();
-
+
//If the header was set, check the date, if the file has been modified since, continue sending the file
if (ifModifedSince.HasValue && ifModifedSince.Value > fileLastModified)
{
@@ -425,109 +413,97 @@ namespace VNLib.Plugins.Essentials
//Get the content type of he file
ContentType fileType = HttpHelpers.GetContentTypeFromFile(filename);
-
+
//Make sure the client accepts the content type
- if (entity.Server.Accepts(fileType))
+ if (!entity.Server.Accepts(fileType))
{
- //set last modified time as the files last write time
- entity.Server.LastModified(fileLastModified);
-
- //try to open the selected file for reading and allow sharing
- FileStream fs = new (filename, FileMode.Open, FileAccess.Read, FileShare.Read);
-
- long endOffset = checked((long)entity.Server.Range.End);
- long startOffset = checked((long)entity.Server.Range.Start);
-
- //Follows rfc7233 -> https://www.rfc-editor.org/rfc/rfc7233#section-1.2
- switch (entity.Server.Range.RangeType)
- {
- case HttpRangeType.FullRange:
- if (endOffset > fs.Length || endOffset - startOffset < 0)
- {
- //Set acceptable range size
- entity.Server.Headers[HttpResponseHeader.ContentRange] = $"bytes */{fs.Length}";
-
- //The start offset is greater than the file length, return range not satisfiable
- entity.CloseResponse(HttpStatusCode.RequestedRangeNotSatisfiable);
- }
- else
- {
- //Seek the stream to the specified start position
- fs.Seek(startOffset, SeekOrigin.Begin);
-
- //Set range header, by passing the actual full content size
- entity.SetContentRangeHeader(entity.Server.Range, fs.Length);
+ //Unacceptable
+ CloseWithError(HttpStatusCode.NotAcceptable, entity);
+ return;
+ }
- //Send the response, with actual response length (diff between stream length and position)
- entity.CloseResponse(HttpStatusCode.PartialContent, fileType, fs, endOffset - startOffset + 1);
- }
- break;
- case HttpRangeType.FromStart:
- if (startOffset > fs.Length)
- {
- //Set acceptable range size
- entity.Server.Headers[HttpResponseHeader.ContentRange] = $"bytes */{fs.Length}";
+ //set last modified time as the files last write time
+ entity.Server.LastModified(fileLastModified);
- //The start offset is greater than the file length, return range not satisfiable
- entity.CloseResponse(HttpStatusCode.RequestedRangeNotSatisfiable);
- }
- else
- {
- //Seek the stream to the specified start position
- fs.Seek(startOffset, SeekOrigin.Begin);
+ //Open the file handle directly, reading will always be sequentially read and async
+ DirectFileStream dfs = DirectFileStream.Open(filename);
- //Set range header, by passing the actual full content size
- entity.SetContentRangeHeader(entity.Server.Range, fs.Length);
+ long endOffset = checked((long)entity.Server.Range.End);
+ long startOffset = checked((long)entity.Server.Range.Start);
- //Send the response, with actual response length (diff between stream length and position)
- entity.CloseResponse(HttpStatusCode.PartialContent, fileType, fs, fs.Length - fs.Position);
- }
- break;
-
- case HttpRangeType.FromEnd:
- if (endOffset > fs.Length)
- {
- //Set acceptable range size
- entity.Server.Headers[HttpResponseHeader.ContentRange] = $"bytes */{fs.Length}";
+ //Follows rfc7233 -> https://www.rfc-editor.org/rfc/rfc7233#section-1.2
+ switch (entity.Server.Range.RangeType)
+ {
+ case HttpRangeType.FullRange:
+ if (endOffset > dfs.Length || endOffset - startOffset < 0)
+ {
+ //The start offset is greater than the file length, return range not satisfiable
+ entity.Server.Headers[HttpResponseHeader.ContentRange] = $"bytes */{dfs.Length}";
+ entity.CloseResponse(HttpStatusCode.RequestedRangeNotSatisfiable);
+ }
+ else
+ {
+ //Seek the stream to the specified start position
+ dfs.Seek(startOffset, SeekOrigin.Begin);
- //The end offset is greater than the file length, return range not satisfiable
- entity.CloseResponse(HttpStatusCode.RequestedRangeNotSatisfiable);
- }
- else
- {
- //Seek the stream to the specified end position, server auto range will handle the rest
- fs.Seek(-endOffset, SeekOrigin.End);
+ //Set range header, by passing the actual full content size
+ entity.SetContentRangeHeader(entity.Server.Range, dfs.Length);
- //Set range header, by passing the actual full content size
- entity.SetContentRangeHeader(entity.Server.Range, fs.Length);
+ //Send the response, with actual response length (diff between stream length and position)
+ entity.CloseResponse(HttpStatusCode.PartialContent, fileType, dfs, endOffset - startOffset + 1);
+ }
+ break;
+ case HttpRangeType.FromStart:
+ if (startOffset > dfs.Length)
+ {
+ //The start offset is greater than the file length, return range not satisfiable
+ entity.Server.Headers[HttpResponseHeader.ContentRange] = $"bytes */{dfs.Length}";
+ entity.CloseResponse(HttpStatusCode.RequestedRangeNotSatisfiable);
+ }
+ else
+ {
+ //Seek the stream to the specified start position
+ dfs.Seek(startOffset, SeekOrigin.Begin);
+
+ entity.SetContentRangeHeader(entity.Server.Range, dfs.Length);
+
+ entity.CloseResponse(HttpStatusCode.PartialContent, fileType, dfs, dfs.Length - dfs.Position);
+ }
+ break;
- //Send the response, with actual response length (diff between stream length and position)
- entity.CloseResponse(HttpStatusCode.PartialContent, fileType, fs, fs.Length - fs.Position);
- }
- break;
- //No range or invalid range (the server is supposed to ignore invalid ranges)
- default:
- //send the whole file
- entity.CloseResponse(HttpStatusCode.OK, fileType, fs, fs.Length);
- break;
- }
-
- }
- else
- {
- //Unacceptable
- CloseWithError(HttpStatusCode.NotAcceptable, entity);
+ case HttpRangeType.FromEnd:
+ if (endOffset > dfs.Length)
+ {
+ //The end offset is greater than the file length, return range not satisfiable
+ entity.Server.Headers[HttpResponseHeader.ContentRange] = $"bytes */{dfs.Length}";
+ entity.CloseResponse(HttpStatusCode.RequestedRangeNotSatisfiable);
+ }
+ else
+ {
+ //Seek the stream to the specified end position, server auto range will handle the rest
+ dfs.Seek(-endOffset, SeekOrigin.End);
+
+ entity.SetContentRangeHeader(entity.Server.Range, dfs.Length);
+
+ entity.CloseResponse(HttpStatusCode.PartialContent, fileType, dfs, dfs.Length - dfs.Position);
+ }
+ break;
+ //No range or invalid range (the server is supposed to ignore invalid ranges)
+ default:
+ //send the whole file
+ entity.CloseResponse(HttpStatusCode.OK, fileType, dfs, dfs.Length);
+ break;
}
}
catch (IOException ioe)
{
- Log.Information(ioe, "Unhandled exception during file opening.");
+ config.Log.Information(ioe, "Unhandled exception during file opening.");
CloseWithError(HttpStatusCode.Locked, entity);
return;
}
catch (Exception ex)
{
- Log.Error(ex, "Unhandled exception during file opening.");
+ config.Log.Error(ex, "Unhandled exception during file opening.");
//Invoke the root error handler
CloseWithError(HttpStatusCode.InternalServerError, entity);
return;
@@ -690,5 +666,83 @@ namespace VNLib.Plugins.Essentials
}
return false;
}
+
+ /// <summary>
+ /// A pool of services that an <see cref="EventProcessor"/> will use can be exchanged at runtime
+ /// </summary>
+ /// <param name="expectedTypes">An ordered array of desired types</param>
+ protected sealed class HttpProcessorServicePool(Type[] expectedTypes)
+ {
+ private readonly uint[] _serviceTable = new uint[expectedTypes.Length];
+ private readonly WeakReference<object?>[] _objects = CreateServiceArray(expectedTypes.Length);
+ private readonly ImmutableArray<Type> _types = [.. expectedTypes];
+
+ /// <summary>
+ /// Gets all of the desired types for the servicec pool
+ /// </summary>
+ public ImmutableArray<Type> Types => _types;
+
+ /// <summary>
+ /// Sets a desired service instance in the pool, or clears it
+ /// from the pool.
+ /// </summary>
+ /// <param name="service">The service type to publish</param>
+ /// <param name="instance">The service instance to store</param>
+ public void SetService(Type service, object? instance)
+ {
+ ArgumentNullException.ThrowIfNull(service);
+
+ //Make sure the instance is of the correct type
+ if(instance is not null && !service.IsInstanceOfType(instance))
+ {
+ throw new ArgumentException("The instance does not match the service type");
+ }
+
+ //If the service type is not desired, return
+ int index = Array.IndexOf(expectedTypes, service);
+ if (index != -1)
+ {
+ //Set the service as a new weak reference atomically
+ Volatile.Write(ref _objects[index], new(instance));
+
+ //Notify that the service has been updated
+ Interlocked.Exchange(ref _serviceTable[index], 1);
+ }
+ }
+
+ /// <summary>
+ /// Determines if a desired services has been modified within
+ /// the pool, if it has, the service will be exchanged for the
+ /// new service.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="instance">A reference to the internal instance to exhange</param>
+ /// <param name="tableIndex">The constant index for the service type</param>
+ /// <returns>The exchanged service instance</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+ internal T? ExchangeVersion<T>(ref T? instance, int tableIndex) where T : class?
+ {
+ //Clear modified flag
+ if (Interlocked.Exchange(ref _serviceTable[tableIndex], 0) == 1)
+ {
+ //Atomic read on the reference instance
+ WeakReference<object?> wr = Volatile.Read(ref _objects[tableIndex]);
+
+ //Try to get the object instance
+ wr.TryGetTarget(out object? value);
+
+ instance = (T?)value;
+ }
+
+ return instance;
+ }
+
+ private static WeakReference<object?>[] CreateServiceArray(int size)
+ {
+ WeakReference<object?>[] arr = new WeakReference<object?>[size];
+ Array.Fill(arr, new (null));
+ return arr;
+ }
+ }
}
} \ No newline at end of file
diff --git a/lib/Plugins.Essentials/src/EventProcessorConfig.cs b/lib/Plugins.Essentials/src/EventProcessorConfig.cs
new file mode 100644
index 0000000..8f401ac
--- /dev/null
+++ b/lib/Plugins.Essentials/src/EventProcessorConfig.cs
@@ -0,0 +1,93 @@
+/*
+* Copyright (c) 2024 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Plugins.Essentials
+* File: EventProcessorConfig.cs
+*
+* EventProcessorConfig.cs is part of VNLib.Plugins.Essentials which is part
+* of the larger VNLib collection of libraries and utilities.
+*
+* VNLib.Plugins.Essentials is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License as
+* published by the Free Software Foundation, either version 3 of the
+* License, or (at your option) any later version.
+*
+* VNLib.Plugins.Essentials is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+
+using System;
+using System.IO;
+using System.Net;
+using System.Collections.Frozen;
+using System.Collections.Generic;
+
+using VNLib.Utils.Logging;
+using VNLib.Plugins.Essentials.Middleware;
+
+namespace VNLib.Plugins.Essentials
+{
+ /// <summary>
+ /// An immutable configuration object for the <see cref="EventProcessor"/> that services the
+ /// lifetieme of the processor.
+ /// </summary>
+ /// <param name="Directory"> The filesystem entrypoint path for the site</param>
+ /// <param name="Hostname">The hostname the server will listen for, and the hostname that will identify this root when a connection requests it</param>
+ /// <param name="Log">The application log provider for writing logging messages to</param>
+ /// <param name="Options">Gets the EP processing options</param>
+ public record class EventProcessorConfig(string Directory, string Hostname, ILogProvider Log, IEpProcessingOptions Options)
+ {
+ /// <summary>
+ /// The table of virtual endpoints that will be used to process requests
+ /// </summary>
+ /// <remarks>
+ /// May be overriden to provide a custom endpoint table
+ /// </remarks>
+ public IVirtualEndpointTable EndpointTable { get; init; } = new SemiConsistentVeTable();
+
+ /// <summary>
+ /// The middleware chain that will be used to process requests
+ /// </summary>
+ /// <remarks>
+ /// If derrieved, may be overriden to provide a custom middleware chain
+ /// </remarks>
+ public IHttpMiddlewareChain MiddlewareChain { get; init; } = new SemiConistentMiddlewareChain();
+
+ /// <summary>
+ /// The name of a default file to search for within a directory if no file is specified (index.html).
+ /// This array should be ordered.
+ /// </summary>
+ public IReadOnlyCollection<string> DefaultFiles { get; init; } = [];
+
+ /// <summary>
+ /// File extensions that are denied from being read from the filesystem
+ /// </summary>
+ public FrozenSet<string> ExcludedExtensions { get; init; } = FrozenSet<string>.Empty;
+
+ /// <summary>
+ /// File attributes that must be matched for the file to be accessed
+ /// </summary>
+ public FileAttributes AllowedAttributes { get; init; }
+
+ /// <summary>
+ /// Files that match any attribute flag set will be denied
+ /// </summary>
+ public FileAttributes DissallowedAttributes { get; init; }
+
+ /// <summary>
+ /// A table of known downstream servers/ports that can be trusted to proxy connections
+ /// </summary>
+ public FrozenSet<IPAddress> DownStreamServers { get; init; } = FrozenSet<IPAddress>.Empty;
+
+ /// <summary>
+ /// A <see cref="TimeSpan"/> for how long a connection may remain open before all operations are cancelled
+ /// </summary>
+ public TimeSpan ExecutionTimeout { get; init; } = TimeSpan.Zero;
+ }
+} \ No newline at end of file
diff --git a/lib/Plugins.Essentials/src/Extensions/ConnectionInfoExtensions.cs b/lib/Plugins.Essentials/src/Extensions/ConnectionInfoExtensions.cs
index 5c36465..92fae08 100644
--- a/lib/Plugins.Essentials/src/Extensions/ConnectionInfoExtensions.cs
+++ b/lib/Plugins.Essentials/src/Extensions/ConnectionInfoExtensions.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Plugins.Essentials
@@ -165,10 +165,7 @@ namespace VNLib.Plugins.Essentials.Extensions
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static void SetContentRangeHeader(this IHttpEvent entity, in HttpRange range, long length)
{
- if(length < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(length), "Length must be greater than or equal to zero");
- }
+ ArgumentOutOfRangeException.ThrowIfNegative(length);
ulong start;
ulong end;
@@ -216,6 +213,7 @@ namespace VNLib.Plugins.Essentials.Extensions
/// <returns>true if the user-agent specified the cors security header</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsCors(this IConnectionInfo server) => "cors".Equals(server.Headers[SEC_HEADER_MODE], StringComparison.OrdinalIgnoreCase);
+
/// <summary>
/// Determines if the User-Agent specified "cross-site" in the Sec-Site header, OR
/// the connection spcified an origin header and the origin's host does not match the
@@ -228,6 +226,7 @@ namespace VNLib.Plugins.Essentials.Extensions
return "cross-site".Equals(server.Headers[SEC_HEADER_SITE], StringComparison.OrdinalIgnoreCase)
|| (server.Origin != null && !server.RequestUri.DnsSafeHost.Equals(server.Origin.DnsSafeHost, StringComparison.Ordinal));
}
+
/// <summary>
/// Is the connection user-agent created, or automatic
/// </summary>
@@ -235,12 +234,14 @@ namespace VNLib.Plugins.Essentials.Extensions
/// <returns>true if sec-user header was set to "?1"</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsUserInvoked(this IConnectionInfo server) => "?1".Equals(server.Headers[SEC_HEADER_USER], StringComparison.OrdinalIgnoreCase);
+
/// <summary>
/// Was this request created from normal user navigation
/// </summary>
/// <returns>true if sec-mode set to "navigate"</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNavigation(this IConnectionInfo server) => "navigate".Equals(server.Headers[SEC_HEADER_MODE], StringComparison.OrdinalIgnoreCase);
+
/// <summary>
/// Determines if the client specified "no-cache" for the cache control header, signalling they do not wish to cache the entity
/// </summary>
@@ -250,6 +251,7 @@ namespace VNLib.Plugins.Essentials.Extensions
string? cache_header = server.Headers[HttpRequestHeader.CacheControl];
return !string.IsNullOrWhiteSpace(cache_header) && cache_header.Contains("no-cache", StringComparison.OrdinalIgnoreCase);
}
+
/// <summary>
/// Sets the response cache headers to match the requested caching type. Does not check against request headers
/// </summary>
@@ -266,6 +268,7 @@ namespace VNLib.Plugins.Essentials.Extensions
//Set the cache hader string using the http helper class
server.Headers[HttpResponseHeader.CacheControl] = HttpHelpers.GetCacheString(type, maxAge);
}
+
/// <summary>
/// Sets the Cache-Control response header to <see cref="NO_CACHE_RESPONSE_HEADER_VALUE"/>
/// and the pragma response header to 'no-cache'
@@ -291,6 +294,7 @@ namespace VNLib.Plugins.Essentials.Extensions
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool EnpointPortsMatch(this IConnectionInfo server) => server.RequestUri.Port == server.LocalEndpoint.Port;
+
/// <summary>
/// Determines if the host of the current request URI matches the referer header host
/// </summary>
@@ -300,6 +304,7 @@ namespace VNLib.Plugins.Essentials.Extensions
{
return server.RequestUri.DnsSafeHost.Equals(server.Referer?.DnsSafeHost, StringComparison.OrdinalIgnoreCase);
}
+
/// <summary>
/// Expires a client's cookie
/// </summary>
@@ -314,6 +319,7 @@ namespace VNLib.Plugins.Essentials.Extensions
{
server.SetCookie(name, string.Empty, domain, path, TimeSpan.Zero, sameSite, false, secure);
}
+
/// <summary>
/// Sets a cookie with an infinite (session life-span)
/// </summary>
@@ -403,6 +409,7 @@ namespace VNLib.Plugins.Essentials.Extensions
//Get user-agent and determine if its a browser
return server.UserAgent != null && !server.UserAgent.Contains("bot", StringComparison.OrdinalIgnoreCase) && server.UserAgent.Contains("Mozilla", StringComparison.OrdinalIgnoreCase);
}
+
/// <summary>
/// Determines if the current connection is the loopback/internal network adapter
/// </summary>
@@ -443,6 +450,7 @@ namespace VNLib.Plugins.Essentials.Extensions
/// <returns>The real ip of the connection</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IPAddress GetTrustedIp(this IConnectionInfo server) => GetTrustedIp(server, server.IsBehindDownStreamServer());
+
/// <summary>
/// Gets the real IP address of the request if behind a trusted downstream server, otherwise returns the transport remote ip address
/// </summary>
diff --git a/lib/Plugins.Essentials/src/Extensions/EssentialHttpEventExtensions.cs b/lib/Plugins.Essentials/src/Extensions/EssentialHttpEventExtensions.cs
index 638b52a..f49af32 100644
--- a/lib/Plugins.Essentials/src/Extensions/EssentialHttpEventExtensions.cs
+++ b/lib/Plugins.Essentials/src/Extensions/EssentialHttpEventExtensions.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Plugins.Essentials
@@ -782,7 +782,7 @@ namespace VNLib.Plugins.Essentials.Extensions
/// <exception cref="PathTooLongException"></exception>
/// <exception cref="ArgumentNullException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static DirectoryInfo GetRootDir(this HttpEntity ev) => new(ev.RequestedRoot.Directory);
+ public static DirectoryInfo GetRootDir(this HttpEntity ev) => new(ev.RequestedRoot.Options.Directory);
/// <summary>
/// Returns the MIME string representation of the content type of the uploaded file.
diff --git a/lib/Plugins.Essentials/src/HttpEntity.cs b/lib/Plugins.Essentials/src/HttpEntity.cs
index f48198b..efdb2cd 100644
--- a/lib/Plugins.Essentials/src/HttpEntity.cs
+++ b/lib/Plugins.Essentials/src/HttpEntity.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Plugins.Essentials
@@ -49,7 +49,7 @@ namespace VNLib.Plugins.Essentials
/// A container for an <see cref="HttpEvent"/> with its attached session.
/// This class cannot be inherited.
/// </summary>
- public sealed class HttpEntity : IHttpEvent
+ public sealed class HttpEntity : IHttpEvent, IDisposable
{
/// <summary>
@@ -59,7 +59,23 @@ namespace VNLib.Plugins.Essentials
private readonly CancellationTokenSource EventCts;
- public HttpEntity(IHttpEvent entity, IWebProcessor root)
+ /// <summary>
+ /// Creates a new <see cref="HttpEntity"/> instance with the optional
+ /// session handle. If the session handle is set, the session will be
+ /// attached to the entity
+ /// </summary>
+ /// <param name="evnt">The event to parse and wrap</param>
+ /// <param name="root">The processor the connection has originated from</param>
+ /// <param name="session">An optional session handle to attach to the entity</param>
+ public HttpEntity(IHttpEvent evnt, IWebProcessor root, ref readonly SessionHandle session)
+ :this(evnt, root)
+ {
+ //Assign optional session and attempt to attach it
+ EventSessionHandle = session;
+ AttachSession();
+ }
+
+ internal HttpEntity(IHttpEvent entity, IWebProcessor root)
{
Entity = entity;
RequestedRoot = root;
@@ -100,12 +116,9 @@ namespace VNLib.Plugins.Essentials
}
/// <summary>
- /// Internal call to cleanup any internal resources
+ /// Cleans up internal resources
/// </summary>
- internal void Dispose()
- {
- EventCts.Dispose();
- }
+ public void Dispose() => EventCts.Dispose();
/// <summary>
/// A token that has a scheduled timeout to signal the cancellation of the entity event
@@ -209,6 +222,20 @@ namespace VNLib.Plugins.Essentials
}
///<inheritdoc/>
+ ///<exception cref="ContentTypeUnacceptableException"></exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void CloseResponse(HttpStatusCode code, ContentType type, IHttpStreamResponse stream, long length)
+ {
+ //Verify content type matches
+ if (!Server.Accepts(type))
+ {
+ throw new ContentTypeUnacceptableException("The client does not accept the content type of the response");
+ }
+
+ Entity.CloseResponse(code, type, stream, length);
+ }
+
+ ///<inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetControlFlag(ulong mask) => Entity.SetControlFlag(mask);
diff --git a/lib/Plugins.Essentials/src/IWebProcessorInfo.cs b/lib/Plugins.Essentials/src/IWebProcessorInfo.cs
index ae920ea..a523296 100644
--- a/lib/Plugins.Essentials/src/IWebProcessorInfo.cs
+++ b/lib/Plugins.Essentials/src/IWebProcessorInfo.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Plugins.Essentials
@@ -33,20 +33,14 @@ namespace VNLib.Plugins.Essentials
public interface IWebProcessor : IWebRoot
{
/// <summary>
- /// The filesystem entrypoint path for the site
- /// </summary>
- string Directory { get; }
-
- /// <summary>
/// Gets the EP processing options
/// </summary>
- IEpProcessingOptions Options { get; }
+ EventProcessorConfig Options { get; }
/// <summary>
- /// The shared <see cref="IAccountSecurityProvider"/> that provides
- /// user account security operations
+ /// Gets the account security provider
/// </summary>
- IAccountSecurityProvider AccountSecurity { get; }
+ IAccountSecurityProvider? AccountSecurity { get; }
/// <summary>
/// <para>
diff --git a/lib/Plugins.Essentials/src/Middleware/IHttpMiddlewareChain.cs b/lib/Plugins.Essentials/src/Middleware/IHttpMiddlewareChain.cs
index 0a05c70..ed6ce3b 100644
--- a/lib/Plugins.Essentials/src/Middleware/IHttpMiddlewareChain.cs
+++ b/lib/Plugins.Essentials/src/Middleware/IHttpMiddlewareChain.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Plugins.Essentials
@@ -49,7 +49,7 @@ namespace VNLib.Plugins.Essentials.Middleware
/// Removes a middleware handler from the chain
/// </summary>
/// <param name="middleware">The middleware instance to remove</param>
- void RemoveMiddleware(IHttpMiddleware middleware);
+ void Remove(IHttpMiddleware middleware);
/// <summary>
/// Removes all middleware handlers from the chain
diff --git a/lib/Plugins.Essentials/src/Middleware/SemiConistentMiddlewareChain.cs b/lib/Plugins.Essentials/src/Middleware/SemiConistentMiddlewareChain.cs
index 5d0c472..d3bc69b 100644
--- a/lib/Plugins.Essentials/src/Middleware/SemiConistentMiddlewareChain.cs
+++ b/lib/Plugins.Essentials/src/Middleware/SemiConistentMiddlewareChain.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Plugins.Essentials
@@ -22,6 +22,7 @@
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
+using System.Threading;
using System.Reflection;
using System.Collections.Generic;
@@ -67,10 +68,14 @@ namespace VNLib.Plugins.Essentials.Middleware
}
///<inheritdoc/>
- public LinkedListNode<IHttpMiddleware>? GetCurrentHead() => _middlewares.First;
+ public LinkedListNode<IHttpMiddleware>? GetCurrentHead()
+ {
+ LinkedList<IHttpMiddleware> currentTable = Volatile.Read(ref _middlewares);
+ return currentTable.First;
+ }
///<inheritdoc/>
- public void RemoveMiddleware(IHttpMiddleware middleware)
+ public void Remove(IHttpMiddleware middleware)
{
lock (_middlewares)
{
@@ -81,7 +86,7 @@ namespace VNLib.Plugins.Essentials.Middleware
newTable.Remove(middleware);
//Replace the current table with the new one
- _middlewares = newTable;
+ Volatile.Write(ref _middlewares, newTable);
}
}
}
diff --git a/lib/Plugins.Essentials/src/Users/IUserManager.cs b/lib/Plugins.Essentials/src/Users/IUserManager.cs
index 400a5d0..7b70f53 100644
--- a/lib/Plugins.Essentials/src/Users/IUserManager.cs
+++ b/lib/Plugins.Essentials/src/Users/IUserManager.cs
@@ -70,11 +70,11 @@ namespace VNLib.Plugins.Essentials.Users
/// <summary>
/// Attempts to get a user object without their password from the database asynchronously
/// </summary>
- /// <param name="emailAddress">The user's email address</param>
+ /// <param name="username">The user's uinque username</param>
/// <param name="cancellationToken">A token to cancel the operation</param>
/// <returns>The user's <see cref="IUser"/> object, null if the user was not found</returns>
/// <exception cref="ArgumentNullException"></exception>
- Task<IUser?> GetUserFromEmailAsync(string emailAddress, CancellationToken cancellationToken = default);
+ Task<IUser?> GetUserFromUsernameAsync(string username, CancellationToken cancellationToken = default);
/// <summary>
/// Creates a new user account in the store as per the request. The user-id field is optional,
diff --git a/lib/Plugins.Runtime/src/LoaderExtensions.cs b/lib/Plugins.Runtime/src/LoaderExtensions.cs
index e88ccb3..5ffbecb 100644
--- a/lib/Plugins.Runtime/src/LoaderExtensions.cs
+++ b/lib/Plugins.Runtime/src/LoaderExtensions.cs
@@ -250,7 +250,7 @@ namespace VNLib.Plugins.Runtime
/// <exception cref="AggregateException"></exception>
public static void InvokeUnload(this IPluginStack runtime)
{
- _ = runtime ?? throw new ArgumentNullException(nameof(runtime));
+ ArgumentNullException.ThrowIfNull(runtime);
//try unloading all plugins
runtime.Plugins.TryForeach(static p => p.UnloadPlugins());
@@ -265,10 +265,14 @@ namespace VNLib.Plugins.Runtime
/// <exception cref="AggregateException"></exception>
public static void UnloadAll(this IPluginStack runtime)
{
- _ = runtime ?? throw new ArgumentNullException(nameof(runtime));
+ ArgumentNullException.ThrowIfNull(runtime);
- //try unloading all plugins and their loaders
- runtime.Plugins.TryForeach(static p => p.UnloadAll());
+ //try unloading all plugins and their loaders, dont invoke GC on each unload
+ runtime.Plugins.TryForeach(static p => p.UnloadAll(false));
+
+ //Invoke a gc
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
}
/// <summary>
@@ -282,7 +286,11 @@ namespace VNLib.Plugins.Runtime
ArgumentNullException.ThrowIfNull(runtime, nameof(runtime));
//try reloading all plugins
- runtime.Plugins.TryForeach(static p => p.ReloadPlugins());
+ runtime.Plugins.TryForeach(static p => p.ReloadPlugins(false));
+
+ //Invoke a gc
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
}
/// <summary>
diff --git a/lib/Plugins.Runtime/src/PluginController.cs b/lib/Plugins.Runtime/src/PluginController.cs
index 7f82c13..3879060 100644
--- a/lib/Plugins.Runtime/src/PluginController.cs
+++ b/lib/Plugins.Runtime/src/PluginController.cs
@@ -52,17 +52,9 @@ namespace VNLib.Plugins.Runtime
*/
private readonly object _stateLock = new();
- private readonly List<LivePlugin> _plugins;
- private readonly List<KeyValuePair<IPluginEventListener, object?>> _listeners;
- private readonly PluginServicePool _servicePool;
-
-
- internal PluginController()
- {
- _plugins = new ();
- _listeners = new ();
- _servicePool = new ();
- }
+ private readonly List<LivePlugin> _plugins = [];
+ private readonly List<KeyValuePair<IPluginEventListener, object?>> _listeners = [];
+ private readonly PluginServicePool _servicePool = new();
/// <summary>
/// The current collection of plugins. Valid before the unload event.
@@ -73,7 +65,7 @@ namespace VNLib.Plugins.Runtime
///<exception cref="ArgumentNullException"></exception>
public void Register(IPluginEventListener listener, object? state = null)
{
- _ = listener ?? throw new ArgumentNullException(nameof(listener));
+ ArgumentNullException.ThrowIfNull(listener);
lock (_stateLock)
{
@@ -87,12 +79,12 @@ namespace VNLib.Plugins.Runtime
lock(_stateLock)
{
//Remove listener
- return _listeners.RemoveAll(p => p.Key == listener) > 0;
+ return _listeners.RemoveAll(p => ReferenceEquals(p.Key, listener)) > 0;
}
}
/// <summary>
- /// Populates the given <see cref="IServiceContainer"/> with all services
+ /// Returns an array of all exported services from all loaded plugins
/// </summary>
public PluginServiceExport[] GetExportedServices() => _servicePool.GetServices();
@@ -118,8 +110,8 @@ namespace VNLib.Plugins.Runtime
{
lock (_stateLock)
{
- _plugins.TryForeach(lp => lp.InitConfig(configData.AsSpan()));
- _plugins.TryForeach(lp => lp.InitLog(cliArgs));
+ _plugins.ForEach(lp => lp.InitConfig(configData.AsSpan()));
+ _plugins.ForEach(lp => lp.InitLog(cliArgs));
}
}
@@ -131,10 +123,10 @@ namespace VNLib.Plugins.Runtime
_plugins.TryForeach(static p => p.LoadPlugin());
//Load all services into the service pool
- _plugins.TryForeach(p => p.GetServices(_servicePool));
+ _plugins.ForEach(p => p.GetServices(_servicePool));
//Notify event handlers
- _listeners.TryForeach(l => l.Key.OnPluginLoaded(this, l.Value));
+ _listeners.ForEach(l => l.Key.OnPluginLoaded(this, l.Value));
}
}
@@ -145,7 +137,7 @@ namespace VNLib.Plugins.Runtime
try
{
//Notify event handlers
- _listeners.TryForeach(l => l.Key.OnPluginUnloaded(this, l.Value));
+ _listeners.ForEach(l => l.Key.OnPluginUnloaded(this, l.Value));
//Unload plugin instances
_plugins.TryForeach(static p => p.UnloadPlugin());
diff --git a/lib/Plugins.Runtime/src/RuntimePluginLoader.cs b/lib/Plugins.Runtime/src/RuntimePluginLoader.cs
index 40cf5ed..60edf55 100644
--- a/lib/Plugins.Runtime/src/RuntimePluginLoader.cs
+++ b/lib/Plugins.Runtime/src/RuntimePluginLoader.cs
@@ -119,18 +119,19 @@ namespace VNLib.Plugins.Runtime
/// Manually reload the internal <see cref="IPluginAssemblyLoader"/>
/// which will reload the assembly and re-initialize the controller
/// </summary>
+ /// <param name="forceGc">A value that indicates if the current unload should cause a manual garbage collection</param>
/// <exception cref="AggregateException"></exception>
/// <exception cref="NotSupportedException"></exception>
- public void ReloadPlugins()
+ public void ReloadPlugins(bool forceGc)
{
//Not unloadable
- if (!Loader.Config.Unloadable)
+ if (!Config.Unloadable)
{
throw new NotSupportedException("The loading context is not unloadable, you may not dynamically reload plugins");
}
-
+
//All plugins must be unloaded first
- UnloadPlugins();
+ UnloadAll(forceGc);
//Reload the assembly and
InitializeController();
@@ -152,8 +153,9 @@ namespace VNLib.Plugins.Runtime
/// then attempts to unload the <see cref="IPluginAssemblyLoader"/> if dynamic unloading
/// is enabled, otherwise does nothing.
/// </summary>
+ /// <param name="forceGc">A value that indicates if the current unload should cause a manual garbage collection</param>
/// <exception cref="AggregateException"></exception>
- public void UnloadAll()
+ public void UnloadAll(bool forceGc)
{
UnloadPlugins();
@@ -162,6 +164,13 @@ namespace VNLib.Plugins.Runtime
{
Loader.Unload();
}
+
+ //Optionally wait for GC to finish
+ if (forceGc)
+ {
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ }
}
//Process unload events
diff --git a/lib/Plugins.Runtime/src/Services/PluginServiceExport.cs b/lib/Plugins.Runtime/src/Services/PluginServiceExport.cs
index 0053a70..acacbb6 100644
--- a/lib/Plugins.Runtime/src/Services/PluginServiceExport.cs
+++ b/lib/Plugins.Runtime/src/Services/PluginServiceExport.cs
@@ -29,21 +29,9 @@ namespace VNLib.Plugins.Runtime.Services
/// <summary>
/// An immutable wrapper for an exported service by an <see cref="IPlugin"/>
/// </summary>
- public readonly record struct PluginServiceExport
- {
- /// <summary>
- /// The exported service type
- /// </summary>
- public readonly Type ServiceType { get; init; }
+ /// <param name="Flags">The export flags</param>
+ /// <param name="Service">The exported service instance</param>
+ /// <param name="ServiceType">The exported service type</param>
+ public readonly record struct PluginServiceExport(Type ServiceType, object Service, ExportFlags Flags);
- /// <summary>
- /// The exported service instance
- /// </summary>
- public readonly object Service { get; init; }
-
- /// <summary>
- /// The export flags
- /// </summary>
- public readonly ExportFlags Flags { get; init; }
- }
}
diff --git a/lib/Utils.Cryptography/argon2/Taskfile.yaml b/lib/Utils.Cryptography/argon2/Taskfile.yaml
index 7fe5332..45ce96b 100644
--- a/lib/Utils.Cryptography/argon2/Taskfile.yaml
+++ b/lib/Utils.Cryptography/argon2/Taskfile.yaml
@@ -9,7 +9,6 @@
version: '3'
vars:
- MS_ARGS: '/p:Platform=x64 /p:RunAnalyzersDuringBuild=false /p:BuildInParallel=true /p:MultiProcessorCompilation=true'
PROJECT_NAME: 'Argon2'
MODULE_NAME: 'vnlib.core'
@@ -27,28 +26,10 @@ tasks:
cmds:
#init cmake build with greedy enabled
- cmake -B./build
+
+ - cmake --build build/ --config Debug
+ - cmake --build build/ --config Release
- #build the rpmalloc library in debug mode first
- - task: build-win
- - task: build-gnumake
-
- #build using msbuild for rpmalloc libraries for debug and release modes
- build-win:
- platforms: ['windows']
- internal: true
- cmds:
- #build solution in debug mode
- - cd build && msbuild {{.PROJECT_NAME}}.sln /p:Configuration=debug {{.BUILD_FLAGS}} {{.MS_ARGS}}
- #build in release
- - cd build && msbuild {{.PROJECT_NAME}}.sln /p:Configuration=release {{.BUILD_FLAGS}} {{.MS_ARGS}}
-
- #build using gnu make
- build-gnumake:
- platforms: ['linux']
- internal: true
- cmds:
- #build project with make
- - cd build && make
postbuild_success:
vars:
@@ -93,10 +74,9 @@ tasks:
- powershell -Command "Copy-Item -Path ./include/argon2.h -Destination '{{.TARGET}}/argon2.h'"
pack_source:
- dir: '{{.USER_WORKING_DIR}}'
cmds:
#just pack up current directory, excluding build, bin, and git directories
- - powershell -Command "tar --exclude build/* --exclude bin/* --exclude .git/* -czvf bin/src.tgz *"
+ - powershell -Command "tar --exclude build/* --exclude bin/* -czf bin/src.tgz ."
clean:
diff --git a/lib/Utils.Cryptography/monocypher/Taskfile.yaml b/lib/Utils.Cryptography/monocypher/Taskfile.yaml
index de4278f..8c9abd8 100644
--- a/lib/Utils.Cryptography/monocypher/Taskfile.yaml
+++ b/lib/Utils.Cryptography/monocypher/Taskfile.yaml
@@ -27,28 +27,8 @@ tasks:
cmds:
#init cmake build
- cmake -B./build
-
- #build the monocypher library in debug mode first
- - task: build-monocypher-win
- - task: build-monocypher-gnumake
-
- #build using msbuild for monocypher libraries for debug and release modes
- build-monocypher-win:
- platforms: ['windows']
- internal: true
- cmds:
- #build solution in debug mode
- - cd build && msbuild {{.PROJECT_NAME}}.sln /p:Configuration=debug {{.BUILD_FLAGS}} {{.MS_ARGS}}
- #build in release
- - cd build && msbuild {{.PROJECT_NAME}}.sln /p:Configuration=release {{.BUILD_FLAGS}} {{.MS_ARGS}}
-
- #build using gnu make
- build-monocypher-gnumake:
- platforms: ['linux']
- internal: true
- cmds:
- #build project with make
- - cd build && make
+ - cmake --build build/ --config Debug
+ - cmake --build build/ --config Release
postbuild_success:
vars:
@@ -96,7 +76,7 @@ tasks:
dir: '{{.USER_WORKING_DIR}}'
cmds:
#pack monocypher source code and create the archive
- - powershell -Command "tar --exclude build/* --exclude bin/* --exclude .git/* -czvf 'bin/src.tgz' ."
+ - powershell -Command "tar --exclude build/* --exclude bin/* --exclude .git/* -czf 'bin/src.tgz' ."
clean:
ignore_error: true
diff --git a/lib/Utils.Memory/NativeHeapApi/LICENSE b/lib/Utils.Memory/NativeHeapApi/LICENSE
index 2848520..eedae8e 100644
--- a/lib/Utils.Memory/NativeHeapApi/LICENSE
+++ b/lib/Utils.Memory/NativeHeapApi/LICENSE
@@ -1,227 +1,410 @@
-The software in this repository is licensed under the GNU GPL version 2.0 (or any later version).
+Copyright (c) 2024 Vaughn Nugent
-SPDX-License-Identifier: GPL-2.0-or-later
+Contact information
+ Name: Vaughn Nugent
+ Email: vnpublic[at]proton.me
+ Website: https://www.vaughnnugent.com
+
+The software in this repository is licensed under the GNU LGPL version 2.1 (or any later version).
+
+SPDX-License-Identifier: LGPL-2.1-or-later
License-Text:
-GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
- a) You must cause the modified files to carry prominent notices
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
+identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
+on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
+entire whole, and thus to each and every part regardless of who wrote
+it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
-collective works based on the Program.
+collective works based on the Library.
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
+distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
+the Library or works based on it.
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
+You are not responsible for enforcing compliance by third parties with
this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
+
+ 11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
+refrain entirely from distribution of the Library.
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
+integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
@@ -232,115 +415,58 @@ impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
- 8. If the distribution and/or use of the Program is restricted in
+ 12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
NO WARRANTY
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
END OF TERMS AND CONDITIONS
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- VNLib.Hashing.Portable is a compact .NET managed cryptographic operation
- utilities library.
- Copyright (C) 2022 Vaughn Nugent
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License. \ No newline at end of file
diff --git a/lib/Utils.Memory/NativeHeapApi/src/NativeHeapApi.h b/lib/Utils.Memory/NativeHeapApi/src/NativeHeapApi.h
index c5d07b2..6a994b2 100644
--- a/lib/Utils.Memory/NativeHeapApi/src/NativeHeapApi.h
+++ b/lib/Utils.Memory/NativeHeapApi/src/NativeHeapApi.h
@@ -1,21 +1,21 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: NativeHeapApi
* File: NativeHeapApi.h
*
-* NativeHeapApi is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published
-* by the Free Software Foundation, either version 2 of the License,
-* or (at your option) any later version.
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public License
+* as published by the Free Software Foundation; either version 2.1
+* of the License, or (at your option) any later version.
*
-* NativeHeapApi is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* General Public License for more details.
+* Lesser General Public License for more details.
*
-* You should have received a copy of the GNU General Public License
+* You should have received a copy of the GNU Lesser General Public License
* along with NativeHeapApi. If not, see http://www.gnu.org/licenses/.
*/
@@ -26,31 +26,35 @@
#ifndef NATIVE_HEAP_API
#define NATIVE_HEAP_API
-/*
-* Method calling convention for export
-*/
-#ifndef HEAP_METHOD_CC
- #ifdef WIN32
- #define HEAP_METHOD_CC __stdcall
- #else
- #define HEAP_METHOD_CC
- #endif // WIN32
-#endif // !HEAP_METHOD_CC
-
-/*
-* Decorator for exporting methods for dll usage
-*/
-#ifndef HEAP_METHOD_EXPORT
- #ifdef WIN32
- #define HEAP_METHOD_EXPORT __declspec(dllexport)
- #else
- #define HEAP_METHOD_EXPORT __attribute__((visibility("default")))
- #endif
-#endif // HEAP_METHOD_EXPORT!
-
-#ifdef WIN32
-typedef void* LPVOID;
-#endif // !WIN32
+#if defined(_MSC_VER) || defined(WIN32) || defined(_WIN32)
+ #define _P_IS_WINDOWS
+#endif
+
+//Set api export calling convention (allow used to override)
+#ifndef VNLIB_CC
+ #ifdef _P_IS_WINDOWS
+ //STD for importing to other languages such as .NET
+ #define VNLIB_CC __stdcall
+ #else
+ #define VNLIB_CC
+ #endif
+#endif // !NC_CC
+
+#ifndef VNLIB_EXPORT //Allow users to disable the export/impoty macro if using source code directly
+ #ifdef VNLIB_EXPORTING
+ #ifdef _P_IS_WINDOWS
+ #define VNLIB_HEAP_API __declspec(dllexport)
+ #else
+ #define VNLIB_HEAP_API __attribute__((visibility("default")))
+ #endif // _NC_IS_WINDOWS
+ #else
+ #ifdef _P_IS_WINDOWS
+ #define VNLIB_HEAP_API __declspec(dllimport)
+ #else
+ #define VNLIB_HEAP_API
+ #endif // _P_IS_WINDOWS
+ #endif // !VNLIB_EXPORTING
+#endif // !VNLIB_EXPORT
/// <summary>
/// Internal heap creation flags passed to the creation method by the library loader
@@ -80,6 +84,10 @@ typedef enum HeapCreationFlags
HEAP_CREATION_SUPPORTS_REALLOC = 0x08,
} HeapCreationFlags;
+#ifdef _P_IS_WINDOWS
+ typedef void* LPVOID;
+#endif // !WIN32
+
/// <summary>
/// The vnlib ERRNO type, integer/process dependent,
/// internally represented as a pointer
@@ -105,7 +113,7 @@ typedef struct UnmanagedHeapDescriptor
/// Gets the shared heap handle for the process/library
/// </summary>
/// <returns>A pointer to the shared heap</returns>
-HEAP_METHOD_EXPORT HeapHandle HEAP_METHOD_CC heapGetSharedHeapHandle(void);
+VNLIB_HEAP_API HeapHandle VNLIB_CC heapGetSharedHeapHandle(void);
/// <summary>
/// The heap creation method. You must set the flags->HeapPointer = your heap
@@ -113,13 +121,13 @@ HEAP_METHOD_EXPORT HeapHandle HEAP_METHOD_CC heapGetSharedHeapHandle(void);
/// </summary>
/// <param name="flags">Creation flags passed by the caller to create the heap. This structure will be initialized, and may be modified</param>
/// <returns>A boolean value that indicates the result of the operation</returns>
-HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapCreate(UnmanagedHeapDescriptor* flags);
+VNLIB_HEAP_API ERRNO VNLIB_CC heapCreate(UnmanagedHeapDescriptor* flags);
/// <summary>
/// Destroys a previously created heap
/// </summary>
/// <param name="heap">The pointer to your custom heap structure from heap creation</param>
-HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapDestroy(HeapHandle heap);
+VNLIB_HEAP_API ERRNO VNLIB_CC heapDestroy(HeapHandle heap);
/// <summary>
/// Allocates a block from the desired heap and returns a pointer
@@ -130,7 +138,7 @@ HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapDestroy(HeapHandle heap);
/// <param name="alignment">The alignment (or size) of each element in bytes</param>
/// <param name="zero">A flag to zero the block before returning the block</param>
/// <returns>A pointer to the allocated block</returns>
-HEAP_METHOD_EXPORT void* HEAP_METHOD_CC heapAlloc(HeapHandle heap, uint64_t elements, uint64_t alignment, int zero);
+VNLIB_HEAP_API void* VNLIB_CC heapAlloc(HeapHandle heap, uint64_t elements, uint64_t alignment, int zero);
/// <summary>
/// Reallocates a block on the desired heap and returns a pointer to the new block. If reallocation
@@ -143,7 +151,7 @@ HEAP_METHOD_EXPORT void* HEAP_METHOD_CC heapAlloc(HeapHandle heap, uint64_t elem
/// <param name="alignment">The element size or block alignment</param>
/// <param name="zero">A flag to zero the block (or the new size) before returning.</param>
/// <returns>A pointer to the reallocated block, or zero if the operation failed or is not supported</returns>
-HEAP_METHOD_EXPORT void* HEAP_METHOD_CC heapRealloc(HeapHandle heap, void* block, uint64_t elements, uint64_t alignment, int zero);
+VNLIB_HEAP_API void* VNLIB_CC heapRealloc(HeapHandle heap, void* block, uint64_t elements, uint64_t alignment, int zero);
/// <summary>
/// Frees a previously allocated block on the desired heap.
@@ -151,6 +159,6 @@ HEAP_METHOD_EXPORT void* HEAP_METHOD_CC heapRealloc(HeapHandle heap, void* block
/// <param name="heap">A pointer to your heap structure</param>
/// <param name="block">A pointer to the block to free</param>
/// <returns>A value that indicates the result of the operation, nonzero if success, 0 if a failure occurred </returns>
-HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapFree(HeapHandle heap, void* block);
+VNLIB_HEAP_API ERRNO VNLIB_CC heapFree(HeapHandle heap, void* block);
#endif // !NATIVE_HEAP_API \ No newline at end of file
diff --git a/lib/Utils.Memory/mimalloc/bin/mimalloc-redirect.dll b/lib/Utils.Memory/mimalloc/bin/mimalloc-redirect.dll
deleted file mode 100644
index a3a3591..0000000
--- a/lib/Utils.Memory/mimalloc/bin/mimalloc-redirect.dll
+++ /dev/null
Binary files differ
diff --git a/lib/Utils.Memory/mimalloc/bin/mimalloc-redirect.lib b/lib/Utils.Memory/mimalloc/bin/mimalloc-redirect.lib
deleted file mode 100644
index de128bb..0000000
--- a/lib/Utils.Memory/mimalloc/bin/mimalloc-redirect.lib
+++ /dev/null
Binary files differ
diff --git a/lib/Utils.Memory/mimalloc/bin/mimalloc-redirect32.dll b/lib/Utils.Memory/mimalloc/bin/mimalloc-redirect32.dll
deleted file mode 100644
index 522723e..0000000
--- a/lib/Utils.Memory/mimalloc/bin/mimalloc-redirect32.dll
+++ /dev/null
Binary files differ
diff --git a/lib/Utils.Memory/mimalloc/bin/mimalloc-redirect32.lib b/lib/Utils.Memory/mimalloc/bin/mimalloc-redirect32.lib
deleted file mode 100644
index 87f19b8..0000000
--- a/lib/Utils.Memory/mimalloc/bin/mimalloc-redirect32.lib
+++ /dev/null
Binary files differ
diff --git a/lib/Utils.Memory/mimalloc/bin/minject.exe b/lib/Utils.Memory/mimalloc/bin/minject.exe
deleted file mode 100644
index 625816f..0000000
--- a/lib/Utils.Memory/mimalloc/bin/minject.exe
+++ /dev/null
Binary files differ
diff --git a/lib/Utils.Memory/mimalloc/bin/minject32.exe b/lib/Utils.Memory/mimalloc/bin/minject32.exe
deleted file mode 100644
index 6857ad0..0000000
--- a/lib/Utils.Memory/mimalloc/bin/minject32.exe
+++ /dev/null
Binary files differ
diff --git a/lib/Utils.Memory/rpmalloc/malloc.c b/lib/Utils.Memory/rpmalloc/malloc.c
deleted file mode 100644
index ecd9330..0000000
--- a/lib/Utils.Memory/rpmalloc/malloc.c
+++ /dev/null
@@ -1,488 +0,0 @@
-/* malloc.c - Memory allocator - Public Domain - 2016 Mattias Jansson
- *
- * This library provides a cross-platform lock free thread caching malloc implementation in C11.
- * The latest source code is always available at
- *
- * https://github.com/mjansson/rpmalloc
- *
- * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
- *
- */
-
-//
-// This file provides overrides for the standard library malloc entry points for C and new/delete operators for C++
-// It also provides automatic initialization/finalization of process and threads
-//
-#if defined(__TINYC__)
-#include <sys/types.h>
-#endif
-
-#ifndef ARCH_64BIT
-# if defined(__LLP64__) || defined(__LP64__) || defined(_WIN64)
-# define ARCH_64BIT 1
-_Static_assert(sizeof(size_t) == 8, "Data type size mismatch");
-_Static_assert(sizeof(void*) == 8, "Data type size mismatch");
-# else
-# define ARCH_64BIT 0
-_Static_assert(sizeof(size_t) == 4, "Data type size mismatch");
-_Static_assert(sizeof(void*) == 4, "Data type size mismatch");
-# endif
-#endif
-
-#if (defined(__GNUC__) || defined(__clang__))
-#pragma GCC visibility push(default)
-#endif
-
-#define USE_IMPLEMENT 1
-#define USE_INTERPOSE 0
-#define USE_ALIAS 0
-
-#if defined(__APPLE__)
-#undef USE_INTERPOSE
-#define USE_INTERPOSE 1
-
-typedef struct interpose_t {
- void* new_func;
- void* orig_func;
-} interpose_t;
-
-#define MAC_INTERPOSE_PAIR(newf, oldf) { (void*)newf, (void*)oldf }
-#define MAC_INTERPOSE_SINGLE(newf, oldf) \
-__attribute__((used)) static const interpose_t macinterpose##newf##oldf \
-__attribute__ ((section("__DATA, __interpose"))) = MAC_INTERPOSE_PAIR(newf, oldf)
-
-#endif
-
-#if !defined(_WIN32) && !defined(__APPLE__)
-#undef USE_IMPLEMENT
-#undef USE_ALIAS
-#define USE_IMPLEMENT 0
-#define USE_ALIAS 1
-#endif
-
-#ifdef _MSC_VER
-#pragma warning (disable : 4100)
-#undef malloc
-#undef free
-#undef calloc
-#define RPMALLOC_RESTRICT __declspec(restrict)
-#else
-#define RPMALLOC_RESTRICT
-#endif
-
-#if ENABLE_OVERRIDE
-
-typedef struct rp_nothrow_t { int __dummy; } rp_nothrow_t;
-
-#if USE_IMPLEMENT
-
-extern inline RPMALLOC_RESTRICT void* RPMALLOC_CDECL malloc(size_t size) { return rpmalloc(size); }
-extern inline RPMALLOC_RESTRICT void* RPMALLOC_CDECL calloc(size_t count, size_t size) { return rpcalloc(count, size); }
-extern inline RPMALLOC_RESTRICT void* RPMALLOC_CDECL realloc(void* ptr, size_t size) { return rprealloc(ptr, size); }
-extern inline void* RPMALLOC_CDECL reallocf(void* ptr, size_t size) { return rprealloc(ptr, size); }
-extern inline void* RPMALLOC_CDECL aligned_alloc(size_t alignment, size_t size) { return rpaligned_alloc(alignment, size); }
-extern inline void* RPMALLOC_CDECL memalign(size_t alignment, size_t size) { return rpmemalign(alignment, size); }
-extern inline int RPMALLOC_CDECL posix_memalign(void** memptr, size_t alignment, size_t size) { return rpposix_memalign(memptr, alignment, size); }
-extern inline void RPMALLOC_CDECL free(void* ptr) { rpfree(ptr); }
-extern inline void RPMALLOC_CDECL cfree(void* ptr) { rpfree(ptr); }
-extern inline size_t RPMALLOC_CDECL malloc_usable_size(void* ptr) { return rpmalloc_usable_size(ptr); }
-extern inline size_t RPMALLOC_CDECL malloc_size(void* ptr) { return rpmalloc_usable_size(ptr); }
-
-#ifdef _WIN32
-// For Windows, #include <rpnew.h> in one source file to get the C++ operator overrides implemented in your module
-#else
-// Overload the C++ operators using the mangled names (https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling)
-// operators delete and delete[]
-#define RPDEFVIS __attribute__((visibility("default")))
-extern void _ZdlPv(void* p); void RPDEFVIS _ZdlPv(void* p) { rpfree(p); }
-extern void _ZdaPv(void* p); void RPDEFVIS _ZdaPv(void* p) { rpfree(p); }
-#if ARCH_64BIT
-// 64-bit operators new and new[], normal and aligned
-extern void* _Znwm(uint64_t size); void* RPDEFVIS _Znwm(uint64_t size) { return rpmalloc(size); }
-extern void* _Znam(uint64_t size); void* RPDEFVIS _Znam(uint64_t size) { return rpmalloc(size); }
-extern void* _Znwmm(uint64_t size, uint64_t align); void* RPDEFVIS _Znwmm(uint64_t size, uint64_t align) { return rpaligned_alloc(align, size); }
-extern void* _Znamm(uint64_t size, uint64_t align); void* RPDEFVIS _Znamm(uint64_t size, uint64_t align) { return rpaligned_alloc(align, size); }
-extern void* _ZnwmSt11align_val_t(uint64_t size, uint64_t align); void* RPDEFVIS _ZnwmSt11align_val_t(uint64_t size, uint64_t align) { return rpaligned_alloc(align, size); }
-extern void* _ZnamSt11align_val_t(uint64_t size, uint64_t align); void* RPDEFVIS _ZnamSt11align_val_t(uint64_t size, uint64_t align) { return rpaligned_alloc(align, size); }
-extern void* _ZnwmRKSt9nothrow_t(uint64_t size, rp_nothrow_t t); void* RPDEFVIS _ZnwmRKSt9nothrow_t(uint64_t size, rp_nothrow_t t) { (void)sizeof(t); return rpmalloc(size); }
-extern void* _ZnamRKSt9nothrow_t(uint64_t size, rp_nothrow_t t); void* RPDEFVIS _ZnamRKSt9nothrow_t(uint64_t size, rp_nothrow_t t) { (void)sizeof(t); return rpmalloc(size); }
-extern void* _ZnwmSt11align_val_tRKSt9nothrow_t(uint64_t size, uint64_t align, rp_nothrow_t t); void* RPDEFVIS _ZnwmSt11align_val_tRKSt9nothrow_t(uint64_t size, uint64_t align, rp_nothrow_t t) { (void)sizeof(t); return rpaligned_alloc(align, size); }
-extern void* _ZnamSt11align_val_tRKSt9nothrow_t(uint64_t size, uint64_t align, rp_nothrow_t t); void* RPDEFVIS _ZnamSt11align_val_tRKSt9nothrow_t(uint64_t size, uint64_t align, rp_nothrow_t t) { (void)sizeof(t); return rpaligned_alloc(align, size); }
-// 64-bit operators sized delete and delete[], normal and aligned
-extern void _ZdlPvm(void* p, uint64_t size); void RPDEFVIS _ZdlPvm(void* p, uint64_t size) { rpfree(p); (void)sizeof(size); }
-extern void _ZdaPvm(void* p, uint64_t size); void RPDEFVIS _ZdaPvm(void* p, uint64_t size) { rpfree(p); (void)sizeof(size); }
-extern void _ZdlPvSt11align_val_t(void* p, uint64_t align); void RPDEFVIS _ZdlPvSt11align_val_t(void* p, uint64_t align) { rpfree(p); (void)sizeof(align); }
-extern void _ZdaPvSt11align_val_t(void* p, uint64_t align); void RPDEFVIS _ZdaPvSt11align_val_t(void* p, uint64_t align) { rpfree(p); (void)sizeof(align); }
-extern void _ZdlPvmSt11align_val_t(void* p, uint64_t size, uint64_t align); void RPDEFVIS _ZdlPvmSt11align_val_t(void* p, uint64_t size, uint64_t align) { rpfree(p); (void)sizeof(size); (void)sizeof(align); }
-extern void _ZdaPvmSt11align_val_t(void* p, uint64_t size, uint64_t align); void RPDEFVIS _ZdaPvmSt11align_val_t(void* p, uint64_t size, uint64_t align) { rpfree(p); (void)sizeof(size); (void)sizeof(align); }
-#else
-// 32-bit operators new and new[], normal and aligned
-extern void* _Znwj(uint32_t size); void* RPDEFVIS _Znwj(uint32_t size) { return rpmalloc(size); }
-extern void* _Znaj(uint32_t size); void* RPDEFVIS _Znaj(uint32_t size) { return rpmalloc(size); }
-extern void* _Znwjj(uint32_t size, uint32_t align); void* RPDEFVIS _Znwjj(uint32_t size, uint32_t align) { return rpaligned_alloc(align, size); }
-extern void* _Znajj(uint32_t size, uint32_t align); void* RPDEFVIS _Znajj(uint32_t size, uint32_t align) { return rpaligned_alloc(align, size); }
-extern void* _ZnwjSt11align_val_t(size_t size, size_t align); void* RPDEFVIS _ZnwjSt11align_val_t(size_t size, size_t align) { return rpaligned_alloc(align, size); }
-extern void* _ZnajSt11align_val_t(size_t size, size_t align); void* RPDEFVIS _ZnajSt11align_val_t(size_t size, size_t align) { return rpaligned_alloc(align, size); }
-extern void* _ZnwjRKSt9nothrow_t(size_t size, rp_nothrow_t t); void* RPDEFVIS _ZnwjRKSt9nothrow_t(size_t size, rp_nothrow_t t) { (void)sizeof(t); return rpmalloc(size); }
-extern void* _ZnajRKSt9nothrow_t(size_t size, rp_nothrow_t t); void* RPDEFVIS _ZnajRKSt9nothrow_t(size_t size, rp_nothrow_t t) { (void)sizeof(t); return rpmalloc(size); }
-extern void* _ZnwjSt11align_val_tRKSt9nothrow_t(size_t size, size_t align, rp_nothrow_t t); void* RPDEFVIS _ZnwjSt11align_val_tRKSt9nothrow_t(size_t size, size_t align, rp_nothrow_t t) { (void)sizeof(t); return rpaligned_alloc(align, size); }
-extern void* _ZnajSt11align_val_tRKSt9nothrow_t(size_t size, size_t align, rp_nothrow_t t); void* RPDEFVIS _ZnajSt11align_val_tRKSt9nothrow_t(size_t size, size_t align, rp_nothrow_t t) { (void)sizeof(t); return rpaligned_alloc(align, size); }
-// 32-bit operators sized delete and delete[], normal and aligned
-extern void _ZdlPvj(void* p, uint64_t size); void RPDEFVIS _ZdlPvj(void* p, uint64_t size) { rpfree(p); (void)sizeof(size); }
-extern void _ZdaPvj(void* p, uint64_t size); void RPDEFVIS _ZdaPvj(void* p, uint64_t size) { rpfree(p); (void)sizeof(size); }
-extern void _ZdlPvSt11align_val_t(void* p, uint32_t align); void RPDEFVIS _ZdlPvSt11align_val_t(void* p, uint64_t a) { rpfree(p); (void)sizeof(align); }
-extern void _ZdaPvSt11align_val_t(void* p, uint32_t align); void RPDEFVIS _ZdaPvSt11align_val_t(void* p, uint64_t a) { rpfree(p); (void)sizeof(align); }
-extern void _ZdlPvjSt11align_val_t(void* p, uint32_t size, uint32_t align); void RPDEFVIS _ZdlPvjSt11align_val_t(void* p, uint64_t size, uint64_t align) { rpfree(p); (void)sizeof(size); (void)sizeof(a); }
-extern void _ZdaPvjSt11align_val_t(void* p, uint32_t size, uint32_t align); void RPDEFVIS _ZdaPvjSt11align_val_t(void* p, uint64_t size, uint64_t align) { rpfree(p); (void)sizeof(size); (void)sizeof(a); }
-#endif
-#endif
-#endif
-
-#if USE_INTERPOSE || USE_ALIAS
-
-static void* rpmalloc_nothrow(size_t size, rp_nothrow_t t) { (void)sizeof(t); return rpmalloc(size); }
-static void* rpaligned_alloc_reverse(size_t size, size_t align) { return rpaligned_alloc(align, size); }
-static void* rpaligned_alloc_reverse_nothrow(size_t size, size_t align, rp_nothrow_t t) { (void)sizeof(t); return rpaligned_alloc(align, size); }
-static void rpfree_size(void* p, size_t size) { (void)sizeof(size); rpfree(p); }
-static void rpfree_aligned(void* p, size_t align) { (void)sizeof(align); rpfree(p); }
-static void rpfree_size_aligned(void* p, size_t size, size_t align) { (void)sizeof(size); (void)sizeof(align); rpfree(p); }
-
-#endif
-
-#if USE_INTERPOSE
-
-__attribute__((used)) static const interpose_t macinterpose_malloc[]
-__attribute__ ((section("__DATA, __interpose"))) = {
- //new and new[]
- MAC_INTERPOSE_PAIR(rpmalloc, _Znwm),
- MAC_INTERPOSE_PAIR(rpmalloc, _Znam),
- MAC_INTERPOSE_PAIR(rpaligned_alloc_reverse, _Znwmm),
- MAC_INTERPOSE_PAIR(rpaligned_alloc_reverse, _Znamm),
- MAC_INTERPOSE_PAIR(rpmalloc_nothrow, _ZnwmRKSt9nothrow_t),
- MAC_INTERPOSE_PAIR(rpmalloc_nothrow, _ZnamRKSt9nothrow_t),
- MAC_INTERPOSE_PAIR(rpaligned_alloc_reverse, _ZnwmSt11align_val_t),
- MAC_INTERPOSE_PAIR(rpaligned_alloc_reverse, _ZnamSt11align_val_t),
- MAC_INTERPOSE_PAIR(rpaligned_alloc_reverse_nothrow, _ZnwmSt11align_val_tRKSt9nothrow_t),
- MAC_INTERPOSE_PAIR(rpaligned_alloc_reverse_nothrow, _ZnamSt11align_val_tRKSt9nothrow_t),
- //delete and delete[]
- MAC_INTERPOSE_PAIR(rpfree, _ZdlPv),
- MAC_INTERPOSE_PAIR(rpfree, _ZdaPv),
- MAC_INTERPOSE_PAIR(rpfree_size, _ZdlPvm),
- MAC_INTERPOSE_PAIR(rpfree_size, _ZdaPvm),
- MAC_INTERPOSE_PAIR(rpfree_aligned, _ZdlPvSt11align_val_t),
- MAC_INTERPOSE_PAIR(rpfree_aligned, _ZdaPvSt11align_val_t),
- MAC_INTERPOSE_PAIR(rpfree_size_aligned, _ZdlPvmSt11align_val_t),
- MAC_INTERPOSE_PAIR(rpfree_size_aligned, _ZdaPvmSt11align_val_t),
- //libc entry points
- MAC_INTERPOSE_PAIR(rpmalloc, malloc),
- MAC_INTERPOSE_PAIR(rpmalloc, calloc),
- MAC_INTERPOSE_PAIR(rprealloc, realloc),
- MAC_INTERPOSE_PAIR(rprealloc, reallocf),
-#if defined(__MAC_10_15) && __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_15
- MAC_INTERPOSE_PAIR(rpaligned_alloc, aligned_alloc),
-#endif
- MAC_INTERPOSE_PAIR(rpmemalign, memalign),
- MAC_INTERPOSE_PAIR(rpposix_memalign, posix_memalign),
- MAC_INTERPOSE_PAIR(rpfree, free),
- MAC_INTERPOSE_PAIR(rpfree, cfree),
- MAC_INTERPOSE_PAIR(rpmalloc_usable_size, malloc_usable_size),
- MAC_INTERPOSE_PAIR(rpmalloc_usable_size, malloc_size)
-};
-
-#endif
-
-#if USE_ALIAS
-
-#define RPALIAS(fn) __attribute__((alias(#fn), used, visibility("default")));
-
-// Alias the C++ operators using the mangled names (https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling)
-
-// operators delete and delete[]
-void _ZdlPv(void* p) RPALIAS(rpfree)
-void _ZdaPv(void* p) RPALIAS(rpfree)
-
-#if ARCH_64BIT
-// 64-bit operators new and new[], normal and aligned
-void* _Znwm(uint64_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(1) RPALIAS(rpmalloc)
-void* _Znam(uint64_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(1) RPALIAS(rpmalloc)
-void* _Znwmm(uint64_t size, uint64_t align) RPALIAS(rpaligned_alloc_reverse)
-void* _Znamm(uint64_t size, uint64_t align) RPALIAS(rpaligned_alloc_reverse)
-void* _ZnwmSt11align_val_t(size_t size, size_t align) RPALIAS(rpaligned_alloc_reverse)
-void* _ZnamSt11align_val_t(size_t size, size_t align) RPALIAS(rpaligned_alloc_reverse)
-void* _ZnwmRKSt9nothrow_t(size_t size, rp_nothrow_t t) RPALIAS(rpmalloc_nothrow)
-void* _ZnamRKSt9nothrow_t(size_t size, rp_nothrow_t t) RPALIAS(rpmalloc_nothrow)
-void* _ZnwmSt11align_val_tRKSt9nothrow_t(size_t size, size_t align, rp_nothrow_t t) RPALIAS(rpaligned_alloc_reverse_nothrow)
-void* _ZnamSt11align_val_tRKSt9nothrow_t(size_t size, size_t align, rp_nothrow_t t) RPALIAS(rpaligned_alloc_reverse_nothrow)
-// 64-bit operators delete and delete[], sized and aligned
-void _ZdlPvm(void* p, size_t n) RPALIAS(rpfree_size)
-void _ZdaPvm(void* p, size_t n) RPALIAS(rpfree_size)
-void _ZdlPvSt11align_val_t(void* p, size_t a) RPALIAS(rpfree_aligned)
-void _ZdaPvSt11align_val_t(void* p, size_t a) RPALIAS(rpfree_aligned)
-void _ZdlPvmSt11align_val_t(void* p, size_t n, size_t a) RPALIAS(rpfree_size_aligned)
-void _ZdaPvmSt11align_val_t(void* p, size_t n, size_t a) RPALIAS(rpfree_size_aligned)
-#else
-// 32-bit operators new and new[], normal and aligned
-void* _Znwj(uint32_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(1) RPALIAS(rpmalloc)
-void* _Znaj(uint32_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(1) RPALIAS(rpmalloc)
-void* _Znwjj(uint32_t size, uint32_t align) RPALIAS(rpaligned_alloc_reverse)
-void* _Znajj(uint32_t size, uint32_t align) RPALIAS(rpaligned_alloc_reverse)
-void* _ZnwjSt11align_val_t(size_t size, size_t align) RPALIAS(rpaligned_alloc_reverse)
-void* _ZnajSt11align_val_t(size_t size, size_t align) RPALIAS(rpaligned_alloc_reverse)
-void* _ZnwjRKSt9nothrow_t(size_t size, rp_nothrow_t t) RPALIAS(rpmalloc_nothrow)
-void* _ZnajRKSt9nothrow_t(size_t size, rp_nothrow_t t) RPALIAS(rpmalloc_nothrow)
-void* _ZnwjSt11align_val_tRKSt9nothrow_t(size_t size, size_t align, rp_nothrow_t t) RPALIAS(rpaligned_alloc_reverse_nothrow)
-void* _ZnajSt11align_val_tRKSt9nothrow_t(size_t size, size_t align, rp_nothrow_t t) RPALIAS(rpaligned_alloc_reverse_nothrow)
-// 32-bit operators delete and delete[], sized and aligned
-void _ZdlPvj(void* p, size_t n) RPALIAS(rpfree_size)
-void _ZdaPvj(void* p, size_t n) RPALIAS(rpfree_size)
-void _ZdlPvSt11align_val_t(void* p, size_t a) RPALIAS(rpfree_aligned)
-void _ZdaPvSt11align_val_t(void* p, size_t a) RPALIAS(rpfree_aligned)
-void _ZdlPvjSt11align_val_t(void* p, size_t n, size_t a) RPALIAS(rpfree_size_aligned)
-void _ZdaPvjSt11align_val_t(void* p, size_t n, size_t a) RPALIAS(rpfree_size_aligned)
-#endif
-
-void* malloc(size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(1) RPALIAS(rpmalloc)
-void* calloc(size_t count, size_t size) RPALIAS(rpcalloc)
-void* realloc(void* ptr, size_t size) RPALIAS(rprealloc)
-void* reallocf(void* ptr, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2) RPALIAS(rprealloc)
-void* aligned_alloc(size_t alignment, size_t size) RPALIAS(rpaligned_alloc)
-void* memalign(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2) RPALIAS(rpmemalign)
-int posix_memalign(void** memptr, size_t alignment, size_t size) RPALIAS(rpposix_memalign)
-void free(void* ptr) RPALIAS(rpfree)
-void cfree(void* ptr) RPALIAS(rpfree)
-#if defined(__ANDROID__) || defined(__FreeBSD__)
-size_t malloc_usable_size(const void* ptr) RPALIAS(rpmalloc_usable_size)
-#else
-size_t malloc_usable_size(void* ptr) RPALIAS(rpmalloc_usable_size)
-#endif
-size_t malloc_size(void* ptr) RPALIAS(rpmalloc_usable_size)
-
-#endif
-
-static inline size_t
-_rpmalloc_page_size(void) {
- return _memory_page_size;
-}
-
-extern void* RPMALLOC_CDECL
-reallocarray(void* ptr, size_t count, size_t size) {
- size_t total;
-#if ENABLE_VALIDATE_ARGS
-#ifdef _MSC_VER
- int err = SizeTMult(count, size, &total);
- if ((err != S_OK) || (total >= MAX_ALLOC_SIZE)) {
- errno = EINVAL;
- return 0;
- }
-#else
- int err = __builtin_umull_overflow(count, size, &total);
- if (err || (total >= MAX_ALLOC_SIZE)) {
- errno = EINVAL;
- return 0;
- }
-#endif
-#else
- total = count * size;
-#endif
- return realloc(ptr, total);
-}
-
-extern inline void* RPMALLOC_CDECL
-valloc(size_t size) {
- get_thread_heap();
- return rpaligned_alloc(_rpmalloc_page_size(), size);
-}
-
-extern inline void* RPMALLOC_CDECL
-pvalloc(size_t size) {
- get_thread_heap();
- const size_t page_size = _rpmalloc_page_size();
- const size_t aligned_size = ((size + page_size - 1) / page_size) * page_size;
-#if ENABLE_VALIDATE_ARGS
- if (aligned_size < size) {
- errno = EINVAL;
- return 0;
- }
-#endif
- return rpaligned_alloc(_rpmalloc_page_size(), aligned_size);
-}
-
-#endif // ENABLE_OVERRIDE
-
-#if ENABLE_PRELOAD
-
-#ifdef _WIN32
-
-#if defined(BUILD_DYNAMIC_LINK) && BUILD_DYNAMIC_LINK
-
-extern __declspec(dllexport) BOOL WINAPI
-DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved);
-
-extern __declspec(dllexport) BOOL WINAPI
-DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) {
- (void)sizeof(reserved);
- (void)sizeof(instance);
- if (reason == DLL_PROCESS_ATTACH)
- rpmalloc_initialize();
- else if (reason == DLL_PROCESS_DETACH)
- rpmalloc_finalize();
- else if (reason == DLL_THREAD_ATTACH)
- rpmalloc_thread_initialize();
- else if (reason == DLL_THREAD_DETACH)
- rpmalloc_thread_finalize(1);
- return TRUE;
-}
-
-//end BUILD_DYNAMIC_LINK
-#else
-
-extern void
-_global_rpmalloc_init(void) {
- rpmalloc_set_main_thread();
- rpmalloc_initialize();
-}
-
-#if defined(__clang__) || defined(__GNUC__)
-
-static void __attribute__((constructor))
-initializer(void) {
- _global_rpmalloc_init();
-}
-
-#elif defined(_MSC_VER)
-
-#pragma section(".CRT$XIB",read)
-__declspec(allocate(".CRT$XIB")) void (*_rpmalloc_module_init)(void) = _global_rpmalloc_init;
-#pragma comment(linker, "/include:_rpmalloc_module_init")
-
-#endif
-
-//end !BUILD_DYNAMIC_LINK
-#endif
-
-#else
-
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <unistd.h>
-
-extern void
-rpmalloc_set_main_thread(void);
-
-static pthread_key_t destructor_key;
-
-static void
-thread_destructor(void*);
-
-static void __attribute__((constructor))
-initializer(void) {
- rpmalloc_set_main_thread();
- rpmalloc_initialize();
- pthread_key_create(&destructor_key, thread_destructor);
-}
-
-static void __attribute__((destructor))
-finalizer(void) {
- rpmalloc_finalize();
-}
-
-typedef struct {
- void* (*real_start)(void*);
- void* real_arg;
-} thread_starter_arg;
-
-static void*
-thread_starter(void* argptr) {
- thread_starter_arg* arg = argptr;
- void* (*real_start)(void*) = arg->real_start;
- void* real_arg = arg->real_arg;
- rpmalloc_thread_initialize();
- rpfree(argptr);
- pthread_setspecific(destructor_key, (void*)1);
- return (*real_start)(real_arg);
-}
-
-static void
-thread_destructor(void* value) {
- (void)sizeof(value);
- rpmalloc_thread_finalize(1);
-}
-
-#ifdef __APPLE__
-
-static int
-pthread_create_proxy(pthread_t* thread,
- const pthread_attr_t* attr,
- void* (*start_routine)(void*),
- void* arg) {
- rpmalloc_initialize();
- thread_starter_arg* starter_arg = rpmalloc(sizeof(thread_starter_arg));
- starter_arg->real_start = start_routine;
- starter_arg->real_arg = arg;
- return pthread_create(thread, attr, thread_starter, starter_arg);
-}
-
-MAC_INTERPOSE_SINGLE(pthread_create_proxy, pthread_create);
-
-#else
-
-#include <dlfcn.h>
-
-int
-pthread_create(pthread_t* thread,
- const pthread_attr_t* attr,
- void* (*start_routine)(void*),
- void* arg) {
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \
- defined(__APPLE__) || defined(__HAIKU__)
- char fname[] = "pthread_create";
-#else
- char fname[] = "_pthread_create";
-#endif
- void* real_pthread_create = dlsym(RTLD_NEXT, fname);
- rpmalloc_thread_initialize();
- thread_starter_arg* starter_arg = rpmalloc(sizeof(thread_starter_arg));
- starter_arg->real_start = start_routine;
- starter_arg->real_arg = arg;
- return (*(int (*)(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*))real_pthread_create)(thread, attr, thread_starter, starter_arg);
-}
-
-#endif
-
-#endif
-
-#endif
-
-#if ENABLE_OVERRIDE
-
-#if defined(__GLIBC__) && defined(__linux__)
-
-void* __libc_malloc(size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(1) RPALIAS(rpmalloc)
-void* __libc_calloc(size_t count, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(1, 2) RPALIAS(rpcalloc)
-void* __libc_realloc(void* p, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2) RPALIAS(rprealloc)
-void __libc_free(void* p) RPALIAS(rpfree)
-void __libc_cfree(void* p) RPALIAS(rpfree)
-void* __libc_memalign(size_t align, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2) RPALIAS(rpmemalign)
-int __posix_memalign(void** p, size_t align, size_t size) RPALIAS(rpposix_memalign)
-
-extern void* __libc_valloc(size_t size);
-extern void* __libc_pvalloc(size_t size);
-
-void*
-__libc_valloc(size_t size) {
- return valloc(size);
-}
-
-void*
-__libc_pvalloc(size_t size) {
- return pvalloc(size);
-}
-
-#endif
-
-#endif
-
-#if (defined(__GNUC__) || defined(__clang__))
-#pragma GCC visibility pop
-#endif
diff --git a/lib/Utils.Memory/rpmalloc/rpnew.h b/lib/Utils.Memory/rpmalloc/rpnew.h
deleted file mode 100644
index 75d381a..0000000
--- a/lib/Utils.Memory/rpmalloc/rpnew.h
+++ /dev/null
@@ -1,111 +0,0 @@
-
-#ifdef __cplusplus
-
-#include <new>
-#include <rpmalloc.h>
-
-#ifndef __CRTDECL
-#define __CRTDECL
-#endif
-
-extern void __CRTDECL
-operator delete(void* p) noexcept {
- rpfree(p);
-}
-
-extern void __CRTDECL
-operator delete[](void* p) noexcept {
- rpfree(p);
-}
-
-extern void* __CRTDECL
-operator new(std::size_t size) noexcept(false) {
- return rpmalloc(size);
-}
-
-extern void* __CRTDECL
-operator new[](std::size_t size) noexcept(false) {
- return rpmalloc(size);
-}
-
-extern void* __CRTDECL
-operator new(std::size_t size, const std::nothrow_t& tag) noexcept {
- (void)sizeof(tag);
- return rpmalloc(size);
-}
-
-extern void* __CRTDECL
-operator new[](std::size_t size, const std::nothrow_t& tag) noexcept {
- (void)sizeof(tag);
- return rpmalloc(size);
-}
-
-#if (__cplusplus >= 201402L || _MSC_VER >= 1916)
-
-extern void __CRTDECL
-operator delete(void* p, std::size_t size) noexcept {
- (void)sizeof(size);
- rpfree(p);
-}
-
-extern void __CRTDECL
-operator delete[](void* p, std::size_t size) noexcept {
- (void)sizeof(size);
- rpfree(p);
-}
-
-#endif
-
-#if (__cplusplus > 201402L || defined(__cpp_aligned_new))
-
-extern void __CRTDECL
-operator delete(void* p, std::align_val_t align) noexcept {
- (void)sizeof(align);
- rpfree(p);
-}
-
-extern void __CRTDECL
-operator delete[](void* p, std::align_val_t align) noexcept {
- (void)sizeof(align);
- rpfree(p);
-}
-
-extern void __CRTDECL
-operator delete(void* p, std::size_t size, std::align_val_t align) noexcept {
- (void)sizeof(size);
- (void)sizeof(align);
- rpfree(p);
-}
-
-extern void __CRTDECL
-operator delete[](void* p, std::size_t size, std::align_val_t align) noexcept {
- (void)sizeof(size);
- (void)sizeof(align);
- rpfree(p);
-}
-
-extern void* __CRTDECL
-operator new(std::size_t size, std::align_val_t align) noexcept(false) {
- return rpaligned_alloc(static_cast<size_t>(align), size);
-}
-
-extern void* __CRTDECL
-operator new[](std::size_t size, std::align_val_t align) noexcept(false) {
- return rpaligned_alloc(static_cast<size_t>(align), size);
-}
-
-extern void* __CRTDECL
-operator new(std::size_t size, std::align_val_t align, const std::nothrow_t& tag) noexcept {
- (void)sizeof(tag);
- return rpaligned_alloc(static_cast<size_t>(align), size);
-}
-
-extern void* __CRTDECL
-operator new[](std::size_t size, std::align_val_t align, const std::nothrow_t& tag) noexcept {
- (void)sizeof(tag);
- return rpaligned_alloc(static_cast<size_t>(align), size);
-}
-
-#endif
-
-#endif
diff --git a/lib/Utils.Memory/vnlib_mimalloc/CMakeLists.txt b/lib/Utils.Memory/vnlib_mimalloc/CMakeLists.txt
index 20383fb..f1ef4b9 100644
--- a/lib/Utils.Memory/vnlib_mimalloc/CMakeLists.txt
+++ b/lib/Utils.Memory/vnlib_mimalloc/CMakeLists.txt
@@ -8,9 +8,6 @@ file(GLOB HEADERS *.h)
#Add indepednent source files to the project
file(GLOB VNLIB_MIMALLOC_SOURCES *.c)
-#add heapapi includes
-include_directories(../NativeHeapApi/src)
-
#set options for greedy allocator defaults
option(ENABLE_GREEDY "Enable greedy allocator configuration" ON)
@@ -104,19 +101,19 @@ elseif(CMAKE_COMPILER_IS_GNUCC)
endif()
#include mimalloc headers
-include_directories(../mimalloc/include)
+include_directories(vendor/include)
if(MSVC)
#find the mimalloc static library for windows builds
find_library(VNLIB_MIMALLOC_DEBUG_LIB
NAMES mimalloc-static
- PATHS ../mimalloc/build/Debug
+ PATHS vendor/build/Debug
)
find_library(VNLIB_MIMALLOC_RELEASE_LIB
NAMES mimalloc-static
- PATHS ../mimalloc/build/Release
+ PATHS vendor/build/Release
)
#target static libraries for all configs
@@ -133,7 +130,7 @@ elseif(UNIX)
#find the mimalloc library for unix builds
find_library(VNLIB_MIMALLOC_LIB
NAMES mimalloc
- PATHS ../mimalloc/build
+ PATHS vendor/build
)
#add the mimalloc library to the project
diff --git a/lib/Utils.Memory/vnlib_mimalloc/LICENSE b/lib/Utils.Memory/vnlib_mimalloc/LICENSE
index ce09686..eedae8e 100644
--- a/lib/Utils.Memory/vnlib_mimalloc/LICENSE
+++ b/lib/Utils.Memory/vnlib_mimalloc/LICENSE
@@ -1,234 +1,410 @@
-Copyright (c) 2023 Vaughn Nugent
+Copyright (c) 2024 Vaughn Nugent
Contact information
Name: Vaughn Nugent
Email: vnpublic[at]proton.me
Website: https://www.vaughnnugent.com
-The software in this repository is licensed under the GNU GPL version 2.0 (or any later version).
+The software in this repository is licensed under the GNU LGPL version 2.1 (or any later version).
-SPDX-License-Identifier: GPL-2.0-or-later
+SPDX-License-Identifier: LGPL-2.1-or-later
License-Text:
-GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
- a) You must cause the modified files to carry prominent notices
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
+identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
+on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
+entire whole, and thus to each and every part regardless of who wrote
+it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
-collective works based on the Program.
+collective works based on the Library.
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
+distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
+the Library or works based on it.
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
+You are not responsible for enforcing compliance by third parties with
this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
+
+ 11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
+refrain entirely from distribution of the Library.
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
+integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
@@ -239,55 +415,58 @@ impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
- 8. If the distribution and/or use of the Program is restricted in
+ 12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
NO WARRANTY
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS \ No newline at end of file
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/lib/Utils.Memory/vnlib_mimalloc/NativeHeapApi.h b/lib/Utils.Memory/vnlib_mimalloc/NativeHeapApi.h
new file mode 100644
index 0000000..6a994b2
--- /dev/null
+++ b/lib/Utils.Memory/vnlib_mimalloc/NativeHeapApi.h
@@ -0,0 +1,164 @@
+/*
+* Copyright (c) 2024 Vaughn Nugent
+*
+* Library: VNLib
+* Package: NativeHeapApi
+* File: NativeHeapApi.h
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public License
+* as published by the Free Software Foundation; either version 2.1
+* of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with NativeHeapApi. If not, see http://www.gnu.org/licenses/.
+*/
+
+#pragma once
+
+#include <stdint.h>
+
+#ifndef NATIVE_HEAP_API
+#define NATIVE_HEAP_API
+
+#if defined(_MSC_VER) || defined(WIN32) || defined(_WIN32)
+ #define _P_IS_WINDOWS
+#endif
+
+//Set api export calling convention (allow used to override)
+#ifndef VNLIB_CC
+ #ifdef _P_IS_WINDOWS
+ //STD for importing to other languages such as .NET
+ #define VNLIB_CC __stdcall
+ #else
+ #define VNLIB_CC
+ #endif
+#endif // !NC_CC
+
+#ifndef VNLIB_EXPORT //Allow users to disable the export/impoty macro if using source code directly
+ #ifdef VNLIB_EXPORTING
+ #ifdef _P_IS_WINDOWS
+ #define VNLIB_HEAP_API __declspec(dllexport)
+ #else
+ #define VNLIB_HEAP_API __attribute__((visibility("default")))
+ #endif // _NC_IS_WINDOWS
+ #else
+ #ifdef _P_IS_WINDOWS
+ #define VNLIB_HEAP_API __declspec(dllimport)
+ #else
+ #define VNLIB_HEAP_API
+ #endif // _P_IS_WINDOWS
+ #endif // !VNLIB_EXPORTING
+#endif // !VNLIB_EXPORT
+
+/// <summary>
+/// Internal heap creation flags passed to the creation method by the library loader
+/// </summary>
+typedef enum HeapCreationFlags
+{
+ /// <summary>
+ /// Default/no flags
+ /// </summary>
+ HEAP_CREATION_NO_FLAGS,
+ /// <summary>
+ /// Specifies that all allocations be zeroed before returning to caller
+ /// </summary>
+ HEAP_CREATION_GLOBAL_ZERO = 0x01,
+ /// <summary>
+ /// Specifies that the heap should use internal locking, aka its not thread safe
+ /// and needs to be made thread safe
+ /// </summary>
+ HEAP_CREATION_SERIALZE_ENABLED = 0x02,
+ /// <summary>
+ /// Specifies that the requested heap will be a shared heap for the process/library
+ /// </summary>
+ HEAP_CREATION_IS_SHARED = 0x04,
+ /// <summary>
+ /// Specifies that the heap will support block reallocation
+ /// </summary>
+ HEAP_CREATION_SUPPORTS_REALLOC = 0x08,
+} HeapCreationFlags;
+
+#ifdef _P_IS_WINDOWS
+ typedef void* LPVOID;
+#endif // !WIN32
+
+/// <summary>
+/// The vnlib ERRNO type, integer/process dependent,
+/// internally represented as a pointer
+/// </summary>
+typedef void* ERRNO;
+
+/// <summary>
+/// A pointer to a heap structure that was stored during heap creation
+/// </summary>
+typedef void* HeapHandle;
+
+/// <summary>
+/// A structure for heap initialization
+/// </summary>
+typedef struct UnmanagedHeapDescriptor
+{
+ HeapHandle HeapPointer;
+ ERRNO Flags;
+ HeapCreationFlags CreationFlags;
+} UnmanagedHeapDescriptor;
+
+/// <summary>
+/// Gets the shared heap handle for the process/library
+/// </summary>
+/// <returns>A pointer to the shared heap</returns>
+VNLIB_HEAP_API HeapHandle VNLIB_CC heapGetSharedHeapHandle(void);
+
+/// <summary>
+/// The heap creation method. You must set the flags->HeapPointer = your heap
+/// structure
+/// </summary>
+/// <param name="flags">Creation flags passed by the caller to create the heap. This structure will be initialized, and may be modified</param>
+/// <returns>A boolean value that indicates the result of the operation</returns>
+VNLIB_HEAP_API ERRNO VNLIB_CC heapCreate(UnmanagedHeapDescriptor* flags);
+
+/// <summary>
+/// Destroys a previously created heap
+/// </summary>
+/// <param name="heap">The pointer to your custom heap structure from heap creation</param>
+VNLIB_HEAP_API ERRNO VNLIB_CC heapDestroy(HeapHandle heap);
+
+/// <summary>
+/// Allocates a block from the desired heap and returns a pointer
+/// to the block. Optionally zeros the block before returning
+/// </summary>
+/// <param name="heap">A pointer to your heap structure</param>
+/// <param name="elements">The number of elements to allocate</param>
+/// <param name="alignment">The alignment (or size) of each element in bytes</param>
+/// <param name="zero">A flag to zero the block before returning the block</param>
+/// <returns>A pointer to the allocated block</returns>
+VNLIB_HEAP_API void* VNLIB_CC heapAlloc(HeapHandle heap, uint64_t elements, uint64_t alignment, int zero);
+
+/// <summary>
+/// Reallocates a block on the desired heap and returns a pointer to the new block. If reallocation
+/// is not supported, you should only return 0 and leave the block unmodified. The data in the valid
+/// size of the block MUST remain unmodified.
+/// </summary>
+/// <param name="heap">A pointer to your heap structure</param>
+/// <param name="block">A pointer to the block to reallocate</param>
+/// <param name="elements">The new size of the block, in elements</param>
+/// <param name="alignment">The element size or block alignment</param>
+/// <param name="zero">A flag to zero the block (or the new size) before returning.</param>
+/// <returns>A pointer to the reallocated block, or zero if the operation failed or is not supported</returns>
+VNLIB_HEAP_API void* VNLIB_CC heapRealloc(HeapHandle heap, void* block, uint64_t elements, uint64_t alignment, int zero);
+
+/// <summary>
+/// Frees a previously allocated block on the desired heap.
+/// </summary>
+/// <param name="heap">A pointer to your heap structure</param>
+/// <param name="block">A pointer to the block to free</param>
+/// <returns>A value that indicates the result of the operation, nonzero if success, 0 if a failure occurred </returns>
+VNLIB_HEAP_API ERRNO VNLIB_CC heapFree(HeapHandle heap, void* block);
+
+#endif // !NATIVE_HEAP_API \ No newline at end of file
diff --git a/lib/Utils.Memory/vnlib_mimalloc/Taskfile.yaml b/lib/Utils.Memory/vnlib_mimalloc/Taskfile.yaml
index e1e0da5..30df868 100644
--- a/lib/Utils.Memory/vnlib_mimalloc/Taskfile.yaml
+++ b/lib/Utils.Memory/vnlib_mimalloc/Taskfile.yaml
@@ -9,7 +9,6 @@
version: '3'
vars:
- MS_ARGS: '/p:Platform=x64 /p:RunAnalyzersDuringBuild=false /p:BuildInParallel=true /p:MultiProcessorCompilation=true'
PROJECT_NAME: 'vnlib_mimalloc'
MODULE_NAME: 'vnlib.core'
@@ -26,41 +25,15 @@ tasks:
build:
cmds:
#build the mimalloc library first
- - cd ../mimalloc && cmake -B./build -DMI_BUILD_STATIC=1
-
- #build the mimalloc library in debug mode first
- - task: build-mimalloc-win
- - task: build-mimalloc-gnumake
-
-
- #build using msbuild for mimalloc libraries for debug and release modes
- build-mimalloc-win:
- platforms: ['windows']
- internal: true
- cmds:
- - cd ../mimalloc/build && msbuild libmimalloc.sln /p:Configuration=debug {{.BUILD_FLAGS}} {{.MS_ARGS}}
- - cd ../mimalloc/build && msbuild libmimalloc.sln /p:Configuration=release {{.BUILD_FLAGS}} {{.MS_ARGS}}
-
- #init cmake build with greedy enabled
- - cmake -B./build -DENABLE_GREEDY=1 {{.MIMALLOC_CMAKE_ARGS}}
-
- #build solution in debug mode
- - cd build && msbuild {{.PROJECT_NAME}}.sln /p:Configuration=debug {{.BUILD_FLAGS}} {{.MS_ARGS}}
- #build in release
- - cd build && msbuild {{.PROJECT_NAME}}.sln /p:Configuration=release {{.BUILD_FLAGS}} {{.MS_ARGS}}
-
- #build using gnu make
- build-mimalloc-gnumake:
- platforms: ['linux']
- internal: true
- cmds:
- - cd ../mimalloc/build && make
-
- #init cmake build with greedy enabled
- - cmake -B./build -DENABLE_GREEDY=1
- #build project with make
- - cd build && make
+ - cd vendor/ && cmake -B./build -DMI_BUILD_STATIC=1 {{.MIMALLOC_CMAKE_ARGS}} -DMI_BUILD_TESTS=0 -DMI_OVERRIDE=0 -DMI_WIN_REDIRECT=0
+ - cd vendor/ && cmake --build build/ --config Debug
+ - cd vendor/ && cmake --build build/ --config Release
+ #build our library
+ - cmake -B./build -DENABLE_GREEDY=1 {{.CMAKE_ARGS}}
+ - cmake --build build/ --config Debug
+ - cmake --build build/ --config Release
+
postbuild_success:
vars:
#required files to include in tar
@@ -93,7 +66,7 @@ tasks:
licenses:
cmds:
#add mimalloc license to binary output
- - powershell -Command "Copy-Item -Path ../mimalloc/license -Destination '{{.TARGET}}/mimalloc_license.txt'"
+ - powershell -Command "Copy-Item -Path vendor/license -Destination '{{.TARGET}}/mimalloc_license.txt'"
#add my license file
- powershell -Command "Copy-Item -Path ./license -Destination '{{.TARGET}}/license.txt'"
#add readme file
@@ -103,17 +76,7 @@ tasks:
dir: '{{.USER_WORKING_DIR}}'
cmds:
#pack mimalloc source code and create the archive
- - cd .. && powershell -Command "tar --exclude */build/* --exclude */.git/* -cvf 'vnlib_mimalloc/bin/src.tar' ./mimalloc/*"
- #append the nativeheapapi directory
- - cd .. && powershell -Command "tar -rvf vnlib_mimalloc/bin/src.tar ./NativeHeapApi/*"
- #append the current directory
- - cd .. && powershell -Command "tar --exclude */build/* --exclude */bin/* -rvf vnlib_mimalloc/bin/src.tar ./vnlib_mimalloc/*"
- #use tar to gzip the archive
- - cd bin && tar -czvf src.tgz src.tar
- # delete the tar archive
- - cmd: powershell -Command "Remove-Item bin/src.tar -Force"
- ignore_error: true
-
+ - powershell -Command "tar --exclude build/* --exclude bin/* --exclude vendor/docs/ --exclude vendor/doc/ --exclude vendor/test/ --exclude vendor/ide/ --exclude vendor/out/ -czf 'bin/src.tgz' ."
clean:
ignore_error: true
diff --git a/lib/Utils.Memory/mimalloc/.gitattributes b/lib/Utils.Memory/vnlib_mimalloc/vendor/.gitattributes
index 0332e03..0332e03 100644
--- a/lib/Utils.Memory/mimalloc/.gitattributes
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/.gitattributes
diff --git a/lib/Utils.Memory/mimalloc/.gitignore b/lib/Utils.Memory/vnlib_mimalloc/vendor/.gitignore
index f8b7f5e..f8b7f5e 100644
--- a/lib/Utils.Memory/mimalloc/.gitignore
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/.gitignore
diff --git a/lib/Utils.Memory/mimalloc/CMakeLists.txt b/lib/Utils.Memory/vnlib_mimalloc/vendor/CMakeLists.txt
index 2bcd1ef..2bcd1ef 100644
--- a/lib/Utils.Memory/mimalloc/CMakeLists.txt
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/CMakeLists.txt
diff --git a/lib/Utils.Memory/mimalloc/LICENSE b/lib/Utils.Memory/vnlib_mimalloc/vendor/LICENSE
index 670b668..670b668 100644
--- a/lib/Utils.Memory/mimalloc/LICENSE
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/LICENSE
diff --git a/lib/Utils.Memory/mimalloc/SECURITY.md b/lib/Utils.Memory/vnlib_mimalloc/vendor/SECURITY.md
index e138ec5..e138ec5 100644
--- a/lib/Utils.Memory/mimalloc/SECURITY.md
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/SECURITY.md
diff --git a/lib/Utils.Memory/mimalloc/azure-pipelines.yml b/lib/Utils.Memory/vnlib_mimalloc/vendor/azure-pipelines.yml
index 0247c76..0247c76 100644
--- a/lib/Utils.Memory/mimalloc/azure-pipelines.yml
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/azure-pipelines.yml
diff --git a/lib/Utils.Memory/mimalloc/cmake/JoinPaths.cmake b/lib/Utils.Memory/vnlib_mimalloc/vendor/cmake/JoinPaths.cmake
index c68d91b..c68d91b 100644
--- a/lib/Utils.Memory/mimalloc/cmake/JoinPaths.cmake
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/cmake/JoinPaths.cmake
diff --git a/lib/Utils.Memory/mimalloc/cmake/mimalloc-config-version.cmake b/lib/Utils.Memory/vnlib_mimalloc/vendor/cmake/mimalloc-config-version.cmake
index a44c121..a44c121 100644
--- a/lib/Utils.Memory/mimalloc/cmake/mimalloc-config-version.cmake
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/cmake/mimalloc-config-version.cmake
diff --git a/lib/Utils.Memory/mimalloc/cmake/mimalloc-config.cmake b/lib/Utils.Memory/vnlib_mimalloc/vendor/cmake/mimalloc-config.cmake
index a49b02a..a49b02a 100644
--- a/lib/Utils.Memory/mimalloc/cmake/mimalloc-config.cmake
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/cmake/mimalloc-config.cmake
diff --git a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-c5-18xlarge-2020-01-20-a.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-c5-18xlarge-2020-01-20-a.svg
index 9005097..9005097 100644
--- a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-c5-18xlarge-2020-01-20-a.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-c5-18xlarge-2020-01-20-a.svg
diff --git a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-c5-18xlarge-2020-01-20-b.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-c5-18xlarge-2020-01-20-b.svg
index 2d853ed..2d853ed 100644
--- a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-c5-18xlarge-2020-01-20-b.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-c5-18xlarge-2020-01-20-b.svg
diff --git a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-c5-18xlarge-2020-01-20-rss-a.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-c5-18xlarge-2020-01-20-rss-a.svg
index 393bfad..393bfad 100644
--- a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-c5-18xlarge-2020-01-20-rss-a.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-c5-18xlarge-2020-01-20-rss-a.svg
diff --git a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-c5-18xlarge-2020-01-20-rss-b.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-c5-18xlarge-2020-01-20-rss-b.svg
index 419dc25..419dc25 100644
--- a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-c5-18xlarge-2020-01-20-rss-b.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-c5-18xlarge-2020-01-20-rss-b.svg
diff --git a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-r5a-1.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-r5a-1.svg
index c296a04..c296a04 100644
--- a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-r5a-1.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-r5a-1.svg
diff --git a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-r5a-12xlarge-2020-01-16-a.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-r5a-12xlarge-2020-01-16-a.svg
index b8a2f20..b8a2f20 100644
--- a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-r5a-12xlarge-2020-01-16-a.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-r5a-12xlarge-2020-01-16-a.svg
diff --git a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-r5a-12xlarge-2020-01-16-b.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-r5a-12xlarge-2020-01-16-b.svg
index 4a7e21e..4a7e21e 100644
--- a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-r5a-12xlarge-2020-01-16-b.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-r5a-12xlarge-2020-01-16-b.svg
diff --git a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-r5a-2.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-r5a-2.svg
index 917ea57..917ea57 100644
--- a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-r5a-2.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-r5a-2.svg
diff --git a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-r5a-rss-1.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-r5a-rss-1.svg
index 375ebd2..375ebd2 100644
--- a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-r5a-rss-1.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-r5a-rss-1.svg
diff --git a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-r5a-rss-2.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-r5a-rss-2.svg
index cb2bbc8..cb2bbc8 100644
--- a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-r5a-rss-2.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-r5a-rss-2.svg
diff --git a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-spec-rss.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-spec-rss.svg
index 2c93616..2c93616 100644
--- a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-spec-rss.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-spec-rss.svg
diff --git a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-spec.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-spec.svg
index af2b41b..af2b41b 100644
--- a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-spec.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-spec.svg
diff --git a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-z4-1.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-z4-1.svg
index dacd8ab..dacd8ab 100644
--- a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-z4-1.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-z4-1.svg
diff --git a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-z4-2.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-z4-2.svg
index 9990cdc..9990cdc 100644
--- a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-z4-2.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-z4-2.svg
diff --git a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-z4-rss-1.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-z4-rss-1.svg
index 891f7d6..891f7d6 100644
--- a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-z4-rss-1.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-z4-rss-1.svg
diff --git a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-z4-rss-2.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-z4-rss-2.svg
index f426537..f426537 100644
--- a/lib/Utils.Memory/mimalloc/doc/bench-2020/bench-z4-rss-2.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2020/bench-z4-rss-2.svg
diff --git a/lib/Utils.Memory/mimalloc/doc/bench-2021/bench-amd5950x-2021-01-30-a.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2021/bench-amd5950x-2021-01-30-a.svg
index 86a97bf..86a97bf 100644
--- a/lib/Utils.Memory/mimalloc/doc/bench-2021/bench-amd5950x-2021-01-30-a.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2021/bench-amd5950x-2021-01-30-a.svg
diff --git a/lib/Utils.Memory/mimalloc/doc/bench-2021/bench-amd5950x-2021-01-30-b.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2021/bench-amd5950x-2021-01-30-b.svg
index c748877..c748877 100644
--- a/lib/Utils.Memory/mimalloc/doc/bench-2021/bench-amd5950x-2021-01-30-b.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2021/bench-amd5950x-2021-01-30-b.svg
diff --git a/lib/Utils.Memory/mimalloc/doc/bench-2021/bench-c5-18xlarge-2021-01-30-a.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2021/bench-c5-18xlarge-2021-01-30-a.svg
index bc91c21..bc91c21 100644
--- a/lib/Utils.Memory/mimalloc/doc/bench-2021/bench-c5-18xlarge-2021-01-30-a.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2021/bench-c5-18xlarge-2021-01-30-a.svg
diff --git a/lib/Utils.Memory/mimalloc/doc/bench-2021/bench-c5-18xlarge-2021-01-30-b.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2021/bench-c5-18xlarge-2021-01-30-b.svg
index e8b04a0..e8b04a0 100644
--- a/lib/Utils.Memory/mimalloc/doc/bench-2021/bench-c5-18xlarge-2021-01-30-b.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2021/bench-c5-18xlarge-2021-01-30-b.svg
diff --git a/lib/Utils.Memory/mimalloc/doc/bench-2021/bench-c5-18xlarge-2021-01-30-rss-a.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2021/bench-c5-18xlarge-2021-01-30-rss-a.svg
index 6cd36aa..6cd36aa 100644
--- a/lib/Utils.Memory/mimalloc/doc/bench-2021/bench-c5-18xlarge-2021-01-30-rss-a.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2021/bench-c5-18xlarge-2021-01-30-rss-a.svg
diff --git a/lib/Utils.Memory/mimalloc/doc/bench-2021/bench-c5-18xlarge-2021-01-30-rss-b.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2021/bench-c5-18xlarge-2021-01-30-rss-b.svg
index c81072e..c81072e 100644
--- a/lib/Utils.Memory/mimalloc/doc/bench-2021/bench-c5-18xlarge-2021-01-30-rss-b.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2021/bench-c5-18xlarge-2021-01-30-rss-b.svg
diff --git a/lib/Utils.Memory/mimalloc/doc/bench-2021/bench-macmini-2021-01-30.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2021/bench-macmini-2021-01-30.svg
index ece6418..ece6418 100644
--- a/lib/Utils.Memory/mimalloc/doc/bench-2021/bench-macmini-2021-01-30.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/bench-2021/bench-macmini-2021-01-30.svg
diff --git a/lib/Utils.Memory/mimalloc/doc/doxyfile b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/doxyfile
index 55cae8b..55cae8b 100644
--- a/lib/Utils.Memory/mimalloc/doc/doxyfile
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/doxyfile
diff --git a/lib/Utils.Memory/mimalloc/doc/ds-logo.jpg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/ds-logo.jpg
index c9abb1a..c9abb1a 100644
--- a/lib/Utils.Memory/mimalloc/doc/ds-logo.jpg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/ds-logo.jpg
Binary files differ
diff --git a/lib/Utils.Memory/mimalloc/doc/ds-logo.png b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/ds-logo.png
index 93b84e4..93b84e4 100644
--- a/lib/Utils.Memory/mimalloc/doc/ds-logo.png
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/ds-logo.png
Binary files differ
diff --git a/lib/Utils.Memory/mimalloc/doc/mimalloc-doc.h b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/mimalloc-doc.h
index 3e75243..3e75243 100644
--- a/lib/Utils.Memory/mimalloc/doc/mimalloc-doc.h
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/mimalloc-doc.h
diff --git a/lib/Utils.Memory/mimalloc/doc/mimalloc-doxygen.css b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/mimalloc-doxygen.css
index b24f564..b24f564 100644
--- a/lib/Utils.Memory/mimalloc/doc/mimalloc-doxygen.css
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/mimalloc-doxygen.css
diff --git a/lib/Utils.Memory/mimalloc/doc/mimalloc-logo-100.png b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/mimalloc-logo-100.png
index 96f0825..96f0825 100644
--- a/lib/Utils.Memory/mimalloc/doc/mimalloc-logo-100.png
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/mimalloc-logo-100.png
Binary files differ
diff --git a/lib/Utils.Memory/mimalloc/doc/mimalloc-logo.png b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/mimalloc-logo.png
index e0a5a8c..e0a5a8c 100644
--- a/lib/Utils.Memory/mimalloc/doc/mimalloc-logo.png
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/mimalloc-logo.png
Binary files differ
diff --git a/lib/Utils.Memory/mimalloc/doc/mimalloc-logo.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/mimalloc-logo.svg
index 672c7e4..672c7e4 100644
--- a/lib/Utils.Memory/mimalloc/doc/mimalloc-logo.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/mimalloc-logo.svg
diff --git a/lib/Utils.Memory/mimalloc/doc/spades-logo.png b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/spades-logo.png
index d8c73fe..d8c73fe 100644
--- a/lib/Utils.Memory/mimalloc/doc/spades-logo.png
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/spades-logo.png
Binary files differ
diff --git a/lib/Utils.Memory/mimalloc/doc/unreal-logo.svg b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/unreal-logo.svg
index 5d5192a..5d5192a 100644
--- a/lib/Utils.Memory/mimalloc/doc/unreal-logo.svg
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/doc/unreal-logo.svg
diff --git a/lib/Utils.Memory/mimalloc/ide/vs2017/mimalloc-override-test.vcxproj b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2017/mimalloc-override-test.vcxproj
index 04c16a9..04c16a9 100644
--- a/lib/Utils.Memory/mimalloc/ide/vs2017/mimalloc-override-test.vcxproj
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2017/mimalloc-override-test.vcxproj
diff --git a/lib/Utils.Memory/mimalloc/ide/vs2017/mimalloc-override.vcxproj b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2017/mimalloc-override.vcxproj
index 3d5c1f7..3d5c1f7 100644
--- a/lib/Utils.Memory/mimalloc/ide/vs2017/mimalloc-override.vcxproj
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2017/mimalloc-override.vcxproj
diff --git a/lib/Utils.Memory/mimalloc/ide/vs2017/mimalloc-test-stress.vcxproj b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2017/mimalloc-test-stress.vcxproj
index 061b860..061b860 100644
--- a/lib/Utils.Memory/mimalloc/ide/vs2017/mimalloc-test-stress.vcxproj
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2017/mimalloc-test-stress.vcxproj
diff --git a/lib/Utils.Memory/mimalloc/ide/vs2017/mimalloc-test.vcxproj b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2017/mimalloc-test.vcxproj
index 04bd653..04bd653 100644
--- a/lib/Utils.Memory/mimalloc/ide/vs2017/mimalloc-test.vcxproj
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2017/mimalloc-test.vcxproj
diff --git a/lib/Utils.Memory/mimalloc/ide/vs2017/mimalloc.sln b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2017/mimalloc.sln
index 515c03f..515c03f 100644
--- a/lib/Utils.Memory/mimalloc/ide/vs2017/mimalloc.sln
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2017/mimalloc.sln
diff --git a/lib/Utils.Memory/mimalloc/ide/vs2017/mimalloc.vcxproj b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2017/mimalloc.vcxproj
index 46eb05d..46eb05d 100644
--- a/lib/Utils.Memory/mimalloc/ide/vs2017/mimalloc.vcxproj
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2017/mimalloc.vcxproj
diff --git a/lib/Utils.Memory/mimalloc/ide/vs2019/mimalloc-override-test.vcxproj b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2019/mimalloc-override-test.vcxproj
index 7a9202f..7a9202f 100644
--- a/lib/Utils.Memory/mimalloc/ide/vs2019/mimalloc-override-test.vcxproj
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2019/mimalloc-override-test.vcxproj
diff --git a/lib/Utils.Memory/mimalloc/ide/vs2019/mimalloc-override.vcxproj b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2019/mimalloc-override.vcxproj
index 1c5c61b..1c5c61b 100644
--- a/lib/Utils.Memory/mimalloc/ide/vs2019/mimalloc-override.vcxproj
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2019/mimalloc-override.vcxproj
diff --git a/lib/Utils.Memory/mimalloc/ide/vs2019/mimalloc-test-api.vcxproj b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2019/mimalloc-test-api.vcxproj
index 812a9cb..812a9cb 100644
--- a/lib/Utils.Memory/mimalloc/ide/vs2019/mimalloc-test-api.vcxproj
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2019/mimalloc-test-api.vcxproj
diff --git a/lib/Utils.Memory/mimalloc/ide/vs2019/mimalloc-test-stress.vcxproj b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2019/mimalloc-test-stress.vcxproj
index ef7ab35..ef7ab35 100644
--- a/lib/Utils.Memory/mimalloc/ide/vs2019/mimalloc-test-stress.vcxproj
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2019/mimalloc-test-stress.vcxproj
diff --git a/lib/Utils.Memory/mimalloc/ide/vs2019/mimalloc-test.vcxproj b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2019/mimalloc-test.vcxproj
index 13af6ab..13af6ab 100644
--- a/lib/Utils.Memory/mimalloc/ide/vs2019/mimalloc-test.vcxproj
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2019/mimalloc-test.vcxproj
diff --git a/lib/Utils.Memory/mimalloc/ide/vs2019/mimalloc.sln b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2019/mimalloc.sln
index 6ff01d3..6ff01d3 100644
--- a/lib/Utils.Memory/mimalloc/ide/vs2019/mimalloc.sln
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2019/mimalloc.sln
diff --git a/lib/Utils.Memory/mimalloc/ide/vs2019/mimalloc.vcxproj b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2019/mimalloc.vcxproj
index 0e2eb31..0e2eb31 100644
--- a/lib/Utils.Memory/mimalloc/ide/vs2019/mimalloc.vcxproj
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2019/mimalloc.vcxproj
diff --git a/lib/Utils.Memory/mimalloc/ide/vs2022/mimalloc-override-test.vcxproj b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2022/mimalloc-override-test.vcxproj
index a3c56f7..a3c56f7 100644
--- a/lib/Utils.Memory/mimalloc/ide/vs2022/mimalloc-override-test.vcxproj
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2022/mimalloc-override-test.vcxproj
diff --git a/lib/Utils.Memory/mimalloc/ide/vs2022/mimalloc-override.vcxproj b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2022/mimalloc-override.vcxproj
index e2c7f71..e2c7f71 100644
--- a/lib/Utils.Memory/mimalloc/ide/vs2022/mimalloc-override.vcxproj
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2022/mimalloc-override.vcxproj
diff --git a/lib/Utils.Memory/mimalloc/ide/vs2022/mimalloc-test-api.vcxproj b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2022/mimalloc-test-api.vcxproj
index d9b9cae..d9b9cae 100644
--- a/lib/Utils.Memory/mimalloc/ide/vs2022/mimalloc-test-api.vcxproj
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2022/mimalloc-test-api.vcxproj
diff --git a/lib/Utils.Memory/mimalloc/ide/vs2022/mimalloc-test-stress.vcxproj b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2022/mimalloc-test-stress.vcxproj
index 14bd3e6..14bd3e6 100644
--- a/lib/Utils.Memory/mimalloc/ide/vs2022/mimalloc-test-stress.vcxproj
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2022/mimalloc-test-stress.vcxproj
diff --git a/lib/Utils.Memory/mimalloc/ide/vs2022/mimalloc-test.vcxproj b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2022/mimalloc-test.vcxproj
index 506dd7d..506dd7d 100644
--- a/lib/Utils.Memory/mimalloc/ide/vs2022/mimalloc-test.vcxproj
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2022/mimalloc-test.vcxproj
diff --git a/lib/Utils.Memory/mimalloc/ide/vs2022/mimalloc.sln b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2022/mimalloc.sln
index 6ff01d3..6ff01d3 100644
--- a/lib/Utils.Memory/mimalloc/ide/vs2022/mimalloc.sln
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2022/mimalloc.sln
diff --git a/lib/Utils.Memory/mimalloc/ide/vs2022/mimalloc.vcxproj b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2022/mimalloc.vcxproj
index c298550..c298550 100644
--- a/lib/Utils.Memory/mimalloc/ide/vs2022/mimalloc.vcxproj
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/ide/vs2022/mimalloc.vcxproj
diff --git a/lib/Utils.Memory/mimalloc/include/mimalloc-new-delete.h b/lib/Utils.Memory/vnlib_mimalloc/vendor/include/mimalloc-new-delete.h
index c16f4a6..c16f4a6 100644
--- a/lib/Utils.Memory/mimalloc/include/mimalloc-new-delete.h
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/include/mimalloc-new-delete.h
diff --git a/lib/Utils.Memory/mimalloc/include/mimalloc-override.h b/lib/Utils.Memory/vnlib_mimalloc/vendor/include/mimalloc-override.h
index c63b0b9..c63b0b9 100644
--- a/lib/Utils.Memory/mimalloc/include/mimalloc-override.h
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/include/mimalloc-override.h
diff --git a/lib/Utils.Memory/mimalloc/include/mimalloc.h b/lib/Utils.Memory/vnlib_mimalloc/vendor/include/mimalloc.h
index f77c2ea..f77c2ea 100644
--- a/lib/Utils.Memory/mimalloc/include/mimalloc.h
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/include/mimalloc.h
diff --git a/lib/Utils.Memory/mimalloc/include/mimalloc/atomic.h b/lib/Utils.Memory/vnlib_mimalloc/vendor/include/mimalloc/atomic.h
index fe418fa..fe418fa 100644
--- a/lib/Utils.Memory/mimalloc/include/mimalloc/atomic.h
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/include/mimalloc/atomic.h
diff --git a/lib/Utils.Memory/mimalloc/include/mimalloc/internal.h b/lib/Utils.Memory/vnlib_mimalloc/vendor/include/mimalloc/internal.h
index 00d2626..00d2626 100644
--- a/lib/Utils.Memory/mimalloc/include/mimalloc/internal.h
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/include/mimalloc/internal.h
diff --git a/lib/Utils.Memory/mimalloc/include/mimalloc/prim.h b/lib/Utils.Memory/vnlib_mimalloc/vendor/include/mimalloc/prim.h
index 9e56069..9e56069 100644
--- a/lib/Utils.Memory/mimalloc/include/mimalloc/prim.h
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/include/mimalloc/prim.h
diff --git a/lib/Utils.Memory/mimalloc/include/mimalloc/track.h b/lib/Utils.Memory/vnlib_mimalloc/vendor/include/mimalloc/track.h
index 9545f75..9545f75 100644
--- a/lib/Utils.Memory/mimalloc/include/mimalloc/track.h
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/include/mimalloc/track.h
diff --git a/lib/Utils.Memory/mimalloc/include/mimalloc/types.h b/lib/Utils.Memory/vnlib_mimalloc/vendor/include/mimalloc/types.h
index 2005238..2005238 100644
--- a/lib/Utils.Memory/mimalloc/include/mimalloc/types.h
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/include/mimalloc/types.h
diff --git a/lib/Utils.Memory/mimalloc/mimalloc.pc.in b/lib/Utils.Memory/vnlib_mimalloc/vendor/mimalloc.pc.in
index 36da203..36da203 100644
--- a/lib/Utils.Memory/mimalloc/mimalloc.pc.in
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/mimalloc.pc.in
diff --git a/lib/Utils.Memory/mimalloc/readme.md b/lib/Utils.Memory/vnlib_mimalloc/vendor/readme.md
index 85d3563..85d3563 100644
--- a/lib/Utils.Memory/mimalloc/readme.md
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/readme.md
diff --git a/lib/Utils.Memory/mimalloc/src/alloc-aligned.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/alloc-aligned.c
index 1cd809f..1cd809f 100644
--- a/lib/Utils.Memory/mimalloc/src/alloc-aligned.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/alloc-aligned.c
diff --git a/lib/Utils.Memory/mimalloc/src/alloc-override.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/alloc-override.c
index 873065d..873065d 100644
--- a/lib/Utils.Memory/mimalloc/src/alloc-override.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/alloc-override.c
diff --git a/lib/Utils.Memory/mimalloc/src/alloc-posix.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/alloc-posix.c
index 225752f..225752f 100644
--- a/lib/Utils.Memory/mimalloc/src/alloc-posix.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/alloc-posix.c
diff --git a/lib/Utils.Memory/mimalloc/src/alloc.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/alloc.c
index ffc1747..ffc1747 100644
--- a/lib/Utils.Memory/mimalloc/src/alloc.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/alloc.c
diff --git a/lib/Utils.Memory/mimalloc/src/arena.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/arena.c
index a04a04c..a04a04c 100644
--- a/lib/Utils.Memory/mimalloc/src/arena.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/arena.c
diff --git a/lib/Utils.Memory/mimalloc/src/bitmap.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/bitmap.c
index a13dbe1..a13dbe1 100644
--- a/lib/Utils.Memory/mimalloc/src/bitmap.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/bitmap.c
diff --git a/lib/Utils.Memory/mimalloc/src/bitmap.h b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/bitmap.h
index 0a765c7..0a765c7 100644
--- a/lib/Utils.Memory/mimalloc/src/bitmap.h
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/bitmap.h
diff --git a/lib/Utils.Memory/mimalloc/src/heap.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/heap.c
index 58520dd..58520dd 100644
--- a/lib/Utils.Memory/mimalloc/src/heap.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/heap.c
diff --git a/lib/Utils.Memory/mimalloc/src/init.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/init.c
index b1db14c..b1db14c 100644
--- a/lib/Utils.Memory/mimalloc/src/init.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/init.c
diff --git a/lib/Utils.Memory/mimalloc/src/options.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/options.c
index 345b560..345b560 100644
--- a/lib/Utils.Memory/mimalloc/src/options.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/options.c
diff --git a/lib/Utils.Memory/mimalloc/src/os.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/os.c
index b4f02ba..b4f02ba 100644
--- a/lib/Utils.Memory/mimalloc/src/os.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/os.c
diff --git a/lib/Utils.Memory/mimalloc/src/page-queue.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/page-queue.c
index cb54b37..cb54b37 100644
--- a/lib/Utils.Memory/mimalloc/src/page-queue.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/page-queue.c
diff --git a/lib/Utils.Memory/mimalloc/src/page.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/page.c
index 8ac0a71..8ac0a71 100644
--- a/lib/Utils.Memory/mimalloc/src/page.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/page.c
diff --git a/lib/Utils.Memory/mimalloc/src/prim/osx/alloc-override-zone.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/osx/alloc-override-zone.c
index 0e0a99d..0e0a99d 100644
--- a/lib/Utils.Memory/mimalloc/src/prim/osx/alloc-override-zone.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/osx/alloc-override-zone.c
diff --git a/lib/Utils.Memory/mimalloc/src/prim/osx/prim.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/osx/prim.c
index 8a2f4e8..8a2f4e8 100644
--- a/lib/Utils.Memory/mimalloc/src/prim/osx/prim.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/osx/prim.c
diff --git a/lib/Utils.Memory/mimalloc/src/prim/prim.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/prim.c
index 9a597d8..9a597d8 100644
--- a/lib/Utils.Memory/mimalloc/src/prim/prim.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/prim.c
diff --git a/lib/Utils.Memory/mimalloc/src/prim/readme.md b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/readme.md
index 380dd3a..380dd3a 100644
--- a/lib/Utils.Memory/mimalloc/src/prim/readme.md
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/readme.md
diff --git a/lib/Utils.Memory/mimalloc/src/prim/unix/prim.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/unix/prim.c
index 314281f..314281f 100644
--- a/lib/Utils.Memory/mimalloc/src/prim/unix/prim.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/unix/prim.c
diff --git a/lib/Utils.Memory/mimalloc/src/prim/wasi/prim.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/wasi/prim.c
index 50511f0..50511f0 100644
--- a/lib/Utils.Memory/mimalloc/src/prim/wasi/prim.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/wasi/prim.c
diff --git a/lib/Utils.Memory/mimalloc/src/prim/windows/etw-mimalloc.wprp b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/windows/etw-mimalloc.wprp
index b00cd7a..b00cd7a 100644
--- a/lib/Utils.Memory/mimalloc/src/prim/windows/etw-mimalloc.wprp
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/windows/etw-mimalloc.wprp
diff --git a/lib/Utils.Memory/mimalloc/src/prim/windows/etw.h b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/windows/etw.h
index 4e0a092..4e0a092 100644
--- a/lib/Utils.Memory/mimalloc/src/prim/windows/etw.h
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/windows/etw.h
diff --git a/lib/Utils.Memory/mimalloc/src/prim/windows/etw.man b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/windows/etw.man
index cfd1f8a..cfd1f8a 100644
--- a/lib/Utils.Memory/mimalloc/src/prim/windows/etw.man
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/windows/etw.man
Binary files differ
diff --git a/lib/Utils.Memory/mimalloc/src/prim/windows/prim.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/windows/prim.c
index e6b6107..e6b6107 100644
--- a/lib/Utils.Memory/mimalloc/src/prim/windows/prim.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/windows/prim.c
diff --git a/lib/Utils.Memory/mimalloc/src/prim/windows/readme.md b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/windows/readme.md
index 217c3d1..217c3d1 100644
--- a/lib/Utils.Memory/mimalloc/src/prim/windows/readme.md
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/prim/windows/readme.md
diff --git a/lib/Utils.Memory/mimalloc/src/random.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/random.c
index 4fc8b2f..4fc8b2f 100644
--- a/lib/Utils.Memory/mimalloc/src/random.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/random.c
diff --git a/lib/Utils.Memory/mimalloc/src/segment-map.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/segment-map.c
index 4c2104b..4c2104b 100644
--- a/lib/Utils.Memory/mimalloc/src/segment-map.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/segment-map.c
diff --git a/lib/Utils.Memory/mimalloc/src/segment.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/segment.c
index 28685f2..28685f2 100644
--- a/lib/Utils.Memory/mimalloc/src/segment.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/segment.c
diff --git a/lib/Utils.Memory/mimalloc/src/static.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/static.c
index bc05dd7..bc05dd7 100644
--- a/lib/Utils.Memory/mimalloc/src/static.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/static.c
diff --git a/lib/Utils.Memory/mimalloc/src/stats.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/stats.c
index 300956c..300956c 100644
--- a/lib/Utils.Memory/mimalloc/src/stats.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/src/stats.c
diff --git a/lib/Utils.Memory/mimalloc/test/CMakeLists.txt b/lib/Utils.Memory/vnlib_mimalloc/vendor/test/CMakeLists.txt
index e76ffa6..e76ffa6 100644
--- a/lib/Utils.Memory/mimalloc/test/CMakeLists.txt
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/test/CMakeLists.txt
diff --git a/lib/Utils.Memory/mimalloc/test/main-override-static.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/test/main-override-static.c
index e71be29..e71be29 100644
--- a/lib/Utils.Memory/mimalloc/test/main-override-static.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/test/main-override-static.c
diff --git a/lib/Utils.Memory/mimalloc/test/main-override.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/test/main-override.c
index 284fdd2..284fdd2 100644
--- a/lib/Utils.Memory/mimalloc/test/main-override.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/test/main-override.c
diff --git a/lib/Utils.Memory/mimalloc/test/main-override.cpp b/lib/Utils.Memory/vnlib_mimalloc/vendor/test/main-override.cpp
index c1607b6..c1607b6 100644
--- a/lib/Utils.Memory/mimalloc/test/main-override.cpp
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/test/main-override.cpp
diff --git a/lib/Utils.Memory/mimalloc/test/main.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/test/main.c
index b148f71..b148f71 100644
--- a/lib/Utils.Memory/mimalloc/test/main.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/test/main.c
diff --git a/lib/Utils.Memory/mimalloc/test/readme.md b/lib/Utils.Memory/vnlib_mimalloc/vendor/test/readme.md
index db3524c..db3524c 100644
--- a/lib/Utils.Memory/mimalloc/test/readme.md
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/test/readme.md
diff --git a/lib/Utils.Memory/mimalloc/test/test-api-fill.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/test/test-api-fill.c
index 3fca3b9..3fca3b9 100644
--- a/lib/Utils.Memory/mimalloc/test/test-api-fill.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/test/test-api-fill.c
diff --git a/lib/Utils.Memory/mimalloc/test/test-api.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/test/test-api.c
index 8dd24e1..8dd24e1 100644
--- a/lib/Utils.Memory/mimalloc/test/test-api.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/test/test-api.c
diff --git a/lib/Utils.Memory/mimalloc/test/test-stress.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/test/test-stress.c
index 7b74b46..7b74b46 100644
--- a/lib/Utils.Memory/mimalloc/test/test-stress.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/test/test-stress.c
diff --git a/lib/Utils.Memory/mimalloc/test/test-wrong.c b/lib/Utils.Memory/vnlib_mimalloc/vendor/test/test-wrong.c
index 56a2339..56a2339 100644
--- a/lib/Utils.Memory/mimalloc/test/test-wrong.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/test/test-wrong.c
diff --git a/lib/Utils.Memory/mimalloc/test/testhelper.h b/lib/Utils.Memory/vnlib_mimalloc/vendor/test/testhelper.h
index a972758..a972758 100644
--- a/lib/Utils.Memory/mimalloc/test/testhelper.h
+++ b/lib/Utils.Memory/vnlib_mimalloc/vendor/test/testhelper.h
diff --git a/lib/Utils.Memory/vnlib_mimalloc/vnlib_mimalloc.c b/lib/Utils.Memory/vnlib_mimalloc/vnlib_mimalloc.c
index cb8707f..e4a5c24 100644
--- a/lib/Utils.Memory/vnlib_mimalloc/vnlib_mimalloc.c
+++ b/lib/Utils.Memory/vnlib_mimalloc/vnlib_mimalloc.c
@@ -1,8 +1,30 @@
-
-#include <NativeHeapApi.h>
+/*
+* Copyright (c) 2024 Vaughn Nugent
+*
+* Library: VNLib
+* Package: vnlib_mimalloc
+* File: vnlib_mimalloc.h
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public License
+* as published by the Free Software Foundation; either version 2.1
+* of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with NativeHeapApi. If not, see http://www.gnu.org/licenses/.
+*/
+
+#define VNLIB_EXPORTING //Exporting when compiling the library
+
+#include "NativeHeapApi.h"
#include <mimalloc.h>
-#if defined(_WIN32) || defined(_WIN64)
+#ifdef _P_IS_WINDOWS
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files
@@ -19,13 +41,13 @@
#define SHARED_HEAP_HANDLE_VALUE ((HeapHandle)1)
-HEAP_METHOD_EXPORT HeapHandle HEAP_METHOD_CC heapGetSharedHeapHandle(void)
+VNLIB_HEAP_API HeapHandle VNLIB_CC heapGetSharedHeapHandle(void)
{
//Return the shared heap pointer
return SHARED_HEAP_HANDLE_VALUE;
}
-HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapCreate(UnmanagedHeapDescriptor* flags)
+VNLIB_HEAP_API ERRNO VNLIB_CC heapCreate(UnmanagedHeapDescriptor* flags)
{
/*
@@ -53,7 +75,7 @@ HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapCreate(UnmanagedHeapDescriptor* flag
}
-HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapDestroy(HeapHandle heap)
+VNLIB_HEAP_API ERRNO VNLIB_CC heapDestroy(HeapHandle heap)
{
//Destroy the heap if not shared heap
if (heap != SHARED_HEAP_HANDLE_VALUE)
@@ -65,7 +87,7 @@ HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapDestroy(HeapHandle heap)
}
-HEAP_METHOD_EXPORT void* HEAP_METHOD_CC heapAlloc(HeapHandle heap, size_t elements, size_t alignment, int zero)
+VNLIB_HEAP_API void* VNLIB_CC heapAlloc(HeapHandle heap, size_t elements, size_t alignment, int zero)
{
//Check for global heap
if (heap == SHARED_HEAP_HANDLE_VALUE)
@@ -85,7 +107,7 @@ HEAP_METHOD_EXPORT void* HEAP_METHOD_CC heapAlloc(HeapHandle heap, size_t elemen
}
-HEAP_METHOD_EXPORT void* HEAP_METHOD_CC heapRealloc(HeapHandle heap, void* block, size_t elements, size_t alignment, int zero)
+VNLIB_HEAP_API void* VNLIB_CC heapRealloc(HeapHandle heap, void* block, size_t elements, size_t alignment, int zero)
{
//Check for global heap
if (heap == SHARED_HEAP_HANDLE_VALUE)
@@ -105,7 +127,7 @@ HEAP_METHOD_EXPORT void* HEAP_METHOD_CC heapRealloc(HeapHandle heap, void* block
}
-HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapFree(HeapHandle heap, void* block)
+VNLIB_HEAP_API ERRNO VNLIB_CC heapFree(HeapHandle heap, void* block)
{
(void)heap;
mi_free(block);
diff --git a/lib/Utils.Memory/vnlib_mimalloc/vnlib_mimalloc.vcxitems b/lib/Utils.Memory/vnlib_mimalloc/vnlib_mimalloc.vcxitems
index 2e9587f..7b45385 100644
--- a/lib/Utils.Memory/vnlib_mimalloc/vnlib_mimalloc.vcxitems
+++ b/lib/Utils.Memory/vnlib_mimalloc/vnlib_mimalloc.vcxitems
@@ -25,4 +25,7 @@
<ItemGroup>
<ClCompile Include="$(MSBuildThisFileDirectory)vnlib_mimalloc.c" />
</ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="$(MSBuildThisFileDirectory)NativeHeapApi.h" />
+ </ItemGroup>
</Project> \ No newline at end of file
diff --git a/lib/Utils.Memory/vnlib_rpmalloc/CMakeLists.txt b/lib/Utils.Memory/vnlib_rpmalloc/CMakeLists.txt
index 82d1c38..5e04d03 100644
--- a/lib/Utils.Memory/vnlib_rpmalloc/CMakeLists.txt
+++ b/lib/Utils.Memory/vnlib_rpmalloc/CMakeLists.txt
@@ -8,12 +8,11 @@ file(GLOB HEADERS *.h)
#Add indepednent source files to the project
set(VNLIB_RPMALLOC_SOURCES
"vnlib_rpmalloc.c"
- "../rpmalloc/rpmalloc.c"
+ "vendor/rpmalloc.c"
)
#add rpmalloc includes, there will only be one library
-include_directories(../rpmalloc)
-include_directories(../NativeHeapApi/src)
+include_directories(vendor)
#set options for greedy allocator defaults
option(ENABLE_GREEDY "Enable greedy allocator configuration" ON)
diff --git a/lib/Utils.Memory/vnlib_rpmalloc/LICENSE b/lib/Utils.Memory/vnlib_rpmalloc/LICENSE
index ce09686..eedae8e 100644
--- a/lib/Utils.Memory/vnlib_rpmalloc/LICENSE
+++ b/lib/Utils.Memory/vnlib_rpmalloc/LICENSE
@@ -1,234 +1,410 @@
-Copyright (c) 2023 Vaughn Nugent
+Copyright (c) 2024 Vaughn Nugent
Contact information
Name: Vaughn Nugent
Email: vnpublic[at]proton.me
Website: https://www.vaughnnugent.com
-The software in this repository is licensed under the GNU GPL version 2.0 (or any later version).
+The software in this repository is licensed under the GNU LGPL version 2.1 (or any later version).
-SPDX-License-Identifier: GPL-2.0-or-later
+SPDX-License-Identifier: LGPL-2.1-or-later
License-Text:
-GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
- a) You must cause the modified files to carry prominent notices
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
+identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
+on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
+entire whole, and thus to each and every part regardless of who wrote
+it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
-collective works based on the Program.
+collective works based on the Library.
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
+distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
+the Library or works based on it.
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
+You are not responsible for enforcing compliance by third parties with
this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
+
+ 11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
+refrain entirely from distribution of the Library.
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
+integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
@@ -239,55 +415,58 @@ impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
- 8. If the distribution and/or use of the Program is restricted in
+ 12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
NO WARRANTY
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS \ No newline at end of file
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/lib/Utils.Memory/vnlib_rpmalloc/NativeHeapApi.h b/lib/Utils.Memory/vnlib_rpmalloc/NativeHeapApi.h
new file mode 100644
index 0000000..6a994b2
--- /dev/null
+++ b/lib/Utils.Memory/vnlib_rpmalloc/NativeHeapApi.h
@@ -0,0 +1,164 @@
+/*
+* Copyright (c) 2024 Vaughn Nugent
+*
+* Library: VNLib
+* Package: NativeHeapApi
+* File: NativeHeapApi.h
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public License
+* as published by the Free Software Foundation; either version 2.1
+* of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with NativeHeapApi. If not, see http://www.gnu.org/licenses/.
+*/
+
+#pragma once
+
+#include <stdint.h>
+
+#ifndef NATIVE_HEAP_API
+#define NATIVE_HEAP_API
+
+#if defined(_MSC_VER) || defined(WIN32) || defined(_WIN32)
+ #define _P_IS_WINDOWS
+#endif
+
+//Set api export calling convention (allow used to override)
+#ifndef VNLIB_CC
+ #ifdef _P_IS_WINDOWS
+ //STD for importing to other languages such as .NET
+ #define VNLIB_CC __stdcall
+ #else
+ #define VNLIB_CC
+ #endif
+#endif // !NC_CC
+
+#ifndef VNLIB_EXPORT //Allow users to disable the export/impoty macro if using source code directly
+ #ifdef VNLIB_EXPORTING
+ #ifdef _P_IS_WINDOWS
+ #define VNLIB_HEAP_API __declspec(dllexport)
+ #else
+ #define VNLIB_HEAP_API __attribute__((visibility("default")))
+ #endif // _NC_IS_WINDOWS
+ #else
+ #ifdef _P_IS_WINDOWS
+ #define VNLIB_HEAP_API __declspec(dllimport)
+ #else
+ #define VNLIB_HEAP_API
+ #endif // _P_IS_WINDOWS
+ #endif // !VNLIB_EXPORTING
+#endif // !VNLIB_EXPORT
+
+/// <summary>
+/// Internal heap creation flags passed to the creation method by the library loader
+/// </summary>
+typedef enum HeapCreationFlags
+{
+ /// <summary>
+ /// Default/no flags
+ /// </summary>
+ HEAP_CREATION_NO_FLAGS,
+ /// <summary>
+ /// Specifies that all allocations be zeroed before returning to caller
+ /// </summary>
+ HEAP_CREATION_GLOBAL_ZERO = 0x01,
+ /// <summary>
+ /// Specifies that the heap should use internal locking, aka its not thread safe
+ /// and needs to be made thread safe
+ /// </summary>
+ HEAP_CREATION_SERIALZE_ENABLED = 0x02,
+ /// <summary>
+ /// Specifies that the requested heap will be a shared heap for the process/library
+ /// </summary>
+ HEAP_CREATION_IS_SHARED = 0x04,
+ /// <summary>
+ /// Specifies that the heap will support block reallocation
+ /// </summary>
+ HEAP_CREATION_SUPPORTS_REALLOC = 0x08,
+} HeapCreationFlags;
+
+#ifdef _P_IS_WINDOWS
+ typedef void* LPVOID;
+#endif // !WIN32
+
+/// <summary>
+/// The vnlib ERRNO type, integer/process dependent,
+/// internally represented as a pointer
+/// </summary>
+typedef void* ERRNO;
+
+/// <summary>
+/// A pointer to a heap structure that was stored during heap creation
+/// </summary>
+typedef void* HeapHandle;
+
+/// <summary>
+/// A structure for heap initialization
+/// </summary>
+typedef struct UnmanagedHeapDescriptor
+{
+ HeapHandle HeapPointer;
+ ERRNO Flags;
+ HeapCreationFlags CreationFlags;
+} UnmanagedHeapDescriptor;
+
+/// <summary>
+/// Gets the shared heap handle for the process/library
+/// </summary>
+/// <returns>A pointer to the shared heap</returns>
+VNLIB_HEAP_API HeapHandle VNLIB_CC heapGetSharedHeapHandle(void);
+
+/// <summary>
+/// The heap creation method. You must set the flags->HeapPointer = your heap
+/// structure
+/// </summary>
+/// <param name="flags">Creation flags passed by the caller to create the heap. This structure will be initialized, and may be modified</param>
+/// <returns>A boolean value that indicates the result of the operation</returns>
+VNLIB_HEAP_API ERRNO VNLIB_CC heapCreate(UnmanagedHeapDescriptor* flags);
+
+/// <summary>
+/// Destroys a previously created heap
+/// </summary>
+/// <param name="heap">The pointer to your custom heap structure from heap creation</param>
+VNLIB_HEAP_API ERRNO VNLIB_CC heapDestroy(HeapHandle heap);
+
+/// <summary>
+/// Allocates a block from the desired heap and returns a pointer
+/// to the block. Optionally zeros the block before returning
+/// </summary>
+/// <param name="heap">A pointer to your heap structure</param>
+/// <param name="elements">The number of elements to allocate</param>
+/// <param name="alignment">The alignment (or size) of each element in bytes</param>
+/// <param name="zero">A flag to zero the block before returning the block</param>
+/// <returns>A pointer to the allocated block</returns>
+VNLIB_HEAP_API void* VNLIB_CC heapAlloc(HeapHandle heap, uint64_t elements, uint64_t alignment, int zero);
+
+/// <summary>
+/// Reallocates a block on the desired heap and returns a pointer to the new block. If reallocation
+/// is not supported, you should only return 0 and leave the block unmodified. The data in the valid
+/// size of the block MUST remain unmodified.
+/// </summary>
+/// <param name="heap">A pointer to your heap structure</param>
+/// <param name="block">A pointer to the block to reallocate</param>
+/// <param name="elements">The new size of the block, in elements</param>
+/// <param name="alignment">The element size or block alignment</param>
+/// <param name="zero">A flag to zero the block (or the new size) before returning.</param>
+/// <returns>A pointer to the reallocated block, or zero if the operation failed or is not supported</returns>
+VNLIB_HEAP_API void* VNLIB_CC heapRealloc(HeapHandle heap, void* block, uint64_t elements, uint64_t alignment, int zero);
+
+/// <summary>
+/// Frees a previously allocated block on the desired heap.
+/// </summary>
+/// <param name="heap">A pointer to your heap structure</param>
+/// <param name="block">A pointer to the block to free</param>
+/// <returns>A value that indicates the result of the operation, nonzero if success, 0 if a failure occurred </returns>
+VNLIB_HEAP_API ERRNO VNLIB_CC heapFree(HeapHandle heap, void* block);
+
+#endif // !NATIVE_HEAP_API \ No newline at end of file
diff --git a/lib/Utils.Memory/vnlib_rpmalloc/Taskfile.yaml b/lib/Utils.Memory/vnlib_rpmalloc/Taskfile.yaml
index af3180e..fa4cff9 100644
--- a/lib/Utils.Memory/vnlib_rpmalloc/Taskfile.yaml
+++ b/lib/Utils.Memory/vnlib_rpmalloc/Taskfile.yaml
@@ -9,7 +9,6 @@
version: '3'
vars:
- MS_ARGS: '/p:Platform=x64 /p:RunAnalyzersDuringBuild=false /p:BuildInParallel=true /p:MultiProcessorCompilation=true'
PROJECT_NAME: 'vnlib_rpmalloc'
MODULE_NAME: 'vnlib.core'
@@ -27,29 +26,9 @@ tasks:
cmds:
#init cmake build with greedy enabled
- cmake -B./build -DENABLE_GREEDY=1
+ - cmake --build build/ --config Debug
+ - cmake --build build/ --config Release
- #build the rpmalloc library in debug mode first
- - task: build-rpmalloc-win
- - task: build-rpmalloc-gnumake
-
- #build using msbuild for rpmalloc libraries for debug and release modes
- build-rpmalloc-win:
- platforms: ['windows']
- internal: true
- cmds:
- #build solution in debug mode
- - cd build && msbuild {{.PROJECT_NAME}}.sln /p:Configuration=debug {{.BUILD_FLAGS}} {{.MS_ARGS}}
- #build in release
- - cd build && msbuild {{.PROJECT_NAME}}.sln /p:Configuration=release {{.BUILD_FLAGS}} {{.MS_ARGS}}
-
- #build using gnu make
- build-rpmalloc-gnumake:
- platforms: ['linux']
- internal: true
- cmds:
- #build project with make
- - cd build && make
-
postbuild_success:
vars:
#required files to include in tar
@@ -86,7 +65,7 @@ tasks:
licenses:
cmds:
#add rpmalloc license to binary output
- - powershell -Command "Copy-Item -Path ../rpmalloc/license -Destination '{{.TARGET}}/rpmalloc_license.txt'"
+ - powershell -Command "Copy-Item -Path vendor/license -Destination '{{.TARGET}}/rpmalloc_license.txt'"
#add my license file
- powershell -Command "Copy-Item -Path ./license -Destination '{{.TARGET}}/license.txt'"
#add readme file
@@ -95,21 +74,11 @@ tasks:
pack_source:
dir: '{{.USER_WORKING_DIR}}'
cmds:
- #pack rpmalloc source code and create the archive
- - cd .. && powershell -Command "tar --exclude */build/* --exclude */.git/* -cvf 'vnlib_rpmalloc/bin/src.tar' ./rpmalloc/*"
- #append the nativeheapapi directory
- - cd .. && powershell -Command "tar -rvf vnlib_rpmalloc/bin/src.tar ./NativeHeapApi/*"
- #append the current directory
- - cd .. && powershell -Command "tar --exclude */build/* --exclude */bin/* -rvf vnlib_rpmalloc/bin/src.tar ./vnlib_rpmalloc/*"
- #use tar to gzip the archive
- - cd bin && tar -czvf src.tgz src.tar
- # delete the tar archive
- - cmd: powershell -Command "Remove-Item bin/src.tar -Force"
- ignore_error: true
+ - powershell -Command "tar --exclude build/* --exclude bin/* --exclude vendor/build/* -czf 'bin/src.tgz' ."
clean:
ignore_error: true
cmds:
- - cmd: powershell -Command "Remove-Item -Recurse './bin'"
- - cmd: powershell -Command "Remove-Item -Recurse './build'" \ No newline at end of file
+ - cmd: powershell -Command "Remove-Item -Recurse 'bin/'"
+ - cmd: powershell -Command "Remove-Item -Recurse 'build/'" \ No newline at end of file
diff --git a/lib/Utils.Memory/rpmalloc/LICENSE b/lib/Utils.Memory/vnlib_rpmalloc/vendor/LICENSE
index be01deb..be01deb 100644
--- a/lib/Utils.Memory/rpmalloc/LICENSE
+++ b/lib/Utils.Memory/vnlib_rpmalloc/vendor/LICENSE
diff --git a/lib/Utils.Memory/rpmalloc/rpmalloc.c b/lib/Utils.Memory/vnlib_rpmalloc/vendor/rpmalloc.c
index ab7703b..ab7703b 100644
--- a/lib/Utils.Memory/rpmalloc/rpmalloc.c
+++ b/lib/Utils.Memory/vnlib_rpmalloc/vendor/rpmalloc.c
diff --git a/lib/Utils.Memory/rpmalloc/rpmalloc.h b/lib/Utils.Memory/vnlib_rpmalloc/vendor/rpmalloc.h
index db5be48..db5be48 100644
--- a/lib/Utils.Memory/rpmalloc/rpmalloc.h
+++ b/lib/Utils.Memory/vnlib_rpmalloc/vendor/rpmalloc.h
diff --git a/lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.c b/lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.c
index 5173643..2b63dcc 100644
--- a/lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.c
+++ b/lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.c
@@ -1,27 +1,25 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: vnlib_rpmalloc
-* File: vnlib_rpmalloc.c
+* File: vnlib_rpmalloc.h
*
-* framework.h is part of vnlib_rpmalloc which is part of the larger
-* VNLib collection of libraries and utilities.
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public License
+* as published by the Free Software Foundation; either version 2.1
+* of the License, or (at your option) any later version.
*
-* vnlib_rpmalloc is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published
-* by the Free Software Foundation, either version 2 of the License,
-* or (at your option) any later version.
-*
-* vnlib_rpmalloc is distributed in the hope that it will be useful,
+* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* General Public License for more details.
+* Lesser General Public License for more details.
*
-* You should have received a copy of the GNU General Public License
-* along with vnlib_rpmalloc. If not, see http://www.gnu.org/licenses/.
+* You should have received a copy of the GNU Lesser General Public License
+* along with NativeHeapApi. If not, see http://www.gnu.org/licenses/.
*/
+
/*
* Top level linux definitions
*/
@@ -33,10 +31,12 @@
#endif
-#include <NativeHeapApi.h>
+#define VNLIB_EXPORTING //Exporting when compiling the library
+
+#include "NativeHeapApi.h"
#include <rpmalloc.h>
-#if defined(_WIN32)
+#if defined(_P_IS_WINDOWS)
/*
* setup windows api incudes
@@ -144,13 +144,13 @@ int pthread_create(pthread_t* thread,
//Define the heap methods
-HEAP_METHOD_EXPORT HeapHandle HEAP_METHOD_CC heapGetSharedHeapHandle(void)
+VNLIB_HEAP_API HeapHandle VNLIB_CC heapGetSharedHeapHandle(void)
{
//Return the shared heap pointer
return SHARED_HEAP_HANDLE_VALUE;
}
-HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapCreate(UnmanagedHeapDescriptor* flags)
+VNLIB_HEAP_API ERRNO VNLIB_CC heapCreate(UnmanagedHeapDescriptor* flags)
{
//All heaps support resizing
flags->CreationFlags |= HEAP_CREATION_SUPPORTS_REALLOC;
@@ -178,7 +178,7 @@ HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapCreate(UnmanagedHeapDescriptor* flag
}
-HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapDestroy(HeapHandle heap)
+VNLIB_HEAP_API ERRNO VNLIB_CC heapDestroy(HeapHandle heap)
{
//Destroy non-shared heaps
if (heap != SHARED_HEAP_HANDLE_VALUE)
@@ -194,7 +194,7 @@ HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapDestroy(HeapHandle heap)
}
-HEAP_METHOD_EXPORT void* HEAP_METHOD_CC heapAlloc(HeapHandle heap, size_t elements, size_t alignment, int zero)
+VNLIB_HEAP_API void* VNLIB_CC heapAlloc(HeapHandle heap, size_t elements, size_t alignment, int zero)
{
//Multiply for element size
size_t size = elements * alignment;
@@ -236,7 +236,7 @@ HEAP_METHOD_EXPORT void* HEAP_METHOD_CC heapAlloc(HeapHandle heap, size_t elemen
}
-HEAP_METHOD_EXPORT void* HEAP_METHOD_CC heapRealloc(HeapHandle heap, void* block, size_t elements, size_t alignment, int zero)
+VNLIB_HEAP_API void* VNLIB_CC heapRealloc(HeapHandle heap, void* block, size_t elements, size_t alignment, int zero)
{
//Multiply for element size
size_t size = elements * alignment;
@@ -263,7 +263,7 @@ HEAP_METHOD_EXPORT void* HEAP_METHOD_CC heapRealloc(HeapHandle heap, void* block
}
-HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapFree(HeapHandle heap, void* block)
+VNLIB_HEAP_API ERRNO VNLIB_CC heapFree(HeapHandle heap, void* block)
{
//Check for global heap
if (heap == SHARED_HEAP_HANDLE_VALUE)
diff --git a/lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.vcxitems b/lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.vcxitems
index 6fc55c7..ff70e80 100644
--- a/lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.vcxitems
+++ b/lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.vcxitems
@@ -16,7 +16,7 @@
<ItemGroup>
<Text Include="$(MSBuildThisFileDirectory)build.readme.txt" />
<Text Include="$(MSBuildThisFileDirectory)CMakeLists.txt" />
- <Text Include="$(MSBuildThisFileDirectory)license.txt" />
+ <Text Include="$(MSBuildThisFileDirectory)license" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(MSBuildThisFileDirectory)vnlib_rpmalloc.c" />
diff --git a/lib/Utils/src/Extensions/CollectionExtensions.cs b/lib/Utils/src/Extensions/CollectionExtensions.cs
index b3a5d2a..eac7baf 100644
--- a/lib/Utils/src/Extensions/CollectionExtensions.cs
+++ b/lib/Utils/src/Extensions/CollectionExtensions.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Utils
@@ -44,10 +44,8 @@ namespace VNLib.Utils.Extensions
/// <returns>The initialized structure, or default if the lookup returns null/empty string</returns>
public static TValue GetValueType<TKey, TValue>(this IIndexable<TKey, string> lookup, TKey key) where TValue : unmanaged where TKey : notnull
{
- if (lookup is null)
- {
- throw new ArgumentNullException(nameof(lookup));
- }
+ ArgumentNullException.ThrowIfNull(lookup);
+
//Get value
string value = lookup[key];
//If the string is set, recover the value and return it
@@ -64,13 +62,12 @@ namespace VNLib.Utils.Extensions
/// <param name="value">The value to serialze</param>
public static void SetValueType<TKey, TValue>(this IIndexable<TKey, string> lookup, TKey key, TValue value) where TValue : unmanaged where TKey : notnull
{
- if (lookup is null)
- {
- throw new ArgumentNullException(nameof(lookup));
- }
+ ArgumentNullException.ThrowIfNull(lookup);
+
//encode string from value type and store in lookup
lookup[key] = VnEncoding.ToBase32String(value);
}
+
/// <summary>
/// Executes a handler delegate on every element of the list within a try-catch block
/// and rethrows exceptions as an <see cref="AggregateException"/>
@@ -81,15 +78,8 @@ namespace VNLib.Utils.Extensions
/// <exception cref="AggregateException"></exception>
public static void TryForeach<T>(this IEnumerable<T> list, Action<T> handler)
{
- if (list is null)
- {
- throw new ArgumentNullException(nameof(list));
- }
-
- if (handler is null)
- {
- throw new ArgumentNullException(nameof(handler));
- }
+ ArgumentNullException.ThrowIfNull(list);
+ ArgumentNullException.ThrowIfNull(handler);
List<Exception>? exceptionList = null;
foreach(T item in list)
@@ -101,15 +91,35 @@ namespace VNLib.Utils.Extensions
catch(Exception ex)
{
//Init new list and add the exception
- exceptionList ??= new();
+ exceptionList ??= [];
exceptionList.Add(ex);
}
}
+
//Raise aggregate exception for all caught exceptions
if(exceptionList?.Count > 0)
{
throw new AggregateException(exceptionList);
}
}
+
+ /// <summary>
+ /// Eumerates the list and executes the handler delegate on each element
+ /// and fails at the first exception
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="list"></param>
+ /// <param name="handler">The callback function to invoke on each element</param>
+ /// <exception cref="ArgumentNullException"></exception>
+ public static void ForEach<T>(this IEnumerable<T> list, Action<T> handler)
+ {
+ ArgumentNullException.ThrowIfNull(list);
+ ArgumentNullException.ThrowIfNull(handler);
+
+ foreach(T item in list)
+ {
+ handler(item);
+ }
+ }
}
}
diff --git a/lib/Utils/src/Extensions/IoExtensions.cs b/lib/Utils/src/Extensions/IoExtensions.cs
index ffa374b..7c53c9b 100644
--- a/lib/Utils/src/Extensions/IoExtensions.cs
+++ b/lib/Utils/src/Extensions/IoExtensions.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Utils
@@ -55,7 +55,7 @@ namespace VNLib.Utils.Extensions
[UnsupportedOSPlatform("tvos")]
public static void Unlock(this FileStream fs)
{
- _ = fs ?? throw new ArgumentNullException(nameof(fs));
+ ArgumentNullException.ThrowIfNull(fs);
//Unlock the entire file
fs.Unlock(0, fs.Length);
}
@@ -69,7 +69,7 @@ namespace VNLib.Utils.Extensions
[UnsupportedOSPlatform("tvos")]
public static void Lock(this FileStream fs)
{
- _ = fs ?? throw new ArgumentNullException(nameof(fs));
+ ArgumentNullException.ThrowIfNull(fs);
//Lock the entire length of the file
fs.Lock(0, fs.Length);
}
@@ -88,15 +88,8 @@ namespace VNLib.Utils.Extensions
/// <exception cref="ArgumentException"></exception>
public static async ValueTask CopyToAsync(this Stream source, Stream dest, int bufferSize, IUnmangedHeap heap, CancellationToken token = default)
{
- if (source is null)
- {
- throw new ArgumentNullException(nameof(source));
- }
-
- if (heap is null)
- {
- throw new ArgumentNullException(nameof(heap));
- }
+ ArgumentNullException.ThrowIfNull(source);
+ ArgumentNullException.ThrowIfNull(heap);
if (source.CanSeek)
{
@@ -123,10 +116,8 @@ namespace VNLib.Utils.Extensions
/// <exception cref="ArgumentException"></exception>
public static async ValueTask CopyToAsync(this Stream source, Stream dest, long count, int bufferSize, IUnmangedHeap heap, CancellationToken token = default)
{
- if (source is null)
- {
- throw new ArgumentNullException(nameof(source));
- }
+ ArgumentNullException.ThrowIfNull(source);
+ ArgumentNullException.ThrowIfNull(dest);
if (source.CanSeek)
{
@@ -148,16 +139,9 @@ namespace VNLib.Utils.Extensions
/// <exception cref="ArgumentNullException"></exception>
public static void CopyTo(this Stream source, Stream dest, IUnmangedHeap? heap = null)
{
- if (dest is null)
- {
- throw new ArgumentNullException(nameof(dest));
- }
+ ArgumentNullException.ThrowIfNull(source);
+ ArgumentNullException.ThrowIfNull(dest);
- if (source is null)
- {
- throw new ArgumentNullException(nameof(source));
- }
-
if (!source.CanRead)
{
throw new ArgumentException("Source stream is unreadable", nameof(source));
@@ -203,16 +187,9 @@ namespace VNLib.Utils.Extensions
/// <exception cref="ArgumentNullException"></exception>
public static void CopyTo(this Stream source, Stream dest, long count, IUnmangedHeap? heap = null)
{
- if (dest is null)
- {
- throw new ArgumentNullException(nameof(dest));
- }
+ ArgumentNullException.ThrowIfNull(source);
+ ArgumentNullException.ThrowIfNull(dest);
- if (source is null)
- {
- throw new ArgumentNullException(nameof(source));
- }
-
if (!source.CanRead)
{
throw new ArgumentException("Source stream is unreadable", nameof(source));
@@ -263,16 +240,9 @@ namespace VNLib.Utils.Extensions
/// <exception cref="ArgumentException"></exception>
public static async ValueTask CopyToAsync(this Stream source, Stream dest, Memory<byte> buffer, CancellationToken token = default)
{
- if (dest is null)
- {
- throw new ArgumentNullException(nameof(dest));
- }
+ ArgumentNullException.ThrowIfNull(source);
+ ArgumentNullException.ThrowIfNull(dest);
- if (source is null)
- {
- throw new ArgumentNullException(nameof(source));
- }
-
//Make sure source can be read from, and dest can be written to
if (!source.CanRead)
{
@@ -310,15 +280,8 @@ namespace VNLib.Utils.Extensions
/// <exception cref="ArgumentException"></exception>
public static async ValueTask CopyToAsync(this Stream source, Stream dest, Memory<byte> buffer, long count, CancellationToken token = default)
{
- if (dest is null)
- {
- throw new ArgumentNullException(nameof(dest));
- }
-
- if (source is null)
- {
- throw new ArgumentNullException(nameof(source));
- }
+ ArgumentNullException.ThrowIfNull(source);
+ ArgumentNullException.ThrowIfNull(dest);
//Make sure source can be read from, and dest can be written to
if (!source.CanRead)
@@ -373,7 +336,8 @@ namespace VNLib.Utils.Extensions
int bufferSize = 4096,
FileOptions options = FileOptions.None)
{
- _ = dir ?? throw new ArgumentNullException(nameof(dir));
+ ArgumentNullException.ThrowIfNull(dir);
+ ArgumentNullException.ThrowIfNull(fileName);
string fullPath = Path.Combine(dir.FullName, fileName);
return new FileStream(fullPath, mode, access, share, bufferSize, options);
}
@@ -386,7 +350,8 @@ namespace VNLib.Utils.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void DeleteFile(this DirectoryInfo dir, string fileName)
{
- _ = dir ?? throw new ArgumentNullException(nameof(dir));
+ ArgumentNullException.ThrowIfNull(dir);
+ ArgumentNullException.ThrowIfNull(fileName);
string fullPath = Path.Combine(dir.FullName, fileName);
File.Delete(fullPath);
}
@@ -400,7 +365,8 @@ namespace VNLib.Utils.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool FileExists(this DirectoryInfo dir, string fileName)
{
- _ = dir ?? throw new ArgumentNullException(nameof(dir));
+ ArgumentNullException.ThrowIfNull(dir);
+ ArgumentNullException.ThrowIfNull(fileName);
string fullPath = Path.Combine(dir.FullName, fileName);
return FileOperations.FileExists(fullPath);
}
@@ -415,7 +381,7 @@ namespace VNLib.Utils.Extensions
/// <returns>A new <see cref="ISimpleFilesystem"/> with a new filesystem directory scope</returns>
public static ISimpleFilesystem CreateNewScope(this ISimpleFilesystem fs, string offsetPath) => new FsScope(fs, offsetPath);
- private sealed record class FsScope(ISimpleFilesystem Parent, string OffsetPath) : ISimpleFilesystem
+ private sealed class FsScope(ISimpleFilesystem Parent, string OffsetPath) : ISimpleFilesystem
{
///<inheritdoc/>
@@ -467,7 +433,7 @@ namespace VNLib.Utils.Extensions
/// <returns>A <see cref="ISimpleFilesystem"/> wrapper around the <see cref="IsolatedStorageDirectory"/></returns>
public static ISimpleFilesystem CreateSimpleFs(this IsolatedStorageDirectory dir) => new IsolatedStorageSimpleFs(dir);
- private sealed record class IsolatedStorageSimpleFs(IsolatedStorageDirectory Directory) : ISimpleFilesystem
+ private sealed class IsolatedStorageSimpleFs(IsolatedStorageDirectory Directory) : ISimpleFilesystem
{
///<inheritdoc/>
public string GetExternalFilePath(string filePath) => Directory.GetFullFilePath(filePath);
diff --git a/lib/Utils/src/Extensions/JsonExtensions.cs b/lib/Utils/src/Extensions/JsonExtensions.cs
index 55ad958..deeaf32 100644
--- a/lib/Utils/src/Extensions/JsonExtensions.cs
+++ b/lib/Utils/src/Extensions/JsonExtensions.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Utils
@@ -156,6 +156,9 @@ namespace VNLib.Utils.Extensions
/// <returns>A new document with a parent root containing the combined objects</returns>
public static JsonDocument Merge(this JsonDocument initial, JsonDocument other, string initalName, string secondName)
{
+ ArgumentNullException.ThrowIfNull(initial);
+ ArgumentNullException.ThrowIfNull(other);
+
//Open a new memory buffer
using VnMemoryStream ms = new();
//Encapuslate the memory stream in a writer
diff --git a/lib/Utils/src/Extensions/SafeLibraryExtensions.cs b/lib/Utils/src/Extensions/SafeLibraryExtensions.cs
index 8866059..632a6ae 100644
--- a/lib/Utils/src/Extensions/SafeLibraryExtensions.cs
+++ b/lib/Utils/src/Extensions/SafeLibraryExtensions.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Utils
@@ -69,14 +69,31 @@ namespace VNLib.Utils.Extensions
/// <exception cref="MissingMemberException"></exception>
/// <exception cref="ObjectDisposedException"></exception>
/// <exception cref="EntryPointNotFoundException"></exception>
+ [Obsolete("Use GetFunction<T>() extension instead")]
public static SafeMethodHandle<T> GetMethod<T>(this SafeLibraryHandle library) where T : Delegate
+ => GetFunction<T>(library);
+
+ /// <summary>
+ /// Loads a native function from the current <see cref="SafeLibraryHandle"/>
+ /// that has a <see cref="SafeMethodNameAttribute"/>
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="library"></param>
+ /// <returns></returns>
+ /// <exception cref="MissingMemberException"></exception>
+ /// <exception cref="ObjectDisposedException"></exception>
+ /// <exception cref="EntryPointNotFoundException"></exception>
+ public static SafeMethodHandle<T> GetFunction<T>(this SafeLibraryHandle library) where T : Delegate
{
+ ArgumentNullException.ThrowIfNull(library);
+
Type t = typeof(T);
//Get the method name attribute
SafeMethodNameAttribute? attr = t.GetCustomAttribute<SafeMethodNameAttribute>();
_ = attr ?? throw new MissingMemberException(_missMemberExceptionMessage);
- return library.GetMethod<T>(attr.MethodName ?? t.Name);
+ return library.GetFunction<T>(attr.MethodName ?? t.Name);
}
+
/// <summary>
/// Loads a native method from the current <see cref="SafeLibraryHandle"/>
/// that has a <see cref="SafeMethodNameAttribute"/>
@@ -90,14 +107,33 @@ namespace VNLib.Utils.Extensions
/// <remarks>
/// The libraries handle count is left unmodified
/// </remarks>
+ [Obsolete("Use DangerousGetFunction<T>() extension instead")]
public static T DangerousGetMethod<T>(this SafeLibraryHandle library) where T: Delegate
+ => DangerousGetFunction<T>(library);
+
+ /// <summary>
+ /// Loads a native method from the current <see cref="SafeLibraryHandle"/>
+ /// that has a <see cref="SafeMethodNameAttribute"/>
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="library"></param>
+ /// <returns></returns>
+ /// <exception cref="MissingMemberException"></exception>
+ /// <exception cref="ObjectDisposedException"></exception>
+ /// <exception cref="EntryPointNotFoundException"></exception>
+ /// <remarks>
+ /// The libraries handle count is left unmodified
+ /// </remarks>
+ public static T DangerousGetFunction<T>(this SafeLibraryHandle library) where T : Delegate
{
+ ArgumentNullException.ThrowIfNull(library);
+
Type t = typeof(T);
//Get the method name attribute
SafeMethodNameAttribute? attr = t.GetCustomAttribute<SafeMethodNameAttribute>();
return string.IsNullOrWhiteSpace(attr?.MethodName)
? throw new MissingMemberException(_missMemberExceptionMessage)
- : library.DangerousGetMethod<T>(attr.MethodName);
+ : library.DangerousGetFunction<T>(attr.MethodName);
}
}
}
diff --git a/lib/Utils/src/IO/FileWatcher.cs b/lib/Utils/src/IO/FileWatcher.cs
new file mode 100644
index 0000000..b0a2fe3
--- /dev/null
+++ b/lib/Utils/src/IO/FileWatcher.cs
@@ -0,0 +1,171 @@
+/*
+* Copyright (c) 2024 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Utils
+* File: FileWatcher.cs
+*
+* FileWatcher.cs is part of VNLib.Utils which is part of the larger
+* VNLib collection of libraries and utilities.
+*
+* VNLib.Utils is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published
+* by the Free Software Foundation, either version 2 of the License,
+* or (at your option) any later version.
+*
+* VNLib.Utils is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with VNLib.Utils. If not, see http://www.gnu.org/licenses/.
+*/
+
+using System.IO;
+using System.Collections.Generic;
+using System.Collections.Concurrent;
+
+namespace VNLib.Utils.IO
+{
+ /// <summary>
+ /// A static class that provides simple ways to listen for changes to files in
+ /// the filesystem. This class is thread-safe and can be used to listen for
+ /// changes to multiple files at once.
+ /// </summary>
+ public static class FileWatcher
+ {
+ private static readonly ConcurrentDictionary<string, DirWatcher> Watchers = new();
+
+ /// <summary>
+ /// Starts listening for changes to a file at the specified path. If the file is already being
+ /// watched, the handler is added to the list of subscribers for that file.
+ /// </summary>
+ /// <param name="path">The path of the file to start listening for changes on</param>
+ /// <param name="handler">The file event handler</param>
+ public static void Subscribe(string path, IFSChangeHandler handler)
+ {
+ //Make sure file is fully qualified
+ path = Path.GetFullPath(path);
+
+ //Get an existing watcher or create a new one while the lock is held
+ DirWatcher watcher = Watchers.GetOrAdd(path, static p => new(p));
+
+ lock (watcher)
+ {
+ watcher.AddHandler(path, handler);
+ }
+ }
+
+ /// <summary>
+ /// Stops listening for changes to a file at the specified path. If the file is not being
+ /// watched, this method does nothing.
+ /// </summary>
+ /// <param name="path">The path to the file to stop listening for</param>
+ /// <param name="handler">The event handler to unsubscribe</param>
+ public static void Unsubscribe(string path, IFSChangeHandler handler)
+ {
+ if (Watchers.TryGetValue(path, out DirWatcher? watcher))
+ {
+ //Syncronize access to the watcher to be completely thread-safe
+ lock (watcher)
+ {
+ if (watcher.RemoveHandler(path, handler))
+ {
+ Watchers.TryRemove(path, out _);
+ watcher.Dispose();
+ }
+ }
+ }
+ }
+
+ private sealed class DirWatcher : VnDisposeable
+ {
+ private readonly ConcurrentDictionary<string, SingleFileSubPool> Handlers = new();
+ private readonly FileSystemWatcher Watcher;
+
+ public DirWatcher(string path)
+ {
+ //Setup new watcher
+ Watcher = new FileSystemWatcher(Path.GetDirectoryName(path)!)
+ {
+ Filter = "*.*",
+ EnableRaisingEvents = true,
+ IncludeSubdirectories = false, //We only care about top-level files
+ InternalBufferSize = 8192,
+ NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size | NotifyFilters.FileName | NotifyFilters.Security
+ };
+
+ Watcher.Changed += Watcher_Changed;
+ Watcher.Created += Watcher_Changed;
+ Watcher.Deleted += Watcher_Changed;
+ Watcher.Renamed += Watcher_Changed;
+ }
+
+ public bool RemoveHandler(string path, IFSChangeHandler handler)
+ {
+ if(Handlers.TryGetValue(Path.GetFileName(path), out SingleFileSubPool? watcher))
+ {
+ //Remove the single handler
+ if(watcher.RemoveHandler(handler))
+ {
+ //Handler watcher is empty, remove it from handlers store
+ _ = Handlers.TryRemove(Path.GetFileName(path), out _);
+ }
+ }
+
+ return Handlers.IsEmpty;
+ }
+
+ public void AddHandler(string path, IFSChangeHandler handler)
+ {
+ //Get the file name only
+ string fileName = Path.GetFileName(path);
+
+ //Get existing watcher or create a new one
+ if (Handlers.TryGetValue(fileName, out SingleFileSubPool? watcher))
+ {
+ watcher.AddHandler(handler);
+ }
+ else
+ {
+ watcher = new SingleFileSubPool(path);
+ watcher.AddHandler(handler);
+ Handlers.TryAdd(fileName, watcher);
+ }
+ }
+
+ private void Watcher_Changed(object sender, FileSystemEventArgs e)
+ {
+ //Only invoke subscribers if the specific file is being watched
+ if (e.Name is not null && Handlers.TryGetValue(e.Name, out SingleFileSubPool? watcher))
+ {
+ watcher.OnFileChanged(e);
+ }
+ }
+
+ protected override void Free()
+ {
+ Handlers.Clear();
+ Watcher.Dispose();
+ }
+
+ private sealed class SingleFileSubPool(string path)
+ {
+ private readonly List<IFSChangeHandler> Handlers = new();
+
+ public string FileName { get; } = Path.GetFileName(path);
+
+ public bool RemoveHandler(IFSChangeHandler handler)
+ {
+ Handlers.Remove(handler);
+ return Handlers.Count == 0;
+ }
+
+ public void AddHandler(IFSChangeHandler handler) => Handlers.Add(handler);
+
+ public void OnFileChanged(FileSystemEventArgs e) => Handlers.ForEach(h => h.OnFileChanged(e));
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/lib/Utils/src/IO/IFSChangeHandler.cs b/lib/Utils/src/IO/IFSChangeHandler.cs
new file mode 100644
index 0000000..b6dc63a
--- /dev/null
+++ b/lib/Utils/src/IO/IFSChangeHandler.cs
@@ -0,0 +1,40 @@
+/*
+* Copyright (c) 2024 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Utils
+* File: IFSChangeHandler.cs
+*
+* IFSChangeHandler.cs is part of VNLib.Utils which is part of the larger
+* VNLib collection of libraries and utilities.
+*
+* VNLib.Utils is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published
+* by the Free Software Foundation, either version 2 of the License,
+* or (at your option) any later version.
+*
+* VNLib.Utils is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with VNLib.Utils. If not, see http://www.gnu.org/licenses/.
+*/
+
+using System.IO;
+
+namespace VNLib.Utils.IO
+{
+ /// <summary>
+ /// Represents an object that can handle file system change events
+ /// </summary>
+ public interface IFSChangeHandler
+ {
+ /// <summary>
+ /// Raised when a file is changed in the filesystem
+ /// </summary>
+ /// <param name="e">The change event</param>
+ void OnFileChanged(FileSystemEventArgs e);
+ }
+} \ No newline at end of file
diff --git a/lib/Utils/src/IO/InMemoryTemplate.cs b/lib/Utils/src/IO/InMemoryTemplate.cs
deleted file mode 100644
index 5a4a799..0000000
--- a/lib/Utils/src/IO/InMemoryTemplate.cs
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Utils
-* File: InMemoryTemplate.cs
-*
-* InMemoryTemplate.cs is part of VNLib.Utils which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* VNLib.Utils is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published
-* by the Free Software Foundation, either version 2 of the License,
-* or (at your option) any later version.
-*
-* VNLib.Utils is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with VNLib.Utils. If not, see http://www.gnu.org/licenses/.
-*/
-
-using System;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-
-using VNLib.Utils.Extensions;
-
-namespace VNLib.Utils.IO
-{
- /// <summary>
- /// Represents a lazily loaded file stored in memory, with a change mointor
- /// that reloads the template if the file was modified in the filesystem
- /// </summary>
- public abstract class InMemoryTemplate : VnDisposeable
- {
- protected ManualResetEventSlim TemplateLock;
- private readonly FileSystemWatcher? Watcher;
- private bool Modified;
- private VnMemoryStream templateBuffer;
- protected readonly FileInfo TemplateFile;
-
- /// <summary>
- /// Gets the name of the template
- /// </summary>
- public abstract string TemplateName { get; }
-
- /// <summary>
- /// Creates a new in-memory copy of a file that will detect changes and refresh
- /// </summary>
- /// <param name="listenForChanges">Should changes to the template file be moniored for changes, and reloaded as necessary</param>
- /// <param name="path">The path of the file template</param>
- protected InMemoryTemplate(string path, bool listenForChanges = true)
- {
- TemplateFile = new FileInfo(path);
- TemplateLock = new(true);
- //Make sure the file exists
- if (!TemplateFile.Exists)
- {
- throw new FileNotFoundException("Template file does not exist");
- }
- if (listenForChanges)
- {
- //Setup a watcher to reload the template when modified
- Watcher = new FileSystemWatcher(TemplateFile.DirectoryName!)
- {
- EnableRaisingEvents = true,
- IncludeSubdirectories = false,
- NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size
- };
- Watcher.Changed += Watcher_Changed;
- }
- //Set modified flag to make sure the template is read on first use
- this.Modified = true;
- }
-
- private void Watcher_Changed(object sender, FileSystemEventArgs e)
- {
- //Make sure the event was raied for this template
- if (!e.FullPath.Equals(TemplateFile.FullName, StringComparison.OrdinalIgnoreCase))
- {
- return;
- }
- TemplateLock.Reset();
- try
- {
- //Set modified flag
- Modified = true;
- //Refresh the fileinfo object
- TemplateFile.Refresh();
- //Invoke onmodifed function
- OnModifed();
- }
- finally
- {
- TemplateLock.Set();
- }
- }
-
- /// <summary>
- /// Gets a cached copy of the template data
- /// </summary>
- protected VnMemoryStream GetTemplateData()
- {
- //Make sure access is synchronized incase the file gets updated during access on another thread
- TemplateLock.Wait();
- //Determine if the file has been modified and needs to be reloaded
- if (Modified)
- {
- TemplateLock.Reset();
- try
- {
- //Read a new copy of the templte into mem
- ReadFile();
- }
- finally
- {
- TemplateLock.Set();
- }
- }
- //Return a copy of the memory stream
- return templateBuffer.GetReadonlyShallowCopy();
- }
- /// <summary>
- /// Updates the internal copy of the file to its memory representation
- /// </summary>
- protected void ReadFile()
- {
- //Open the file stream
- using FileStream fs = TemplateFile.OpenRead();
- //Dispose the old template buffer
- templateBuffer?.Dispose();
- //Create a new stream for storing the cached copy
- VnMemoryStream newBuf = new();
- try
- {
- fs.CopyTo(newBuf, null);
- }
- catch
- {
- newBuf.Dispose();
- throw;
- }
- //Create the readonly copy
- templateBuffer = VnMemoryStream.CreateReadonly(newBuf);
- //Clear the modified flag
- Modified = false;
- }
- /// <summary>
- /// Updates the internal copy of the file to its memory representation, asynchronously
- /// </summary>
- /// <param name="cancellationToken"></param>
- /// <returns>A task that completes when the file has been copied into memory</returns>
- protected async Task ReadFileAsync(CancellationToken cancellationToken = default)
- {
- //Open the file stream
- await using FileStream fs = TemplateFile.OpenRead();
- //Dispose the old template buffer
- templateBuffer?.Dispose();
- //Create a new stream for storing the cached copy
- VnMemoryStream newBuf = new();
- try
- {
- //Copy async
- await fs.CopyToAsync(newBuf, 8192, Memory.MemoryUtil.Shared, cancellationToken);
- }
- catch
- {
- newBuf.Dispose();
- throw;
- }
- //Create the readonly copy
- templateBuffer = VnMemoryStream.CreateReadonly(newBuf);
- //Clear the modified flag
- Modified = false;
- }
-
- /// <summary>
- /// Invoked when the template file has been modifed. Note: This event is raised
- /// while the <see cref="TemplateLock"/> is held.
- /// </summary>
- protected abstract void OnModifed();
-
- ///<inheritdoc/>
- protected override void Free()
- {
- //Dispose the watcher
- Watcher?.Dispose();
- //free the stream
- templateBuffer?.Dispose();
- }
- }
-} \ No newline at end of file
diff --git a/lib/Utils/src/IO/VnMemoryStream.cs b/lib/Utils/src/IO/VnMemoryStream.cs
index 885d9c2..ed8ed5a 100644
--- a/lib/Utils/src/IO/VnMemoryStream.cs
+++ b/lib/Utils/src/IO/VnMemoryStream.cs
@@ -28,7 +28,6 @@ using System.Buffers;
using System.Threading;
using System.Diagnostics;
using System.Threading.Tasks;
-using System.Runtime.InteropServices;
using VNLib.Utils.Memory;
using VNLib.Utils.Extensions;
@@ -520,11 +519,7 @@ namespace VNLib.Utils.IO
///<inheritdoc/>
///<exception cref="OutOfMemoryException"></exception>
- public override void WriteByte(byte value)
- {
- Span<byte> buf = MemoryMarshal.CreateSpan(ref value, 1);
- Write(buf);
- }
+ public override void WriteByte(byte value) => Write(new Span<byte>(ref value));
/// <summary>
/// Allocates and copies internal buffer to new managed byte[]
diff --git a/lib/Utils/src/IO/VnStreamWriter.cs b/lib/Utils/src/IO/VnStreamWriter.cs
index 5ec65fc..ddebc07 100644
--- a/lib/Utils/src/IO/VnStreamWriter.cs
+++ b/lib/Utils/src/IO/VnStreamWriter.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Utils
@@ -130,11 +130,7 @@ namespace VNLib.Utils.IO
}
///<inheritdoc/>
- public override void Write(char value)
- {
- ReadOnlySpan<char> tbuf = MemoryMarshal.CreateSpan(ref value, 0x01);
- Write(tbuf);
- }
+ public override void Write(char value) => Write(new Span<char>(ref value));
///<inheritdoc/>
public override void Write(object? value) => Write(value?.ToString());
@@ -310,15 +306,9 @@ namespace VNLib.Utils.IO
Close();
base.Dispose(disposing);
}
-
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void Check()
- {
- if (closed)
- {
- throw new ObjectDisposedException("The stream is closed");
- }
- }
+ private void Check() => ObjectDisposedException.ThrowIf(closed, this);
///<inheritdoc/>
public override async ValueTask DisposeAsync()
diff --git a/lib/Utils/src/Memory/Caching/LRUCache.cs b/lib/Utils/src/Memory/Caching/LRUCache.cs
index 4cadc9d..52b81a5 100644
--- a/lib/Utils/src/Memory/Caching/LRUCache.cs
+++ b/lib/Utils/src/Memory/Caching/LRUCache.cs
@@ -32,7 +32,7 @@ namespace VNLib.Utils.Memory.Caching
/// </summary>
/// <typeparam name="TKey">The key for O(1) lookups</typeparam>
/// <typeparam name="TValue">The value to store within cache</typeparam>
- public abstract class LRUCache<TKey, TValue> : LRUDataStore<TKey, TValue> where TKey : notnull
+ public abstract class LRUCache<TKey, TValue> : LRUCollection<TKey, TValue> where TKey : notnull
{
///<inheritdoc/>
protected LRUCache(): base()
@@ -59,7 +59,7 @@ namespace VNLib.Utils.Memory.Caching
/// Adds a new record to the LRU cache
/// </summary>
/// <param name="item">A <see cref="KeyValuePair{TKey, TValue}"/> to add to the cache store</param>
- public override void Add(in KeyValuePair<TKey, TValue> item)
+ public override void Add(ref readonly KeyValuePair<TKey, TValue> item)
{
//See if the store is at max capacity and an item needs to be evicted
if (Count == MaxCapacity)
@@ -123,7 +123,7 @@ namespace VNLib.Utils.Memory.Caching
/// Invoked when a record is evicted from the cache
/// </summary>
/// <param name="evicted">The record that is being evicted</param>
- protected abstract void Evicted(ref KeyValuePair<TKey, TValue> evicted);
+ protected abstract void Evicted(ref readonly KeyValuePair<TKey, TValue> evicted);
/// <summary>
/// Invoked when an entry was requested and was not found in cache.
diff --git a/lib/Utils/src/Memory/Caching/LRUDataStore.cs b/lib/Utils/src/Memory/Caching/LRUCollection.cs
index c1eb22b..522108c 100644
--- a/lib/Utils/src/Memory/Caching/LRUDataStore.cs
+++ b/lib/Utils/src/Memory/Caching/LRUCollection.cs
@@ -1,11 +1,11 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Utils
-* File: LRUDataStore.cs
+* File: LRUCollection.cs
*
-* LRUDataStore.cs is part of VNLib.Utils which is part of the larger
+* LRUCollection.cs is part of VNLib.Utils which is part of the larger
* VNLib collection of libraries and utilities.
*
* VNLib.Utils is free software: you can redistribute it and/or modify
@@ -35,7 +35,11 @@ namespace VNLib.Utils.Memory.Caching
/// </summary>
/// <typeparam name="TKey">A key used for O(1) lookups</typeparam>
/// <typeparam name="TValue">A value to store</typeparam>
- public abstract class LRUDataStore<TKey, TValue> : IDictionary<TKey, TValue>, IReadOnlyDictionary<TKey, TValue>, IReadOnlyCollection<TValue>, IEnumerable<KeyValuePair<TKey, TValue>>
+ public abstract class LRUCollection<TKey, TValue> :
+ IDictionary<TKey, TValue>,
+ IReadOnlyDictionary<TKey, TValue>,
+ IReadOnlyCollection<TValue>,
+ IEnumerable<KeyValuePair<TKey, TValue>>
where TKey: notnull
{
/// <summary>
@@ -51,40 +55,40 @@ namespace VNLib.Utils.Memory.Caching
protected LinkedList<KeyValuePair<TKey, TValue>> List { get; }
/// <summary>
- /// Initializes an empty <see cref="LRUDataStore{TKey, TValue}"/>
+ /// Initializes an empty <see cref="LRUCollection{TKey, TValue}"/>
/// </summary>
- protected LRUDataStore() : this(EqualityComparer<TKey>.Default)
+ protected LRUCollection() : this(EqualityComparer<TKey>.Default)
{ }
/// <summary>
- /// Initializes an empty <see cref="LRUDataStore{TKey, TValue}"/> and sets
+ /// Initializes an empty <see cref="LRUCollection{TKey, TValue}"/> and sets
/// the lookup table's inital capacity
/// </summary>
/// <param name="initialCapacity">LookupTable initial capacity</param>
- protected LRUDataStore(int initialCapacity)
+ protected LRUCollection(int initialCapacity)
{
LookupTable = new(initialCapacity);
List = new();
}
/// <summary>
- /// Initializes an empty <see cref="LRUDataStore{TKey, TValue}"/> and uses the
+ /// Initializes an empty <see cref="LRUCollection{TKey, TValue}"/> and uses the
/// specified keycomparison
/// </summary>
/// <param name="keyComparer">A <see cref="IEqualityComparer{T}"/> used by the Lookuptable to compare keys</param>
- protected LRUDataStore(IEqualityComparer<TKey> keyComparer)
+ protected LRUCollection(IEqualityComparer<TKey> keyComparer)
{
LookupTable = new(keyComparer);
List = new();
}
/// <summary>
- /// Initializes an empty <see cref="LRUDataStore{TKey, TValue}"/> and uses the
+ /// Initializes an empty <see cref="LRUCollection{TKey, TValue}"/> and uses the
/// specified keycomparison, and sets the lookup table's initial capacity
/// </summary>
/// <param name="initialCapacity">LookupTable initial capacity</param>
/// <param name="keyComparer">A <see cref="IEqualityComparer{T}"/> used by the Lookuptable to compare keys</param>
- protected LRUDataStore(int initialCapacity, IEqualityComparer<TKey> keyComparer)
+ protected LRUCollection(int initialCapacity, IEqualityComparer<TKey> keyComparer)
{
LookupTable = new(initialCapacity, keyComparer);
List = new();
@@ -163,7 +167,7 @@ namespace VNLib.Utils.Memory.Caching
}
///<inheritdoc/>
- public bool Remove(in KeyValuePair<TKey, TValue> item) => Remove(item.Key);
+ public bool Remove(ref readonly KeyValuePair<TKey, TValue> item) => Remove(item.Key);
///<inheritdoc/>
IEnumerator IEnumerable.GetEnumerator() => List.GetEnumerator();
@@ -180,7 +184,7 @@ namespace VNLib.Utils.Memory.Caching
/// Adds the specified record to the store and places it at the end of the LRU queue
/// </summary>
/// <param name="item">The item to add</param>
- public virtual void Add(in KeyValuePair<TKey, TValue> item)
+ public virtual void Add(ref readonly KeyValuePair<TKey, TValue> item)
{
//Init new ll node
LinkedListNode<KeyValuePair<TKey, TValue>> newNode = new(item);
@@ -205,7 +209,7 @@ namespace VNLib.Utils.Memory.Caching
/// </summary>
/// <param name="item">The record to search for</param>
/// <returns>True if the key was found in the store and the value equals the stored value, false otherwise</returns>
- public virtual bool Contains(in KeyValuePair<TKey, TValue> item)
+ public virtual bool Contains(ref readonly KeyValuePair<TKey, TValue> item)
{
if (LookupTable.TryGetValue(item.Key, out LinkedListNode<KeyValuePair<TKey, TValue>>? lookup))
{
diff --git a/lib/Utils/src/Memory/MemoryHandle.cs b/lib/Utils/src/Memory/MemoryHandle.cs
index 09d4c32..c5cc295 100644
--- a/lib/Utils/src/Memory/MemoryHandle.cs
+++ b/lib/Utils/src/Memory/MemoryHandle.cs
@@ -118,7 +118,7 @@ namespace VNLib.Utils.Memory
/// <param name="initial">The initial block of allocated memory to wrap</param>
internal MemoryHandle(IUnmangedHeap heap, IntPtr initial, nuint elements, bool zero) : base(true)
{
- //Set element size (always allocate at least 1 object)
+ //Set element size
_length = elements;
ZeroMemory = zero;
//assign heap ref
diff --git a/lib/Utils/src/Memory/MemoryUtil.CopyUtilCore.cs b/lib/Utils/src/Memory/MemoryUtil.CopyUtilCore.cs
new file mode 100644
index 0000000..bcc5be9
--- /dev/null
+++ b/lib/Utils/src/Memory/MemoryUtil.CopyUtilCore.cs
@@ -0,0 +1,313 @@
+/*
+* Copyright (c) 2024 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Utils
+* File: MemoryUtil.CopyUtilCore.cs
+*
+* MemoryUtil.CopyUtilCore.cs is part of VNLib.Utils which is part
+* of the larger VNLib collection of libraries and utilities.
+*
+* VNLib.Utils is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published
+* by the Free Software Foundation, either version 2 of the License,
+* or (at your option) any later version.
+*
+* VNLib.Utils is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with VNLib.Utils. If not, see http://www.gnu.org/licenses/.
+*/
+
+using System;
+using System.Reflection;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+using VNLib.Utils.Resources;
+
+namespace VNLib.Utils.Memory
+{
+
+ public static unsafe partial class MemoryUtil
+ {
+ private static class CopyUtilCore
+ {
+ const nuint _avx32ByteAlignment = 0x20u;
+
+ private static readonly ReflectedInternalMemmove _reflectedMemmove = new();
+ private static readonly FallbackUnsafeMemmove _fallbackMemmove = new();
+ private static readonly FallbackBufferCopy _bufferCopy = new();
+ private static readonly AvxCopyStrategy _avxCopy = new();
+
+ /// <summary>
+ /// Gets a value that indicates if the platform supports hardware
+ /// acceleration for memmove operations.
+ /// </summary>
+ public static readonly bool IsHwAccelerationSupported = _avxCopy.Features.HasFlag(CopyFeatures.HwAccelerated);
+
+ /*
+ * The following function allows callers to determine if a memmove
+ * operation may require pinning memory to complete a copy operation.
+ *
+ * If known ahead of time, the caller may be able to optimize the
+ * pinning mechanism to avoid the GC overhead of pinning memory.
+ *
+ * The caller will then pass pointers as references to the memmove
+ * function that may fix pointers in memory.
+ */
+
+ /// <summary>
+ /// Determines if the given block size to copy will require memory pinning.
+ /// </summary>
+ /// <param name="byteSize">The number of bytes to copy in a memmove operation</param>
+ /// <param name="forceAcceleration">A value that indicates that hardware acceleration is requested</param>
+ /// <returns>A value that indicates if pinning will be required</returns>
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool RequiresPinning(nuint byteSize, bool forceAcceleration)
+ {
+ /*
+ * Pinnin is required, if reflected memmove is not supported on the platform
+ * AND the size of the data to copy is larger than 32 bit width.
+ *
+ * Otherwise if accleration is forced, pinning will always be required.
+ */
+
+ if(byteSize > uint.MaxValue && _reflectedMemmove.Features == CopyFeatures.NotSupported)
+ {
+ return true;
+ }
+
+ if((forceAcceleration || Is32ByteAligned(byteSize)) && _avxCopy.Features != CopyFeatures.NotSupported)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ /*
+ * Why does this function exist. For centralized memmove operations primarily.
+ *
+ * When the block is known to be small, all of the brances in memmove can be
+ * alot of overhead including the possability of Avx2 being used for really
+ * small blocks if they are aligned. If the block is known to be small, we
+ * can just skip all of that and use the fastest method for small blocks,
+ * which is currently the Unsafe.CopyBlock method. It is intrinsic to
+ * the CLR at the moment.
+ */
+
+ /// <summary>
+ /// Copies a known small block of memory from one location to another,
+ /// as fast as possible. Hardware acceleration is not used.
+ /// </summary>
+ /// <param name="srcByte">A reference to the first byte in the source sequence</param>
+ /// <param name="dstByte">A reference to the first byte in the target sequence</param>
+ /// <param name="byteCount">The number of bytes to copy</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+ public static void SmallMemmove(ref readonly byte srcByte, ref byte dstByte, uint byteCount)
+ {
+ Debug.Assert(!Unsafe.IsNullRef(in srcByte), "Null source reference passed to MemmoveByRef");
+ Debug.Assert(!Unsafe.IsNullRef(in dstByte), "Null destination reference passed to MemmoveByRef");
+
+ _fallbackMemmove.Memmove(in srcByte, ref dstByte, byteCount);
+ return;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+ public static void Memmove(ref readonly byte srcByte, ref byte dstByte, nuint byteCount, bool forceAcceleration)
+ {
+ Debug.Assert(!Unsafe.IsNullRef(in srcByte), "Null source reference passed to MemmoveByRef");
+ Debug.Assert(!Unsafe.IsNullRef(in dstByte), "Null destination reference passed to MemmoveByRef");
+
+ //Check for 64bit copy
+ if(byteCount > uint.MaxValue)
+ {
+ //We need a 64bit copy strategy
+ if(forceAcceleration || Is32ByteAligned(byteCount))
+ {
+ //Must be supported
+ if(_avxCopy.Features != CopyFeatures.NotSupported)
+ {
+ //Copy
+ _avxCopy.Memmove(in srcByte, ref dstByte, byteCount);
+ return;
+ }
+ }
+
+ //try reflected memove incase it supports 64bit blocks
+ if(_reflectedMemmove.Features != CopyFeatures.NotSupported)
+ {
+ //Copy
+ _reflectedMemmove.Memmove(in srcByte, ref dstByte, byteCount);
+ return;
+ }
+
+ //Fallback to buffer copy, caller should have used pinning
+ _bufferCopy.Memmove(in srcByte, ref dstByte, byteCount);
+ return;
+ }
+
+ //32byte copy
+
+ //Try hardware acceleration if supported and aligned
+ if ((forceAcceleration || Is32ByteAligned(byteCount)) && _avxCopy.Features != CopyFeatures.NotSupported)
+ {
+ //Copy
+ _avxCopy.Memmove(in srcByte, ref dstByte, byteCount);
+ return;
+ }
+
+ //fallback to unsafe.copy on 32bit copy
+ _fallbackMemmove.Memmove(in srcByte, ref dstByte, byteCount);
+ return;
+ }
+
+ /// <summary>
+ /// Determines if the given size 32-byte aligned
+ /// </summary>
+ /// <param name="size">The block size to test</param>
+ /// <returns>A value that indicates if the block size is 32byte aligned</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ static bool Is32ByteAligned(nuint size) => unchecked(size % _avx32ByteAlignment) == 0;
+
+ private enum CopyFeatures
+ {
+ None = 0,
+ NotSupported = 1,
+ Supports64Bit = 2,
+ HwAccelerated = 4
+ }
+
+ private interface ICopyStrategy
+ {
+ CopyFeatures Features { get; }
+
+ void Memmove(ref readonly byte src, ref byte dst, nuint byteCount);
+ }
+
+ private sealed class ReflectedInternalMemmove : ICopyStrategy
+ {
+ /*
+ * Dirty little trick to access internal Buffer.Memmove method for
+ * large references. May not always be supported, so optional safe
+ * guards are in place.
+ */
+ private delegate void BigMemmove(ref byte dest, ref readonly byte src, nuint len);
+ private static readonly BigMemmove? _clrMemmove = ManagedLibrary.TryGetStaticMethod<BigMemmove>(typeof(Buffer), "Memmove", BindingFlags.NonPublic);
+
+ //Cache features flags
+ private readonly CopyFeatures _features = _clrMemmove is null ? CopyFeatures.NotSupported : CopyFeatures.Supports64Bit;
+
+ ///<inheritdoc/>
+ public CopyFeatures Features => _features;
+
+ ///<inheritdoc/>
+ [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+ public void Memmove(ref readonly byte src, ref byte dst, nuint byteCount)
+ {
+ Debug.Assert(_clrMemmove != null, "Memmove delegate is null and flags assumed is was supported");
+ _clrMemmove!.Invoke(ref dst, in src, byteCount);
+ }
+ }
+
+ private sealed class FallbackUnsafeMemmove : ICopyStrategy
+ {
+ ///<inheritdoc/>
+ public CopyFeatures Features => CopyFeatures.None;
+
+ ///<inheritdoc/>
+ public void Memmove(ref readonly byte src, ref byte dst, nuint byteCount)
+ {
+ Debug.Assert(byteCount < uint.MaxValue, "Byte count must be less than uint.MaxValue and flags assumed 64bit blocks were supported");
+ Unsafe.CopyBlock(ref dst, in src, (uint)byteCount);
+ }
+ }
+
+ private sealed class FallbackBufferCopy : ICopyStrategy
+ {
+ /*
+ * This class is considered a fallback because it require's a fixed
+ * statment to get a pointer from a reference. This should avoided
+ * unless pinning happens and pointers are converted to references.
+ *
+ * Then it is a zero cost fixed statment capturing pointers from references
+ * that were already pinned.
+ */
+
+ ///<inheritdoc/>
+ public CopyFeatures Features => CopyFeatures.Supports64Bit;
+
+ ///<inheritdoc/>
+ [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+ public void Memmove(ref readonly byte src, ref byte dst, nuint byteCount)
+ {
+ /*
+ * We assume that the references passed are not null and are
+ * already pinned, so this statement is zero cost.
+ */
+ fixed (byte* srcPtr = &src, dstPtr = &dst)
+ {
+ Buffer.MemoryCopy(srcPtr, dstPtr, byteCount, byteCount);
+ }
+ }
+ }
+
+ private sealed class AvxCopyStrategy : ICopyStrategy
+ {
+ const nuint _avx32ByteAlignment = 0x20u;
+
+ //If avx is supported, then set 64bit flags and hw acceleration
+ private readonly CopyFeatures _features = Avx2.IsSupported ? CopyFeatures.HwAccelerated | CopyFeatures.Supports64Bit : CopyFeatures.NotSupported;
+
+ ///<inheritdoc/>
+ public CopyFeatures Features => _features;
+
+ ///<inheritdoc/>
+ [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+ public void Memmove(ref readonly byte src, ref byte dst, nuint byteCount)
+ {
+ Debug.Assert(Avx2.IsSupported, "AVX2 is not supported on this platform");
+ Debug.Assert(_avx32ByteAlignment == (nuint)Vector256<byte>.Count, "AVX2 vector size is not 32 bytes");
+
+ //determine the number of loops
+ nuint loopCount = byteCount / _avx32ByteAlignment;
+
+ //Remaining bytes if not exactly 32 byte aligned
+ nuint remaingBytes = byteCount % _avx32ByteAlignment;
+
+ fixed (byte* srcPtr = &src, dstPtr = &dst)
+ {
+ //local mutable copies
+ byte* srcOffset = srcPtr;
+ byte* dstOffset = dstPtr;
+
+ for (nuint i = 0; i < loopCount; i++)
+ {
+ //avx vector load
+ Vector256<byte> srcVector = Avx.LoadVector256(srcOffset);
+ Avx.Store(dstOffset, srcVector);
+
+ //Upshift pointers
+ srcOffset += _avx32ByteAlignment;
+ dstOffset += _avx32ByteAlignment;
+ }
+
+ //finish copy manually since it will always be less than 32 bytes
+ for (nuint i = 0; i < remaingBytes; i++)
+ {
+ dstOffset[i] = srcOffset[i];
+ }
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/lib/Utils/src/Memory/MemoryUtil.cs b/lib/Utils/src/Memory/MemoryUtil.cs
index ab1b0ec..774aca3 100644
--- a/lib/Utils/src/Memory/MemoryUtil.cs
+++ b/lib/Utils/src/Memory/MemoryUtil.cs
@@ -30,8 +30,6 @@ using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
-
-using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
using VNLib.Utils.Resources;
@@ -93,9 +91,6 @@ namespace VNLib.Utils.Memory
//Cache the system page size
private static readonly int SystemPageSize = Environment.SystemPageSize;
- //Cache avx2 support
- private static readonly bool IsAvx2Supported = Avx2.IsSupported;
-
/// <summary>
/// Provides a shared heap instance for the process to allocate memory from.
/// </summary>
@@ -148,8 +143,8 @@ namespace VNLib.Utils.Memory
* If heap is allocated and the heap type is a tracked heap,
* get the heap's stats, otherwise return an empty handle
*/
- return _sharedHeap.IsValueCreated && _sharedHeap.Value is TrackedHeapWrapper h
- ? h.GetCurrentStats() : new HeapStatistics();
+ return _sharedHeap.IsValueCreated && _sharedHeap.Value is TrackedHeapWrapper h
+ ? h.GetCurrentStats() : default;
}
/// <summary>
@@ -247,11 +242,12 @@ namespace VNLib.Utils.Memory
{
return;
}
-
- ref T r0 = ref MemoryMarshal.GetReference(block);
//Calls memset
- ZeroByRef(ref r0, (uint)block.Length);
+ ZeroByRef(
+ ref Refs.AsByte(block, 0),
+ (uint)block.Length
+ );
}
/// <summary>
@@ -337,8 +333,10 @@ namespace VNLib.Utils.Memory
CheckBounds(array, 0, count);
//Get array data reference
- ref T arrRef = ref MemoryMarshal.GetArrayDataReference(array);
- ZeroByRef(ref arrRef, count);
+ ZeroByRef(
+ ref MemoryMarshal.GetArrayDataReference(array),
+ count
+ );
}
/// <summary>
@@ -350,10 +348,7 @@ namespace VNLib.Utils.Memory
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
public static void InitializeBlock<T>(ref T block, int itemCount) where T : struct
{
- if (Unsafe.IsNullRef(ref block))
- {
- throw new ArgumentNullException(nameof(block));
- }
+ ThrowIfNullRef(ref block, nameof(block));
if (itemCount <= 0)
{
@@ -372,10 +367,7 @@ namespace VNLib.Utils.Memory
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
public static void InitializeBlock<T>(T* block, int itemCount) where T : unmanaged
{
- if (block == null)
- {
- throw new ArgumentNullException(nameof(block));
- }
+ ArgumentNullException.ThrowIfNull(block);
InitializeBlock(ref *block, itemCount);
}
@@ -397,10 +389,7 @@ namespace VNLib.Utils.Memory
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ZeroStruct<T>(ref T structRef) where T : unmanaged
{
- if (Unsafe.IsNullRef(ref structRef))
- {
- throw new ArgumentNullException(nameof(structRef));
- }
+ ThrowIfNullRef(ref structRef, nameof(structRef));
//Get a byte reference to the structure
ref byte byteRef = ref Unsafe.As<T, byte>(ref structRef);
@@ -416,10 +405,7 @@ namespace VNLib.Utils.Memory
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ZeroStruct<T>(T* structPtr) where T : unmanaged
{
- if (structPtr == null)
- {
- throw new ArgumentNullException(nameof(structPtr));
- }
+ ArgumentNullException.ThrowIfNull(structPtr);
ZeroStruct(ref *structPtr);
}
@@ -450,7 +436,7 @@ namespace VNLib.Utils.Memory
* large references. May not always be supported, so optional safe
* guards are in place.
*/
- private delegate void BigMemmove(ref byte dest, ref byte src, nuint len);
+ private delegate void BigMemmove(ref byte dest, ref readonly byte src, nuint len);
private static readonly BigMemmove? _clrMemmove = ManagedLibrary.TryGetStaticMethod<BigMemmove>(typeof(Buffer), "Memmove", System.Reflection.BindingFlags.NonPublic);
/// <summary>
@@ -461,21 +447,15 @@ namespace VNLib.Utils.Memory
/// <param name="source">A referrence to the first byte of source data to copy from</param>
/// <param name="target">An initialized target structure to copy data to</param>
/// <exception cref="ArgumentNullException"></exception>
- public static void CopyStruct<T>(ref byte source, ref T target) where T : unmanaged
+ public static void CopyStruct<T>(ref readonly byte source, ref T target) where T : unmanaged
{
- if (Unsafe.IsNullRef(ref target))
- {
- throw new ArgumentNullException(nameof(target));
- }
- if (Unsafe.IsNullRef(ref source))
- {
- throw new ArgumentNullException(nameof(source));
- }
+ ThrowIfNullRef(in source, nameof(target));
+ ThrowIfNullRef(ref target, nameof(target));
//Recover byte reference of target struct
ref byte dst = ref Unsafe.As<T, byte>(ref target);
- Unsafe.CopyBlockUnaligned(ref dst, ref source, (uint)sizeof(T));
+ Unsafe.CopyBlockUnaligned(ref dst, in source, (uint)sizeof(T));
}
/// <summary>
@@ -490,19 +470,13 @@ namespace VNLib.Utils.Memory
/// <param name="source">A referrence to the first byte of source data to copy from</param>
/// <param name="target">A reference to the first byte of the memory location to copy the struct data to</param>
/// <exception cref="ArgumentNullException"></exception>
- public static void CopyStruct<T>(ref T source, ref byte target) where T : unmanaged
+ public static void CopyStruct<T>(scoped ref readonly T source, ref byte target) where T : unmanaged
{
- if (Unsafe.IsNullRef(ref source))
- {
- throw new ArgumentNullException(nameof(source));
- }
- if (Unsafe.IsNullRef(ref target))
- {
- throw new ArgumentNullException(nameof(target));
- }
+ ThrowIfNullRef(in source, nameof(source));
+ ThrowIfNullRef(in target, nameof(target));
//Recover byte reference to struct
- ref byte src = ref Unsafe.As<T, byte>(ref source);
+ ref byte src = ref Unsafe.As<T, byte>(ref Unsafe.AsRef(in source));
//Memmove
Unsafe.CopyBlockUnaligned(ref target, ref src, (uint)sizeof(T));
@@ -518,10 +492,10 @@ namespace VNLib.Utils.Memory
/// <param name="target">A pointer to initialized target structure to copy data to</param>
/// <exception cref="ArgumentNullException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void CopyStruct<T>(ref byte source, T* target) where T : unmanaged
+ public static void CopyStruct<T>(ref readonly byte source, T* target) where T : unmanaged
{
ArgumentNullException.ThrowIfNull(target);
- CopyStruct(ref source, ref *target);
+ CopyStruct(in source, ref *target);
}
/// <summary>
@@ -533,7 +507,7 @@ namespace VNLib.Utils.Memory
/// <param name="target">A pointer to initialized target structure to copy data to</param>
/// <exception cref="ArgumentNullException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void CopyStruct<T>(ref byte source, void* target) where T : unmanaged => CopyStruct(ref source, (T*)target);
+ public static void CopyStruct<T>(ref readonly byte source, void* target) where T : unmanaged => CopyStruct(in source, (T*)target);
/// <summary>
/// Copies structure data from a source sequence of data to the target structure reference.
@@ -623,12 +597,15 @@ namespace VNLib.Utils.Memory
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void CopyStruct<T>(ref T source, Span<byte> target) where T : unmanaged
+ public static void CopyStruct<T>(scoped ref readonly T source, Span<byte> target) where T : unmanaged
{
//check that the span is large enough to hold the structure
ArgumentOutOfRangeException.ThrowIfLessThan(target.Length, sizeof(T), nameof(target));
- CopyStruct(ref source, ref MemoryMarshal.GetReference(target));
+ CopyStruct(
+ in source,
+ ref Refs.AsByte(target, 0)
+ );
}
/// <summary>
@@ -693,22 +670,16 @@ namespace VNLib.Utils.Memory
/// <param name="source">A reference to the source structure to copy from</param>
/// <param name="target">A reference to the target structure to copy to</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void CloneStruct<T>(ref T source, ref T target) where T : unmanaged
+ public static void CloneStruct<T>(scoped ref readonly T source, ref T target) where T : unmanaged
{
- if (Unsafe.IsNullRef(ref source))
- {
- throw new ArgumentNullException(nameof(source));
- }
- if (Unsafe.IsNullRef(ref target))
- {
- throw new ArgumentNullException(nameof(target));
- }
-
- //Byte refs
- ref byte src = ref Unsafe.As<T, byte>(ref source);
- ref byte dst = ref Unsafe.As<T, byte>(ref target);
+ ThrowIfNullRef(in source, nameof(source));
+ ThrowIfNullRef(ref target, nameof(target));
- Unsafe.CopyBlockUnaligned(ref dst, ref src, (uint)sizeof(T));
+ Unsafe.CopyBlockUnaligned(
+ ref Refs.AsByte(ref target, 0),
+ ref Refs.AsByteR(in source, 0),
+ (uint)sizeof(T)
+ );
}
/// <summary>
@@ -738,9 +709,10 @@ namespace VNLib.Utils.Memory
/// <param name="sourceOffset">Source offset</param>
/// <param name="destOffset">Dest offset</param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
- public static void Copy<T>(ReadOnlySpan<T> source, int sourceOffset, IMemoryHandle<T> dest, nuint destOffset, int count) where T: struct
+ public static void Copy<T>(ReadOnlySpan<T> source, int sourceOffset, IMemoryHandle<T> dest, nuint destOffset, int count)
+ where T: struct
{
- ArgumentNullException.ThrowIfNull(dest, nameof(dest));
+ ArgumentNullException.ThrowIfNull(dest);
if (count == 0)
{
@@ -752,14 +724,12 @@ namespace VNLib.Utils.Memory
CheckBounds(dest, destOffset, (uint)count);
//Use memmove by ref
- bool success = CopyUtilCore.MemmoveByRef(
+ CopyUtilCore.Memmove(
ref Refs.AsByte(source, (nuint)sourceOffset),
ref Refs.AsByte(dest, destOffset),
ByteCount<T>((uint)count),
false
);
-
- Debug.Assert(success, "Memmove by ref call failed during a 32bit copy");
}
/// <summary>
@@ -772,9 +742,25 @@ namespace VNLib.Utils.Memory
/// <param name="destOffset">Dest element offset</param>
/// <param name="count">The number of elements to copy</param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void Copy<T>(ReadOnlyMemory<T> source, int sourceOffset, IMemoryHandle<T> dest, nuint destOffset, int count) where T : struct
- => Copy(source.Span, sourceOffset, dest, destOffset, count);
+ public static void Copy<T>(ReadOnlyMemory<T> source, int sourceOffset, IMemoryHandle<T> dest, nuint destOffset, int count)
+ where T : unmanaged
+ {
+ ArgumentNullException.ThrowIfNull(dest);
+
+ //Dest offset will never be negative so defer that to the validation stage
+ ValidateCopyArgs(sourceOffset, 0, count);
+
+ if (count == 0)
+ {
+ return;
+ }
+
+ //Create copy handles
+ RMemCopyHandle<T> src = new(source, (nuint)sourceOffset);
+ MemhandleCopyHandle<T> dst = new(dest, destOffset);
+
+ MemmoveInternal<T, RMemCopyHandle<T>, MemhandleCopyHandle<T>>(in src, in dst, (nuint)count, false);
+ }
/// <summary>
/// Copies data from source memory to destination memory of an umanged data type
@@ -788,7 +774,7 @@ namespace VNLib.Utils.Memory
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static void Copy<T>(IMemoryHandle<T> source, nint sourceOffset, Span<T> dest, int destOffset, int count) where T : struct
{
- ArgumentNullException.ThrowIfNull(source, nameof(source));
+ ArgumentNullException.ThrowIfNull(source);
//Validate source/dest/count
ValidateCopyArgs(sourceOffset, destOffset, count);
@@ -804,14 +790,12 @@ namespace VNLib.Utils.Memory
CheckBounds(dest, destOffset, count);
//Use memmove by ref
- bool success = CopyUtilCore.MemmoveByRef(
+ CopyUtilCore.Memmove(
ref Refs.AsByte(source, (nuint)sourceOffset),
ref Refs.AsByte(dest, (nuint)destOffset),
ByteCount<T>((uint)count),
false
);
-
- Debug.Assert(success, "Memmove by ref call failed during a 32bit copy");
}
/// <summary>
@@ -825,9 +809,26 @@ namespace VNLib.Utils.Memory
/// <param name="count">Number of elements to copy</param>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void Copy<T>(IMemoryHandle<T> source, nint sourceOffset, Memory<T> dest, int destOffset, int count) where T : struct
- => Copy(source, sourceOffset, dest.Span, destOffset, count);
+ public static void Copy<T>(IMemoryHandle<T> source, nint sourceOffset, Memory<T> dest, int destOffset, int count)
+ where T : unmanaged
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ //Validate source/dest/count
+ ValidateCopyArgs(sourceOffset, destOffset, count);
+
+ //Check count last for debug reasons
+ if (count == 0)
+ {
+ return;
+ }
+
+ //Create copy handles
+ MemhandleCopyHandle<T> src = new(source, (nuint)sourceOffset);
+ WMemCopyHandle<T> dst = new(dest, (nuint)destOffset);
+
+ MemmoveInternal<T, MemhandleCopyHandle<T>, WMemCopyHandle<T>>(in src, in dst, (nuint)count, false);
+ }
/// <summary>
/// Copies data from source memory to destination memory of an umanged data type
@@ -844,52 +845,19 @@ namespace VNLib.Utils.Memory
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static void Copy<T>(IMemoryHandle<T> source, nuint sourceOffset, IMemoryHandle<T> dest, nuint destOffset, nuint count) where T : unmanaged
{
- ArgumentNullException.ThrowIfNull(source, nameof(source));
- ArgumentNullException.ThrowIfNull(dest, nameof(dest));
-
- CheckBounds(source, sourceOffset, count);
- CheckBounds(dest, destOffset, count);
-
- //Get byte ref and byte count
- nuint byteCount = ByteCount<T>(count);
-
- if (!CopyUtilCore.MemmoveByRef(
- ref Refs.AsByte(source, sourceOffset),
- ref Refs.AsByte(dest, destOffset),
- byteCount,
- false
- )
- )
- {
- //Copying block larger than 32bit must be done with pointers
- using MemoryHandle srcH = source.Pin(0);
- using MemoryHandle dstH = dest.Pin(0);
-
- //Get pointers and add offsets
- T* srcOffset = ((T*)srcH.Pointer) + sourceOffset;
- T* dstOffset = ((T*)dstH.Pointer) + destOffset;
-
- //Copy memory
- Buffer.MemoryCopy(srcOffset, dstOffset, byteCount, byteCount);
- }
- }
+ ArgumentNullException.ThrowIfNull(source);
+ ArgumentNullException.ThrowIfNull(dest);
- private static void ValidateCopyArgs(nint sourceOffset, nint destOffset, nint count)
- {
- if(sourceOffset < 0)
+ //Check count last for debug reasons
+ if (count == 0)
{
- throw new ArgumentOutOfRangeException(nameof(sourceOffset), "Source offset must be a postive integer");
+ return;
}
- if(destOffset < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(destOffset), "Destination offset must be a positive integer");
- }
+ MemhandleCopyHandle<T> src = new(source, sourceOffset);
+ MemhandleCopyHandle<T> dst = new(dest, destOffset);
- if(count < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(count), "Count parameter must be a postitive integer");
- }
+ MemmoveInternal<T, MemhandleCopyHandle<T>, MemhandleCopyHandle<T>>(in src, in dst, count, false);
}
/// <summary>
@@ -901,47 +869,24 @@ namespace VNLib.Utils.Memory
/// <param name="source">The source memory handle to copy data from</param>
/// <param name="sourceOffset">The element offset to begin reading from</param>
/// <param name="dest">The destination array to write data to</param>
- /// <param name="destOffset"></param>
+ /// <param name="destOffset">The destination element offset</param>
/// <param name="count">The number of elements to copy</param>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static void CopyArray<T>(IMemoryHandle<T> source, nuint sourceOffset, T[] dest, nuint destOffset, nuint count) where T : unmanaged
{
- ArgumentNullException.ThrowIfNull(source, nameof(source));
- ArgumentNullException.ThrowIfNull(dest, nameof(dest));
+ ArgumentNullException.ThrowIfNull(source);
+ ArgumentNullException.ThrowIfNull(dest);
if (count == 0)
{
return;
}
- //Check bounds
- CheckBounds(source, sourceOffset, count);
- CheckBounds(dest, destOffset, count);
-
- //Get byte count
- nuint byteCount = ByteCount<T>(count);
-
- //Try to memove by ref first, otherwise fallback to pinning
- if (!CopyUtilCore.MemmoveByRef(
- ref Refs.AsByte(source, sourceOffset),
- ref Refs.AsByte(dest, destOffset),
- byteCount,
- false
- )
- )
- {
- //Copying block larger than 32bit must be done with pointers
- using MemoryHandle srcH = source.Pin(0);
- using MemoryHandle dstH = PinArrayAndGetHandle(dest, 0);
-
- //Get pointers and add offsets
- T* srcOffset = ((T*)srcH.Pointer) + sourceOffset;
- T* dstOffset = ((T*)dstH.Pointer) + destOffset;
+ MemhandleCopyHandle<T> src = new(source, sourceOffset);
+ ArrayCopyHandle<T> dst = new(dest, destOffset);
- //Copy memory
- Buffer.MemoryCopy(srcOffset, dstOffset, byteCount, byteCount);
- }
+ MemmoveInternal<T, MemhandleCopyHandle<T>, ArrayCopyHandle<T>>(in src, in dst, count, false);
}
/// <summary>
@@ -953,47 +898,89 @@ namespace VNLib.Utils.Memory
/// <param name="source">The source memory handle to copy data from</param>
/// <param name="sourceOffset">The element offset to begin reading from</param>
/// <param name="dest">The destination array to write data to</param>
- /// <param name="destOffset"></param>
+ /// <param name="destOffset">The detination element offset</param>
/// <param name="count">The number of elements to copy</param>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static void CopyArray<T>(T[] source, nuint sourceOffset, IMemoryHandle<T> dest, nuint destOffset, nuint count) where T : unmanaged
{
- ArgumentNullException.ThrowIfNull(source, nameof(source));
- ArgumentNullException.ThrowIfNull(dest, nameof(dest));
+ ArgumentNullException.ThrowIfNull(source);
+ ArgumentNullException.ThrowIfNull(dest);
if (count == 0)
{
return;
}
- //Check bounds
- CheckBounds(source, sourceOffset, count);
- CheckBounds(dest, destOffset, count);
+ ArrayCopyHandle<T> ach = new(source, sourceOffset);
+ MemhandleCopyHandle<T> mch = new(dest, destOffset);
- //Get byte count
- nuint byteCount = ByteCount<T>(count);
+ MemmoveInternal<T, ArrayCopyHandle<T>, MemhandleCopyHandle<T>>(in ach, in mch, count, false);
+ }
- //Try to memove by ref first, otherwise fallback to pinning
- if (!CopyUtilCore.MemmoveByRef(
- ref Refs.AsByte(source, sourceOffset),
- ref Refs.AsByte(dest, destOffset),
- byteCount,
- false
- )
- )
+ /// <summary>
+ /// Copies data from one managed array to another using the fastest method
+ /// available and hardware acceleration if supported.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="source">The source memory handle to copy data from</param>
+ /// <param name="sourceOffset">The element offset to begin reading from</param>
+ /// <param name="dest">The destination array to write data to</param>
+ /// <param name="destOffset">The detination element offset</param>
+ /// <param name="count">The number of elements to copy</param>
+ public static void CopyArray<T>(T[] source, nuint sourceOffset, T[] dest, nuint destOffset, nuint count)
+ where T : unmanaged
+ {
+ ArgumentNullException.ThrowIfNull(source);
+ ArgumentNullException.ThrowIfNull(dest);
+
+ //Check count last for debug reasons
+ if (count == 0)
{
- //Copying block larger than 32bit must be done with pointers
- using MemoryHandle srcH = PinArrayAndGetHandle(source, 0);
- using MemoryHandle dstH = dest.Pin(0);
+ return;
+ }
+
+ //Init copy handles and call memmove
+ ArrayCopyHandle<T> srcH = new(source, sourceOffset);
+ ArrayCopyHandle<T> dstH = new(dest, destOffset);
- //Get pointers and add offsets
- T* srcOffset = ((T*)srcH.Pointer) + sourceOffset;
- T* dstOffset = ((T*)dstH.Pointer) + destOffset;
+ MemmoveInternal<T, ArrayCopyHandle<T>, ArrayCopyHandle<T>>(in srcH, in dstH, count, false);
+ }
- //Copy memory
- Buffer.MemoryCopy(srcOffset, dstOffset, byteCount, byteCount);
+ /// <summary>
+ /// Optimized memmove for known small memory blocks. This method is faster than
+ /// <see cref="Memmove{T}(ref readonly T, nuint, ref T, nuint, nuint)"/> when the
+ /// number of elements to copy is known to be small.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="src">A readonly reference to the first element in the source memory sequence</param>
+ /// <param name="srcOffset">The number of elements to offset the source sequence by</param>
+ /// <param name="dst">A reference to the first element in the target memory sequence</param>
+ /// <param name="dstOffset">The number of elements to offset the destination pointer by</param>
+ /// <param name="elementCount">The number of elements to copy from source to destination memory</param>
+ /// <remarks>
+ /// WARNING: This is a low level api that cannot do bounds checking when using references. Be sure you
+ /// know what you are doing!
+ /// </remarks>
+ /// <exception cref="ArgumentNullException"></exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void SmallMemmove<T>(ref readonly T src, nuint srcOffset, ref T dst, nuint dstOffset, ushort elementCount)
+ where T: struct
+ {
+ ThrowIfNullRef(in src, nameof(src));
+ ThrowIfNullRef(in dst, nameof(dst));
+
+ if (elementCount == 0)
+ {
+ return;
}
+
+ //Keep all core memory related optimizations to the core class
+ CopyUtilCore.SmallMemmove(
+ in Refs.AsByteR(in src, srcOffset),
+ ref Refs.AsByte(ref dst, dstOffset),
+ (uint)ByteCount<T>(elementCount)
+ );
}
/// <summary>
@@ -1012,8 +999,23 @@ namespace VNLib.Utils.Memory
/// <param name="elementCount"></param>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="ArgumentNullException"></exception>
- public static void Memmove<T>(ref T src, nuint srcOffset, ref T dst, nuint dstOffset, nuint elementCount) where T : struct
- => Memmove(ref src, srcOffset, ref dst, dstOffset, elementCount, false);
+ public static void Memmove<T>(ref readonly T src, nuint srcOffset, ref T dst, nuint dstOffset, nuint elementCount) where T : struct
+ {
+ ThrowIfNullRef(in src, nameof(src));
+ ThrowIfNullRef(in dst, nameof(dst));
+
+ if (elementCount == 0)
+ {
+ return;
+ }
+
+ CopyUtilCore.Memmove(
+ in Refs.AsByteR(in src, srcOffset),
+ ref Refs.AsByte(ref dst, dstOffset),
+ ByteCount<T>(elementCount),
+ false
+ );
+ }
/// <summary>
/// Low level api for copying data from source memory to destination memory of an
@@ -1024,7 +1026,7 @@ namespace VNLib.Utils.Memory
/// </para>
/// <para>
/// If the <see cref="Avx.IsSupported"/> flag is false, this function will fallback to
- /// the default method used by <see cref="Memmove{T}(ref T, nuint, ref T, nuint, nuint)"/>
+ /// the default method used by <see cref="Memmove{T}(ref readonly T, nuint, ref T, nuint, nuint)"/>
/// </para>
/// </summary>
/// <remarks>
@@ -1039,35 +1041,80 @@ namespace VNLib.Utils.Memory
/// <param name="elementCount"></param>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="ArgumentNullException"></exception>
- public static void AcceleratedMemmove<T>(ref T src, nuint srcOffset, ref T dst, nuint dstOffset, nuint elementCount) where T : struct
- => Memmove(ref src, srcOffset, ref dst, dstOffset, elementCount, IsAvx2Supported);
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void Memmove<T>(ref T src, nuint srcOffset, ref T dst, nuint dstOffset, nuint elementCount, bool useAcceleration) where T : struct
+ public static void AcceleratedMemmove<T>(ref readonly T src, nuint srcOffset, ref T dst, nuint dstOffset, nuint elementCount) where T : struct
{
- if (Unsafe.IsNullRef(ref src))
+ ThrowIfNullRef(in src, nameof(src));
+ ThrowIfNullRef(in dst, nameof(dst));
+
+ if(elementCount == 0)
{
- throw new ArgumentNullException(nameof(src));
+ return;
}
- if (Unsafe.IsNullRef(ref dst))
+ CopyUtilCore.Memmove(
+ in Refs.AsByteR(in src, srcOffset),
+ ref Refs.AsByte(ref dst, dstOffset),
+ ByteCount<T>(elementCount),
+ CopyUtilCore.IsHwAccelerationSupported
+ );
+ }
+
+ private static void MemmoveInternal<T, TSrc, TDst>(ref readonly TSrc src, ref readonly TDst dst, nuint elementCount, bool forceAcceleration)
+ where T : unmanaged
+ where TSrc: I64BitBlock
+ where TDst: I64BitBlock
+ {
+ //Validate source/dest arguments
+ src.Validate(elementCount);
+ dst.Validate(elementCount);
+
+ nuint byteCount = ByteCount<T>(elementCount);
+
+ /*
+ * The internal copy strategy may require buffers to be pinned in memory
+ * instead of references based. We can pin the handles now to use a
+ * memoryHandle pointer instead of fixing a reference. This can offer
+ * better pinning performance for handles that that have zero-cost pinning
+ * such as unmanaged blocks.
+ */
+ if(CopyUtilCore.RequiresPinning(byteCount, forceAcceleration))
{
- throw new ArgumentNullException(nameof(dst));
+ //Pin before calling memmove
+ using MemoryHandle srcH = src.Pin();
+ using MemoryHandle dstH = dst.Pin();
+
+ CopyUtilCore.Memmove(
+ in Refs.AsByte<T>(srcH.Pointer, src.Offset),
+ ref Refs.AsByte<T>(dstH.Pointer, dst.Offset),
+ byteCount,
+ forceAcceleration
+ );
}
-
- if (elementCount == 0)
+ else
{
- return;
+ //Reference based memmove
+ CopyUtilCore.Memmove(
+ in src.GetOffsetRef(),
+ ref dst.GetOffsetRef(),
+ byteCount,
+ forceAcceleration
+ );
}
+ }
+
+ private static void ValidateCopyArgs(nint sourceOffset, nint destOffset, nint count)
+ {
+ ArgumentOutOfRangeException.ThrowIfNegative(sourceOffset);
+ ArgumentOutOfRangeException.ThrowIfNegative(destOffset);
+ ArgumentOutOfRangeException.ThrowIfNegative(count);
+ }
- if (!CopyUtilCore.MemmoveByRef(
- ref Refs.AsByte(ref src, srcOffset),
- ref Refs.AsByte(ref dst, dstOffset),
- ByteCount<T>(elementCount),
- useAcceleration)
- )
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void ThrowIfNullRef<T>(ref readonly T value, string argName)
+ {
+ if (Unsafe.IsNullRef(in value))
{
- throw new ArgumentException("The number of bytes to copy was larger than Uint32.MaxValue and was unsupported on this platform", nameof(elementCount));
+ throw new ArgumentNullException(argName);
}
}
@@ -1187,6 +1234,40 @@ namespace VNLib.Utils.Memory
/// <summary>
/// Checks if the offset/count paramters for the given block
+ /// point outside the block wrapped in the handle
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="block">The handle to check bounds of</param>
+ /// <param name="offset">The base offset to add</param>
+ /// <param name="count">The number of bytes expected to be assigned or dereferrenced</param>
+ /// <exception cref="ArgumentOutOfRangeException"></exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void CheckBounds<T>(ReadOnlyMemory<T> block, int offset, int count)
+ {
+ ArgumentOutOfRangeException.ThrowIfNegative(offset);
+ ArgumentOutOfRangeException.ThrowIfNegative(count);
+ ArgumentOutOfRangeException.ThrowIfGreaterThan(offset + count, block.Length, nameof(count));
+ }
+
+ /// <summary>
+ /// Checks if the offset/count paramters for the given block
+ /// point outside the block wrapped in the handle
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="block">The handle to check bounds of</param>
+ /// <param name="offset">The base offset to add</param>
+ /// <param name="count">The number of bytes expected to be assigned or dereferrenced</param>
+ /// <exception cref="ArgumentOutOfRangeException"></exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void CheckBounds<T>(Memory<T> block, int offset, int count)
+ {
+ ArgumentOutOfRangeException.ThrowIfNegative(offset);
+ ArgumentOutOfRangeException.ThrowIfNegative(count);
+ ArgumentOutOfRangeException.ThrowIfGreaterThan(offset + count, block.Length, nameof(count));
+ }
+
+ /// <summary>
+ /// Checks if the offset/count paramters for the given block
/// point outside the block bounds
/// </summary>
/// <typeparam name="T"></typeparam>
@@ -1251,7 +1332,8 @@ namespace VNLib.Utils.Memory
/// <param name="pinnable">An optional <see cref="IPinnable"/> instace to wrap with the handle</param>
/// <returns>The <see cref="MemoryHandle"/> wrapper</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static MemoryHandle GetMemoryHandleFromPointer(IntPtr value, GCHandle handle = default, IPinnable? pinnable = null) => new (value.ToPointer(), handle, pinnable);
+ public static MemoryHandle GetMemoryHandleFromPointer(IntPtr value, GCHandle handle = default, IPinnable? pinnable = null)
+ => new (value.ToPointer(), handle, pinnable);
/// <summary>
/// Gets a <see cref="Span{T}"/> from the supplied address
@@ -1304,7 +1386,7 @@ namespace VNLib.Utils.Memory
public static ref T GetRef<T>(IntPtr address, nuint offset)
{
ref T baseRef = ref GetRef<T>(address);
- return ref Unsafe.Add(ref baseRef, (nint)offset);
+ return ref Unsafe.Add(ref baseRef, offset);
}
/// <summary>
@@ -1313,7 +1395,7 @@ namespace VNLib.Utils.Memory
/// <param name="handle">A reference to the handle to get the intpr for</param>
/// <returns>A managed pointer from the handle</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static IntPtr GetIntptr(ref MemoryHandle handle) => new(handle.Pointer);
+ public static IntPtr GetIntptr(ref readonly MemoryHandle handle) => new(handle.Pointer);
/// <summary>
/// Rounds the requested byte size up to the nearest page
@@ -1373,123 +1455,25 @@ namespace VNLib.Utils.Memory
return NearestPage(elements * elSize) / elSize;
}
-
- private static class CopyUtilCore
+ private static class Refs
{
- const nuint _avx32ByteAlignment = 0x20u;
-
- [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
- public static bool MemmoveByRef(ref byte srcByte, ref byte dstByte, nuint byteCount, bool forceAcceleration)
+ public static ref byte AsByte<T>(void* ptr, nuint elementOffset) where T : unmanaged
{
- Debug.Assert(!Unsafe.IsNullRef(ref srcByte), "Null source reference passed to MemmoveByRef");
- Debug.Assert(!Unsafe.IsNullRef(ref dstByte), "Null destination reference passed to MemmoveByRef");
-
- if (IsAvx2Supported)
- {
- //If the data is aligned, always use the 32 byte copy
- if (Is32ByteAligned(byteCount))
- {
- _avx32ByteCopy(ref srcByte, ref dstByte, byteCount);
- return true;
- }
-
- //See if forcing acceleration is desired
- if (forceAcceleration)
- {
- //not aligned, so we need to only copy the aligned portion
- nuint remainder = byteCount % _avx32ByteAlignment;
- nuint alignedCount = byteCount - remainder;
-
- //Copy aligned portion
- _avx32ByteCopy(ref srcByte, ref dstByte, alignedCount);
-
- //Upshift references to the remainder addresses
- ref byte srcRemainder = ref Unsafe.Add(ref srcByte, alignedCount);
- ref byte dstRemainder = ref Unsafe.Add(ref dstByte, alignedCount);
-
- //finish copying remaining data
- bool success = _memmove(ref srcRemainder, ref dstRemainder, remainder);
- Debug.Assert(success, "Memmove by ref call failed during a 32bit copy");
-
- return true;
- }
- }
-
- //fallback to memmove
- return _memmove(ref srcByte, ref dstByte, byteCount);
+ //Compute the pointer offset and return the reference
+ ref T asType = ref Unsafe.AsRef<T>(ptr);
+ ref T offset = ref Unsafe.Add(ref asType, elementOffset);
+ return ref Unsafe.AsRef<byte>(ptr);
}
-
- [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
- private static bool _memmove(ref byte src, ref byte dst, nuint byteCount)
- {
- if (_clrMemmove != null)
- {
- //Call sysinternal memmove
- _clrMemmove(ref dst, ref src, byteCount);
- return true;
- }
- else if (byteCount < uint.MaxValue)
- {
- //Use safe 32bit block copy
- Unsafe.CopyBlock(ref dst, ref src, (uint)byteCount);
- return true;
- }
- else
- {
- return false;
- }
- }
-
-
- [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
- private static void _avx32ByteCopy(
- ref byte src,
- ref byte dst,
- nuint count
- )
+ public static ref byte AsByte<T>(ref T ptr, nuint elementOffset)
{
- Debug.Assert(Is32ByteAligned(count), "Byte count must be 32 byte aligned");
- Debug.Assert(Avx2.IsSupported, "AVX2 is not supported on this platform");
- Debug.Assert(_avx32ByteAlignment == (nuint)Vector256<byte>.Count, "AVX2 vector size is not 32 bytes");
-
- //determine the number of loops
- nuint loopCount = count / _avx32ByteAlignment;
-
- fixed (byte* srcPtr = &src, dstPtr = &dst)
- {
- //local mutable copies
- byte* srcOffset = srcPtr;
- byte* dstOffset = dstPtr;
-
- for (nuint i = 0; i < loopCount; i++)
- {
- //avx vector load
- Vector256<byte> srcVector = Avx.LoadVector256(srcOffset);
- Avx.Store(dstOffset, srcVector);
-
- //Upshift pointers
- srcOffset += Vector256<byte>.Count;
- dstOffset += Vector256<byte>.Count;
- }
- }
+ ref T offset = ref Unsafe.Add(ref ptr, elementOffset);
+ return ref Unsafe.As<T, byte>(ref offset);
}
-
- /// <summary>
- /// Determines if the given size 32-byte aligned
- /// </summary>
- /// <param name="size">The block size to test</param>
- /// <returns>A value that indicates if the block size is 32byte aligned</returns>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool Is32ByteAligned(nuint size) => unchecked(size % _avx32ByteAlignment) == 0;
- }
-
- private static class Refs
- {
- public static ref byte AsByte<T>(ref T ptr, nuint elementOffset)
+ public static ref byte AsByteR<T>(scoped ref readonly T ptr, nuint elementOffset)
{
- ref T offset = ref Unsafe.Add(ref ptr, elementOffset);
+ ref T offset = ref Unsafe.Add(ref Unsafe.AsRef(in ptr), elementOffset);
return ref Unsafe.As<T, byte>(ref offset);
}
@@ -1521,5 +1505,90 @@ namespace VNLib.Utils.Memory
return ref Unsafe.As<T, byte>(ref offset);
}
}
+
+ private interface I64BitBlock
+ {
+ ref byte GetOffsetRef();
+
+ MemoryHandle Pin();
+
+ nuint Size { get; }
+
+ nuint Offset { get; }
+
+ void Validate(nuint count);
+ }
+
+ private readonly struct ArrayCopyHandle<T>(T[] array, nuint offset) : I64BitBlock
+ {
+ ///<inheritdoc/>
+ public readonly nuint Offset => offset;
+
+ ///<inheritdoc/>
+ public readonly nuint Size => ByteCount<T>((nuint)array.Length);
+
+ ///<inheritdoc/>
+ public readonly MemoryHandle Pin() => PinArrayAndGetHandle(array, 0);
+
+ ///<inheritdoc/>
+ public readonly ref byte GetOffsetRef() => ref Refs.AsByte(array, offset);
+
+ ///<inheritdoc/>
+ public readonly void Validate(nuint count) => CheckBounds(array, offset, count);
+ }
+
+ private readonly struct RMemCopyHandle<T>(ReadOnlyMemory<T> block, nuint offset) : I64BitBlock
+ {
+ ///<inheritdoc/>
+ public readonly nuint Offset => offset;
+
+ ///<inheritdoc/>
+ public readonly nuint Size => ByteCount<T>((nuint)block.Length);
+
+ ///<inheritdoc/>
+ public readonly MemoryHandle Pin() => block.Pin();
+
+ ///<inheritdoc/>
+ public readonly ref byte GetOffsetRef() => ref Refs.AsByte(block.Span, offset);
+
+ ///<inheritdoc/>
+ public readonly void Validate(nuint count) => CheckBounds(block, (int)offset, checked((int)count));
+ }
+
+ private readonly struct WMemCopyHandle<T>(Memory<T> block, nuint offset) : I64BitBlock
+ {
+ ///<inheritdoc/>
+ public readonly nuint Offset => offset;
+
+ ///<inheritdoc/>
+ public readonly nuint Size => ByteCount<T>((nuint)block.Length);
+
+ ///<inheritdoc/>
+ public readonly MemoryHandle Pin() => block.Pin();
+
+ ///<inheritdoc/>
+ public readonly ref byte GetOffsetRef() => ref Refs.AsByte(block.Span, offset);
+
+ ///<inheritdoc/>
+ public readonly void Validate(nuint count) => CheckBounds(block, (int)offset, checked((int)count));
+ }
+
+ private readonly struct MemhandleCopyHandle<T>(IMemoryHandle<T> handle, nuint offset) : I64BitBlock
+ {
+ ///<inheritdoc/>
+ public readonly nuint Offset => offset;
+
+ ///<inheritdoc/>
+ public readonly nuint Size => handle.Length;
+
+ ///<inheritdoc/>
+ public readonly MemoryHandle Pin() => handle.Pin(0);
+
+ ///<inheritdoc/>
+ public readonly ref byte GetOffsetRef() => ref Refs.AsByte(handle, offset);
+
+ ///<inheritdoc/>
+ public readonly void Validate(nuint count) => CheckBounds(handle, offset, count);
+ }
}
} \ No newline at end of file
diff --git a/lib/Utils/src/Memory/NativeHeap.cs b/lib/Utils/src/Memory/NativeHeap.cs
index 7a3d4dd..6381dd9 100644
--- a/lib/Utils/src/Memory/NativeHeap.cs
+++ b/lib/Utils/src/Memory/NativeHeap.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Utils
@@ -28,6 +28,7 @@ using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using VNLib.Utils.Native;
+using VNLib.Utils.Extensions;
namespace VNLib.Utils.Memory
{
@@ -58,17 +59,16 @@ namespace VNLib.Utils.Memory
/// <returns>The newly initialized <see cref="NativeHeap"/></returns>
public unsafe static NativeHeap LoadHeap(string dllPath, DllImportSearchPath searchPath, HeapCreation creationFlags, ERRNO flags)
{
- //Create a flags structure
- UnmanagedHeapDescriptor hf;
- UnmanagedHeapDescriptor* hFlags = &hf;
-
- //Set defaults
- hFlags->Flags = flags;
- hFlags->CreationFlags = creationFlags;
- hFlags->HeapPointer = IntPtr.Zero;
+ //Create a flags structure with defaults
+ UnmanagedHeapDescriptor hFlags = new()
+ {
+ CreationFlags = creationFlags,
+ Flags = flags,
+ HeapPointer = IntPtr.Zero
+ };
//Create the heap
- return LoadHeapCore(dllPath, searchPath, hFlags);
+ return LoadHeapCore(dllPath, searchPath, &hFlags);
}
private unsafe static NativeHeap LoadHeapCore(string path, DllImportSearchPath searchPath, UnmanagedHeapDescriptor* flags)
@@ -78,34 +78,20 @@ namespace VNLib.Utils.Memory
try
{
//Open method table
- HeapMethods table = new()
- {
- //Get method delegates
- Alloc = library.DangerousGetMethod<AllocDelegate>(ALLOCATE_METHOD_NAME),
-
- Destroy = library.DangerousGetMethod<DestroyHeapDelegate>(DESTROY_METHOD_NAME),
-
- Free = library.DangerousGetMethod<FreeDelegate>(FREE_METHOD_NAME),
-
- Realloc = library.DangerousGetMethod<ReallocDelegate>(REALLOC_METHOD_NAME),
-
- Library = library
- };
+ HeapMethods table = new(library);
Trace.WriteLine($"Creating user defined native heap at {path}");
//Get the create method
- CreateHeapDelegate create = library.DangerousGetMethod<CreateHeapDelegate>(CREATE_METHOD_NAME);
+ CreateHeapDelegate create = library.DangerousGetFunction<CreateHeapDelegate>();
//Create the new heap
- bool success = create(flags);
-
- if (!success)
+ if (!create(flags))
{
throw new NativeMemoryException("Failed to create the new heap, the heap create method returned a null pointer");
}
- Trace.WriteLine($"Successfully created user defined native heap {flags->HeapPointer:x} with flags {flags->CreationFlags:x}");
+ Trace.WriteLine($"Successfully created user defined native heap 0x{flags->HeapPointer:x} with flags 0x{flags->CreationFlags:x}");
//Return the neap heap
return new(flags, table);
@@ -153,7 +139,7 @@ namespace VNLib.Utils.Memory
//Cleanup the method table
MethodTable = default;
- Trace.WriteLine($"Successfully deestroyed user defined heap {handle:x}");
+ Trace.WriteLine($"Successfully deestroyed user defined heap 0x{handle:x}");
return ret;
}
@@ -162,14 +148,19 @@ namespace VNLib.Utils.Memory
* Delegate methods match the native header impl for unmanaged heaps
*/
+ [SafeMethodName(CREATE_METHOD_NAME)]
unsafe delegate ERRNO CreateHeapDelegate(UnmanagedHeapDescriptor* createFlags);
+ [SafeMethodName(ALLOCATE_METHOD_NAME)]
delegate IntPtr AllocDelegate(IntPtr handle, nuint elements, nuint alignment, [MarshalAs(UnmanagedType.Bool)] bool zero);
+ [SafeMethodName(REALLOC_METHOD_NAME)]
delegate IntPtr ReallocDelegate(IntPtr heap, IntPtr block, nuint elements, nuint alignment, [MarshalAs(UnmanagedType.Bool)] bool zero);
+ [SafeMethodName(FREE_METHOD_NAME)]
delegate ERRNO FreeDelegate(IntPtr heap, IntPtr block);
+ [SafeMethodName(DESTROY_METHOD_NAME)]
delegate ERRNO DestroyHeapDelegate(IntPtr heap);
[StructLayout(LayoutKind.Sequential)]
@@ -182,17 +173,12 @@ namespace VNLib.Utils.Memory
public HeapCreation CreationFlags;
}
- readonly record struct HeapMethods
+ readonly record struct HeapMethods(SafeLibraryHandle Library)
{
- public readonly SafeLibraryHandle Library { get; init; }
-
- public readonly AllocDelegate Alloc { get; init; }
-
- public readonly ReallocDelegate Realloc { get; init; }
-
- public readonly FreeDelegate Free { get; init; }
-
- public readonly DestroyHeapDelegate Destroy { get; init; }
+ public readonly AllocDelegate Alloc = Library.DangerousGetFunction<AllocDelegate>();
+ public readonly ReallocDelegate Realloc = Library.DangerousGetFunction<ReallocDelegate>();
+ public readonly FreeDelegate Free = Library.DangerousGetFunction<FreeDelegate>();
+ public readonly DestroyHeapDelegate Destroy = Library.DangerousGetFunction<DestroyHeapDelegate>();
}
}
} \ No newline at end of file
diff --git a/lib/Utils/src/Memory/PrivateString.cs b/lib/Utils/src/Memory/PrivateString.cs
index 3952084..4cdaa77 100644
--- a/lib/Utils/src/Memory/PrivateString.cs
+++ b/lib/Utils/src/Memory/PrivateString.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Utils
@@ -152,12 +152,14 @@ namespace VNLib.Utils.Memory
/// <param name="data">The string reference to wrap</param>
/// <param name="ownsString">A value that indicates if the string memory is owned by the instance</param>
/// <returns>The new private string wrapper, or null if the value is null</returns>
+ [return:NotNullIfNotNull(nameof(data))]
public static PrivateString? ToPrivateString(string? data, bool ownsString) => data == null ? null : new(data, ownsString);
/// <summary>
/// Casts the <see cref="PrivateString"/> to a <see cref="string"/>
/// </summary>
/// <param name="str"></param>
+ [return: NotNullIfNotNull(nameof(str))]
public static explicit operator string?(PrivateString? str) => str?.StringRef;
/// <summary>
diff --git a/lib/Utils/src/Memory/PrivateStringManager.cs b/lib/Utils/src/Memory/PrivateStringManager.cs
index 3d50463..073ee9e 100644
--- a/lib/Utils/src/Memory/PrivateStringManager.cs
+++ b/lib/Utils/src/Memory/PrivateStringManager.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Utils
@@ -29,15 +29,13 @@ namespace VNLib.Utils.Memory
/// <summary>
/// When inherited by a class, provides a safe string storage that zeros a CLR string memory on disposal
/// </summary>
- public class PrivateStringManager : VnDisposeable
+ /// <remarks>
+ /// Create a new instance with fixed array size
+ /// </remarks>
+ /// <param name="elements">Number of elements to protect</param>
+ public class PrivateStringManager(int elements) : VnDisposeable
{
- private readonly StringRef[] ProtectedElements;
-
- /// <summary>
- /// Create a new instance with fixed array size
- /// </summary>
- /// <param name="elements">Number of elements to protect</param>
- public PrivateStringManager(int elements) => ProtectedElements = new StringRef[elements];
+ private readonly StringRef[] ProtectedElements = new StringRef[elements];
/// <summary>
/// Gets or sets a string referrence into the protected elements store
diff --git a/lib/Utils/src/Memory/SubSequence.cs b/lib/Utils/src/Memory/SubSequence.cs
index 86b2347..80aa084 100644
--- a/lib/Utils/src/Memory/SubSequence.cs
+++ b/lib/Utils/src/Memory/SubSequence.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Utils
@@ -29,7 +29,7 @@ using VNLib.Utils.Extensions;
namespace VNLib.Utils.Memory
{
/// <summary>
- /// Represents a subset (or window) of data within a <see cref="MemoryHandle{T}"/>
+ /// Represents a subset (or window) of data within a <see cref="IMemoryHandle{T}"/>
/// </summary>
/// <typeparam name="T">The unmanaged type to wrap</typeparam>
public readonly record struct SubSequence<T>
@@ -56,9 +56,11 @@ namespace VNLib.Utils.Memory
/// <exception cref="ArgumentOutOfRangeException"></exception>
public SubSequence(IMemoryHandle<T> block, nuint offset, int size)
{
- Handle = block ?? throw new ArgumentNullException(nameof(block));
- Size = size >= 0 ? size : throw new ArgumentOutOfRangeException(nameof(size));
- _offset = offset;
+ ArgumentNullException.ThrowIfNull(block);
+ ArgumentOutOfRangeException.ThrowIfNegative(size);
+ Size = size;
+ Handle = block;
+ _offset = offset;
//Check handle bounds
MemoryUtil.CheckBounds(block, offset, (uint)size);
@@ -72,6 +74,12 @@ namespace VNLib.Utils.Memory
public readonly Span<T> Span => Size > 0 ? Handle.GetOffsetSpan(_offset, Size) : Span<T>.Empty;
/// <summary>
+ /// Gets a reference to the first element in the current sequence
+ /// </summary>
+ /// <returns>The element reference</returns>
+ public readonly ref T GetReference() => ref Handle.GetOffsetRef(_offset);
+
+ /// <summary>
/// Slices the current sequence into a smaller <see cref="SubSequence{T}"/>
/// </summary>
/// <param name="offset">The relative offset from the current window offset</param>
@@ -87,15 +95,9 @@ namespace VNLib.Utils.Memory
//Cal max size after the slice
int newMaxSize = Size - (int)offset;
- if(newMaxSize < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(offset));
- }
-
- if(size > newMaxSize)
- {
- throw new ArgumentOutOfRangeException(nameof(size));
- }
+ ArgumentOutOfRangeException.ThrowIfNegative(offset);
+ ArgumentOutOfRangeException.ThrowIfGreaterThan(size, newMaxSize);
+
return new SubSequence<T>(Handle, newOffset, size > newMaxSize ? newMaxSize : size);
}
diff --git a/lib/Utils/src/Memory/UnmanagedHeapBase.cs b/lib/Utils/src/Memory/UnmanagedHeapBase.cs
index a038358..599d8d9 100644
--- a/lib/Utils/src/Memory/UnmanagedHeapBase.cs
+++ b/lib/Utils/src/Memory/UnmanagedHeapBase.cs
@@ -29,7 +29,7 @@ using Microsoft.Win32.SafeHandles;
using VNLib.Utils.Native;
-using LPVOID = System.IntPtr;
+using LPVOID = nint;
namespace VNLib.Utils.Memory
{
@@ -37,28 +37,17 @@ namespace VNLib.Utils.Memory
/// Provides a synchronized base methods for accessing unmanaged memory. Implements <see cref="SafeHandle"/>
/// for safe disposal of heaps
/// </summary>
- public abstract class UnmanagedHeapBase : SafeHandleZeroOrMinusOneIsInvalid, IUnmangedHeap
+ /// <param name="flags">The creation flags to obey</param>
+ /// <param name="ownsHandle">A flag that indicates if the handle is owned by the instance</param>
+ public abstract class UnmanagedHeapBase(HeapCreation flags, bool ownsHandle) : SafeHandleZeroOrMinusOneIsInvalid(ownsHandle), IUnmangedHeap
{
- private readonly HeapCreation _flags;
-
/// <summary>
/// The heap synchronization handle
/// </summary>
- protected readonly object HeapLock;
-
- /// <summary>
- /// Initalizes the unmanaged heap base class (init synchronization handle)
- /// </summary>
- /// <param name="flags">Creation flags to obey</param>
- /// <param name="ownsHandle">A flag that indicates if the handle is owned by the instance</param>
- protected UnmanagedHeapBase(HeapCreation flags, bool ownsHandle) : base(ownsHandle)
- {
- HeapLock = new();
- _flags = flags;
- }
+ protected readonly object HeapLock = new();
///<inheritdoc/>
- public HeapCreation CreationFlags => _flags;
+ public HeapCreation CreationFlags => flags;
///<inheritdoc/>
///<remarks>Increments the handle count, free must be called to decrement the handle count</remarks>
@@ -68,10 +57,10 @@ namespace VNLib.Utils.Memory
public LPVOID Alloc(nuint elements, nuint size, bool zero)
{
//Check for overflow for size
- _ = checked(elements * size);
+ _ = checked(elements * size);
//Force zero if global flag is set
- zero |= (_flags & HeapCreation.GlobalZero) > 0;
+ zero |= (flags & HeapCreation.GlobalZero) > 0;
bool handleCountIncremented = false;
//Increment handle count to prevent premature release
@@ -85,7 +74,7 @@ namespace VNLib.Utils.Memory
LPVOID block;
//Check if lock should be used
- if ((_flags & HeapCreation.UseSynchronization) > 0)
+ if ((flags & HeapCreation.UseSynchronization) > 0)
{
//Enter lock
lock(HeapLock)
@@ -124,11 +113,11 @@ namespace VNLib.Utils.Memory
//If disposed, set the block handle to zero and exit to avoid raising exceptions during finalization
if (IsClosed || IsInvalid)
{
- block = IntPtr.Zero;
+ block = LPVOID.Zero;
return true;
}
- if ((_flags & HeapCreation.UseSynchronization) > 0)
+ if ((flags & HeapCreation.UseSynchronization) > 0)
{
//wait for lock
lock (HeapLock)
@@ -156,7 +145,7 @@ namespace VNLib.Utils.Memory
///<exception cref="ObjectDisposedException"></exception>
public void Resize(ref LPVOID block, nuint elements, nuint size, bool zero)
{
- if ((_flags & HeapCreation.SupportsRealloc) == 0)
+ if ((flags & HeapCreation.SupportsRealloc) == 0)
{
throw new NotSupportedException("The underlying heap does not support block reallocation");
}
@@ -167,7 +156,7 @@ namespace VNLib.Utils.Memory
LPVOID newBlock;
//Global zero flag will cause a zero
- zero |= (_flags & HeapCreation.GlobalZero) > 0;
+ zero |= (flags & HeapCreation.GlobalZero) > 0;
/*
* Realloc may return a null pointer if allocation fails
@@ -176,7 +165,7 @@ namespace VNLib.Utils.Memory
* be left untouched
*/
- if ((_flags & HeapCreation.UseSynchronization) > 0)
+ if ((flags & HeapCreation.UseSynchronization) > 0)
{
lock (HeapLock)
{
diff --git a/lib/Utils/src/Memory/UnsafeMemoryHandle.cs b/lib/Utils/src/Memory/UnsafeMemoryHandle.cs
index 6976e4f..fbf96eb 100644
--- a/lib/Utils/src/Memory/UnsafeMemoryHandle.cs
+++ b/lib/Utils/src/Memory/UnsafeMemoryHandle.cs
@@ -86,7 +86,7 @@ namespace VNLib.Utils.Memory
/// <see cref="ArrayPool{T}"/>
/// </summary>
/// <param name="elements">The number of elements to store</param>
- /// <param name="array">The array reference to store/param>
+ /// <param name="array">The array reference to store</param>
/// <param name="pool">The explicit pool to alloc buffers from</param>
/// <exception cref="OutOfMemoryException"></exception>
/// <exception cref="ArgumentNullException"></exception>
diff --git a/lib/Utils/src/Native/SafeLibraryHandle.cs b/lib/Utils/src/Native/SafeLibraryHandle.cs
index 867523d..6b1af00 100644
--- a/lib/Utils/src/Native/SafeLibraryHandle.cs
+++ b/lib/Utils/src/Native/SafeLibraryHandle.cs
@@ -147,6 +147,7 @@ namespace VNLib.Utils.Native
libary = null;
return false;
}
+
private static string? GetLibraryFile(string dirPath, string libPath, SearchOption search)
{
//slice the lib to its file name
@@ -157,15 +158,16 @@ namespace VNLib.Utils.Native
}
/// <summary>
- /// Loads a native method from the library of the specified name and managed delegate
+ /// Loads a native function pointer from the library of the specified name and
+ /// creates a new managed delegate
/// </summary>
/// <typeparam name="T">The native method delegate type</typeparam>
- /// <param name="methodName">The name of the native method</param>
+ /// <param name="functionName">The name of the native function</param>
/// <returns>A wapper handle around the native method delegate</returns>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ObjectDisposedException">If the handle is closed or invalid</exception>
/// <exception cref="EntryPointNotFoundException">When the specified entrypoint could not be found</exception>
- public SafeMethodHandle<T> GetMethod<T>(string methodName) where T : Delegate
+ public SafeMethodHandle<T> GetFunction<T>(string functionName) where T : Delegate
{
//Increment handle count before obtaining a method
bool success = false;
@@ -176,7 +178,7 @@ namespace VNLib.Utils.Native
try
{
//Get the method pointer
- IntPtr nativeMethod = NativeLibrary.GetExport(handle, methodName);
+ IntPtr nativeMethod = NativeLibrary.GetExport(handle, functionName);
//Get the delegate for the function pointer
T method = Marshal.GetDelegateForFunctionPointer<T>(nativeMethod);
return new(this, method);
@@ -187,26 +189,54 @@ namespace VNLib.Utils.Native
throw;
}
}
+
/// <summary>
- /// Gets an delegate wrapper for the specified method without tracking its referrence.
+ /// Gets an delegate wrapper for the specified native function without tracking its referrence.
/// The caller must manage the <see cref="SafeLibraryHandle"/> referrence count in order
/// to not leak resources or cause process corruption
/// </summary>
/// <typeparam name="T">The native method delegate type</typeparam>
- /// <param name="methodName">The name of the native method</param>
+ /// <param name="functionName">The name of the native library function</param>
/// <returns>A the delegate wrapper on the native method</returns>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ObjectDisposedException">If the handle is closed or invalid</exception>
/// <exception cref="EntryPointNotFoundException">When the specified entrypoint could not be found</exception>
- public T DangerousGetMethod<T>(string methodName) where T : Delegate
+ public T DangerousGetFunction<T>(string functionName) where T : Delegate
{
this.ThrowIfClosed();
//Get the method pointer
- IntPtr nativeMethod = NativeLibrary.GetExport(handle, methodName);
+ IntPtr nativeMethod = NativeLibrary.GetExport(handle, functionName);
//Get the delegate for the function pointer
return Marshal.GetDelegateForFunctionPointer<T>(nativeMethod);
}
+ /// <summary>
+ /// Loads a native method from the library of the specified name and managed delegate
+ /// </summary>
+ /// <typeparam name="T">The native method delegate type</typeparam>
+ /// <param name="methodName">The name of the native method</param>
+ /// <returns>A wapper handle around the native method delegate</returns>
+ /// <exception cref="ArgumentNullException"></exception>
+ /// <exception cref="ObjectDisposedException">If the handle is closed or invalid</exception>
+ /// <exception cref="EntryPointNotFoundException">When the specified entrypoint could not be found</exception>
+ [Obsolete("Updated naming, use GetFunction<T>() instead")]
+ public SafeMethodHandle<T> GetMethod<T>(string methodName) where T : Delegate => GetFunction<T>(methodName);
+
+ /// <summary>
+ /// Gets an delegate wrapper for the specified method without tracking its referrence.
+ /// The caller must manage the <see cref="SafeLibraryHandle"/> referrence count in order
+ /// to not leak resources or cause process corruption
+ /// </summary>
+ /// <typeparam name="T">The native method delegate type</typeparam>
+ /// <param name="methodName">The name of the native method</param>
+ /// <returns>A the delegate wrapper on the native method</returns>
+ /// <exception cref="ArgumentNullException"></exception>
+ /// <exception cref="ObjectDisposedException">If the handle is closed or invalid</exception>
+ /// <exception cref="EntryPointNotFoundException">When the specified entrypoint could not be found</exception>
+ [Obsolete("Updated naming, use DangerousGetFunction<T>() instead")]
+ public T DangerousGetMethod<T>(string methodName) where T : Delegate => DangerousGetFunction<T>(methodName);
+
+
///<inheritdoc/>
protected override bool ReleaseHandle()
{
diff --git a/lib/Utils/src/VnEncoding.cs b/lib/Utils/src/VnEncoding.cs
index 5509955..b7b3783 100644
--- a/lib/Utils/src/VnEncoding.cs
+++ b/lib/Utils/src/VnEncoding.cs
@@ -669,7 +669,7 @@ namespace VNLib.Utils
{
//Percent encode
utf8Output[outPos++] = 0x25; // '%'
- //Calc and store the encoded by the upper 4 bits
+ //Calc and store the encoded by the upper 4 bits
utf8Output[outPos++] = lookupTable[(value & 0xf0) >> 4];
//Store lower 4 bits in encoded value
utf8Output[outPos++] = lookupTable[value & 0x0f];
@@ -771,12 +771,9 @@ namespace VNLib.Utils
ERRNO encoded = PercentEncode(utf8Bytes, output, allowedChars);
- if(encoded <= 0)
- {
- throw new FormatException("Failed to percent encode the input data");
- }
-
- return Encoding.UTF8.GetString(output);
+ return encoded > 0
+ ? Encoding.UTF8.GetString(output)
+ : throw new FormatException("Failed to percent encode the input data");
}
else
{
@@ -785,12 +782,9 @@ namespace VNLib.Utils
ERRNO encoded = PercentEncode(utf8Bytes, handle.Span, allowedChars);
- if (encoded <= 0)
- {
- throw new FormatException("Failed to percent encode the input data");
- }
-
- return Encoding.UTF8.GetString(handle.AsSpan(0, encoded));
+ return encoded > 0
+ ? Encoding.UTF8.GetString(handle.AsSpan(0, encoded))
+ : throw new FormatException("Failed to percent encode the input data");
}
}
@@ -1054,26 +1048,16 @@ namespace VNLib.Utils
/// <exception cref="ArgumentException"></exception>
public static string ToBase64UrlSafeStringInPlace(Span<byte> rawData, int length, bool includePadding)
{
+ ERRNO converted = Base64UrlEncodeInPlace(rawData, length, includePadding);
+
//Encode in place
- if (Base64.EncodeToUtf8InPlace(rawData, length, out int converted) != OperationStatus.Done)
+ if (converted < 1)
{
throw new ArgumentException("The input buffer was not large enough to encode in-place", nameof(rawData));
}
- //trim to converted size
- Span<byte> base64 = rawData[..converted];
-
- //Make url safe
- Base64ToUrlSafeInPlace(base64);
-
- //Remove padding
- if (!includePadding)
- {
- base64 = base64.TrimEnd((byte)0x3d);
- }
-
//Convert to string
- return Encoding.UTF8.GetString(base64);
+ return Encoding.UTF8.GetString(rawData[..(int)converted]);
}
/// <summary>
@@ -1086,6 +1070,11 @@ namespace VNLib.Utils
/// <exception cref="ArgumentException"></exception>
public static string ToBase64UrlSafeString(ReadOnlySpan<byte> rawData, bool includePadding)
{
+ if (rawData.IsEmpty)
+ {
+ throw new ArgumentException("The input buffer was empty", nameof(rawData));
+ }
+
int maxBufSize = Base64.GetMaxEncodedToUtf8Length(rawData.Length);
if(maxBufSize > MAX_STACKALLOC)
diff --git a/lib/Utils/tests/Memory/MemoryUtilTests.cs b/lib/Utils/tests/Memory/MemoryUtilTests.cs
index 9b8ed1e..63342b5 100644
--- a/lib/Utils/tests/Memory/MemoryUtilTests.cs
+++ b/lib/Utils/tests/Memory/MemoryUtilTests.cs
@@ -498,6 +498,34 @@ namespace VNLib.Utils.Memory.Tests
Assert.IsTrue(pageSize == Environment.SystemPageSize);
}
+
+ [TestMethod()]
+ public void SimpleCopyTest()
+ {
+ const int blockSize = 10 * 1024;
+
+ using IMemoryHandle<byte> dest = MemoryUtil.SafeAlloc<byte>(blockSize, false);
+ using IMemoryHandle<byte> src = MemoryUtil.SafeAlloc<byte>(blockSize, false);
+
+ Assert.IsTrue(src.Length == dest.Length);
+
+ //Fill source with random data
+ RandomNumberGenerator.Fill(src.Span);
+
+ //Copy
+ MemoryUtil.Copy(src, 0, dest, 0, blockSize);
+
+ //Confirm data is the same
+ Assert.IsTrue(src.Span.SequenceEqual(dest.Span));
+
+ //try with array
+ byte[] destArray = new byte[blockSize];
+ MemoryUtil.CopyArray(src, 0, destArray, 0, blockSize);
+
+ //Confirm data is the same
+ Assert.IsTrue(src.Span.SequenceEqual(destArray));
+ }
+
[TestMethod()]
public void AllocNearestPage()
{
@@ -663,7 +691,7 @@ namespace VNLib.Utils.Memory.Tests
}
[TestMethod]
- public void CopyTest()
+ public void CopyArgsTest()
{
/*
* Testing the MemoryUtil.Copy/CopyArray family of functions and their overloads
@@ -685,9 +713,12 @@ namespace VNLib.Utils.Memory.Tests
Assert.ThrowsException<ArgumentNullException>(() => MemoryUtil.Copy(ReadOnlyMemory<byte>.Empty, 0, null, 0, 1));
Assert.ThrowsException<ArgumentNullException>(() => MemoryUtil.Copy(ReadOnlySpan<byte>.Empty, 0, null, 0, 1));
- Assert.ThrowsException<ArgumentNullException>(() => MemoryUtil.CopyArray(null, 0, testArray, 0, 1));
+ Assert.ThrowsException<ArgumentNullException>(() => MemoryUtil.CopyArray((IMemoryHandle<byte>)null, 0, testArray, 0, 1));
Assert.ThrowsException<ArgumentNullException>(() => MemoryUtil.CopyArray(testHandle, 0, null, 0, 1));
+ Assert.ThrowsException<ArgumentNullException>(() => MemoryUtil.CopyArray(null, 0, testHandle, 0, 1));
+ Assert.ThrowsException<ArgumentNullException>(() => MemoryUtil.CopyArray(testArray, 0, (byte[])null, 0, 1));
+
/*
* Test out of range values for empty blocks
@@ -704,6 +735,9 @@ namespace VNLib.Utils.Memory.Tests
Assert.ThrowsException<ArgumentOutOfRangeException>(() => MemoryUtil.CopyArray(Array.Empty<byte>(), 0, testHandle, 0, 1));
Assert.ThrowsException<ArgumentOutOfRangeException>(() => MemoryUtil.CopyArray(testHandle, 0, Array.Empty<byte>(), 0, 1));
+ Assert.ThrowsException<ArgumentOutOfRangeException>(() => MemoryUtil.CopyArray(Array.Empty<byte>(), 0, Array.Empty<byte>(), 0, 1));
+
+
/*
* Check for out of range with valid handles
@@ -739,6 +773,11 @@ namespace VNLib.Utils.Memory.Tests
Assert.ThrowsException<ArgumentOutOfRangeException>(() => MemoryUtil.CopyArray(testArray, 0, testHandle, 1, 16));
Assert.ThrowsException<ArgumentOutOfRangeException>(() => MemoryUtil.CopyArray(testArray, 1, testHandle, 0, 16));
+ Assert.ThrowsException<ArgumentOutOfRangeException>(() => MemoryUtil.CopyArray(testArray, 0, new byte[16], 0, 17));
+ Assert.ThrowsException<ArgumentOutOfRangeException>(() => MemoryUtil.CopyArray(new byte[16], 0, testArray, 1, 16));
+ Assert.ThrowsException<ArgumentOutOfRangeException>(() => MemoryUtil.CopyArray(new byte[16], 1, testArray, 0, 16));
+
+
/*
* Test inbounds test values
*/
@@ -769,6 +808,7 @@ namespace VNLib.Utils.Memory.Tests
MemoryUtil.CopyArray(testHandle, 0, testArray, 1, 15);
MemoryUtil.CopyArray(testHandle, 1, testArray, 0, 15);
+
MemoryUtil.CopyArray(testArray, 0, testHandle, 0, 16);
MemoryUtil.CopyArray(testArray, 0, testHandle, 1, 15);
MemoryUtil.CopyArray(testArray, 1, testHandle, 0, 15);
@@ -784,6 +824,7 @@ namespace VNLib.Utils.Memory.Tests
MemoryUtil.Copy(testMem.Span, 0, testHandle, 0, 0);
MemoryUtil.CopyArray(testHandle, 0, testArray, 0, 0);
MemoryUtil.CopyArray(testArray, 0, testHandle, 0, 0);
+ MemoryUtil.CopyArray(testArray, 0, [], 0, 0);
/*
* Test negative values for span/memory overloads that
diff --git a/lib/Utils/tests/Memory/NativeHeapTests.cs b/lib/Utils/tests/Memory/NativeHeapTests.cs
index 291faa5..8653bd0 100644
--- a/lib/Utils/tests/Memory/NativeHeapTests.cs
+++ b/lib/Utils/tests/Memory/NativeHeapTests.cs
@@ -8,6 +8,7 @@ namespace VNLib.Utils.Memory.Tests
public class NativeHeapTests
{
const string RpMallocLibPath = "../../../../../Utils.Memory/vnlib_rpmalloc/build/Debug/vnlib_rpmalloc.dll";
+ const string MimallocLibPath = "../../../../../Utils.Memory/vnlib_mimalloc/build/Debug/vnlib_mimalloc.dll";
[TestMethod()]
public void LoadInTreeRpmallocTest()
@@ -21,6 +22,31 @@ namespace VNLib.Utils.Memory.Tests
Assert.IsTrue(block != IntPtr.Zero);
+ //Attempt to realloc
+ heap.Resize(ref block, 200, sizeof(byte), false);
+
+ //Free the block
+ Assert.IsTrue(heap.Free(ref block));
+
+ //confirm the pointer it zeroed
+ Assert.IsTrue(block == IntPtr.Zero);
+ }
+
+ [TestMethod()]
+ public void LoadInTreeMimallocTest()
+ {
+ //Try to load the shared heap
+ using NativeHeap heap = NativeHeap.LoadHeap(MimallocLibPath, System.Runtime.InteropServices.DllImportSearchPath.SafeDirectories, HeapCreation.Shared, 0);
+
+ Assert.IsFalse(heap.IsInvalid);
+
+ IntPtr block = heap.Alloc(100, sizeof(byte), false);
+
+ Assert.IsTrue(block != IntPtr.Zero);
+
+ //Attempt to realloc
+ heap.Resize(ref block, 200, sizeof(byte), false);
+
//Free the block
Assert.IsTrue(heap.Free(ref block));
diff --git a/lib/Utils/tests/VNLib.UtilsTests.csproj b/lib/Utils/tests/VNLib.UtilsTests.csproj
index 6a8a065..75093f8 100644
--- a/lib/Utils/tests/VNLib.UtilsTests.csproj
+++ b/lib/Utils/tests/VNLib.UtilsTests.csproj
@@ -16,9 +16,9 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
- <PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
- <PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
+ <PackageReference Include="MSTest.TestAdapter" Version="3.2.0" />
+ <PackageReference Include="MSTest.TestFramework" Version="3.2.0" />
<PackageReference Include="coverlet.collector" Version="6.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>