// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. using System; using SixLabors.ImageSharp.Memory; namespace SixLabors.ImageSharp.Tests.Memory.DiscontiguousBuffers { public struct MemoryGroupIndex : IEquatable { public override bool Equals(object obj) => obj is MemoryGroupIndex other && this.Equals(other); public override int GetHashCode() => HashCode.Combine(this.BufferLength, this.BufferIndex, this.ElementIndex); public int BufferLength { get; } public int BufferIndex { get; } public int ElementIndex { get; } public MemoryGroupIndex(int bufferLength, int bufferIndex, int elementIndex) { this.BufferLength = bufferLength; this.BufferIndex = bufferIndex; this.ElementIndex = elementIndex; } public static MemoryGroupIndex operator +(MemoryGroupIndex idx, int val) { int nextElementIndex = idx.ElementIndex + val; return new MemoryGroupIndex( idx.BufferLength, idx.BufferIndex + (nextElementIndex / idx.BufferLength), nextElementIndex % idx.BufferLength); } public bool Equals(MemoryGroupIndex other) { if (this.BufferLength != other.BufferLength) { throw new InvalidOperationException(); } return this.BufferIndex == other.BufferIndex && this.ElementIndex == other.ElementIndex; } public static bool operator ==(MemoryGroupIndex a, MemoryGroupIndex b) => a.Equals(b); public static bool operator !=(MemoryGroupIndex a, MemoryGroupIndex b) => !a.Equals(b); public static bool operator <(MemoryGroupIndex a, MemoryGroupIndex b) { if (a.BufferLength != b.BufferLength) { throw new InvalidOperationException(); } if (a.BufferIndex < b.BufferIndex) { return true; } if (a.BufferIndex == b.BufferIndex) { return a.ElementIndex < b.ElementIndex; } return false; } public static bool operator >(MemoryGroupIndex a, MemoryGroupIndex b) { if (a.BufferLength != b.BufferLength) { throw new InvalidOperationException(); } if (a.BufferIndex > b.BufferIndex) { return true; } if (a.BufferIndex == b.BufferIndex) { return a.ElementIndex > b.ElementIndex; } return false; } } internal static class MemoryGroupIndexExtensions { public static T GetElementAt(this IMemoryGroup group, MemoryGroupIndex idx) where T : struct { return group[idx.BufferIndex].Span[idx.ElementIndex]; } public static void SetElementAt(this IMemoryGroup group, MemoryGroupIndex idx, T value) where T : struct { group[idx.BufferIndex].Span[idx.ElementIndex] = value; } public static MemoryGroupIndex MinIndex(this IMemoryGroup group) where T : struct { return new MemoryGroupIndex(group.BufferLength, 0, 0); } public static MemoryGroupIndex MaxIndex(this IMemoryGroup group) where T : struct { return group.Count == 0 ? new MemoryGroupIndex(group.BufferLength, 0, 0) : new MemoryGroupIndex(group.BufferLength, group.Count - 1, group[group.Count - 1].Length); } } }