SimpleArray_T.java 9.99 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
/*
 * SimpleArray_T.java
 *
 * Copyright (C) 2003-2007 Peter Graves
 * $Id$
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * As a special exception, the copyright holders of this library give you
 * permission to link this library with independent modules to produce an
 * executable, regardless of the license terms of these independent
 * modules, and to copy and distribute the resulting executable under
 * terms of your choice, provided that you also meet, for each linked
 * independent module, the terms and conditions of the license of that
 * module.  An independent module is a module which is not derived from
 * or based on this library.  If you modify this library, you may extend
 * this exception to your version of the library, but you are not
 * obligated to do so.  If you do not wish to do so, delete this
 * exception statement from your version.
 */

package org.armedbear.lisp;

36 37
import static org.armedbear.lisp.Lisp.*;

38 39 40 41 42
public final class SimpleArray_T extends AbstractArray
{
  private final int[] dimv;
  private final LispObject elementType;
  private final int totalSize;
43
  final LispObject[] data;
44 45 46 47 48 49 50 51 52 53 54 55 56 57

  public SimpleArray_T(int[] dimv, LispObject elementType)
  {
    this.dimv = dimv;
    this.elementType = elementType;
    totalSize = computeTotalSize(dimv);
    data = new LispObject[totalSize];
    for (int i = totalSize; i-- > 0;)
      data[i] = Fixnum.ZERO;
  }

  public SimpleArray_T(int[] dimv,
                       LispObject elementType,
                       LispObject initialContents)
58

59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
  {
    this.dimv = dimv;
    this.elementType = elementType;
    final int rank = dimv.length;
    LispObject rest = initialContents;
    for (int i = 0; i < rank; i++)
      {
        dimv[i] = rest.length();
        rest = rest.elt(0);
      }
    totalSize = computeTotalSize(dimv);
    data = new LispObject[totalSize];
    setInitialContents(0, dimv, initialContents, 0);
  }

  public SimpleArray_T(int rank, LispObject initialContents)
75

76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
  {
    if (rank < 2)
      Debug.assertTrue(false);
    dimv = new int[rank];
    this.elementType = T;
    LispObject rest = initialContents;
    for (int i = 0; i < rank; i++)
      {
        dimv[i] = rest.length();
        if (rest == NIL || rest.length() == 0)
          break;
        rest = rest.elt(0);
      }
    totalSize = computeTotalSize(dimv);
    data = new LispObject[totalSize];
    setInitialContents(0, dimv, initialContents, 0);
  }

94 95 96 97 98 99 100 101
  public SimpleArray_T(final int[] dimv, final LispObject[] initialData,
          final LispObject elementType) {
      this.dimv = dimv;
      this.elementType = elementType;
      this.data = initialData;
      this.totalSize = computeTotalSize(dimv);
  }

102 103
  private int setInitialContents(int axis, int[] dims, LispObject contents,
                                 int index)
104

105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
  {
    if (dims.length == 0)
      {
        try
          {
            data[index] = contents;
          }
        catch (ArrayIndexOutOfBoundsException e)
          {
            error(new LispError("Bad initial contents for array."));
            return -1;
          }
        ++index;
      }
    else
      {
        int dim = dims[0];
        if (dim != contents.length())
          {
            error(new LispError("Bad initial contents for array."));
            return -1;
          }
        int[] newDims = new int[dims.length-1];
        for (int i = 1; i < dims.length; i++)
          newDims[i-1] = dims[i];
        if (contents.listp())
          {
            for (int i = contents.length();i-- > 0;)
              {
                LispObject content = contents.car();
                index =
                  setInitialContents(axis + 1, newDims, content, index);
                contents = contents.cdr();
              }
          }
        else
          {
            AbstractVector v = checkVector(contents);
            final int length = v.length();
            for (int i = 0; i < length; i++)
              {
                LispObject content = v.AREF(i);
                index =
                  setInitialContents(axis + 1, newDims, content, index);
              }
          }
      }
    return index;
  }

155
  @Override
156 157
  public LispObject typeOf()
  {
158
    return list(Symbol.SIMPLE_ARRAY, elementType, getDimensions());
159 160
  }

161
  @Override
162 163 164 165 166
  public LispObject classOf()
  {
    return BuiltInClass.SIMPLE_ARRAY;
  }

167
  @Override
168
  public LispObject typep(LispObject typeSpecifier)
169 170 171 172 173 174 175 176
  {
    if (typeSpecifier == Symbol.SIMPLE_ARRAY)
      return T;
    if (typeSpecifier == BuiltInClass.SIMPLE_ARRAY)
      return T;
    return super.typep(typeSpecifier);
  }

177
  @Override
178 179 180 181 182
  public int getRank()
  {
    return dimv.length;
  }

183
  @Override
184 185 186 187
  public LispObject getDimensions()
  {
    LispObject result = NIL;
    for (int i = dimv.length; i-- > 0;)
188
      result = new Cons(Fixnum.getInstance(dimv[i]), result);
189 190 191
    return result;
  }

192
  @Override
193
  public int getDimension(int n)
194 195 196 197 198 199 200 201 202 203 204 205
  {
    try
      {
        return dimv[n];
      }
    catch (ArrayIndexOutOfBoundsException e)
      {
        error(new TypeError("Bad array dimension " + n + "."));
        return -1;
      }
  }

206
  @Override
207 208 209 210 211
  public LispObject getElementType()
  {
    return elementType;
  }

212
  @Override
213 214 215 216 217
  public int getTotalSize()
  {
    return totalSize;
  }

218
  @Override
219 220 221 222 223
  public boolean isAdjustable()
  {
    return false;
  }

224
  @Override
225
  public LispObject AREF(int index)
226 227 228 229 230 231 232 233 234 235 236
  {
    try
      {
        return data[index];
      }
    catch (ArrayIndexOutOfBoundsException e)
      {
        return error(new TypeError("Bad row major index " + index + "."));
      }
  }

237
  @Override
238
  public void aset(int index, LispObject newValue)
239 240 241 242 243 244 245 246 247 248 249
  {
    try
      {
        data[index] = newValue;
      }
    catch (ArrayIndexOutOfBoundsException e)
      {
        error(new TypeError("Bad row major index " + index + "."));
      }
  }

250
  @Override
251
  public int getRowMajorIndex(int[] subscripts)
252 253 254 255
  {
    final int rank = dimv.length;
    if (rank != subscripts.length)
      {
256
        StringBuilder sb = new StringBuilder("Wrong number of subscripts (");
257 258 259 260
        sb.append(subscripts.length);
        sb.append(") for array of rank ");
        sb.append(rank);
        sb.append('.');
261
        program_error(sb.toString());
262 263 264 265 266 267 268 269 270 271 272
      }
    int sum = 0;
    int size = 1;
    for (int i = rank; i-- > 0;)
      {
        final int dim = dimv[i];
        final int lastSize = size;
        size *= dim;
        int n = subscripts[i];
        if (n < 0 || n >= dim)
          {
273
            StringBuilder sb = new StringBuilder("Invalid index ");
274 275 276 277
            sb.append(n);
            sb.append(" for array ");
            sb.append(this);
            sb.append('.');
278
            program_error(sb.toString());
279 280 281 282 283 284
          }
        sum += n * lastSize;
      }
    return sum;
  }

285
  @Override
286
  public LispObject get(int[] subscripts)
287 288 289 290 291 292 293 294 295 296 297 298
  {
    try
      {
        return data[getRowMajorIndex(subscripts)];
      }
    catch (ArrayIndexOutOfBoundsException e)
      {
        return error(new TypeError("Bad row major index " +
                                   getRowMajorIndex(subscripts) + "."));
      }
  }

299
  @Override
300
  public void set(int[] subscripts, LispObject newValue)
301

302 303 304 305 306 307 308 309 310 311 312 313
  {
    try
      {
        data[getRowMajorIndex(subscripts)] = newValue;
      }
    catch (ArrayIndexOutOfBoundsException e)
      {
        error(new TypeError("Bad row major index " +
                            getRowMajorIndex(subscripts) + "."));
      }
  }

314
  @Override
315 316 317 318 319 320
  public void fill(LispObject obj)
  {
    for (int i = totalSize; i-- > 0;)
      data[i] = obj;
  }

321
  @Override
322
  public String printObject()
323
  {
324
    return printObject(dimv);
325 326
  }

327
  @Override
328 329
  public AbstractArray adjustArray(int[] dimv, LispObject initialElement,
                                   LispObject initialContents)
330

331
  {
332
    if (initialContents != null)
333 334 335 336 337 338
      return new SimpleArray_T(dimv, elementType, initialContents);
    for (int i = 0; i < dimv.length; i++)
      {
        if (dimv[i] != this.dimv[i])
          {
            SimpleArray_T newArray = new SimpleArray_T(dimv, elementType);
339 340
            if (initialElement != null)
                newArray.fill(initialElement);
341 342 343 344
            copyArray(this, newArray);
            return newArray;
          }
      }
345 346 347
    // New dimensions are identical to old dimensions, yet
    // we're not mutable, so, we need to return a new array
    return new SimpleArray_T(dimv, data.clone(), elementType);
348 349 350
  }

  // Copy a1 to a2 for index tuples that are valid for both arrays.
351
  static void copyArray(AbstractArray a1, AbstractArray a2)
352

353 354 355 356 357 358 359 360 361
  {
    Debug.assertTrue(a1.getRank() == a2.getRank());
    int[] subscripts = new int[a1.getRank()];
    int axis = 0;
    copySubArray(a1, a2, subscripts, axis);
  }

  private static void copySubArray(AbstractArray a1, AbstractArray a2,
                                   int[] subscripts, int axis)
362

363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
  {
    if (axis < subscripts.length)
      {
        final int limit =
          Math.min(a1.getDimension(axis), a2.getDimension(axis));
        for (int i = 0; i < limit; i++)
          {
            subscripts[axis] = i;
            copySubArray(a1, a2, subscripts, axis + 1);
          }
      }
    else
      {
        int i1 = a1.getRowMajorIndex(subscripts);
        int i2 = a2.getRowMajorIndex(subscripts);
        a2.aset(i2, a1.AREF(i1));
      }
  }

382
  @Override
383 384 385 386 387 388
  public AbstractArray adjustArray(int[] dimv, AbstractArray displacedTo,
                                   int displacement)
  {
    return new ComplexArray(dimv, displacedTo, displacement);
  }
}