From de94d788e9a47432a7630a8215896b8dd3628599 Mon Sep 17 00:00:00 2001 From: vnugent Date: Sun, 8 Jan 2023 16:01:54 -0500 Subject: Reorder + analyzer cleanup --- Utils/LICENSE.txt | 293 ------- Utils/README.md | 36 - Utils/src/Async/AccessSerializer.cs | 297 ------- Utils/src/Async/AsyncExclusiveResource.cs | 169 ---- Utils/src/Async/AsyncQueue.cs | 144 ---- Utils/src/Async/AsyncUpdatableResource.cs | 111 --- Utils/src/Async/Exceptions/AsyncUpdateException.cs | 52 -- Utils/src/Async/IAsyncExclusiveResource.cs | 40 - Utils/src/Async/IAsyncWaitHandle.cs | 41 - Utils/src/Async/IWaitHandle.cs | 59 -- Utils/src/BitField.cs | 115 --- Utils/src/ERRNO.cs | 152 ---- Utils/src/Extensions/CacheExtensions.cs | 348 -------- Utils/src/Extensions/CollectionExtensions.cs | 98 --- Utils/src/Extensions/IoExtensions.cs | 345 -------- Utils/src/Extensions/JsonExtensions.cs | 215 ----- Utils/src/Extensions/MemoryExtensions.cs | 769 ----------------- Utils/src/Extensions/MutexReleaser.cs | 62 -- Utils/src/Extensions/SafeLibraryExtensions.cs | 103 --- Utils/src/Extensions/SemSlimReleaser.cs | 51 -- Utils/src/Extensions/StringExtensions.cs | 481 ----------- Utils/src/Extensions/ThreadingExtensions.cs | 226 ----- Utils/src/Extensions/TimerExtensions.cs | 66 -- Utils/src/Extensions/VnStringExtensions.cs | 418 ---------- Utils/src/IIndexable.cs | 43 - Utils/src/IO/ArrayPoolStreamBuffer.cs | 70 -- Utils/src/IO/BackingStream.cs | 181 ---- Utils/src/IO/FileOperations.cs | 105 --- Utils/src/IO/IDataAccumulator.cs | 64 -- Utils/src/IO/ISlindingWindowBuffer.cs | 91 -- Utils/src/IO/IVnTextReader.cs | 72 -- Utils/src/IO/InMemoryTemplate.cs | 196 ----- Utils/src/IO/IsolatedStorageDirectory.cs | 154 ---- Utils/src/IO/SlidingWindowBufferExtensions.cs | 213 ----- Utils/src/IO/TemporayIsolatedFile.cs | 57 -- Utils/src/IO/VnMemoryStream.cs | 469 ----------- Utils/src/IO/VnStreamReader.cs | 180 ---- Utils/src/IO/VnStreamWriter.cs | 292 ------- Utils/src/IO/VnTextReaderExtensions.cs | 223 ----- Utils/src/IO/WriteOnlyBufferedStream.cs | 255 ------ Utils/src/IObjectStorage.cs | 48 -- Utils/src/Logging/ILogProvider.cs | 79 -- Utils/src/Logging/LogLevel.cs | 33 - Utils/src/Logging/LoggerExtensions.cs | 60 -- Utils/src/Memory/Caching/ICacheHolder.cs | 45 - Utils/src/Memory/Caching/ICacheable.cs | 44 - Utils/src/Memory/Caching/IObjectRental.cs | 47 -- Utils/src/Memory/Caching/IReusable.cs | 42 - Utils/src/Memory/Caching/LRUCache.cs | 127 --- Utils/src/Memory/Caching/LRUDataStore.cs | 232 ------ Utils/src/Memory/Caching/ObjectRental.cs | 236 ------ Utils/src/Memory/Caching/ObjectRentalBase.cs | 155 ---- Utils/src/Memory/Caching/ReusableStore.cs | 61 -- .../src/Memory/Caching/ThreadLocalObjectStorage.cs | 76 -- .../src/Memory/Caching/ThreadLocalReusableStore.cs | 64 -- Utils/src/Memory/ForwardOnlyBufferWriter.cs | 122 --- Utils/src/Memory/ForwardOnlyMemoryReader.cs | 74 -- Utils/src/Memory/ForwardOnlyMemoryWriter.cs | 122 --- Utils/src/Memory/ForwardOnlyReader.cs | 74 -- Utils/src/Memory/IMemoryHandle.cs | 53 -- Utils/src/Memory/IStringSerializeable.cs | 55 -- Utils/src/Memory/IUnmangedHeap.cs | 59 -- Utils/src/Memory/Memory.cs | 456 ---------- Utils/src/Memory/MemoryHandle.cs | 237 ------ Utils/src/Memory/PrivateBuffersMemoryPool.cs | 67 -- Utils/src/Memory/PrivateHeap.cs | 184 ----- Utils/src/Memory/PrivateString.cs | 185 ----- Utils/src/Memory/PrivateStringManager.cs | 117 --- Utils/src/Memory/ProcessHeap.cs | 82 -- Utils/src/Memory/RpMallocPrivateHeap.cs | 279 ------- Utils/src/Memory/SubSequence.cs | 113 --- Utils/src/Memory/SysBufferMemoryManager.cs | 102 --- Utils/src/Memory/UnmanagedHeapBase.cs | 185 ----- Utils/src/Memory/UnsafeMemoryHandle.cs | 231 ------ Utils/src/Memory/VnString.cs | 497 ----------- Utils/src/Memory/VnTable.cs | 213 ----- Utils/src/Memory/VnTempBuffer.cs | 207 ----- Utils/src/Native/SafeLibraryHandle.cs | 220 ----- Utils/src/Native/SafeMethodHandle.cs | 61 -- Utils/src/NativeLibraryException.cs | 89 -- Utils/src/Resources/BackedResourceBase.cs | 79 -- Utils/src/Resources/CallbackOpenHandle.cs | 44 - Utils/src/Resources/ExclusiveResourceHandle.cs | 81 -- Utils/src/Resources/IExclusiveResource.cs | 39 - Utils/src/Resources/IResource.cs | 38 - Utils/src/Resources/OpenHandle.cs | 38 - Utils/src/Resources/OpenResourceHandle.cs | 44 - .../src/Resources/ResourceDeleteFailedException.cs | 40 - .../src/Resources/ResourceUpdateFailedException.cs | 40 - Utils/src/Resources/UpdatableResource.cs | 113 --- Utils/src/VNLib.Utils.csproj | 47 -- Utils/src/VnDisposeable.cs | 85 -- Utils/src/VnEncoding.cs | 914 --------------------- Utils/tests/ERRNOTest.cs | 48 -- Utils/tests/Memory/MemoryHandleTest.cs | 183 ----- Utils/tests/Memory/MemoryTests.cs | 244 ------ Utils/tests/Memory/VnTableTests.cs | 168 ---- Utils/tests/README.md | 0 Utils/tests/VNLib.UtilsTests.csproj | 36 - Utils/tests/VnEncodingTests.cs | 100 --- 100 files changed, 15170 deletions(-) delete mode 100644 Utils/LICENSE.txt delete mode 100644 Utils/README.md delete mode 100644 Utils/src/Async/AccessSerializer.cs delete mode 100644 Utils/src/Async/AsyncExclusiveResource.cs delete mode 100644 Utils/src/Async/AsyncQueue.cs delete mode 100644 Utils/src/Async/AsyncUpdatableResource.cs delete mode 100644 Utils/src/Async/Exceptions/AsyncUpdateException.cs delete mode 100644 Utils/src/Async/IAsyncExclusiveResource.cs delete mode 100644 Utils/src/Async/IAsyncWaitHandle.cs delete mode 100644 Utils/src/Async/IWaitHandle.cs delete mode 100644 Utils/src/BitField.cs delete mode 100644 Utils/src/ERRNO.cs delete mode 100644 Utils/src/Extensions/CacheExtensions.cs delete mode 100644 Utils/src/Extensions/CollectionExtensions.cs delete mode 100644 Utils/src/Extensions/IoExtensions.cs delete mode 100644 Utils/src/Extensions/JsonExtensions.cs delete mode 100644 Utils/src/Extensions/MemoryExtensions.cs delete mode 100644 Utils/src/Extensions/MutexReleaser.cs delete mode 100644 Utils/src/Extensions/SafeLibraryExtensions.cs delete mode 100644 Utils/src/Extensions/SemSlimReleaser.cs delete mode 100644 Utils/src/Extensions/StringExtensions.cs delete mode 100644 Utils/src/Extensions/ThreadingExtensions.cs delete mode 100644 Utils/src/Extensions/TimerExtensions.cs delete mode 100644 Utils/src/Extensions/VnStringExtensions.cs delete mode 100644 Utils/src/IIndexable.cs delete mode 100644 Utils/src/IO/ArrayPoolStreamBuffer.cs delete mode 100644 Utils/src/IO/BackingStream.cs delete mode 100644 Utils/src/IO/FileOperations.cs delete mode 100644 Utils/src/IO/IDataAccumulator.cs delete mode 100644 Utils/src/IO/ISlindingWindowBuffer.cs delete mode 100644 Utils/src/IO/IVnTextReader.cs delete mode 100644 Utils/src/IO/InMemoryTemplate.cs delete mode 100644 Utils/src/IO/IsolatedStorageDirectory.cs delete mode 100644 Utils/src/IO/SlidingWindowBufferExtensions.cs delete mode 100644 Utils/src/IO/TemporayIsolatedFile.cs delete mode 100644 Utils/src/IO/VnMemoryStream.cs delete mode 100644 Utils/src/IO/VnStreamReader.cs delete mode 100644 Utils/src/IO/VnStreamWriter.cs delete mode 100644 Utils/src/IO/VnTextReaderExtensions.cs delete mode 100644 Utils/src/IO/WriteOnlyBufferedStream.cs delete mode 100644 Utils/src/IObjectStorage.cs delete mode 100644 Utils/src/Logging/ILogProvider.cs delete mode 100644 Utils/src/Logging/LogLevel.cs delete mode 100644 Utils/src/Logging/LoggerExtensions.cs delete mode 100644 Utils/src/Memory/Caching/ICacheHolder.cs delete mode 100644 Utils/src/Memory/Caching/ICacheable.cs delete mode 100644 Utils/src/Memory/Caching/IObjectRental.cs delete mode 100644 Utils/src/Memory/Caching/IReusable.cs delete mode 100644 Utils/src/Memory/Caching/LRUCache.cs delete mode 100644 Utils/src/Memory/Caching/LRUDataStore.cs delete mode 100644 Utils/src/Memory/Caching/ObjectRental.cs delete mode 100644 Utils/src/Memory/Caching/ObjectRentalBase.cs delete mode 100644 Utils/src/Memory/Caching/ReusableStore.cs delete mode 100644 Utils/src/Memory/Caching/ThreadLocalObjectStorage.cs delete mode 100644 Utils/src/Memory/Caching/ThreadLocalReusableStore.cs delete mode 100644 Utils/src/Memory/ForwardOnlyBufferWriter.cs delete mode 100644 Utils/src/Memory/ForwardOnlyMemoryReader.cs delete mode 100644 Utils/src/Memory/ForwardOnlyMemoryWriter.cs delete mode 100644 Utils/src/Memory/ForwardOnlyReader.cs delete mode 100644 Utils/src/Memory/IMemoryHandle.cs delete mode 100644 Utils/src/Memory/IStringSerializeable.cs delete mode 100644 Utils/src/Memory/IUnmangedHeap.cs delete mode 100644 Utils/src/Memory/Memory.cs delete mode 100644 Utils/src/Memory/MemoryHandle.cs delete mode 100644 Utils/src/Memory/PrivateBuffersMemoryPool.cs delete mode 100644 Utils/src/Memory/PrivateHeap.cs delete mode 100644 Utils/src/Memory/PrivateString.cs delete mode 100644 Utils/src/Memory/PrivateStringManager.cs delete mode 100644 Utils/src/Memory/ProcessHeap.cs delete mode 100644 Utils/src/Memory/RpMallocPrivateHeap.cs delete mode 100644 Utils/src/Memory/SubSequence.cs delete mode 100644 Utils/src/Memory/SysBufferMemoryManager.cs delete mode 100644 Utils/src/Memory/UnmanagedHeapBase.cs delete mode 100644 Utils/src/Memory/UnsafeMemoryHandle.cs delete mode 100644 Utils/src/Memory/VnString.cs delete mode 100644 Utils/src/Memory/VnTable.cs delete mode 100644 Utils/src/Memory/VnTempBuffer.cs delete mode 100644 Utils/src/Native/SafeLibraryHandle.cs delete mode 100644 Utils/src/Native/SafeMethodHandle.cs delete mode 100644 Utils/src/NativeLibraryException.cs delete mode 100644 Utils/src/Resources/BackedResourceBase.cs delete mode 100644 Utils/src/Resources/CallbackOpenHandle.cs delete mode 100644 Utils/src/Resources/ExclusiveResourceHandle.cs delete mode 100644 Utils/src/Resources/IExclusiveResource.cs delete mode 100644 Utils/src/Resources/IResource.cs delete mode 100644 Utils/src/Resources/OpenHandle.cs delete mode 100644 Utils/src/Resources/OpenResourceHandle.cs delete mode 100644 Utils/src/Resources/ResourceDeleteFailedException.cs delete mode 100644 Utils/src/Resources/ResourceUpdateFailedException.cs delete mode 100644 Utils/src/Resources/UpdatableResource.cs delete mode 100644 Utils/src/VNLib.Utils.csproj delete mode 100644 Utils/src/VnDisposeable.cs delete mode 100644 Utils/src/VnEncoding.cs delete mode 100644 Utils/tests/ERRNOTest.cs delete mode 100644 Utils/tests/Memory/MemoryHandleTest.cs delete mode 100644 Utils/tests/Memory/MemoryTests.cs delete mode 100644 Utils/tests/Memory/VnTableTests.cs delete mode 100644 Utils/tests/README.md delete mode 100644 Utils/tests/VNLib.UtilsTests.csproj delete mode 100644 Utils/tests/VnEncodingTests.cs (limited to 'Utils') diff --git a/Utils/LICENSE.txt b/Utils/LICENSE.txt deleted file mode 100644 index cbb3969..0000000 --- a/Utils/LICENSE.txt +++ /dev/null @@ -1,293 +0,0 @@ -Copyright (c) 2022 Vaughn Nugent - -Contact information - Name: Vaughn Nugent - Email: public[at]vaughnnugent[dot]com - Website: https://www.vaughnnugent.com - -The software in this repository is licensed under the GNU GPL version 2.0 (or any later version). - -SPDX-License-Identifier: GPL-2.0-or-later - -License-Text: - -GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 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. - - 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. - - 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. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU 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 -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 -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 - 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.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -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 -this License, whose permissions for other licensees extend to the -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. - -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 -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 -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 -signed it. However, nothing else grants you permission to modify or -distribute the Program 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 -all its terms and conditions for copying, distributing or modifying -the Program 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 -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. 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 -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. - -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 -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 -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -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 -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. - - 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 diff --git a/Utils/README.md b/Utils/README.md deleted file mode 100644 index ddd7e84..0000000 --- a/Utils/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# VNLib.Utils - -A .NET/C# library for common .NET operation optimizations. - -namespaces -- VNLib.Utils.Async - Provides classes for asynchronous access synchronization and some asynchronous collections -- VNLib.Utils.Extensions - Internal and external extensions for condensed common operations -- VNLib.Utils.IO - Memory focused data structures for IO operations -- VNLib.Utils.Logging - Logging interfaces for zero dependency logging -- VNLib.Utils.Memory - Utilities for safely accessing unmanaged memory and CLR memory -- VNLib.Utils.Memory.Caching - Data structures for managed object, data caching, and interfaces for cache-able objects - - -### Recommended 3rd Party Libs - -This library does not *require* any direct dependencies, however there are some optional ones that are desired for higher performance code. This library does not, modify, contribute, or affect the functionality of any of the 3rd party libraries recommended below. - -[**RPMalloc**](https://github.com/mjansson/rpmalloc) By Mattias Jansson - VNlib.Utils.Memory (and sub-classes) may load and bind function calls to this native library determined by environment variables. To use RPMalloc as the default unmanaged allocator simply add the dynamic library to the native lib search path, such as in the executable directory, and set the allocator environment variable as instructed below. - - -### Allocator selection via environment variables -Valid allocator value for the `VNLIB_SHARED_HEAP_TYPE` environment variable: -- "win32" - for win32 based private heaps (only valid if using the Microsoft Windows operating system) -- "rpmalloc" - to load the RPMalloc native library if compiled for your platform -- none - the default value, will attempt to load the win32 private heap Kernel32 library, otherwise, the native ProcessHeap() cross platform allocator - - -## Usage -A usage breakdown would be far to lengthy for this library, and instead I intend to keep valid and comprehensive documentation in Visual Studio XML documentation files included in this project's src directory. - -This library is a utilities library and therefor may be directly included in your application or libraries, - -### License - -The software in this repository is licensed under the GNU GPL version 2.0 (or any later version). -See the LICENSE files for more information. \ No newline at end of file diff --git a/Utils/src/Async/AccessSerializer.cs b/Utils/src/Async/AccessSerializer.cs deleted file mode 100644 index ce78f6c..0000000 --- a/Utils/src/Async/AccessSerializer.cs +++ /dev/null @@ -1,297 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: AccessSerializer.cs -* -* AccessSerializer.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.Threading; -using System.Threading.Tasks; - -using VNLib.Utils.Resources; - -namespace VNLib.Utils.Async -{ - /// - /// Provides access arbitration to an exclusive resouce - /// - /// The uinique identifier type for the resource - /// The resource type - public sealed class AccessSerializer where TResource : IExclusiveResource - { - private readonly SemaphoreSlim semaphore; - private readonly Func Factory; - private readonly Action CompletedCb; - private int WaitingCount; - /// - /// Creates a new with the specified factory and completed callback - /// - /// Factory function to genereate new objects from keys - /// Function to be invoked when the encapsulated objected is no longer in use - /// - public AccessSerializer(Func factory, Action completedCb) - { - this.Factory = factory ?? throw new ArgumentNullException(nameof(factory)); - this.CompletedCb = completedCb; - //Setup semaphore for locking - this.semaphore = new SemaphoreSlim(1, 1); - this.WaitingCount = 0; - } - - /// - /// Attempts to obtain an exclusive lock on the object - /// - /// - /// Time to wait for lock - /// - /// true if lock was obtained within the timeout, false if the lock was not obtained - /// - /// - public bool TryWait(TKey key, TimeSpan wait, out ExclusiveResourceHandle exObj) - { - //Increase waiting count while we wait - Interlocked.Increment(ref WaitingCount); - try - { - //Try to obtain the lock - if (semaphore.Wait(wait)) - { - TResource get() => Factory(key); - //Create new exclusive lock handle that will generate a new that calls release when freed - exObj = new(get, Release); - return true; - } - //Lock not taken - exObj = null; - return false; - } - finally - { - //Decrease the waiting count since we are no longer waiting - Interlocked.Decrement(ref WaitingCount); - } - } - /// - /// Waits for exclusive access to the resource. - /// - /// - /// An encapsulating the resource - public ExclusiveResourceHandle Wait(TKey key) - { - try - { - //Increase waiting count while we wait - Interlocked.Increment(ref WaitingCount); - //Try to obtain the lock - semaphore.Wait(); - //Local function to generate the output value - TResource get() => Factory(key); - //Create new exclusive lock handle that will generate a new that calls release when freed - return new(get, Release); - } - finally - { - //Decrease the waiting count since we are no longer waiting - Interlocked.Decrement(ref WaitingCount); - } - } - /// - /// Asynchronously waits for exclusive access to the resource. - /// - /// An encapsulating the resource - public async Task> WaitAsync(TKey key, CancellationToken cancellationToken = default) - { - try - { - //Increase waiting count while we wait - Interlocked.Increment(ref WaitingCount); - //Try to obtain the lock - await semaphore.WaitAsync(cancellationToken); - //Local function to generate the output value - TResource get() => Factory(key); - //Create new exclusive lock handle that will generate a new that calls release when freed - return new(get, Release); - } - finally - { - //Decrease the waiting count since we are no longer waiting - Interlocked.Decrement(ref WaitingCount); - } - } - /// - /// Releases an exclusive lock that is held on an object - /// - private void Release() - { - /* - * If objects are waiting for the current instance, then we will release - * the semaphore and exit, as we no longer have control over the context - */ - if (WaitingCount > 0) - { - this.semaphore.Release(); - } - else - { - //Do not release the sempahore, just dispose of the semaphore - this.semaphore.Dispose(); - //call the completed function - CompletedCb?.Invoke(); - } - } - } - - /// - /// Provides access arbitration to an - /// - /// The uinique identifier type for the resource - /// The type of the optional argument to be passed to the user-implemented factory function - /// The resource type - public sealed class AccessSerializer where TResource : IExclusiveResource - { - private readonly SemaphoreSlim semaphore; - private readonly Func Factory; - private readonly Action CompletedCb; - private int WaitingCount; - /// - /// Creates a new with the specified factory and completed callback - /// - /// Factory function to genereate new objects from keys - /// Function to be invoked when the encapsulated objected is no longer in use - /// - public AccessSerializer(Func factory, Action completedCb) - { - this.Factory = factory ?? throw new ArgumentNullException(nameof(factory)); - this.CompletedCb = completedCb; - //Setup semaphore for locking - this.semaphore = new SemaphoreSlim(1, 1); - this.WaitingCount = 0; - } - - /// - /// Attempts to obtain an exclusive lock on the object - /// - /// - /// The key identifying the resource - /// Time to wait for lock - /// - /// true if lock was obtained within the timeout, false if the lock was not obtained - /// - /// - public bool TryWait(TKey key, TArg arg, TimeSpan wait, out ExclusiveResourceHandle exObj) - { - //Increase waiting count while we wait - Interlocked.Increment(ref WaitingCount); - try - { - //Try to obtain the lock - if (semaphore.Wait(wait)) - { - TResource get() => Factory(key, arg); - //Create new exclusive lock handle that will generate a new that calls release when freed - exObj = new(get, Release); - return true; - } - //Lock not taken - exObj = null; - return false; - } - finally - { - //Decrease the waiting count since we are no longer waiting - Interlocked.Decrement(ref WaitingCount); - } - } - /// - /// Waits for exclusive access to the resource. - /// - /// The unique key that identifies the resource - /// The state argument to pass to the factory function - /// An encapsulating the resource - public ExclusiveResourceHandle Wait(TKey key, TArg arg) - { - try - { - //Increase waiting count while we wait - Interlocked.Increment(ref WaitingCount); - //Try to obtain the lock - semaphore.Wait(); - //Local function to generate the output value - TResource get() => Factory(key, arg); - //Create new exclusive lock handle that will generate a new that calls release when freed - return new(get, Release); - } - finally - { - //Decrease the waiting count since we are no longer waiting - Interlocked.Decrement(ref WaitingCount); - } - } - /// - /// Asynchronously waits for exclusive access to the resource. - /// - /// - /// The state argument to pass to the factory function - /// - /// An encapsulating the resource - public async Task> WaitAsync(TKey key, TArg arg, CancellationToken cancellationToken = default) - { - try - { - //Increase waiting count while we wait - Interlocked.Increment(ref WaitingCount); - //Try to obtain the lock - await semaphore.WaitAsync(cancellationToken); - //Local function to generate the output value - TResource get() => Factory(key, arg); - //Create new exclusive lock handle that will generate a new that calls release when freed - return new(get, Release); - } - finally - { - //Decrease the waiting count since we are no longer waiting - Interlocked.Decrement(ref WaitingCount); - } - } - - /// - /// Releases an exclusive lock that is held on an object - /// - private void Release() - { - /* - * If objects are waiting for the current instance, then we will release - * the semaphore and exit, as we no longer have control over the context - */ - if (WaitingCount > 0) - { - this.semaphore.Release(); - } - else - { - //Do not release the sempahore, just dispose of the semaphore - this.semaphore.Dispose(); - //call the completed function - CompletedCb?.Invoke(); - } - } - } -} \ No newline at end of file diff --git a/Utils/src/Async/AsyncExclusiveResource.cs b/Utils/src/Async/AsyncExclusiveResource.cs deleted file mode 100644 index 18e2a42..0000000 --- a/Utils/src/Async/AsyncExclusiveResource.cs +++ /dev/null @@ -1,169 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: AsyncExclusiveResource.cs -* -* AsyncExclusiveResource.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.Threading; -using System.Threading.Tasks; - -namespace VNLib.Utils.Async -{ - /// - /// Provides a base class for resources that must be obtained exclusivly in a multi-threaded environment - /// but allow state update operations (and their exceptions) to be deferred to the next accessor. - /// - /// The state parameter type passed during updates - public abstract class AsyncExclusiveResource : VnDisposeable, IWaitHandle, IAsyncWaitHandle - { - /// - /// Main mutli-threading lock used for primary access synchronization - /// - protected SemaphoreSlim MainLock { get; } = new (1, 1); - - private Task? LastUpdate; - - /// - /// - ///

- ///

- /// If the previous call to resulted in an asynchronous update, and exceptions occured, an - /// will be thrown enclosing the exception - ///
- /// Time in milliseconds to wait for exclusive access to the resource - /// - /// - public virtual bool WaitOne(int millisecondsTimeout) - { - //First wait for main lock - if (MainLock.Wait(millisecondsTimeout)) - { - //Main lock has been taken - try - { - //Wait for async update if there is one pending(will throw exceptions if any occurred) - LastUpdate?.Wait(); - return true; - } - catch (AggregateException ae) when (ae.InnerException != null) - { - //Release the main lock and re-throw the inner exception - _ = MainLock.Release(); - //Throw a new async update exception - throw new AsyncUpdateException(ae.InnerException); - } - catch - { - //Release the main lock and re-throw the exception - _ = MainLock.Release(); - throw; - } - } - return false; - } - - /// - /// - public virtual async Task WaitOneAsync(CancellationToken token = default) - { - //Wait for main lock - await MainLock.WaitAsync(token).ConfigureAwait(true); - //if the last update completed synchronously, return true - if (LastUpdate == null) - { - return; - } - try - { - //Await the last update task and catch its exceptions - await LastUpdate.ConfigureAwait(false); - } - catch - { - //Release the main lock and re-throw the exception - _ = MainLock.Release(); - throw; - } - } - - /// - /// Requests a resource update and releases the exclusive lock on this resource. If a deferred update operation has any - /// exceptions during its last operation, they will be thrown here. - /// - /// Specifies weather the update should be deferred or awaited on the current call - /// A state parameter to be pased to the update function - /// - public async ValueTask UpdateAndRelease(bool defer, TState state) - { - //Otherwise wait and update on the current thread - try - { - //Dispose the update task - LastUpdate?.Dispose(); - //Remove the referrence - LastUpdate = null; - //Run update on the current thread - LastUpdate = await UpdateResource(defer, state).ConfigureAwait(true); - //If the update is not deferred, await the results - if (!defer && LastUpdate != null) - { - await LastUpdate.ConfigureAwait(true); - } - } - finally - { - //Release the main lock - _ = MainLock.Release(); - } - } - - /// - /// - /// When overrriden in a derived class, is responsible for updating the state of the instance if necessary. - /// - /// - /// If the result of the update retruns a that represents the deferred update, the next call to will - /// block until the operation completes and will throw any exceptions that occured - /// - /// - /// true if the caller expects a resource update to be deferred, false if the caller expects the result of the update to be awaited - /// State parameter passed when releasing - /// A representing the async state update operation, or null if no async state update operation need's to be monitored - protected abstract ValueTask UpdateResource(bool defer, TState state); - - /// - protected override void Free() - { - //Dispose lock - MainLock.Dispose(); - - //Try to cleanup the last update - if (LastUpdate != null && LastUpdate.IsCompletedSuccessfully) - { - LastUpdate.Dispose(); - } - - LastUpdate = null; - } - - } -} \ No newline at end of file diff --git a/Utils/src/Async/AsyncQueue.cs b/Utils/src/Async/AsyncQueue.cs deleted file mode 100644 index ba45513..0000000 --- a/Utils/src/Async/AsyncQueue.cs +++ /dev/null @@ -1,144 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: AsyncQueue.cs -* -* AsyncQueue.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.Threading; -using System.Threading.Tasks; -using System.Threading.Channels; -using System.Diagnostics.CodeAnalysis; - -namespace VNLib.Utils.Async -{ - /// - /// Provides a based asynchronous queue - /// - /// The event object type - public class AsyncQueue - { - private readonly Channel _channel; - - /// - /// Initalizes a new multi-threaded bound channel queue, that accepts - /// the number of items before it will - /// return asynchronously, or fail to enqueue items - /// - /// The maxium number of items to allow in the queue - public AsyncQueue(int capacity):this(false, false, capacity) - {} - /// - /// Initalizes a new multi-threaded unbound channel queue - /// - public AsyncQueue():this(false, false) - {} - - /// - /// Initalizes a new queue that allows specifying concurrency requirements - /// and a bound/unbound channel capacity - /// - /// A value that specifies only a single thread be enqueing items? - /// A value that specifies only a single thread will be dequeing - /// The maxium number of items to enque without failing - public AsyncQueue(bool singleWriter, bool singleReader, int capacity = int.MaxValue) - { - if(capacity == int.MaxValue) - { - //Create unbounded - UnboundedChannelOptions opt = new() - { - SingleReader = singleReader, - SingleWriter = singleWriter, - AllowSynchronousContinuations = true, - }; - _channel = Channel.CreateUnbounded(opt); - } - else - { - //Create bounded - BoundedChannelOptions opt = new(capacity) - { - SingleReader = singleReader, - SingleWriter = singleWriter, - AllowSynchronousContinuations = true, - //Default wait for space - FullMode = BoundedChannelFullMode.Wait - }; - _channel = Channel.CreateBounded(opt); - } - } - - /// - /// Initalizes a new unbound channel based queue - /// - /// Channel options - public AsyncQueue(UnboundedChannelOptions ubOptions) - { - _channel = Channel.CreateUnbounded(ubOptions); - } - - /// - /// Initalizes a new bound channel based queue - /// - /// Channel options - public AsyncQueue(BoundedChannelOptions options) - { - _channel = Channel.CreateBounded(options); - } - - /// - /// Attemts to enqeue an item if the queue has the capacity - /// - /// The item to eqneue - /// True if the queue can accept another item, false otherwise - public bool TryEnque(T item) => _channel.Writer.TryWrite(item); - /// - /// Enqueues an item to the end of the queue and notifies a waiter that an item was enqueued - /// - /// The item to enqueue - /// - /// - public ValueTask EnqueueAsync(T item, CancellationToken cancellationToken = default) => _channel.Writer.WriteAsync(item, cancellationToken); - /// - /// Asynchronously waits for an item to be Enqueued to the end of the queue. - /// - /// The item at the begining of the queue - /// - public ValueTask DequeueAsync(CancellationToken cancellationToken = default) => _channel.Reader.ReadAsync(cancellationToken); - /// - /// Removes the object at the beginning of the queue and stores it to the result parameter. Without waiting for a change - /// event. - /// - /// The item that was at the begining of the queue - /// True if the queue could be read synchronously, false if the lock could not be entered, or the queue contains no items - /// - public bool TryDequeue([MaybeNullWhen(false)] out T result) => _channel.Reader.TryRead(out result); - /// - /// Peeks the object at the beginning of the queue and stores it to the result parameter. Without waiting for a change - /// event. - /// - /// The item that was at the begining of the queue - /// True if the queue could be read synchronously, false if the lock could not be entered, or the queue contains no items - /// - public bool TryPeek([MaybeNullWhen(false)] out T result) => _channel.Reader.TryPeek(out result); - } -} diff --git a/Utils/src/Async/AsyncUpdatableResource.cs b/Utils/src/Async/AsyncUpdatableResource.cs deleted file mode 100644 index b4ce519..0000000 --- a/Utils/src/Async/AsyncUpdatableResource.cs +++ /dev/null @@ -1,111 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: AsyncUpdatableResource.cs -* -* AsyncUpdatableResource.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.Text.Json; -using System.Threading.Tasks; - -using VNLib.Utils.IO; -using VNLib.Utils.Resources; - -namespace VNLib.Utils.Async -{ - /// - /// A callback delegate used for updating a - /// - /// The to be updated - /// The serialized data to be stored/updated - /// - public delegate Task AsyncUpdateCallback(object source, Stream data); - /// - /// A callback delegate invoked when a delete is requested - /// - /// The to be deleted - /// - public delegate Task AsyncDeleteCallback(object source); - - /// - /// Implemented by a resource that is backed by an external data store, that when modified or deleted will - /// be reflected to the backing store. - /// - public abstract class AsyncUpdatableResource : BackedResourceBase, IAsyncExclusiveResource - { - protected abstract AsyncUpdateCallback UpdateCb { get; } - protected abstract AsyncDeleteCallback DeleteCb { get; } - - /// - /// Releases the resource and flushes pending changes to its backing store. - /// - /// A task that represents the async operation - /// - /// - /// - public virtual async ValueTask ReleaseAsync() - { - //If resource has already been realeased, return - if (IsReleased) - { - return; - } - //If deleted flag is set, invoke the delete callback - if (Deleted) - { - await DeleteCb(this).ConfigureAwait(true); - } - //If the state has been modifed, flush changes to the store - else if (Modified) - { - await FlushPendingChangesAsync().ConfigureAwait(true); - } - //Set the released value - IsReleased = true; - } - - /// - /// - /// Writes the current state of the the resource to the backing store - /// immediatly by invoking the specified callback. - /// - /// - /// Only call this method if your store supports multiple state updates - /// - /// - protected virtual async Task FlushPendingChangesAsync() - { - //Get the resource - object resource = GetResource(); - //Open a memory stream to store data in - using VnMemoryStream data = new(); - //Serialize and write to stream - VnEncoding.JSONSerializeToBinary(resource, data, resource.GetType(), base.JSO); - //Reset stream to begining - _ = data.Seek(0, SeekOrigin.Begin); - //Invoke update callback - await UpdateCb(this, data).ConfigureAwait(true); - //Clear modified flag - Modified = false; - } - } -} diff --git a/Utils/src/Async/Exceptions/AsyncUpdateException.cs b/Utils/src/Async/Exceptions/AsyncUpdateException.cs deleted file mode 100644 index de5a491..0000000 --- a/Utils/src/Async/Exceptions/AsyncUpdateException.cs +++ /dev/null @@ -1,52 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: AsyncUpdateException.cs -* -* AsyncUpdateException.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 VNLib.Utils.Resources; - -namespace VNLib.Utils.Async -{ - /// - /// Represents an exception that was raised during an asyncronous update of a resource. The stores the - /// details of the actual exception raised - /// - public sealed class AsyncUpdateException : ResourceUpdateFailedException - { - /// - /// - /// - /// - public AsyncUpdateException(Exception inner) : base("", inner) { } - - public AsyncUpdateException() - {} - - public AsyncUpdateException(string message) : base(message) - {} - - public AsyncUpdateException(string message, Exception innerException) : base(message, innerException) - {} - } -} \ No newline at end of file diff --git a/Utils/src/Async/IAsyncExclusiveResource.cs b/Utils/src/Async/IAsyncExclusiveResource.cs deleted file mode 100644 index 93157ce..0000000 --- a/Utils/src/Async/IAsyncExclusiveResource.cs +++ /dev/null @@ -1,40 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: IAsyncExclusiveResource.cs -* -* IAsyncExclusiveResource.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.Threading.Tasks; -using VNLib.Utils.Resources; - -namespace VNLib.Utils.Async -{ - /// - /// - /// - public interface IAsyncExclusiveResource : IResource - { - /// - /// Releases the resource from use. Called when a is disposed - /// - ValueTask ReleaseAsync(); - } -} \ No newline at end of file diff --git a/Utils/src/Async/IAsyncWaitHandle.cs b/Utils/src/Async/IAsyncWaitHandle.cs deleted file mode 100644 index 1cadc06..0000000 --- a/Utils/src/Async/IAsyncWaitHandle.cs +++ /dev/null @@ -1,41 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: IAsyncWaitHandle.cs -* -* IAsyncWaitHandle.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.Threading; -using System.Threading.Tasks; - -namespace VNLib.Utils.Async -{ - /// - /// Provides a synchronization handle that can be asynchronously aquired - /// - public interface IAsyncWaitHandle - { - /// - /// Waits for exclusive access to the resource until the expires - /// - /// - Task WaitOneAsync(CancellationToken token = default); - } -} \ No newline at end of file diff --git a/Utils/src/Async/IWaitHandle.cs b/Utils/src/Async/IWaitHandle.cs deleted file mode 100644 index 85e8a2a..0000000 --- a/Utils/src/Async/IWaitHandle.cs +++ /dev/null @@ -1,59 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: IWaitHandle.cs -* -* IWaitHandle.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.Threading; - -namespace VNLib.Utils.Async -{ - /// - /// Provides basic thread synchronization functions similar to - /// - public interface IWaitHandle - { - /// - /// Waits for exclusive access to the resource indefinitly. If the signal is never received this method never returns - /// - /// - /// - /// - /// true if the current thread received the signal - public virtual bool WaitOne() => WaitOne(Timeout.Infinite); - /// - /// Waits for exclusive access to the resource until the specified number of milliseconds - /// - /// Time in milliseconds to wait for exclusive access to the resource - /// true if the current thread received the signal, false if the timout expired, and access was not granted - /// - /// - bool WaitOne(int millisecondsTimeout); - /// - /// Waits for exclusive access to the resource until the specified - /// - /// true if the current thread received the signal, false if the timout expired, and access was not granted - /// - /// - public virtual bool WaitOne(TimeSpan timeout) => WaitOne(Convert.ToInt32(timeout.TotalMilliseconds)); - } -} \ No newline at end of file diff --git a/Utils/src/BitField.cs b/Utils/src/BitField.cs deleted file mode 100644 index bc001df..0000000 --- a/Utils/src/BitField.cs +++ /dev/null @@ -1,115 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: BitField.cs -* -* BitField.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.Runtime.CompilerServices; - -namespace VNLib.Utils -{ - /// - /// Represents a field of 64 bits that can be set or cleared using unsigned or signed masks - /// - public class BitField - { - private ulong Field; - /// - /// The readonly value of the - /// - public ulong Value => Field; - /// - /// Creates a new initialized to the specified value - /// - /// Initial value - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public BitField(ulong initial) => Field = initial; - /// - /// Creates a new initialized to the specified value - /// - /// Initial value - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public BitField(long initial) => Field = unchecked((ulong)initial); - /// - /// Determines if the specified flag is set - /// - /// The mask to compare against the field value - /// True if the flag(s) is currently set, false if flag is not set - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsSet(ulong mask) => (Field & mask) != 0; - /// - /// Determines if the specified flag is set - /// - /// The mask to compare against the field value - /// True if the flag(s) is currently set, false if flag is not set - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsSet(long mask) => (Field & unchecked((ulong)mask)) != 0; - /// - /// Determines if the specified flag is set - /// - /// The mask to compare against the field value - /// True if the flag(s) is currently set, false if flag is not set - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Set(ulong mask) => Field |= mask; - /// - /// Determines if the specified flag is set - /// - /// The mask to compare against the field value - /// True if the flag(s) is currently set, false if flag is not set - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Set(long mask) => Field |= unchecked((ulong)mask); - /// - /// Sets or clears a flag(s) indentified by a mask based on the value - /// - /// Mask used to identify flags - /// True to set a flag, false to clear a flag - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Set(ulong mask, bool value) - { - if (value) - { - Set(mask); - } - else - { - Clear(mask); - } - } - /// - /// Clears the flag identified by the specified mask - /// - /// The mask used to clear the given flag - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Clear(ulong mask) => Field &= ~mask; - /// - /// Clears the flag identified by the specified mask - /// - /// The mask used to clear the given flag - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Clear(long mask) => Field &= ~unchecked((ulong)mask); - /// - /// Clears all flags by setting the property value to 0 - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ClearAll() => Field = 0; - } -} \ No newline at end of file diff --git a/Utils/src/ERRNO.cs b/Utils/src/ERRNO.cs deleted file mode 100644 index c3c61de..0000000 --- a/Utils/src/ERRNO.cs +++ /dev/null @@ -1,152 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: ERRNO.cs -* -* ERRNO.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.Runtime.InteropServices; - -namespace VNLib.Utils -{ - /// - /// Implements a C style integer error code type. Size is platform dependent - /// - [StructLayout(LayoutKind.Sequential)] - public readonly struct ERRNO : IEquatable, ISpanFormattable, IFormattable - { - /// - /// Represents a successfull error code (true) - /// - public static readonly ERRNO SUCCESS = true; - - /// - /// Represents a failure error code (false) - /// - public static readonly ERRNO E_FAIL = false; - - private readonly nint ErrorCode; - /// - /// Creates a new from the specified error value - /// - /// The value of the error to represent - public ERRNO(nint errno) => ErrorCode = errno; - /// - /// Creates a new from an error code. null = 0 = false - /// - /// Error code - public static implicit operator ERRNO(int errorVal) => new (errorVal); - /// - /// Creates a new from an error code. null = 0 = false - /// - /// Error code - public static explicit operator ERRNO(int? errorVal) => new(errorVal ?? 0); - /// - /// Creates a new from a booleam, 1 if true, 0 if false - /// - /// - public static implicit operator ERRNO(bool errorVal) => new(errorVal ? 1 : 0); - /// - /// Creates a new from a pointer value - /// - /// The pointer value representing an error code - public static implicit operator ERRNO(nint errno) => new(errno); - /// - /// Error value as integer. Value of supplied error code or if cast from boolean 1 if true, 0 if false - /// - /// to get error code from - public static implicit operator int(ERRNO errorVal) => (int)errorVal.ErrorCode; - /// - /// C style boolean conversion. false if 0, true otherwise - /// - /// - public static implicit operator bool(ERRNO errorVal) => errorVal != 0; - /// - /// Creates a new from the value if the stored (nint) error code - /// - /// The contating the pointer value - public static implicit operator IntPtr(ERRNO errno) => new(errno.ErrorCode); - /// - /// Creates a new nint from the value if the stored error code - /// - /// The contating the pointer value - public static implicit operator nint(ERRNO errno) => errno.ErrorCode; - - public static ERRNO operator +(ERRNO err, int add) => new(err.ErrorCode + add); - public static ERRNO operator +(ERRNO err, nint add) => new(err.ErrorCode + add); - public static ERRNO operator ++(ERRNO err) => new(err.ErrorCode + 1); - public static ERRNO operator --(ERRNO err) => new(err.ErrorCode - 1); - public static ERRNO operator -(ERRNO err, int subtract) => new(err.ErrorCode - subtract); - public static ERRNO operator -(ERRNO err, nint subtract) => new(err.ErrorCode - subtract); - - public static bool operator >(ERRNO err, ERRNO other) => err.ErrorCode > other.ErrorCode; - public static bool operator <(ERRNO err, ERRNO other) => err.ErrorCode < other.ErrorCode; - public static bool operator >=(ERRNO err, ERRNO other) => err.ErrorCode >= other.ErrorCode; - public static bool operator <=(ERRNO err, ERRNO other) => err.ErrorCode <= other.ErrorCode; - - public static bool operator >(ERRNO err, int other) => err.ErrorCode > other; - public static bool operator <(ERRNO err, int other) => err.ErrorCode < other; - public static bool operator >=(ERRNO err, int other) => err.ErrorCode >= other; - public static bool operator <=(ERRNO err, int other) => err.ErrorCode <= other; - - public static bool operator >(ERRNO err, nint other) => err.ErrorCode > other; - public static bool operator <(ERRNO err, nint other) => err.ErrorCode < other; - public static bool operator >=(ERRNO err, nint other) => err.ErrorCode >= other; - public static bool operator <=(ERRNO err, nint other) => err.ErrorCode <= other; - - public static bool operator ==(ERRNO err, ERRNO other) => err.ErrorCode == other.ErrorCode; - public static bool operator !=(ERRNO err, ERRNO other) => err.ErrorCode != other.ErrorCode; - public static bool operator ==(ERRNO err, int other) => err.ErrorCode == other; - public static bool operator !=(ERRNO err, int other) => err.ErrorCode != other; - public static bool operator ==(ERRNO err, nint other) => err.ErrorCode == other; - public static bool operator !=(ERRNO err, nint other) => err.ErrorCode != other; - - public readonly bool Equals(ERRNO other) => ErrorCode == other.ErrorCode; - public readonly override bool Equals(object obj) => obj is ERRNO other && Equals(other); - public readonly override int GetHashCode() => ErrorCode.GetHashCode(); - - /// - /// The integer error value of the current instance in radix 10 - /// - /// - public readonly override string ToString() - { - //Return the string of the error code number - return ErrorCode.ToString(); - } - public readonly string ToString(string format) - { - //Return the string of the error code number - return ErrorCode.ToString(format); - } - - /// - public readonly bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider provider) - { - return ErrorCode.TryFormat(destination, out charsWritten, format, provider); - } - /// - public readonly string ToString(string format, IFormatProvider formatProvider) - { - return ErrorCode.ToString(format, formatProvider); - } - } -} diff --git a/Utils/src/Extensions/CacheExtensions.cs b/Utils/src/Extensions/CacheExtensions.cs deleted file mode 100644 index 5485c2d..0000000 --- a/Utils/src/Extensions/CacheExtensions.cs +++ /dev/null @@ -1,348 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: CacheExtensions.cs -* -* CacheExtensions.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.Linq; -using System.Collections.Generic; - -using VNLib.Utils.Memory.Caching; - -namespace VNLib.Utils.Extensions -{ - /// - /// Cache collection extensions - /// - public static class CacheExtensions - { - /// - /// - /// Stores a new record. If an old record exists, the records are compared, - /// if they are not equal, the old record is evicted and the new record is stored - /// - /// - /// - /// A cachable object - /// - /// The unique key identifying the record - /// The record to store - /// - /// Locks on the store parameter to provide mutual exclusion for non thread-safe - /// data structures. - /// - public static void StoreRecord(this IDictionary store, TKey key, T record) where T : ICacheable - { - T ?oldRecord = default; - lock (store) - { - //See if an old record exists - if (!store.Remove(key, out oldRecord) || oldRecord == null) - { - //Old record doesnt exist, store and return - store[key] = record; - return; - } - //See if the old and new records and the same record - if (oldRecord.Equals(record)) - { - //records are equal, so we can exit - return; - } - //Old record is not equal, so we can store the new record and evict the old on - store[key] = record; - } - //Call evict on the old record - oldRecord.Evicted(); - } - /// - /// - /// Stores a new record and updates the expiration date. If an old record exists, the records - /// are compared, if they are not equal, the old record is evicted and the new record is stored - /// - /// - /// - /// A cachable object - /// - /// The unique key identifying the record - /// The record to store - /// The new expiration time of the record - /// - /// Locks on the store parameter to provide mutual exclusion for non thread-safe - /// data structures. - /// - public static void StoreRecord(this IDictionary store, TKey key, T record, TimeSpan validFor) where T : ICacheable - { - //Update the expiration time - record.Expires = DateTime.UtcNow.Add(validFor); - //Store - StoreRecord(store, key, record); - } - /// - /// - /// Returns a stored record if it exists and is not expired. If the record exists - /// but has expired, it is evicted. - /// - /// - /// If a record is evicted, the return value evaluates to -1 and the value parameter - /// is set to the old record if the caller wished to inspect the record after the - /// eviction method completes - /// - /// - /// - /// A cachable object - /// - /// - /// The record - /// - /// Gets a value indicating the reults of the operation. 0 if the record is not found, -1 if expired, 1 if - /// record is valid - /// - /// - /// Locks on the store parameter to provide mutual exclusion for non thread-safe - /// data structures. - /// - public static ERRNO TryGetOrEvictRecord(this IDictionary store, TKey key, out T? value) where T : ICacheable - { - value = default; - //Cache current date time before entering the lock - DateTime now = DateTime.UtcNow; - //Get value - lock (store) - { - //try to get the value - if (!store.TryGetValue(key, out value)) - { - //not found - return 0; - } - //Not expired - if (value.Expires > now) - { - return true; - } - //Remove from store - _ = store.Remove(key); - } - //Call the evict func - value.Evicted(); - return -1; - } - /// - /// Updates the expiration date on a record to the specified time if it exists, regardless - /// of its validity - /// - /// Diction key type - /// A cachable object - /// - /// The unique key identifying the record to update - /// The expiration time (time added to ) - /// - /// Locks on the store parameter to provide mutual exclusion for non thread-safe - /// data structures. - /// - public static void UpdateRecord(this IDictionary store, TKey key, TimeSpan extendedTime) where T : ICacheable - { - //Cacl the expiration time - DateTime expiration = DateTime.UtcNow.Add(extendedTime); - lock (store) - { - //Update the expiration time if the record exists - if (store.TryGetValue(key, out T? record) && record != null) - { - record.Expires = expiration; - } - } - } - /// - /// Evicts a stored record from the store. If the record is found, the eviction - /// method is executed - /// - /// - /// - /// - /// The unique key identifying the record - /// True if the record was found and evicted - public static bool EvictRecord(this IDictionary store, TKey key) where T : ICacheable - { - T? record = default; - lock (store) - { - //Try to remove the record - if (!store.Remove(key, out record) || record == null) - { - //No record found or null - return false; - } - } - //Call eviction mode - record.Evicted(); - return true; - } - /// - /// Evicts all expired records from the store - /// - /// - /// - public static void CollectRecords(this IDictionary store) where T : ICacheable - { - CollectRecords(store, DateTime.UtcNow); - } - - /// - /// Evicts all expired records from the store - /// - /// - /// - /// - /// A time that specifies the time which expired records should be evicted - public static void CollectRecords(this IDictionary store, DateTime validAfter) where T : ICacheable - { - //Build a query to get the keys that belong to the expired records - IEnumerable> expired = store.Where(s => s.Value.Expires < validAfter); - //temp list for expired records - IEnumerable evicted; - //Take lock on store - lock (store) - { - KeyValuePair[] kvp = expired.ToArray(); - //enumerate to array so values can be removed while the lock is being held - foreach (KeyValuePair pair in kvp) - { - //remove the record and call the eviction method - _ = store.Remove(pair); - } - //select values while lock held - evicted = kvp.Select(static v => v.Value); - } - //Iterrate over evicted records and call evicted method - foreach (T ev in evicted) - { - ev.Evicted(); - } - } - - /// - /// Allows for mutually exclusive use of a record with a - /// state parameter - /// - /// - /// - /// - /// - /// The unique key identifying the record - /// A user-token type state parameter to pass to the use callback method - /// A callback method that will be passed the record to use within an exclusive context - public static void UseRecord(this IDictionary store, TKey key, State state, Action useCtx) where T: ICacheable - { - lock (store) - { - //If the record exists - if(store.TryGetValue(key, out T record)) - { - //Use it within the lock statement - useCtx(record, state); - } - } - } - /// - /// Allows for mutually exclusive use of a - /// - /// - /// - /// - /// The unique key identifying the record - /// A callback method that will be passed the record to use within an exclusive context - public static void UseRecord(this IDictionary store, TKey key, Action useCtx) where T : ICacheable - { - lock (store) - { - //If the record exists - if (store.TryGetValue(key, out T record)) - { - //Use it within the lock statement - useCtx(record); - } - } - } - /// - /// Allows for mutually exclusive use of a record with a - /// state parameter, only if the found record is valid - /// - /// - /// - /// - /// - /// The unique key identifying the record - /// A user-token type state parameter to pass to the use callback method - /// A callback method that will be passed the record to use within an exclusive context - /// If the record is found, but is expired, the record is evicted from the store. The callback is never invoked - public static void UseIfValid(this IDictionary store, TKey key, State state, Action useCtx) where T : ICacheable - { - DateTime now = DateTime.UtcNow; - T? record; - lock (store) - { - //If the record exists, check if its valid - if (store.TryGetValue(key, out record) && record.Expires < now) - { - //Use it within the lock statement - useCtx(record, state); - return; - } - //Record is no longer valid - _ = store.Remove(key); - } - //Call evicted method - record?.Evicted(); - } - /// - /// Allows for mutually exclusive use of a record with a - /// state parameter, only if the found record is valid - /// - /// - /// - /// - /// The unique key identifying the record - /// A callback method that will be passed the record to use within an exclusive context - /// If the record is found, but is expired, the record is evicted from the store. The callback is never invoked - public static void UseIfValid(this IDictionary store, TKey key, Action useCtx) where T : ICacheable - { - DateTime now = DateTime.UtcNow; - T? record; - lock (store) - { - //If the record exists, check if its valid - if (store.TryGetValue(key, out record) && record.Expires < now) - { - //Use it within the lock statement - useCtx(record); - return; - } - //Record is no longer valid - _ = store.Remove(key); - } - //Call evicted method - record?.Evicted(); - } - } -} diff --git a/Utils/src/Extensions/CollectionExtensions.cs b/Utils/src/Extensions/CollectionExtensions.cs deleted file mode 100644 index e4ec459..0000000 --- a/Utils/src/Extensions/CollectionExtensions.cs +++ /dev/null @@ -1,98 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: CollectionExtensions.cs -* -* CollectionExtensions.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.Collections.Generic; - -using VNLib.Utils.Memory; - -namespace VNLib.Utils.Extensions -{ - /// - /// Provides collection extension methods - /// - public static class CollectionExtensions - { - /// - /// Gets a previously-stored base32 encoded value-type from the lookup and returns its initialized structure from - /// the value stored - /// - /// The key type used to index the lookup - /// An unmanaged structure type - /// - /// The key used to identify the value - /// The initialized structure, or default if the lookup returns null/empty string - public static TValue GetValueType(this IIndexable lookup, TKey key) where TValue : unmanaged where TKey : notnull - { - //Get value - string value = lookup[key]; - //If the string is set, recover the value and return it - return string.IsNullOrWhiteSpace(value) ? default : VnEncoding.FromBase32String(value); - } - - /// - /// Serializes a value-type in base32 encoding and stores it at the specified key - /// - /// The key type used to index the lookup - /// An unmanaged structure type - /// - /// The key used to identify the value - /// The value to serialze - public static void SetValueType(this IIndexable lookup, TKey key, TValue value) where TValue : unmanaged where TKey : notnull - { - //encode string from value type and store in lookup - lookup[key] = VnEncoding.ToBase32String(value); - } - /// - /// Executes a handler delegate on every element of the list within a try-catch block - /// and rethrows exceptions as an - /// - /// - /// - /// An handler delegate to complete some operation on the elements within the list - /// - public static void TryForeach(this IEnumerable list, Action handler) - { - List? exceptionList = null; - foreach(T item in list) - { - try - { - handler(item); - } - catch(Exception ex) - { - //Init new list and add the exception - exceptionList ??= new(); - exceptionList.Add(ex); - } - } - //Raise aggregate exception for all caught exceptions - if(exceptionList?.Count > 0) - { - throw new AggregateException(exceptionList); - } - } - } -} diff --git a/Utils/src/Extensions/IoExtensions.cs b/Utils/src/Extensions/IoExtensions.cs deleted file mode 100644 index f312203..0000000 --- a/Utils/src/Extensions/IoExtensions.cs +++ /dev/null @@ -1,345 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: IoExtensions.cs -* -* IoExtensions.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.Buffers; -using System.Threading; -using System.Threading.Tasks; -using System.Runtime.Versioning; -using System.Runtime.CompilerServices; - -using VNLib.Utils.IO; -using VNLib.Utils.Memory; - -using static VNLib.Utils.Memory.Memory; - -namespace VNLib.Utils.Extensions -{ - /// - /// Provieds extension methods for common IO operations - /// - public static class IoExtensions - { - /// - /// Unlocks the entire file - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("macos")] - [UnsupportedOSPlatform("tvos")] - public static void Unlock(this FileStream fs) - { - _ = fs ?? throw new ArgumentNullException(nameof(fs)); - //Unlock the entire file - fs.Unlock(0, fs.Length); - } - - /// - /// Locks the entire file - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("macos")] - [UnsupportedOSPlatform("tvos")] - public static void Lock(this FileStream fs) - { - _ = fs ?? throw new ArgumentNullException(nameof(fs)); - //Lock the entire length of the file - fs.Lock(0, fs.Length); - } - - /// - /// Provides an async wrapper for copying data from the current stream to another using an unmanged - /// buffer. - /// - /// - /// The destination data stream to write data to - /// The size of the buffer to use while copying data. (Value will be clamped to the size of the stream if seeking is available) - /// The to allocate the buffer from - /// A token that may cancel asynchronous operations - /// A that completes when the copy operation has completed - /// - /// - public static async ValueTask CopyToAsync(this Stream source, Stream dest, int bufferSize, IUnmangedHeap heap, CancellationToken token = default) - { - if (source.CanSeek) - { - bufferSize = (int)Math.Min(source.Length, bufferSize); - } - //Alloc a buffer - using IMemoryOwner buffer = heap.DirectAlloc(bufferSize); - //Wait for copy to complete - await CopyToAsync(source, dest, buffer.Memory, token); - } - /// - /// Provides an async wrapper for copying data from the current stream to another with a - /// buffer from the - /// - /// - /// The destination data stream to write data to - /// The size of the buffer to use while copying data. (Value will be clamped to the size of the stream if seeking is available) - /// The number of bytes to copy from the current stream to destination stream - /// The heap to alloc buffer from - /// A token that may cancel asynchronous operations - /// A that completes when the copy operation has completed - /// - /// - public static async ValueTask CopyToAsync(this Stream source, Stream dest, long count, int bufferSize, IUnmangedHeap heap, CancellationToken token = default) - { - if (source.CanSeek) - { - bufferSize = (int)Math.Min(source.Length, bufferSize); - } - //Alloc a buffer - using IMemoryOwner buffer = heap.DirectAlloc(bufferSize); - //Wait for copy to complete - await CopyToAsync(source, dest, buffer.Memory, count, token); - } - - /// - /// Copies data from one stream to another, using self managed buffers. May allocate up to 2MB. - /// - /// Source stream to read from - /// Destination stream to write data to - /// The heap to allocate buffers from - /// - /// - public static void CopyTo(this Stream source, Stream dest, IUnmangedHeap? heap = null) - { - if (!source.CanRead) - { - throw new ArgumentException("Source stream is unreadable", nameof(source)); - } - if (!dest.CanWrite) - { - throw new ArgumentException("Destination stream is unwritable", nameof(dest)); - } - heap ??= Shared; - //Get a buffer size, maximum of 2mb buffer size if the stream supports seeking, otherwise, min buf size - int bufSize = source.CanSeek ? (int)Math.Min(source.Length, MAX_BUF_SIZE) : MIN_BUF_SIZE; - //Length must be 0, so return - if (bufSize == 0) - { - return; - } - //Alloc a buffer - using UnsafeMemoryHandle buffer = heap.UnsafeAlloc(bufSize); - int read; - do - { - //read - read = source.Read(buffer.Span); - //Guard - if (read == 0) - { - break; - } - //write only the data that was read (slice) - dest.Write(buffer.Span[..read]); - } while (true); - } - /// - /// Copies data from one stream to another, using self managed buffers. May allocate up to 2MB. - /// - /// Source stream to read from - /// Destination stream to write data to - /// Number of bytes to read/write - /// The heap to allocate buffers from - /// - /// - public static void CopyTo(this Stream source, Stream dest, long count, IUnmangedHeap? heap = null) - { - if (!source.CanRead) - { - throw new ArgumentException("Source stream is unreadable", nameof(source)); - } - if (!dest.CanWrite) - { - throw new ArgumentException("Destination stream is unwritable", nameof(dest)); - } - //Set default heap - heap ??= Shared; - //Get a buffer size, maximum of 2mb buffer size if the stream supports seeking, otherwise, min buf size - int bufSize = source.CanSeek ? (int)Math.Min(source.Length, MAX_BUF_SIZE) : MIN_BUF_SIZE; - //Length must be 0, so return - if (bufSize == 0) - { - return; - } - //Alloc a buffer - using UnsafeMemoryHandle buffer = heap.UnsafeAlloc(bufSize); - //wrapper around offset pointer - long total = 0; - int read; - do - { - Span wrapper = buffer.Span[..(int)Math.Min(bufSize, (count - total))]; - //read - read = source.Read(wrapper); - //Guard - if (read == 0) - { - break; - } - //write only the data that was read (slice) - dest.Write(wrapper[..read]); - //Update total - total += read; - } while (true); - } - - /// - /// Copies data from the current stream to the destination stream using the supplied memory buffer - /// - /// - /// The destination data stream to write data to - /// The buffer to use when copying data - /// A token that may cancel asynchronous operations - /// A that completes when the copy operation has completed - /// - public static async ValueTask CopyToAsync(this Stream source, Stream dest, Memory buffer, CancellationToken token = default) - { - //Make sure source can be read from, and dest can be written to - if (!source.CanRead) - { - throw new ArgumentException("Source stream is unreadable", nameof(source)); - } - if (!dest.CanWrite) - { - throw new ArgumentException("Destination stream is unwritable", nameof(dest)); - } - //Read in loop - int read; - while (true) - { - //read - read = await source.ReadAsync(buffer, token); - //Guard - if (read == 0) - { - break; - } - //write only the data that was read (slice) - await dest.WriteAsync(buffer[..read], token); - } - } - - /// - /// Copies data from the current stream to the destination stream using the supplied memory buffer - /// - /// - /// The destination data stream to write data to - /// The buffer to use when copying data - /// The number of bytes to copy from the current stream to destination stream - /// A token that may cancel asynchronous operations - /// A that completes when the copy operation has completed - /// - public static async ValueTask CopyToAsync(this Stream source, Stream dest, Memory buffer, long count, CancellationToken token = default) - { - //Make sure source can be read from, and dest can be written to - if (!source.CanRead) - { - throw new ArgumentException("Source stream is unreadable", nameof(source)); - } - if (!dest.CanWrite) - { - throw new ArgumentException("Destination stream is unwritable", nameof(dest)); - } - /* - * Track total count so we copy the exect number of - * bytes from the source - */ - long total = 0; - int bufferSize = buffer.Length; - int read; - while (true) - { - //get offset wrapper of the total buffer or remaining count - Memory offset = buffer[..(int)Math.Min(bufferSize, count - total)]; - //read - read = await source.ReadAsync(offset, token); - //Guard - if (read == 0) - { - break; - } - //write only the data that was read (slice) - await dest.WriteAsync(offset[..read], token); - //Update total - total += read; - } - } - - /// - /// Opens a file within the current directory - /// - /// - /// The name of the file to open - /// The to open the file with - /// The to open the file with - /// - /// The size of the buffer to read/write with - /// - /// The of the opened file - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static FileStream OpenFile(this DirectoryInfo dir, - string fileName, - FileMode mode, - FileAccess access, - FileShare share = FileShare.None, - int bufferSize = 4096, - FileOptions options = FileOptions.None) - { - _ = dir ?? throw new ArgumentNullException(nameof(dir)); - string fullPath = Path.Combine(dir.FullName, fileName); - return new FileStream(fullPath, mode, access, share, bufferSize, options); - } - /// - /// Deletes the speicifed file from the current directory - /// - /// - /// The name of the file to delete - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void DeleteFile(this DirectoryInfo dir, string fileName) - { - _ = dir ?? throw new ArgumentNullException(nameof(dir)); - string fullPath = Path.Combine(dir.FullName, fileName); - File.Delete(fullPath); - } - /// - /// Determines if a file exists within the current directory - /// - /// - /// The name of the file to search for - /// True if the file is found and the user has permission to access the file, false otherwise - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool FileExists(this DirectoryInfo dir, string fileName) - { - _ = dir ?? throw new ArgumentNullException(nameof(dir)); - string fullPath = Path.Combine(dir.FullName, fileName); - return FileOperations.FileExists(fullPath); - } - } -} \ No newline at end of file diff --git a/Utils/src/Extensions/JsonExtensions.cs b/Utils/src/Extensions/JsonExtensions.cs deleted file mode 100644 index a27dcc0..0000000 --- a/Utils/src/Extensions/JsonExtensions.cs +++ /dev/null @@ -1,215 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: JsonExtensions.cs -* -* JsonExtensions.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.Text.Json; -using System.Collections.Generic; - -using VNLib.Utils.IO; - -namespace VNLib.Utils.Extensions -{ - /// - /// Specifies how to parse a timespan value from a element - /// - public enum TimeParseType - { - Milliseconds, - Seconds, - Minutes, - Hours, - Days, - Ticks - } - - public static class JsonExtensions - { - /// - /// Converts a JSON encoded string to an object of the specified type - /// - /// Output type of the object - /// - /// to use during de-serialization - /// The new object or default if the string is null or empty - /// - /// - public static T? AsJsonObject(this string value, JsonSerializerOptions? options = null) - { - return !string.IsNullOrWhiteSpace(value) ? JsonSerializer.Deserialize(value, options) : default; - } - /// - /// Converts a JSON encoded binary data to an object of the specified type - /// - /// Output type of the object - /// - /// to use during de-serialization - /// The new object or default if the string is null or empty - /// - /// - public static T? AsJsonObject(this in ReadOnlySpan utf8bin, JsonSerializerOptions? options = null) - { - return utf8bin.IsEmpty ? default : JsonSerializer.Deserialize(utf8bin, options); - } - /// - /// Converts a JSON encoded binary data to an object of the specified type - /// - /// Output type of the object - /// - /// to use during de-serialization - /// The new object or default if the string is null or empty - /// - /// - public static T? AsJsonObject(this in ReadOnlyMemory utf8bin, JsonSerializerOptions? options = null) - { - return utf8bin.IsEmpty ? default : JsonSerializer.Deserialize(utf8bin.Span, options); - } - /// - /// Converts a JSON encoded binary data to an object of the specified type - /// - /// Output type of the object - /// - /// to use during de-serialization - /// The new object or default if the string is null or empty - /// - /// - public static T? AsJsonObject(this byte[] utf8bin, JsonSerializerOptions? options = null) - { - return utf8bin == null ? default : JsonSerializer.Deserialize(utf8bin.AsSpan(), options); - } - /// - /// Parses a json encoded string to a json documen - /// - /// - /// - /// If the json string is null, returns null, otherwise the json document around the data - /// - public static JsonDocument? AsJsonDocument(this string jsonString, JsonDocumentOptions options = default) - { - return jsonString == null ? null : JsonDocument.Parse(jsonString, options); - } - /// - /// Shortcut extension to and returns a string - /// - /// - /// The name of the property to get the string value of - /// If the property exists, returns the string stored at that property - public static string? GetPropString(this in JsonElement element, string propertyName) - { - return element.TryGetProperty(propertyName, out JsonElement el) ? el.GetString() : null; - } - /// - /// Shortcut extension to and returns a string - /// - /// - /// The name of the property to get the string value of - /// If the property exists, returns the string stored at that property - public static string? GetPropString(this IReadOnlyDictionary conf, string propertyName) - { - return conf.TryGetValue(propertyName, out JsonElement el) ? el.GetString() : null; - } - - /// - /// Shortcut extension to and returns a string - /// - /// - /// The name of the property to get the string value of - /// If the property exists, returns the string stored at that property - public static string? GetPropString(this IDictionary conf, string propertyName) - { - return conf.TryGetValue(propertyName, out JsonElement el) ? el.GetString() : null; - } - - /// - /// Attemts to serialze an object to a JSON encoded string - /// - /// - /// to use during serialization - /// A JSON encoded string of the serialized object, or null if the object is null - /// - public static string? ToJsonString(this T obj, JsonSerializerOptions? options = null) - { - return obj == null ? null : JsonSerializer.Serialize(obj, options); - } - - /// - /// Merges the current with another to - /// create a new document of combined properties - /// - /// - /// The to combine with the first document - /// The name of the new element containing the initial document data - /// The name of the new element containing the additional document data - /// A new document with a parent root containing the combined objects - public static JsonDocument Merge(this JsonDocument initial, JsonDocument other, string initalName, string secondName) - { - //Open a new memory buffer - using VnMemoryStream ms = new(); - //Encapuslate the memory stream in a writer - using (Utf8JsonWriter writer = new(ms)) - { - //Write the starting - writer.WriteStartObject(); - //Write the first object name - writer.WritePropertyName(initalName); - //Write the inital docuemnt to the stream - initial.WriteTo(writer); - //Write the second object property - writer.WritePropertyName(secondName); - //Write the merging document to the stream - other.WriteTo(writer); - //End the parent element - writer.WriteEndObject(); - } - //rewind the buffer - _ = ms.Seek(0, System.IO.SeekOrigin.Begin); - //Parse the stream into the new document and return it - return JsonDocument.Parse(ms); - } - - /// - /// Parses a number value into a of the specified time - /// - /// - /// The the value represents - /// The of the value - /// - /// - /// - /// - /// - public static TimeSpan GetTimeSpan(this in JsonElement el, TimeParseType type) - { - return type switch - { - TimeParseType.Milliseconds => TimeSpan.FromMilliseconds(el.GetDouble()), - TimeParseType.Seconds => TimeSpan.FromSeconds(el.GetDouble()), - TimeParseType.Minutes => TimeSpan.FromMinutes(el.GetDouble()), - TimeParseType.Hours => TimeSpan.FromHours(el.GetDouble()), - TimeParseType.Days => TimeSpan.FromDays(el.GetDouble()), - TimeParseType.Ticks => TimeSpan.FromTicks(el.GetInt64()), - _ => throw new NotSupportedException(), - }; - } - } -} \ No newline at end of file diff --git a/Utils/src/Extensions/MemoryExtensions.cs b/Utils/src/Extensions/MemoryExtensions.cs deleted file mode 100644 index c8ee5ef..0000000 --- a/Utils/src/Extensions/MemoryExtensions.cs +++ /dev/null @@ -1,769 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: MemoryExtensions.cs -* -* MemoryExtensions.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.Text; -using System.Buffers; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; - -namespace VNLib.Utils.Extensions -{ - using Utils.Memory; - using VNLib.Utils.Resources; - - /// - /// Provides memory based extensions to .NET and VNLib memory abstractions - /// - public static class MemoryExtensions - { - /// - /// Rents a new array and stores it as a resource within an to return the - /// array when work is completed - /// - /// - /// - /// The minimum size array to allocate - /// Should elements from 0 to size be set to default(T) - /// A new encapsulating the rented array - public static UnsafeMemoryHandle Lease(this ArrayPool pool, int size, bool zero = false) where T: unmanaged - { - //Pool buffer handles are considered "safe" so im reusing code for now - return new(pool, size, zero); - } - - /// - /// Retreives a buffer that is at least the reqested length, and clears the array from 0-size. - ///

- /// The array may be larger than the requested size, and the entire buffer is zeroed - ///
- /// - /// The minimum length of the array - /// True if contents should be zeroed - /// The zeroed array - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static T[] Rent(this ArrayPool pool, int size, bool zero) - { - //Rent the array - T[] arr = pool.Rent(size); - //If zero flag is set, zero only the used section - if (zero) - { - Array.Fill(arr, default); - } - return arr; - } - - /// - /// Copies the characters within the memory handle to a - /// - /// The string representation of the buffer - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static string ToString(this T charBuffer) where T: IMemoryHandle - { - return charBuffer.Span.ToString(); - } - - /// - /// Wraps the instance in System.Buffers.MemoryManager - /// wrapper to provide buffers from umanaged handles. - /// - /// The unmanaged data type - /// - /// - /// A value that indicates if the new owns the handle. - /// When true, the new maintains the lifetime of the handle. - /// - /// The wrapper - /// NOTE: This wrapper now manages the lifetime of the current handle - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static MemoryManager ToMemoryManager(this MemoryHandle handle, bool ownsHandle = true) where T : unmanaged - { - _ = handle ?? throw new ArgumentNullException(nameof(handle)); - return new SysBufferMemoryManager(handle, ownsHandle); - } - - /// - /// Wraps the instance in System.Buffers.MemoryManager - /// wrapper to provide buffers from umanaged handles. - /// - /// The unmanaged data type - /// - /// - /// A value that indicates if the new owns the handle. - /// When true, the new maintains the lifetime of the handle. - /// - /// The wrapper - /// NOTE: This wrapper now manages the lifetime of the current handle - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static MemoryManager ToMemoryManager(this VnTempBuffer handle, bool ownsHandle = true) where T : unmanaged - { - _ = handle ?? throw new ArgumentNullException(nameof(handle)); - return new SysBufferMemoryManager(handle, ownsHandle); - } - - /// - /// Allows direct allocation of a fixed size from a instance - /// of the specified number of elements - /// - /// The unmanaged data type - /// - /// The number of elements to allocate on the heap - /// Optionally zeros conents of the block when allocated - /// The wrapper around the block of memory - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static MemoryManager DirectAlloc(this IUnmangedHeap heap, ulong size, bool zero = false) where T : unmanaged - { - return new SysBufferMemoryManager(heap, size, zero); - } - - /// - /// Allows direct allocation of a fixed size from a instance - /// of the specified number of elements - /// - /// The unmanaged data type - /// - /// The number of elements to allocate on the heap - /// Optionally zeros conents of the block when allocated - /// The wrapper around the block of memory - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static MemoryManager DirectAlloc(this IUnmangedHeap heap, long size, bool zero = false) where T : unmanaged - { - return size < 0 ? throw new ArgumentOutOfRangeException(nameof(size)) : DirectAlloc(heap, (ulong)size, zero); - } - /// - /// Gets an offset pointer from the base postion to the number of bytes specified. Performs bounds checks - /// - /// - /// Number of elements of type to offset - /// - /// - /// pointer to the memory offset specified - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe T* GetOffset(this MemoryHandle memory, long elements) where T : unmanaged - { - return elements < 0 ? throw new ArgumentOutOfRangeException(nameof(elements)) : memory.GetOffset((ulong)elements); - } - /// - /// Resizes the current handle on the heap - /// - /// - /// Positive number of elemnts the current handle should referrence - /// - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Resize(this MemoryHandle memory, long elements) where T : unmanaged - { - if (elements < 0) - { - throw new ArgumentOutOfRangeException(nameof(elements)); - } - memory.Resize((ulong)elements); - } - - /// - /// Resizes the target handle only if the handle is smaller than the requested element count - /// - /// - /// - /// The number of elements to resize to - /// - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ResizeIfSmaller(this MemoryHandle handle, long count) where T : unmanaged - { - if(count < 0) - { - throw new ArgumentOutOfRangeException(nameof(count)); - } - ResizeIfSmaller(handle, (ulong)count); - } - - /// - /// Resizes the target handle only if the handle is smaller than the requested element count - /// - /// - /// - /// The number of elements to resize to - /// - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ResizeIfSmaller(this MemoryHandle handle, ulong count) where T : unmanaged - { - //Check handle size - if(handle.Length < count) - { - //handle too small, resize - handle.Resize(count); - } - } - -#if TARGET_64_BIT - /// - /// Gets a 64bit friendly span offset for the current - /// - /// - /// - /// The offset (in elements) from the begining of the block - /// The size of the block (in elements) - /// The offset span - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe Span GetOffsetSpan(this MemoryHandle block, ulong offset, int size) where T: unmanaged - { - _ = block ?? throw new ArgumentNullException(nameof(block)); - if(size < 0) - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - if(size == 0) - { - return Span.Empty; - } - //Make sure the offset size is within the size of the block - if(offset + (ulong)size <= block.Length) - { - //Get long offset from the destination handle - void* ofPtr = block.GetOffset(offset); - return new Span(ofPtr, size); - } - throw new ArgumentOutOfRangeException(nameof(size)); - } - /// - /// Gets a 64bit friendly span offset for the current - /// - /// - /// - /// The offset (in elements) from the begining of the block - /// The size of the block (in elements) - /// The offset span - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe Span GetOffsetSpan(this MemoryHandle block, long offset, int size) where T : unmanaged - { - return offset < 0 ? throw new ArgumentOutOfRangeException(nameof(offset)) : block.GetOffsetSpan((ulong)offset, size); - } - - - /// - /// Gets a window within the current block - /// - /// - /// - /// An offset within the handle - /// The size of the window - /// The new within the block - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static SubSequence GetSubSequence(this MemoryHandle block, ulong offset, int size) where T : unmanaged - { - return new SubSequence(block, offset, size); - } -#else - - /// - /// Gets a window within the current block - /// - /// - /// - /// An offset within the handle - /// The size of the window - /// The new within the block - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static SubSequence GetSubSequence(this MemoryHandle block, int offset, int size) where T : unmanaged - { - return new SubSequence(block, offset, size); - } - - /// - /// Gets a 64bit friendly span offset for the current - /// - /// - /// - /// The offset (in elements) from the begining of the block - /// The size of the block (in elements) - /// The offset span - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe Span GetOffsetSpan(this MemoryHandle block, long offset, int size) where T : unmanaged - { - //TODO fix 32bit/64 bit, this is a safe lazy workaround - return block.Span.Slice(checked((int) offset), size); - } -#endif - - /// - /// Wraps the current instance with a wrapper - /// to allow System.Memory buffer rentals. - /// - /// The unmanged data type to provide allocations from - /// The new heap wrapper. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static MemoryPool ToPool(this IUnmangedHeap heap) where T : unmanaged - { - return new PrivateBuffersMemoryPool(heap); - } - - /// - /// Allocates a structure of the specified type on the current unmanged heap and zero's its memory - /// - /// The structure type - /// - /// A pointer to the structure ready for use. - /// Allocations must be freed with - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe T* StructAlloc(this IUnmangedHeap heap) where T : unmanaged - { - //Allocate the struct on the heap and zero memory it points to - IntPtr handle = heap.Alloc(1, (uint)sizeof(T), true); - //returns the handle - return (T*)handle; - } - /// - /// Frees a structure at the specified address from the this heap. - /// This must be the same heap the structure was allocated from - /// - /// The structure type - /// - /// A pointer to the structure - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe void StructFree(this IUnmangedHeap heap, T* structPtr) where T : unmanaged - { - IntPtr block = new(structPtr); - //Free block from heap - heap.Free(ref block); - //Clear ref - *structPtr = default; - } - /// - /// Allocates a block of unmanaged memory of the number of elements to store of an unmanged type - /// - /// Unmanaged data type to create a block of - /// - /// The size of the block (number of elements) - /// A flag that zeros the allocated block before returned - /// The unmanaged - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe MemoryHandle Alloc(this IUnmangedHeap heap, ulong elements, bool zero = false) where T : unmanaged - { - //Minimum of one element - elements = Math.Max(elements, 1); - //Get element size - uint elementSize = (uint)sizeof(T); - //If zero flag is set then specify zeroing memory - IntPtr block = heap.Alloc(elements, elementSize, zero); - //Return handle wrapper - return new MemoryHandle(heap, block, elements, zero); - } - /// - /// Allocates a block of unmanaged memory of the number of elements to store of an unmanged type - /// - /// Unmanaged data type to create a block of - /// - /// The size of the block (number of elements) - /// A flag that zeros the allocated block before returned - /// The unmanaged - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static MemoryHandle Alloc(this IUnmangedHeap heap, long elements, bool zero = false) where T : unmanaged - { - return elements < 0 ? throw new ArgumentOutOfRangeException(nameof(elements)) : Alloc(heap, (ulong)elements, zero); - } - /// - /// Allocates a buffer from the current heap and initialzies it by copying the initial data buffer - /// - /// - /// - /// The initial data to set the buffer to - /// The initalized block - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static MemoryHandle AllocAndCopy(this IUnmangedHeap heap, ReadOnlySpan initialData) where T:unmanaged - { - MemoryHandle handle = heap.Alloc(initialData.Length); - Memory.Copy(initialData, handle, 0); - return handle; - } - - /// - /// Copies data from the input buffer to the current handle and resizes the handle to the - /// size of the buffer - /// - /// The unamanged value type - /// - /// The input buffer to copy data from - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteAndResize(this MemoryHandle handle, ReadOnlySpan input) where T: unmanaged - { - handle.Resize(input.Length); - Memory.Copy(input, handle, 0); - } - - /// - /// Allocates a block of unamanged memory of the number of elements of an unmanaged type, and - /// returns the that must be used cautiously - /// - /// The unamanged value type - /// The heap to allocate block from - /// The number of elements to allocate - /// A flag to zero the initial contents of the buffer - /// The allocated handle of the specified number of elements - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe UnsafeMemoryHandle UnsafeAlloc(this IUnmangedHeap heap, int elements, bool zero = false) where T : unmanaged - { - if (elements < 1) - { - throw new ArgumentException("Elements must be greater than 0", nameof(elements)); - } - //Minimum of one element - elements = Math.Max(elements, 1); - //Get element size - uint elementSize = (uint)sizeof(T); - //If zero flag is set then specify zeroing memory - IntPtr block = heap.Alloc((uint)elements, elementSize, zero); - //handle wrapper - return new (heap, block, elements); - } - - #region VnBufferWriter - - /// - /// Formats and appends a value type to the writer with proper endianess - /// - /// - /// The value to format and append to the buffer - /// - public static void Append(this ref ForwardOnlyWriter buffer, T value) where T: unmanaged - { - //Calc size of structure and fix te size of the buffer - int size = Unsafe.SizeOf(); - Span output = buffer.Remaining[..size]; - - //Format value and write to buffer - MemoryMarshal.Write(output, ref value); - - //If byte order is reversed, reverse elements - if (!BitConverter.IsLittleEndian) - { - output.Reverse(); - } - - //Update written posiion - buffer.Advance(size); - } - - /// - /// Formats and appends a value type to the writer with proper endianess - /// - /// - /// The value to format and append to the buffer - /// - public static void Append(this ref ForwardOnlyMemoryWriter buffer, T value) where T : struct - { - //Format value and write to buffer - int size = Unsafe.SizeOf(); - Span output = buffer.Remaining.Span[..size]; - - //Format value and write to buffer - MemoryMarshal.Write(output, ref value); - - //If byte order is reversed, reverse elements - if (BitConverter.IsLittleEndian) - { - output.Reverse(); - } - - //Update written posiion - buffer.Advance(size); - } - - /// - /// Formats and appends the value to end of the buffer - /// - /// - /// The value to format and append to the buffer - /// An optional format argument - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Append(this ref ForwardOnlyWriter buffer, T value, ReadOnlySpan format = default, IFormatProvider? formatProvider = default) where T : ISpanFormattable - { - //Format value and write to buffer - if (!value.TryFormat(buffer.Remaining, out int charsWritten, format, formatProvider)) - { - throw new ArgumentOutOfRangeException(nameof(buffer), "The value could not be formatted and appended to the buffer, because there is not enough available space"); - } - //Update written posiion - buffer.Advance(charsWritten); - } - - /// - /// Formats and appends the value to end of the buffer - /// - /// - /// The value to format and append to the buffer - /// An optional format argument - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Append(this ref ForwardOnlyMemoryWriter buffer, T value, ReadOnlySpan format = default, IFormatProvider? formatProvider = default) where T : ISpanFormattable - { - //Format value and write to buffer - if (!value.TryFormat(buffer.Remaining.Span, out int charsWritten, format, formatProvider)) - { - throw new ArgumentOutOfRangeException(nameof(buffer), "The value could not be formatted and appended to the buffer, because there is not enough available space"); - } - //Update written posiion - buffer.Advance(charsWritten); - } - - - - /// - /// Encodes a set of characters in the input characters span and any characters - /// in the internal buffer into a sequence of bytes that are stored in the input - /// byte span. A parameter indicates whether to clear the internal state of the - /// encoder after the conversion. - /// - /// - /// Character buffer to encode - /// The offset in the char buffer to begin encoding chars from - /// The number of characers to encode - /// The buffer writer to use - /// true to clear the internal state of the encoder after the conversion; otherwise, false. - /// The actual number of bytes written at the location indicated by the bytes parameter. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int GetBytes(this Encoder enc, char[] chars, int offset, int charCount, ref ForwardOnlyWriter writer, bool flush) - { - return GetBytes(enc, chars.AsSpan(offset, charCount), ref writer, flush); - } - /// - /// Encodes a set of characters in the input characters span and any characters - /// in the internal buffer into a sequence of bytes that are stored in the input - /// byte span. A parameter indicates whether to clear the internal state of the - /// encoder after the conversion. - /// - /// - /// The character buffer to encode - /// The buffer writer to use - /// true to clear the internal state of the encoder after the conversion; otherwise, false. - /// The actual number of bytes written at the location indicated by the bytes parameter. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int GetBytes(this Encoder enc, ReadOnlySpan chars, ref ForwardOnlyWriter writer, bool flush) - { - //Encode the characters - int written = enc.GetBytes(chars, writer.Remaining, flush); - //Update the writer position - writer.Advance(written); - return written; - } - /// - /// Encodes a set of characters in the input characters span and any characters - /// in the internal buffer into a sequence of bytes that are stored in the input - /// byte span. - /// - /// - /// The character buffer to encode - /// The buffer writer to use - /// The actual number of bytes written at the location indicated by the bytes parameter. - /// - public static int GetBytes(this Encoding encoding, ReadOnlySpan chars, ref ForwardOnlyWriter writer) - { - //Encode the characters - int written = encoding.GetBytes(chars, writer.Remaining); - //Update the writer position - writer.Advance(written); - return written; - } - /// - /// Decodes a character buffer in the input characters span and any characters - /// in the internal buffer into a sequence of bytes that are stored in the input - /// byte span. - /// - /// - /// The binary buffer to decode - /// The buffer writer to use - /// The actual number of *characters* written at the location indicated by the chars parameter. - /// - public static int GetChars(this Encoding encoding, ReadOnlySpan bytes, ref ForwardOnlyWriter writer) - { - int charCount = encoding.GetCharCount(bytes); - //Encode the characters - _ = encoding.GetChars(bytes, writer.Remaining); - //Update the writer position - writer.Advance(charCount); - return charCount; - } - - /// - /// Converts the buffer data to a - /// - /// A instance that owns the underlying string memory - public static PrivateString ToPrivate(this ref ForwardOnlyWriter buffer) => new(buffer.ToString(), true); - /// - /// Gets a over the modified section of the internal buffer - /// - /// A over the modified data - public static Span AsSpan(this ref ForwardOnlyWriter buffer) => buffer.Buffer[..buffer.Written]; - - - #endregion - - /// - /// Slices the current array by the specified starting offset to the end - /// of the array - /// - /// The array type - /// - /// The start offset of the new array slice - /// The sliced array - /// - public static T[] Slice(this T[] arr, int start) - { - if(start < 0 || start > arr.Length) - { - throw new ArgumentOutOfRangeException(nameof(start)); - } - Range sliceRange = new(start, arr.Length - start); - return RuntimeHelpers.GetSubArray(arr, sliceRange); - } - /// - /// Slices the current array by the specified starting offset to including the - /// speciifed number of items - /// - /// The array type - /// - /// The start offset of the new array slice - /// The size of the new array - /// The sliced array - /// - public static T[] Slice(this T[] arr, int start, int count) - { - if(start < 0) - { - throw new ArgumentOutOfRangeException(nameof(start)); - } - if(count < 0) - { - throw new ArgumentOutOfRangeException(nameof(count)); - } - if(start + count >= arr.Length) - { - throw new ArgumentOutOfRangeException(nameof(count)); - } - if(count == 0) - { - return Array.Empty(); - } - //Calc the slice range - Range sliceRange = new(start, start + count); - return RuntimeHelpers.GetSubArray(arr, sliceRange); - } - - /// - /// Creates a new sub-sequence over the target handle. (allows for convient sub span) - /// - /// - /// - /// Intial offset into the handle - /// The sub-sequence of the current handle - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Span AsSpan(this IMemoryHandle handle, int start) => handle.Span[start..]; - - /// - /// Creates a new sub-sequence over the target handle. (allows for convient sub span) - /// - /// - /// - /// Intial offset into the handle - /// The number of elements within the new sequence - /// The sub-sequence of the current handle - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Span AsSpan(this IMemoryHandle handle, int start, int count) => handle.Span.Slice(start, count); - - /// - /// Creates a new sub-sequence over the target handle. (allows for convient sub span) - /// - /// - /// - /// Intial offset into the handle - /// The sub-sequence of the current handle - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Span AsSpan(this in UnsafeMemoryHandle handle, int start) where T: unmanaged => handle.Span[start..]; - - /// - /// Creates a new sub-sequence over the target handle. (allows for convient sub span) - /// - /// - /// - /// Intial offset into the handle - /// The number of elements within the new sequence - /// The sub-sequence of the current handle - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Span AsSpan(this in UnsafeMemoryHandle handle, int start, int count) where T : unmanaged => handle.Span.Slice(start, count); - - /// - /// Raises an if the current handle - /// has been disposed or set as invalid - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ThrowIfClosed(this SafeHandle handle) - { - if (handle.IsClosed || handle.IsInvalid) - { - throw new ObjectDisposedException(handle.GetType().Name); - } - } - } -} diff --git a/Utils/src/Extensions/MutexReleaser.cs b/Utils/src/Extensions/MutexReleaser.cs deleted file mode 100644 index 84dd60f..0000000 --- a/Utils/src/Extensions/MutexReleaser.cs +++ /dev/null @@ -1,62 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: MutexReleaser.cs -* -* MutexReleaser.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.Threading; - -namespace VNLib.Utils.Extensions -{ - /// - /// Represents a releaser handle for a - /// that has been entered and will be released. Best if used - /// within a using() statment - /// - public readonly struct MutexReleaser : IDisposable, IEquatable - { - private readonly Mutex _mutext; - internal MutexReleaser(Mutex mutex) => _mutext = mutex; - /// - /// Releases the held System.Threading.Mutex once. - /// - public readonly void Dispose() => _mutext.ReleaseMutex(); - /// - /// Releases the held System.Threading.Mutex once. - /// - public readonly void ReleaseMutext() => _mutext.ReleaseMutex(); - - /// - public bool Equals(MutexReleaser other) => _mutext.Equals(other._mutext); - - /// - public override bool Equals(object? obj) => obj is MutexReleaser releaser && Equals(releaser); - - /// - public override int GetHashCode() => _mutext.GetHashCode(); - - /// - public static bool operator ==(MutexReleaser left, MutexReleaser right) => left.Equals(right); - /// - public static bool operator !=(MutexReleaser left, MutexReleaser right) => !(left == right); - } -} \ No newline at end of file diff --git a/Utils/src/Extensions/SafeLibraryExtensions.cs b/Utils/src/Extensions/SafeLibraryExtensions.cs deleted file mode 100644 index 8866059..0000000 --- a/Utils/src/Extensions/SafeLibraryExtensions.cs +++ /dev/null @@ -1,103 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: SafeLibraryExtensions.cs -* -* SafeLibraryExtensions.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 VNLib.Utils.Native; - -namespace VNLib.Utils.Extensions -{ - /// - /// When applied to a delegate, specifies the name of the native method to load - /// - [AttributeUsage(AttributeTargets.Delegate)] - public sealed class SafeMethodNameAttribute : Attribute - { - /// - /// Creates a new - /// - /// The name of the native method - public SafeMethodNameAttribute(string MethodName) => this.MethodName = MethodName; - /// - /// Creates a new , that uses the - /// delegate name as the native method name - /// - public SafeMethodNameAttribute() => MethodName = null; - /// - /// The name of the native method - /// - public string? MethodName { get; } - } - - - /// - /// Contains native library extension methods - /// - public static class SafeLibraryExtensions - { - const string _missMemberExceptionMessage = $"The delegate type is missing the required {nameof(SafeMethodNameAttribute)} to designate the native method to load"; - - /// - /// Loads a native method from the current - /// that has a - /// - /// - /// - /// - /// - /// - /// - public static SafeMethodHandle GetMethod(this SafeLibraryHandle library) where T : Delegate - { - Type t = typeof(T); - //Get the method name attribute - SafeMethodNameAttribute? attr = t.GetCustomAttribute(); - _ = attr ?? throw new MissingMemberException(_missMemberExceptionMessage); - return library.GetMethod(attr.MethodName ?? t.Name); - } - /// - /// Loads a native method from the current - /// that has a - /// - /// - /// - /// - /// - /// - /// - /// - /// The libraries handle count is left unmodified - /// - public static T DangerousGetMethod(this SafeLibraryHandle library) where T: Delegate - { - Type t = typeof(T); - //Get the method name attribute - SafeMethodNameAttribute? attr = t.GetCustomAttribute(); - return string.IsNullOrWhiteSpace(attr?.MethodName) - ? throw new MissingMemberException(_missMemberExceptionMessage) - : library.DangerousGetMethod(attr.MethodName); - } - } -} diff --git a/Utils/src/Extensions/SemSlimReleaser.cs b/Utils/src/Extensions/SemSlimReleaser.cs deleted file mode 100644 index c8a22fe..0000000 --- a/Utils/src/Extensions/SemSlimReleaser.cs +++ /dev/null @@ -1,51 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: SemSlimReleaser.cs -* -* SemSlimReleaser.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.Threading; - -namespace VNLib.Utils.Extensions -{ - /// - /// Represents a releaser handle for a - /// that has been entered and will be released. Best if used - /// within a using() statment - /// - public readonly struct SemSlimReleaser : IDisposable - { - private readonly SemaphoreSlim _semaphore; - internal SemSlimReleaser(SemaphoreSlim semaphore) => _semaphore = semaphore; - /// - /// Releases the System.Threading.SemaphoreSlim object once. - /// - public readonly void Dispose() => _semaphore.Release(); - /// - /// Releases the System.Threading.SemaphoreSlim object once. - /// - /// The previous count of the - /// - /// - public readonly int Release() => _semaphore.Release(); - } -} \ No newline at end of file diff --git a/Utils/src/Extensions/StringExtensions.cs b/Utils/src/Extensions/StringExtensions.cs deleted file mode 100644 index 09d6517..0000000 --- a/Utils/src/Extensions/StringExtensions.cs +++ /dev/null @@ -1,481 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: StringExtensions.cs -* -* StringExtensions.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.Buffers; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -using VNLib.Utils.Memory; - -namespace VNLib.Utils.Extensions -{ - public delegate void StatelessSpanAction(ReadOnlySpan line); - - /// - /// Extention methods for string (character buffer) - /// - public static class StringExtensions - { - /// - /// Split a string based on split value and insert into the specified list - /// - /// - /// The value to split the string on - /// The list to output data to - /// String split options - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Split(this string value, string splitter, T output, StringSplitOptions options) where T : ICollection - { - Split(value, splitter.AsSpan(), output, options); - } - /// - /// Split a string based on split value and insert into the specified list - /// - /// - /// The value to split the string on - /// The list to output data to - /// String split options - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Split(this string value, char splitter, T output, StringSplitOptions options) where T: ICollection - { - //Create span from char pointer - ReadOnlySpan cs = MemoryMarshal.CreateReadOnlySpan(ref splitter, 1); - //Call the split function on the span - Split(value, cs, output, options); - } - /// - /// Split a string based on split value and insert into the specified list - /// - /// - /// The value to split the string on - /// The list to output data to - /// String split options - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Split(this string value, ReadOnlySpan splitter, T output, StringSplitOptions options) where T : ICollection - { - Split(value.AsSpan(), splitter, output, options); - } - /// - /// Split a string based on split value and insert into the specified list - /// - /// - /// The value to split the string on - /// The list to output data to - /// String split options - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Split(this in ReadOnlySpan value, char splitter, T output, StringSplitOptions options) where T : ICollection - { - //Create span from char pointer - ReadOnlySpan cs = MemoryMarshal.CreateReadOnlySpan(ref splitter, 1); - //Call the split function on the span - Split(in value, cs, output, options); - } - /// - /// Split a based on split value and insert into the specified list - /// - /// - /// The value to split the string on - /// The list to output data to - /// String split options - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Split(this in ReadOnlySpan value, ReadOnlySpan splitter, T output, StringSplitOptions options) where T : ICollection - { - //Create a local function that adds the split strings to the list - static void SplitFound(ReadOnlySpan split, T output) => output.Add(split.ToString()); - //Invoke the split function with the local callback method - Split(in value, splitter, options, SplitFound, output); - } - /// - /// Split a based on split value and pass it to the split delegate handler - /// - /// - /// The sequence to split the string on - /// String split options - /// The action to invoke when a split segment has been found - /// The state to pass to the callback handler - /// - public static void Split(this in ReadOnlySpan value, ReadOnlySpan splitter, StringSplitOptions options, ReadOnlySpanAction splitCb, T state) - { - _ = splitCb ?? throw new ArgumentNullException(nameof(splitCb)); - //Get span over string - ForwardOnlyReader reader = new(value); - //No string options - if (options == 0) - { - do - { - //Find index of the splitter - int start = reader.Window.IndexOf(splitter); - //guard - if (start == -1) - { - break; - } - //Trim and add it regardless of length - splitCb(reader.Window[..start], state); - //shift window - reader.Advance(start + splitter.Length); - } while (true); - //Trim remaining and add it regardless of length - splitCb(reader.Window, state); - } - //Trim but do not remove empties - else if ((options & StringSplitOptions.RemoveEmptyEntries) == 0) - { - do - { - //Find index of the splitter - int start = reader.Window.IndexOf(splitter); - //guard - if (start == -1) - { - break; - } - //Trim and add it regardless of length - splitCb(reader.Window[..start].Trim(), state); - //shift window - reader.Advance(start + splitter.Length); - } while (true); - //Trim remaining and add it regardless of length - splitCb(reader.Window.Trim(), state); - } - //Remove empty entires but do not trim them - else if ((options & StringSplitOptions.TrimEntries) == 0) - { - //Get data before splitter and trim it - ReadOnlySpan data; - do - { - //Find index of the splitter - int start = reader.Window.IndexOf(splitter); - //guard - if (start == -1) - { - break; - } - //Get data before splitter and trim it - data = reader.Window[..start]; - //If its not empty, then add it to the list - if (!data.IsEmpty) - { - splitCb(data, state); - } - //shift window - reader.Advance(start + splitter.Length); - } while (true); - //Add if not empty - if (reader.WindowSize > 0) - { - splitCb(reader.Window, state); - } - } - //Must mean remove and trim - else - { - //Get data before splitter and trim it - ReadOnlySpan data; - do - { - //Find index of the splitter - int start = reader.Window.IndexOf(splitter); - //guard - if (start == -1) - { - break; - } - //Get data before splitter and trim it - data = reader.Window[..start].Trim(); - //If its not empty, then add it to the list - if (!data.IsEmpty) - { - splitCb(data, state); - } - //shift window - reader.Advance(start + splitter.Length); - } while (true); - //Trim remaining - data = reader.Window.Trim(); - //Add if not empty - if (!data.IsEmpty) - { - splitCb(data, state); - } - } - } - - /// - /// Split a based on split value and pass it to the split delegate handler - /// - /// - /// The character to split the string on - /// String split options - /// The action to invoke when a split segment has been found - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Split(this in ReadOnlySpan value, char splitter, StringSplitOptions options, ReadOnlySpanAction splitCb, T state) - { - //Alloc a span for char - ReadOnlySpan cs = MemoryMarshal.CreateReadOnlySpan(ref splitter, 1); - //Call the split function on the span - Split(in value, cs, options, splitCb, state); - } - /// - /// Split a based on split value and pass it to the split delegate handler - /// - /// - /// The sequence to split the string on - /// String split options - /// The action to invoke when a split segment has been found - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Split(this in ReadOnlySpan value, ReadOnlySpan splitter, StringSplitOptions options, StatelessSpanAction splitCb) - { - //Create a SpanSplitDelegate with the non-typed delegate as the state argument - static void ssplitcb(ReadOnlySpan param, StatelessSpanAction callback) => callback(param); - //Call split with the new callback delegate - Split(in value, splitter, options, ssplitcb, splitCb); - } - /// - /// Split a based on split value and pass it to the split delegate handler - /// - /// - /// The character to split the string on - /// String split options - /// The action to invoke when a split segment has been found - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Split(this in ReadOnlySpan value, char splitter, StringSplitOptions options, StatelessSpanAction splitCb) - { - //Create a SpanSplitDelegate with the non-typed delegate as the state argument - static void ssplitcb(ReadOnlySpan param, StatelessSpanAction callback) => callback(param); - //Call split with the new callback delegate - Split(in value, splitter, options, ssplitcb, splitCb); - } - - /// - /// Gets the index of the end of the found sequence - /// - /// - /// Sequence to search for within the current sequence - /// the index of the end of the sequenc - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int EndOf(this in ReadOnlySpan data, ReadOnlySpan search) - { - int index = data.IndexOf(search); - return index > -1 ? index + search.Length : -1; - } - /// - /// Gets the index of the end of the found character - /// - /// - /// Character to search for within the current sequence - /// the index of the end of the sequence - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int EndOf(this in ReadOnlySpan data, char search) - { - int index = data.IndexOf(search); - return index > -1 ? index + 1 : -1; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int IndexOf(this in Memory data, byte search) => data.Span.IndexOf(search); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int IndexOf(this in Memory data, ReadOnlySpan search) => data.Span.IndexOf(search); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int IndexOf(this in Memory data, ReadOnlyMemory search) => IndexOf(data, search.Span); - - /// - /// Slices the current span from the begining of the segment to the first occurrance of the specified character. - /// If the character is not found, the entire segment is returned - /// - /// - /// The delimiting character - /// The segment of data before the search character, or the entire segment if not found - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan SliceBeforeParam(this in ReadOnlySpan data, char search) - { - //Find the index of the specified data - int index = data.IndexOf(search); - //Return the slice of data before the index, or an empty span if it was not found - return index > -1 ? data[..index] : data; - } - /// - /// Slices the current span from the begining of the segment to the first occurrance of the specified character sequence. - /// If the character sequence is not found, the entire segment is returned - /// - /// - /// The delimiting character sequence - /// The segment of data before the search character, or the entire if the seach sequence is not found - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan SliceBeforeParam(this in ReadOnlySpan data, ReadOnlySpan search) - { - //Find the index of the specified data - int index = data.IndexOf(search); - //Return the slice of data before the index, or an empty span if it was not found - return index > -1 ? data[..index] : data; - } - /// - /// Gets the remaining segment of data after the specified search character or - /// if the search character is not found within the current segment - /// - /// - /// The character to search for within the segment - /// The segment of data after the search character or if not found - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan SliceAfterParam(this in ReadOnlySpan data, char search) - { - //Find the index of the specified data - int index = EndOf(in data, search); - //Return the slice of data after the index, or an empty span if it was not found - return index > -1 ? data[index..] : ReadOnlySpan.Empty; - } - /// - /// Gets the remaining segment of data after the specified search sequence or - /// if the search sequence is not found within the current segment - /// - /// - /// The sequence to search for within the segment - /// The segment of data after the search sequence or if not found - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan SliceAfterParam(this in ReadOnlySpan data, ReadOnlySpan search) - { - //Find the index of the specified data - int index = EndOf(data, search); - //Return the slice of data after the index, or an empty span if it was not found - return index > -1 ? data[index..] : ReadOnlySpan.Empty; - } - /// - /// Trims any leading or trailing '\r'|'\n'|' '(whitespace) characters from the segment - /// - /// The trimmed segment - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan TrimCRLF(this in ReadOnlySpan data) - { - int start = 0, end = data.Length; - //trim leading \r\n chars - while(start < end) - { - char t = data[start]; - //If character \r or \n slice it off - if (t != '\r' && t != '\n' && t != ' ') { - break; - } - //Shift - start++; - } - //remove trailing crlf characters - while (end > start) - { - char t = data[end - 1]; - //If character \r or \n slice it off - if (t != '\r' && t != '\n' && t != ' ') { - break; - } - end--; - } - return data[start..end]; - } - - /// - /// Replaces a character sequence within the buffer - /// - /// The character buffer to process - /// The sequence to search for - /// The sequence to write in the place of the search parameter - /// - public static int Replace(this ref Span buffer, ReadOnlySpan search, ReadOnlySpan replace) - { - ForwardOnlyWriter writer = new (buffer); - writer.Replace(search, replace); - return writer.Written; - } - - /// - /// Replaces a character sequence within the writer - /// - /// - /// The sequence to search for - /// The sequence to write in the place of the search parameter - /// - public static void Replace(this ref ForwardOnlyWriter writer, ReadOnlySpan search, ReadOnlySpan replace) - { - Span buffer = writer.AsSpan(); - //If the search and replacment parameters are the same length - if (search.Length == replace.Length) - { - buffer.ReplaceInPlace(search, replace); - return; - } - //Search and replace are not the same length - int searchLen = search.Length, start = buffer.IndexOf(search); - if(start == -1) - { - return; - } - //Replacment might be empty - writer.Reset(); - do - { - //Append the data before the split character - writer.Append(buffer[..start]); - //Append the replacment - writer.Append(replace); - //Shift buffer to the end of the - buffer = buffer[(start + searchLen)..]; - //search for next index - start = buffer.IndexOf(search); - } while (start > -1); - //Write remaining data - writer.Append(replace); - } - /// - /// Replaces very ocurrance of character sequence within a buffer with another sequence of the same length - /// - /// - /// The sequence to search for - /// The sequence to replace the found sequence with - /// - public static void ReplaceInPlace(this Span buffer, ReadOnlySpan search, ReadOnlySpan replace) - { - if(search.Length != replace.Length) - { - throw new ArgumentException("Search parameter and replacment parameter must be the same length"); - } - int start = buffer.IndexOf(search); - while(start > -1) - { - //Shift the buffer to the begining of the search parameter - buffer = buffer[start..]; - //Overwite the search parameter - replace.CopyTo(buffer); - //Search for next index of the search character - start = buffer.IndexOf(search); - } - } - } -} \ No newline at end of file diff --git a/Utils/src/Extensions/ThreadingExtensions.cs b/Utils/src/Extensions/ThreadingExtensions.cs deleted file mode 100644 index cc9fab9..0000000 --- a/Utils/src/Extensions/ThreadingExtensions.cs +++ /dev/null @@ -1,226 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: ThreadingExtensions.cs -* -* ThreadingExtensions.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.Threading; -using System.Threading.Tasks; -using VNLib.Utils.Resources; - -namespace VNLib.Utils.Extensions -{ - - /// - /// Provides extension methods to common threading and TPL library operations - /// - public static class ThreadingExtensions - { - /// - /// Allows an to execute within a scope limited context - /// - /// The resource type - /// - /// The function body that will execute with controlled access to the resource - public static void EnterSafeContext(this OpenResourceHandle rh, Action safeCallback) - { - using (rh) - { - safeCallback(rh.Resource); - } - } - - /// - /// Asynchronously waits to enter the while observing a - /// and getting a releaser handle - /// - /// - /// A token to cancel the operation - /// A releaser handle that may be disposed to release the semaphore - /// - /// - public static async Task GetReleaserAsync(this SemaphoreSlim semaphore, CancellationToken cancellationToken = default) - { - await semaphore.WaitAsync(cancellationToken); - return new SemSlimReleaser(semaphore); - } - /// - /// Asynchronously waits to enter the using a 32-bit signed integer to measure the time intervale - /// and getting a releaser handle - /// - /// - /// A the maximum amount of time in milliseconds to wait to enter the semaphore - /// A releaser handle that may be disposed to release the semaphore - /// - /// - public static async Task GetReleaserAsync(this SemaphoreSlim semaphore, int timeout) - { - if (await semaphore.WaitAsync(timeout)) - { - return new SemSlimReleaser(semaphore); - } - throw new TimeoutException("Failed to enter the semaphore before the specified timeout period"); - } - - /// - /// Blocks the current thread until it can enter the - /// - /// - /// A releaser handler that releases the semaphore when disposed - /// - public static SemSlimReleaser GetReleaser(this SemaphoreSlim semaphore) - { - semaphore.Wait(); - return new SemSlimReleaser(semaphore); - } - /// - /// Blocks the current thread until it can enter the - /// - /// - /// A the maximum amount of time in milliseconds to wait to enter the semaphore - /// A releaser handler that releases the semaphore when disposed - /// - /// - public static SemSlimReleaser GetReleaser(this SemaphoreSlim semaphore, int timeout) - { - if (semaphore.Wait(timeout)) - { - return new SemSlimReleaser(semaphore); - } - throw new TimeoutException("Failed to enter the semaphore before the specified timeout period"); - } - - /// - /// Blocks the current thread until it can enter the - /// - /// - /// A releaser handler that releases the semaphore when disposed - /// - /// - public static MutexReleaser Enter(this Mutex mutex) - { - mutex.WaitOne(); - return new MutexReleaser(mutex); - } - /// - /// Blocks the current thread until it can enter the - /// - /// - /// A the maximum amount of time in milliseconds to wait to enter the semaphore - /// A releaser handler that releases the semaphore when disposed - /// - /// - public static MutexReleaser Enter(this Mutex mutex, int timeout) - { - if (mutex.WaitOne(timeout)) - { - return new MutexReleaser(mutex); - } - throw new TimeoutException("Failed to enter the semaphore before the specified timeout period"); - } - - private static readonly Task TrueCompleted = Task.FromResult(true); - private static readonly Task FalseCompleted = Task.FromResult(false); - - /// - /// Asynchronously waits for a the to receive a signal. This method spins until - /// a thread yield will occur, then asynchronously yields. - /// - /// - /// The timeout interval in milliseconds - /// - /// A task that compeletes when the wait handle receives a signal or times-out, - /// the result of the awaited task will be true if the signal is received, or - /// false if the timeout interval expires - /// - /// - /// - /// - public static Task WaitAsync(this WaitHandle handle, int timeoutMs = Timeout.Infinite) - { - _ = handle ?? throw new ArgumentNullException(nameof(handle)); - //test non-blocking handle state - if (handle.WaitOne(0)) - { - return TrueCompleted; - } - //When timeout is 0, wh will block, return false - else if(timeoutMs == 0) - { - return FalseCompleted; - } - //Init short lived spinwait - SpinWait sw = new(); - //Spin until yield occurs - while (!sw.NextSpinWillYield) - { - sw.SpinOnce(); - //Check handle state - if (handle.WaitOne(0)) - { - return TrueCompleted; - } - } - //Completion source used to signal the awaiter when the wait handle is signaled - TaskCompletionSource completion = new(TaskCreationOptions.None); - //Register wait on threadpool to complete the task source - RegisteredWaitHandle registration = ThreadPool.RegisterWaitForSingleObject(handle, TaskCompletionCallback, completion, timeoutMs, true); - //Register continuation to cleanup - _ = completion.Task.ContinueWith(CleanupContinuation, registration, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default) - .ConfigureAwait(false); - return completion.Task; - } - - private static void CleanupContinuation(Task task, object? taskCompletion) - { - RegisteredWaitHandle registration = (taskCompletion as RegisteredWaitHandle)!; - registration.Unregister(null); - task.Dispose(); - } - private static void TaskCompletionCallback(object? tcsState, bool timedOut) - { - TaskCompletionSource completion = (tcsState as TaskCompletionSource)!; - //Set the result of the wait handle timeout - _ = completion.TrySetResult(!timedOut); - } - - - /// - /// Registers a callback method that will be called when the token has been cancelled. - /// This method waits indefinitely for the token to be cancelled. - /// - /// - /// The callback method to invoke when the token has been cancelled - /// A task that may be unobserved, that completes when the token has been cancelled - public static Task RegisterUnobserved(this CancellationToken token, Action callback) - { - //Call callback when the wait handle is set - return token.WaitHandle.WaitAsync() - .ContinueWith(static (t, callback) => (callback as Action)!.Invoke(), - callback, - CancellationToken.None, - TaskContinuationOptions.ExecuteSynchronously, - TaskScheduler.Default - ); - } - } -} \ No newline at end of file diff --git a/Utils/src/Extensions/TimerExtensions.cs b/Utils/src/Extensions/TimerExtensions.cs deleted file mode 100644 index a980d63..0000000 --- a/Utils/src/Extensions/TimerExtensions.cs +++ /dev/null @@ -1,66 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: TimerExtensions.cs -* -* TimerExtensions.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.Threading; -using VNLib.Utils.Resources; - -namespace VNLib.Utils.Extensions -{ - public static class TimerExtensions - { - /// - /// Attempts to stop the timer - /// - /// True if the timer was successfully modified, false otherwise - public static bool Stop(this Timer timer) => timer.Change(Timeout.Infinite, Timeout.Infinite); - - /// - /// Attempts to stop an active timer and prepare a configured to restore the state of the timer to the specified timespan - /// - /// - /// representing the amount of time the timer should wait before invoking the callback function - /// A new if the timer was stopped successfully that will resume the timer when closed, null otherwise - public static OpenHandle Stop(this Timer timer, TimeSpan resumeTime) - { - return timer.Change(Timeout.Infinite, Timeout.Infinite) ? new CallbackOpenHandle(() => timer.Change(resumeTime, Timeout.InfiniteTimeSpan)) : null; - } - - /// - /// Attempts to reset and start a timer - /// - /// - /// to wait before the timer event is fired - /// True if the timer was successfully modified - public static bool Restart(this Timer timer, TimeSpan wait) => timer.Change(wait, Timeout.InfiniteTimeSpan); - - /// - /// Attempts to reset and start a timer - /// - /// - /// Time in milliseconds to wait before the timer event is fired - /// True if the timer was successfully modified - public static bool Restart(this Timer timer, int waitMilliseconds) => timer.Change(waitMilliseconds, Timeout.Infinite); - } -} \ No newline at end of file diff --git a/Utils/src/Extensions/VnStringExtensions.cs b/Utils/src/Extensions/VnStringExtensions.cs deleted file mode 100644 index 285fc4f..0000000 --- a/Utils/src/Extensions/VnStringExtensions.cs +++ /dev/null @@ -1,418 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: VnStringExtensions.cs -* -* VnStringExtensions.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.Linq; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; - -using VNLib.Utils.Memory; - -namespace VNLib.Utils.Extensions -{ - [SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "")] - public static class VnStringExtensions - { - /// - /// Derermines if the character exists within the instance - /// - /// - /// The value to find - /// True if the character exists within the instance - /// - public static bool Contains(this VnString str, char value) => str.AsSpan().Contains(value); - /// - /// Derermines if the sequence exists within the instance - /// - /// - /// The sequence to find - /// - /// True if the character exists within the instance - /// - - public static bool Contains(this VnString str, ReadOnlySpan value, StringComparison stringComparison) => str.AsSpan().Contains(value, stringComparison); - - /// - /// Searches for the first occurrance of the specified character within the current instance - /// - /// - /// The character to search for within the instance - /// The 0 based index of the occurance, -1 if the character was not found - /// - public static int IndexOf(this VnString str, char value) => str.IsEmpty ? -1 : str.AsSpan().IndexOf(value); - /// - /// Searches for the first occurrance of the specified sequence within the current instance - /// - /// - /// The sequence to search for - /// The 0 based index of the occurance, -1 if the sequence was not found - /// - public static int IndexOf(this VnString str, ReadOnlySpan search) - { - //Using spans to avoid memory leaks... - ReadOnlySpan self = str.AsSpan(); - return self.IndexOf(search); - } - /// - /// Searches for the first occurrance of the specified sequence within the current instance - /// - /// - /// The sequence to search for - /// The type to use in searchr - /// The 0 based index of the occurance, -1 if the sequence was not found - /// - public static int IndexOf(this VnString str, ReadOnlySpan search, StringComparison comparison) - { - //Using spans to avoid memory leaks... - ReadOnlySpan self = str.AsSpan(); - return self.IndexOf(search, comparison); - } - /// - /// Searches for the 0 based index of the first occurance of the search parameter after the start index. - /// - /// - /// The sequence of data to search for - /// The lower boundry of the search area - /// The absolute index of the first occurrance within the instance, -1 if the sequency was not found in the windowed segment - /// - /// - public static int IndexOf(this VnString str, ReadOnlySpan search, int start) - { - if (start < 0) - { - throw new ArgumentOutOfRangeException(nameof(start), "Start cannot be less than 0"); - } - //Get shifted window - ReadOnlySpan self = str.AsSpan()[start..]; - //Check indexof - int index = self.IndexOf(search); - return index > -1 ? index + start : -1; - } - - /// - /// Returns the realtive index after the specified sequence within the instance - /// - /// - /// The sequence to search for - /// The index after the found sequence within the string, -1 if the sequence was not found within the instance - /// - public static int EndOf(this VnString str, ReadOnlySpan search) - { - //Try to get the index of the data - int index = IndexOf(str, search); - //If the data was found, add the length to get the end of the string - return index > -1 ? index + search.Length : -1; - } - - /// - /// Allows for trimming whitespace characters in a realtive sequence from - /// within a buffer defined by the start and end parameters - /// and returning the trimmed entry. - /// - /// - /// The starting position within the sequence to trim - /// The end of the sequence to trim - /// The trimmed instance as a child of the original entry - /// - /// - public static VnString AbsoluteTrim(this VnString data, int start, int end) - { - AbsoluteTrim(data, ref start, ref end); - return data[start..end]; - } - /// - /// Finds whitespace characters within the sequence defined between start and end parameters - /// and adjusts the specified window to "trim" whitespace - /// - /// - /// The starting position within the sequence to trim - /// The end of the sequence to trim - /// - /// - public static void AbsoluteTrim(this VnString data, ref int start, ref int end) - { - ReadOnlySpan trimmed = data.AsSpan(); - //trim leading whitespace - while (start < end) - { - //If whitespace character shift start up - if (trimmed[start] != ' ') - { - break; - } - //Shift - start++; - } - //remove trailing whitespace characters - while (end > start) - { - //If whiterspace character shift end param down - if (trimmed[end - 1] != ' ') - { - break; - } - end--; - } - } - /// - /// Allows for trimming whitespace characters in a realtive sequence from - /// within a buffer and returning the trimmed entry. - /// - /// - /// The starting position within the sequence to trim - /// The trimmed instance as a child of the original entry - /// - /// - public static VnString AbsoluteTrim(this VnString data, int start) => AbsoluteTrim(data, start, data.Length); - /// - /// Trims leading or trailing whitespace characters and returns a new child instance - /// without leading or trailing whitespace - /// - /// A child of the current instance without leading or trailing whitespaced - /// - public static VnString RelativeTirm(this VnString data) => AbsoluteTrim(data, 0); - - /// - /// Allows for enumeration of segments of data within the specified instance that are - /// split by the search parameter - /// - /// - /// The sequence of data to delimit segments - /// The options used to split the string instances - /// An iterator to enumerate the split segments - /// - public static IEnumerable Split(this VnString data, ReadOnlyMemory search, StringSplitOptions options = StringSplitOptions.None) - { - int lowerBound = 0; - //Make sure the length of the search param is not 0 - if(search.IsEmpty) - { - //Return the entire string - yield return data; - } - //No string options - else if (options == 0) - { - do - { - //Capture the first = and store argument + value - int splitIndex = data.IndexOf(search.Span, lowerBound); - //If no split index is found, then return remaining data - if (splitIndex == -1) - { - break; - } - yield return data[lowerBound..splitIndex]; - //Shift the lower window to the end of the last string - lowerBound = splitIndex + search.Length; - } while (true); - //Return remaining data - yield return data[lowerBound..]; - } - //Trim but do not remove empties - else if ((options & StringSplitOptions.RemoveEmptyEntries) == 0) - { - do - { - //Capture the first = and store argument + value - int splitIndex = data.IndexOf(search.Span, lowerBound); - //If no split index is found, then return remaining data - if (splitIndex == -1) - { - break; - } - //trim and return - yield return data.AbsoluteTrim(lowerBound, splitIndex); - //Shift the lower window to the end of the last string - lowerBound = splitIndex + search.Length; - } while (true); - //Return remaining data - yield return data.AbsoluteTrim(lowerBound); - } - //Remove empty entires but do not trim them - else if ((options & StringSplitOptions.TrimEntries) == 0) - { - do - { - //Capture the first = and store argument + value - int splitIndex = data.IndexOf(search.Span, lowerBound); - //If no split index is found, then return remaining data - if (splitIndex == -1) - { - break; - } - //If the split index is the next sequence, then the result is empty, so exclude it - else if(splitIndex > 0) - { - yield return data[lowerBound..splitIndex]; - } - //Shift the lower window to the end of the last string - lowerBound = splitIndex + search.Length; - } while (true); - //Return remaining data if available - if (lowerBound < data.Length) - { - yield return data[lowerBound..]; - } - } - //Must mean remove and trim - else - { - //Get stack varables to pass to trim function - int trimStart, trimEnd; - do - { - //Capture the first = and store argument + value - int splitIndex = data.IndexOf(search.Span, lowerBound); - //If no split index is found, then return remaining data - if (splitIndex == -1) - { - break; - } - //Get stack varables to pass to trim function - trimStart = lowerBound; - trimEnd = splitIndex; //End of the segment is the relative split index + the lower bound of the window - //Trim whitespace chars - data.AbsoluteTrim(ref trimStart, ref trimEnd); - //See if the string has data - if((trimEnd - trimStart) > 0) - { - yield return data[trimStart..trimEnd]; - } - //Shift the lower window to the end of the last string - lowerBound = splitIndex + search.Length; - } while (true); - //Trim remaining - trimStart = lowerBound; - trimEnd = data.Length; - data.AbsoluteTrim(ref trimStart, ref trimEnd); - //If the remaining string is not empty return it - if ((trimEnd - trimStart) > 0) - { - yield return data[trimStart..trimEnd]; - } - } - } - - /// - /// Trims any leading or trailing '\r'|'\n'|' '(whitespace) characters from the segment - /// - /// The trimmed segment - /// - public static VnString TrimCRLF(this VnString data) - { - ReadOnlySpan trimmed = data.AsSpan(); - int start = 0, end = trimmed.Length; - //trim leading \r\n chars - while (start < end) - { - char t = trimmed[start]; - //If character \r or \n slice it off - if (t != '\r' && t != '\n' && t != ' ') { - break; - } - //Shift - start++; - } - //remove trailing crlf characters - while (end > start) - { - char t = trimmed[end - 1]; - //If character \r or \n slice it off - if (t != '\r' && t != '\n' && t != ' ') { - break; - } - end--; - } - return data[start..end]; - } - - /// - /// Unoptimized character enumerator. You should use to enumerate the unerlying data. - /// - /// The next character in the sequence - /// - public static IEnumerator GetEnumerator(this VnString data) - { - int index = 0; - while (index < data.Length) - { - yield return data[index++]; - } - } - /// - /// Converts the current handle to a , a zero-alloc immutable wrapper - /// for a memory handle - /// - /// - /// The number of characters from the handle to reference (length of the string) - /// The new wrapper - /// - /// - public static VnString ToVnString(this MemoryHandle handle, int length) - { - if(handle.Length > int.MaxValue) - { - throw new OverflowException("The handle is larger than 2GB in size"); - } - return VnString.ConsumeHandle(handle, 0, length); - } - /// - /// Converts the current handle to a , a zero-alloc immutable wrapper - /// for a memory handle - /// - /// - /// The new wrapper - /// - /// - public static VnString ToVnString(this MemoryHandle handle) - { - return VnString.ConsumeHandle(handle, 0, handle.IntLength); - } - /// - /// Converts the current handle to a , a zero-alloc immutable wrapper - /// for a memory handle - /// - /// - /// The offset in characters that represents the begining of the string - /// The number of characters from the handle to reference (length of the string) - /// The new wrapper - /// - /// - public static VnString ToVnString(this MemoryHandle handle, -#if TARGET_64_BIT - ulong offset, -#else - int offset, -#endif - int length) - { - if (handle.Length > int.MaxValue) - { - throw new OverflowException("The handle is larger than 2GB in size"); - } - return VnString.ConsumeHandle(handle, offset, length); - } - } -} \ No newline at end of file diff --git a/Utils/src/IIndexable.cs b/Utils/src/IIndexable.cs deleted file mode 100644 index 129d703..0000000 --- a/Utils/src/IIndexable.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: IIndexable.cs -* -* IIndexable.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; - -namespace VNLib.Utils -{ - /// - /// Provides an interface that provides an indexer - /// - /// The lookup Key - /// The lookup value - public interface IIndexable - { - /// - /// Gets or sets the value at the specified index in the collection - /// - /// The key to lookup the value at - /// The value at the specified key - TValue this[TKey key] { get; set;} - } -} diff --git a/Utils/src/IO/ArrayPoolStreamBuffer.cs b/Utils/src/IO/ArrayPoolStreamBuffer.cs deleted file mode 100644 index df366e3..0000000 --- a/Utils/src/IO/ArrayPoolStreamBuffer.cs +++ /dev/null @@ -1,70 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: ArrayPoolStreamBuffer.cs -* -* ArrayPoolStreamBuffer.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.Buffers; - -namespace VNLib.Utils.IO -{ - internal class ArrayPoolStreamBuffer : ISlindingWindowBuffer - { - private readonly ArrayPool _pool; - private T[] _buffer; - - public ArrayPoolStreamBuffer(ArrayPool pool, int bufferSize) - { - _pool = pool; - _buffer = _pool.Rent(bufferSize); - } - - public int WindowStartPos { get; set; } - public int WindowEndPos { get; set; } - - public Memory Buffer => _buffer.AsMemory(); - - public void Advance(int count) - { - WindowEndPos += count; - } - - public void AdvanceStart(int count) - { - WindowStartPos += count; - } - - public void Close() - { - //Return buffer to pool - _pool.Return(_buffer); - _buffer = null; - } - - public void Reset() - { - //Reset window positions - WindowStartPos = 0; - WindowEndPos = 0; - } - } -} \ No newline at end of file diff --git a/Utils/src/IO/BackingStream.cs b/Utils/src/IO/BackingStream.cs deleted file mode 100644 index cb56b09..0000000 --- a/Utils/src/IO/BackingStream.cs +++ /dev/null @@ -1,181 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: BackingStream.cs -* -* BackingStream.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; - -namespace VNLib.Utils.IO -{ - /// - /// Provides basic stream support sync/async stream operations to a - /// backing stream with virtual event methods. Provides a pass-through - /// as best as possbile. - /// - public abstract class BackingStream : Stream where T: Stream - { - /// - /// The backing/underlying stream operations are being performed on - /// - protected T BaseStream { get; set; } - /// - /// A value that will cause all calls to write to throw - /// - protected bool ForceReadOnly { get; set; } - /// - public override bool CanRead => BaseStream.CanRead; - /// - public override bool CanSeek => BaseStream.CanSeek; - /// - public override bool CanWrite => BaseStream.CanWrite && !ForceReadOnly; - /// - public override long Length => BaseStream.Length; - /// - public override int WriteTimeout { get => BaseStream.WriteTimeout; set => BaseStream.WriteTimeout = value; } - /// - public override int ReadTimeout { get => BaseStream.ReadTimeout; set => BaseStream.ReadTimeout = value; } - /// - public override long Position { get => BaseStream.Position; set => BaseStream.Position = value; } - /// - public override void Flush() - { - BaseStream.Flush(); - OnFlush(); - } - /// - public override int Read(byte[] buffer, int offset, int count) => BaseStream.Read(buffer, offset, count); - /// - public override int Read(Span buffer) => BaseStream.Read(buffer); - /// - public override long Seek(long offset, SeekOrigin origin) => BaseStream.Seek(offset, origin); - /// - public override void SetLength(long value) => BaseStream.SetLength(value); - /// - public override void Write(byte[] buffer, int offset, int count) - { - if (ForceReadOnly) - { - throw new NotSupportedException("Stream is set to readonly mode"); - } - BaseStream.Write(buffer, offset, count); - //Call onwrite function - OnWrite(count); - } - /// - public override void Write(ReadOnlySpan buffer) - { - if (ForceReadOnly) - { - throw new NotSupportedException("Stream is set to readonly mode"); - } - BaseStream.Write(buffer); - //Call onwrite function - OnWrite(buffer.Length); - } - /// - public override void Close() - { - BaseStream.Close(); - //Call on close function - OnClose(); - } - - /// - /// Raised directly after the base stream is closed, when a call to close is made - /// - protected virtual void OnClose() { } - /// - /// Raised directly after the base stream is flushed, when a call to flush is made - /// - protected virtual void OnFlush() { } - /// - /// Raised directly after a successfull write operation. - /// - /// The number of bytes written to the stream - protected virtual void OnWrite(int count) { } - - /// - public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - return BaseStream.ReadAsync(buffer, offset, count, cancellationToken); - } - /// - public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) - { - return BaseStream.ReadAsync(buffer, cancellationToken); - } - /// - public override void CopyTo(Stream destination, int bufferSize) => BaseStream.CopyTo(destination, bufferSize); - /// - public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken) - { - return BaseStream.CopyToAsync(destination, bufferSize, cancellationToken); - } - /// - public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - if (ForceReadOnly) - { - throw new NotSupportedException("Stream is set to readonly mode"); - } - //We want to maintain pass through as much as possible, so supress warning -#pragma warning disable CA1835 // Prefer the 'Memory'-based overloads for 'ReadAsync' and 'WriteAsync' - await BaseStream.WriteAsync(buffer, offset, count, cancellationToken); -#pragma warning restore CA1835 // Prefer the 'Memory'-based overloads for 'ReadAsync' and 'WriteAsync' - - //Call on-write and pass the number of bytes written - OnWrite(count); - } - /// - public override async ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) - { - if (ForceReadOnly) - { - throw new NotSupportedException("Stream is set to readonly mode"); - } - await BaseStream.WriteAsync(buffer, cancellationToken); - //Call on-write and pass the length - OnWrite(buffer.Length); - } - /// - public override async Task FlushAsync(CancellationToken cancellationToken) - { - await BaseStream.FlushAsync(cancellationToken); - //Call onflush - OnFlush(); - } - - /// - public override async ValueTask DisposeAsync() - { - //Dispose the base stream and await it - await BaseStream.DisposeAsync(); - //Call onclose - OnClose(); - //Suppress finalize - GC.SuppressFinalize(this); - } - } -} \ No newline at end of file diff --git a/Utils/src/IO/FileOperations.cs b/Utils/src/IO/FileOperations.cs deleted file mode 100644 index e040da4..0000000 --- a/Utils/src/IO/FileOperations.cs +++ /dev/null @@ -1,105 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: FileOperations.cs -* -* FileOperations.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.Runtime.InteropServices; - -namespace VNLib.Utils.IO -{ - /// - /// Contains cross-platform optimized filesystem operations. - /// - public static class FileOperations - { - public const int INVALID_FILE_ATTRIBUTES = -1; - - [DllImport("Shlwapi", SetLastError = true, CharSet = CharSet.Auto)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return:MarshalAs(UnmanagedType.Bool)] - private static unsafe extern bool PathFileExists(char* path); - [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return:MarshalAs(UnmanagedType.I4)] - private static unsafe extern int GetFileAttributes(char* path); - - static readonly bool IsWindows = OperatingSystem.IsWindows(); - /// - /// Determines if a file exists. If application is current running in the Windows operating system, Shlwapi.PathFileExists is invoked, - /// otherwise is invoked - /// - /// the path to the file - /// True if the file can be opened, false otherwise - public static bool FileExists(string filePath) - { - //If windows is detected, use the unmanged function - if (!IsWindows) - { - return File.Exists(filePath); - } - unsafe - { - //Get a char pointer to the file path - fixed (char* path = filePath) - { - //Invoke the winap file function - return PathFileExists(path); - } - } - } - - /// - /// If Windows is detected at load time, gets the attributes for the specified file. - /// - /// The path to the existing file - /// The attributes of the file - /// - /// - /// - public static FileAttributes GetAttributes(string filePath) - { - //If windows is detected, use the unmanged function - if (!IsWindows) - { - return File.GetAttributes(filePath); - } - unsafe - { - //Get a char pointer to the file path - fixed (char* path = filePath) - { - //Invoke the winap file function and cast the returned int value to file attributes - int attr = GetFileAttributes(path); - //Check for error - if (attr == INVALID_FILE_ATTRIBUTES) - { - throw new FileNotFoundException("The requested file was not found", filePath); - } - //Cast to file attributes and return - return (FileAttributes)attr; - } - } - } - } -} \ No newline at end of file diff --git a/Utils/src/IO/IDataAccumulator.cs b/Utils/src/IO/IDataAccumulator.cs deleted file mode 100644 index 5129a55..0000000 --- a/Utils/src/IO/IDataAccumulator.cs +++ /dev/null @@ -1,64 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: IDataAccumulator.cs -* -* IDataAccumulator.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; - -namespace VNLib.Utils.IO -{ - /// - /// A data structure that represents a sliding window over a buffer - /// for resetable forward-only reading or writing - /// - /// The accumuation data type - public interface IDataAccumulator - { - /// - /// Gets the number of available items within the buffer - /// - int AccumulatedSize { get; } - /// - /// The number of elements remaining in the buffer - /// - int RemainingSize { get; } - /// - /// The remaining space in the internal buffer as a contiguous segment - /// - Span Remaining { get; } - /// - /// The buffer window over the accumulated data - /// - Span Accumulated { get; } - - /// - /// Advances the accumulator buffer window by the specified amount - /// - /// The number of elements accumulated - void Advance(int count); - - /// - /// Resets the internal state of the accumulator - /// - void Reset(); - } -} \ No newline at end of file diff --git a/Utils/src/IO/ISlindingWindowBuffer.cs b/Utils/src/IO/ISlindingWindowBuffer.cs deleted file mode 100644 index ff4e142..0000000 --- a/Utils/src/IO/ISlindingWindowBuffer.cs +++ /dev/null @@ -1,91 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: ISlindingWindowBuffer.cs -* -* ISlindingWindowBuffer.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; - -namespace VNLib.Utils.IO -{ - /// - /// Represents a sliding window buffer for reading/wiriting data - /// - /// - public interface ISlindingWindowBuffer : IDataAccumulator - { - /// - /// The number of elements remaining in the buffer - /// - int IDataAccumulator.RemainingSize => Buffer.Length - WindowEndPos; - /// - /// The remaining space in the internal buffer as a contiguous segment - /// - Span IDataAccumulator.Remaining => RemainingBuffer.Span; - /// - /// The buffer window over the accumulated data - /// - Span IDataAccumulator.Accumulated => AccumulatedBuffer.Span; - /// - /// Gets the number of available items within the buffer - /// - int IDataAccumulator.AccumulatedSize => WindowEndPos - WindowStartPos; - - /// - /// The starting positon of the available data within the buffer - /// - int WindowStartPos { get; } - /// - /// The ending position of the available data within the buffer - /// - int WindowEndPos { get; } - /// - /// Buffer memory wrapper - /// - Memory Buffer { get; } - - /// - /// Releases resources used by the current instance - /// - void Close(); - /// - /// - /// Advances the begining of the accumulated data window. - /// - /// - /// This method is used during reading to singal that data - /// has been read from the internal buffer and the - /// accumulator window can be shifted. - /// - /// - /// The number of elements to shift by - void AdvanceStart(int count); - - /// - /// Gets a window within the buffer of available buffered data - /// - Memory AccumulatedBuffer => Buffer[WindowStartPos..WindowEndPos]; - /// - /// Gets the available buffer window to write data to - /// - Memory RemainingBuffer => Buffer[WindowEndPos..]; - } -} \ No newline at end of file diff --git a/Utils/src/IO/IVnTextReader.cs b/Utils/src/IO/IVnTextReader.cs deleted file mode 100644 index 625ba78..0000000 --- a/Utils/src/IO/IVnTextReader.cs +++ /dev/null @@ -1,72 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: IVnTextReader.cs -* -* IVnTextReader.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.Text; - -namespace VNLib.Utils.IO -{ - /// - /// Represents a streaming text reader with internal buffers - /// - public interface IVnTextReader - { - /// - /// The base stream to read data from - /// - Stream BaseStream { get; } - /// - /// The character encoding used by the TextReader - /// - Encoding Encoding { get; } - /// - /// Number of available bytes of buffered data within the current buffer window - /// - int Available { get; } - /// - /// Gets or sets the line termination used to deliminate a line of data - /// - ReadOnlyMemory LineTermination { get; } - /// - /// The unread/available data within the internal buffer - /// - Span BufferedDataWindow { get; } - /// - /// Shifts the sliding buffer window by the specified number of bytes. - /// - /// The number of bytes read from the buffer - void Advance(int count); - /// - /// Reads data from the stream into the remaining buffer space for processing - /// - void FillBuffer(); - /// - /// Compacts the available buffer space back to the begining of the buffer region - /// and determines if there is room for more data to be buffered - /// - /// The remaining buffer space if any - ERRNO CompactBufferWindow(); - } -} \ No newline at end of file diff --git a/Utils/src/IO/InMemoryTemplate.cs b/Utils/src/IO/InMemoryTemplate.cs deleted file mode 100644 index 12f9092..0000000 --- a/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 -{ - /// - /// Represents a lazily loaded file stored in memory, with a change mointor - /// that reloads the template if the file was modified in the filesystem - /// - public abstract class InMemoryTemplate : VnDisposeable - { - protected ManualResetEventSlim TemplateLock; - private readonly FileSystemWatcher? Watcher; - private bool Modified; - private VnMemoryStream templateBuffer; - protected readonly FileInfo TemplateFile; - - /// - /// Gets the name of the template - /// - public abstract string TemplateName { get; } - - /// - /// Creates a new in-memory copy of a file that will detect changes and refresh - /// - /// Should changes to the template file be moniored for changes, and reloaded as necessary - /// The path of the file template - 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(); - } - } - - /// - /// Gets a cached copy of the template data - /// - 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(); - } - /// - /// Updates the internal copy of the file to its memory representation - /// - 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; - } - /// - /// Updates the internal copy of the file to its memory representation, asynchronously - /// - /// - /// A task that completes when the file has been copied into memory - 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.Memory.Shared, cancellationToken); - } - catch - { - newBuf.Dispose(); - throw; - } - //Create the readonly copy - templateBuffer = VnMemoryStream.CreateReadonly(newBuf); - //Clear the modified flag - Modified = false; - } - - /// - /// Invoked when the template file has been modifed. Note: This event is raised - /// while the is held. - /// - protected abstract void OnModifed(); - - /// - protected override void Free() - { - //Dispose the watcher - Watcher?.Dispose(); - //free the stream - templateBuffer?.Dispose(); - } - } -} \ No newline at end of file diff --git a/Utils/src/IO/IsolatedStorageDirectory.cs b/Utils/src/IO/IsolatedStorageDirectory.cs deleted file mode 100644 index 65460ff..0000000 --- a/Utils/src/IO/IsolatedStorageDirectory.cs +++ /dev/null @@ -1,154 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: IsolatedStorageDirectory.cs -* -* IsolatedStorageDirectory.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.IO.IsolatedStorage; - -namespace VNLib.Utils.IO -{ - /// - /// Represents an open directory within an store for which files can be created, opened, or deleted. - /// - public sealed class IsolatedStorageDirectory : IsolatedStorage - { - private readonly string DirectoryPath; - private readonly IsolatedStorageFile Storage; - /// - /// Creates a new within the specified file using the directory name. - /// - /// A configured and open - /// The directory name to open or create within the store - public IsolatedStorageDirectory(IsolatedStorageFile storage, string dir) - { - this.Storage = storage; - this.DirectoryPath = dir; - //If the directory doesnt exist, create it - if (!this.Storage.DirectoryExists(dir)) - this.Storage.CreateDirectory(dir); - } - - private IsolatedStorageDirectory(IsolatedStorageDirectory parent, string dirName) - { - //Store ref to parent dir - Parent = parent; - //Referrence store - this.Storage = parent.Storage; - //Add the name of this dir to the end of the specified dir path - this.DirectoryPath = Path.Combine(parent.DirectoryPath, dirName); - } - - /// - /// Creates a file by its path name within the currnet directory - /// - /// The name of the file - /// The open file - /// - /// - /// - public IsolatedStorageFileStream CreateFile(string fileName) - { - return this.Storage.CreateFile(Path.Combine(DirectoryPath, fileName)); - } - /// - /// Removes a file from the current directory - /// - /// The path of the file to remove - /// - public void DeleteFile(string fileName) - { - this.Storage.DeleteFile(Path.Combine(this.DirectoryPath, fileName)); - } - /// - /// Opens a file that exists within the current directory - /// - /// Name with extension of the file - /// File mode - /// File access - /// The open from the current directory - public IsolatedStorageFileStream OpenFile(string fileName, FileMode mode, FileAccess access) - { - return this.Storage.OpenFile(Path.Combine(DirectoryPath, fileName), mode, access); - } - /// - /// Opens a file that exists within the current directory - /// - /// Name with extension of the file - /// File mode - /// File access - /// The file shareing mode - /// The open from the current directory - public IsolatedStorageFileStream OpenFile(string fileName, FileMode mode, FileAccess access, FileShare share) - { - return this.Storage.OpenFile(Path.Combine(DirectoryPath, fileName), mode, access, share); - } - - /// - /// Determiens if the specified file path refers to an existing file within the directory - /// - /// The name of the file to search for - /// True if the file exists within the current directory - /// - /// - /// - /// - public bool FileExists(string fileName) - { - return this.Storage.FileExists(Path.Combine(this.DirectoryPath, fileName)); - } - - /// - /// Removes the directory and its contents from the store - /// - public override void Remove() - { - Storage.DeleteDirectory(this.DirectoryPath); - } - - public override long AvailableFreeSpace => Storage.AvailableFreeSpace; - public override long Quota => Storage.Quota; - public override long UsedSize => Storage.UsedSize; - public override bool IncreaseQuotaTo(long newQuotaSize) => Storage.IncreaseQuotaTo(newQuotaSize); - - /// - /// The parent this directory is a child within. null if there are no parent directories - /// above this dir - /// - - public IsolatedStorageDirectory? Parent { get; } -#nullable disable - - /// - /// Creates a child directory within the current directory - /// - /// The name of the child directory - /// A new for which s can be opened/created - /// - /// - public IsolatedStorageDirectory CreateChildDirectory(string directoryName) - { - return new IsolatedStorageDirectory(this, directoryName); - } - } -} \ No newline at end of file diff --git a/Utils/src/IO/SlidingWindowBufferExtensions.cs b/Utils/src/IO/SlidingWindowBufferExtensions.cs deleted file mode 100644 index 0509061..0000000 --- a/Utils/src/IO/SlidingWindowBufferExtensions.cs +++ /dev/null @@ -1,213 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: SlidingWindowBufferExtensions.cs -* -* SlidingWindowBufferExtensions.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.Memory; -using VNLib.Utils.Extensions; -using System.Runtime.CompilerServices; - -namespace VNLib.Utils.IO -{ - /// - /// Extention methods for - /// - public static class SlidingWindowBufferExtensions - { - /// - /// Shifts/resets the current buffered data window down to the - /// begining of the buffer if the buffer window is shifted away - /// from the begining. - /// - /// The number of bytes of available space in the buffer - public static ERRNO CompactBufferWindow(this ISlindingWindowBuffer sBuf) - { - //Nothing to compact if the starting data pointer is at the beining of the window - if (sBuf.WindowStartPos > 0) - { - //Get span over engire buffer - Span buffer = sBuf.Buffer.Span; - //Get data within window - Span usedData = sBuf.Accumulated; - //Copy remaining to the begining of the buffer - usedData.CopyTo(buffer); - - //Reset positions, then advance to the specified size - sBuf.Reset(); - sBuf.Advance(usedData.Length); - } - //Return the number of bytes of available space - return sBuf.RemainingSize; - } - - /// - /// Appends the specified data to the end of the buffer - /// - /// - /// - /// The value to append to the end of the buffer - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Append(this IDataAccumulator sBuf, T val) - { - //Set the value at first position - sBuf.Remaining[0] = val; - //Advance by 1 - sBuf.Advance(1); - } - /// - /// Appends the specified data to the end of the buffer - /// - /// - /// - /// The value to append to the end of the buffer - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Append(this IDataAccumulator sBuf, ReadOnlySpan val) - { - val.CopyTo(sBuf.Remaining); - sBuf.Advance(val.Length); - } - /// - /// Formats and appends a value type to the accumulator with proper endianess - /// - /// The value type to appent - /// The binary accumulator to append - /// The value type to append - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Append(this IDataAccumulator accumulator, T value) where T: unmanaged - { - //Use forward reader for the memory extension to append a value type to a binary accumulator - ForwardOnlyWriter w = new(accumulator.Remaining); - w.Append(value); - accumulator.Advance(w.Written); - } - - /// - /// Attempts to write as much data as possible to the remaining space - /// in the buffer and returns the number of bytes accumulated. - /// - /// - /// - /// The value to accumulate - /// The number of bytes accumulated - public static ERRNO TryAccumulate(this IDataAccumulator accumulator, ReadOnlySpan value) - { - //Calc data size and reserve space for final crlf - int dataToCopy = Math.Min(value.Length, accumulator.RemainingSize); - - //Write as much data as possible - accumulator.Append(value[..dataToCopy]); - - //Return number of bytes not written - return dataToCopy; - } - - /// - /// Appends a instance to the end of the accumulator - /// - /// - /// - /// The formattable instance to write to the accumulator - /// The format arguments - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Append(this IDataAccumulator accumulator, in T formattable, ReadOnlySpan format = default) where T : struct, ISpanFormattable - { - ForwardOnlyWriter writer = new(accumulator.Remaining); - writer.Append(formattable, format); - accumulator.Advance(writer.Written); - } - - /// - /// Uses the remaining data buffer to compile a - /// instance, then advances the accumulator by the number of characters used. - /// - /// - /// - /// The instance to compile - public static void Append(this IDataAccumulator accumulator, in T compileable) where T : IStringSerializeable - { - //Write directly to the remaining space - int written = compileable.Compile(accumulator.Remaining); - //Advance the writer - accumulator.Advance(written); - } - - /// - /// Reads available data from the current window and writes as much as possible it to the supplied buffer - /// and advances the buffer window - /// - /// Element type - /// - /// The output buffer to write data to - /// The number of elements written to the buffer - public static ERRNO Read(this ISlindingWindowBuffer sBuf, in Span buffer) - { - //Calculate the amount of data to copy - int dataToCopy = Math.Min(buffer.Length, sBuf.AccumulatedSize); - //Copy the data to the buffer - sBuf.Accumulated[..dataToCopy].CopyTo(buffer); - //Advance the window - sBuf.AdvanceStart(dataToCopy); - //Return the number of bytes copied - return dataToCopy; - } - - /// - /// Fills the remaining window space of the current accumulator with - /// data from the specified stream asynchronously. - /// - /// - /// The stream to read data from - /// A token to cancel the operation - /// A value task representing the operation - public static async ValueTask AccumulateDataAsync(this ISlindingWindowBuffer accumulator, Stream input, CancellationToken cancellationToken) - { - //Get a buffer from the end of the current window to the end of the buffer - Memory bufWindow = accumulator.RemainingBuffer; - //Read from stream async - int read = await input.ReadAsync(bufWindow, cancellationToken); - //Update the end of the buffer window to the end of the read data - accumulator.Advance(read); - } - /// - /// Fills the remaining window space of the current accumulator with - /// data from the specified stream. - /// - /// - /// The stream to read data from - public static void AccumulateData(this IDataAccumulator accumulator, Stream input) - { - //Get a buffer from the end of the current window to the end of the buffer - Span bufWindow = accumulator.Remaining; - //Read from stream async - int read = input.Read(bufWindow); - //Update the end of the buffer window to the end of the read data - accumulator.Advance(read); - } - } -} \ No newline at end of file diff --git a/Utils/src/IO/TemporayIsolatedFile.cs b/Utils/src/IO/TemporayIsolatedFile.cs deleted file mode 100644 index 3bee92b..0000000 --- a/Utils/src/IO/TemporayIsolatedFile.cs +++ /dev/null @@ -1,57 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: TemporayIsolatedFile.cs -* -* TemporayIsolatedFile.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.IO.IsolatedStorage; - -namespace VNLib.Utils.IO -{ - /// - /// Allows for temporary files to be generated, used, then removed from an - /// - public sealed class TemporayIsolatedFile : BackingStream - { - private readonly IsolatedStorageDirectory Storage; - private readonly string Filename; - /// - /// Creates a new temporary filestream within the specified - /// - /// The file store to genreate temporary files within - public TemporayIsolatedFile(IsolatedStorageDirectory storage) - { - //Store ref - this.Storage = storage; - //Creaet a new random filename - this.Filename = Path.GetRandomFileName(); - //try to created a new file within the isolaged storage - this.BaseStream = storage.CreateFile(this.Filename); - } - protected override void OnClose() - { - //Remove the file from the storage - Storage.DeleteFile(this.Filename); - } - } -} \ No newline at end of file diff --git a/Utils/src/IO/VnMemoryStream.cs b/Utils/src/IO/VnMemoryStream.cs deleted file mode 100644 index 389a7da..0000000 --- a/Utils/src/IO/VnMemoryStream.cs +++ /dev/null @@ -1,469 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: VnMemoryStream.cs -* -* VnMemoryStream.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 System.Runtime.InteropServices; - -using VNLib.Utils.Extensions; - -namespace VNLib.Utils.IO -{ - - using Utils.Memory; - - /// - /// Provides an unmanaged memory stream. Desigend to help reduce garbage collector load for - /// high frequency memory operations. Similar to - /// - public sealed class VnMemoryStream : Stream, ICloneable - { - private long _position; - private long _length; - //Memory - private readonly MemoryHandle _buffer; - private bool IsReadonly; - //Default owns handle - private readonly bool OwnsHandle = true; - - /// - /// Creates a new pointing to the begining of memory, and consumes the handle. - /// - /// to consume - /// Length of the stream - /// Should the stream be readonly? - /// - /// A wrapper to access the handle data - public static VnMemoryStream ConsumeHandle(MemoryHandle handle, Int64 length, bool readOnly) - { - handle.ThrowIfClosed(); - return new VnMemoryStream(handle, length, readOnly, true); - } - - /// - /// Converts a writable to readonly to allow shallow copies - /// - /// The stream to make readonly - /// The readonly stream - public static VnMemoryStream CreateReadonly(VnMemoryStream stream) - { - //Set the readonly flag - stream.IsReadonly = true; - //Return the stream - return stream; - } - - /// - /// Creates a new memory stream - /// - public VnMemoryStream() : this(Memory.Shared) { } - /// - /// Create a new memory stream where buffers will be allocated from the specified heap - /// - /// to allocate memory from - /// - /// - public VnMemoryStream(IUnmangedHeap heap) : this(heap, 0, false) { } - - /// - /// Creates a new memory stream and pre-allocates the internal - /// buffer of the specified size on the specified heap to avoid resizing. - /// - /// to allocate memory from - /// Number of bytes (length) of the stream if known - /// Zero memory allocations during buffer expansions - /// - /// - /// - public VnMemoryStream(IUnmangedHeap heap, long bufferSize, bool zero) - { - _ = heap ?? throw new ArgumentNullException(nameof(heap)); - _buffer = heap.Alloc(bufferSize, zero); - } - - /// - /// Creates a new memory stream from the data provided - /// - /// to allocate memory from - /// Initial data - public VnMemoryStream(IUnmangedHeap heap, ReadOnlySpan data) - { - _ = heap ?? throw new ArgumentNullException(nameof(heap)); - //Alloc the internal buffer to match the data stream - _buffer = heap.AllocAndCopy(data); - //Set length - _length = data.Length; - //Position will default to 0 cuz its dotnet :P - return; - } - - /// - /// WARNING: Dangerous constructor, make sure read-only and owns hanlde are set accordingly - /// - /// The buffer to referrence directly - /// The length property of the stream - /// Is the stream readonly (should mostly be true!) - /// Does the new stream own the memory -> - private VnMemoryStream(MemoryHandle buffer, long length, bool readOnly, bool ownsHandle) - { - OwnsHandle = ownsHandle; - _buffer = buffer; //Consume the handle - _length = length; //Store length of the buffer - IsReadonly = readOnly; - } - - /// - /// UNSAFE Number of bytes between position and length. Never negative - /// - private long LenToPosDiff => Math.Max(_length - _position, 0); - - /// - /// If the current stream is a readonly stream, creates an unsafe shallow copy for reading only. - /// - /// New stream shallow copy of the internal stream - /// - public VnMemoryStream GetReadonlyShallowCopy() - { - //Create a new readonly copy (stream does not own the handle) - return !IsReadonly - ? throw new NotSupportedException("This stream is not readonly. Cannot create shallow copy on a mutable stream") - : new VnMemoryStream(_buffer, _length, true, false); - } - - /// - /// Writes data directly to the destination stream from the internal buffer - /// without allocating or copying any data. - /// - /// The stream to write data to - /// The size of the chunks to write to the destination stream - /// - public override void CopyTo(Stream destination, int bufferSize) - { - _ = destination ?? throw new ArgumentNullException(nameof(destination)); - - if (!destination.CanWrite) - { - throw new IOException("The destinaion stream is not writeable"); - } - - do - { - //Calc the remaining bytes to read no larger than the buffer size - int bytesToRead = (int)Math.Min(LenToPosDiff, bufferSize); - - //Create a span wrapper by using the offet function to support memory handles larger than 2gb - ReadOnlySpan span = _buffer.GetOffsetSpan(_position, bytesToRead); - - destination.Write(span); - - //Update position - _position += bytesToRead; - - } while (LenToPosDiff > 0); - } - - /// - /// Allocates a temporary buffer of the desired size, copies data from the internal - /// buffer and writes it to the destination buffer asynchronously. - /// - /// The stream to write output data to - /// The size of the buffer to use when copying data - /// A token to cancel the opreation - /// A task that resolves when the remaining data in the stream has been written to the destination - /// - /// - /// - public override async Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken) - { - _ = destination ?? throw new ArgumentNullException(nameof(destination)); - - if (!destination.CanWrite) - { - throw new IOException("The destinaion stream is not writeable"); - } - - cancellationToken.ThrowIfCancellationRequested(); - - /* - * Alloc temp copy buffer. This is a requirement because - * the stream may be larger than an int32 so it must be - * copied by segment - */ - - using VnTempBuffer copyBuffer = new(bufferSize); - - do - { - //read from internal stream - int read = Read(copyBuffer); - - if(read <= 0) - { - break; - } - - //write async - await destination.WriteAsync(copyBuffer.AsMemory(0, read), cancellationToken); - - } while (true); - - } - - /// - /// - /// - /// This property is always true - /// - /// - public override bool CanRead => true; - /// - /// - /// - /// This propery is always true - /// - /// - public override bool CanSeek => true; - /// - /// True unless the stream is (or has been converted to) a readonly - /// stream. - /// - public override bool CanWrite => !IsReadonly; - /// - public override long Length => _length; - /// - public override bool CanTimeout => false; - - /// - public override long Position - { - get => _position; - set => Seek(value, SeekOrigin.Begin); - } - /// - /// Closes the stream and frees the internal allocated memory blocks - /// - public override void Close() - { - //Only dispose buffer if we own it - if (OwnsHandle) - { - _buffer.Dispose(); - } - } - /// - public override void Flush() { } - // Override to reduce base class overhead - /// - public override Task FlushAsync(CancellationToken cancellationToken) => Task.CompletedTask; - /// - public override int Read(byte[] buffer, int offset, int count) => Read(new Span(buffer, offset, count)); - /// - public override int Read(Span destination) - { - if (destination.Length == 0) - { - return 0; - } - //Number of bytes to read from memory buffer - int bytesToRead = checked((int)Math.Min(LenToPosDiff, destination.Length)); - //Copy bytes to buffer - Memory.Copy(_buffer, _position, destination, 0, bytesToRead); - //Increment buffer position - _position += bytesToRead; - //Bytestoread should never be larger than int.max because span length is an integer - return bytesToRead; - } - - /* - * Async reading will always run synchronously in a memory stream, - * so overrides are just so avoid base class overhead - */ - /// - public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) - { - //Read synchronously and return a completed task - int read = Read(buffer.Span); - return ValueTask.FromResult(read); - } - /// - public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - //Read synchronously and return a completed task - int read = Read(buffer.AsSpan(offset, count)); - return Task.FromResult(read); - } - /// - public override long Seek(long offset, SeekOrigin origin) - { - if (offset < 0) - { - throw new ArgumentOutOfRangeException(nameof(offset), "Offset cannot be less than 0"); - } - switch (origin) - { - case SeekOrigin.Begin: - //Length will never be greater than int.Max so output will never exceed int.max - _position = Math.Min(_length, offset); - return _position; - case SeekOrigin.Current: - long newPos = _position + offset; - //Length will never be greater than int.Max so output will never exceed length - _position = Math.Min(_length, newPos); - return newPos; - case SeekOrigin.End: - long real_index = _length - offset; - //If offset moves the position negative, just set the position to 0 and continue - _position = Math.Min(real_index, 0); - return real_index; - default: - throw new ArgumentException("Stream operation is not supported on current stream"); - } - } - - - /// - /// Resizes the internal buffer to the exact size (in bytes) of the - /// value argument. A value of 0 will free the entire buffer. A value - /// greater than zero will resize the buffer (and/or alloc) - /// - /// The size of the stream (and internal buffer) - /// - /// - /// - /// - public override void SetLength(long value) - { - if (IsReadonly) - { - throw new NotSupportedException("This stream is readonly"); - } - if (value < 0) - { - throw new ArgumentOutOfRangeException(nameof(value), "Value cannot be less than 0"); - } - //Resize the buffer to the specified length - _buffer.Resize(value); - //Set length - _length = value; - //Make sure the position is not pointing outside of the buffer - _position = Math.Min(_position, _length); - return; - } - /// - public override void Write(byte[] buffer, int offset, int count) => Write(new ReadOnlySpan(buffer, offset, count)); - /// - public override void Write(ReadOnlySpan buffer) - { - if (IsReadonly) - { - throw new NotSupportedException("Write operation is not allowed on readonly stream!"); - } - //Calculate the new final position - long newPos = (_position + buffer.Length); - //Determine if the buffer needs to be expanded - if (buffer.Length > LenToPosDiff) - { - //Expand buffer if required - _buffer.ResizeIfSmaller(newPos); - //Update length - _length = newPos; - } - //Copy the input buffer to the internal buffer - Memory.Copy(buffer, _buffer, _position); - //Update the position - _position = newPos; - return; - } - /// - public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - //Write synchronously and return a completed task - Write(buffer, offset, count); - return Task.CompletedTask; - } - /// - public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) - { - //Write synchronously and return a completed task - Write(buffer.Span); - return ValueTask.CompletedTask; - } - /// - public override void WriteByte(byte value) - { - Span buf = MemoryMarshal.CreateSpan(ref value, 1); - Write(buf); - } - - /// - /// Allocates and copies internal buffer to new managed byte[] - /// - /// Copy of internal buffer - /// - /// - public byte[] ToArray() - { - //Alloc a new array of the size of the internal buffer - byte[] data = new byte[_length]; - //Copy data from the internal buffer to the output buffer - _buffer.Span.CopyTo(data); - return data; - - } - /// - /// Returns a window over the data within the entire stream - /// - /// A of the data within the entire stream - /// - public ReadOnlySpan AsSpan() - { - ReadOnlySpan output = _buffer.Span; - return output[..(int)_length]; - } - - /// - /// If the current stream is a readonly stream, creates a shallow copy for reading only. - /// - /// New stream shallow copy of the internal stream - /// - public object Clone() => GetReadonlyShallowCopy(); - - /* - * Override the Dispose async method to avoid the base class overhead - * and task allocation since this will always be a syncrhonous - * operation (freeing memory) - */ - - /// - public override ValueTask DisposeAsync() - { - //Dispose and return completed task - base.Dispose(true); - GC.SuppressFinalize(this); - return ValueTask.CompletedTask; - } - } -} \ No newline at end of file diff --git a/Utils/src/IO/VnStreamReader.cs b/Utils/src/IO/VnStreamReader.cs deleted file mode 100644 index 70b9734..0000000 --- a/Utils/src/IO/VnStreamReader.cs +++ /dev/null @@ -1,180 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: VnStreamReader.cs -* -* VnStreamReader.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.Text; -using System.Buffers; -using System.Threading; -using System.Threading.Tasks; - -using VNLib.Utils.Extensions; - -namespace VNLib.Utils.IO -{ - /// - /// Binary based buffered text reader, optimized for reading network streams - /// - public class VnStreamReader : TextReader, IVnTextReader - { - private bool disposedValue; - - private readonly ISlindingWindowBuffer _buffer; - /// - public virtual Stream BaseStream { get; } - /// - public Encoding Encoding { get; } - - /// - /// Number of available bytes of buffered data within the current buffer window - /// - public int Available => _buffer.AccumulatedSize; - /// - /// Gets or sets the line termination used to deliminate a line of data - /// - public ReadOnlyMemory LineTermination { get; set; } - Span IVnTextReader.BufferedDataWindow => _buffer.Accumulated; - - /// - /// Creates a new that reads encoded data from the base. - /// Internal buffers will be alloced from - /// - /// The underlying stream to read data from - /// The to use when reading from the stream - /// The size of the internal binary buffer - public VnStreamReader(Stream baseStream, Encoding enc, int bufferSize) - { - BaseStream = baseStream; - Encoding = enc; - //Init a new buffer - _buffer = InitializeBuffer(bufferSize); - } - - /// - /// Invoked by the constuctor method to allocte the internal buffer with the specified buffer size. - /// - /// The requested size of the buffer to alloc - /// By default requests the buffer from the instance - protected virtual ISlindingWindowBuffer InitializeBuffer(int bufferSize) => new ArrayPoolStreamBuffer(ArrayPool.Shared, bufferSize); - - /// - public override async Task ReadLineAsync() - { - //If buffered data is available, check for line termination - if (Available > 0) - { - //Get current buffer window - Memory buffered = _buffer.AccumulatedBuffer; - //search for line termination in current buffer - int term = buffered.IndexOf(LineTermination); - //Termination found in buffer window - if (term > -1) - { - //Capture the line from the begining of the window to the termination - Memory line = buffered[..term]; - //Shift the window to the end of the line (excluding the termination) - _buffer.AdvanceStart(term + LineTermination.Length); - //Decode the line to a string - return Encoding.GetString(line.Span); - } - //Termination not found - } - //Compact the buffer window and see if space is avialble to buffer more data - if (_buffer.CompactBufferWindow()) - { - //There is room, so buffer more data - await _buffer.AccumulateDataAsync(BaseStream, CancellationToken.None); - //Check again to see if more data is buffered - if (Available <= 0) - { - //No string found - return null; - } - //Get current buffer window - Memory buffered = _buffer.AccumulatedBuffer; - //search for line termination in current buffer - int term = buffered.IndexOf(LineTermination); - //Termination found in buffer window - if (term > -1) - { - //Capture the line from the begining of the window to the termination - Memory line = buffered[..term]; - //Shift the window to the end of the line (excluding the termination) - _buffer.AdvanceStart(term + LineTermination.Length); - //Decode the line to a string - return Encoding.GetString(line.Span); - } - } - //Termination not found within the entire buffer, so buffer space has been exhausted - - //OOM is raised in the TextReader base class, the standard is preserved -#pragma warning disable CA2201 // Do not raise reserved exception types - throw new OutOfMemoryException("A line termination was not found within the buffer"); -#pragma warning restore CA2201 // Do not raise reserved exception types - } - - /// - public override int Read(char[] buffer, int index, int count) => Read(buffer.AsSpan(index, count)); - /// - public override int Read(Span buffer) - { - if (Available <= 0) - { - return 0; - } - //Get current buffer window - Span buffered = _buffer.Accumulated; - //Convert all avialable data - int encoded = Encoding.GetChars(buffered, buffer); - //Shift buffer window to the end of the converted data - _buffer.AdvanceStart(encoded); - //return the number of chars written - return Encoding.GetCharCount(buffered); - } - /// - public override void Close() => _buffer.Close(); - /// - protected override void Dispose(bool disposing) - { - if (!disposedValue) - { - Close(); - disposedValue = true; - } - base.Dispose(disposing); - } - - /// - /// Resets the internal buffer window - /// - protected void ClearBuffer() - { - _buffer.Reset(); - } - - void IVnTextReader.Advance(int count) => _buffer.AdvanceStart(count); - void IVnTextReader.FillBuffer() => _buffer.AccumulateData(BaseStream); - ERRNO IVnTextReader.CompactBufferWindow() => _buffer.CompactBufferWindow(); - } -} \ No newline at end of file diff --git a/Utils/src/IO/VnStreamWriter.cs b/Utils/src/IO/VnStreamWriter.cs deleted file mode 100644 index 37d700c..0000000 --- a/Utils/src/IO/VnStreamWriter.cs +++ /dev/null @@ -1,292 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: VnStreamWriter.cs -* -* VnStreamWriter.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.Text; -using System.Buffers; -using System.Threading; -using System.Threading.Tasks; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; - -using VNLib.Utils.Memory; - -namespace VNLib.Utils.IO -{ - /// - /// Provides a memory optimized implementation. Optimized for writing - /// to network streams - /// - public class VnStreamWriter : TextWriter - { - private readonly Encoder Enc; - - private readonly ISlindingWindowBuffer _buffer; - - private bool closed; - - /// - /// Gets the underlying stream that interfaces with the backing store - /// - public virtual Stream BaseStream { get; } - /// - public override Encoding Encoding { get; } - - /// - /// Line termination to use when writing lines to the output - /// - public ReadOnlyMemory LineTermination { get; set; } - /// - public override string NewLine - { - get => Encoding.GetString(LineTermination.Span); - set => LineTermination = Encoding.GetBytes(value); - } - - /// - /// Creates a new that writes formatted data - /// to the specified base stream - /// - /// The stream to write data to - /// The to use when writing data - /// The size of the internal buffer used to buffer binary data before writing to the base stream - public VnStreamWriter(Stream baseStream, Encoding encoding, int bufferSize = 1024) - { - //Store base stream - BaseStream = baseStream; - Encoding = encoding; - //Get an encoder - Enc = encoding.GetEncoder(); - _buffer = InitializeBuffer(bufferSize); - } - - /// - /// Invoked by the constuctor method to allocte the internal buffer with the specified buffer size. - /// - /// The requested size of the buffer to alloc - /// By default requests the buffer from the instance - protected virtual ISlindingWindowBuffer InitializeBuffer(int bufferSize) => new ArrayPoolStreamBuffer(ArrayPool.Shared, bufferSize); - /// - public void Write(byte value) - { - //See if there is room in the binary buffer - if (_buffer.AccumulatedSize == 0) - { - //There is not enough room to store the single byte - Flush(); - } - //Store at the end of the window - _buffer.Append(value); - } - /// - public override void Write(char value) - { - ReadOnlySpan tbuf = MemoryMarshal.CreateSpan(ref value, 0x01); - Write(tbuf); - } - /// - public override void Write(object value) => Write(value.ToString()); - /// - public override void Write(string value) => Write(value.AsSpan()); - /// - public override void Write(ReadOnlySpan buffer) - { - Check(); - - ForwardOnlyReader reader = new(buffer); - - //Create a variable for a character buffer window - bool completed; - do - { - //Get an available buffer window to store characters in and convert the characters to binary - Enc.Convert(reader.Window, _buffer.Remaining, true, out int charsUsed, out int bytesUsed, out completed); - //Update byte position - _buffer.Advance(bytesUsed); - //Update char position - reader.Advance(charsUsed); - - //Converting did not complete because the buffer was too small - if (!completed || reader.WindowSize == 0) - { - //Flush the buffer and continue - Flush(); - } - - } while (!completed); - //Reset the encoder - Enc.Reset(); - } - /// - public override async Task WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) - { - Check(); - //Create a variable for a character buffer window - bool completed; - ForwardOnlyMemoryReader reader = new(buffer); - do - { - //Get an available buffer window to store characters in and convert the characters to binary - Enc.Convert(reader.Window.Span, _buffer.Remaining, true, out int charsUsed, out int bytesUsed, out completed); - //Update byte position - _buffer.Advance(bytesUsed); - //Update char position - reader.Advance(charsUsed); - //Converting did not complete because the buffer was too small - if (!completed || reader.WindowSize == 0) - { - //Flush the buffer and continue - await FlushWriterAsync(cancellationToken); - } - } while (!completed); - //Reset the encoder - Enc.Reset(); - } - - /// - public override void WriteLine() - { - Check(); - //See if there is room in the binary buffer - if (_buffer.RemainingSize < LineTermination.Length) - { - //There is not enough room to store the termination, so we need to flush the buffer - Flush(); - } - _buffer.Append(LineTermination.Span); - } - /// - public override void WriteLine(object value) => WriteLine(value.ToString()); - /// - public override void WriteLine(string value) => WriteLine(value.AsSpan()); - /// - public override void WriteLine(ReadOnlySpan buffer) - { - //Write the value itself - Write(buffer); - //Write the line termination - WriteLine(); - } - - /// - /// - public override void Flush() - { - Check(); - //If data is available to be written, write it to the base stream - if (_buffer.AccumulatedSize > 0) - { - //Write all buffered data to stream - BaseStream.Write(_buffer.Accumulated); - //Reset the buffer - _buffer.Reset(); - } - } - /// - /// Asynchronously flushes the internal buffers to the , and resets the internal buffer state - /// - /// A that represents the asynchronous flush operation - /// - public async ValueTask FlushWriterAsync(CancellationToken cancellationToken = default) - { - Check(); - if (_buffer.AccumulatedSize > 0) - { - //Flush current window to the stream - await BaseStream.WriteAsync(_buffer.AccumulatedBuffer, cancellationToken); - //Reset the buffer - _buffer.Reset(); - } - } - - /// - public override Task FlushAsync() => FlushWriterAsync().AsTask(); - - /// - /// Resets internal properies for resuse - /// - protected void Reset() - { - _buffer.Reset(); - Enc.Reset(); - } - /// - public override void Close() - { - //Only invoke close once - if (closed) - { - return; - } - try - { - Flush(); - } - finally - { - //Release the memory handle if its set - _buffer.Close(); - //Set closed flag - closed = true; - } - } - /// - protected override void Dispose(bool disposing) - { - Close(); - base.Dispose(disposing); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void Check() - { - if (closed) - { - throw new ObjectDisposedException("The stream is closed"); - } - } - /// - public override async ValueTask DisposeAsync() - { - //Only invoke close once - if (closed) - { - return; - } - try - { - await FlushWriterAsync(); - } - finally - { - //Set closed flag - closed = true; - //Release the memory handle if its set - _buffer.Close(); - } - GC.SuppressFinalize(this); - } - } -} \ No newline at end of file diff --git a/Utils/src/IO/VnTextReaderExtensions.cs b/Utils/src/IO/VnTextReaderExtensions.cs deleted file mode 100644 index 119461b..0000000 --- a/Utils/src/IO/VnTextReaderExtensions.cs +++ /dev/null @@ -1,223 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: VnTextReaderExtensions.cs -* -* VnTextReaderExtensions.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 VNLib.Utils.Extensions; - -namespace VNLib.Utils.IO -{ - /// - /// Extension methods to help reuse code for used TextReader implementations - /// - public static class VnTextReaderExtensions - { - public const int E_BUFFER_TOO_SMALL = -1; - - - /* - * Generic extensions provide constained compiler method invocation - * for structs the implement the IVNtextReader - */ - - /// - /// Attempts to read a line from the stream and store it in the specified buffer - /// - /// - /// The character buffer to write data to - /// Returns the number of bytes read, - /// if the buffer was not large enough, 0 if no data was available - /// - /// Allows reading lines of data from the stream without allocations - public static ERRNO ReadLine(this ref T reader, Span charBuffer) where T:struct, IVnTextReader - { - return readLine(ref reader, charBuffer); - } - /// - /// Attempts to read a line from the stream and store it in the specified buffer - /// - /// - /// The character buffer to write data to - /// Returns the number of bytes read, - /// if the buffer was not large enough, 0 if no data was available - /// - /// Allows reading lines of data from the stream without allocations - public static ERRNO ReadLine(this T reader, Span charBuffer) where T : class, IVnTextReader - { - return readLine(ref reader, charBuffer); - } - - /// - /// Fill a buffer with reamining buffered data - /// - /// - /// Buffer to copy data to - /// Offset in buffer to begin writing - /// Number of bytes to read - /// The number of bytes copied to the input buffer - public static int ReadRemaining(this ref T reader, byte[] buffer, int offset, int count) where T : struct, IVnTextReader - { - return reader.ReadRemaining(buffer.AsSpan(offset, count)); - } - /// - /// Fill a buffer with reamining buffered data - /// - /// - /// Buffer to copy data to - /// Offset in buffer to begin writing - /// Number of bytes to read - /// The number of bytes copied to the input buffer - public static int ReadRemaining(this T reader, byte[] buffer, int offset, int count) where T : class, IVnTextReader - { - return reader.ReadRemaining(buffer.AsSpan(offset, count)); - } - - /// - /// Fill a buffer with reamining buffered data, up to - /// the size of the supplied buffer - /// - /// - /// Buffer to copy data to - /// The number of bytes copied to the input buffer - /// You should use the property to know how much remaining data is buffered - public static int ReadRemaining(this ref T reader, Span buffer) where T : struct, IVnTextReader - { - return readRemaining(ref reader, buffer); - } - /// - /// Fill a buffer with reamining buffered data, up to - /// the size of the supplied buffer - /// - /// - /// Buffer to copy data to - /// The number of bytes copied to the input buffer - /// You should use the property to know how much remaining data is buffered - public static int ReadRemaining(this T reader, Span buffer) where T : class, IVnTextReader - { - return readRemaining(ref reader, buffer); - } - - private static ERRNO readLine(ref T reader, Span chars) where T: IVnTextReader - { - /* - * I am aware of a potential bug, the line decoding process - * shifts the interal buffer by the exact number of bytes to - * the end of the line, without considering if the decoder failed - * to properly decode the entire line. - * - * I dont expect this to be an issue unless there is a bug within the specified - * encoder implementation - */ - ReadOnlySpan LineTermination = reader.LineTermination.Span; - //If buffered data is available, check for line termination - if (reader.Available > 0) - { - //Get current buffer window - ReadOnlySpan bytes = reader.BufferedDataWindow; - //search for line termination in current buffer - int term = bytes.IndexOf(LineTermination); - //Termination found in buffer window - if (term > -1) - { - //Capture the line from the begining of the window to the termination - ReadOnlySpan line = bytes[..term]; - //Get the number ot chars - int charCount = reader.Encoding.GetCharCount(line); - //See if the buffer is large enough - if (bytes.Length < charCount) - { - return E_BUFFER_TOO_SMALL; - } - //Use the decoder to convert the data - _ = reader.Encoding.GetChars(line, chars); - //Shift the window to the end of the line (excluding the termination, regardless of the conversion result) - reader.Advance(term + LineTermination.Length); - //Return the number of characters - return charCount; - } - //Termination not found but there may be more data waiting - } - //Compact the buffer window and make sure it was compacted so there is room to fill the buffer - if (reader.CompactBufferWindow()) - { - //There is room, so buffer more data - reader.FillBuffer(); - //Check again to see if more data is buffered - if (reader.Available <= 0) - { - //No data avialable - return 0; - } - //Get current buffer window - ReadOnlySpan bytes = reader.BufferedDataWindow; - //search for line termination in current buffer - int term = bytes.IndexOf(LineTermination); - //Termination found in buffer window - if (term > -1) - { - //Capture the line from the begining of the window to the termination - ReadOnlySpan line = bytes[..term]; - //Get the number ot chars - int charCount = reader.Encoding.GetCharCount(line); - //See if the buffer is large enough - if (bytes.Length < charCount) - { - return E_BUFFER_TOO_SMALL; - } - //Use the decoder to convert the data - _ = reader.Encoding.GetChars(line, chars); - //Shift the window to the end of the line (excluding the termination, regardless of the conversion result) - reader.Advance(term + LineTermination.Length); - //Return the number of characters - return charCount; - } - } - - //Termination not found within the entire buffer, so buffer space has been exhausted - - //Supress as this response is expected when the buffer is exhausted, -#pragma warning disable CA2201 // Do not raise reserved exception types - throw new OutOfMemoryException("The line was not found within the current buffer, cannot continue"); -#pragma warning restore CA2201 // Do not raise reserved exception types - } - - private static int readRemaining(ref T reader, Span buffer) where T: IVnTextReader - { - //guard for empty buffer - if (buffer.Length == 0 || reader.Available == 0) - { - return 0; - } - //get the remaining bytes in the reader - Span remaining = reader.BufferedDataWindow; - //Calculate the number of bytes to copy - int canCopy = Math.Min(remaining.Length, buffer.Length); - //Copy remaining bytes to buffer - remaining[..canCopy].CopyTo(buffer); - //Shift the window by the number of bytes copied - reader.Advance(canCopy); - return canCopy; - } - } -} \ No newline at end of file diff --git a/Utils/src/IO/WriteOnlyBufferedStream.cs b/Utils/src/IO/WriteOnlyBufferedStream.cs deleted file mode 100644 index 5e7faa1..0000000 --- a/Utils/src/IO/WriteOnlyBufferedStream.cs +++ /dev/null @@ -1,255 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: WriteOnlyBufferedStream.cs -* -* WriteOnlyBufferedStream.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.Buffers; -using System.Threading; -using System.Threading.Tasks; - -using VNLib.Utils.Memory; - -namespace VNLib.Utils.IO -{ - /// - /// A basic accumulator style write buffered stream - /// - public class WriteOnlyBufferedStream : Stream - { - private readonly ISlindingWindowBuffer _buffer; - private readonly bool LeaveOpen; - - /// - /// Gets the underlying stream that interfaces with the backing store - /// - public Stream BaseStream { get; init; } - - /// - /// Initalizes a new using the - /// specified backing stream, using the specified buffer size, and - /// optionally leaves the stream open - /// - /// The backing stream to write buffered data to - /// The size of the internal buffer - /// A value indicating of the stream should be left open when the buffered stream is closed - public WriteOnlyBufferedStream(Stream baseStream, int bufferSize, bool leaveOpen = false) - { - BaseStream = baseStream; - //Create buffer - _buffer = InitializeBuffer(bufferSize); - LeaveOpen = leaveOpen; - } - /// - /// Invoked by the constuctor method to allocte the internal buffer with the specified buffer size. - /// - /// The requested size of the buffer to alloc - /// By default requests the buffer from the instance - protected virtual ISlindingWindowBuffer InitializeBuffer(int bufferSize) - { - return new ArrayPoolStreamBuffer(ArrayPool.Shared, bufferSize); - } - - /// - public override void Close() - { - try - { - //Make sure the buffer is empty - WriteBuffer(); - - if (!LeaveOpen) - { - //Dispose stream - BaseStream.Dispose(); - } - } - finally - { - _buffer.Close(); - } - } - /// - public override async ValueTask DisposeAsync() - { - try - { - if (_buffer.AccumulatedSize > 0) - { - await WriteBufferAsync(CancellationToken.None); - } - - if (!LeaveOpen) - { - //Dispose stream - await BaseStream.DisposeAsync(); - } - - GC.SuppressFinalize(this); - } - finally - { - _buffer.Close(); - } - } - - /// - public override void Flush() => WriteBuffer(); - /// - public override Task FlushAsync(CancellationToken cancellationToken) => WriteBufferAsync(cancellationToken).AsTask(); - - private void WriteBuffer() - { - //Only if data is available to write - if (_buffer.AccumulatedSize > 0) - { - //Write data to stream - BaseStream.Write(_buffer.Accumulated); - //Reset position - _buffer.Reset(); - } - } - - private async ValueTask WriteBufferAsync(CancellationToken token = default) - { - if(_buffer.AccumulatedSize > 0) - { - await BaseStream.WriteAsync(_buffer.AccumulatedBuffer, token); - _buffer.Reset(); - } - } - /// - public override void Write(byte[] buffer, int offset, int count) => Write(buffer.AsSpan(offset, count)); - - public override void Write(ReadOnlySpan buffer) - { - ForwardOnlyReader reader = new(buffer); - //Attempt to buffer/flush data until all data is sent - do - { - //Try to buffer as much as possible - ERRNO buffered = _buffer.TryAccumulate(reader.Window); - - if(buffered < reader.WindowSize) - { - //Buffer is full and needs to be flushed - WriteBuffer(); - //Advance reader and continue to buffer - reader.Advance(buffered); - continue; - } - - break; - } - while (true); - } - - public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - return WriteAsync(buffer.AsMemory(offset, count), cancellationToken).AsTask(); - } - - public async override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) - { - ForwardOnlyMemoryReader reader = new(buffer); - //Attempt to buffer/flush data until all data is sent - do - { - //Try to buffer as much as possible - ERRNO buffered = _buffer.TryAccumulate(reader.Window.Span); - - if (buffered < reader.WindowSize) - { - //Buffer is full and needs to be flushed - await WriteBufferAsync(cancellationToken); - //Advance reader and continue to buffer - reader.Advance(buffered); - continue; - } - - break; - } - while (true); - } - - - /// - /// Always false - /// - public override bool CanRead => false; - /// - /// Always returns false - /// - public override bool CanSeek => false; - /// - /// Always true - /// - public override bool CanWrite => true; - /// - /// Returns the size of the underlying buffer - /// - public override long Length => _buffer.AccumulatedSize; - /// - /// Always throws - /// - /// - public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } - /// - /// Always throws - /// - /// - /// - public override int Read(byte[] buffer, int offset, int count) - { - throw new NotSupportedException("This stream is not readable"); - } - - /// - /// Always throws - /// - /// - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - /// - /// Always throws - /// - /// - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } - - public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - } -} diff --git a/Utils/src/IObjectStorage.cs b/Utils/src/IObjectStorage.cs deleted file mode 100644 index 5c99cd8..0000000 --- a/Utils/src/IObjectStorage.cs +++ /dev/null @@ -1,48 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: IObjectStorage.cs -* -* IObjectStorage.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/. -*/ - -namespace VNLib.Utils -{ - /// - /// This object will provide methods for storing and retreiving objects by key-value pairing - /// - public interface IObjectStorage - { - /// - /// Attempts to retrieve the specified object from storage - /// - /// - /// Key for storage - /// The object in storage, or T.default if object is not found - public T GetObject(string key); - - /// - /// Stores the specified object with the specified key - /// - /// - /// Key paired with object - /// Object to store - public void SetObject(string key, T obj); - } -} \ No newline at end of file diff --git a/Utils/src/Logging/ILogProvider.cs b/Utils/src/Logging/ILogProvider.cs deleted file mode 100644 index 55dbd6f..0000000 --- a/Utils/src/Logging/ILogProvider.cs +++ /dev/null @@ -1,79 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: ILogProvider.cs -* -* ILogProvider.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; - -namespace VNLib.Utils.Logging -{ - /// - /// Self-contained logging interface that allows for applications events to be written to an - /// output source - /// - public interface ILogProvider - { - /// - /// Flushes any buffers to the output source - /// - abstract void Flush(); - - /// - /// Writes the string to the log with the specified priority log level - /// - /// The log priority level - /// The message to print - void Write(LogLevel level, string value); - /// - /// Writes the exception and optional string to the log with the specified priority log level - /// - /// The log priority level - /// An exception object to write - /// The message to print - void Write(LogLevel level, Exception exception, string value = ""); - /// - /// Writes the template string and params arguments to the log with the specified priority log level - /// - /// The log priority level - /// The log template string - /// Variable length array of objects to log with the specified templatre - void Write(LogLevel level, string value, params object?[] args); - /// - /// Writes the template string and params arguments to the log with the specified priority log level - /// - /// The log priority level - /// The log template string - /// Variable length array of objects to log with the specified templatre - void Write(LogLevel level, string value, params ValueType[] args); - - /// - /// Gets the underlying log source - /// - /// The underlying log source - object GetLogProvider(); - /// - /// Gets the underlying log source - /// - /// The underlying log source - public virtual T GetLogProvider() => (T)GetLogProvider(); - } -} diff --git a/Utils/src/Logging/LogLevel.cs b/Utils/src/Logging/LogLevel.cs deleted file mode 100644 index 1851c26..0000000 --- a/Utils/src/Logging/LogLevel.cs +++ /dev/null @@ -1,33 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: LogLevel.cs -* -* LogLevel.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; - -namespace VNLib.Utils.Logging -{ - public enum LogLevel - { - Verbose, Debug, Information, Warning, Error, Fatal - } -} diff --git a/Utils/src/Logging/LoggerExtensions.cs b/Utils/src/Logging/LoggerExtensions.cs deleted file mode 100644 index cd314ed..0000000 --- a/Utils/src/Logging/LoggerExtensions.cs +++ /dev/null @@ -1,60 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: LoggerExtensions.cs -* -* LoggerExtensions.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/. -*/ - -#pragma warning disable CA1062 // Validate arguments of public methods - -using System; - -namespace VNLib.Utils.Logging -{ - /// - /// Extension helper methods for writing logs to a - /// - public static class LoggerExtensions - { - public static void Debug(this ILogProvider log, Exception exp, string value = "") => log.Write(LogLevel.Debug, exp, value); - public static void Debug(this ILogProvider log, string value) => log.Write(LogLevel.Debug, value); - public static void Debug(this ILogProvider log, string format, params object?[] args) => log.Write(LogLevel.Debug, format, args); - public static void Debug(this ILogProvider log, string format, params ValueType[] args) => log.Write(LogLevel.Debug, format, args); - public static void Error(this ILogProvider log, Exception exp, string value = "") => log.Write(LogLevel.Error, exp, value); - public static void Error(this ILogProvider log, string value) => log.Write(LogLevel.Error, value); - public static void Error(this ILogProvider log, string format, params object?[] args) => log.Write(LogLevel.Error, format, args); - public static void Fatal(this ILogProvider log, Exception exp, string value = "") => log.Write(LogLevel.Fatal, exp, value); - public static void Fatal(this ILogProvider log, string value) => log.Write(LogLevel.Fatal, value); - public static void Fatal(this ILogProvider log, string format, params object?[] args) => log.Write(LogLevel.Fatal, format, args); - public static void Fatal(this ILogProvider log, string format, params ValueType[] args) => log.Write(LogLevel.Fatal, format, args); - public static void Information(this ILogProvider log, Exception exp, string value = "") => log.Write(LogLevel.Information, exp, value); - public static void Information(this ILogProvider log, string value) => log.Write(LogLevel.Information, value); - public static void Information(this ILogProvider log, string format, params object?[] args) => log.Write(LogLevel.Information, format, args); - public static void Information(this ILogProvider log, string format, params ValueType[] args) => log.Write(LogLevel.Information, format, args); - public static void Verbose(this ILogProvider log, Exception exp, string value = "") => log.Write(LogLevel.Verbose, exp, value); - public static void Verbose(this ILogProvider log, string value) => log.Write(LogLevel.Verbose, value); - public static void Verbose(this ILogProvider log, string format, params object?[] args) => log.Write(LogLevel.Verbose, format, args); - public static void Verbose(this ILogProvider log, string format, params ValueType[] args) => log.Write(LogLevel.Verbose, format, args); - public static void Warn(this ILogProvider log, Exception exp, string value = "") => log.Write(LogLevel.Warning, exp, value); - public static void Warn(this ILogProvider log, string value) => log.Write(LogLevel.Warning, value); - public static void Warn(this ILogProvider log, string format, params object?[] args) => log.Write(LogLevel.Warning, format, args); - public static void Warn(this ILogProvider log, string format, params ValueType[] args) => log.Write(LogLevel.Warning, format, args); - } -} diff --git a/Utils/src/Memory/Caching/ICacheHolder.cs b/Utils/src/Memory/Caching/ICacheHolder.cs deleted file mode 100644 index 19eee64..0000000 --- a/Utils/src/Memory/Caching/ICacheHolder.cs +++ /dev/null @@ -1,45 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: ICacheHolder.cs -* -* ICacheHolder.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; - -namespace VNLib.Utils.Memory.Caching -{ - /// - /// Exposes basic control of classes that manage private caches - /// - public interface ICacheHolder - { - /// - /// Clears all held caches without causing application stopping effects. - /// - /// This is a safe "light" cache clear - void CacheClear(); - /// - /// Performs all necessary actions to clear all held caches immediatly. - /// - /// A "hard" cache clear/reset regardless of cost - void CacheHardClear(); - } -} \ No newline at end of file diff --git a/Utils/src/Memory/Caching/ICacheable.cs b/Utils/src/Memory/Caching/ICacheable.cs deleted file mode 100644 index 37575cc..0000000 --- a/Utils/src/Memory/Caching/ICacheable.cs +++ /dev/null @@ -1,44 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: ICacheable.cs -* -* ICacheable.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; - -namespace VNLib.Utils.Memory.Caching -{ - /// - /// Represents a cacheable entity with an expiration - /// - public interface ICacheable : IEquatable - { - /// - /// A value that the entry is no longer valid - /// - DateTime Expires { get; set; } - - /// - /// Invoked when a collection occurs - /// - void Evicted(); - } -} diff --git a/Utils/src/Memory/Caching/IObjectRental.cs b/Utils/src/Memory/Caching/IObjectRental.cs deleted file mode 100644 index d9489f4..0000000 --- a/Utils/src/Memory/Caching/IObjectRental.cs +++ /dev/null @@ -1,47 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: IObjectRental.cs -* -* IObjectRental.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/. -*/ - -namespace VNLib.Utils.Memory.Caching -{ - - /// - /// A thread safe store for reusing CLR managed objects - /// - /// The reusable object class - public interface IObjectRental where T: class - { - /// - /// Gets an object from the store, or creates a new one if none are available - /// - /// An instance of from the store if available or a new instance if none were available - T Rent(); - - /// - /// Returns a rented object back to the rental store for reuse - /// - /// The previously rented item - void Return(T item); - } - -} \ No newline at end of file diff --git a/Utils/src/Memory/Caching/IReusable.cs b/Utils/src/Memory/Caching/IReusable.cs deleted file mode 100644 index 618878f..0000000 --- a/Utils/src/Memory/Caching/IReusable.cs +++ /dev/null @@ -1,42 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: IReusable.cs -* -* IReusable.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/. -*/ - -namespace VNLib.Utils.Memory.Caching -{ - /// - /// Allows for use within a , this object is intended to be reused heavily - /// - public interface IReusable - { - /// - /// The instance should prepare itself for use (or re-use) - /// - void Prepare(); - /// - /// The intance is being returned and should determine if it's state is reusabled - /// - /// true if the instance can/should be reused, false if it should not be reused - bool Release(); - } -} \ No newline at end of file diff --git a/Utils/src/Memory/Caching/LRUCache.cs b/Utils/src/Memory/Caching/LRUCache.cs deleted file mode 100644 index 7e96e0a..0000000 --- a/Utils/src/Memory/Caching/LRUCache.cs +++ /dev/null @@ -1,127 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: LRUCache.cs -* -* LRUCache.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.Collections.Generic; -using System.Diagnostics.CodeAnalysis; - -namespace VNLib.Utils.Memory.Caching -{ - /// - /// A base class for a Least Recently Used cache - /// - /// The key for O(1) lookups - /// The value to store within cache - public abstract class LRUCache : LRUDataStore where TKey : notnull - { - /// - protected LRUCache() - {} - /// - protected LRUCache(int initialCapacity) : base(initialCapacity) - {} - /// - protected LRUCache(IEqualityComparer keyComparer) : base(keyComparer) - {} - /// - protected LRUCache(int initialCapacity, IEqualityComparer keyComparer) : base(initialCapacity, keyComparer) - {} - - /// - /// The maximum number of items to store in LRU cache - /// - protected abstract int MaxCapacity { get; } - - /// - /// Adds a new record to the LRU cache - /// - /// A to add to the cache store - public override void Add(KeyValuePair item) - { - //See if the store is at max capacity and an item needs to be evicted - if(Count == MaxCapacity) - { - //A record needs to be evicted before a new record can be added - - //Get the oldest node from the list to reuse its instance and remove the old value - LinkedListNode> oldNode = List.First!; //not null because count is at max capacity so an item must be at the end of the list - //Store old node value field - KeyValuePair oldRecord = oldNode.Value; - //Remove from lookup - LookupTable.Remove(oldRecord.Key); - //Remove the node - List.RemoveFirst(); - //Reuse the old ll node - oldNode.Value = item; - //add lookup with new key - LookupTable.Add(item.Key, oldNode); - //Add to end of list - List.AddLast(oldNode); - //Invoke evicted method - Evicted(oldRecord); - } - else - { - //Add new item to the list - base.Add(item); - } - } - /// - /// Attempts to get a value by the given key. - /// - /// The key identifying the value to store - /// The value to store - /// A value indicating if the value was found in the store - public override bool TryGetValue(TKey key, [NotNullWhen(true)] out TValue? value) - { - //See if the cache contains the value - if(base.TryGetValue(key, out value)) - { - //Cache hit - return true; - } - //Cache miss - if(CacheMiss(key, out value)) - { - //Lookup hit - //Add the record to the store (eviction will happen as necessary - Add(key, value); - return true; - } - //Record does not exist - return false; - } - /// - /// Invoked when a record is evicted from the cache - /// - /// The record that is being evicted - protected abstract void Evicted(KeyValuePair evicted); - /// - /// Invoked when an entry was requested and was not found in cache. - /// - /// The key identifying the record to lookup - /// The found value matching the key - /// A value indicating if the record was found - protected abstract bool CacheMiss(TKey key, [NotNullWhen(true)] out TValue? value); - } -} diff --git a/Utils/src/Memory/Caching/LRUDataStore.cs b/Utils/src/Memory/Caching/LRUDataStore.cs deleted file mode 100644 index f564fcc..0000000 --- a/Utils/src/Memory/Caching/LRUDataStore.cs +++ /dev/null @@ -1,232 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: LRUDataStore.cs -* -* LRUDataStore.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.Linq; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; - -namespace VNLib.Utils.Memory.Caching -{ - /// - /// A Least Recently Used store base class for E2E O(1) operations - /// - /// A key used for O(1) lookups - /// A value to store - public abstract class LRUDataStore : IDictionary, IReadOnlyDictionary, IReadOnlyCollection, IEnumerable> - where TKey: notnull - { - /// - /// A lookup table that provides O(1) access times for key-value lookups - /// - protected Dictionary>> LookupTable { get; } - /// - /// A linked list that tracks the least recently used item. - /// New items (or recently access items) are moved to the end of the list. - /// The head contains the least recently used item - /// - protected LinkedList> List { get; } - - /// - /// Initializes an empty - /// - protected LRUDataStore() - { - LookupTable = new(); - List = new(); - } - /// - /// Initializes an empty and sets - /// the lookup table's inital capacity - /// - /// LookupTable initial capacity - protected LRUDataStore(int initialCapacity) - { - LookupTable = new(initialCapacity); - List = new(); - } - /// - /// Initializes an empty and uses the - /// specified keycomparison - /// - /// A used by the Lookuptable to compare keys - protected LRUDataStore(IEqualityComparer keyComparer) - { - LookupTable = new(keyComparer); - List = new(); - } - /// - /// Initializes an empty and uses the - /// specified keycomparison, and sets the lookup table's initial capacity - /// - /// LookupTable initial capacity - /// A used by the Lookuptable to compare keys - protected LRUDataStore(int initialCapacity, IEqualityComparer keyComparer) - { - LookupTable = new(initialCapacity, keyComparer); - List = new(); - } - - /// - /// Gets or sets a value within the LRU cache. - /// - /// The key identifying the value - /// The value stored at the given key - /// Items are promoted in the store when accessed - public virtual TValue this[TKey key] - { - get - { - return TryGetValue(key, out TValue? value) - ? value - : throw new KeyNotFoundException("The item or its key were not found in the LRU data store"); - } - set - { - //If a node by the same key in the store exists, just replace its value - if(LookupTable.TryGetValue(key, out LinkedListNode>? oldNode)) - { - //Remove the node before re-adding it - List.Remove(oldNode); - oldNode.Value = new KeyValuePair(key, value); - //Move the item to the front of the list - List.AddLast(oldNode); - } - else - { - //Node does not exist yet so create new one - Add(key, value); - } - } - } - /// - public ICollection Keys => LookupTable.Keys; - /// - /// - public ICollection Values => throw new NotImplementedException(); - IEnumerable IReadOnlyDictionary.Keys => LookupTable.Keys; - IEnumerable IReadOnlyDictionary.Values => List.Select(static node => node.Value); - IEnumerator IEnumerable.GetEnumerator() => List.Select(static node => node.Value).GetEnumerator(); - - /// - /// Gets the number of items within the LRU store - /// - public int Count => List.Count; - /// - public abstract bool IsReadOnly { get; } - - /// - /// Adds the specified record to the store and places it at the end of the LRU queue - /// - /// The key identifying the record - /// The value to store at the key - public void Add(TKey key, TValue value) - { - //Create new kvp lookup ref - KeyValuePair lookupRef = new(key, value); - //Insert the lookup - Add(lookupRef); - } - /// - public bool Remove(KeyValuePair item) => Remove(item.Key); - /// - IEnumerator IEnumerable.GetEnumerator() => List.GetEnumerator(); - /// - public void CopyTo(KeyValuePair[] array, int arrayIndex) => List.CopyTo(array, arrayIndex); - /// - public virtual bool ContainsKey(TKey key) => LookupTable.ContainsKey(key); - /// - public virtual IEnumerator> GetEnumerator() => List.GetEnumerator(); - - /// - /// Adds the specified record to the store and places it at the end of the LRU queue - /// - /// The item to add - public virtual void Add(KeyValuePair item) - { - //Init new ll node - LinkedListNode> newNode = new(item); - //Insert the new node - LookupTable.Add(item.Key, newNode); - //Add to the end of the linked list - List.AddLast(newNode); - } - /// - /// Removes all elements from the LRU store - /// - public virtual void Clear() - { - //Clear lists - LookupTable.Clear(); - List.Clear(); - } - /// - /// Determines if the exists in the store - /// - /// The record to search for - /// True if the key was found in the store and the value equals the stored value, false otherwise - public virtual bool Contains(KeyValuePair item) - { - if (LookupTable.TryGetValue(item.Key, out LinkedListNode>? lookup)) - { - return lookup.Value.Value?.Equals(item.Value) ?? false; - } - return false; - } - /// - public virtual bool Remove(TKey key) - { - //Remove the item from the lookup table and if it exists, remove the node from the list - if(LookupTable.Remove(key, out LinkedListNode>? node)) - { - //Remove the new from the list - List.Remove(node); - return true; - } - return false; - } - /// - /// Tries to get a value from the store with its key. Found items are promoted - /// - /// The key identifying the value - /// The found value - /// A value indicating if the element was found in the store - public virtual bool TryGetValue(TKey key, [NotNullWhen(true)] out TValue? value) - { - //Lookup the - if (LookupTable.TryGetValue(key, out LinkedListNode>? val)) - { - //Remove the value from the list and add it to the front of the list - List.Remove(val); - List.AddLast(val); - value = val.Value.Value!; - return true; - } - value = default; - return false; - } - - } -} diff --git a/Utils/src/Memory/Caching/ObjectRental.cs b/Utils/src/Memory/Caching/ObjectRental.cs deleted file mode 100644 index 22aca95..0000000 --- a/Utils/src/Memory/Caching/ObjectRental.cs +++ /dev/null @@ -1,236 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: ObjectRental.cs -* -* ObjectRental.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.Threading; -using System.Diagnostics; -using System.Collections; -using System.Collections.Generic; - -using VNLib.Utils.Extensions; - -namespace VNLib.Utils.Memory.Caching -{ - //TODO: implement lock-free object tracking - - /// - /// Provides concurrent storage for reusable objects to be rented and returned. This class - /// and its members is thread-safe - /// - /// The data type to reuse - public class ObjectRental : ObjectRental, IObjectRental, ICacheHolder, IEnumerable where T: class - { - /// - /// The initial data-structure capacity if quota is not defined - /// - public const int INITIAL_STRUCTURE_SIZE = 50; - - protected readonly SemaphoreSlim StorageLock; - protected readonly Stack Storage; - protected readonly HashSet ContainsStore; - - protected readonly Action? ReturnAction; - protected readonly Action? RentAction; - protected readonly Func Constructor; - /// - /// Is the object type in the current store implement the Idisposable interface? - /// - protected readonly bool IsDisposableType; - - /// - /// The maximum number of objects that will be cached. - /// Once this threshold has been reached, objects are - /// no longer stored - /// - protected readonly int QuotaLimit; - -#pragma warning disable CS8618 //Internal constructor does not set the constructor function - private ObjectRental(int quota) -#pragma warning restore CS8618 - { - //alloc new stack for rentals - Storage = new(Math.Max(quota, INITIAL_STRUCTURE_SIZE)); - //Hashtable for quick lookups - ContainsStore = new(Math.Max(quota, INITIAL_STRUCTURE_SIZE)); - //Semaphore slim to provide exclusive access - StorageLock = new SemaphoreSlim(1, 1); - //Store quota, if quota is -1, set to int-max to "disable quota" - QuotaLimit = quota == 0 ? int.MaxValue : quota; - //Determine if the type is disposeable and store a local value - IsDisposableType = typeof(IDisposable).IsAssignableFrom(typeof(T)); - } - - /// - /// Creates a new store with the rent/return callback methods - /// - /// The type initializer - /// The pre-retnal preperation action - /// The pre-return cleanup action - /// The maximum number of elements to cache in the store - protected internal ObjectRental(Func constructor, Action? rentCb, Action? returnCb, int quota) : this(quota) - { - this.RentAction = rentCb; - this.ReturnAction = returnCb; - this.Constructor = constructor; - } - - /// - /// - public virtual T Rent() - { - Check(); - //See if we have an available object, if not return a new one by invoking the constructor function - T? rental = default; - //Get lock - using (SemSlimReleaser releader = StorageLock.GetReleaser()) - { - //See if the store contains an item ready to use - if(Storage.TryPop(out T? item)) - { - rental = item; - //Remove the item from the hash table - ContainsStore.Remove(item); - } - } - //If no object was removed from the store, create a new one - rental ??= Constructor(); - //If rental cb is defined, invoke it - RentAction?.Invoke(rental); - return rental; - } - - /// - /// - public virtual void Return(T item) - { - Check(); - //Invoke return callback if set - ReturnAction?.Invoke(item); - //Keeps track to know if the element was added or need to be cleaned up - bool wasAdded = false; - using (SemSlimReleaser releader = StorageLock.GetReleaser()) - { - //Check quota limit - if (Storage.Count < QuotaLimit) - { - //Store item if it doesnt exist already - if (ContainsStore.Add(item)) - { - //Store the object - Storage.Push(item); - } - //Set the was added flag - wasAdded = true; - } - } - if (!wasAdded && IsDisposableType) - { - //If the element was not added and is disposeable, we can dispose the element - (item as IDisposable)!.Dispose(); - //Write debug message - Debug.WriteLine("Object rental disposed an object over quota"); - } - } - - /// - /// NOTE: If implements - /// interface, this method does nothing - /// - /// - /// - public virtual void CacheClear() - { - Check(); - //If the type is disposeable, cleaning can be a long process, so defer to hard clear - if (IsDisposableType) - { - return; - } - //take the semaphore - using SemSlimReleaser releader = StorageLock.GetReleaser(); - //Clear stores - ContainsStore.Clear(); - Storage.Clear(); - } - - /// - /// - public virtual void CacheHardClear() - { - Check(); - //take the semaphore - using SemSlimReleaser releader = StorageLock.GetReleaser(); - //If the type is disposable, dispose all elements before clearing storage - if (IsDisposableType) - { - //Dispose all elements - foreach (T element in Storage.ToArray()) - { - (element as IDisposable)!.Dispose(); - } - } - //Clear the storeage - Storage.Clear(); - ContainsStore.Clear(); - } - /// - protected override void Free() - { - StorageLock.Dispose(); - //If the element type is disposable, dispose all elements on a hard clear - if (IsDisposableType) - { - //Get all elements - foreach (T element in Storage.ToArray()) - { - (element as IDisposable)!.Dispose(); - } - } - } - - /// - public IEnumerator GetEnumerator() - { - Check(); - //Enter the semaphore - using SemSlimReleaser releader = StorageLock.GetReleaser(); - foreach (T item in Storage) - { - yield return item; - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - Check(); - //Enter the semaphore - using SemSlimReleaser releader = StorageLock.GetReleaser(); - foreach (T item in Storage) - { - yield return item; - } - } - } - -} \ No newline at end of file diff --git a/Utils/src/Memory/Caching/ObjectRentalBase.cs b/Utils/src/Memory/Caching/ObjectRentalBase.cs deleted file mode 100644 index 305d93f..0000000 --- a/Utils/src/Memory/Caching/ObjectRentalBase.cs +++ /dev/null @@ -1,155 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: ObjectRentalBase.cs -* -* ObjectRentalBase.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; - -namespace VNLib.Utils.Memory.Caching -{ - /// - /// Provides concurrent storage for reusable objects to be rented and returned. This class - /// and its members is thread-safe - /// - public abstract class ObjectRental : VnDisposeable - { - /// - /// Creates a new store - /// - /// The maximum number of elements that will be cached - public static ObjectRental Create(int quota = 0) where TNew : class, new() - { - static TNew constructor() => new(); - return new ObjectRental(constructor, null, null, quota); - } - /// - /// Creates a new store with generic rental and return callback handlers - /// - /// Function responsible for preparing an instance to be rented - /// Function responsible for cleaning up an instance before reuse - /// The maximum number of elements that will be cached - public static ObjectRental Create(Action? rentCb, Action? returnCb, int quota = 0) where TNew : class, new() - { - static TNew constructor() => new(); - return new ObjectRental(constructor, rentCb, returnCb, quota); - } - /// - /// Creates a new store with a generic constructor function - /// - /// The function invoked to create a new instance when required - /// The maximum number of elements that will be cached - /// - public static ObjectRental Create(Func constructor, int quota = 0) where TNew: class - { - return new ObjectRental(constructor, null, null, quota); - } - /// - /// Creates a new store with generic rental and return callback handlers - /// - /// The function invoked to create a new instance when required - /// Function responsible for preparing an instance to be rented - /// Function responsible for cleaning up an instance before reuse - /// The maximum number of elements that will be cached - public static ObjectRental Create(Func constructor, Action? rentCb, Action? returnCb, int quota = 0) where TNew : class - { - return new ObjectRental(constructor, rentCb, returnCb, quota); - } - - /// - /// Creates a new store with generic rental and return callback handlers - /// - /// - /// The function invoked to create a new instance when required - /// Function responsible for preparing an instance to be rented - /// Function responsible for cleaning up an instance before reuse - /// The initialized store - public static ThreadLocalObjectStorage CreateThreadLocal(Func constructor, Action? rentCb, Action? returnCb) where TNew : class - { - return new ThreadLocalObjectStorage(constructor, rentCb, returnCb); - } - /// - /// Creates a new store with generic rental and return callback handlers - /// - /// Function responsible for preparing an instance to be rented - /// Function responsible for cleaning up an instance before reuse - public static ThreadLocalObjectStorage CreateThreadLocal(Action? rentCb, Action? returnCb) where TNew : class, new() - { - static TNew constructor() => new(); - return new ThreadLocalObjectStorage(constructor, rentCb, returnCb); - } - /// - /// Creates a new store - /// - public static ThreadLocalObjectStorage CreateThreadLocal() where TNew : class, new() - { - static TNew constructor() => new(); - return new ThreadLocalObjectStorage(constructor, null, null); - } - /// - /// Creates a new store with a generic constructor function - /// - /// The function invoked to create a new instance when required - /// - public static ThreadLocalObjectStorage CreateThreadLocal(Func constructor) where TNew : class - { - return new ThreadLocalObjectStorage(constructor, null, null); - } - - /// - /// Creates a new instance with a parameterless constructor - /// - /// The type - /// The maximum number of elements that will be cached - /// - public static ReusableStore CreateReusable(int quota = 0) where T : class, IReusable, new() - { - static T constructor() => new(); - return new(constructor, quota); - } - /// - /// Creates a new instance with the specified constructor - /// - /// The type - /// The constructor function invoked to create new instances of the type - /// The maximum number of elements that will be cached - /// - public static ReusableStore CreateReusable(Func constructor, int quota = 0) where T : class, IReusable => new(constructor, quota); - - /// - /// Creates a new instance with a parameterless constructor - /// - /// The type - /// - public static ThreadLocalReusableStore CreateThreadLocalReusable() where T : class, IReusable, new() - { - static T constructor() => new(); - return new(constructor); - } - /// - /// Creates a new instance with the specified constructor - /// - /// The type - /// The constructor function invoked to create new instances of the type - /// - public static ThreadLocalReusableStore CreateThreadLocalReusable(Func constructor) where T : class, IReusable => new(constructor); - } -} diff --git a/Utils/src/Memory/Caching/ReusableStore.cs b/Utils/src/Memory/Caching/ReusableStore.cs deleted file mode 100644 index aacd012..0000000 --- a/Utils/src/Memory/Caching/ReusableStore.cs +++ /dev/null @@ -1,61 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: ReusableStore.cs -* -* ReusableStore.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; - -namespace VNLib.Utils.Memory.Caching -{ - - /// - /// A reusable object store that extends , that allows for objects to be reused heavily - /// - /// A reusable object - public class ReusableStore : ObjectRental where T : class, IReusable - { - internal ReusableStore(Func constructor, int quota) :base(constructor, null, null, quota) - {} - /// - public override T Rent() - { - //Rent the object (or create it) - T rental = base.Rent(); - //Invoke prepare function - rental.Prepare(); - //return object - return rental; - } - /// - public override void Return(T item) - { - /* - * Clean up the item by invoking the cleanup function, - * and only return the item for reuse if the caller allows - */ - if (item.Release()) - { - base.Return(item); - } - } - } -} \ No newline at end of file diff --git a/Utils/src/Memory/Caching/ThreadLocalObjectStorage.cs b/Utils/src/Memory/Caching/ThreadLocalObjectStorage.cs deleted file mode 100644 index 511af24..0000000 --- a/Utils/src/Memory/Caching/ThreadLocalObjectStorage.cs +++ /dev/null @@ -1,76 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: ThreadLocalObjectStorage.cs -* -* ThreadLocalObjectStorage.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.Threading; - -namespace VNLib.Utils.Memory.Caching -{ - /// - /// Derrives from to provide object rental syntax for - /// storage - /// - /// The data type to store - public class ThreadLocalObjectStorage : ObjectRental where T: class - { - protected ThreadLocal Store { get; } - - internal ThreadLocalObjectStorage(Func constructor, Action? rentCb, Action? returnCb) - :base(constructor, rentCb, returnCb, 0) - { - Store = new(Constructor); - } - - /// - /// "Rents" or creates an object for the current thread - /// - /// The new or stored instanced - /// - public override T Rent() - { - Check(); - //Get the tlocal value - T value = Store.Value!; - //Invoke the rent action if set - base.RentAction?.Invoke(value); - return value; - } - - /// - /// - public override void Return(T item) - { - Check(); - //Invoke the rent action - base.ReturnAction?.Invoke(item); - } - - /// - protected override void Free() - { - Store.Dispose(); - base.Free(); - } - } -} \ No newline at end of file diff --git a/Utils/src/Memory/Caching/ThreadLocalReusableStore.cs b/Utils/src/Memory/Caching/ThreadLocalReusableStore.cs deleted file mode 100644 index 83cd4d6..0000000 --- a/Utils/src/Memory/Caching/ThreadLocalReusableStore.cs +++ /dev/null @@ -1,64 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: ThreadLocalReusableStore.cs -* -* ThreadLocalReusableStore.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; - -namespace VNLib.Utils.Memory.Caching -{ - /// - /// A reusable object store that extends , that allows for objects to be reused heavily - /// in a thread-local cache - /// - /// A reusable object - public class ThreadLocalReusableStore : ThreadLocalObjectStorage where T: class, IReusable - { - /// - /// Creates a new instance - /// - internal ThreadLocalReusableStore(Func constructor):base(constructor, null, null) - { } - /// - public override T Rent() - { - //Rent the object (or create it) - T rental = base.Rent(); - //Invoke prepare function - rental.Prepare(); - //return object - return rental; - } - /// - public override void Return(T item) - { - /* - * Clean up the item by invoking the cleanup function, - * and only return the item for reuse if the caller allows - */ - if (item.Release()) - { - base.Return(item); - } - } - } -} \ No newline at end of file diff --git a/Utils/src/Memory/ForwardOnlyBufferWriter.cs b/Utils/src/Memory/ForwardOnlyBufferWriter.cs deleted file mode 100644 index 0ea507e..0000000 --- a/Utils/src/Memory/ForwardOnlyBufferWriter.cs +++ /dev/null @@ -1,122 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: ForwardOnlyBufferWriter.cs -* -* ForwardOnlyBufferWriter.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; - -namespace VNLib.Utils.Memory -{ - /// - /// Provides a stack based buffer writer - /// - public ref struct ForwardOnlyWriter - { - /// - /// The buffer for writing output data to - /// - public readonly Span Buffer { get; } - /// - /// The number of characters written to the buffer - /// - public int Written { readonly get; set; } - /// - /// The number of characters remaining in the buffer - /// - public readonly int RemainingSize => Buffer.Length - Written; - - /// - /// The remaining buffer window - /// - public readonly Span Remaining => Buffer[Written..]; - - /// - /// Creates a new assigning the specified buffer - /// - /// The buffer to write data to - public ForwardOnlyWriter(in Span buffer) - { - Buffer = buffer; - Written = 0; - } - - /// - /// Returns a compiled string from the characters written to the buffer - /// - /// A string of the characters written to the buffer - public readonly override string ToString() => Buffer[..Written].ToString(); - - /// - /// Appends a sequence to the buffer - /// - /// The data to append to the buffer - /// - public void Append(ReadOnlySpan data) - { - //Make sure the current window is large enough to buffer the new string - if (data.Length > RemainingSize) - { - throw new ArgumentOutOfRangeException(nameof(Remaining) ,"The internal buffer does not have enough buffer space"); - } - Span window = Buffer[Written..]; - //write data to window - data.CopyTo(window); - //update char position - Written += data.Length; - } - /// - /// Appends a single item to the buffer - /// - /// The item to append to the buffer - /// - public void Append(T c) - { - //Make sure the current window is large enough to buffer the new string - if (RemainingSize == 0) - { - throw new ArgumentOutOfRangeException(nameof(Remaining), "The internal buffer does not have enough buffer space"); - } - //Write data to buffer and increment the buffer position - Buffer[Written++] = c; - } - - /// - /// Advances the writer forward the specifed number of elements - /// - /// The number of elements to advance the writer by - /// - public void Advance(int count) - { - if (count > RemainingSize) - { - throw new ArgumentOutOfRangeException(nameof(Remaining), "The internal buffer does not have enough buffer space"); - } - Written += count; - } - - /// - /// Resets the writer by setting the - /// property to 0. - /// - public void Reset() => Written = 0; - } -} diff --git a/Utils/src/Memory/ForwardOnlyMemoryReader.cs b/Utils/src/Memory/ForwardOnlyMemoryReader.cs deleted file mode 100644 index c850b14..0000000 --- a/Utils/src/Memory/ForwardOnlyMemoryReader.cs +++ /dev/null @@ -1,74 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: ForwardOnlyMemoryReader.cs -* -* ForwardOnlyMemoryReader.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; - -namespace VNLib.Utils.Memory -{ - /// - /// A mutable structure used to implement a simple foward only - /// reader for a memory segment - /// - /// The element type - public struct ForwardOnlyMemoryReader - { - private readonly ReadOnlyMemory _segment; - private readonly int _size; - - private int _position; - - /// - /// Initializes a new - /// of the specified type using the specified internal buffer - /// - /// The buffer to read from - public ForwardOnlyMemoryReader(in ReadOnlyMemory buffer) - { - _segment = buffer; - _size = buffer.Length; - _position = 0; - } - - /// - /// The remaining data window - /// - public readonly ReadOnlyMemory Window => _segment[_position..]; - /// - /// The number of elements remaining in the window - /// - public readonly int WindowSize => _size - _position; - - - /// - /// Advances the window position the specified number of elements - /// - /// The number of elements to advance the widnow position - public void Advance(int count) => _position += count; - - /// - /// Resets the sliding window to the begining of the buffer - /// - public void Reset() => _position = 0; - } -} diff --git a/Utils/src/Memory/ForwardOnlyMemoryWriter.cs b/Utils/src/Memory/ForwardOnlyMemoryWriter.cs deleted file mode 100644 index 4f5286d..0000000 --- a/Utils/src/Memory/ForwardOnlyMemoryWriter.cs +++ /dev/null @@ -1,122 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: ForwardOnlyMemoryWriter.cs -* -* ForwardOnlyMemoryWriter.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; - -namespace VNLib.Utils.Memory -{ - /// - /// Provides a mutable sliding buffer writer - /// - public struct ForwardOnlyMemoryWriter - { - /// - /// The buffer for writing output data to - /// - public readonly Memory Buffer { get; } - /// - /// The number of characters written to the buffer - /// - public int Written { readonly get; set; } - /// - /// The number of characters remaining in the buffer - /// - public readonly int RemainingSize => Buffer.Length - Written; - - /// - /// The remaining buffer window - /// - public readonly Memory Remaining => Buffer[Written..]; - - /// - /// Creates a new assigning the specified buffer - /// - /// The buffer to write data to - public ForwardOnlyMemoryWriter(in Memory buffer) - { - Buffer = buffer; - Written = 0; - } - - /// - /// Returns a compiled string from the characters written to the buffer - /// - /// A string of the characters written to the buffer - public readonly override string ToString() => Buffer[..Written].ToString(); - - /// - /// Appends a sequence to the buffer - /// - /// The data to append to the buffer - /// - public void Append(ReadOnlyMemory data) - { - //Make sure the current window is large enough to buffer the new string - if (data.Length > RemainingSize) - { - throw new ArgumentOutOfRangeException(nameof(Remaining), "The internal buffer does not have enough buffer space"); - } - Memory window = Buffer[Written..]; - //write data to window - data.CopyTo(window); - //update char position - Written += data.Length; - } - /// - /// Appends a single item to the buffer - /// - /// The item to append to the buffer - /// - public void Append(T c) - { - //Make sure the current window is large enough to buffer the new string - if (RemainingSize == 0) - { - throw new ArgumentOutOfRangeException(nameof(Remaining), "The internal buffer does not have enough buffer space"); - } - //Write data to buffer and increment the buffer position - Buffer.Span[Written++] = c; - } - - /// - /// Advances the writer forward the specifed number of elements - /// - /// The number of elements to advance the writer by - /// - public void Advance(int count) - { - if (count > RemainingSize) - { - throw new ArgumentOutOfRangeException(nameof(count), count, "Cannot advance past the end of the buffer"); - } - Written += count; - } - - /// - /// Resets the writer by setting the - /// property to 0. - /// - public void Reset() => Written = 0; - } -} diff --git a/Utils/src/Memory/ForwardOnlyReader.cs b/Utils/src/Memory/ForwardOnlyReader.cs deleted file mode 100644 index aa268c4..0000000 --- a/Utils/src/Memory/ForwardOnlyReader.cs +++ /dev/null @@ -1,74 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: ForwardOnlyReader.cs -* -* ForwardOnlyReader.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; - -namespace VNLib.Utils.Memory -{ - /// - /// A mutable structure used to implement a simple foward only - /// reader for a memory segment - /// - /// The element type - public ref struct ForwardOnlyReader - { - private readonly ReadOnlySpan _segment; - private readonly int _size; - - private int _position; - - /// - /// Initializes a new - /// of the specified type using the specified internal buffer - /// - /// The buffer to read from - public ForwardOnlyReader(in ReadOnlySpan buffer) - { - _segment = buffer; - _size = buffer.Length; - _position = 0; - } - - /// - /// The remaining data window - /// - public readonly ReadOnlySpan Window => _segment[_position..]; - - /// - /// The number of elements remaining in the window - /// - public readonly int WindowSize => _size - _position; - - /// - /// Advances the window position the specified number of elements - /// - /// The number of elements to advance the widnow position - public void Advance(int count) => _position += count; - - /// - /// Resets the sliding window to the begining of the buffer - /// - public void Reset() => _position = 0; - } -} diff --git a/Utils/src/Memory/IMemoryHandle.cs b/Utils/src/Memory/IMemoryHandle.cs deleted file mode 100644 index 75d1cce..0000000 --- a/Utils/src/Memory/IMemoryHandle.cs +++ /dev/null @@ -1,53 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: IMemoryHandle.cs -* -* IMemoryHandle.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.Buffers; - -namespace VNLib.Utils.Memory -{ - /// - /// Represents a handle for safe access to memory managed/unamanged memory - /// - /// The type this handle represents - public interface IMemoryHandle : IDisposable, IPinnable - { - /// - /// The size of the block as an integer - /// - /// - int IntLength { get; } - - /// - /// The number of elements in the block - /// - ulong Length { get; } - - /// - /// Gets the internal block as a span - /// - Span Span { get; } - } - -} diff --git a/Utils/src/Memory/IStringSerializeable.cs b/Utils/src/Memory/IStringSerializeable.cs deleted file mode 100644 index 12cfe52..0000000 --- a/Utils/src/Memory/IStringSerializeable.cs +++ /dev/null @@ -1,55 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: IStringSerializeable.cs -* -* IStringSerializeable.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; - -namespace VNLib.Utils.Memory -{ - /// - /// A interface that provides indempodent abstractions for compiling an instance - /// to its representitive string. - /// - public interface IStringSerializeable - { - /// - /// Compiles the current instance into its safe string representation - /// - /// A string of the desired representation of the current instance - string Compile(); - /// - /// Compiles the current instance into its safe string representation, and writes its - /// contents to the specified buffer writer - /// - /// The ouput writer to write the serialized representation to - /// - void Compile(ref ForwardOnlyWriter writer); - /// - /// Compiles the current instance into its safe string representation, and writes its - /// contents to the specified buffer writer - /// - /// The buffer to write the serialized representation to - /// The number of characters written to the buffer - ERRNO Compile(in Span buffer); - } -} diff --git a/Utils/src/Memory/IUnmangedHeap.cs b/Utils/src/Memory/IUnmangedHeap.cs deleted file mode 100644 index 5d8f4bf..0000000 --- a/Utils/src/Memory/IUnmangedHeap.cs +++ /dev/null @@ -1,59 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: IUnmangedHeap.cs -* -* IUnmangedHeap.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; - -namespace VNLib.Utils.Memory -{ - /// - /// Abstraction for handling (allocating, resizing, and freeing) blocks of unmanaged memory from an unmanged heap - /// - public interface IUnmangedHeap : IDisposable - { - /// - /// Allocates a block of memory from the heap and returns a pointer to the new memory block - /// - /// The size (in bytes) of the element - /// The number of elements to allocate - /// An optional parameter to zero the block of memory - /// - IntPtr Alloc(UInt64 elements, UInt64 size, bool zero); - - /// - /// Resizes the allocated block of memory to the new size - /// - /// The block to resize - /// The new number of elements - /// The size (in bytes) of the type - /// An optional parameter to zero the block of memory - void Resize(ref IntPtr block, UInt64 elements, UInt64 size, bool zero); - - /// - /// Free's a previously allocated block of memory - /// - /// The memory to be freed - /// A value indicating if the free operation succeeded - bool Free(ref IntPtr block); - } -} diff --git a/Utils/src/Memory/Memory.cs b/Utils/src/Memory/Memory.cs deleted file mode 100644 index 822d98c..0000000 --- a/Utils/src/Memory/Memory.cs +++ /dev/null @@ -1,456 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: Memory.cs -* -* Memory.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.Buffers; -using System.Security; -using System.Threading; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; - -using VNLib.Utils.Extensions; - -namespace VNLib.Utils.Memory -{ - /// - /// Provides optimized cross-platform maanged/umanaged safe/unsafe memory operations - /// - [SecurityCritical] - [ComVisible(false)] - public unsafe static class Memory - { - public const string SHARED_HEAP_TYPE_ENV= "VNLIB_SHARED_HEAP_TYPE"; - public const string SHARED_HEAP_INTIAL_SIZE_ENV = "VNLIB_SHARED_HEAP_SIZE"; - - /// - /// Initial shared heap size (bytes) - /// - public const ulong SHARED_HEAP_INIT_SIZE = 20971520; - - public const int MAX_BUF_SIZE = 2097152; - public const int MIN_BUF_SIZE = 16000; - - /// - /// The maximum buffer size requested by - /// that will use the array pool before falling back to the . - /// heap. - /// - public const int MAX_UNSAFE_POOL_SIZE = 500 * 1024; - - /// - /// Provides a shared heap instance for the process to allocate memory from. - /// - /// - /// The backing heap - /// is determined by the OS type and process environment varibles. - /// - public static IUnmangedHeap Shared => _sharedHeap.Value; - - private static readonly Lazy _sharedHeap; - - static Memory() - { - _sharedHeap = new Lazy(() => InitHeapInternal(true), LazyThreadSafetyMode.PublicationOnly); - //Cleanup the heap on process exit - AppDomain.CurrentDomain.DomainUnload += DomainUnloaded; - } - - private static void DomainUnloaded(object sender, EventArgs e) - { - //Dispose the heap if allocated - if (_sharedHeap.IsValueCreated) - { - _sharedHeap.Value.Dispose(); - } - } - - /// - /// Initializes a new determined by compilation/runtime flags - /// and operating system type for the current proccess. - /// - /// An for the current process - /// - /// - public static IUnmangedHeap InitializeNewHeapForProcess() => InitHeapInternal(false); - - private static IUnmangedHeap InitHeapInternal(bool isShared) - { - bool IsWindows = OperatingSystem.IsWindows(); - //Get environment varable - string heapType = Environment.GetEnvironmentVariable(SHARED_HEAP_TYPE_ENV); - //Get inital size - string sharedSize = Environment.GetEnvironmentVariable(SHARED_HEAP_INTIAL_SIZE_ENV); - //Try to parse the shared size from the env - if (!ulong.TryParse(sharedSize, out ulong defaultSize)) - { - defaultSize = SHARED_HEAP_INIT_SIZE; - } - //Gen the private heap from its type or default - switch (heapType) - { - case "win32": - if (!IsWindows) - { - throw new PlatformNotSupportedException("Win32 private heaps are not supported on non-windows platforms"); - } - return PrivateHeap.Create(defaultSize); - case "rpmalloc": - //If the shared heap is being allocated, then return a lock free global heap - return isShared ? RpMallocPrivateHeap.GlobalHeap : new RpMallocPrivateHeap(false); - default: - return IsWindows ? PrivateHeap.Create(defaultSize) : new ProcessHeap(); - } - } - - /// - /// Gets a value that indicates if the Rpmalloc native library is loaded - /// - public static bool IsRpMallocLoaded { get; } = Environment.GetEnvironmentVariable(SHARED_HEAP_TYPE_ENV) == "rpmalloc"; - - #region Zero - /// - /// Zeros a block of memory of umanged type. If Windows is detected at runtime, calls RtlSecureZeroMemory Win32 function - /// - /// Unmanged datatype - /// Block of memory to be cleared - [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] - public static void UnsafeZeroMemory(ReadOnlySpan block) where T : unmanaged - { - if (!block.IsEmpty) - { - checked - { - fixed (void* ptr = &MemoryMarshal.GetReference(block)) - { - //Calls memset - Unsafe.InitBlock(ptr, 0, (uint)(block.Length * sizeof(T))); - } - } - } - } - /// - /// Zeros a block of memory of umanged type. If Windows is detected at runtime, calls RtlSecureZeroMemory Win32 function - /// - /// Unmanged datatype - /// Block of memory to be cleared - [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] - public static void UnsafeZeroMemory(ReadOnlyMemory block) where T : unmanaged - { - if (!block.IsEmpty) - { - checked - { - //Pin memory and get pointer - using MemoryHandle handle = block.Pin(); - //Calls memset - Unsafe.InitBlock(handle.Pointer, 0, (uint)(block.Length * sizeof(T))); - } - } - } - - /// - /// Initializes a block of memory with zeros - /// - /// The unmanaged - /// The block of memory to initialize - public static void InitializeBlock(Span block) where T : unmanaged => UnsafeZeroMemory(block); - /// - /// Initializes a block of memory with zeros - /// - /// The unmanaged - /// The block of memory to initialize - public static void InitializeBlock(Memory block) where T : unmanaged => UnsafeZeroMemory(block); - - /// - /// Zeroes a block of memory pointing to the structure - /// - /// The structure type - /// The pointer to the allocated structure - public static void ZeroStruct(IntPtr block) - { - //get thes size of the structure - int size = Unsafe.SizeOf(); - //Zero block - Unsafe.InitBlock(block.ToPointer(), 0, (uint)size); - } - /// - /// Zeroes a block of memory pointing to the structure - /// - /// The structure type - /// The pointer to the allocated structure - public static void ZeroStruct(void* structPtr) where T: unmanaged - { - //get thes size of the structure - int size = Unsafe.SizeOf(); - //Zero block - Unsafe.InitBlock(structPtr, 0, (uint)size); - } - /// - /// Zeroes a block of memory pointing to the structure - /// - /// The structure type - /// The pointer to the allocated structure - public static void ZeroStruct(T* structPtr) where T : unmanaged - { - //get thes size of the structure - int size = Unsafe.SizeOf(); - //Zero block - Unsafe.InitBlock(structPtr, 0, (uint)size); - } - - #endregion - - #region Copy - /// - /// Copies data from source memory to destination memory of an umanged data type - /// - /// Unmanged type - /// Source data - /// Destination - /// Dest offset - /// - public static void Copy(ReadOnlySpan source, MemoryHandle dest, Int64 destOffset) where T : unmanaged - { - if (source.IsEmpty) - { - return; - } - if (dest.Length < (ulong)(destOffset + source.Length)) - { - throw new ArgumentException("Source data is larger than the dest data block", nameof(source)); - } - //Get long offset from the destination handle - T* offset = dest.GetOffset(destOffset); - fixed(void* src = &MemoryMarshal.GetReference(source)) - { - int byteCount = checked(source.Length * sizeof(T)); - Unsafe.CopyBlock(offset, src, (uint)byteCount); - } - } - /// - /// Copies data from source memory to destination memory of an umanged data type - /// - /// Unmanged type - /// Source data - /// Destination - /// Dest offset - /// - public static void Copy(ReadOnlyMemory source, MemoryHandle dest, Int64 destOffset) where T : unmanaged - { - if (source.IsEmpty) - { - return; - } - if (dest.Length < (ulong)(destOffset + source.Length)) - { - throw new ArgumentException("Dest constraints are larger than the dest data block", nameof(source)); - } - //Get long offset from the destination handle - T* offset = dest.GetOffset(destOffset); - //Pin the source memory - using MemoryHandle srcHandle = source.Pin(); - int byteCount = checked(source.Length * sizeof(T)); - //Copy block using unsafe class - Unsafe.CopyBlock(offset, srcHandle.Pointer, (uint)byteCount); - } - /// - /// Copies data from source memory to destination memory of an umanged data type - /// - /// Unmanged type - /// Source data - /// Number of elements to offset source data - /// Destination - /// Dest offset - /// Number of elements to copy - /// - public static void Copy(MemoryHandle source, Int64 sourceOffset, Span dest, int destOffset, int count) where T : unmanaged - { - if (count <= 0) - { - return; - } - if (source.Length < (ulong)(sourceOffset + count)) - { - throw new ArgumentException("Source constraints are larger than the source data block", nameof(count)); - } - if (dest.Length < destOffset + count) - { - throw new ArgumentOutOfRangeException(nameof(destOffset), "Destination offset range cannot exceed the size of the destination buffer"); - } - //Get offset to allow large blocks of memory - T* src = source.GetOffset(sourceOffset); - fixed(T* dst = &MemoryMarshal.GetReference(dest)) - { - //Cacl offset - T* dstoffset = dst + destOffset; - int byteCount = checked(count * sizeof(T)); - //Aligned copy - Unsafe.CopyBlock(dstoffset, src, (uint)byteCount); - } - } - /// - /// Copies data from source memory to destination memory of an umanged data type - /// - /// Unmanged type - /// Source data - /// Number of elements to offset source data - /// Destination - /// Dest offset - /// Number of elements to copy - /// - public static void Copy(MemoryHandle source, Int64 sourceOffset, Memory dest, int destOffset, int count) where T : unmanaged - { - if (count == 0) - { - return; - } - if (source.Length < (ulong)(sourceOffset + count)) - { - throw new ArgumentException("Source constraints are larger than the source data block", nameof(count)); - } - if(dest.Length < destOffset + count) - { - throw new ArgumentOutOfRangeException(nameof(destOffset), "Destination offset range cannot exceed the size of the destination buffer"); - } - //Get offset to allow large blocks of memory - T* src = source.GetOffset(sourceOffset); - //Pin the memory handle - using MemoryHandle handle = dest.Pin(); - //Byte count - int byteCount = checked(count * sizeof(T)); - //Dest offset - T* dst = ((T*)handle.Pointer) + destOffset; - //Aligned copy - Unsafe.CopyBlock(dst, src, (uint)byteCount); - } - #endregion - - #region Streams - /// - /// Copies data from one stream to another in specified blocks - /// - /// Source memory - /// Source offset - /// Destination memory - /// Destination offset - /// Number of elements to copy - public static void Copy(Stream source, Int64 srcOffset, Stream dest, Int64 destOffst, Int64 count) - { - if (count == 0) - { - return; - } - if (count < 0) - { - throw new ArgumentException("Count must be a positive integer", nameof(count)); - } - //Seek streams - _ = source.Seek(srcOffset, SeekOrigin.Begin); - _ = dest.Seek(destOffst, SeekOrigin.Begin); - //Create new buffer - using IMemoryHandle buffer = Shared.Alloc(count); - Span buf = buffer.Span; - int total = 0; - do - { - //read from source - int read = source.Read(buf); - //guard - if (read == 0) - { - break; - } - //write read slice to dest - dest.Write(buf[..read]); - //update total read - total += read; - } while (total < count); - } - #endregion - - #region alloc - - /// - /// Allocates a block of unmanaged, or pooled manaaged memory depending on - /// compilation flags and runtime unamanged allocators. - /// - /// The unamanged type to allocate - /// The number of elements of the type within the block - /// Flag to zero elements during allocation before the method returns - /// A handle to the block of memory - /// - /// - public static UnsafeMemoryHandle UnsafeAlloc(int elements, bool zero = false) where T : unmanaged - { - if (elements < 0) - { - throw new ArgumentException("Number of elements must be a positive integer", nameof(elements)); - } - if(elements > MAX_UNSAFE_POOL_SIZE || IsRpMallocLoaded) - { - // Alloc from heap - IntPtr block = Shared.Alloc((uint)elements, (uint)sizeof(T), zero); - //Init new handle - return new(Shared, block, elements); - } - else - { - return new(ArrayPool.Shared, elements, zero); - } - } - - /// - /// Allocates a block of unmanaged, or pooled manaaged memory depending on - /// compilation flags and runtime unamanged allocators. - /// - /// The unamanged type to allocate - /// The number of elements of the type within the block - /// Flag to zero elements during allocation before the method returns - /// A handle to the block of memory - /// - /// - public static IMemoryHandle SafeAlloc(int elements, bool zero = false) where T: unmanaged - { - if (elements < 0) - { - throw new ArgumentException("Number of elements must be a positive integer", nameof(elements)); - } - - //If the element count is larger than max pool size, alloc from shared heap - if (elements > MAX_UNSAFE_POOL_SIZE) - { - //Alloc from shared heap - return Shared.Alloc(elements, zero); - } - else - { - //Get temp buffer from shared buffer pool - return new VnTempBuffer(elements, zero); - } - } - - #endregion - } -} \ No newline at end of file diff --git a/Utils/src/Memory/MemoryHandle.cs b/Utils/src/Memory/MemoryHandle.cs deleted file mode 100644 index a09edea..0000000 --- a/Utils/src/Memory/MemoryHandle.cs +++ /dev/null @@ -1,237 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: MemoryHandle.cs -* -* MemoryHandle.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.Buffers; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; - -using Microsoft.Win32.SafeHandles; - -using VNLib.Utils.Extensions; - -namespace VNLib.Utils.Memory -{ - /// - /// Provides a wrapper for using umanged memory handles from an assigned for types - /// - /// - /// Handles are configured to address blocks larger than 2GB, - /// so some properties may raise exceptions if large blocks are used. - /// - public sealed class MemoryHandle : SafeHandleZeroOrMinusOneIsInvalid, IMemoryHandle, IEquatable> where T : unmanaged - { - /// - /// New * pointing to the base of the allocated block - /// - /// - public unsafe T* Base - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => GetOffset(0); - } - /// - /// New pointing to the base of the allocated block - /// - /// - public unsafe IntPtr BasePtr - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => (IntPtr)GetOffset(0); - } - /// - /// Gets a span over the entire allocated block - /// - /// A over the internal data - /// - /// - public unsafe Span Span - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - this.ThrowIfClosed(); - return _length == 0 ? Span.Empty : new Span(Base, IntLength); - } - } - - private readonly bool ZeroMemory; - private readonly IUnmangedHeap Heap; - private ulong _length; - - /// - /// Number of elements allocated to the current instance - /// - public ulong Length - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _length; - } - /// - /// Number of elements in the memory block casted to an integer - /// - /// - public int IntLength - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => checked((int)_length); - } - - /// - /// Number of bytes allocated to the current instance - /// - /// - public unsafe ulong ByteLength - { - //Check for overflows when converting to bytes (should run out of memory before this is an issue, but just incase) - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => checked(_length * (UInt64)sizeof(T)); - } - - /// - /// Creates a new memory handle, for which is holds ownership, and allocates the number of elements specified on the heap. - /// - /// The heap to allocate/deallocate memory from - /// Number of elements to allocate - /// Zero all memory during allocations from heap - /// The initial block of allocated memory to wrap - internal MemoryHandle(IUnmangedHeap heap, IntPtr initial, ulong elements, bool zero) : base(true) - { - //Set element size (always allocate at least 1 object) - _length = elements; - ZeroMemory = zero; - //assign heap ref - Heap = heap; - handle = initial; - } - - /// - /// Resizes the current handle on the heap - /// - /// Positive number of elemnts the current handle should referrence - /// - /// - /// - public unsafe void Resize(ulong elements) - { - this.ThrowIfClosed(); - //Update size (should never be less than inital size) - _length = elements; - //Re-alloc (Zero if required) - try - { - Heap.Resize(ref handle, Length, (ulong)sizeof(T), ZeroMemory); - } - //Catch the disposed exception so we can invalidate the current ptr - catch (ObjectDisposedException) - { - base.handle = IntPtr.Zero; - //Set as invalid so release does not get called - base.SetHandleAsInvalid(); - //Propagate the exception - throw; - } - } - /// - /// Gets an offset pointer from the base postion to the number of bytes specified. Performs bounds checks - /// - /// Number of elements of type to offset - /// - /// - /// pointer to the memory offset specified - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe T* GetOffset(ulong elements) - { - if (elements >= _length) - { - throw new ArgumentOutOfRangeException(nameof(elements), "Element offset cannot be larger than allocated size"); - } - this.ThrowIfClosed(); - //Get ptr and offset it - T* bs = ((T*)handle) + elements; - return bs; - } - - /// - /// - /// - public unsafe MemoryHandle Pin(int elementIndex) - { - //Get ptr and guard checks before adding the referrence - T* ptr = GetOffset((ulong)elementIndex); - - bool addRef = false; - //use the pinned field as success val - DangerousAddRef(ref addRef); - //Create a new system.buffers memory handle from the offset ptr address - return !addRef - ? throw new ObjectDisposedException("Failed to increase referrence count on the memory handle because it was released") - : new MemoryHandle(ptr, pinnable: this); - } - - /// - /// - public void Unpin() - { - //Dec count on release - DangerousRelease(); - } - - - /// - protected override bool ReleaseHandle() - { - //Return result of free - return Heap.Free(ref handle); - } - - - - /// - /// Determines if the memory blocks are equal by comparing their base addresses. - /// - /// to compare - /// true if the block of memory is the same, false if the handle's size does not - /// match or the base addresses do not match even if they point to an overlapping address space - /// - public bool Equals(MemoryHandle other) - { - this.ThrowIfClosed(); - other.ThrowIfClosed(); - return _length == other._length && handle == other.handle; - } - /// - public override bool Equals(object obj) => obj is MemoryHandle oHandle && Equals(oHandle); - /// - public override int GetHashCode() => base.GetHashCode(); - - - /// - public static implicit operator Span(MemoryHandle handle) - { - //If the handle is invalid or closed return an empty span - return handle.IsClosed || handle.IsInvalid || handle._length == 0 ? Span.Empty : handle.Span; - } - } -} \ No newline at end of file diff --git a/Utils/src/Memory/PrivateBuffersMemoryPool.cs b/Utils/src/Memory/PrivateBuffersMemoryPool.cs deleted file mode 100644 index 1e85207..0000000 --- a/Utils/src/Memory/PrivateBuffersMemoryPool.cs +++ /dev/null @@ -1,67 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: PrivateBuffersMemoryPool.cs -* -* PrivateBuffersMemoryPool.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.Buffers; - -namespace VNLib.Utils.Memory -{ - /// - /// Provides a wrapper for using unmanged s - /// - /// Unamanged memory type to provide data memory instances from - public sealed class PrivateBuffersMemoryPool : MemoryPool where T : unmanaged - { - private readonly IUnmangedHeap Heap; - - internal PrivateBuffersMemoryPool(IUnmangedHeap heap):base() - { - this.Heap = heap; - } - /// - public override int MaxBufferSize => int.MaxValue; - /// - /// - /// - /// - public override IMemoryOwner Rent(int minBufferSize = 0) => new SysBufferMemoryManager(Heap, (uint)minBufferSize, false); - - /// - /// Allocates a new of a different data type from the pool - /// - /// The unmanaged data type to allocate for - /// Minumum size of the buffer - /// The memory owner of a different data type - public IMemoryOwner Rent(int minBufferSize = 0) where TDifType : unmanaged - { - return new SysBufferMemoryManager(Heap, (uint)minBufferSize, false); - } - /// - protected override void Dispose(bool disposing) - { - //Dispose the heap - Heap.Dispose(); - } - } -} diff --git a/Utils/src/Memory/PrivateHeap.cs b/Utils/src/Memory/PrivateHeap.cs deleted file mode 100644 index 5d97506..0000000 --- a/Utils/src/Memory/PrivateHeap.cs +++ /dev/null @@ -1,184 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: PrivateHeap.cs -* -* PrivateHeap.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.Diagnostics; -using System.Runtime.Versioning; -using System.Runtime.InteropServices; - -using DWORD = System.Int64; -using SIZE_T = System.UInt64; -using LPVOID = System.IntPtr; - -namespace VNLib.Utils.Memory -{ - /// - /// - /// Provides a win32 private heap managed wrapper class - /// - /// - /// - /// implements and tracks allocated blocks by its - /// referrence counter. Allocations increment the count, and free's decrement the count, so the heap may - /// be disposed safely - /// - [ComVisible(false)] - [SupportedOSPlatform("Windows")] - public sealed class PrivateHeap : UnmanagedHeapBase - { - private const string KERNEL_DLL = "Kernel32"; - - #region Extern - //Heap flags - public const DWORD HEAP_NO_FLAGS = 0x00; - public const DWORD HEAP_GENERATE_EXCEPTIONS = 0x04; - public const DWORD HEAP_NO_SERIALIZE = 0x01; - public const DWORD HEAP_REALLOC_IN_PLACE_ONLY = 0x10; - public const DWORD HEAP_ZERO_MEMORY = 0x08; - - [DllImport(KERNEL_DLL, SetLastError = true, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - private static extern LPVOID HeapAlloc(IntPtr hHeap, DWORD flags, SIZE_T dwBytes); - [DllImport(KERNEL_DLL, SetLastError = true, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - private static extern LPVOID HeapReAlloc(IntPtr hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes); - [DllImport(KERNEL_DLL, SetLastError = true, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool HeapFree(IntPtr hHeap, DWORD dwFlags, LPVOID lpMem); - - [DllImport(KERNEL_DLL, SetLastError = true, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - private static extern LPVOID HeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize); - [DllImport(KERNEL_DLL, SetLastError = true, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool HeapDestroy(IntPtr hHeap); - [DllImport(KERNEL_DLL, SetLastError = true, ExactSpelling = true)] - [return: MarshalAs(UnmanagedType.Bool)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - private static extern bool HeapValidate(IntPtr hHeap, DWORD dwFlags, LPVOID lpMem); - [DllImport(KERNEL_DLL, SetLastError = true, ExactSpelling = true)] - [return: MarshalAs(UnmanagedType.U8)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - private static extern SIZE_T HeapSize(IntPtr hHeap, DWORD flags, LPVOID lpMem); - - #endregion - - /// - /// Create a new with the specified sizes and flags - /// - /// Intial size of the heap - /// Maximum size allowed for the heap (disabled = 0, default) - /// Defalt heap flags to set globally for all blocks allocated by the heap (default = 0) - public static PrivateHeap Create(SIZE_T initialSize, SIZE_T maxHeapSize = 0, DWORD flags = HEAP_NO_FLAGS) - { - //Call create, throw exception if the heap falled to allocate - IntPtr heapHandle = HeapCreate(flags, initialSize, maxHeapSize); - if (heapHandle == IntPtr.Zero) - { - throw new NativeMemoryException("Heap could not be created"); - } -#if TRACE - Trace.WriteLine($"Win32 private heap {heapHandle:x} created"); -#endif - //Heap has been created so we can wrap it - return new(heapHandle); - } - /// - /// LIFETIME WARNING. Consumes a valid win32 handle and will manage it's lifetime once constructed. - /// Locking and memory blocks will attempt to be allocated from this heap handle. - /// - /// An open and valid handle to a win32 private heap - /// A wrapper around the specified heap - public static PrivateHeap ConsumeExisting(IntPtr win32HeapHandle) => new (win32HeapHandle); - - private PrivateHeap(IntPtr heapPtr) : base(false, true) => handle = heapPtr; - - /// - /// Retrieves the size of a memory block allocated from the current heap. - /// - /// The pointer to a block of memory to get the size of - /// The size of the block of memory, (SIZE_T)-1 if the operation fails - public SIZE_T HeapSize(ref LPVOID block) => HeapSize(handle, HEAP_NO_FLAGS, block); - - /// - /// Validates the specified block of memory within the current heap instance. This function will block hte - /// - /// Pointer to the block of memory to validate - /// True if the block is valid, false otherwise - public bool Validate(ref LPVOID block) - { - bool result; - //Lock the heap before validating - HeapLock.Wait(); - //validate the block on the current heap - result = HeapValidate(handle, HEAP_NO_FLAGS, block); - //Unlock the heap - HeapLock.Release(); - return result; - - } - /// - /// Validates the current heap instance. The function scans all the memory blocks in the heap and verifies that the heap control structures maintained by - /// the heap manager are in a consistent state. - /// - /// If the specified heap or memory block is valid, the return value is nonzero. - /// This can be a consuming operation which will block all allocations - public bool Validate() - { - bool result; - //Lock the heap before validating - HeapLock.Wait(); - //validate the entire heap - result = HeapValidate(handle, HEAP_NO_FLAGS, IntPtr.Zero); - //Unlock the heap - HeapLock.Release(); - return result; - } - - /// - protected override bool ReleaseHandle() - { -#if TRACE - Trace.WriteLine($"Win32 private heap {handle:x} destroyed"); -#endif - return HeapDestroy(handle) && base.ReleaseHandle(); - } - /// - protected override sealed LPVOID AllocBlock(ulong elements, ulong size, bool zero) - { - ulong bytes = checked(elements * size); - return HeapAlloc(handle, zero ? HEAP_ZERO_MEMORY : HEAP_NO_FLAGS, bytes); - } - /// - protected override sealed bool FreeBlock(LPVOID block) => HeapFree(handle, HEAP_NO_FLAGS, block); - /// - protected override sealed LPVOID ReAllocBlock(LPVOID block, ulong elements, ulong size, bool zero) - { - ulong bytes = checked(elements * size); - return HeapReAlloc(handle, zero ? HEAP_ZERO_MEMORY : HEAP_NO_FLAGS, block, bytes); - } - } -} \ No newline at end of file diff --git a/Utils/src/Memory/PrivateString.cs b/Utils/src/Memory/PrivateString.cs deleted file mode 100644 index cd3b1f6..0000000 --- a/Utils/src/Memory/PrivateString.cs +++ /dev/null @@ -1,185 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: PrivateString.cs -* -* PrivateString.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.Diagnostics.CodeAnalysis; - -namespace VNLib.Utils.Memory -{ - /// - /// Provides a wrapper class that will have unsafe access to the memory of - /// the specified provided during object creation. - /// - /// The value of the memory the protected string points to is undefined when the instance is disposed - public class PrivateString : PrivateStringManager, IEquatable, IEquatable, ICloneable - { - protected string StrRef => base[0]!; - private readonly bool OwnsReferrence; - - /// - /// Creates a new over the specified string and the memory it points to. - /// - /// The instance pointing to the memory to protect - /// Does the current instance "own" the memory the data parameter points to - /// You should no longer reference the input string directly - public PrivateString(string data, bool ownsReferrence = true) : base(1) - { - //Create a private string manager to store referrence to string - base[0] = data ?? throw new ArgumentNullException(nameof(data)); - OwnsReferrence = ownsReferrence; - } - - //Create private string from a string - public static explicit operator PrivateString?(string? data) - { - //Allow passing null strings during implicit casting - return data == null ? null : new(data); - } - - public static PrivateString? ToPrivateString(string? value) - { - return value == null ? null : new PrivateString(value, true); - } - - //Cast to string - public static explicit operator string (PrivateString str) - { - //Check if disposed, or return the string - str.Check(); - return str.StrRef; - } - - public static implicit operator ReadOnlySpan(PrivateString str) - { - return str.Disposed ? Span.Empty : str.StrRef.AsSpan(); - } - - /// - /// Gets the value of the internal string as a - /// - /// The referrence to the internal string - /// - public ReadOnlySpan ToReadOnlySpan() - { - Check(); - return StrRef.AsSpan(); - } - - /// - public bool Equals(string? other) - { - Check(); - return StrRef.Equals(other); - } - /// - public bool Equals(PrivateString? other) - { - Check(); - return other != null && StrRef.Equals(other.StrRef); - } - /// - public override bool Equals(object? other) - { - Check(); - return other is PrivateString otherRef && StrRef.Equals(otherRef); - } - /// - public bool Equals(ReadOnlySpan other) - { - Check(); - return StrRef.AsSpan().SequenceEqual(other); - } - /// - /// Creates a deep copy of the internal string and returns that copy - /// - /// A deep copy of the internal string - public override string ToString() - { - Check(); - return new(StrRef.AsSpan()); - } - /// - /// String length - /// - /// - public int Length - { - get - { - Check(); - return StrRef.Length; - } - } - /// - /// Indicates whether the underlying string is null or an empty string ("") - /// - /// - /// True if the parameter is null, or an empty string (""). False otherwise - public static bool IsNullOrEmpty([NotNullWhen(false)] PrivateString? ps) => ps == null|| ps.Length == 0; - - /// - /// The hashcode of the underlying string - /// - /// - public override int GetHashCode() - { - Check(); - return StrRef.GetHashCode(); - } - - /// - /// Creates a new deep copy of the current instance that is an independent - /// - /// The new instance - /// - public override object Clone() - { - Check(); - //Copy all contents of string to another reference - string clone = new (StrRef.AsSpan()); - //return a new private string - return new PrivateString(clone, true); - } - - /// - protected override void Free() - { - Erase(); - } - - /// - /// Erases the contents of the internal CLR string - /// - public void Erase() - { - //Only dispose the instance if we own the memory - if (OwnsReferrence && !Disposed) - { - base.Free(); - } - } - - - } -} \ No newline at end of file diff --git a/Utils/src/Memory/PrivateStringManager.cs b/Utils/src/Memory/PrivateStringManager.cs deleted file mode 100644 index 9ed8f5f..0000000 --- a/Utils/src/Memory/PrivateStringManager.cs +++ /dev/null @@ -1,117 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: PrivateStringManager.cs -* -* PrivateStringManager.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; - - -namespace VNLib.Utils.Memory -{ - /// - /// When inherited by a class, provides a safe string storage that zeros a CLR string memory on disposal - /// - public class PrivateStringManager : VnDisposeable, ICloneable - { - /// - /// Strings to be cleared when exiting - /// - private readonly string?[] ProtectedElements; - /// - /// Gets or sets a string referrence into the protected elements store - /// - /// - /// - /// - /// - /// - /// Referrence to string associated with the index - protected string? this[int index] - { - get - { - Check(); - return ProtectedElements[index]; - } - set - { - Check(); - //Check to see if the string has been interned - if (!string.IsNullOrEmpty(value) && string.IsInterned(value) != null) - { - throw new ArgumentException($"The specified string has been CLR interned and cannot be stored in {nameof(PrivateStringManager)}"); - } - //Clear the old value before setting the new one - if (!string.IsNullOrEmpty(ProtectedElements[index])) - { - Memory.UnsafeZeroMemory(ProtectedElements[index]); - } - //set new value - ProtectedElements[index] = value; - } - } - /// - /// Create a new instance with fixed array size - /// - /// Number of elements to protect - public PrivateStringManager(int elements) - { - //Allocate the string array - ProtectedElements = new string[elements]; - } - /// - protected override void Free() - { - //Zero all strings specified - for (int i = 0; i < ProtectedElements.Length; i++) - { - if (!string.IsNullOrEmpty(ProtectedElements[i])) - { - //Zero the string memory - Memory.UnsafeZeroMemory(ProtectedElements[i]); - //Set to null - ProtectedElements[i] = null; - } - } - } - - /// - /// Creates a deep copy for a new independent - /// - /// A new independent instance - /// Be careful duplicating large instances, and make sure clones are properly disposed if necessary - /// - public virtual object Clone() - { - Check(); - PrivateStringManager other = new (ProtectedElements.Length); - //Copy all strings to the other instance - for(int i = 0; i < ProtectedElements.Length; i++) - { - //Copy all strings and store their copies in the new array - other.ProtectedElements[i] = this.ProtectedElements[i].AsSpan().ToString(); - } - //return the new copy - return other; - } - } -} diff --git a/Utils/src/Memory/ProcessHeap.cs b/Utils/src/Memory/ProcessHeap.cs deleted file mode 100644 index 4f06d52..0000000 --- a/Utils/src/Memory/ProcessHeap.cs +++ /dev/null @@ -1,82 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: ProcessHeap.cs -* -* ProcessHeap.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.Diagnostics; -using System.Runtime.InteropServices; - -namespace VNLib.Utils.Memory -{ - /// - /// Provides a wrapper for the virtualalloc - /// global heap methods - /// - [ComVisible(false)] - public unsafe class ProcessHeap : VnDisposeable, IUnmangedHeap - { - /// - /// Initalizes a new global (cross platform) process heap - /// - public ProcessHeap() - { -#if TRACE - Trace.WriteLine($"Default heap instnace created {GetHashCode():x}"); -#endif - } - - /// - /// - /// - public IntPtr Alloc(ulong elements, ulong size, bool zero) - { - return zero - ? (IntPtr)NativeMemory.AllocZeroed((nuint)elements, (nuint)size) - : (IntPtr)NativeMemory.Alloc((nuint)elements, (nuint)size); - } - /// - public bool Free(ref IntPtr block) - { - //Free native mem from ptr - NativeMemory.Free(block.ToPointer()); - block = IntPtr.Zero; - return true; - } - /// - protected override void Free() - { -#if TRACE - Trace.WriteLine($"Default heap instnace disposed {GetHashCode():x}"); -#endif - } - /// - /// - /// - public void Resize(ref IntPtr block, ulong elements, ulong size, bool zero) - { - nuint bytes = checked((nuint)(elements * size)); - IntPtr old = block; - block = (IntPtr)NativeMemory.Realloc(old.ToPointer(), bytes); - } - } -} diff --git a/Utils/src/Memory/RpMallocPrivateHeap.cs b/Utils/src/Memory/RpMallocPrivateHeap.cs deleted file mode 100644 index 70c8a7f..0000000 --- a/Utils/src/Memory/RpMallocPrivateHeap.cs +++ /dev/null @@ -1,279 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: RpMallocPrivateHeap.cs -* -* RpMallocPrivateHeap.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.Buffers; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; - -using size_t = System.UInt64; -using LPVOID = System.IntPtr; -using LPHEAPHANDLE = System.IntPtr; - -namespace VNLib.Utils.Memory -{ - /// - /// A wrapper class for cross platform RpMalloc implementation. - /// - [ComVisible(false)] - public sealed class RpMallocPrivateHeap : UnmanagedHeapBase - { - const string DLL_NAME = "rpmalloc"; - - #region statics - [DllImport(DLL_NAME, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] - static extern int rpmalloc_initialize(); - [DllImport(DLL_NAME, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] - static extern void rpmalloc_finalize(); - - //Heap api - [DllImport(DLL_NAME, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] - static extern LPHEAPHANDLE rpmalloc_heap_acquire(); - [DllImport(DLL_NAME, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] - static extern void rpmalloc_heap_release(LPHEAPHANDLE heap); - [DllImport(DLL_NAME, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] - static extern LPVOID rpmalloc_heap_alloc(LPHEAPHANDLE heap, size_t size); - [DllImport(DLL_NAME, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] - static extern LPVOID rpmalloc_heap_aligned_alloc(LPHEAPHANDLE heap, size_t alignment, size_t size); - [DllImport(DLL_NAME, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] - static extern LPVOID rpmalloc_heap_calloc(LPHEAPHANDLE heap, size_t num, size_t size); - [DllImport(DLL_NAME, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] - static extern LPVOID rpmalloc_heap_aligned_calloc(LPHEAPHANDLE heap, size_t alignment, size_t num, size_t size); - [DllImport(DLL_NAME, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] - static extern LPVOID rpmalloc_heap_realloc(LPHEAPHANDLE heap, LPVOID ptr, size_t size, nuint flags); - [DllImport(DLL_NAME, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] - static extern LPVOID rpmalloc_heap_aligned_realloc(LPHEAPHANDLE heap, LPVOID ptr, size_t alignment, size_t size, nuint flags); - [DllImport(DLL_NAME, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] - static extern void rpmalloc_heap_free(LPHEAPHANDLE heap, LPVOID ptr); - [DllImport(DLL_NAME, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] - static extern void rpmalloc_heap_free_all(LPHEAPHANDLE heap); - [DllImport(DLL_NAME, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] - static extern void rpmalloc_heap_thread_set_current(LPHEAPHANDLE heap); - - [DllImport(DLL_NAME, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] - static extern void rpmalloc_thread_initialize(); - [DllImport(DLL_NAME, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] - static extern int rpmalloc_is_thread_initialized(); - [DllImport(DLL_NAME, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] - static extern void rpmalloc_thread_finalize(int release_caches); - [DllImport(DLL_NAME, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] - static extern LPVOID rpmalloc(size_t size); - [DllImport(DLL_NAME, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] - static extern LPVOID rpcalloc(size_t num, size_t size); - [DllImport(DLL_NAME, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] - static extern LPVOID rprealloc(LPVOID ptr, size_t size); - [DllImport(DLL_NAME, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] - static extern void rpfree(LPVOID ptr); - - #endregion - - private class RpMallocGlobalHeap : IUnmangedHeap - { - IntPtr IUnmangedHeap.Alloc(ulong elements, ulong size, bool zero) - { - return RpMalloc(elements, (nuint)size, zero); - } - - //Global heap does not need to be disposed - void IDisposable.Dispose() - { } - - bool IUnmangedHeap.Free(ref IntPtr block) - { - //Free the block - RpFree(ref block); - return true; - } - - void IUnmangedHeap.Resize(ref IntPtr block, ulong elements, ulong size, bool zero) - { - //Try to resize the block - IntPtr resize = RpRealloc(block, elements, (nuint)size); - - if (resize == IntPtr.Zero) - { - throw new NativeMemoryOutOfMemoryException("Failed to resize the block"); - } - //assign ptr - block = resize; - } - } - - /// - /// - /// A API for the RPMalloc library if loaded. - /// - /// - /// This heap is thread safe and may be converted to a - /// infinitley and disposed safely. - /// - /// - /// If the native library is not loaded, calls to this API will throw a . - /// - /// - public static IUnmangedHeap GlobalHeap { get; } = new RpMallocGlobalHeap(); - - /// - /// - /// Initializes RpMalloc for the current thread and alloctes a block of memory - /// - /// - /// The number of elements to allocate - /// The number of bytes per element type (aligment) - /// Zero the block of memory before returning - /// A pointer to the block, (zero if failed) - public static LPVOID RpMalloc(size_t elements, nuint size, bool zero) - { - //See if the current thread has been initialized - if (rpmalloc_is_thread_initialized() == 0) - { - //Initialize the current thread - rpmalloc_thread_initialize(); - } - //Alloc block - LPVOID block; - if (zero) - { - block = rpcalloc(elements, size); - } - else - { - //Calculate the block size - ulong blockSize = checked(elements * size); - block = rpmalloc(blockSize); - } - return block; - } - - /// - /// Frees a block of memory allocated by RpMalloc - /// - /// A ref to the pointer of the block to free - public static void RpFree(ref LPVOID block) - { - if (block != IntPtr.Zero) - { - rpfree(block); - block = IntPtr.Zero; - } - } - - /// - /// Attempts to re-allocate the specified block on the global heap - /// - /// A pointer to a previously allocated block of memory - /// The number of elements in the block - /// The number of bytes in the element - /// A pointer to the new block if the reallocation succeeded, null if the resize failed - /// - /// - public static LPVOID RpRealloc(LPVOID block, size_t elements, nuint size) - { - if(block == IntPtr.Zero) - { - throw new ArgumentException("The supplied block is not valid", nameof(block)); - } - //Calc new block size - size_t blockSize = checked(elements * size); - return rprealloc(block, blockSize); - } - - #region instance - - /// - /// Initializes a new RpMalloc first class heap to allocate memory blocks from - /// - /// A global flag to zero all blocks of memory allocated - /// - public RpMallocPrivateHeap(bool zeroAll):base(zeroAll, true) - { - //Alloc the heap - handle = rpmalloc_heap_acquire(); - if(IsInvalid) - { - throw new NativeMemoryException("Failed to aquire a new heap"); - } -#if TRACE - Trace.WriteLine($"RPMalloc heap {handle:x} created"); -#endif - } - /// - protected override bool ReleaseHandle() - { -#if TRACE - Trace.WriteLine($"RPMalloc heap {handle:x} destroyed"); -#endif - //Release all heap memory - rpmalloc_heap_free_all(handle); - //Destroy the heap - rpmalloc_heap_release(handle); - //Release base - return base.ReleaseHandle(); - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected sealed override LPVOID AllocBlock(ulong elements, ulong size, bool zero) - { - //Alloc or calloc and initalize - return zero ? rpmalloc_heap_calloc(handle, elements, size) : rpmalloc_heap_alloc(handle, checked(size * elements)); - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected sealed override bool FreeBlock(LPVOID block) - { - //Free block - rpmalloc_heap_free(handle, block); - return true; - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected sealed override LPVOID ReAllocBlock(LPVOID block, ulong elements, ulong size, bool zero) - { - //Realloc - return rpmalloc_heap_realloc(handle, block, checked(elements * size), 0); - } - #endregion - } -} diff --git a/Utils/src/Memory/SubSequence.cs b/Utils/src/Memory/SubSequence.cs deleted file mode 100644 index 3800fb5..0000000 --- a/Utils/src/Memory/SubSequence.cs +++ /dev/null @@ -1,113 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: SubSequence.cs -* -* SubSequence.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 VNLib.Utils.Extensions; - -namespace VNLib.Utils.Memory -{ - /// - /// Represents a subset (or window) of data within a - /// - /// The unmanaged type to wrap - public readonly struct SubSequence : IEquatable> where T: unmanaged - { - private readonly MemoryHandle _handle; - /// - /// The number of elements in the current window - /// - public readonly int Size { get; } - - /// - /// Creates a new to the handle to get a window of the block - /// - /// - /// - /// -#if TARGET_64_BIT - public SubSequence(MemoryHandle block, ulong offset, int size) -#else - public SubSequence(MemoryHandle block, int offset, int size) -#endif - { - _offset = offset; - Size = size >= 0 ? size : throw new ArgumentOutOfRangeException(nameof(size)); - _handle = block ?? throw new ArgumentNullException(nameof(block)); - } - - -#if TARGET_64_BIT - private readonly ulong _offset; -#else - private readonly int _offset; -#endif - /// - /// Gets a that is offset from the base of the handle - /// - /// - -#if TARGET_64_BIT - public readonly Span Span => Size > 0 ? _handle.GetOffsetSpan(_offset, Size) : Span.Empty; -#else - public readonly Span Span => Size > 0 ? _handle.Span.Slice(_offset, Size) : Span.Empty; -#endif - - /// - /// Slices the current sequence into a smaller - /// - /// The relative offset from the current window offset - /// The size of the block - /// A of the current sequence - public readonly SubSequence Slice(uint offset, int size) => new (_handle, _offset + checked((int)offset), size); - - /// - /// Returns the signed 32-bit hashcode - /// - /// A signed 32-bit integer that represents the hashcode for the current instance - /// - public readonly override int GetHashCode() => _handle.GetHashCode() + _offset.GetHashCode(); - - /// - public readonly bool Equals(SubSequence other) => Span.SequenceEqual(other.Span); - - /// - public readonly override bool Equals(object? obj) => obj is SubSequence other && Equals(other); - - /// - /// Determines if two are equal - /// - /// - /// - /// True if the sequences are equal, false otherwise - public static bool operator ==(SubSequence left, SubSequence right) => left.Equals(right); - /// - /// Determines if two are not equal - /// - /// - /// - /// True if the sequences are not equal, false otherwise - public static bool operator !=(SubSequence left, SubSequence right) => !left.Equals(right); - } -} \ No newline at end of file diff --git a/Utils/src/Memory/SysBufferMemoryManager.cs b/Utils/src/Memory/SysBufferMemoryManager.cs deleted file mode 100644 index 040467f..0000000 --- a/Utils/src/Memory/SysBufferMemoryManager.cs +++ /dev/null @@ -1,102 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: SysBufferMemoryManager.cs -* -* SysBufferMemoryManager.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.Buffers; - -using VNLib.Utils.Extensions; - -namespace VNLib.Utils.Memory -{ - /// - /// Provides an unmanaged System.Buffers integration with zero-cost pinning. Uses - /// as a memory provider which implements a - /// - /// Unmanaged memory type - public sealed class SysBufferMemoryManager : MemoryManager where T :unmanaged - { - private readonly IMemoryHandle BackingMemory; - private readonly bool _ownsHandle; - - /// - /// Consumes an exisitng to provide wrappers. - /// The handle should no longer be referrenced directly - /// - /// The existing handle to consume - /// A value that indicates if the memory manager owns the handle reference - internal SysBufferMemoryManager(IMemoryHandle existingHandle, bool ownsHandle) - { - BackingMemory = existingHandle; - _ownsHandle = ownsHandle; - } - - /// - /// Allocates a fized size buffer from the specified unmanaged - /// - /// The heap to perform allocations from - /// The number of elements to allocate - /// Zero allocations - public SysBufferMemoryManager(IUnmangedHeap heap, ulong elements, bool zero) - { - BackingMemory = heap.Alloc(elements, zero); - _ownsHandle = true; - } - - /// - protected override bool TryGetArray(out ArraySegment segment) - { - //Always false since no array is available - segment = default; - return false; - } - - /// - /// - /// - public override Span GetSpan() => BackingMemory.Span; - - /// - /// - /// - /// - /// - public unsafe override MemoryHandle Pin(int elementIndex = 0) - { - return BackingMemory.Pin(elementIndex); - } - - /// - public override void Unpin() - {} - - /// - protected override void Dispose(bool disposing) - { - if (_ownsHandle) - { - BackingMemory.Dispose(); - } - } - } -} diff --git a/Utils/src/Memory/UnmanagedHeapBase.cs b/Utils/src/Memory/UnmanagedHeapBase.cs deleted file mode 100644 index 5c92aff..0000000 --- a/Utils/src/Memory/UnmanagedHeapBase.cs +++ /dev/null @@ -1,185 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: UnmanagedHeapBase.cs -* -* UnmanagedHeapBase.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.Threading; -using System.Runtime.InteropServices; - -using Microsoft.Win32.SafeHandles; - -using size_t = System.UInt64; -using LPVOID = System.IntPtr; - -namespace VNLib.Utils.Memory -{ - /// - /// Provides a synchronized base methods for accessing unmanaged memory. Implements - /// for safe disposal of heaps - /// - public abstract class UnmanagedHeapBase : SafeHandleZeroOrMinusOneIsInvalid, IUnmangedHeap - { - /// - /// The heap synchronization handle - /// - protected readonly SemaphoreSlim HeapLock; - /// - /// The global heap zero flag - /// - protected readonly bool GlobalZero; - - /// - /// Initalizes the unmanaged heap base class (init synchronization handle) - /// - /// A global flag to zero all blocks of memory during allocation - /// A flag that indicates if the handle is owned by the instance - protected UnmanagedHeapBase(bool globalZero, bool ownsHandle) : base(ownsHandle) - { - HeapLock = new(1, 1); - GlobalZero = globalZero; - } - - /// - ///Increments the handle count - /// - /// - public LPVOID Alloc(size_t elements, size_t size, bool zero) - { - //Force zero if global flag is set - zero |= GlobalZero; - bool handleCountIncremented = false; - //Increment handle count to prevent premature release - DangerousAddRef(ref handleCountIncremented); - //Failed to increment ref count, class has been disposed - if (!handleCountIncremented) - { - throw new ObjectDisposedException("The handle has been released"); - } - try - { - //wait for lock - HeapLock.Wait(); - //Alloc block - LPVOID block = AllocBlock(elements, size, zero); - //release lock - HeapLock.Release(); - //Check if block was allocated - return block != IntPtr.Zero ? block : throw new NativeMemoryOutOfMemoryException("Failed to allocate the requested block"); - } - catch - { - //Decrement handle count since allocation failed - DangerousRelease(); - throw; - } - } - /// - ///Decrements the handle count - public bool Free(ref LPVOID block) - { - bool result; - //If disposed, set the block handle to zero and exit to avoid raising exceptions during finalization - if (IsClosed || IsInvalid) - { - block = IntPtr.Zero; - return true; - } - //wait for lock - HeapLock.Wait(); - //Free block - result = FreeBlock(block); - //Release lock before releasing handle - HeapLock.Release(); - //Decrement handle count - DangerousRelease(); - //set block to invalid - block = IntPtr.Zero; - return result; - } - /// - /// - /// - public void Resize(ref LPVOID block, size_t elements, size_t size, bool zero) - { - //wait for lock - HeapLock.Wait(); - /* - * Realloc may return a null pointer if allocation fails - * so check the results and only assign the block pointer - * if the result is valid. Otherwise pointer block should - * be left untouched - */ - LPVOID newBlock = ReAllocBlock(block, elements, size, zero); - //release lock - HeapLock.Release(); - //Check block - if (newBlock == IntPtr.Zero) - { - throw new NativeMemoryOutOfMemoryException("The memory block could not be resized"); - } - //Set the new block - block = newBlock; - } - - /// - protected override bool ReleaseHandle() - { - HeapLock.Dispose(); - return true; - } - - /// - /// Allocates a block of memory from the heap - /// - /// The number of elements within the block - /// The size of the element type (in bytes) - /// A flag to zero the allocated block - /// A pointer to the allocated block - protected abstract LPVOID AllocBlock(size_t elements, size_t size, bool zero); - /// - /// Frees a previously allocated block of memory - /// - /// The block to free - protected abstract bool FreeBlock(LPVOID block); - /// - /// Resizes the previously allocated block of memory on the current heap - /// - /// The prevously allocated block - /// The new number of elements within the block - /// The size of the element type (in bytes) - /// A flag to indicate if the new region of the block should be zeroed - /// A pointer to the same block, but resized, null if the allocation falied - /// - /// Heap base relies on the block pointer to remain unchanged if the resize fails so the - /// block is still valid, and the return value is used to determine if the resize was successful - /// - protected abstract LPVOID ReAllocBlock(LPVOID block, size_t elements, size_t size, bool zero); - /// - public override int GetHashCode() => handle.GetHashCode(); - /// - public override bool Equals(object? obj) - { - return obj is UnmanagedHeapBase heap && !heap.IsInvalid && !heap.IsClosed && handle == heap.handle; - } - } -} diff --git a/Utils/src/Memory/UnsafeMemoryHandle.cs b/Utils/src/Memory/UnsafeMemoryHandle.cs deleted file mode 100644 index b05ad40..0000000 --- a/Utils/src/Memory/UnsafeMemoryHandle.cs +++ /dev/null @@ -1,231 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: UnsafeMemoryHandle.cs -* -* UnsafeMemoryHandle.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.Buffers; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; -using System.Diagnostics.CodeAnalysis; - -using VNLib.Utils.Extensions; - -namespace VNLib.Utils.Memory -{ - /// - /// Represents an unsafe handle to managed/unmanaged memory that should be used cautiously. - /// A referrence counter is not maintained. - /// - /// Unmanaged memory type - [StructLayout(LayoutKind.Sequential)] - public readonly struct UnsafeMemoryHandle : IMemoryHandle, IEquatable> where T : unmanaged - { - private enum HandleType - { - None, - Pool, - PrivateHeap - } - - private readonly T[]? _poolArr; - private readonly IntPtr _memoryPtr; - private readonly ArrayPool? _pool; - private readonly IUnmangedHeap? _heap; - private readonly HandleType _handleType; - private readonly int _length; - - /// - public readonly unsafe Span Span - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _handleType == HandleType.Pool ? _poolArr.AsSpan(0, IntLength) : new (_memoryPtr.ToPointer(), IntLength); - } - /// - public readonly int IntLength => _length; - /// - public readonly ulong Length => (ulong)_length; - - /// - /// Creates an empty - /// - public UnsafeMemoryHandle() - { - _pool = null; - _heap = null; - _poolArr = null; - _memoryPtr = IntPtr.Zero; - _handleType = HandleType.None; - _length = 0; - } - - /// - /// Inializes a new using the specified - /// - /// - /// The number of elements to store - /// Zero initial contents? - /// The explicit pool to alloc buffers from - /// - /// - /// - public unsafe UnsafeMemoryHandle(ArrayPool pool, int elements, bool zero) - { - if (elements < 0) - { - throw new ArgumentOutOfRangeException(nameof(elements)); - } - //Pool is required - _pool = pool ?? throw new ArgumentNullException(nameof(pool)); - //Rent the array from the pool and hold referrence to it - _poolArr = pool.Rent(elements, zero); - //Cant store ref to array becase GC can move it - _memoryPtr = IntPtr.Zero; - //Set pool handle type - _handleType = HandleType.Pool; - //No heap being loaded - _heap = null; - _length = elements; - } - - /// - /// Intializes a new for block of memory allocated from - /// an - /// - /// The heap the initial memory block belongs to - /// A pointer to the unmanaged memory block - /// The number of elements this block points to - internal UnsafeMemoryHandle(IUnmangedHeap heap, IntPtr initial, int elements) - { - _pool = null; - _poolArr = null; - _heap = heap; - _length = elements; - _memoryPtr = initial; - _handleType = HandleType.PrivateHeap; - } - - /// - /// Releases memory back to the pool or heap from which is was allocated. - /// - /// After this method is called, this handle points to invalid memory - public readonly void Dispose() - { - switch (_handleType) - { - case HandleType.Pool: - { - //Return array to pool - _pool!.Return(_poolArr!); - } - break; - case HandleType.PrivateHeap: - { - IntPtr unalloc = _memoryPtr; - //Free the unmanaged handle - _heap!.Free(ref unalloc); - } - break; - } - } - - /// - public readonly override int GetHashCode() => _handleType == HandleType.Pool ? _poolArr!.GetHashCode() : _memoryPtr.GetHashCode(); - /// - public readonly unsafe MemoryHandle Pin(int elementIndex) - { - //Guard - if (elementIndex < 0 || elementIndex >= IntLength) - { - throw new ArgumentOutOfRangeException(nameof(elementIndex)); - } - - if (_handleType == HandleType.Pool) - { - //Pin the array - GCHandle arrHandle = GCHandle.Alloc(_poolArr, GCHandleType.Pinned); - //Get array base address - void* basePtr = (void*)arrHandle.AddrOfPinnedObject(); - //Get element offset - void* indexOffet = Unsafe.Add(basePtr, elementIndex); - return new (indexOffet, arrHandle); - } - else - { - //Get offset pointer and pass self as pinnable argument, (nothing happens but support it) - void* basePtr = Unsafe.Add(_memoryPtr.ToPointer(), elementIndex); - //Unmanaged memory is always pinned, so no need to pass this as IPinnable, since it will cause a box - return new (basePtr); - } - } - /// - public readonly void Unpin() - { - //Nothing to do since gc handle takes care of array, and unmanaged pointers are not pinned - } - - /// - /// Determines if the other handle represents the same memory block as the - /// current handle. - /// - /// The other handle to test - /// True if the other handle points to the same block of memory as the current handle - public readonly bool Equals(UnsafeMemoryHandle other) - { - return _handleType == other._handleType && Length == other.Length && GetHashCode() == other.GetHashCode(); - } - - /// - /// Override for object equality operator, will cause boxing - /// for structures - /// - /// The other object to compare - /// - /// True if the passed object is of type - /// and uses the structure equality operator - /// false otherwise. - /// - public readonly override bool Equals([NotNullWhen(true)] object? obj) => obj is UnsafeMemoryHandle other && Equals(other); - - /// - /// Casts the handle to it's representation - /// - /// the handle to cast - public static implicit operator Span(in UnsafeMemoryHandle handle) => handle.Span; - - /// - /// Equality overload - /// - /// - /// - /// True if handles are equal, flase otherwise - public static bool operator ==(in UnsafeMemoryHandle left, in UnsafeMemoryHandle right) => left.Equals(right); - /// - /// Equality overload - /// - /// - /// - /// True if handles are equal, flase otherwise - public static bool operator !=(in UnsafeMemoryHandle left, in UnsafeMemoryHandle right) => !left.Equals(right); - - } -} \ No newline at end of file diff --git a/Utils/src/Memory/VnString.cs b/Utils/src/Memory/VnString.cs deleted file mode 100644 index 7fa0c5a..0000000 --- a/Utils/src/Memory/VnString.cs +++ /dev/null @@ -1,497 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: VnString.cs -* -* VnString.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.Text; -using System.Buffers; -using System.ComponentModel; -using System.Threading.Tasks; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; - -using VNLib.Utils.IO; -using VNLib.Utils.Extensions; - -namespace VNLib.Utils.Memory -{ - - /// - /// Provides an immutable character buffer stored on an unmanged heap. Contains handles to unmanged memory, and should be disposed - /// - [ComVisible(false)] - [ImmutableObject(true)] - public sealed class VnString : VnDisposeable, IEquatable, IEquatable, IEquatable, IComparable, IComparable - { - private readonly MemoryHandle? Handle; - - private readonly SubSequence _stringSequence; - - /// - /// The number of unicode characters the current instance can reference - /// - public int Length => _stringSequence.Size; - /// - /// Gets a value indicating if the current instance is empty - /// - public bool IsEmpty => Length == 0; - - private VnString(SubSequence sequence) - { - _stringSequence = sequence; - } - - private VnString( - MemoryHandle handle, -#if TARGET_64_BIT - ulong start, -#else - int start, -#endif - int length) - { - Handle = handle ?? throw new ArgumentNullException(nameof(handle)); - //get sequence - _stringSequence = handle.GetSubSequence(start, length); - } - - /// - /// Creates and empty , not particularly usefull, just and empty instance. - /// - public VnString() - { - //Default string sequence is empty and does not hold any memory - } - /// - /// Creates a new around a or a of data - /// - /// of data to replicate - /// - public VnString(ReadOnlySpan data) - { - //Create new handle with enough size (heap) - Handle = Memory.Shared.Alloc(data.Length); - //Copy - Memory.Copy(data, Handle, 0); - //Get subsequence over the whole copy of data - _stringSequence = Handle.GetSubSequence(0, data.Length); - } - /// - /// Allocates a temporary buffer to read data from the stream until the end of the stream is reached. - /// Decodes data from the user-specified encoding - /// - /// Active stream of data to decode to a string - /// to use for decoding - /// The size of the buffer to allocate during copying - /// The new instance - /// - /// - /// - /// - public static VnString FromStream(Stream stream, Encoding encoding, uint bufferSize) - { - //Make sure the stream is readable - if (!stream.CanRead) - { - throw new InvalidOperationException(); - } - //See if the stream is a vn memory stream - if (stream is VnMemoryStream vnms) - { - //Get the number of characters - int numChars = encoding.GetCharCount(vnms.AsSpan()); - //New handle - MemoryHandle charBuffer = Memory.Shared.Alloc(numChars); - try - { - //Write characters to character buffer - _ = encoding.GetChars(vnms.AsSpan(), charBuffer); - //Consume the new handle - return ConsumeHandle(charBuffer, 0, numChars); - } - catch - { - //If an error occured, dispose the buffer - charBuffer.Dispose(); - throw; - } - } - //Need to read from the stream old school with buffers - else - { - //Create a new char bufer that will expand dyanmically - MemoryHandle charBuffer = Memory.Shared.Alloc(bufferSize); - //Allocate a binary buffer - MemoryHandle binBuffer = Memory.Shared.Alloc(bufferSize); - try - { - int length = 0; - //span ref to bin buffer - Span buffer = binBuffer; - //Run in checked context for overflows - checked - { - do - { - //read - int read = stream.Read(buffer); - //guard - if (read <= 0) - { - break; - } - //Slice into only the read data - ReadOnlySpan readbytes = buffer[..read]; - //get num chars - int numChars = encoding.GetCharCount(readbytes); - //Guard for overflow - if (((ulong)(numChars + length)) >= int.MaxValue) - { - throw new OverflowException(); - } - //Re-alloc buffer - charBuffer.ResizeIfSmaller(length + numChars); - //Decode and update position - _= encoding.GetChars(readbytes, charBuffer.Span.Slice(length, numChars)); - //Update char count - length += numChars; - } while (true); - } - return ConsumeHandle(charBuffer, 0, length); - } - catch - { - //Free the memory allocated - charBuffer.Dispose(); - //We still want the exception to be propagated! - throw; - } - finally - { - //Dispose the binary buffer - binBuffer.Dispose(); - } - } - } - /// - /// Creates a new Vnstring from the buffer provided. This function "consumes" - /// a handle, meaning it now takes ownsership of the the memory it points to. - /// - /// The to consume - /// The offset from the begining of the buffer marking the begining of the string - /// The number of characters this string points to - /// The new - /// - public static VnString ConsumeHandle( - MemoryHandle handle, - -#if TARGET_64_BIT - ulong start, -#else - int start, -#endif - - int length) - { - if(length < 0) - { - throw new ArgumentOutOfRangeException(nameof(length)); - } - if((uint)length > handle.Length) - { - throw new ArgumentOutOfRangeException(nameof(length)); - } - return new VnString(handle, start, length); - } - /// - /// Asynchronously reads data from the specified stream and uses the specified encoding - /// to decode the binary data to a new heap character buffer. - /// - /// The stream to read data from - /// The encoding to use while decoding data - /// The to allocate buffers from - /// The size of the buffer to allocate - /// The new containing the data - /// - /// - public static async ValueTask FromStreamAsync(Stream stream, Encoding encoding, IUnmangedHeap heap, int bufferSize) - { - _ = stream ?? throw new ArgumentNullException(nameof(stream)); - _ = encoding ?? throw new ArgumentNullException(nameof(encoding)); - _ = heap ?? throw new ArgumentNullException(nameof(heap)); - - //Make sure the stream is readable - if (!stream.CanRead) - { - throw new IOException("The input stream is not readable"); - } - //See if the stream is a vn memory stream - if (stream is VnMemoryStream vnms) - { - //Get the number of characters - int numChars = encoding.GetCharCount(vnms.AsSpan()); - //New handle - MemoryHandle charBuffer = heap.Alloc(numChars); - try - { - //Write characters to character buffer - _ = encoding.GetChars(vnms.AsSpan(), charBuffer); - //Consume the new handle - return ConsumeHandle(charBuffer, 0, numChars); - } - catch - { - //If an error occured, dispose the buffer - charBuffer.Dispose(); - throw; - } - } - else - { - //Create a new char bufer starting with the buffer size - MemoryHandle charBuffer = heap.Alloc(bufferSize); - //Rent a temp binary buffer - IMemoryOwner binBuffer = heap.DirectAlloc(bufferSize); - try - { - int length = 0; - do - { - //read async - int read = await stream.ReadAsync(binBuffer.Memory); - //guard - if (read <= 0) - { - break; - } - //calculate the number of characters - int numChars = encoding.GetCharCount(binBuffer.Memory.Span[..read]); - //Guard for overflow - if (((ulong)(numChars + length)) >= int.MaxValue) - { - throw new OverflowException(); - } - //Re-alloc buffer - charBuffer.ResizeIfSmaller(length + numChars); - //Decode and update position - _ = encoding.GetChars(binBuffer.Memory.Span[..read], charBuffer.Span.Slice(length, numChars)); - //Update char count - length += numChars; - } while (true); - return ConsumeHandle(charBuffer, 0, length); - } - catch - { - //Free the memory allocated - charBuffer.Dispose(); - //We still want the exception to be propagated! - throw; - } - finally - { - //Dispose the binary buffer - binBuffer.Dispose(); - } - } - } - - /// - /// Gets the value of the character at the specified index - /// - /// The index of the character to get - /// The at the specified index within the buffer - /// - public char CharAt(int index) - { - //Check - Check(); - //Check bounds - return _stringSequence.Span[index]; - } - -#pragma warning disable IDE0057 // Use range operator - /// - /// Creates a that is a window within the current string, - /// the referrence points to the same memory as the first instnace. - /// - /// The index within the current string to begin the child string - /// The number of characters (or length) of the child string - /// The child - /// - /// Making substrings will reference the parents's underlying - /// and all children will be set in a disposed state when the parent instance is disposed - /// - /// - /// - public VnString Substring(int start, int count) - { - //Check - Check(); - //Check bounds - if (start < 0 || (start + count) >= Length) - { - throw new ArgumentOutOfRangeException(nameof(count)); - } - //get sub-sequence slice for the current string - SubSequence sub = _stringSequence.Slice((uint)start, count); - //Create new string with offsets pointing to same internal referrence - return new VnString(sub); - } - /// - /// Creates a that is a window within the current string, - /// the referrence points to the same memory as the first instnace. - /// - /// The index within the current string to begin the child string - /// The child - /// - /// Making substrings will reference the parents's underlying - /// and all children will be set in a disposed state when the parent instance is disposed - /// - /// - /// - public VnString Substring(int start) => Substring(start, (Length - start)); - public VnString this[Range range] - { - get - { - //get start - int start = range.Start.IsFromEnd ? Length - range.Start.Value : range.Start.Value; - //Get end - int end = range.End.IsFromEnd ? Length - range.End.Value : range.End.Value; - //Handle strings with no ending range - return (end >= start) ? Substring(start, (end - start)) : Substring(start); - } - } -#pragma warning restore IDE0057 // Use range operator - - /// - /// Gets a over the internal character buffer - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ReadOnlySpan AsSpan() - { - //Check - Check(); - return _stringSequence.Span; - } - - /// - /// Gets a copy of the internal buffer - /// - /// representation of internal data - /// - public override unsafe string ToString() - { - //Check - Check(); - //Create a new - return AsSpan().ToString(); - } - /// - /// Gets the value of the character at the specified index - /// - /// The index of the character to get - /// The at the specified index within the buffer - /// - public char this[int index] => CharAt(index); - - //Casting to a vnstring should be explicit so the caller doesnt misuse memory managment - public static explicit operator ReadOnlySpan(VnString? value) => Unsafe.IsNullRef(ref value) || value!.Disposed ? ReadOnlySpan.Empty : value.AsSpan(); - public static explicit operator VnString(string value) => new (value); - public static explicit operator VnString(ReadOnlySpan value) => new (value); - public static explicit operator VnString(char[] value) => new (value); - /// - public override bool Equals(object? obj) - { - if(obj == null) - { - return false; - } - return obj switch - { - VnString => Equals(obj as VnString), //Use operator overload - string => Equals(obj as string), //Use operator overload - char[] => Equals(obj as char[]), //Use operator overload - _ => false, - }; - } - /// - public bool Equals(VnString? other) => !ReferenceEquals(other, null) && Equals(other.AsSpan()); - /// - public bool Equals(VnString? other, StringComparison stringComparison) => !ReferenceEquals(other, null) && Equals(other.AsSpan(), stringComparison); - /// - public bool Equals(string? other) => Equals(other.AsSpan()); - /// - public bool Equals(string? other, StringComparison stringComparison) => Equals(other.AsSpan(), stringComparison); - /// - public bool Equals(char[]? other) => Equals(other.AsSpan()); - /// - public bool Equals(char[]? other, StringComparison stringComparison) => Equals(other.AsSpan(), stringComparison); - /// - public bool Equals(ReadOnlySpan other, StringComparison stringComparison = StringComparison.Ordinal) => Length == other.Length && AsSpan().Equals(other, stringComparison); - /// - public bool Equals(SubSequence other) => Length == other.Size && AsSpan().SequenceEqual(other.Span); - /// - public int CompareTo(string? other) => AsSpan().CompareTo(other, StringComparison.Ordinal); - /// - /// - public int CompareTo(VnString? other) - { - _ = other ?? throw new ArgumentNullException(nameof(other)); - return AsSpan().CompareTo(other.AsSpan(), StringComparison.Ordinal); - } - - /// - /// Gets a hashcode for the underyling string by using the .NET - /// method on the character representation of the data - /// - /// - /// - /// It is safe to compare hashcodes of to the class or - /// a character span etc - /// - /// - public override int GetHashCode() => string.GetHashCode(AsSpan()); - /// - protected override void Free() - { - //Dispose the handle if we own it (null if we do not have the parent handle) - Handle?.Dispose(); - } - - public static bool operator ==(VnString left, VnString right) => ReferenceEquals(left, null) ? ReferenceEquals(right, null) : left.Equals(right); - - public static bool operator !=(VnString left, VnString right) => !(left == right); - - public static bool operator <(VnString left, VnString right) => ReferenceEquals(left, null) ? !ReferenceEquals(right, null) : left.CompareTo(right) < 0; - - public static bool operator <=(VnString left, VnString right) => ReferenceEquals(left, null) || left.CompareTo(right) <= 0; - - public static bool operator >(VnString left, VnString right) => !ReferenceEquals(left, null) && left.CompareTo(right) > 0; - - public static bool operator >=(VnString left, VnString right) => ReferenceEquals(left, null) ? ReferenceEquals(right, null) : left.CompareTo(right) >= 0; - } -} \ No newline at end of file diff --git a/Utils/src/Memory/VnTable.cs b/Utils/src/Memory/VnTable.cs deleted file mode 100644 index 1d5c0a6..0000000 --- a/Utils/src/Memory/VnTable.cs +++ /dev/null @@ -1,213 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: VnTable.cs -* -* VnTable.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 VNLib.Utils.Extensions; - -namespace VNLib.Utils.Memory -{ - /// - /// Provides a Row-Major ordered table for use of storing value-types in umnaged heap memory - /// - /// - public sealed class VnTable : VnDisposeable, IIndexable where T : unmanaged - { - private readonly MemoryHandle? BufferHandle; - /// - /// A value that indicates if the table does not contain any values - /// - public bool Empty { get; } - /// - /// The number of rows in the table - /// - public int Rows { get; } - /// - /// The nuber of columns in the table - /// - public int Cols { get; } - /// - /// Creates a new 2 dimensional table in unmanaged heap memory, using the heap. - /// User should dispose of the table when no longer in use - /// - /// Number of rows in the table - /// Number of columns in the table - public VnTable(int rows, int cols) : this(Memory.Shared, rows, cols) { } - /// - /// Creates a new 2 dimensional table in unmanaged heap memory, using the specified heap. - /// User should dispose of the table when no longer in use - /// - /// to allocate table memory from - /// Number of rows in the table - /// Number of columns in the table - public VnTable(IUnmangedHeap heap, int rows, int cols) - { - if (rows < 0 || cols < 0) - { - throw new ArgumentOutOfRangeException(nameof(rows), "Row and coulmn number must be 0 or larger"); - } - //empty table - if (rows == 0 && cols == 0) - { - Empty = true; - return; - } - - _ = heap ?? throw new ArgumentNullException(nameof(heap)); - - this.Rows = rows; - this.Cols = cols; - - long tableSize = Math.BigMul(rows, cols); - - //Alloc a buffer with zero memory enabled, with Rows * Cols number of elements - BufferHandle = heap.Alloc(tableSize, true); - } - /// - /// Gets the value of an item in the table at the given indexes - /// - /// Row address of the item - /// Column address of item - /// The value of the item - /// - /// - /// - public T Get(int row, int col) - { - Check(); - if (this.Empty) - { - throw new InvalidOperationException("Table is empty"); - } - if (row < 0 || col < 0) - { - throw new ArgumentOutOfRangeException(nameof(row), "Row or column address less than 0"); - } - if (row > this.Rows) - { - throw new ArgumentOutOfRangeException(nameof(row), "Row out of range of current table"); - } - if (col > this.Cols) - { - throw new ArgumentOutOfRangeException(nameof(col), "Column address out of range of current table"); - } - //Calculate the address in memory for the item - //Calc row offset - long address = Cols * row; - //Calc column offset - address += col; - unsafe - { - //Get the value item - return *(BufferHandle!.GetOffset(address)); - } - } - /// - /// Sets the value of an item in the table at the given address - /// - /// Value of item to store - /// Row address of the item - /// Column address of item - /// The value of the item - /// - /// - /// - public void Set(int row, int col, T item) - { - Check(); - if (this.Empty) - { - throw new InvalidOperationException("Table is empty"); - } - if (row < 0 || col < 0) - { - throw new ArgumentOutOfRangeException(nameof(row), "Row or column address less than 0"); - } - if (row > this.Rows) - { - throw new ArgumentOutOfRangeException(nameof(row), "Row out of range of current table"); - } - if (col > this.Cols) - { - throw new ArgumentOutOfRangeException(nameof(col), "Column address out of range of current table"); - } - //Calculate the address in memory for the item - //Calc row offset - long address = Cols * row; - //Calc column offset - address += col; - //Set the value item - unsafe - { - *BufferHandle!.GetOffset(address) = item; - } - } - /// - /// Equivalent to and - /// - /// Row address of item - /// Column address of item - /// The value of the item - public T this[int row, int col] - { - get => Get(row, col); - set => Set(row, col, value); - } - /// - /// Allows for direct addressing in the table. - /// - /// - /// - /// - /// - /// - public unsafe T this[uint index] - { - get - { - Check(); - return !Empty ? *(BufferHandle!.GetOffset(index)) : throw new InvalidOperationException("Cannot index an empty table"); - } - - set - { - Check(); - if (Empty) - { - throw new InvalidOperationException("Cannot index an empty table"); - } - *(BufferHandle!.GetOffset(index)) = value; - } - } - /// - protected override void Free() - { - if (!this.Empty) - { - //Dispose the buffer - BufferHandle!.Dispose(); - } - } - } -} \ No newline at end of file diff --git a/Utils/src/Memory/VnTempBuffer.cs b/Utils/src/Memory/VnTempBuffer.cs deleted file mode 100644 index 7726fe1..0000000 --- a/Utils/src/Memory/VnTempBuffer.cs +++ /dev/null @@ -1,207 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: VnTempBuffer.cs -* -* VnTempBuffer.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.Buffers; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; - -using VNLib.Utils.Extensions; -using System.Security.Cryptography; - -namespace VNLib.Utils.Memory -{ - /// - /// A disposable temporary buffer from shared ArrayPool - /// - /// Type of buffer to create - public sealed class VnTempBuffer : VnDisposeable, IIndexable, IMemoryHandle - { - private readonly ArrayPool Pool; - - /// - /// Referrence to internal buffer - /// - public T[] Buffer { get; private set; } - /// - /// Inital/desired size of internal buffer - /// - public int InitSize { get; } - - /// - /// Actual length of internal buffer - /// - public ulong Length => (ulong)Buffer.LongLength; - - /// - /// Actual length of internal buffer - /// - public int IntLength => Buffer.Length; - - /// - /// - public Span Span - { - get - { - Check(); - return new Span(Buffer, 0, InitSize); - } - } - - /// - /// Allocates a new with a new buffer from shared array-pool - /// - /// Minimum size of the buffer - /// Set the zero memory flag on close - public VnTempBuffer(int minSize, bool zero = false) :this(ArrayPool.Shared, minSize, zero) - {} - /// - /// Allocates a new with a new buffer from specified array-pool - /// - /// The to allocate from and return to - /// Minimum size of the buffer - /// Set the zero memory flag on close - public VnTempBuffer(ArrayPool pool, int minSize, bool zero = false) - { - Pool = pool; - Buffer = pool.Rent(minSize, zero); - InitSize = minSize; - } - /// - /// Gets an offset wrapper around the current buffer - /// - /// Offset from begining of current buffer - /// Number of from offset - /// An wrapper around the current buffer containing the offset - public ArraySegment GetOffsetWrapper(int offset, int count) - { - Check(); - //Let arraysegment throw exceptions for checks - return new ArraySegment(Buffer, offset, count); - } - /// - public T this[int index] - { - get - { - Check(); - return Buffer[index]; - } - set - { - Check(); - Buffer[index] = value; - } - } - - /// - /// Gets a memory structure around the internal buffer - /// - /// A memory structure over the buffer - /// - /// - public Memory AsMemory() - { - Check(); - return new Memory(Buffer, 0, InitSize); - } - /// - /// Gets a memory structure around the internal buffer - /// - /// The number of elements included in the result - /// A value specifying the begining index of the buffer to include - /// A memory structure over the buffer - /// - /// - public Memory AsMemory(int start, int count) - { - Check(); - return new Memory(Buffer, start, count); - } - /// - /// Gets a memory structure around the internal buffer - /// - /// The number of elements included in the result - /// A memory structure over the buffer - /// - /// - public Memory AsMemory(int count) - { - Check(); - return new Memory(Buffer, 0, count); - } - - /* - * Allow implict casts to span/arrayseg/memory - */ - public static implicit operator Memory(VnTempBuffer buf) => buf == null ? Memory.Empty : buf.ToMemory(); - public static implicit operator Span(VnTempBuffer buf) => buf == null ? Span.Empty : buf.ToSpan(); - public static implicit operator ArraySegment(VnTempBuffer buf) => buf == null ? ArraySegment.Empty : buf.ToArraySegment(); - - public Memory ToMemory() => Disposed ? Memory.Empty : Buffer.AsMemory(0, InitSize); - public Span ToSpan() => Disposed ? Span.Empty : Buffer.AsSpan(0, InitSize); - public ArraySegment ToArraySegment() => Disposed ? ArraySegment.Empty : new(Buffer, 0, InitSize); - - /// - /// Returns buffer to shared array-pool - /// - protected override void Free() - { - //Return the buffer to the array pool - Pool.Return(Buffer); - - //Set buffer to null, -#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. - Buffer = null; -#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. - } - - unsafe MemoryHandle IPinnable.Pin(int elementIndex) - { - //Guard - if (elementIndex < 0 || elementIndex >= IntLength) - { - throw new ArgumentOutOfRangeException(nameof(elementIndex)); - } - - //Pin the array - GCHandle arrHandle = GCHandle.Alloc(Buffer, GCHandleType.Pinned); - //Get array base address - void* basePtr = (void*)arrHandle.AddrOfPinnedObject(); - //Get element offset - void* indexOffet = Unsafe.Add(basePtr, elementIndex); - return new(indexOffet, arrHandle, this); - } - - void IPinnable.Unpin() - { - //Gchandle will manage the unpin - } - - ~VnTempBuffer() => Free(); - - - } -} \ No newline at end of file diff --git a/Utils/src/Native/SafeLibraryHandle.cs b/Utils/src/Native/SafeLibraryHandle.cs deleted file mode 100644 index 4772bd4..0000000 --- a/Utils/src/Native/SafeLibraryHandle.cs +++ /dev/null @@ -1,220 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: SafeLibraryHandle.cs -* -* SafeLibraryHandle.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.Linq; -using System.Reflection; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Diagnostics.CodeAnalysis; - -using VNLib.Utils.Extensions; - -namespace VNLib.Utils.Native -{ - /// - /// Represents a safe handle to a native library loaded to the current process - /// - public sealed class SafeLibraryHandle : SafeHandle - { - /// - public override bool IsInvalid => handle == IntPtr.Zero; - - private SafeLibraryHandle(IntPtr libHandle) : base(IntPtr.Zero, true) - { - //Init handle - SetHandle(libHandle); - } - - /// - /// Finds and loads the specified native libary into the current process by its name at runtime - /// - /// The path (or name of libary) to search for - /// - /// The used to search for libaries - /// within the current filesystem - /// - /// The loaded - /// - /// - public static SafeLibraryHandle LoadLibrary(string libPath, DllImportSearchPath searchPath = DllImportSearchPath.ApplicationDirectory) - { - _ = libPath ?? throw new ArgumentNullException(nameof(libPath)); - //See if the path includes a file extension - return TryLoadLibrary(libPath, searchPath, out SafeLibraryHandle? lib) - ? lib - : throw new DllNotFoundException($"The library {libPath} or one of its dependencies could not be found"); - } - - /// - /// Attempts to load the specified native libary into the current process by its name at runtime - /// - ///The path (or name of libary) to search for - /// - /// The used to search for libaries - /// within the current filesystem - /// - /// The handle to the libary if successfully loaded - /// True if the libary was found and loaded into the current process - public static bool TryLoadLibrary(string libPath, DllImportSearchPath searchPath, [NotNullWhen(true)] out SafeLibraryHandle? lib) - { - lib = null; - //Allow full rooted paths - if (Path.IsPathRooted(libPath)) - { - //Attempt a native load - if (NativeLibrary.TryLoad(libPath, out IntPtr libHandle)) - { - lib = new(libHandle); - return true; - } - return false; - } - //Check application directory first (including subdirectories) - if ((searchPath & DllImportSearchPath.ApplicationDirectory) > 0) - { - //get the current directory - string libDir = Directory.GetCurrentDirectory(); - if (TryLoadLibraryInternal(libDir, libPath, SearchOption.TopDirectoryOnly, out lib)) - { - return true; - } - } - //See if search in the calling assembly directory - if ((searchPath & DllImportSearchPath.AssemblyDirectory) > 0) - { - //Get the calling assmblies directory - string libDir = Assembly.GetCallingAssembly().Location; - Debug.WriteLine("Native library searching for calling assembly location:{0} ", libDir); - if (TryLoadLibraryInternal(libDir, libPath, SearchOption.TopDirectoryOnly, out lib)) - { - return true; - } - } - //Search system32 dir - if ((searchPath & DllImportSearchPath.System32) > 0) - { - //Get the system directory - string libDir = Environment.GetFolderPath(Environment.SpecialFolder.SystemX86); - if (TryLoadLibraryInternal(libDir, libPath, SearchOption.TopDirectoryOnly, out lib)) - { - return true; - } - } - //Attempt a native load - { - if (NativeLibrary.TryLoad(libPath, out IntPtr libHandle)) - { - lib = new(libHandle); - return true; - } - return false; - } - } - - private static bool TryLoadLibraryInternal(string libDir, string libPath, SearchOption dirSearchOptions, [NotNullWhen(true)] out SafeLibraryHandle? libary) - { - //Try to find the libary file - string? libFile = GetLibraryFile(libDir, libPath, dirSearchOptions); - //Load libary - if (libFile != null && NativeLibrary.TryLoad(libFile, out IntPtr libHandle)) - { - libary = new SafeLibraryHandle(libHandle); - return true; - } - libary = null; - return false; - } - private static string? GetLibraryFile(string dirPath, string libPath, SearchOption search) - { - //slice the lib to its file name - libPath = Path.GetFileName(libPath); - libPath = Path.ChangeExtension(libPath, OperatingSystem.IsWindows() ? ".dll" : ".so"); - //Select the first file that matches the name - return Directory.EnumerateFiles(dirPath, libPath, search).FirstOrDefault(); - } - - /// - /// Loads a native method from the library of the specified name and managed delegate - /// - /// The native method delegate type - /// The name of the native method - /// A wapper handle around the native method delegate - /// - /// If the handle is closed or invalid - /// When the specified entrypoint could not be found - public SafeMethodHandle GetMethod(string methodName) where T : Delegate - { - //Increment handle count before obtaining a method - bool success = false; - DangerousAddRef(ref success); - if (!success) - { - throw new ObjectDisposedException("The libary has been released!"); - } - try - { - //Get the method pointer - IntPtr nativeMethod = NativeLibrary.GetExport(handle, methodName); - //Get the delegate for the function pointer - T method = Marshal.GetDelegateForFunctionPointer(nativeMethod); - return new(this, method); - } - catch - { - DangerousRelease(); - throw; - } - } - /// - /// Gets an delegate wrapper for the specified method without tracking its referrence. - /// The caller must manage the referrence count in order - /// to not leak resources or cause process corruption - /// - /// The native method delegate type - /// The name of the native method - /// A the delegate wrapper on the native method - /// - /// If the handle is closed or invalid - /// When the specified entrypoint could not be found - public T DangerousGetMethod(string methodName) where T : Delegate - { - this.ThrowIfClosed(); - //Get the method pointer - IntPtr nativeMethod = NativeLibrary.GetExport(handle, methodName); - //Get the delegate for the function pointer - return Marshal.GetDelegateForFunctionPointer(nativeMethod); - } - - /// - protected override bool ReleaseHandle() - { - //Free the library and set the handle as invalid - NativeLibrary.Free(handle); - SetHandleAsInvalid(); - return true; - } - } -} diff --git a/Utils/src/Native/SafeMethodHandle.cs b/Utils/src/Native/SafeMethodHandle.cs deleted file mode 100644 index 3ba0879..0000000 --- a/Utils/src/Native/SafeMethodHandle.cs +++ /dev/null @@ -1,61 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: SafeMethodHandle.cs -* -* SafeMethodHandle.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 VNLib.Utils.Resources; - -namespace VNLib.Utils.Native -{ - /// - /// Represents a handle to a 's - /// native method - /// - /// The native method deelgate type - public class SafeMethodHandle : OpenHandle where T : Delegate - { - private T? _method; - private readonly SafeLibraryHandle Library; - - internal SafeMethodHandle(SafeLibraryHandle lib, T method) - { - Library = lib; - _method = method; - } - - /// - /// A delegate to the native method - /// - public T? Method => _method; - - /// - protected override void Free() - { - //Release the method - _method = default; - //Decrement lib handle count - Library.DangerousRelease(); - } - } -} diff --git a/Utils/src/NativeLibraryException.cs b/Utils/src/NativeLibraryException.cs deleted file mode 100644 index 5c66852..0000000 --- a/Utils/src/NativeLibraryException.cs +++ /dev/null @@ -1,89 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: NativeLibraryException.cs -* -* NativeLibraryException.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; - -namespace VNLib.Utils -{ - /// - /// Raised when an internal buffer was not propery sized for the opreation - /// - public class InternalBufferTooSmallException : OutOfMemoryException - { - public InternalBufferTooSmallException(string message) : base(message) - {} - - public InternalBufferTooSmallException(string message, Exception innerException) : base(message, innerException) - {} - - public InternalBufferTooSmallException() - {} - } - - /// - /// A base class for all native library related exceptions - /// - public class NativeLibraryException : SystemException - { - public NativeLibraryException(string message) : base(message) - {} - - public NativeLibraryException(string message, Exception innerException) : base(message, innerException) - {} - - public NativeLibraryException() - {} - } - - /// - /// Base exception class for native memory related exceptions - /// - public class NativeMemoryException : NativeLibraryException - { - public NativeMemoryException(string message) : base(message) - {} - - public NativeMemoryException(string message, Exception innerException) : base(message, innerException) - {} - - public NativeMemoryException() - {} - } - - /// - /// Raised when a memory allocation or resize failed because there is - /// no more memory available - /// - public class NativeMemoryOutOfMemoryException : OutOfMemoryException - { - public NativeMemoryOutOfMemoryException(string message) : base(message) - {} - - public NativeMemoryOutOfMemoryException(string message, Exception innerException) : base(message, innerException) - {} - - public NativeMemoryOutOfMemoryException() - {} - } -} diff --git a/Utils/src/Resources/BackedResourceBase.cs b/Utils/src/Resources/BackedResourceBase.cs deleted file mode 100644 index 0a2e1e3..0000000 --- a/Utils/src/Resources/BackedResourceBase.cs +++ /dev/null @@ -1,79 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: BackedResourceBase.cs -* -* BackedResourceBase.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.Text.Json; -using System.Runtime.CompilerServices; - -namespace VNLib.Utils.Resources -{ - /// - /// A base class for a resource that is backed by an external data store. - /// Implements the interfaceS - /// - public abstract class BackedResourceBase : IResource - { - /// - public bool IsReleased { get; protected set; } - - /// - /// Optional to be used when serializing - /// the resource - /// - internal protected virtual JsonSerializerOptions? JSO { get; } - - /// - /// A value indicating whether the instance should be deleted when released - /// - protected bool Deleted { get; set; } - /// - /// A value indicating whether the instance should be updated when released - /// - protected bool Modified { get; set; } - - /// - /// Checks if the resouce has been disposed and raises an exception if it is - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected void Check() - { - if (IsReleased) - { - throw new ObjectDisposedException("The resource has been disposed"); - } - } - - /// - /// Returns the JSON serializable resource to be updated during an update - /// - /// The resource to update - protected abstract object GetResource(); - - /// - /// Marks the resource for deletion from backing store during closing events - /// - public virtual void Delete() => Deleted = true; - } -} \ No newline at end of file diff --git a/Utils/src/Resources/CallbackOpenHandle.cs b/Utils/src/Resources/CallbackOpenHandle.cs deleted file mode 100644 index 625bd45..0000000 --- a/Utils/src/Resources/CallbackOpenHandle.cs +++ /dev/null @@ -1,44 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: CallbackOpenHandle.cs -* -* CallbackOpenHandle.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; - -namespace VNLib.Utils.Resources -{ - /// - /// A concrete for a defered operation or a resource that should be released or unwound - /// when the instance lifetime has ended. - /// - public sealed class CallbackOpenHandle : OpenHandle - { - private readonly Action ReleaseFunc; - /// - /// Creates a new generic with the specified release callback method - /// - /// The callback function to invoke when the is disposed - public CallbackOpenHandle(Action release) => ReleaseFunc = release; - /// - protected override void Free() => ReleaseFunc(); - } -} \ No newline at end of file diff --git a/Utils/src/Resources/ExclusiveResourceHandle.cs b/Utils/src/Resources/ExclusiveResourceHandle.cs deleted file mode 100644 index 173bdd1..0000000 --- a/Utils/src/Resources/ExclusiveResourceHandle.cs +++ /dev/null @@ -1,81 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: ExclusiveResourceHandle.cs -* -* ExclusiveResourceHandle.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; - -namespace VNLib.Utils.Resources -{ - /// - /// While in scope, holds an exclusive lock on the specified object that implements the interface - /// - /// - public class ExclusiveResourceHandle : OpenResourceHandle where T : IExclusiveResource - { - private readonly Action Release; - private readonly Lazy LazyVal; - - /// - /// - ///

- ///

- /// This value is lazy inialized and will invoke the factory function on first access. - /// Accessing this variable is thread safe while the handle is in scope - ///

- ///

- /// Exceptions will be propagated during initialziation - ///
- public override T Resource => LazyVal.Value; - - /// - /// Creates a new wrapping the - /// object to manage its lifecycle and reuse - /// - /// Factory function that will generate the value when used - /// Callback function that will be invoked after object gets disposed - internal ExclusiveResourceHandle(Func factory, Action release) - { - //Store the release action - Release = release; - //Store the new lazy val from the factory function (enabled thread safey) - LazyVal = new(factory, System.Threading.LazyThreadSafetyMode.ExecutionAndPublication); - } - - protected override void Free() - { - try - { - //Dispose the value if it was created, otherwise do not create it - if (LazyVal.IsValueCreated) - { - Resource?.Release(); - } - } - finally - { - //Always invoke the release callback - Release(); - } - } - } -} \ No newline at end of file diff --git a/Utils/src/Resources/IExclusiveResource.cs b/Utils/src/Resources/IExclusiveResource.cs deleted file mode 100644 index 43ec607..0000000 --- a/Utils/src/Resources/IExclusiveResource.cs +++ /dev/null @@ -1,39 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: IExclusiveResource.cs -* -* IExclusiveResource.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/. -*/ - -namespace VNLib.Utils.Resources -{ - - /// - /// An object, that when used in a mulithreading context, guaruntees that the caller has exclusive - /// access to the instance and relinquishes exclusive access when Release() is called; - /// - public interface IExclusiveResource : IResource - { - /// - /// Releases the resource from use. Called when a is disposed - /// - void Release(); - } -} \ No newline at end of file diff --git a/Utils/src/Resources/IResource.cs b/Utils/src/Resources/IResource.cs deleted file mode 100644 index 345e284..0000000 --- a/Utils/src/Resources/IResource.cs +++ /dev/null @@ -1,38 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: IResource.cs -* -* IResource.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/. -*/ - -namespace VNLib.Utils.Resources -{ - /// - /// The base interface for any resource that may be backed by an external - /// data store, and has a finite lifetime, usually accessed within a handle - /// - public interface IResource - { - /// - /// Gets a value indicating if the resource has been released - /// - bool IsReleased { get; } - } -} \ No newline at end of file diff --git a/Utils/src/Resources/OpenHandle.cs b/Utils/src/Resources/OpenHandle.cs deleted file mode 100644 index 6133a65..0000000 --- a/Utils/src/Resources/OpenHandle.cs +++ /dev/null @@ -1,38 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: OpenHandle.cs -* -* OpenHandle.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/. -*/ - -namespace VNLib.Utils.Resources -{ - /// - /// Represents a base class for an open resource or operation that is valid while being held, - /// and is released or unwound when disposed. - /// - /// - /// The pattern, may throw exceptions when disposed as deferred - /// release actions are completed - /// - public abstract class OpenHandle : VnDisposeable - { - } -} \ No newline at end of file diff --git a/Utils/src/Resources/OpenResourceHandle.cs b/Utils/src/Resources/OpenResourceHandle.cs deleted file mode 100644 index d9f9fd2..0000000 --- a/Utils/src/Resources/OpenResourceHandle.cs +++ /dev/null @@ -1,44 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: OpenResourceHandle.cs -* -* OpenResourceHandle.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; - -namespace VNLib.Utils.Resources -{ - /// - /// - /// An abstract base class for an that holds a specific resource and manages its lifetime. - /// - /// - /// - /// The resource type - public abstract class OpenResourceHandle : OpenHandle - { - /// - /// The resource held by the open handle - /// - /// - public abstract TResource Resource { get; } - } -} \ No newline at end of file diff --git a/Utils/src/Resources/ResourceDeleteFailedException.cs b/Utils/src/Resources/ResourceDeleteFailedException.cs deleted file mode 100644 index 8e796b5..0000000 --- a/Utils/src/Resources/ResourceDeleteFailedException.cs +++ /dev/null @@ -1,40 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: ResourceDeleteFailedException.cs -* -* ResourceDeleteFailedException.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.Runtime.Serialization; - -namespace VNLib.Utils.Resources -{ - /// - /// Raised when a resource delete has failed - /// - public class ResourceDeleteFailedException : Exception - { - public ResourceDeleteFailedException() { } - public ResourceDeleteFailedException(string message) : base(message) { } - public ResourceDeleteFailedException(string message, Exception innerException) : base(message, innerException) { } - protected ResourceDeleteFailedException(SerializationInfo info, StreamingContext context) : base(info, context) { } - } -} \ No newline at end of file diff --git a/Utils/src/Resources/ResourceUpdateFailedException.cs b/Utils/src/Resources/ResourceUpdateFailedException.cs deleted file mode 100644 index b4b2b3a..0000000 --- a/Utils/src/Resources/ResourceUpdateFailedException.cs +++ /dev/null @@ -1,40 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: ResourceUpdateFailedException.cs -* -* ResourceUpdateFailedException.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.Runtime.Serialization; - -namespace VNLib.Utils.Resources -{ - /// - /// Raised when a resource update has failed - /// - public class ResourceUpdateFailedException : Exception - { - public ResourceUpdateFailedException() { } - public ResourceUpdateFailedException(string message) : base(message) { } - public ResourceUpdateFailedException(string message, Exception innerException) : base(message, innerException) { } - protected ResourceUpdateFailedException(SerializationInfo info, StreamingContext context) : base(info, context) { } - } -} \ No newline at end of file diff --git a/Utils/src/Resources/UpdatableResource.cs b/Utils/src/Resources/UpdatableResource.cs deleted file mode 100644 index 16f26f2..0000000 --- a/Utils/src/Resources/UpdatableResource.cs +++ /dev/null @@ -1,113 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: UpdatableResource.cs -* -* UpdatableResource.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 VNLib.Utils.IO; - -namespace VNLib.Utils.Resources -{ - /// - /// A callback delegate used for updating a - /// - /// The to be updated - /// The serialized data to be stored/updated - /// - public delegate void UpdateCallback(object source, Stream data); - /// - /// A callback delegate invoked when a delete is requested - /// - /// The to be deleted - /// - public delegate void DeleteCallback(object source); - - /// - /// Implemented by a resource that is backed by an external data store, that when modified or deleted will - /// be reflected to the backing store. - /// - public abstract class UpdatableResource : BackedResourceBase, IExclusiveResource - { - /// - /// The update callback method to invoke during a release operation - /// when the resource is updated. - /// - protected abstract UpdateCallback UpdateCb { get; } - /// - /// The callback method to invoke during a realease operation - /// when the resource should be deleted - /// - protected abstract DeleteCallback DeleteCb { get; } - - /// - /// - /// - /// - /// - /// - public virtual void Release() - { - //If resource has already been realeased, return - if (IsReleased) - { - return; - } - //If deleted flag is set, invoke the delete callback - if (Deleted) - { - DeleteCb(this); - } - //If the state has been modifed, flush changes to the store - else if (Modified) - { - FlushPendingChanges(); - } - //Set the released value - IsReleased = true; - } - - /// - /// Writes the current state of the the resource to the backing store - /// immediatly by invoking the specified callback. - ///

- ///

- /// Only call this method if your store supports multiple state updates - ///
- protected virtual void FlushPendingChanges() - { - //Get the resource - object resource = GetResource(); - //Open a memory stream to store data in - using VnMemoryStream data = new(); - //Serialize and write to stream - VnEncoding.JSONSerializeToBinary(resource, data, resource.GetType(), JSO); - //Reset stream to begining - _ = data.Seek(0, SeekOrigin.Begin); - //Invoke update callback - UpdateCb(this, data); - //Clear modified flag - Modified = false; - } - } -} \ No newline at end of file diff --git a/Utils/src/VNLib.Utils.csproj b/Utils/src/VNLib.Utils.csproj deleted file mode 100644 index b14ab27..0000000 --- a/Utils/src/VNLib.Utils.csproj +++ /dev/null @@ -1,47 +0,0 @@ - - - - net6.0 - VNLib.Utils - Vaughn Nugent - VNLib Utilities Library - Copyright © 2022 Vaughn Nugent - https://www.vaughnnugent.com/resources - VNLib.Utils - 1.0.1.10 - Base utilities library, structs, classes - true - enable - True - latest-all - True - \\vaughnnugent.com\Internal\Folder Redirection\vman\Documents\Programming\Software\StrongNameingKey.snk - - - - - - - - true - - - - False - - - - False - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - diff --git a/Utils/src/VnDisposeable.cs b/Utils/src/VnDisposeable.cs deleted file mode 100644 index 4230a13..0000000 --- a/Utils/src/VnDisposeable.cs +++ /dev/null @@ -1,85 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: VnDisposeable.cs -* -* VnDisposeable.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.Runtime.CompilerServices; - -namespace VNLib.Utils -{ - /// - /// Provides a base class with abstract methods for for disposable objects, with disposed check method - /// - public abstract class VnDisposeable : IDisposable - { - /// - protected bool Disposed { get; private set; } - - /// - /// When overriden in a child class, is responsible for freeing resources - /// - protected abstract void Free(); - - /// - /// Checks if the current object has been disposed. Method will be inlined where possible - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected virtual void Check() - { - if (Disposed) - { - throw new ObjectDisposedException("Object has been disposed"); - } - } - - /// - /// Sets the internal state to diposed without calling operation. - /// Usefull if another code-path performs the free operation independant of a dispose opreation. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected void SetDisposedState() => Disposed = true; - /// - protected virtual void Dispose(bool disposing) - { - if (!Disposed) - { - if (disposing) - { - //Call free method - Free(); - } - Disposed = true; - } - } - //Finalizer is not needed here - - /// - public void Dispose() - { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: true); - GC.SuppressFinalize(this); - } - } -} \ No newline at end of file diff --git a/Utils/src/VnEncoding.cs b/Utils/src/VnEncoding.cs deleted file mode 100644 index 94d8a1a..0000000 --- a/Utils/src/VnEncoding.cs +++ /dev/null @@ -1,914 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Utils -* File: VnEncoding.cs -* -* VnEncoding.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.Text; -using System.Buffers; -using System.Text.Json; -using System.Threading; -using System.Buffers.Text; -using System.Threading.Tasks; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; - -using VNLib.Utils.IO; -using VNLib.Utils.Memory; -using VNLib.Utils.Extensions; - - -namespace VNLib.Utils -{ - /// - /// Contains static methods for encoding data - /// - public static class VnEncoding - { - /// - /// Encodes a with the specified to a that must be disposed by the user - /// - /// Data to be encoded - /// to encode data with - /// A contating the encoded data - public static VnMemoryStream GetMemoryStream(in ReadOnlySpan data, Encoding encoding) - { - _ = encoding ?? throw new ArgumentNullException(nameof(encoding)); - //Create new memory handle to copy data to - MemoryHandle? handle = null; - try - { - //get number of bytes - int byteCount = encoding.GetByteCount(data); - //resize the handle to fit the data - handle = Memory.Memory.Shared.Alloc(byteCount); - //encode - int size = encoding.GetBytes(data, handle); - //Consume the handle into a new vnmemstream and return it - return VnMemoryStream.ConsumeHandle(handle, size, true); - } - catch - { - //Dispose the handle if there is an excpetion - handle?.Dispose(); - throw; - } - } - - /// - /// Attempts to deserialze a json object from a stream of UTF8 data - /// - /// The type of the object to deserialize - /// Binary data to read from - /// object to pass to deserializer - /// The object decoded from the stream - /// - /// - public static T? JSONDeserializeFromBinary(Stream? data, JsonSerializerOptions? options = null) - { - //Return default if null - if (data == null) - { - return default; - } - //Create a memory stream as a buffer - using VnMemoryStream ms = new(); - //Copy stream data to memory - data.CopyTo(ms, null); - if (ms.Length > 0) - { - //Rewind - ms.Position = 0; - //Recover data from stream - return ms.AsSpan().AsJsonObject(options); - } - //Stream is empty - return default; - } - /// - /// Attempts to deserialze a json object from a stream of UTF8 data - /// - /// Binary data to read from - /// - /// object to pass to deserializer - /// The object decoded from the stream - /// - /// - public static object? JSONDeserializeFromBinary(Stream? data, Type type, JsonSerializerOptions? options = null) - { - //Return default if null - if (data == null) - { - return default; - } - //Create a memory stream as a buffer - using VnMemoryStream ms = new(); - //Copy stream data to memory - data.CopyTo(ms, null); - if (ms.Length > 0) - { - //Rewind - ms.Position = 0; - //Recover data from stream - return JsonSerializer.Deserialize(ms.AsSpan(), type, options); - } - //Stream is empty - return default; - } - /// - /// Attempts to deserialze a json object from a stream of UTF8 data - /// - /// The type of the object to deserialize - /// Binary data to read from - /// object to pass to deserializer - /// - /// The object decoded from the stream - /// - /// - public static ValueTask JSONDeserializeFromBinaryAsync(Stream? data, JsonSerializerOptions? options = null, CancellationToken cancellationToken = default) - { - //Return default if null - return data == null || data.Length == 0 ? ValueTask.FromResult(default) : JsonSerializer.DeserializeAsync(data, options, cancellationToken); - } - /// - /// Attempts to deserialze a json object from a stream of UTF8 data - /// - /// Binary data to read from - /// - /// object to pass to deserializer - /// - /// The object decoded from the stream - /// - /// - public static ValueTask JSONDeserializeFromBinaryAsync(Stream? data, Type type, JsonSerializerOptions? options = null, CancellationToken cancellationToken = default) - { - //Return default if null - return data == null || data.Length == 0 ? ValueTask.FromResult(default) : JsonSerializer.DeserializeAsync(data, type, options, cancellationToken); - } - /// - /// Attempts to serialize the object to json and write the encoded data to the stream - /// - /// The object type to serialize - /// The object to serialize - /// The to write output data to - /// object to pass to serializer - /// - public static void JSONSerializeToBinary(T data, Stream output, JsonSerializerOptions? options = null) - { - //return if null - if(data == null) - { - return; - } - //Serialize - JsonSerializer.Serialize(output, data, options); - } - /// - /// Attempts to serialize the object to json and write the encoded data to the stream - /// - /// The object to serialize - /// The to write output data to - /// - /// object to pass to serializer - /// - public static void JSONSerializeToBinary(object data, Stream output, Type type, JsonSerializerOptions? options = null) - { - //return if null - if (data == null) - { - return; - } - //Serialize - JsonSerializer.Serialize(output, data, type, options); - } - - #region Base32 - - private const string RFC_4648_BASE32_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; - - /// - /// Attempts to convert the specified byte sequence in Base32 encoding - /// and writing the encoded data to the output buffer. - /// - /// The input buffer to convert - /// The ouput buffer to write encoded data to - /// The number of characters written, false if no data was written or output buffer was too small - public static ERRNO TryToBase32Chars(ReadOnlySpan input, Span output) - { - ForwardOnlyWriter writer = new(output); - return TryToBase32Chars(input, ref writer); - } - /// - /// Attempts to convert the specified byte sequence in Base32 encoding - /// and writing the encoded data to the output buffer. - /// - /// The input buffer to convert - /// A to write encoded chars to - /// The number of characters written, false if no data was written or output buffer was too small - public static ERRNO TryToBase32Chars(ReadOnlySpan input, ref ForwardOnlyWriter writer) - { - //calculate char size - int charCount = (int)Math.Ceiling(input.Length / 5d) * 8; - //Make sure there is enough room - if(charCount > writer.RemainingSize) - { - return false; - } - //sliding window over input buffer - ForwardOnlyReader reader = new(input); - - while (reader.WindowSize > 0) - { - //Convert the current window - WriteChars(reader.Window, ref writer); - //shift the window - reader.Advance(Math.Min(5, reader.WindowSize)); - } - return writer.Written; - } - private unsafe static void WriteChars(ReadOnlySpan input, ref ForwardOnlyWriter writer) - { - //Get the input buffer as long - ulong inputAsLong = 0; - //Get a byte pointer over the ulong to index it as a byte buffer - byte* buffer = (byte*)&inputAsLong; - //Check proc endianness - if (BitConverter.IsLittleEndian) - { - //store each byte consecutivley and allow for padding - for (int i = 0; (i < 5 && i < input.Length); i++) - { - //Write bytes from upper to lower byte order for little endian systems - buffer[7 - i] = input[i]; - } - } - else - { - //store each byte consecutivley and allow for padding - for (int i = 0; (i < 5 && i < input.Length); i++) - { - //Write bytes from lower to upper byte order for Big Endian systems - buffer[i] = input[i]; - } - } - int rounds = (input.Length) switch - { - 1 => 2, - 2 => 4, - 3 => 5, - 4 => 7, - _ => 8 - }; - //Convert each byte segment up to the number of bytes encoded - for (int i = 0; i < rounds; i++) - { - //store the leading byte - byte val = buffer[7]; - //right shift the value to lower 5 bits - val >>= 3; - //Lookup charcode - char base32Char = RFC_4648_BASE32_CHARS[val]; - //append the character to the writer - writer.Append(base32Char); - //Shift input left by 5 bits so the next 5 bits can be read - inputAsLong <<= 5; - } - //Fill remaining bytes with padding chars - for(; rounds < 8; rounds++) - { - //Append trailing '=' - writer.Append('='); - } - } - - /// - /// Attempts to decode the Base32 encoded string - /// - /// The Base32 encoded data to decode - /// The output buffer to write decoded data to - /// The number of bytes written to the output - /// - public static ERRNO TryFromBase32Chars(ReadOnlySpan input, Span output) - { - ForwardOnlyWriter writer = new(output); - return TryFromBase32Chars(input, ref writer); - } - /// - /// Attempts to decode the Base32 encoded string - /// - /// The Base32 encoded data to decode - /// A to write decoded bytes to - /// The number of bytes written to the output - /// - public unsafe static ERRNO TryFromBase32Chars(ReadOnlySpan input, ref ForwardOnlyWriter writer) - { - //TODO support Big-Endian byte order - - //trim padding characters - input = input.Trim('='); - //Calc the number of bytes to write - int outputSize = (input.Length * 5) / 8; - //make sure the output buffer is large enough - if(writer.RemainingSize < outputSize) - { - return false; - } - - //buffer used to shift data while decoding - ulong bufferLong = 0; - - //re-cast to byte* to index it as a byte buffer - byte* buffer = (byte*)&bufferLong; - - int count = 0, len = input.Length; - while(count < len) - { - //Convert the character to its char code - byte charCode = GetCharCode(input[count]); - //write byte to buffer - buffer[0] |= charCode; - count++; - //If 8 characters have been decoded, reset the buffer - if((count % 8) == 0) - { - //Write the 5 upper bytes in reverse order to the output buffer - for(int j = 0; j < 5; j++) - { - writer.Append(buffer[4 - j]); - } - //reset - bufferLong = 0; - } - //left shift the buffer up by 5 bits - bufferLong <<= 5; - } - //If remaining data has not be written, but has been buffed, finalize it - if (writer.Written < outputSize) - { - //calculate how many bits the buffer still needs to be shifted by (will be 5 bits off because of the previous loop) - int remainingShift = (7 - (count % 8)) * 5; - //right shift the buffer by the remaining bit count - bufferLong <<= remainingShift; - //calc remaining bytes - int remaining = (outputSize - writer.Written); - //Write remaining bytes to the output - for(int i = 0; i < remaining; i++) - { - writer.Append(buffer[4 - i]); - } - } - return writer.Written; - } - private static byte GetCharCode(char c) - { - //cast to byte to get its base 10 value - return c switch - { - //Upper case - 'A' => 0, - 'B' => 1, - 'C' => 2, - 'D' => 3, - 'E' => 4, - 'F' => 5, - 'G' => 6, - 'H' => 7, - 'I' => 8, - 'J' => 9, - 'K' => 10, - 'L' => 11, - 'M' => 12, - 'N' => 13, - 'O' => 14, - 'P' => 15, - 'Q' => 16, - 'R' => 17, - 'S' => 18, - 'T' => 19, - 'U' => 20, - 'V' => 21, - 'W' => 22, - 'X' => 23, - 'Y' => 24, - 'Z' => 25, - //Lower case - 'a' => 0, - 'b' => 1, - 'c' => 2, - 'd' => 3, - 'e' => 4, - 'f' => 5, - 'g' => 6, - 'h' => 7, - 'i' => 8, - 'j' => 9, - 'k' => 10, - 'l' => 11, - 'm' => 12, - 'n' => 13, - 'o' => 14, - 'p' => 15, - 'q' => 16, - 'r' => 17, - 's' => 18, - 't' => 19, - 'u' => 20, - 'v' => 21, - 'w' => 22, - 'x' => 23, - 'y' => 24, - 'z' => 25, - //Base10 digits - '2' => 26, - '3' => 27, - '4' => 28, - '5' => 29, - '6' => 30, - '7' => 31, - - _=> throw new FormatException("Character found is not a Base32 encoded character") - }; - } - - /// - /// Calculates the maximum buffer size required to encode a binary block to its Base32 - /// character encoding - /// - /// The binary buffer size used to calculate the base32 buffer size - /// The maximum size (including padding) of the character buffer required to encode the binary data - public static int Base32CalcMaxBufferSize(int bufferSize) - { - /* - * Base32 encoding consumes 8 bytes for every 5 bytes - * of input data - */ - //Add up to 8 bytes for padding - return (int)(Math.Ceiling(bufferSize / 5d) * 8) + (8 - (bufferSize % 8)); - } - - /// - /// Converts the binary buffer to a base32 character string with optional padding characters - /// - /// The buffer to encode - /// Should padding be included in the result - /// The base32 encoded string representation of the specified buffer - /// - public static string ToBase32String(ReadOnlySpan binBuffer, bool withPadding = false) - { - string value; - //Calculate the base32 entropy to alloc an appropriate buffer (minium buffer of 2 chars) - int entropy = Base32CalcMaxBufferSize(binBuffer.Length); - //Alloc buffer for enough size (2*long bytes) is not an issue - using (UnsafeMemoryHandle charBuffer = Memory.Memory.UnsafeAlloc(entropy)) - { - //Encode - ERRNO encoded = TryToBase32Chars(binBuffer, charBuffer.Span); - if (!encoded) - { - throw new InternalBufferTooSmallException("Base32 char buffer was too small"); - } - //Convert with or w/o padding - if (withPadding) - { - value = charBuffer.Span[0..(int)encoded].ToString(); - } - else - { - value = charBuffer.Span[0..(int)encoded].Trim('=').ToString(); - } - } - return value; - } - /// - /// Converts the base32 character buffer to its structure representation - /// - /// The structure type - /// The base32 character buffer - /// The new structure of the base32 data - /// - /// - public static T FromBase32String(ReadOnlySpan base32) where T: unmanaged - { - //calc size of bin buffer - int size = base32.Length; - //Rent a bin buffer - using UnsafeMemoryHandle binBuffer = Memory.Memory.UnsafeAlloc(size); - //Try to decode the data - ERRNO decoded = TryFromBase32Chars(base32, binBuffer.Span); - //Marshal back to a struct - return decoded ? MemoryMarshal.Read(binBuffer.Span[..(int)decoded]) : throw new InternalBufferTooSmallException("Binbuffer was too small"); - } - - /// - /// Gets a byte array of the base32 decoded data - /// - /// The character array to decode - /// The byte[] of the decoded binary data, or null if the supplied character array was empty - /// - public static byte[]? FromBase32String(ReadOnlySpan base32) - { - if (base32.IsEmpty) - { - return null; - } - //Buffer size of the base32 string will always be enough buffer space - using UnsafeMemoryHandle tempBuffer = Memory.Memory.UnsafeAlloc(base32.Length); - //Try to decode the data - ERRNO decoded = TryFromBase32Chars(base32, tempBuffer.Span); - - return decoded ? tempBuffer.Span[0..(int)decoded].ToArray() : throw new InternalBufferTooSmallException("Binbuffer was too small"); - } - - /// - /// Converts a structure to its base32 representation and returns the string of its value - /// - /// The structure type - /// The structure to encode - /// A value indicating if padding should be used - /// The base32 string representation of the structure - /// - /// - public static string ToBase32String(T value, bool withPadding = false) where T : unmanaged - { - //get the size of the structure - int binSize = Unsafe.SizeOf(); - //Rent a bin buffer - Span binBuffer = stackalloc byte[binSize]; - //Write memory to buffer - MemoryMarshal.Write(binBuffer, ref value); - //Convert to base32 - return ToBase32String(binBuffer, withPadding); - } - - #endregion - - #region percent encoding - - private static readonly ReadOnlyMemory HexToUtf8Pos = new byte[16] - { - 0x30, //0 - 0x31, //1 - 0x32, //2 - 0x33, //3 - 0x34, //4 - 0x35, //5 - 0x36, //6 - 0x37, //7 - 0x38, //8 - 0x39, //9 - - 0x41, //A - 0x42, //B - 0x43, //C - 0x44, //D - 0x45, //E - 0x46 //F - }; - - /// - /// Deterimes the size of the buffer needed to encode a utf8 encoded - /// character buffer into its url-safe percent/hex encoded representation - /// - /// The buffer to examine - /// A sequence of characters that are excluded from encoding - /// The size of the buffer required to encode - public static unsafe int PercentEncodeCalcBufferSize(ReadOnlySpan utf8Bytes, in ReadOnlySpan allowedChars = default) - { - /* - * For every illegal character, the percent encoding adds 3 bytes of - * entropy. So a single byte will be replaced by 3, so adding - * 2 bytes for every illegal character plus the length of the - * intial buffer, we get the size of the buffer needed to - * percent encode. - */ - int count = 0, len = utf8Bytes.Length; - fixed (byte* utfBase = &MemoryMarshal.GetReference(utf8Bytes)) - { - //Find all unsafe characters and add the entropy size - for (int i = 0; i < len; i++) - { - if (!IsUrlSafeChar(utfBase[i], in allowedChars)) - { - count += 2; - } - } - } - //Size is initial buffer size + count bytes - return len + count; - } - - /// - /// Percent encodes the buffer for utf8 encoded characters to its percent/hex encoded - /// utf8 character representation - /// - /// The buffer of utf8 encoded characters to encode - /// The buffer to write the encoded characters to - /// A sequence of characters that are excluded from encoding - /// The number of characters encoded and written to the output buffer - public static ERRNO PercentEncode(ReadOnlySpan utf8Bytes, Span utf8Output, in ReadOnlySpan allowedChars = default) - { - int outPos = 0, len = utf8Bytes.Length; - ReadOnlySpan lookupTable = HexToUtf8Pos.Span; - for (int i = 0; i < len; i++) - { - byte value = utf8Bytes[i]; - //Check if value is url safe - if(IsUrlSafeChar(value, in allowedChars)) - { - //Skip - utf8Output[outPos++] = value; - } - else - { - //Percent encode - utf8Output[outPos++] = 0x25; // '%' - //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]; - } - } - //Return the size of the output buffer - return outPos; - } - - private static bool IsUrlSafeChar(byte value, in ReadOnlySpan allowedChars) - { - return - // base10 digits - value > 0x2f && value < 0x3a - // '_' (underscore) - || value == 0x5f - // '-' (hyphen) - || value == 0x2d - // Uppercase letters - || value > 0x40 && value < 0x5b - // lowercase letters - || value > 0x60 && value < 0x7b - // Check allowed characters - || allowedChars.Contains(value); - } - - //TODO: Implement decode with better performance, lookup table or math vs searching the table - - /// - /// Decodes a percent (url/hex) encoded utf8 encoded character buffer to its utf8 - /// encoded binary value - /// - /// The buffer containg characters to be decoded - /// The buffer to write deocded values to - /// The nuber of bytes written to the output buffer - /// - public static ERRNO PercentDecode(ReadOnlySpan utf8Encoded, Span utf8Output) - { - int outPos = 0, len = utf8Encoded.Length; - ReadOnlySpan lookupTable = HexToUtf8Pos.Span; - for (int i = 0; i < len; i++) - { - byte value = utf8Encoded[i]; - //Begining of percent encoding character - if(value == 0x25) - { - //Calculate the base16 multiplier from the upper half of the - int multiplier = lookupTable.IndexOf(utf8Encoded[i + 1]); - //get the base16 lower half to add - int lower = lookupTable.IndexOf(utf8Encoded[i + 2]); - //Check format - if(multiplier < 0 || lower < 0) - { - throw new FormatException($"Encoded buffer contains invalid hexadecimal characters following the % character at position {i}"); - } - //Calculate the new value, shift multiplier to the upper 4 bits, then mask + or the lower 4 bits - value = (byte)(((byte)(multiplier << 4)) | ((byte)lower & 0x0f)); - //Advance the encoded index by the two consumed chars - i += 2; - } - utf8Output[outPos++] = value; - } - return outPos; - } - - #endregion - - #region Base64 - - /// - /// Tries to convert the specified span containing a string representation that is - /// encoded with base-64 digits into a span of 8-bit unsigned integers. - /// - /// Base64 character data to recover - /// The binary output buffer to write converted characters to - /// The number of bytes written, or of the conversion was unsucessful - public static ERRNO TryFromBase64Chars(ReadOnlySpan base64, Span buffer) - { - return Convert.TryFromBase64Chars(base64, buffer, out int bytesWritten) ? bytesWritten : ERRNO.E_FAIL; - } - /// - /// Tries to convert the 8-bit unsigned integers inside the specified read-only span - /// into their equivalent string representation that is encoded with base-64 digits. - /// You can optionally specify whether to insert line breaks in the return value. - /// - /// The binary buffer to convert characters from - /// The base64 output buffer - /// - /// One of the enumeration values that specify whether to insert line breaks in the - /// return value. The default value is System.Base64FormattingOptions.None. - /// - /// The number of characters encoded, or if conversion was unsuccessful - public static ERRNO TryToBase64Chars(ReadOnlySpan buffer, Span base64, Base64FormattingOptions options = Base64FormattingOptions.None) - { - return Convert.TryToBase64Chars(buffer, base64, out int charsWritten, options: options) ? charsWritten : ERRNO.E_FAIL; - } - - - /* - * Calc base64 padding chars excluding the length mod 4 = 0 case - * by and-ing 0x03 (011) with the result - */ - - /// - /// Determines the number of missing padding bytes from the length of the base64 - /// data sequence. - /// - /// Formula (4 - (length mod 4) and 0x03 - /// - /// - /// The length of the base64 buffer - /// The number of padding bytes to add to the end of the sequence - public static int Base64CalcRequiredPadding(int length) => (4 - (length % 4)) & 0x03; - - /// - /// Converts a base64 utf8 encoded binary buffer to - /// its base64url encoded version - /// - /// The binary buffer to convert - public static unsafe void Base64ToUrlSafeInPlace(Span base64) - { - int len = base64.Length; - - fixed(byte* ptr = &MemoryMarshal.GetReference(base64)) - { - for (int i = 0; i < len; i++) - { - switch (ptr[i]) - { - //Replace + with - (minus) - case 0x2b: - ptr[i] = 0x2d; - break; - //Replace / with _ (underscore) - case 0x2f: - ptr[i] = 0x5f; - break; - } - } - } - } - /// - /// Converts a base64url encoded utf8 encoded binary buffer to - /// its base64 encoded version - /// - /// The base64url utf8 to decode - public static unsafe void Base64FromUrlSafeInPlace(Span uft8Base64Url) - { - int len = uft8Base64Url.Length; - - fixed (byte* ptr = &MemoryMarshal.GetReference(uft8Base64Url)) - { - for (int i = 0; i < len; i++) - { - switch (ptr[i]) - { - //Replace - with + (plus) - case 0x2d: - ptr[i] = 0x2b; - break; - //Replace _ with / (slash) - case 0x5f: - ptr[i] = 0x2f; - break; - } - } - } - } - - /// - /// Converts the input buffer to a url safe base64 encoded - /// utf8 buffer from the base64 input buffer. The base64 is copied - /// directly to the output then converted in place. This is - /// just a shortcut method for readonly spans - /// - /// The base64 encoded data - /// The base64url encoded output - /// The size of the buffer - public static ERRNO Base64ToUrlSafe(ReadOnlySpan base64, Span base64Url) - { - //Aligned copy to the output buffer - base64.CopyTo(base64Url); - //One time convert the output buffer to url safe - Base64ToUrlSafeInPlace(base64Url); - return base64.Length; - } - - /// - /// Converts the urlsafe input buffer to a base64 encoded - /// utf8 buffer from the base64 input buffer. The base64 is copied - /// directly to the output then converted in place. This is - /// just a shortcut method for readonly spans - /// - /// The base64 encoded data - /// The base64url encoded output - /// The size of the buffer - public static ERRNO Base64FromUrlSafe(ReadOnlySpan base64Url, Span base64) - { - //Aligned copy to the output buffer - base64Url.CopyTo(base64); - //One time convert the output buffer to url safe - Base64FromUrlSafeInPlace(base64); - return base64Url.Length; - } - - /// - /// Decodes a utf8 base64url encoded sequence of data and writes it - /// to the supplied output buffer - /// - /// The utf8 base64 url encoded string - /// The output buffer to write the decoded data to - /// The number of bytes written or if the operation failed - public static ERRNO Base64UrlDecode(ReadOnlySpan utf8Base64Url, Span output) - { - if(utf8Base64Url.IsEmpty || output.IsEmpty) - { - return ERRNO.E_FAIL; - } - //url deocde - ERRNO count = Base64FromUrlSafe(utf8Base64Url, output); - - //Writer for adding padding bytes - ForwardOnlyWriter writer = new (output); - writer.Advance(count); - - //Calc required padding - int paddingToAdd = Base64CalcRequiredPadding(writer.Written); - //Add padding bytes - for (; paddingToAdd > 0; paddingToAdd--) - { - writer.Append(0x3d); // '=' - } - - //Base64 decode in place, we should have a buffer large enough - OperationStatus status = Base64.DecodeFromUtf8InPlace(writer.AsSpan(), out int bytesWritten); - //If status is successful return the number of bytes written - return status == OperationStatus.Done ? bytesWritten : ERRNO.E_FAIL; - } - - /// - /// Decodes a base64url encoded character sequence - /// of data and writes it to the supplied output buffer - /// - /// The character buffer to decode - /// The output buffer to write decoded data to - /// The character encoding - /// The number of bytes written or if the operation failed - /// - public static ERRNO Base64UrlDecode(ReadOnlySpan chars, Span output, Encoding? encoding = null) - { - if (chars.IsEmpty || output.IsEmpty) - { - return ERRNO.E_FAIL; - } - //Set the encoding to utf8 - encoding ??= Encoding.UTF8; - //get the number of bytes to alloc a buffer - int decodedSize = encoding.GetByteCount(chars); - - //alloc buffer - using UnsafeMemoryHandle decodeHandle = Memory.Memory.UnsafeAlloc(decodedSize); - //Get the utf8 binary data - int count = encoding.GetBytes(chars, decodeHandle); - return Base64UrlDecode(decodeHandle.Span[..count], output); - } - - #endregion - } -} \ No newline at end of file diff --git a/Utils/tests/ERRNOTest.cs b/Utils/tests/ERRNOTest.cs deleted file mode 100644 index bd14b50..0000000 --- a/Utils/tests/ERRNOTest.cs +++ /dev/null @@ -1,48 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.UtilsTests -* File: ERRNOTest.cs -* -* ERRNOTest.cs is part of VNLib.UtilsTests which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.UtilsTests 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.UtilsTests 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.UtilsTests. If not, see http://www.gnu.org/licenses/. -*/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using Microsoft.VisualStudio.TestTools.UnitTesting; - -using VNLib.Utils; - -namespace VNLib.Utils.Tests -{ - [TestClass] - public class ERRNOTest - { - - [TestMethod] - public unsafe void ERRNOSizeTest() - { - Assert.IsTrue(sizeof(ERRNO) == sizeof(nint)); - } - - } -} diff --git a/Utils/tests/Memory/MemoryHandleTest.cs b/Utils/tests/Memory/MemoryHandleTest.cs deleted file mode 100644 index 02ef1f1..0000000 --- a/Utils/tests/Memory/MemoryHandleTest.cs +++ /dev/null @@ -1,183 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.UtilsTests -* File: MemoryHandleTest.cs -* -* MemoryHandleTest.cs is part of VNLib.UtilsTests which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.UtilsTests 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.UtilsTests 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.UtilsTests. If not, see http://www.gnu.org/licenses/. -*/ - - -using Microsoft.VisualStudio.TestTools.UnitTesting; - -using VNLib.Utils; -using VNLib.Utils.Extensions; - -using static VNLib.Utils.Memory.Memory; - -namespace VNLib.Utils.Memory.Tests -{ - [TestClass] - public class MemoryHandleTest - { - - [TestMethod] - public void MemoryHandleAllocLongExtensionTest() - { - //Check for negatives - Assert.ThrowsException(() => Shared.Alloc(-1)); - - //Make sure over-alloc throws - Assert.ThrowsException(() => Shared.Alloc(ulong.MaxValue, false)); - } -#if TARGET_64_BIT - [TestMethod] - public unsafe void MemoryHandleBigAllocTest() - { - const long bigHandleSize = (long)uint.MaxValue + 1024; - - using MemoryHandle handle = Shared.Alloc(bigHandleSize); - - //verify size - Assert.AreEqual(handle.ByteLength, (ulong)bigHandleSize); - //Since handle is byte, should also match - Assert.AreEqual(handle.Length, (ulong)bigHandleSize); - - //Should throw overflow - Assert.ThrowsException(() => _ = handle.Span); - Assert.ThrowsException(() => _ = handle.IntLength); - - //Should get the remaining span - Span offsetTest = handle.GetOffsetSpan(int.MaxValue, 1024); - - Assert.ThrowsException(() => _ = handle.GetOffsetSpan((long)int.MaxValue + 1, 1024)); - - } -#else - -#endif - - [TestMethod] - public unsafe void BasicMemoryHandleTest() - { - using MemoryHandle handle = Shared.Alloc(128, true); - - Assert.AreEqual(handle.IntLength, 128); - - Assert.AreEqual(handle.Length, (ulong)128); - - //Check span against base pointer deref - - handle.Span[120] = 10; - - Assert.AreEqual(*handle.GetOffset(120), 10); - } - - - [TestMethod] - public unsafe void MemoryHandleDisposedTest() - { - using MemoryHandle handle = Shared.Alloc(1024); - - //Make sure handle is not invalid until disposed - Assert.IsFalse(handle.IsInvalid); - Assert.IsFalse(handle.IsClosed); - Assert.AreNotEqual(IntPtr.Zero, handle.BasePtr); - - //Dispose the handle early and test - handle.Dispose(); - - Assert.IsTrue(handle.IsInvalid); - Assert.IsTrue(handle.IsClosed); - - Assert.ThrowsException(() => _ = handle.Span); - Assert.ThrowsException(() => _ = handle.BasePtr); - Assert.ThrowsException(() => _ = handle.Base); - Assert.ThrowsException(() => handle.Resize(10)); - Assert.ThrowsException(() => _ = handle.GetOffset(10)); - Assert.ThrowsException(() => handle.ThrowIfClosed()); - } - - [TestMethod] - public unsafe void MemoryHandleCountDisposedTest() - { - using MemoryHandle handle = Shared.Alloc(1024); - - //Make sure handle is not invalid until disposed - Assert.IsFalse(handle.IsInvalid); - Assert.IsFalse(handle.IsClosed); - Assert.AreNotEqual(IntPtr.Zero, handle.BasePtr); - - bool test = false; - //Increase handle counter - handle.DangerousAddRef(ref test); - Assert.IsTrue(test); - - //Dispose the handle early and test - handle.Dispose(); - - //Asser is valid still - - //Make sure handle is not invalid until disposed - Assert.IsFalse(handle.IsInvalid); - Assert.IsFalse(handle.IsClosed); - Assert.AreNotEqual(IntPtr.Zero, handle.BasePtr); - - //Dec handle count - handle.DangerousRelease(); - - //Now make sure the class is disposed - - Assert.IsTrue(handle.IsInvalid); - Assert.IsTrue(handle.IsClosed); - Assert.ThrowsException(() => _ = handle.Span); - } - - [TestMethod] - public unsafe void MemoryHandleExtensionsTest() - { - using MemoryHandle handle = Shared.Alloc(1024); - - Assert.AreEqual(handle.IntLength, 1024); - - Assert.ThrowsException(() => handle.Resize(-1)); - - //Resize the handle - handle.Resize(2048); - - Assert.AreEqual(handle.IntLength, 2048); - - Assert.IsTrue(handle.AsSpan(2048).IsEmpty); - - Assert.ThrowsException(() => _ = handle.AsSpan(2049)); - - Assert.ThrowsException(() => _ = handle.GetOffset(2049)); - - Assert.ThrowsException(() => _ = handle.GetOffset(-1)); - - //test resize - handle.ResizeIfSmaller(100); - //Handle should be unmodified - Assert.AreEqual(handle.IntLength, 2048); - - //test working - handle.ResizeIfSmaller(4096); - Assert.AreEqual(handle.IntLength, 4096); - } - } -} diff --git a/Utils/tests/Memory/MemoryTests.cs b/Utils/tests/Memory/MemoryTests.cs deleted file mode 100644 index 5b68cf5..0000000 --- a/Utils/tests/Memory/MemoryTests.cs +++ /dev/null @@ -1,244 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.UtilsTests -* File: MemoryTests.cs -* -* MemoryTests.cs is part of VNLib.UtilsTests which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.UtilsTests 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.UtilsTests 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.UtilsTests. If not, see http://www.gnu.org/licenses/. -*/ - -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System.Runtime.InteropServices; - -using VNLib.Utils.Extensions; - -namespace VNLib.Utils.Memory.Tests -{ - [TestClass()] - public class MemoryTests - { - [TestMethod] - public void MemorySharedHeapLoadedTest() - { - Assert.IsNotNull(Memory.Shared); - } - - [TestMethod()] - public void UnsafeAllocTest() - { - //test against negative number - Assert.ThrowsException(() => Memory.UnsafeAlloc(-1)); - - //Alloc large block test (100mb) - const int largTestSize = 100000 * 1024; - //Alloc super small block - const int smallTestSize = 5; - - using (UnsafeMemoryHandle buffer = Memory.UnsafeAlloc(largTestSize, false)) - { - Assert.AreEqual(largTestSize, buffer.IntLength); - Assert.AreEqual(largTestSize, buffer.Span.Length); - - buffer.Span[0] = 254; - Assert.AreEqual(buffer.Span[0], 254); - } - - using (UnsafeMemoryHandle buffer = Memory.UnsafeAlloc(smallTestSize, false)) - { - Assert.AreEqual(smallTestSize, buffer.IntLength); - Assert.AreEqual(smallTestSize, buffer.Span.Length); - - buffer.Span[0] = 254; - Assert.AreEqual(buffer.Span[0], 254); - } - - //Different data type - - using(UnsafeMemoryHandle buffer = Memory.UnsafeAlloc(largTestSize, false)) - { - Assert.AreEqual(largTestSize, buffer.IntLength); - Assert.AreEqual(largTestSize, buffer.Span.Length); - - buffer.Span[0] = long.MaxValue; - Assert.AreEqual(buffer.Span[0], long.MaxValue); - } - - using (UnsafeMemoryHandle buffer = Memory.UnsafeAlloc(smallTestSize, false)) - { - Assert.AreEqual(smallTestSize, buffer.IntLength); - Assert.AreEqual(smallTestSize, buffer.Span.Length); - - buffer.Span[0] = long.MaxValue; - Assert.AreEqual(buffer.Span[0], long.MaxValue); - } - } - - [TestMethod()] - public void UnsafeZeroMemoryAsSpanTest() - { - //Alloc test buffer - Span test = new byte[1024]; - test.Fill(0); - //test other empty span - Span verify = new byte[1024]; - verify.Fill(0); - - //Fill test buffer with random values - Random.Shared.NextBytes(test); - - //make sure buffers are not equal - Assert.IsFalse(test.SequenceEqual(verify)); - - //Zero buffer - Memory.UnsafeZeroMemory(test); - - //Make sure buffers are equal - Assert.IsTrue(test.SequenceEqual(verify)); - } - - [TestMethod()] - public void UnsafeZeroMemoryAsMemoryTest() - { - //Alloc test buffer - Memory test = new byte[1024]; - test.Span.Fill(0); - //test other empty span - Memory verify = new byte[1024]; - verify.Span.Fill(0); - - //Fill test buffer with random values - Random.Shared.NextBytes(test.Span); - - //make sure buffers are not equal - Assert.IsFalse(test.Span.SequenceEqual(verify.Span)); - - //Zero buffer - Memory.UnsafeZeroMemory(test); - - //Make sure buffers are equal - Assert.IsTrue(test.Span.SequenceEqual(verify.Span)); - } - - [TestMethod()] - public void InitializeBlockAsSpanTest() - { - //Alloc test buffer - Span test = new byte[1024]; - test.Fill(0); - //test other empty span - Span verify = new byte[1024]; - verify.Fill(0); - - //Fill test buffer with random values - Random.Shared.NextBytes(test); - - //make sure buffers are not equal - Assert.IsFalse(test.SequenceEqual(verify)); - - //Zero buffer - Memory.InitializeBlock(test); - - //Make sure buffers are equal - Assert.IsTrue(test.SequenceEqual(verify)); - } - - [TestMethod()] - public void InitializeBlockMemoryTest() - { - //Alloc test buffer - Memory test = new byte[1024]; - test.Span.Fill(0); - //test other empty span - Memory verify = new byte[1024]; - verify.Span.Fill(0); - - //Fill test buffer with random values - Random.Shared.NextBytes(test.Span); - - //make sure buffers are not equal - Assert.IsFalse(test.Span.SequenceEqual(verify.Span)); - - //Zero buffer - Memory.InitializeBlock(test); - - //Make sure buffers are equal - Assert.IsTrue(test.Span.SequenceEqual(verify.Span)); - } - - #region structmemory tests - - [StructLayout(LayoutKind.Sequential)] - struct TestStruct - { - public int X; - public int Y; - } - - [TestMethod()] - public unsafe void ZeroStructAsPointerTest() - { - TestStruct* s = Memory.Shared.StructAlloc(); - s->X = 10; - s->Y = 20; - Assert.AreEqual(10, s->X); - Assert.AreEqual(20, s->Y); - //zero struct - Memory.ZeroStruct(s); - //Verify data was zeroed - Assert.AreEqual(0, s->X); - Assert.AreEqual(0, s->Y); - //Free struct - Memory.Shared.StructFree(s); - } - - [TestMethod()] - public unsafe void ZeroStructAsVoidPointerTest() - { - TestStruct* s = Memory.Shared.StructAlloc(); - s->X = 10; - s->Y = 20; - Assert.AreEqual(10, s->X); - Assert.AreEqual(20, s->Y); - //zero struct - Memory.ZeroStruct((void*)s); - //Verify data was zeroed - Assert.AreEqual(0, s->X); - Assert.AreEqual(0, s->Y); - //Free struct - Memory.Shared.StructFree(s); - } - - [TestMethod()] - public unsafe void ZeroStructAsIntPtrTest() - { - TestStruct* s = Memory.Shared.StructAlloc(); - s->X = 10; - s->Y = 20; - Assert.AreEqual(10, s->X); - Assert.AreEqual(20, s->Y); - //zero struct - Memory.ZeroStruct((IntPtr)s); - //Verify data was zeroed - Assert.AreEqual(0, s->X); - Assert.AreEqual(0, s->Y); - //Free struct - Memory.Shared.StructFree(s); - } - #endregion - } -} \ No newline at end of file diff --git a/Utils/tests/Memory/VnTableTests.cs b/Utils/tests/Memory/VnTableTests.cs deleted file mode 100644 index 11350d4..0000000 --- a/Utils/tests/Memory/VnTableTests.cs +++ /dev/null @@ -1,168 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.UtilsTests -* File: VnTableTests.cs -* -* VnTableTests.cs is part of VNLib.UtilsTests which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.UtilsTests 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.UtilsTests 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.UtilsTests. If not, see http://www.gnu.org/licenses/. -*/ - -using Microsoft.VisualStudio.TestTools.UnitTesting; - - -namespace VNLib.Utils.Memory.Tests -{ - [TestClass()] - public class VnTableTests - { - [TestMethod()] - public void VnTableTest() - { - Assert.ThrowsException(() => - { - using VnTable table = new(-1, 0); - }); - Assert.ThrowsException(() => - { - using VnTable table = new(0, -1); - }); - Assert.ThrowsException(() => - { - using VnTable table = new(-1, -1); - }); - - //Empty table - using (VnTable empty = new(0, 0)) - { - Assert.IsTrue(empty.Empty); - //Test 0 rows/cols - Assert.AreEqual(0, empty.Rows); - Assert.AreEqual(0, empty.Cols); - } - - using (VnTable table = new(40000, 10000)) - { - Assert.IsFalse(table.Empty); - - //Test table size - Assert.AreEqual(40000, table.Rows); - Assert.AreEqual(10000, table.Cols); - } - - - //Test oom, should be native - Assert.ThrowsException(() => - { - using VnTable table = new(int.MaxValue, 2); - }); - } - - [TestMethod()] - public void VnTableTest1() - { - //No throw if empty - using VnTable table = new(null!,0, 0); - - //Throw if table is not empty - Assert.ThrowsException(() => - { - using VnTable table = new(null!,1, 1); - }); - - } - - [TestMethod()] - public void GetSetTest() - { - static void TestIndexAt(VnTable table, int row, int col, int value) - { - table[row, col] = value; - Assert.AreEqual(value, table[row, col]); - Assert.AreEqual(value, table.Get(row, col)); - } - - static void TestSetAt(VnTable table, int row, int col, int value) - { - table.Set(row, col, value); - Assert.AreEqual(value, table[row, col]); - Assert.AreEqual(value, table.Get(row, col)); - } - - static void TestSetDirectAccess(VnTable table, int row, int col, int value) - { - int address = row * table.Cols + col; - table[(uint)address] = value; - - //Get value using indexer - Assert.AreEqual(value, table[row, col]); - } - - static void TestGetDirectAccess(VnTable table, int row, int col, int value) - { - table[row, col] = value; - - int address = row * table.Cols + col; - - //Test direct access - Assert.AreEqual(value, table[(uint)address]); - - //Get value using indexer - Assert.AreEqual(value, table[row, col]); - Assert.AreEqual(value, table.Get(row, col)); - } - - - using (VnTable table = new(11, 11)) - { - //Test index at 10,10 - TestIndexAt(table, 10, 10, 11); - //Test same index with different value using the .set() method - TestSetAt(table, 10, 10, 25); - - //Test direct access - TestSetDirectAccess(table, 10, 10, 50); - - TestGetDirectAccess(table, 10, 10, 37); - - //Test index at 0,0 - TestIndexAt(table, 0, 0, 13); - TestSetAt(table, 0, 0, 85); - - //Test at 0,0 - TestSetDirectAccess(table, 0, 0, 100); - TestGetDirectAccess(table, 0, 0, 86); - } - } - - [TestMethod()] - public void DisposeTest() - { - //Alloc table - VnTable table = new(10, 10); - //Dispose table - table.Dispose(); - - //Test that methods throw on access - Assert.ThrowsException(() => table[10, 10] = 10); - Assert.ThrowsException(() => table.Set(10, 10, 10)); - Assert.ThrowsException(() => table[10, 10] == 10); - Assert.ThrowsException(() => table.Get(10, 10)); - } - - } -} \ No newline at end of file diff --git a/Utils/tests/README.md b/Utils/tests/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/Utils/tests/VNLib.UtilsTests.csproj b/Utils/tests/VNLib.UtilsTests.csproj deleted file mode 100644 index 89b3124..0000000 --- a/Utils/tests/VNLib.UtilsTests.csproj +++ /dev/null @@ -1,36 +0,0 @@ - - - - net6.0 - enable - enable - - false - - true - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - diff --git a/Utils/tests/VnEncodingTests.cs b/Utils/tests/VnEncodingTests.cs deleted file mode 100644 index a4e52f0..0000000 --- a/Utils/tests/VnEncodingTests.cs +++ /dev/null @@ -1,100 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.UtilsTests -* File: VnEncodingTests.cs -* -* VnEncodingTests.cs is part of VNLib.UtilsTests which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.UtilsTests 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.UtilsTests 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.UtilsTests. If not, see http://www.gnu.org/licenses/. -*/ - -using System; -using System.Buffers; -using System.Buffers.Text; -using System.Collections.Generic; -using System.Linq; -using System.Security.Cryptography; -using System.Text; -using System.Threading.Tasks; - -using Microsoft.VisualStudio.TestTools.UnitTesting; -using VNLib.Utils; - -namespace VNLib.Utils.Tests -{ - [TestClass()] - public class VnEncodingTests - { - - [TestMethod()] - public void Base64ToUrlSafeInPlaceTest() - { - //Get randomd data to encode - byte[] dataToEncode = RandomNumberGenerator.GetBytes(64); - //Calc buffer size - int base64Output = Base64.GetMaxEncodedToUtf8Length(64); - - byte[] encodeBuffer = new byte[base64Output]; - //Base64 encode - OperationStatus status = Base64.EncodeToUtf8(dataToEncode, encodeBuffer, out _, out int bytesEncoded, true); - - Assert.IsTrue(status == OperationStatus.Done); - - Span encodeSpan = encodeBuffer.AsSpan(0, bytesEncoded); - - //Make sure some illegal characters are encoded - Assert.IsTrue(encodeSpan.Contains((byte)'+') || encodeSpan.Contains((byte)'/')); - - //Convert to url safe - VnEncoding.Base64ToUrlSafeInPlace(encodeSpan); - - //Make sure the illegal characters are gone - Assert.IsFalse(encodeSpan.Contains((byte)'+') || encodeSpan.Contains((byte)'/')); - } - - [TestMethod()] - public void Base64FromUrlSafeInPlaceTest() - { - //url safe base64 with known encoded characters - const string base64UrlSafe = "lZUABUd8q2BS7p8giysuC7PpEabAFBnMqBPL-9A-qgfR1lbTHQ4tMm8E8nimm2YAd5NGDIQ0vxfU9i5l53tF_WXa_H4vkHfzlv0Df-lLADJV7z8sn-8sfUGdaAiIS8_4OmVGnnY4-TppLMsVR6ov2t07HdOHPPsFFhSpBMXa2pwRveRATcxBA2XxVe09FOWgahhssNS7lU9eC7fRw7icD4ZoJcLSRBbxrjRmeVXKhPIaXR-4mnQ5-vqYzAr9S99CthgbAtVn_WjmDcda6pUB9JW9lp7ylDa9e1r_z39cihTXMOGaUSjVURJaWrNF8CkfW56_x2ODCBmZPov1YyEhww=="; - - //Convert to utf8 binary - byte[] utf8 = Encoding.UTF8.GetBytes(base64UrlSafe); - - //url decode - VnEncoding.Base64FromUrlSafeInPlace(utf8); - - //Confirm illegal chars have been converted back to base64 - Assert.IsFalse(utf8.Contains((byte)'_') || utf8.Contains((byte)'-')); - - //Decode in place to confrim its valid - OperationStatus status = Base64.DecodeFromUtf8InPlace(utf8, out int bytesWritten); - - Assert.IsFalse(status == OperationStatus.NeedMoreData); - Assert.IsFalse(status == OperationStatus.DestinationTooSmall); - Assert.IsFalse(status == OperationStatus.InvalidData); - } - - [TestMethod()] - public void TryToBase64CharsTest() - { - - } - - - } -} \ No newline at end of file -- cgit