HCommons.Math 1.0.0

dotnet add package HCommons.Math --version 1.0.0
                    
NuGet\Install-Package HCommons.Math -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="HCommons.Math" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="HCommons.Math" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="HCommons.Math" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add HCommons.Math --version 1.0.0
                    
#r "nuget: HCommons.Math, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package HCommons.Math@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=HCommons.Math&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=HCommons.Math&version=1.0.0
                    
Install as a Cake Tool

HCommons

A C# commons library providing utility types and helper functions for .NET applications.

Features

  • Buffers: Memory-efficient pooled array types for high-performance scenarios
  • Math: Mathematical helper methods and extensions for common operations
  • Monads: Functional programming utilities for safe and expressive error handling

Installation

dotnet add package HCommons

Buffers

The HCommons.Buffers namespace provides memory-efficient array types that use ArrayPool<T> for reduced allocations and improved performance.

PooledArray<T>

A disposable wrapper around a pooled array that must be disposed to return the array to the pool.

Key Features
  • Automatically rents arrays from ArrayPool<T>.Shared
  • Must be disposed to avoid memory leaks
  • Supports indexing, spans, and memory operations
  • Provides slicing and copying capabilities
Basic Usage
using HCommons.Buffers;

// Rent a pooled array
using var pooled = PooledArray<int>.Rent(100);

// Access elements
pooled[0] = 42;
Console.WriteLine(pooled[0]); // 42

// Get a span for efficient operations
Span<int> span = pooled.Span;
span.Fill(1);

// Get memory
Memory<int> memory = pooled.Memory;
Ownership Semantics

PooledArray<T> is a struct. Copying it transfers ownership of the underlying array:

using var original = PooledArray<int>.Rent(10);
var copy = original; // Transfers ownership

// Only dispose once - either original or copy, not both
// Using statement will dispose 'original', so don't dispose 'copy'
Prefer Passing Spans

Best practice: Pass Span<T> to methods instead of PooledArray<T> to avoid ownership confusion:

void ProcessData(Span<int> data) {
    // Work with data
}

using var pooled = PooledArray<int>.Rent(100);
ProcessData(pooled.Span); // Recommended approach
Creating Copies

Use RentCopy() when you need independent copies:

using var original = PooledArray<int>.Rent(10);
original.Span.Fill(42);

using var copy = original.RentCopy(); // Independent copy
copy[0] = 1; // Doesn't affect original
Slicing
using var original = PooledArray<int>.Rent(100);

using var slice = original.RentSlice(10, 20); // 20 elements starting at index 10
Returning to Pool
var pooled = PooledArray<int>.Rent(100);
PooledArray<int>.Return(ref pooled); // Explicitly return and dispose

PooledArrayBuilder<T>

A builder for constructing pooled arrays incrementally, similar to List<T> but using pooled memory.

using HCommons.Buffers;

// Create a builder
using var builder = new PooledArrayBuilder<int>();

// Add elements
builder.Add(1);
builder.Add(2);
builder.Add(3);

// Build and transfer ownership
using var result = builder.BuildAndDispose();
Console.WriteLine(result.Length); // 3

// Or create a copy while keeping builder valid
using var builder2 = new PooledArrayBuilder<int>();
builder2.Add(1);
using var copy = builder2.BuildCopy();
builder2.Add(2); // Builder still valid

Math

The HCommons.Math namespace provides mathematical helper methods and extensions for common operations.

HMath

Static utility methods for mathematical operations.

ClampToFloat

Clamps a double value to the float range and converts it to a float.

using HCommons.Math;

double largeValue = 1e100;
float clamped = HMath.ClampToFloat(largeValue); // Returns float.MaxValue

double smallValue = -1e100;
float clampedSmall = HMath.ClampToFloat(smallValue); // Returns float.MinValue

// With custom range
double value = 150.0;
float inRange = HMath.ClampToFloat(value, 0.0f, 100.0f); // Returns 100.0f
Map

Maps values from one range to another range. Available for int, float, and double types.

using HCommons.Math;

// Map integer from 0-100 to 0-255
int brightness = 75;
int byteValue = HMath.Map(brightness, 0, 100, 0, 255); // 191 (75% of 255)

// Map float from 0-1 to -1 to 1
float normalized = 0.75f;
float scaled = HMath.Map(normalized, 0f, 1f, -1f, 1f); // 0.5

// Map double for precise calculations (Celsius to Fahrenheit)
double temperature = 20.0;
double fahrenheit = HMath.Map(temperature, 0.0, 100.0, 32.0, 212.0); // 68.0

HMathExtensions

Extension methods that provide the same functionality as HMath but in a fluent style.

using HCommons.Math;

// ClampToFloat as extension
double value = 1e100;
float clamped = value.ClampToFloat(); // Returns float.MaxValue

// Map as extension
int brightness = 75;
int byteValue = brightness.Map(0, 100, 0, 255); // 191 (75% of 255)

float normalized = 0.75f;
float scaled = normalized.Map(0f, 1f, -1f, 1f); // 0.5

Monads

The HCommons.Monads namespace provides functional programming utilities for expressive and safe error handling.

Optional<T>

Represents a value that may or may not be present, eliminating null reference issues.

Creating Optionals
using HCommons.Monads;

// Some value
Optional<int> some = Optional<int>.Some(42);
Optional<int> someImplicit = 42; // Implicit conversion

// No value
Optional<int> none = Optional<int>.None();
Checking and Accessing Values
Optional<int> opt = 42;

if (opt.HasValue) {
    Console.WriteLine(opt.Value); // 42
}

// Try pattern
if (opt.TryGetValue(out var value)) {
    Console.WriteLine(value);
}

// Get value or default
int val = opt.GetValueOrDefault(0);
Pattern Matching
var message = opt.Match(
    onValue: v => $"Value is {v}",
    onNone: () => "No value"
);

// With actions
opt.Switch(
    onValue: v => Console.WriteLine($"Got {v}"),
    onNone: () => Console.WriteLine("Nothing")
);
Transformations
Optional<int> opt = 42;

// Select (map)
Optional<string> str = opt.Select(x => x.ToString());

// Bind (flatMap)
Optional<int> doubled = opt.Bind(x => Optional<int>.Some(x * 2));

// Where (filter)
Optional<int> filtered = opt.Where(x => x > 10);

// SelectMany (LINQ query syntax)
var result = from x in opt
             from y in Optional<int>.Some(10)
             select x + y;
Stateful Transformations

All transformation methods (Select, Bind, Where, Match, Switch, and SelectMany) have overloads that accept a state parameter, allowing you to pass additional context without closures:

Optional<int> opt = 42;

// Select with state
var multiplier = 2;
Optional<int> doubled = opt.Select(multiplier, (state, x) => x * state);

// Bind with state
var options = new Dictionary<int, string>();
Optional<string> lookup = opt.Bind(options, (dict, key) => 
    dict.TryGetValue(key, out var val) ? Optional<string>.Some(val) : Optional<string>.None());

// Where with state
var threshold = 10;
Optional<int> filtered = opt.Where(threshold, (limit, x) => x > limit);

// Match with state
var context = "Result";
string message = opt.Match(context, 
    (ctx, v) => $"{ctx}: {v}", 
    ctx => $"{ctx}: None");

// Switch with state
var logger = new Logger();
opt.Switch(logger,
    (log, v) => log.Info($"Got {v}"),
    log => log.Info("No value"));

Either<TLeft, TRight>

Represents a value that is one of two possible types, commonly used for success/error scenarios.

using HCommons.Monads;

// Create Either
Either<string, int> left = "Error occurred";
Either<string, int> right = 42;

// Check which side
if (right.IsRight) {
    Console.WriteLine(right.Right); // 42
}

// Pattern matching
var message = right.Match(
    leftFunc: err => $"Error: {err}",
    rightFunc: val => $"Success: {val}"
);

// Switch with actions
right.Switch(
    leftAction: err => Console.WriteLine($"Failed: {err}"),
    rightAction: val => Console.WriteLine($"Got: {val}")
);
Either Extensions

The Either type includes powerful extension methods for transformations and conversions:

using HCommons.Monads;

Either<string, int> either = 42;

// Swap left and right
Either<int, string> swapped = either.Swap(); // Right(42) becomes Left(42)

// Convert to Optional
Optional<int> rightOpt = either.AsRightOptional(); // Some(42)
Optional<string> leftOpt = either.AsLeftOptional(); // None

// Map both sides
Either<int, string> mapped = either.Map(
    leftMapper: err => err.Length,
    rightMapper: val => val.ToString()
);

// Map only one side
Either<string, string> rightMapped = either.MapRight(x => x.ToString());
Either<int, int> leftMapped = either.MapLeft(err => err.Length);
Stateful Either Transformations

Either also supports stateful transformations for Map, MapLeft, MapRight, Match, and Switch:

Either<string, int> either = 42;

// Map with state
var formatter = new NumberFormatter();
Either<string, string> formatted = either.Map(formatter,
    (fmt, err) => fmt.FormatError(err),
    (fmt, val) => fmt.FormatValue(val));

// Match with state
var logger = new Logger();
var result = either.Match(logger,
    (log, err) => { log.Error(err); return -1; },
    (log, val) => { log.Info($"Got {val}"); return val; });

Result and Result<TValue>

Represents the outcome of an operation that can succeed or fail with an error.

Result (no value)
using HCommons.Monads;

Result DoOperation() {
    try {
        // Some operation
        return Result.Success();
    } catch (Exception ex) {
        return Result.Failure(Error.FromException(ex));
    }
}

var result = DoOperation();

if (result.IsSuccess) {
    Console.WriteLine("Operation succeeded");
} else {
    Console.WriteLine($"Operation failed: {result.Error}");
}
Result<TValue> (with value)
Result<int> Divide(int a, int b) {
    if (b == 0)
        return Result<int>.Failure(Error.WithMessage("Division by zero"));
    
    return Result<int>.Success(a / b);
}

var result = Divide(10, 2);

// Pattern matching
var message = result.Match(
    onSuccess: value => $"Result: {value}",
    onFailure: error => $"Error: {error.Message}"
);

// Get value or default
int value = result.GetValueOrDefault(-1);

// Try pattern
if (result.TryGetValue(out var val)) {
    Console.WriteLine(val);
}
Result Extensions

Result and Result<TValue> have extension methods for functional transformations:

using HCommons.Monads;

Result<int> result = Result<int>.Success(42);

// Select (map) to transform success values
Result<string> strResult = result.Select(x => x.ToString());

// Bind (flatMap) to chain operations that return results
Result<int> doubled = result.Bind(x => 
    x > 0 ? Result<int>.Success(x * 2) : Result<int>.Failure("Value must be positive"));

// MapError to transform errors
Result<int> remapped = result.MapError(err => 
    Error.WithMessage($"Operation failed: {err.Message}"));

// Match for pattern matching
var message = result.Match(
    onSuccess: val => $"Got {val}",
    onFailure: err => $"Error: {err.Message}"
);
Stateful Result Transformations

All Result transformation methods support stateful overloads:

Result<int> result = Result<int>.Success(42);

// Select with state
var multiplier = 2;
Result<int> doubled = result.Select(multiplier, (m, x) => x * m);

// Bind with state
var validator = new Validator();
Result<int> validated = result.Bind(validator, (v, x) => 
    v.IsValid(x) ? Result<int>.Success(x) : Result<int>.Failure("Invalid"));

// MapError with state
var logger = new Logger();
Result<int> logged = result.MapError(logger, (log, err) => {
    log.Error(err.Message);
    return err;
});

// Match with state
var formatter = new Formatter();
string formatted = result.Match(formatter,
    (fmt, val) => fmt.FormatSuccess(val),
    (fmt, err) => fmt.FormatError(err));

OperationResult and OperationResult<TValue>

Extends Result with cancellation support for operations that can be cancelled.

using HCommons.Monads;

OperationResult<int> PerformOperation(CancellationToken ct) {
    if (ct.IsCancellationRequested)
        return OperationResult<int>.Cancelled(Cancelled.Because("User cancelled"));
    
    try {
        int result = 42; // Some operation
        return OperationResult<int>.Success(result);
    } catch (Exception ex) {
        return OperationResult<int>.Failure(Error.FromException(ex));
    }
}

var result = PerformOperation(CancellationToken.None);

if (result.IsSuccess) {
    Console.WriteLine($"Success: {result.Value}");
} else if (result.IsCancelled) {
    Console.WriteLine($"Cancelled: {result.Cancellation.Reason}");
} else {
    Console.WriteLine($"Failed: {result.Error.Message}");
}
OperationResult Extensions

OperationResult<TValue> supports the same functional transformations as Result<TValue>, with cancellation awareness:

using HCommons.Monads;

OperationResult<int> opResult = OperationResult<int>.Success(42);

// Select preserves cancellation state
OperationResult<string> strResult = opResult.Select(x => x.ToString());

// Bind chains operations
OperationResult<int> doubled = opResult.Bind(x => 
    OperationResult<int>.Success(x * 2));

// All transformation methods have stateful overloads
var multiplier = 3;
OperationResult<int> tripled = opResult.Select(multiplier, (m, x) => x * m);

Error

Represents an error with a message and optional exception.

using HCommons.Monads;

// From message
Error error1 = Error.WithMessage("Something went wrong");
Error error2 = "Something went wrong"; // Implicit conversion

// From exception
try {
    throw new InvalidOperationException("Bad operation");
} catch (Exception ex) {
    Error error3 = Error.FromException(ex);
    Error error4 = ex; // Implicit conversion
    
    Console.WriteLine(error3.Message);
    Console.WriteLine(error3.HasException); // true
}

// Error with value
Error<int> error5 = Error<int>.WithMessage(42, "Partial result available");

Cancelled

Represents a cancellation with a reason and optional associated value.

using HCommons.Monads;

// Simple cancellation
Cancelled cancellation1 = Cancelled.Because("User requested");
Cancelled cancellation2 = "User requested"; // Implicit conversion

// Cancellation with value
Cancelled<int> cancellation3 = Cancelled<int>.Because(42, "Partial result");

Target Frameworks

  • .NET 9.0
  • .NET 8.0
  • .NET Standard 2.1
  • .NET Standard 2.0

License

This project is licensed under the MIT License - see the LICENSE file for details.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 is compatible. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

    • No dependencies.
  • .NETStandard 2.1

    • No dependencies.
  • net8.0

    • No dependencies.
  • net9.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on HCommons.Math:

Package Downloads
HCommons

Commonly used types, functions, and extensions.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 219 1/27/2026