Formatting

This commit is contained in:
Marek Lemańczyk committed 2025-09-24 23:33:37 +02:00
1 parent fc73205507
commit a8588d0ec5
1 file changed
+404 -404
+404 -404
View File
@@ -7,408 +7,408 @@ namespace PerfectNumbers.Core;
public sealed class DivisorCycleCache public sealed class DivisorCycleCache
{ {
internal sealed class CycleBlock internal sealed class CycleBlock
{ {
private int _referenceCount; private int _referenceCount;
internal CycleBlock(int index, ulong start, ulong[] cycles) internal CycleBlock(int index, ulong start, ulong[] cycles)
{ {
Index = index; Index = index;
Start = start; Start = start;
Cycles = cycles; Cycles = cycles;
End = start + (ulong)cycles.Length - 1UL; End = start + (ulong)cycles.Length - 1UL;
} }
internal int Index { get; } internal int Index { get; }
internal ulong Start { get; } internal ulong Start { get; }
internal ulong End { get; } internal ulong End { get; }
internal ulong[] Cycles { get; } internal ulong[] Cycles { get; }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void AddRef() internal void AddRef()
{ {
Interlocked.Increment(ref _referenceCount); Interlocked.Increment(ref _referenceCount);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void Release() internal void Release()
{ {
Interlocked.Decrement(ref _referenceCount); Interlocked.Decrement(ref _referenceCount);
} }
internal bool IsInUse => Volatile.Read(ref _referenceCount) > 0; internal bool IsInUse => Volatile.Read(ref _referenceCount) > 0;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ulong GetCycle(ulong divisor) internal ulong GetCycle(ulong divisor)
{ {
if (divisor < Start || divisor > End) if (divisor < Start || divisor > End)
{ {
return 0UL; return 0UL;
} }
return Cycles[(int)(divisor - Start)]; return Cycles[(int)(divisor - Start)];
} }
} }
public struct Lease : IDisposable public struct Lease : IDisposable
{ {
private readonly DivisorCycleCache? _owner; private readonly DivisorCycleCache? _owner;
private CycleBlock? _block; private CycleBlock? _block;
internal Lease(DivisorCycleCache owner, CycleBlock block) internal Lease(DivisorCycleCache owner, CycleBlock block)
{ {
_owner = owner; _owner = owner;
_block = block; _block = block;
_block.AddRef(); _block.AddRef();
} }
public bool IsValid => _block is not null; public bool IsValid => _block is not null;
public ulong Start => _block?.Start ?? 0UL; public ulong Start => _block?.Start ?? 0UL;
public ulong End => _block?.End ?? 0UL; public ulong End => _block?.End ?? 0UL;
public ulong[]? Values => _block?.Cycles; public ulong[]? Values => _block?.Cycles;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public ulong GetCycle(ulong divisor) public ulong GetCycle(ulong divisor)
{ {
return _block?.GetCycle(divisor) ?? 0UL; return _block?.GetCycle(divisor) ?? 0UL;
} }
public void Dispose() public void Dispose()
{ {
CycleBlock? block = _block; CycleBlock? block = _block;
if (block is null) if (block is null)
{ {
return; return;
} }
block.Release(); block.Release();
_owner?.Release(block); _owner?.Release(block);
_block = null; _block = null;
} }
} }
private readonly object _sync = new(); private readonly object _sync = new();
private readonly ConcurrentDictionary<int, Task<CycleBlock>> _pending = new(); private readonly ConcurrentDictionary<int, Task<CycleBlock>> _pending = new();
private CycleBlock _baseBlock = null!; private CycleBlock _baseBlock = null!;
private CycleBlock? _previous; private CycleBlock? _previous;
private CycleBlock? _current; private CycleBlock? _current;
private CycleBlock? _next; private CycleBlock? _next;
private bool _initialized; private bool _initialized;
private static readonly Lazy<DivisorCycleCache> _lazy = new(() => new DivisorCycleCache()); private static readonly Lazy<DivisorCycleCache> _lazy = new(() => new DivisorCycleCache());
public static DivisorCycleCache Shared => _lazy.Value; public static DivisorCycleCache Shared => _lazy.Value;
private DivisorCycleCache() private DivisorCycleCache()
{ {
ulong[] snapshot = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot(); ulong[] snapshot = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot();
Initialize(snapshot); Initialize(snapshot);
} }
public void ReloadFromCurrentSnapshot() public void ReloadFromCurrentSnapshot()
{ {
ulong[] snapshot = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot(); ulong[] snapshot = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot();
Initialize(snapshot); Initialize(snapshot);
} }
private void Initialize(ulong[] snapshot) private void Initialize(ulong[] snapshot)
{ {
lock (_sync) lock (_sync)
{ {
_pending.Clear(); _pending.Clear();
_baseBlock = new CycleBlock(index: 0, start: 0UL, snapshot); _baseBlock = new CycleBlock(index: 0, start: 0UL, snapshot);
_previous = _baseBlock; _previous = _baseBlock;
_current = null; _current = null;
_next = null; _next = null;
_initialized = true; _initialized = true;
StartPrefetchLocked(1); StartPrefetchLocked(1);
} }
} }
public Lease Acquire(ulong divisor) public Lease Acquire(ulong divisor)
{ {
if (!_initialized) if (!_initialized)
{ {
throw new InvalidOperationException("DivisorCycleCache must be initialized before use."); throw new InvalidOperationException("DivisorCycleCache must be initialized before use.");
} }
if (divisor <= _baseBlock.End) if (divisor <= _baseBlock.End)
{ {
return new Lease(this, _baseBlock); return new Lease(this, _baseBlock);
} }
CycleBlock block = AcquireDynamicBlock(divisor); CycleBlock block = AcquireDynamicBlock(divisor);
return new Lease(this, block); return new Lease(this, block);
} }
private CycleBlock AcquireDynamicBlock(ulong divisor) private CycleBlock AcquireDynamicBlock(ulong divisor)
{ {
int blockIndex = GetBlockIndex(divisor); int blockIndex = GetBlockIndex(divisor);
while (true) while (true)
{ {
Task<CycleBlock>? taskToAwait = null; Task<CycleBlock>? taskToAwait = null;
lock (_sync) lock (_sync)
{ {
if (TryGetCachedBlockLocked(blockIndex, out CycleBlock? cached)) if (TryGetCachedBlockLocked(blockIndex, out CycleBlock? cached))
{ {
return cached!; return cached!;
} }
if (!_pending.TryGetValue(blockIndex, out taskToAwait)) if (!_pending.TryGetValue(blockIndex, out taskToAwait))
{ {
taskToAwait = Task.Run(() => GenerateBlock(blockIndex)); taskToAwait = Task.Run(() => GenerateBlock(blockIndex));
_pending[blockIndex] = taskToAwait; _pending[blockIndex] = taskToAwait;
} }
} }
CycleBlock block = taskToAwait.GetAwaiter().GetResult(); CycleBlock block = taskToAwait.GetAwaiter().GetResult();
lock (_sync) lock (_sync)
{ {
_pending.TryRemove(blockIndex, out _); _pending.TryRemove(blockIndex, out _);
if (TryGetCachedBlockLocked(blockIndex, out CycleBlock? cachedAfterAwait)) if (TryGetCachedBlockLocked(blockIndex, out CycleBlock? cachedAfterAwait))
{ {
return cachedAfterAwait!; return cachedAfterAwait!;
} }
PromoteBlockLocked(block); PromoteBlockLocked(block);
return block; return block;
} }
} }
} }
private bool TryGetCachedBlockLocked(int blockIndex, out CycleBlock? block) private bool TryGetCachedBlockLocked(int blockIndex, out CycleBlock? block)
{ {
if (_current is { Index: var currentIndex } current && currentIndex == blockIndex) if (_current is { Index: var currentIndex } current && currentIndex == blockIndex)
{ {
block = current; block = current;
return true; return true;
} }
if (_previous is { Index: var previousIndex } previous && previousIndex == blockIndex) if (_previous is { Index: var previousIndex } previous && previousIndex == blockIndex)
{ {
block = previous; block = previous;
return true; return true;
} }
if (_next is { Index: var nextIndex } next && nextIndex == blockIndex) if (_next is { Index: var nextIndex } next && nextIndex == blockIndex)
{ {
PromoteNextLocked(); PromoteNextLocked();
block = _current!; block = _current!;
return true; return true;
} }
block = null; block = null;
return false; return false;
} }
private void PromoteNextLocked() private void PromoteNextLocked()
{ {
if (_next is null) if (_next is null)
{ {
return; return;
} }
CycleBlock? oldPrevious = _previous; CycleBlock? oldPrevious = _previous;
_previous = _current ?? _baseBlock; _previous = _current ?? _baseBlock;
_current = _next; _current = _next;
_next = null; _next = null;
StartPrefetchLocked(_current!.Index + 1); StartPrefetchLocked(_current!.Index + 1);
TryReleaseBlockLocked(oldPrevious); TryReleaseBlockLocked(oldPrevious);
} }
private void PromoteBlockLocked(CycleBlock block) private void PromoteBlockLocked(CycleBlock block)
{ {
if (_current is null) if (_current is null)
{ {
_previous = _baseBlock; _previous = _baseBlock;
_current = block; _current = block;
StartPrefetchLocked(block.Index + 1); StartPrefetchLocked(block.Index + 1);
return; return;
} }
if (block.Index > _current.Index) if (block.Index > _current.Index)
{ {
CycleBlock? oldPrevious = _previous; CycleBlock? oldPrevious = _previous;
_previous = _current; _previous = _current;
_current = block; _current = block;
StartPrefetchLocked(block.Index + 1); StartPrefetchLocked(block.Index + 1);
TryReleaseBlockLocked(oldPrevious); TryReleaseBlockLocked(oldPrevious);
return; return;
} }
if (_previous is null || block.Index >= _previous.Index) if (_previous is null || block.Index >= _previous.Index)
{ {
CycleBlock? oldPrevious = _previous; CycleBlock? oldPrevious = _previous;
_previous = block; _previous = block;
TryReleaseBlockLocked(oldPrevious); TryReleaseBlockLocked(oldPrevious);
} }
} }
private void StartPrefetchLocked(int blockIndex) private void StartPrefetchLocked(int blockIndex)
{ {
if (blockIndex <= 0) if (blockIndex <= 0)
{ {
return; return;
} }
if (_next is { Index: var nextIndex } next && nextIndex == blockIndex) if (_next is { Index: var nextIndex } next && nextIndex == blockIndex)
{ {
return; return;
} }
if (_pending.TryGetValue(blockIndex, out Task<CycleBlock>? existing)) if (_pending.TryGetValue(blockIndex, out Task<CycleBlock>? existing))
{ {
if (existing.IsCompletedSuccessfully) if (existing.IsCompletedSuccessfully)
{ {
if (_next is null || _next.Index < blockIndex) if (_next is null || _next.Index < blockIndex)
{ {
_next = existing.Result; _next = existing.Result;
} }
_pending.TryRemove(blockIndex, out _); _pending.TryRemove(blockIndex, out _);
} }
return; return;
} }
Task<CycleBlock> task = Task.Run(() => GenerateBlock(blockIndex)); Task<CycleBlock> task = Task.Run(() => GenerateBlock(blockIndex));
_pending[blockIndex] = task; _pending[blockIndex] = task;
task.ContinueWith(t => OnPrefetchCompleted(blockIndex, t), TaskScheduler.Default); task.ContinueWith(t => OnPrefetchCompleted(blockIndex, t), TaskScheduler.Default);
} }
private void OnPrefetchCompleted(int blockIndex, Task<CycleBlock> task) private void OnPrefetchCompleted(int blockIndex, Task<CycleBlock> task)
{ {
if (!task.IsCompletedSuccessfully) if (!task.IsCompletedSuccessfully)
{ {
_pending.TryRemove(blockIndex, out _); _pending.TryRemove(blockIndex, out _);
return; return;
} }
lock (_sync) lock (_sync)
{ {
if (_next is null || _next.Index < blockIndex) if (_next is null || _next.Index < blockIndex)
{ {
_next = task.Result; _next = task.Result;
} }
_pending.TryRemove(blockIndex, out _); _pending.TryRemove(blockIndex, out _);
TrimCacheLocked(); TrimCacheLocked();
} }
} }
private void TrimCacheLocked() private void TrimCacheLocked()
{ {
if (_previous is null) if (_previous is null)
{ {
return; return;
} }
if (ReferenceEquals(_previous, _baseBlock)) if (ReferenceEquals(_previous, _baseBlock))
{ {
return; return;
} }
if (_previous.IsInUse) if (_previous.IsInUse)
{ {
return; return;
} }
if (_next is not null && _current is not null) if (_next is not null && _current is not null)
{ {
_previous = null; _previous = null;
} }
} }
private void TryReleaseBlockLocked(CycleBlock? block) private void TryReleaseBlockLocked(CycleBlock? block)
{ {
if (block is null || ReferenceEquals(block, _baseBlock)) if (block is null || ReferenceEquals(block, _baseBlock))
{ {
return; return;
} }
if (ReferenceEquals(block, _current) || ReferenceEquals(block, _next)) if (ReferenceEquals(block, _current) || ReferenceEquals(block, _next))
{ {
return; return;
} }
if (block.IsInUse) if (block.IsInUse)
{ {
return; return;
} }
if (ReferenceEquals(block, _previous)) if (ReferenceEquals(block, _previous))
{ {
_previous = null; _previous = null;
} }
} }
private void Release(CycleBlock block) private void Release(CycleBlock block)
{ {
if (!block.IsInUse) if (!block.IsInUse)
{ {
lock (_sync) lock (_sync)
{ {
TryReleaseBlockLocked(block); TryReleaseBlockLocked(block);
} }
} }
} }
private CycleBlock GenerateBlock(int blockIndex) private CycleBlock GenerateBlock(int blockIndex)
{ {
if (blockIndex == 0) if (blockIndex == 0)
{ {
return _baseBlock; return _baseBlock;
} }
ulong start = GetBlockStart(blockIndex); ulong start = GetBlockStart(blockIndex);
int length = GetBlockLength(blockIndex); int length = GetBlockLength(blockIndex);
ulong[] cycles = new ulong[length]; ulong[] cycles = new ulong[length];
ulong divisor = start; ulong divisor = start;
for (int i = 0; i < length; i++) for (int i = 0; i < length; i++)
{ {
cycles[i] = MersenneDivisorCycles.CalculateCycleLength(divisor); cycles[i] = MersenneDivisorCycles.CalculateCycleLength(divisor);
divisor++; divisor++;
} }
return new CycleBlock(blockIndex, start, cycles); return new CycleBlock(blockIndex, start, cycles);
} }
private int GetBlockLength(int blockIndex) private int GetBlockLength(int blockIndex)
{ {
if (blockIndex == 0) if (blockIndex == 0)
{ {
return _baseBlock.Cycles.Length; return _baseBlock.Cycles.Length;
} }
return PerfectNumberConstants.MaxQForDivisorCycles; return PerfectNumberConstants.MaxQForDivisorCycles;
} }
private ulong GetBlockStart(int blockIndex) private ulong GetBlockStart(int blockIndex)
{ {
if (blockIndex == 0) if (blockIndex == 0)
{ {
return 0UL; return 0UL;
} }
ulong baseEnd = _baseBlock.End; ulong baseEnd = _baseBlock.End;
return baseEnd + 1UL + (ulong)(blockIndex - 1) * (ulong)PerfectNumberConstants.MaxQForDivisorCycles; return baseEnd + 1UL + (ulong)(blockIndex - 1) * (ulong)PerfectNumberConstants.MaxQForDivisorCycles;
} }
private int GetBlockIndex(ulong divisor) private int GetBlockIndex(ulong divisor)
{ {
if (divisor <= _baseBlock.End) if (divisor <= _baseBlock.End)
{ {
return 0; return 0;
} }
ulong offset = divisor - (_baseBlock.End + 1UL); ulong offset = divisor - (_baseBlock.End + 1UL);
return (int)(offset / (ulong)PerfectNumberConstants.MaxQForDivisorCycles) + 1; return (int)(offset / (ulong)PerfectNumberConstants.MaxQForDivisorCycles) + 1;
} }
} }