AlignedArray.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. #region Copyright and License
  2. /*
  3. This file is part of FFTW.NET, a wrapper around the FFTW library for the .NET framework.
  4. Copyright (C) 2017 Tobias Meyer
  5. License: Microsoft Reciprocal License (MS-RL)
  6. */
  7. #endregion
  8. using System;
  9. using System.Numerics;
  10. using System.Runtime.InteropServices;
  11. namespace FFTW.NET
  12. {
  13. public class AlignedArray<T> : IPinnedArray<T>
  14. where T : struct
  15. {
  16. readonly byte[] _buffer;
  17. readonly PinnedGCHandle _pin;
  18. readonly int _alignment;
  19. readonly IntPtr _alignedPtr;
  20. readonly int _length;
  21. readonly int[] _lengths;
  22. public int Length => _length;
  23. public bool IsDisposed => !_pin.IsAllocated;
  24. public int Rank => _lengths.Length;
  25. public IntPtr Pointer => _alignedPtr;
  26. public AlignedArray(byte[] buffer, int alignment, params int[] lengths)
  27. {
  28. _buffer = buffer;
  29. _alignment = alignment;
  30. _length = Utils.GetTotalSize(lengths);
  31. _lengths = lengths;
  32. if (_length > buffer.Length / Marshal.SizeOf<T>())
  33. throw new ArgumentException($"Buffer is to small to hold array of size {nameof(lengths)}", nameof(buffer));
  34. _pin = PinnedGCHandle.Pin(buffer);
  35. long value = _pin.Pointer.ToInt64();
  36. int offset = alignment - (int)(value % alignment);
  37. _alignedPtr = new IntPtr(value + offset);
  38. int maxLength = (_buffer.Length - offset) / Marshal.SizeOf<T>();
  39. if (_length > maxLength)
  40. {
  41. _pin.Free();
  42. throw new ArgumentException($"Buffer is to small to hold array of size {nameof(lengths)}", nameof(buffer));
  43. }
  44. }
  45. public AlignedArray(int alignment, params int[] lengths)
  46. : this(GetBuffer(alignment, lengths), alignment, lengths) { }
  47. static byte[] GetBuffer(int alignment, int[] lengths)
  48. {
  49. long length = Marshal.SizeOf<T>();
  50. foreach (var n in lengths)
  51. length *= n;
  52. return new byte[length + alignment];
  53. }
  54. public void Dispose() => _pin.Free();
  55. public int GetLength(int dimension) => _lengths[dimension];
  56. public int[] GetSize()
  57. {
  58. int[] result = new int[Rank];
  59. Buffer.BlockCopy(_lengths, 0, result, 0, Rank * sizeof(int));
  60. return result;
  61. }
  62. protected virtual T GetCore(IntPtr ptr) => Marshal.PtrToStructure<T>(ptr);
  63. protected virtual void SetCore(T value, IntPtr ptr) => Marshal.StructureToPtr<T>(value, ptr, false);
  64. void VerifyRank(int rank)
  65. {
  66. if (rank != this.Rank)
  67. throw new InvalidOperationException($"Dimension mismatch: Rank is not {Rank}");
  68. }
  69. void VerifyNotDisposed()
  70. {
  71. if (!_pin.IsAllocated)
  72. throw new ObjectDisposedException(this.GetType().FullName);
  73. }
  74. public T this[int i1]
  75. {
  76. get
  77. {
  78. VerifyNotDisposed();
  79. VerifyRank(1);
  80. var ptr = this.Pointer + (i1 * Marshal.SizeOf<T>());
  81. return GetCore(ptr);
  82. }
  83. set
  84. {
  85. VerifyNotDisposed();
  86. VerifyRank(1);
  87. var ptr = this.Pointer + (i1 * Marshal.SizeOf<T>());
  88. SetCore(value, ptr);
  89. }
  90. }
  91. public T this[int i1, int i2]
  92. {
  93. get
  94. {
  95. VerifyNotDisposed();
  96. VerifyRank(2);
  97. var ptr = this.Pointer + (i2 + GetLength(1) * i1) * Marshal.SizeOf<T>();
  98. return GetCore(ptr);
  99. }
  100. set
  101. {
  102. VerifyNotDisposed();
  103. VerifyRank(2);
  104. var ptr = this.Pointer + (i2 + GetLength(1) * i1) * Marshal.SizeOf<T>();
  105. SetCore(value, ptr);
  106. }
  107. }
  108. public T this[int i1, int i2, int i3]
  109. {
  110. get
  111. {
  112. VerifyNotDisposed();
  113. VerifyRank(3);
  114. var ptr = this.Pointer + (i3 + GetLength(2) * (i2 + GetLength(1) * i1)) * Marshal.SizeOf<T>();
  115. return GetCore(ptr);
  116. }
  117. set
  118. {
  119. VerifyNotDisposed();
  120. VerifyRank(3);
  121. var ptr = this.Pointer + (i3 + GetLength(2) * (i2 + GetLength(1) * i1)) * Marshal.SizeOf<T>();
  122. SetCore(value, ptr);
  123. }
  124. }
  125. public T this[params int[] indices]
  126. {
  127. get
  128. {
  129. VerifyNotDisposed();
  130. VerifyRank(indices.Length);
  131. var ptr = new IntPtr(this.Pointer.ToInt64() + this.GetIndex(indices));
  132. return GetCore(ptr);
  133. }
  134. set
  135. {
  136. VerifyNotDisposed();
  137. VerifyRank(indices.Length);
  138. var ptr = new IntPtr(this.Pointer.ToInt64() + this.GetIndex(indices));
  139. SetCore(value, ptr);
  140. }
  141. }
  142. }
  143. public class AlignedArrayComplex : AlignedArray<Complex>
  144. {
  145. public AlignedArrayComplex(byte[] buffer, int alignment, params int[] lengths)
  146. : base(buffer, alignment, lengths) { }
  147. public AlignedArrayComplex(int alignment, params int[] lengths)
  148. : base(alignment, lengths) { }
  149. protected unsafe override Complex GetCore(IntPtr ptr) => *((Complex*)ptr.ToPointer());
  150. protected unsafe override void SetCore(Complex value, IntPtr ptr) => *((Complex*)ptr.ToPointer()) = value;
  151. }
  152. public class AlignedArrayDouble : AlignedArray<double>
  153. {
  154. public AlignedArrayDouble(byte[] buffer, int alignment, params int[] lengths)
  155. : base(buffer, alignment, lengths) { }
  156. public AlignedArrayDouble(int alignment, params int[] lengths)
  157. : base(alignment, lengths) { }
  158. protected unsafe override double GetCore(IntPtr ptr) => *((double*)ptr.ToPointer());
  159. protected unsafe override void SetCore(double value, IntPtr ptr) => *((double*)ptr.ToPointer()) = value;
  160. }
  161. }