- Only .NET 10+ support.
- Some computed properties in
BufferWrapper{T}were madereadonlyto hint the compiler to not create defensive copies. PersistentDictionaryin all of its variants have been removed - usedArrowDbinstead.SerializableObject<T>,MonitoredSerializableObject<T>andThreadSafe<T>have all been combined intoSynchronized<T>which is much simpler, more performant. But can be more manual as it isn't coupled withFile.IO. Instead it provides a delegate that can be provided and called on update.Collections.IsNullOrEmptyand all the other alias functions forCollectionsMarshalhave been removed.Utilssubclasses have been flattened and all the contents will reside directly inUtils.Strings.FormatByteshave been removedPathutilities were also removed - useAppContextinstead.String.IsNullOrEmpty|IsNullOrWhiteSpace|Concatwere also removed to enforce build-in language features.TryConvertFromTo32was also removed -int.Parse|TryParseare more than fast enough now.
- A struct
PooledArrayOwner{T}was added to rent arrays fromArrayPool{T}without additional penalties.- Extensions to match were added to any
ArrayPool{T}includingShared, they allow you to get the owner and the array at the same time.using var owner = ArrayPool{T}.Shared.Rent(minLength, out T[] array); - You can then proceed to use
BufferWrapper{T}.Create(array)to get anIBufferWriterimplementation over it.
- Extensions to match were added to any
- Updated to support .NET 9.0 and optimized certain methods to use .NET 9 specific API's wherever possible.
- Added
BufferWrapper<T>which can be used to append items to aSpan<T>without managing indexes and capacity. This buffer also implementIBufferWriter<T>, and as aref struct implementing an interfaceit is only available on .NET 9.0 and above. Utils.String.FormatBytesnow uses a much larger buffer size of 512 chars by default, to handle the edge case ofdouble.MaxValuewhich would previously cause anArgumentOutOfRangeExceptionto be thrown or similarly any number of bytes that would be bigger than 1024 petabytes. The result will now also include thousands separators to improve readability.- The inner implementation that uses this buffer size is pooled so this should not have any impact on performance.
- All derived types of
PersistentDictionarynow implementIDisposableinterface. - Main concurrent processing methods are now
ICollection<T>.ForAll()andICollection<T>.ForAllAsync()from many, many benchmarks it became clear that for short duration tasks not involving heavy compute, it has by far the best compromise of speed and memory-allocation. If you use it with a nonasync functionall the tasks will yield immediately and require virtually no allocations at all. Which is as good asValueTaskfrom benchmarks. This method has 2 overloads, one which accepts anIAsyncActionwhich enables users with long code and many captured variables to maintain a better structured codebase, and aFuncalternative for quick and easy usage. The difference in memory allocation / execution time between time is nearly non-existent, this mainly for maintainability. - For heavier compute tasks, please revert to using
Parallel.FororParallel.ForEachAsyncand their overloads, they are excellent in load balancing. - Due to the changes above, all other concurrent processing methods, such as
ForEachAsync,InvokeAsyncand all the related functionality from theConcurrentclass have been removed.AsAsyncLocalentry is also removed, and users will be able to access the newForAllandForAllAsyncmethods directly from theICollection<T>interface static extensions. ForAllandForAllAsyncmethods have identical parameters, the only difference is that the implementation forForAllis optimized for synchronous lambdas that don't need to allocate an AsyncStateMachine, while theForAllAsyncis optimized for increased concurrency for asynchronous lambdas. ChoosingForAllfor synchronous lambdas massively decreases memory allocation and execution time.IAsyncAction<T>'sInvokeAsyncmethod now has aCancellationTokenparameter.- Changes to
TimeSpanrelated functions:Format,FormatNonAllocated,ToRemainingDuration,ToRemainingDurationNonAllocated,ToTimeStamp,ToTimeStampNonAllocated, were all removed due to duplication and suboptimal implementations.- The new methods replacing these functionalities are now in
Utils.DateAndTimenamespace. FormatTimeSpanis now replacingFormatandFormatNonAllocated,FormatTimeSpanis hyper optimized. The first overload requires aSpan{char}buffer of at least 30 characters, and returns aReadOnlySpan{char}of the written portion. The second doesn't require a buffer, and allocated a newstringwhich is returned.FormatTimeSpanoutputs a different format than the predecessor, as the time was formatted in decimal and is rather confusing, now it is formatted as00:00unitfor the largest 2 units. So a minute and a half would be01:30mand a day and a half would be02:30detc... this seems more intuitive to me.FormatTimeStampis now replacingToTimeStampandToTimeStampNonAllocated, it is also optimized and the overloads work the same way asFormatTimeSpan.
- The
StringBufferwhich previously rented arrays from the shared array pool, then used the same API's to write to it asAllocatedStringBufferwas removed. The previousAllocatedStringBufferwas now renamed toStringBufferand it requires a pre-allocatedSpan{char}. You can get the same functionality by renting any buffer, and simply supplying toStringBuffer.Create. This allowed removal of a lot of duplicated code and made the API more consistent.StringBuffernow doesn't have an implicit converter toReadOnlySpan{char}anymore, useStringBuffer.WrittenSpaninstead. IModifier{T}was removed, useFunc<T, T>instead.Utils.Strings.FormatByteswas changed in the same manner asUtils.DateAndTime.FormatTimeSpanandUtils.DateAndTime.FormatTimeStamp, it now returns aReadOnlySpan<char>instead of astringand it is optimized to use less memory.ThreadSafe<T>now implementsIEquatable<T>andIEquatable<ThreadSafe<T>>to allow comparisons.
SortedListGetIndexnow is not simplified, instead returns pure result of performing a binary search:- if the item exists, a zero based index
- if not, a negative number that is the bitwise complement of the index of the next element that is larger than the item or, if there is no larger element, the bitwise complement of
Countproperty. - With this you can still find out if something exists by checking for negative, but you can now also use the negative bitwise complement of the index to get section of the list in relation to the item, best used with the span.
- Added
AddRangefunctions forReadOnlySpan{T}andIEnumerable{T}
- Collection extensions
ToArrayFastandToListFastwere removed after being marked asObsoletein the previous version, theLINQalternatives perform only marginally slower, but will improve passively under the hood, consider using them instead.
- Changes to
RentedBufferWriter{T}:RenterBufferWriter{T}no longer throws an exception when the initial capacity is set to 0, instead it will just be disabled, this can be checked with the.IsDisabledproperty. Setting the initial capacity to a negative number will still throw an exception. This change was made to accommodate use cases where aRentedBufferWritercould be used as a return type, before an "invalid" operation, could not be attained, as it would've been required to give a valid capacity in any case, lest you risk a runtime exception. Now you could actually return a "Disabled"RentedBufferWriterif you set the capacity to 0, which intuitively means that the buffer doesn't actually have a backing array, and all operations would throw an exception.- To increase it's usability, a method
WriteAndAdvancewas also added that accepts either a singleTor aReadOnlySpan{T}, it checks if there is enough capacity to write the data to the buffer, if so it writes it and advances the position automatically. - A secondary access
ref T[] GetReferenceUnsafewas added, to allow passing the inner buffer to methods that write to aref T[]which previously required using unsafe code to manipulate the pointers. As implied by the name, this usesUnsafeto acquire the reference, and should only be used if you are carful and know what you are doing.
- Collection extension methods such as
ToArrayFast()andToListFast()were made deprecated, use theToArray()andToList()LINQ methods instead, with time they become the fastest possible implementation and will continue to improve, the performance gap is already minimal, and only improves speed, not memory allocations, which makes it negligible.
-
Performance improvements to parallel extensions that use
AsyncLocal- The changes are BREAKING as now the call sites should use newer convention, behavior will be the same.
- Instead of the previous
.AsAsyncLocal, there are now 2 overloads, both use nested generics which is the reason for the update, instead ofIList<T>they use<TList, TItem>whereTList : IList<TItem>. The first overload with no additional parameters can be used but it will require to specify both generic types as the compiler cannot inferTItemfor some reason. To partially compensate for the verbosity it creates when using complex types, a second overload accepts aTItem? @defaultargument. Specifyingdefault(TItem)there will enable the compiler to infer the generic.
// EXAMPLE var items = List<int>() { 1, 2, 3 }; _ = items.AsAsyncLocal<List<int>, int>(); // Overload 1 with no arguments _ = items.AsAsyncLocal(default(int)); // Overload 2 with TItem? @default
- This might seem like a step backwards but using a nested generic here, can improve performance by not virtualizing interface calls to
IList<T>, and also enable the compiler to more accurately trim the code when compiling toNativeAOT.
-
Both overloads of
DecryptBytesinAesProvidernow have an optional parameterthrowOnErrorwhich is set tofalseby default, retaining the previous behavior. Setting it totruewill make sure the exception is thrown in case of aCryptographicExceptioninstead of just returning an empty array or 0 (respective of the overloads). This might help catch certain issues.- Note: Previously and still now, exceptions other than
CryptographicExceptionwould and will be thrown. They are not caught in the methods.
- Note: Previously and still now, exceptions other than
-
Implement a trick in
RemoveDuplicatesFromSorted,RemoveDuplicates,RemoveDuplicatesSortedandTryConvertToInt32to ensure the compiler knows to remove the bounds checking from the loops. -
IComparer<T>parameter type inSortedList<T>was changed toComparer<T>, the interface virtualization seemed to make custom comparers produce unexpected results. -
StringBufferandAllocatedStringBuffercan now use the builder pattern to chain its construction, same asStringBuilder.var buffer = StringBuffer.Create(stackalloc char[20]).Append("Hello").AppendLine().Append("World");
- This change required each method to return the actual reference of the struct, Use this with caution as this means you can change the actual reference instead of a copy if you manually assign it a new value.
- From my testing, with correct usage, without manually assigning values to the original variable, previous and builder pattern usage passes my tests. If you encounter any issue with this, make sure to submit it in the GitHub repo.
-
Fixed edge case where pausing an
AsyncRoutinewould stop it permanently, regardless of calls toResume.
- Small performance improvement to
Array.ToListFast()
AllocatedStringBuffernow has variation that accepts achar[]as input buffer, this version which also has a corresponding overload inStringBuffer.Createsupports an implicit converter toReadOnlyMemory<char>, intellisense will allow you to use this converter even you usedSpan<char>as a buffer, but doing so will cause an exception to be thrown, as aSpan<char>can bestack allocatedand won't be able to be referenced.- The method above paved the way to creating a
FormatNonAllocated(TimeSpan),ToRemainingDurationNonAllocated(TimeSpan),ToTimeStampNonAllocated(TimeSpan), andFormatBytesNonAllocated(double), these overloads would format directly to span, and return a slice, this would completely bypass thestringallocation, which would've otherwise caused large amounts of GC overhead in frequent calls. - Added
ToArrayFast(List)andToListFast(Array)extension methods, that efficiently create an array from list and the other way around. SerializableObject<T>andMonitoredSerializableObject<T>now require aJsonTypeInfo<T>instead of aJsonSerializerContextto improve type safety, as theJsonSerializerContextoverloads cannot verify that the context has any implementation for the type, potentially leading to exceptions at runtime.
- Made improvements to all
IDisposableimplementing types making theirDisposeimplementations idempotent (consecutive calls will just be ignored, eliminating exceptions that can occur when misused). - Added a new
AsyncLocal<IList<T>>extensionForEachoverload that uses a synchronousIAction<T>implementation, it should be the more modern approach to executing synchronous but parallel actions, it also has parameters fordegreeOfParallelismandcancellationToken, and it also returns aValueTask, which means you should await it, and you can attempt to cancel it if you want. It should also perform a bit better as now it is using a partitioner internally. In the case of performing synchronous operations on parallel, there is less room for speed optimization that can occur by jumping between tasks when a task is just waiting like it is possible in async, here your main tool to optimize will be the figure out the right amount ofdegreeOfParallelism, taking into account the capabilities of the system and complexity of each action. Nevertheless, the default (-1) is not a bad baseline.- If you want the call site to be sync as well, use the "older"
ForEachConcurrentoverload, as calling the newValueTaskoverload in a non-async context, will degrade performance.
- If you want the call site to be sync as well, use the "older"
- Moved
_lockacquiring statements into thetry-finallyblocks to handleout-of-bandexceptions. Thanks TheGenbox. - Modified most of the internal
awaitstatements to useConfigureAwait(false)wherever it was possible, also thanks to TheGenbox.
- Added
AppendLineoverloads to allAppendmethods of theStringBuffervariants that append the platform specific new line sequence at after theAppend, there is also an empty overload which just appends the new line sequence. This was made to reduce code when using newlines, and to make the api even more similar toStringBuilder. - Added
RentedBufferWriter{T}toSharpify.Collections, it is an implementation of theIBufferWriter{T}that uses an array rented from the shared array pool as the backing buffer, it provides an allocation free alternative toArrayBufferWriter{T}. - Heavily implement array pooling in
AesProvider, increasing performance and reducing memory allocations in virtually all APIs. - Added another
CopyToArrayextension forHashSet{T}which enables usage of pre-existing buffer, which in turn enables usage of pooling. - Improved performance of
LazyPersistentDictionaryreads using pooling. - Reduced memory usage in initialization of
SerializableObject{T} AsyncRoutinewith the optionExecuteOnParallelnow also uses pooling, virtually eliminating memory allocations (which used to happen regularly per the execution interval)- Optimized
FibonacciApproximationinUtils.Mathematics
Sharpifyis now fully AOT-Compatible!!- Performed IO optimizations to
LocalPersistentDictionaryandLazyLocalPersistentDictionaryand configured to use compile-time JSON. - BREAKING
ReturnRentedBufferwas renamed toReturnBufferToSharedArrayPoolto better explain what it does, Also added a methodReturnToArrayPoolwhich takes anArrayPoolin case anyone wanted an extension method to be used with customArrayPool. The main reason for both these extensions is because theArrayPools generic type is on the class and not the method, it usually can't be inferred, resulting in longer and more difficult code to write. The extension methods hide all of the generic types because they are made in a format which the compiler can infer from. - BREAKING
SerializableObjectandMonitoredSerializableObjectnow require aJsonSerializationContextparameter, that makes them use compile time AOT compatible serialization. This was required in order to make the entire library AOT compatible.
- BREAKING
StringBuffers andAllocatedStringBuffers constructor have been made internal, to enforce usage of the factory methods. The factory methods of both are now underStringBufferand vary by name to indicate the type you are getting back.StringBuffer.Rent(capacity)will return aStringBufferwhich rents memory from the array pool. AndStringBuffer.Create(Span{char})will return anAllocatedStringBufferwhich works on pre-allocated buffer.StringBufferstill implementsIDisposableso should be used together with ausingstatement or keyword. Also, the implicit converters should now be prioritized to be inlined by the compiler.- It should be noted that in some cases JetBrains Rider marks it an error when the implicit operator to string is used in return statements of a method, this is not an actual error, it compiles and works fine, rather seems as an intellisense failure. If this bothers you, use
.Allocate(true)instead, it does the same thing.
- It should be noted that in some cases JetBrains Rider marks it an error when the implicit operator to string is used in return statements of a method, this is not an actual error, it compiles and works fine, rather seems as an intellisense failure. If this bothers you, use
- Added newer faster and memory memory efficient concurrent APIs whose entry point is
AsyncLocal<IList<T>>, for more information check the updatedParallelsection in the repo Wiki. - Added
Dictionary{K,V}.CopyTo((K,V)[], index)extension (as built-in one isn't available without casting.) - Added
RentBufferAndCopyEntries(Dictionary<K,V>)extension method that returns a tuple of the reference to the rented buffer and array segment over the buffer with the correct range, simplifying renting buffers for a copy of the dictionary contents to perform parallel operations on it. - Added
ReturnRentedBuffer(T[])extension to supplement the entry above, or with anyArrayPool<T>.Shared.Rentcall.
- Updated synchronization aspect of
SerializableObject{T}andMonitoredSerializableObject{T}, they now both implementIDisposableand finalizers in case you forget to dispose of them, or their context makes it inconvenient.
- Introduced new
SerializableObject{T}class that will serialize an object to a file and expose an event that will fire on once the object has changed, also a variantMonitoredSerializableObjectthat has the same functionality and in addition it will monitor for external changes within the file system and synchronize them as well. - Added implicit converters to
ReadOnlySpan{Char}forStringBufferandAllocatedStringBuffer, which can enable usage of the buffer without any allocation in api's that acceptReadOnlySpan{Char}. - Added
[Flags]attribute toRoutineOptionsto calm down some IDEs. - Updated
AesProvider.EncryptBytesandAesProvider.DecryptBytesto useReadOnlySpan{byte}parameters - Added
AesProvider.EncryptBytesandAesProvider.DecryptBytesoverloads that encrypt into a destination span, with guides to length requirements in the summary. - Added implicit converter to
ReadOnlyMemory{char}forStringBufferthat might help usage in some cases.
- Fixed issue where assemblies inside the nuget package were older than the package version
- Addressed issue which resulted in some parts of the library having older implementations when downloading the package using nuget.
- Added new
StringBuffercollection, which rents a buffer of specified length, and allows efficient appending of elements without using any low level apis, indexing or slice management. And with zero costs to performance (tested in benchmarks), for smaller lengths it is more recommended to useAllocatedStringBufferwithstackalloc, for larger than about 1024 characters it would be better to useStringBufferas the it would create less pressure on the system, at those scalesstackalloccan become slow and sometimes may even fail. - Added new
AllocateStringBufferwhich is similar toStringBufferbut requires a preallocated buffer - allowing usage ofstackalloc. StringBufferandAllocatedStringBufferwere internally integrated to replace almost all low level buffer manipulationsAesProvider.EncryptUrlandAesProvider.DecryptUrlin .NET8 or later were optimized to minimize allocations and using hardware intrinsics api's for character replacement.- BREAKING Removed
String.Suffixas the abstraction is the same asString.Concatwhich already uses a very good implementation - Updated project properties for better end user support via nuget.
- Modifications to
PersistentDictionary:Upserthas been renamed toUpsertAsyncto make its nature more obvious (Possible BREAKING change)Upsertnow handles a special case in which the key exists and value is the same as new value, it will completely forgo the operation, requiring noTaskcreation and no serialization.GetOrCreateAsync(key, val)andUpsertAsync(key, val)now return aValueTaskreducing resource usagePersistentDictionarynow uses a regularDictionaryas the internal data structure to be lighter and handle reads even faster. This is the *BREAKING change as custom inherited types will need to be updated to also serialize and deserialize to a regularDictionary.- To allow concurrent writes, a very efficient and robust concurrency model using a
ConcurrentQueueand aSemaphoreSlimis used. It perfect conditions it will even reduce serialization counts. - The base
Dictionaryis also not nullable anymore, which reduces null checks. - More methods of
PersistentDictionarythat had a base implementation were marked asvirtualfor more customization options with inheritance. - Overloads for
Ttypes were added to bothGetOrCreateAsync(key, T val)andUpsertAsync(key, T val)to make usage even easier for primitive types, and they both rely on thestringoverloads so that inherited types would'nt need to implement both. LocalPersistentDictionaryandLazyLocalPersistentDictionarywere both updated to support this new structure and also now utilize a single internal instance of theJsonOptionsfor serialization, thus reducing resource usage in some scenarios.LazyLocalPersistentDictionaryget key implementation was revised and improved to reduce memory allocations.- Edge cases of concurrent writing with
PersistentDictionaryare very hard to detect in unit tests due to inconsistencies in executing upserts in parallel, if you encounter any issues, please post the issue in the repo or email me.
- Added
OpenLink(string url)function toUtils.Envthat supports opening a link on Windows, Mac, and Linux Result.MessageandResult<T>.Messageis no longer nullable, and instead will default to an empty string.string.GetReferenceextension- Added
Result.Failoverloads that support a value, to allow usage of static defaults or empty collections - Added
HashSet.ToArrayFast()method which converts a hash set to an array more efficiently than Linq. - Further optimized
AesProvider.GeneratePassword - BREAKING, The
FormatBytesfunction forlonganddoublewas moved toUtils.Stringsclass and is no longer an extension function, this will make the usage clearer. - Further optimized
TimeSpan.Format - Multiple string creating functions which used to stack allocate the buffers, now rent them instead, potentially reducing overall application memory usage.
- Added another class
Utils.Unsafethat has "hacky" utilities that allow you to reuse existing code in other high performance apis - New exceptions were added to validate function input in places where the JIT could you use this information to optimize the code by removing bound checks and such.
- BREAKING all of the
ConvertToInt32methods were removed, an in place a methodTryConvertToInt32(ReadOnlySpan{char}, out int result)was added, it is more efficient and generic as it can work for signed and unsigned integers by relaying on the bool as the operation status. SortedList<T>'s fields were changed to be protected and not private, this will make inheritance if you so choose, also added an implicit operator that will return the inner list for places which require a list input.
- Changed nullability of return type of
PersistentDictionary.GetOrCreateAsync(key, val) - Finalized features, seems it is a good place to end the patches and start the next minor release
- Updated to support .NET 8.0
- Added
GetOrCreateAsync(key, val)method toPersistentDictionary - Further performance improvement to the
FormatBytesextension Eithers default empty constructor now throws an exception instead of simply warning during usage.AesProvider.IsPasswordValidwas further optimized using spans (Only applies when running > .NET8)- Updated outdates summary documentations
- Added 2 new persistent dictionary types:
LocalPersistentDictionaryandLazyLocalPersistentDictionary- Both of them Inherit from
PersistentDictionary, they are essentially aConcurrentDictionary<string, string>data store, which is optimized for maximal performance. LocalPersistentDictionaryrequires a local path and utilizes Json to serialize and deserialize the dictionary, requiring minimal setup.LazyLocalPersistentDictionaryis similar toLocalPersistentDictionarybut doesn't keep a permanent copy in-memory. Instead it loads and unloads the dictionary per operation.- Do not be mistaken by the simplicity of the
ConcurrentDictionary<string, string>base type, as the string value allows you as much complexity as you want. You can create entire types for the value and just pass their to the dictionary. PersistentDictionaryis an abstract class which lays the ground work for creating such dictionaries with efficiency and thread-safety. You can create your own implementation easily by inheriting the class, you will need at the very least to overrideSerializeAsyncandDeserializeand create your own constructors for setup. It is also possible to overrideGetValueByKeyandSetKeyAndValuewhich allows you to implement lazy loading for example. The flexibility of the serialization is what gives you the option to persist the dictionary to where ever you choose, even an online database. For examples just look howLocalPersistentDictionaryandLazyLocalPersistentDictionaryare implemented in the source code.- Both types support a
StringComparerparameter allowing you to customize the dictionary key management protocol, perhaps you want to ignore case, this is how you configure it.
- Both of them Inherit from
- Added new extension method
ICollection<T>.IsNullOrEmptythat check if it is null or empty using pattern matching. - Added new function
Utils.Env.PathInBaseDirectory(filename)that returns the combined path of the base directory of the executable and the filename.
- Performance increase in
RollingAverageandFibonacciApproximation - changes to
List.RemoveDuplicates:- api change: parameter
isSortedwas moved to be after thecompareroverride, since it usually is used less frequently. - Another overload is available which accepts an
out HashSet<T>parameter that can return the already allocatedHashSetthat was used to check the collection. Using it withisSorted = trueis discouraged as the algorithm doesn't use nHashSetin that case, and it would be more efficient to justnew HashSet(list)in that case.
- api change: parameter
- Small performance and stability enhancement in
DateTime.ToTimeStamp Concurrent.InvokeAsyncmemory usage further optimized when using large collections by using an array with exact item count.- Added new
Routinesnamespace that includes two types:RoutineandAsyncRoutine- Both types allow you to create a routine/background job that will execute a series of functions on a requested interval. And both support configuration with the
Builderpattern. Routineis the simplest and lightest that works best with simple actions.AsyncRoutineis more complex and made specifically to accommodate async functions, it manages an async timer that will execute a collection of async functions. It has aCancellationTokenSourcethat will manage the cancellation of the timer itself and each of the functions. If you want more control you can provide it yourself. Despite the fact thatAsyncRoutinecan be configured using theBuilderpattern, unlikeRoutine, theStartmethod returns a task, so to avoid loosing track of the routine, DO NOT callStartin the same call to the configuration.RoutineOptionsis an enum that is accepted to configure anAsyncRoutineand currently has 2 options:ExecuteInParallelthis will create execute the functions provided in parallel in every tick, this may increase memory allocation since parallel execution requires a collection of tasks to be re-created upon every execution. But, it might provide a speed benefit when using long-running background functions in the routine.ThrowOnCancellation, stopping a task using acancellationTokeninevitably throws aTaskCancelledException. By default to make the routine easier to use it ignores this exception as it should only occur by design. If you toggle this option, it will re-throw the exception and you will be required to handle it. If you want to ensure that the routine finishes when you want to without controlling the token, simply callDisposeon the routine.
- Both types allow you to create a routine/background job that will execute a series of functions on a requested interval. And both support configuration with the
- New collection type
SortedList<T>inSharpify.Collections, it is a List that maintains a sorted order, unlike the originalSortedList<K,V>which is based on a sorted dictionary and a tree. This isn't, it is lighter, more customizable. And enables super efficient iteration and even internalSpan<T>access- Performance stats:
- Initialization from collection: O(nlogn)
- Add and remove item: O(logn)
- Get by index: O(1)
- New
RemoveDuplicatesextensions forList<T>was added, it is implemented using a more efficient algorithm, and has an optional parameterisSortedthat allows further optimization. There is also an optionalIEqualityComparer<T>parameter for types that their default comparer doesn't provide accurate results - Performance enhancements to
AesProvider - New
ChunkToSegmentsextension method for arrays that returnsList<ArraySegment>>that can be used to segment array and process them concurrently, which is the most efficient way to do this asEnumerable.Chunkwill actually create new arrays (much more memory allocation), andspans are very limited when it comes to concurrent processing withTasks. - Optimized
base64related methods inAesProvider - Several methods that relied on exception throwing for invalid input parameters, no instead use
Debug.Assertto improve performance on Release builds.
Listextensions:RemovedDuplicatesSorted,SortAndRemoveDuplicateshave been removed. Their functionality is replaces with the newRemoveDuplicatesextension
THIS UPDATE MAY INTRODUCES THE FOLLOWING BREAKING CHANGES BUT THEY ARE REQUIRED FOR FURTHER STABILITY
- Updated
ResultandResult<T>to disallow default constructors, thus enforcing use of factory methods such asResult.OK(message)andResult.Fail(message)and their overloads. - Updated
Concurrentto also disallow default constructor, enforcing use ofICollection.Concurrent()extension method.
- Added url encryption and decryption functions to
AesProvider - Added more safeguards that prevent exceptions when
plaintext input is passed asencryptedto decryption functions. They now return an empty output, eitherbyte[]orstring.Empty, depends on the method.
- Fixed implementation of
IModifier<T>to better fit the requirements ofFunc<T, T>
- Introduces a new
ThreadSafe<T>wrapper which makes any type thread-safe - Introduces a new
AesProviderclass with enables no-setup access to encryption
- Access the value by using
ThreadSafe<T>.Value - Modify the value by using
ThreadSafe<T>.Modify(Func<T, T>)orThreadSafe<T>.Modify(IModifier<T>) IModifier<T>allows you to create an operation that will be better optimized than aFunc<T, T>and possibly avoid the memory allocation penalty associated withdelegates- Unlike the
Interlockedapi's, which require usingrefthus making them unusable inasyncmethods,ThreadSafe<T>doesn't, which makes it much more usable
- Has
stringkey based constructor that takes care of the headache for padding and key size for you - Has methods for encrypting and decrypting both
strings andbyte[]s - Provides an option to generate an
ICryptoTransformfor either encryption or decryption to fit special needs - Properly implements
IDisposablewith api notices to prevent memory leaks - Has static methods for generating hashed passwords and validating them
Utilsclass was made upper class ofEnv,MathematicsandDateAndTimeto allow better categorization and maintenance- Fixed invalid options in the .csproj file
- Added
GetBaseFolderwhich returns the base path of the application directory - Added
IsRunningAsAdminandIsRunningOnWindowswhich are self-explanatory - Added
IsInternetAvailablewhich checks for internet connection
- Added
FibonacciApproximationandFactorialfunctions