GeneralArray.java 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. // Copyright (c) 2001, 2002, 2016 Per M.A. Bothner and Brainfood Inc.
  2. // This is free software; for terms and warranty disclaimer see ./COPYING.
  3. package gnu.lists;
  4. import static gnu.lists.AbstractSequence.noInts;
  5. /** A class to handle general multi-dimensional arrays.
  6. * If the number of dimensions (the "rank") is one, should use
  7. * a class that implements Sequence.
  8. * GeneralArray uses a SimpleVector 'base' to store the actual data, and
  9. * provides general linear mapping from the array indexes to an
  10. * element index in the 'base' SimpleVector. Thus such uperations as
  11. * transposing an array can be implement as just creating a simple
  12. * re-mapping of the indexes. */
  13. public class GeneralArray<E> extends TransformedArray<E>
  14. {
  15. int[] dimensions;
  16. int[] strides;
  17. int[] lowBounds;
  18. static final int[] zeros = new int[8];
  19. int offset;
  20. boolean simple;
  21. protected int nextIndex(int ipos) { return ipos>>>1; }
  22. // deprecated?
  23. public static Array makeSimple(int[] lowBounds, int[] dimensions,
  24. SimpleVector base) {
  25. int d = dimensions.length;
  26. if (d == 1 && (lowBounds == null || lowBounds[0] == 0))
  27. return base;
  28. return new GeneralArray(base, dimensions, lowBounds);
  29. }
  30. public GeneralArray() {
  31. }
  32. public GeneralArray(int[] dimensions) {
  33. init(new FVector(getSize(dimensions)), dimensions, null, null, 0);
  34. }
  35. public GeneralArray(AVector<E> base, int[] dimensions, int[] lowBounds,
  36. int[] strides, int offset) {
  37. init(base, dimensions, lowBounds, strides, offset);
  38. }
  39. public GeneralArray(AVector<E> base, int[] dimensions, int[] lowBounds) {
  40. init(base, dimensions, lowBounds, null, 0);
  41. }
  42. protected void init(AVector<E> base, int[] dimensions, int[] lowBounds,
  43. int[] strides, int offset) {
  44. this.base = base;
  45. simple = strides == null && offset == 0;
  46. int d = dimensions.length;
  47. if (lowBounds == null) {
  48. lowBounds = zeros;
  49. if (d > lowBounds.length)
  50. lowBounds = new int[d];
  51. }
  52. if (strides == null) {
  53. strides = new int[d];
  54. int n = 1;
  55. for (int i = d; --i >= 0; ) {
  56. strides[i] = n;
  57. n *= dimensions[i];
  58. }
  59. }
  60. this.strides = strides;
  61. this.dimensions = dimensions;
  62. this.lowBounds = lowBounds;
  63. this.offset = offset;
  64. }
  65. private static int getSize(int[] dimensions) {
  66. int sz = 1;
  67. for (int i = dimensions.length; --i >= 0; )
  68. sz *= dimensions[i];
  69. return sz;
  70. }
  71. public static<E> GeneralArray<E> make0(AVector<E> base) {
  72. return make(base, noInts, noInts, noInts, 0);
  73. }
  74. public static<E> GeneralArray<E> make(AVector<E> base, int[] dimensions,
  75. int[] lowBounds,
  76. int[] strides, int offset) {
  77. GeneralArray array =
  78. dimensions.length == 1 && (lowBounds == null || lowBounds[0] == 0)
  79. ? new GeneralArray1()
  80. : new GeneralArray();
  81. array.init(base, dimensions, lowBounds, strides, offset);
  82. return array;
  83. }
  84. public AVector<E> getBase() { return (AVector<E>) base; }
  85. public void setBase(AVector<E> base) {
  86. if (this.base != null)
  87. throw new IllegalStateException();
  88. this.base = base;
  89. }
  90. public void setBase(E[] data) {
  91. setBase(new FVector(data));
  92. }
  93. public void setStrides(int[] strides, int offset) {
  94. this.strides = strides;
  95. this.offset = offset;
  96. }
  97. public int[] getDimensions() { return dimensions; }
  98. public int[] getLowBounds() { return lowBounds; }
  99. public int rank() { return dimensions.length; }
  100. @Override
  101. public int effectiveIndex() {
  102. checkRank(0);
  103. return base.effectiveIndex(offset);
  104. }
  105. @Override
  106. public int effectiveIndex(int i) {
  107. checkRank(1);
  108. int low = lowBounds[0];
  109. if (i < low || (i -= low) >= dimensions[0])
  110. throw new IndexOutOfBoundsException();
  111. return base.effectiveIndex(offset + strides[0] * i);
  112. }
  113. @Override
  114. public int effectiveIndex(int i, int j) {
  115. checkRank(2);
  116. int result = offset;
  117. int low = lowBounds[0];
  118. if (i < low || (i -= low) >= dimensions[0])
  119. throw new IndexOutOfBoundsException();
  120. result += strides[0] * i;
  121. low = lowBounds[1];
  122. if (j < low || (j -= low) >= dimensions[1])
  123. throw new IndexOutOfBoundsException();
  124. result += strides[1] * j;
  125. return base.effectiveIndex(result);
  126. }
  127. @Override
  128. public int effectiveIndex(int i, int j, int k, int... rest) {
  129. checkRank(rest.length+3);
  130. int result = offset;
  131. int low = lowBounds[0];
  132. if (i < low || (i -= low) >= dimensions[0])
  133. throw new IndexOutOfBoundsException();
  134. result += strides[0] * i;
  135. low = lowBounds[1];
  136. if (j < low || (j -= low) >= dimensions[1])
  137. throw new IndexOutOfBoundsException();
  138. result += strides[1] * j;
  139. low = lowBounds[2];
  140. if (k < low || (k -= low) >= dimensions[2])
  141. throw new IndexOutOfBoundsException();
  142. result += strides[2] * k;
  143. for (int d = rest.length; --d >= 0; ) {
  144. int index = rest[d];
  145. low = lowBounds[d+3];
  146. if (index < low || (index -= low) >= dimensions[d+3])
  147. throw new IndexOutOfBoundsException();
  148. result += strides[d+3] * index;
  149. }
  150. return result;
  151. }
  152. /** Calculate corresponding index in base array.
  153. * effectiveIndex[indexes] == base.effectiveIndex(resolve[indexes]) */
  154. public int resolve(int[] indexes)
  155. {
  156. int result = offset;
  157. for (int i = dimensions.length; --i >= 0; )
  158. {
  159. int index = indexes[i];
  160. int low = lowBounds[i];
  161. if (index < low || (index -= low) >= dimensions[i])
  162. throw new IndexOutOfBoundsException();
  163. result += strides[i] * index;
  164. }
  165. return result;
  166. }
  167. /*
  168. public int createPos(int index, boolean isAfter)
  169. {
  170. int total = offset;
  171. for (int i = dimensions.length; --i >= 0; )
  172. {
  173. int dim = dimensions[i];
  174. int cur = index % dim;
  175. index = index / dim;
  176. total = total + strides[i] * cur;
  177. }
  178. return (total << 1) | (isAfter ? 1 : 0);
  179. }
  180. */
  181. public E get(int[] indexes)
  182. {
  183. return (E) base.getRaw(effectiveIndex(indexes));
  184. }
  185. /** See java.util.Collection. */
  186. public int size()
  187. {
  188. int total = 1;
  189. for (int i = dimensions.length; --i >= 0; )
  190. total *= dimensions[i];
  191. return total;
  192. }
  193. public int getLowBound(int dim)
  194. {
  195. return lowBounds[dim];
  196. }
  197. public int getSize(int dim)
  198. {
  199. return dimensions[dim];
  200. }
  201. public static void toString (Array array, StringBuffer sbuf)
  202. {
  203. sbuf.append("#<array");
  204. int r = array.rank();
  205. for (int i = 0; i < r; i++)
  206. {
  207. sbuf.append(' ');
  208. int lo = array.getLowBound(i);
  209. int sz = array.getSize(i);
  210. if (lo != 0)
  211. {
  212. sbuf.append(lo);
  213. sbuf.append(':');
  214. }
  215. sbuf.append(lo+sz);
  216. }
  217. sbuf.append('>');
  218. }
  219. public String getTag() {
  220. if (base instanceof SimpleVector)
  221. return ((SimpleVector) base).getTag();
  222. else
  223. return null;
  224. }
  225. public String toString ()
  226. {
  227. StringBuffer sbuf = new StringBuffer();
  228. toString(this, sbuf);
  229. return sbuf.toString();
  230. }
  231. }