// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System; using Regorus.Internal; #nullable enable namespace Regorus { /// /// Helpers for configuring and inspecting Regorus memory limits via the native allocator bridge. /// public static class MemoryLimits { /// /// Configure the process-wide global memory limit in bytes. Pass null to remove the limit. /// /// Maximum number of bytes the allocator may reserve before signalling an error. public static void SetGlobalMemoryLimit(ulong? bytes) { var result = API.regorus_set_global_memory_limit(bytes ?? 0, bytes.HasValue); EnsureSuccess(result, nameof(SetGlobalMemoryLimit)); } /// /// Returns the currently configured global memory limit, if any. /// public static ulong? GetGlobalMemoryLimit() { var result = API.regorus_get_global_memory_limit(); return ExtractOptionalU64(result, "Failed to get global memory limit"); } /// /// Forces the allocator to flush this thread's pending counters into the global aggregates. /// public static void FlushThreadMemoryCounters() { var result = API.regorus_flush_thread_memory_counters(); EnsureSuccess(result, nameof(FlushThreadMemoryCounters)); } /// /// Immediately checks the global memory limit and throws if the allocator reports exhaustion. /// public static void CheckGlobalMemoryLimit() { var result = API.regorus_check_global_memory_limit(); EnsureSuccess(result, nameof(CheckGlobalMemoryLimit)); } /// /// Override the per-thread automatic flush threshold in bytes. Pass null to restore the default. /// public static void SetThreadFlushThresholdOverride(ulong? bytes) { var result = API.regorus_set_thread_flush_threshold_override(bytes ?? 0, bytes.HasValue); EnsureSuccess(result, nameof(SetThreadFlushThresholdOverride)); } /// /// Returns the per-thread flush threshold, if automatic flushing is enabled. /// public static ulong? GetThreadMemoryFlushThreshold() { var result = API.regorus_get_thread_memory_flush_threshold(); return ExtractOptionalU64(result, "Failed to get thread memory flush threshold"); } private static unsafe ulong? ExtractOptionalU64(RegorusResult result, string errorContext) { try { if (result.status != RegorusStatus.Ok) { var message = Utf8Marshaller.FromUtf8(result.error_message) ?? $"{errorContext}: native call failed"; throw result.status.CreateException(message); } if (!result.bool_value) { return null; } if (result.data_type != RegorusDataType.Integer) { throw new InvalidOperationException( $"{errorContext}: native call returned {result.data_type} ({(int)result.data_type}) with bool_value={result.bool_value}" ); } try { return checked((ulong)result.int_value); } catch (OverflowException ex) { throw new OverflowException($"{errorContext}: native value was out of range ({result.int_value})", ex); } } finally { API.regorus_result_drop(result); } } private static void EnsureSuccess(RegorusResult result, string operation) { try { if (result.status != RegorusStatus.Ok) { string? message; unsafe { message = Utf8Marshaller.FromUtf8(result.error_message); } throw result.status.CreateException(message); } } finally { API.regorus_result_drop(result); } } } }