KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > python > core > PyArray


1 // Copyright (c) Corporation for National Research Initiatives
2
package org.python.core;
3
4 import java.io.ByteArrayInputStream JavaDoc;
5 import java.io.ByteArrayOutputStream JavaDoc;
6 import java.io.DataInputStream JavaDoc;
7 import java.io.DataOutputStream JavaDoc;
8 import java.io.EOFException JavaDoc;
9 import java.io.IOException JavaDoc;
10 import java.io.InputStream JavaDoc;
11 import java.io.OutputStream JavaDoc;
12 import java.lang.reflect.Array JavaDoc;
13
14 /**
15  * A wrapper class around native java arrays.
16  *
17  * Instances of PyArray are created either by java functions or
18  * directly by the jarray module.
19  * <p>
20  * See also the jarray module.
21  */

22 public class PyArray extends PySequence implements Cloneable JavaDoc, ClassDictInit {
23
24     protected Object JavaDoc data;
25     protected Class JavaDoc type;
26     protected String JavaDoc typecode;
27     protected ArrayDelegate delegate;
28
29     // PyArray can't extend anymore, so delegate
30
private class ArrayDelegate extends AbstractArray {
31         
32         final PyArray pyArray;
33         
34         private ArrayDelegate(PyArray pyArray) {
35             super((pyArray.data == null) ? 0 : Array.getLength(pyArray.data));
36             this.pyArray = pyArray;
37         }
38         
39         protected Object JavaDoc getArray() {
40             return pyArray.data;
41         }
42         protected void setArray(Object JavaDoc array) {
43             pyArray.data = array;
44         }
45         
46         protected void makeInsertSpace(int index) {
47             super.makeInsertSpace(index, 1);
48         }
49         
50         protected void makeInsertSpace(int index, int length) {
51             super.makeInsertSpace(index, length);
52         }
53         
54         public void remove(int index) {
55             super.remove(index);
56         }
57     }
58
59     private PyArray() {
60         // do nothing, shell instance
61
}
62     
63     public PyArray(PyArray toCopy) {
64         
65         data = toCopy.delegate.copyArray();
66         delegate = new ArrayDelegate(this);
67         type = toCopy.type;
68     }
69     
70     public PyArray(Class JavaDoc type, Object JavaDoc data) {
71         this.type = type;
72         this.data = data;
73         delegate = new ArrayDelegate(this);
74     }
75
76     public PyArray(Class JavaDoc type, int n) {
77         this(type, Array.newInstance(type, n));
78     }
79
80     public static PyArray zeros(int n, char typecode) {
81         PyArray array = zeros(n, char2class(typecode));
82         array.typecode = Character.toString(typecode);
83         return array;
84     }
85     
86     public static PyArray zeros(int n, Class JavaDoc ctype) {
87         PyArray array = new PyArray(ctype, n);
88         array.typecode = ctype.getName();
89         return array;
90     }
91
92     public static PyArray array(PyObject seq, char typecode) {
93         PyArray array = PyArray.array(seq, char2class(typecode));
94         array.typecode = Character.toString(typecode);
95         return array;
96     }
97     
98      /**
99    * Create a PyArray storing <em>ctype</em> types and being initialised
100    * with <em>initialiser</em>.
101    *
102    * @param init an initialiser for the array - can be PyString or
103    * PySequence (including PyArray) or iterable type.
104      * @param ctype <code>Class</code> type of the elements stored in the array.
105      * @return a new PyArray
106    */

107     public static PyArray array(PyObject init, Class JavaDoc ctype) {
108
109         PyArray array = new PyArray(ctype, 0);
110         array.typecode = ctype.getName();
111
112      array.extendInternal(init);
113
114      return array;
115     }
116
117   /**
118    * Adds (appends) two PyArrays together
119    *
120    * @param other a PyArray to be added to the instance
121    * @return the result of the addition as a new PyArray instance
122    */

123     public PyObject __add__(PyObject other) {
124         PyArray otherArr = null;
125         if (!(other instanceof PyArray)) {
126             throw Py.TypeError("can only append another array to an array");
127         }
128         otherArr = (PyArray)other;
129         if (!otherArr.type.equals(this.type)) {
130             throw Py.TypeError(
131                     "can only append arrays of the same type, " +
132                     "expected '" + this.type + ", found " + otherArr.type);
133         }
134         PyArray ret = new PyArray(this);
135         ret.delegate.appendArray(otherArr.delegate.copyArray());
136         return ret;
137     }
138     
139     /**
140      * Finds the attribute.
141      *
142      * @param name the name of the attribute of interest
143      * @return the value for the attribute of the specified name
144      */

145     public PyObject __findattr__(String JavaDoc name) {
146         if("typecode".equals(name)) {
147             return new PyString(getTypecode());
148         }
149         return super.__findattr__(name);
150     }
151
152   /**
153    * Length of the array
154    *
155    * @return number of elements in the array
156    */

157     public int __len__() {
158         return delegate.getSize();
159     }
160
161   /**
162    * String representation of PyArray
163    *
164    * @return string representation of PyArray
165    */

166     public PyString __repr__() {
167         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(128);
168         buf.append("array(").append(class2char(type)).append(",[");
169         for (int i=0; i<__len__()-1; i++) {
170             buf.append(pyget(i).__repr__().toString());
171             buf.append(", ");
172         }
173         if (__len__() > 0) {
174             buf.append(pyget(__len__()-1).__repr__().toString());
175         }
176         buf.append("]) ");
177         return new PyString(buf.toString());
178     }
179     
180     /**
181      *
182      * @param c target <em>Class</em> for the conversion
183      * @return Java object converted to required class type if possible.
184      */

185     public Object JavaDoc __tojava__(Class JavaDoc c) {
186         if (c == Object JavaDoc.class ||
187             (c.isArray() && c.getComponentType().isAssignableFrom(type)))
188         {
189             return data;
190         }
191         if (c.isInstance(this)) return this;
192         return Py.NoConversion;
193     }
194
195   /**
196    * Append new value x to the end of the array.
197    *
198    * @param value item to be appended to the array
199    */

200     public void append(PyObject value) {
201         // Currently, this is asymmetric with extend, which
202
// *will* do conversions like append(5.0) to an int array.
203
// Also, cpython 2.2 will do the append coersion. However,
204
// it is deprecated in cpython 2.3, so maybe we are just
205
// ahead of our time ;-)
206

207         int afterLast = delegate.getSize();
208         delegate.makeInsertSpace(afterLast);
209         try {
210           set(afterLast, value);
211         } catch (PyException e) {
212            delegate.setSize(afterLast);
213            throw new PyException(e.type, e.value);
214         }
215     }
216     
217     /**
218      * "Byteswap" all items of the array. This is only supported for values
219      * which are 1, 2, 4, or 8 bytes in size; for other types of values,
220      * RuntimeError is raised. It is useful when reading data from a file
221      * written on a machine with a different byte order.
222      */

223     public void byteswap() {
224         //unknown type - throw RuntimeError
225
if (getItemsize() == 0) {
226             throw Py.RuntimeError("don't know how to byteswap this array type");
227         }
228         
229         ByteSwapper.swap(data);
230     }
231
232   /**
233    * Initialised class dictionary
234    */

235     public static void classDictInit(PyObject dict) throws PyIgnoreMethodTag {
236         PySequence.classDictInit(dict);
237         dict.__setitem__("clone", null);
238         dict.__setitem__("classDictInit", null);
239     }
240
241   /**
242    * Implementation of <em>Cloneable</em> interface.
243    *
244    * @return copy of current PyArray
245    */

246     public Object JavaDoc clone() {
247         return new PyArray(this);
248     }
249
250     /**
251      * Converts a character code for the array type to a Java
252      * <code>Class</code>.<p />
253      *
254      * The following character codes and their native types are supported:<br />
255      * <table>
256      * <tr><td><strong>Type code</strong></td>
257      * <td><strong>native type</strong></td></tr>
258      * <tr><td>z</td><td><code>boolean</code></td></tr>
259      * <tr><td>c</td><td><code>char</code></td></tr>
260      * <tr><td>b</td><td><code>byte</code></td></tr>
261      * <tr><td>h</td><td><code>short</code></td></tr>
262      * <tr><td>i</td><td><code>int</code></td></tr>
263      * <tr><td>l</td><td><code>long</code></td></tr>
264      * <tr><td>f</td><td><code>float</code></td></tr>
265      * <tr><td>d</td><td><code>double</code></td></tr>
266      * </table>
267      * <p />
268      *
269      * @param type character code for the array type
270      *
271      * @return <code>Class</code> of the native type
272      */

273     public static Class JavaDoc char2class(char type) throws PyIgnoreMethodTag {
274         switch (type) {
275         case 'z':
276             return Boolean.TYPE;
277         case 'c':
278             return Character.TYPE;
279         case 'b':
280             return Byte.TYPE;
281         case 'h':
282             return Short.TYPE;
283         case 'i':
284             return Integer.TYPE;
285         case 'l':
286             return Long.TYPE;
287         case 'f':
288             return Float.TYPE;
289         case 'd':
290             return Double.TYPE;
291         default:
292             throw Py.ValueError("typecode must be in [zcbhilfd]");
293         }
294     }
295     
296     private static String JavaDoc class2char(Class JavaDoc cls) {
297         
298         if (cls.equals(Boolean.TYPE) ) return "'z'";
299         else if (cls.equals(Character.TYPE)) return "'c'";
300         else if (cls.equals(Byte.TYPE) ) return "'b'";
301         else if (cls.equals(Short.TYPE) ) return "'h'";
302         else if (cls.equals(Integer.TYPE) ) return "'i'";
303         else if (cls.equals(Long.TYPE) ) return "'l'";
304         else if (cls.equals(Float.TYPE) ) return "'f'";
305         else if (cls.equals(Double.TYPE) ) return "'d'";
306         else return cls.getName();
307     }
308
309   /**
310    * Return the number of occurrences of x in the array.
311    *
312    * @param value instances of the value to be counted
313    * @return number of time value was found in the array.
314    */

315     public PyObject count(PyObject value) {
316         // note: cpython does not raise type errors based on item type
317
int iCount = 0;
318         for (int i = 0; i < delegate.getSize(); i++) {
319             if (value.equals(Py.java2py(Array.get(data, i)))) iCount++;
320         }
321         return new PyInteger(iCount);
322     }
323     
324     /**
325      * Delete the element at position <em>i</em> from the array
326      *
327      * @param i index of the item to be deleted from the array
328      */

329     protected void del(int i) {
330         //Now the AbstractArray can support this:
331
//throw Py.TypeError("can't remove from array");
332
delegate.remove(i);
333     }
334     
335     /**
336      * Delete the slice defined by <em>start</em>, <em>stop</em> and
337      * <em>step</em> from the array.
338      *
339      * @param start starting index of slice
340      * @param stop finishing index of slice
341      * @param step stepping increment between start and stop
342      */

343     protected void delRange(int start, int stop, int step) {
344         // Now the AbstractArray can support this:
345
//throw Py.TypeError("can't remove from array");
346
if (step > 0 && stop < start) stop = start;
347         
348         if (step == 1) {
349             delegate.remove(start, stop);
350         } else {
351             int n = sliceLength(start, stop, step);
352
353             for (int i = start, j = 0; j < n; i += step, j++) {
354                 delegate.remove(i);
355             }
356         }
357     }
358
359     /**
360      * Append items from <em>iterable</em> to the end of the array. If iterable
361      * is another array, it must have exactly the same type code; if not,
362      * TypeError will be raised. If iterable is not an array, it must be
363      * iterable and its elements must be the right type to be appended to the
364      * array.
365      * Changed in version 2.4: Formerly, the argument could only be another
366      * array.
367      *
368      * @param iterable iterable object used to extend the array
369      */

370     public void extend(PyObject iterable) {
371      extendInternal(iterable);
372     }
373     
374     /**
375      * Internal extend function, provides basic interface for extending arrays.
376      * Handles specific cases of <em>iterable</em> being PyStrings or PyArrays.
377      * Default behaviour is to defer to
378      * {@link #extendInternalIter(PyObject) extendInternalIter }
379      *
380      * @param iterable object of type PyString, PyArray or any object that can
381      * be iterated over.
382      */

383     private void extendInternal(PyObject iterable) {
384
385      //string input
386
if (iterable instanceof PyString) {
387         fromstring( ((PyString)iterable).toString() );
388      
389      //PyArray input
390
} else if (iterable instanceof PyArray) {
391         PyArray source = (PyArray)iterable;
392         
393         if(! source.type.equals(this.type)) {
394               throw Py.TypeError(
395                  "can only extend with an array of the same kind");
396         }
397         
398         delegate.appendArray(source.delegate.copyArray());
399         
400      } else {
401            extendInternalIter(iterable);
402      }
403   }
404   
405     /**
406      * Internal extend function to process iterable objects.
407      *
408      * @param iterable any object that can be iterated over.
409      */

410     private void extendInternalIter(PyObject iterable) {
411      PyObject iter = iterable.__iter__();
412      PyObject item = null;
413   
414      // iterable object without a length property - cannot presize the
415
// array, so append each item
416
if (iterable.__findattr__("__len__") == null) {
417          for (int i = 0; (item = iter.__iternext__()) != null; i++) {
418              append(item);
419          }
420      } else {
421         
422         //create room
423
int last = delegate.getSize();
424         delegate.ensureCapacity(last + iterable.__len__() );
425         
426          for (int i = last; (item = iter.__iternext__()) != null; i++) {
427              set(i, item);
428              delegate.size++;
429          }
430      }
431      }
432     
433     /**
434      * Read <em>count</em> items (as machine values) from the file object
435      * <em>f</em> and append them to the end of the array. If less than
436      * <em>count</em> items are available, EOFError is raised, but the items
437      * that were available are still inserted into the array. <em>f</em> must
438      * be a real built-in file object; something else with a read() method
439      * won't do.
440      *
441      * @param f Python builtin file object to retrieve data
442      * @param count number of array elements to read
443      */

444     public void fromfile(PyObject f, int count) {
445      
446      //check for arg1 as file object
447
if(!(f instanceof PyFile)) {
448         throw Py.TypeError("arg1 must be open file");
449      }
450      
451      PyFile file = (PyFile)f;
452      
453      // check for read only
454
if (file.mode.indexOf("r") == -1) {
455         throw Py.TypeError("file needs to be in read mode");
456      }
457      
458      
459      // read the data via the PyFile
460
int readbytes = count * getItemsize();
461      String JavaDoc buffer = file.read(readbytes).toString();
462            
463      // load whatever was collected into the array
464
fromstring(buffer);
465      
466      // check for underflow
467
if (buffer.length() < readbytes) {
468         int readcount = buffer.length() / getItemsize();
469         throw Py.EOFError("not enough items in file. "+
470                        Integer.toString(count)+" requested, "+
471                        Integer.toString(readcount)+" actually read"
472            );
473      }
474     }
475     
476     /**
477      * Append items from the list. This is equivalent to
478      * "for x in list: a.append(x)"except that if there is a type error, the
479      * array is unchanged.
480      *
481      * @param obj input list object that will be appended to the array
482      */

483     public void fromlist(PyObject obj) {
484      //check for list
485
if(!(obj instanceof PyList))
486         throw Py.TypeError("expected list argument");
487      
488      //store the current size of the internal array
489
int size = delegate.getSize();
490      
491      try {
492         extendInternalIter(obj);
493      } catch (PyException e) {
494         //trap any exception - any error invalidates the whole list
495
delegate.setSize(size);
496         //re-throw
497
throw new PyException(e.type, e.value);
498      }
499     }
500     
501     /**
502      * Generic stream reader to read the entire contents of a stream into the
503      * array.
504      *
505      * @param is InputStream to source the data from
506      *
507      * @return number of primitives successfully read
508      *
509      * @throws IOException
510      * @throws EOFException
511      */

512     private int fromStream(InputStream JavaDoc is) throws IOException JavaDoc, EOFException JavaDoc {
513      return fromStream(is, is.available() / getItemsize());
514     }
515     
516     /**
517      * Generic stream reader to read <em>count</em> primitive types from a
518      * stream into the array.
519      *
520      * @param is InputStream to source the data from
521      * @param count number of primitive types to read from the stream
522      *
523      * @return number of primitives successfully read
524      *
525      * @throws IOException
526      * @throws EOFException
527      */

528     private int fromStream(InputStream JavaDoc is, int count) throws IOException JavaDoc, EOFException JavaDoc {
529     
530      DataInputStream JavaDoc dis = new DataInputStream JavaDoc(is);
531
532         // current number of items present
533
int origsize = delegate.getSize();
534         // position to start inserting into
535
int index = origsize;
536         
537         // create capacity for 'count' items
538
delegate.ensureCapacity(index + count);
539
540         if (type.isPrimitive()) {
541            
542         if (type == Boolean.TYPE) {
543            for (int i = 0; i < count; i++, index++) {
544               Array.setBoolean(data, index, dis.readBoolean());
545               delegate.size++;
546            }
547         } else if (type == Byte.TYPE) {
548            for (int i = 0; i < count; i++, index++) {
549               Array.setByte(data, index, dis.readByte());
550               delegate.size++;
551            }
552         } else if (type == Character.TYPE) {
553            for (int i = 0; i < count; i++, index++) {
554               Array.setChar(data, index, (char)dis.readByte());
555               delegate.size++;
556            }
557         } else if(type == Integer.TYPE) {
558            for (int i = 0; i < count; i++, index++) {
559               Array.setInt(data, index, dis.readInt());
560               delegate.size++;
561            }
562         } else if (type == Short.TYPE) {
563            for (int i = 0; i < count; i++, index++) {
564               Array.setShort(data, index, dis.readShort());
565               delegate.size++;
566            }
567         } else if (type == Long.TYPE) {
568            for (int i = 0; i < count; i++, index++) {
569               Array.setLong(data, index, dis.readLong());
570               delegate.size++;
571            }
572         } else if (type == Float.TYPE) {
573            for (int i = 0; i < count; i++, index++) {
574               Array.setFloat(data, index, dis.readFloat());
575               delegate.size++;
576            }
577         } else if (type == Double.TYPE) {
578            for (int i = 0; i < count; i++, index++) {
579               Array.setDouble(data, index, dis.readDouble());
580               delegate.size++;
581            }
582         }
583      }
584      dis.close();
585      
586      
587      return (index - origsize);
588   }
589     
590     /**
591      * Appends items from the string, interpreting the string as an array of
592      * machine values (as if it had been read from a file using the
593      * {@link #fromfile(PyObject, int) fromfile()} method).
594      *
595      * @param input string of bytes containing array data
596      */

597     public void fromstring(String JavaDoc input) {
598      
599      int itemsize = getItemsize();
600      int strlen = input.length();
601      if((strlen % itemsize) != 0) {
602         throw Py.ValueError("string length not a multiple of item size");
603      }
604      
605      ByteArrayInputStream JavaDoc bis = new ByteArrayInputStream JavaDoc(input.getBytes());
606      
607      int origsize = delegate.getSize();
608      
609      try {
610         fromStream(bis);
611      }
612      catch(EOFException JavaDoc e) {
613         //stubbed catch for fromStream throws
614
throw Py.EOFError("not enough items in string");
615      }
616      catch(IOException JavaDoc e) {
617         //discard anything successfully loaded
618
delegate.setSize(origsize);
619         throw Py.IOError(e);
620      }
621     }
622     
623     /**
624      * Get the element at position <em>i</em> from the array
625      *
626      * @param i index of the item to be retrieved from the array
627      */

628     protected PyObject pyget(int i) {
629         return Py.java2py(Array.get(data, i));
630     }
631     
632     /**
633      * Return the internal Java array storage of the PyArray instance
634      *
635      * @return the <code>Array</code> store.
636      */

637     public Object JavaDoc getArray() throws PyIgnoreMethodTag {
638         return delegate.copyArray();
639     }
640     
641     /**
642      * Getter for the storage size of the array's type.<p />
643      *
644      * The sizes returned by this method represent the number of bytes used
645      * to store the type. In the case of streams, this is the number of bytes
646      * written to, or read from a stream. For memory this value is the
647      * <em>minimum</em> number of bytes required to store the type.<p />
648      *
649      * This method is used by other methods to define read/write quanta from
650      * strings and streams. <p />
651      *
652      * Values returned are:<br />
653      * <table>
654      * <tr><td><strong>Type</strong></td> <td><strong>Size</strong></td></tr>
655      * <tr><td><code>boolean</code></td> <td>1</td></tr>
656      * <tr><td><code>byte</code></td> <td>1</td></tr>
657      * <tr><td><code>char</code></td> <td>1</td></tr>
658      * <tr><td><code>short</code></td> <td>2</td></tr>
659      * <tr><td><code>int</code></td> <td>4</td></tr>
660      * <tr><td><code>long</code></td> <td>8</td></tr>
661      * <tr><td><code>float</code></td> <td>4</td></tr>
662      * <tr><td><code>double</code></td> <td>8</td></tr>
663      * </table>
664      *
665      * @return number of bytes used to store array type.
666      */

667     public int getItemsize() {
668
669       if (type.isPrimitive()) {
670   
671         if (type == Boolean.TYPE)
672            return 1;
673            else if (type == Byte.TYPE)
674               return 1;
675            else if (type == Character.TYPE)
676               return 1;
677            else if (type == Short.TYPE)
678               return 2;
679            else if (type == Integer.TYPE)
680               return 4;
681            else if (type == Long.TYPE)
682               return 8;
683            else if (type == Float.TYPE)
684               return 4;
685            else if (type == Double.TYPE)
686               return 8;
687       }
688       
689       //return something here... could be a calculated size?
690
return 0;
691     }
692     
693     /**
694      * Retrieve a slice from the array specified by the <em>start</em>,
695      * <em>stop</em> and <em>step</em>.
696      *
697      * @param start start index of the slice
698      * @param stop stop index of the slice
699      * @param step stepping increment of the slice
700      * @return A new PyArray object containing the described slice
701      */

702     protected PyObject getslice(int start, int stop, int step) {
703         if (step > 0 && stop < start) stop = start;
704         int n = sliceLength(start, stop, step);
705
706         PyArray ret = new PyArray(type, n);
707         if (step == 1) {
708             System.arraycopy(data, start, ret.data, 0, n);
709             return ret;
710         }
711         for (int i = start, j = 0; j < n; i += step, j++) {
712             Array.set(ret.data, j, Array.get(data, i));
713         }
714         return ret;
715     }
716
717     /**
718      * Getter for the type code of the array.
719      * {@link #char2class(char) char2class} describes the possible type codes
720      * and their meaning.
721      *
722      * @return single character type code for the array
723      */

724     public String JavaDoc getTypecode() throws PyIgnoreMethodTag {
725         return typecode;
726     }
727
728     /**
729      * Return the smallest <em>i</em> such that <em>i</em> is the index of the
730      * first occurrence of <em>value</em> in the array.
731      *
732      * @param value value to find the index of
733      * @return index of the first occurance of <em>value</em>
734      */

735     public PyObject index(PyObject value) {
736         
737         int index = indexInternal(value);
738         if(index != -1) return new PyInteger(index);
739         
740         throw Py.ValueError("array.index(" + value + "): " + value +
741         " not found in array");
742      }
743
744     /**
745      * Return the smallest <em>i</em> such that <em>i</em> is the index of the
746      * first occurrence of <em>value</em> in the array.
747      *
748      * @param value value to find the index of
749      * @return index of the first occurance of <em>value</em>
750      */

751     private int indexInternal(PyObject value) {
752         // note: cpython does not raise type errors based on item type
753
for (int i = 0; i < delegate.getSize(); i++) {
754             if (value.equals(Py.java2py(Array.get(data, i)))) {
755                 return i;
756             }
757         }
758         return -1;
759     }
760
761   /**
762    * Insert a new item with value <em>value</em> in the array before position
763    * <em>index</em>. Negative values are treated as being relative to the end
764    * of the array.
765    *
766    * @param index insert position
767    * @param value value to be inserted into array
768    */

769     public void insert(int index, PyObject value) {
770         delegate.makeInsertSpace(index);
771         Array.set(data, index, Py.tojava(value, type));
772     }
773     
774     /**
775      * Removes the item with the index <em>index</em> from the array and
776      * returns it. The optional argument defaults to -1, so that by default
777      * the last item is removed and returned.
778      */

779     public PyObject pop() {
780         return pop(-1);
781     }
782     
783     /**
784      * Removes the item with the index <em>index</em> from the array and
785      * returns it. The optional argument defaults to -1, so that by default
786      * the last item is removed and returned.
787      *
788      * @param index array location to be popped from the array
789      * @return array element popped from index
790      */

791     public PyObject pop(int index) {
792         // todo: python-style error handling
793
index = (index < 0)
794               ? delegate.getSize() + index
795               : index;
796         PyObject ret = Py.java2py(Array.get(data, index));
797         delegate.remove(index);
798         return ret;
799     }
800     
801     /**
802      * Remove the first occurrence of <em>value</em> from the array.
803      *
804      * @param value array value to be removed
805      */

806     public void remove(PyObject value) {
807         int index = indexInternal(value) ;
808         if(index != -1) {
809             delegate.remove(index);
810             return;
811         }
812
813         throw Py.ValueError("array.remove(" + value + "): "
814                 + value + " not found in array");
815     }
816     
817   /**
818    * Repeat the array <em>count</em> times.
819    *
820    * @param count number of times to repeat the array
821    * @return A new PyArray object containing the source object repeated
822    * <em>count</em> times.
823    */

824     protected PyObject repeat(int count) {
825      Object JavaDoc arraycopy = delegate.copyArray();
826      
827      PyArray ret = new PyArray(type, 0);
828      
829      for(int i = 0; i < count; i++) {
830         ret.delegate.appendArray(arraycopy);
831      }
832         
833         return ret;
834     }
835     
836     /**
837      * Reverse the elements in the array
838      *
839      */

840     public void reverse() {
841         // build a new reversed array and set this.data to it when done
842
Object JavaDoc array = Array.newInstance(type, Array.getLength(data));
843         for(int i = 0, lastIndex = delegate.getSize() - 1; i <= lastIndex; i++) {
844             Array.set(array, lastIndex - i, Array.get(data, i));
845         }
846         data = array;
847     }
848     
849   /**
850    * Set an element in the array - the index needs to exist, this method does
851    * not automatically extend the array. See
852    * {@link AbstractArray#setSize(int) AbstractArray.setSize()} or
853    * {@link AbstractArray#ensureCapacity(int) AbstractArray.ensureCapacity()}
854    * for ways to extend capacity.<p />
855    *
856    * This code specifically checks for overflows of the integral types:
857    * byte, short, int and long.
858    *
859    * @param i index of the element to be set
860    * @param value value to set the element to
861    */

862     protected void set(int i, PyObject value) {
863         
864         //check for overflow of the integral types
865
if (type == Byte.TYPE) {
866         long val;
867         
868         try {
869            val = ((Long JavaDoc)value.__tojava__(Long.TYPE)).longValue();
870         } catch (ClassCastException JavaDoc e) {
871            throw Py.TypeError("Type not compatible with array type");
872         }
873         
874         if(val < Byte.MIN_VALUE) {
875            throw Py.OverflowError("value too small for " + type.getName());
876         } else if (val > Byte.MAX_VALUE) {
877            throw Py.OverflowError("value too large for " + type.getName());
878         }
879      } else if (type == Short.TYPE) {
880         long val;
881         
882         try {
883            val = ((Long JavaDoc)value.__tojava__(Long.TYPE)).longValue();
884         } catch (ClassCastException JavaDoc e) {
885            throw Py.TypeError("Type not compatible with array type");
886         }
887         
888         if(val < Short.MIN_VALUE) {
889            throw Py.OverflowError("value too small for " + type.getName());
890         } else if (val > Short.MAX_VALUE) {
891            throw Py.OverflowError("value too large for " + type.getName());
892         }
893      } else if (type == Integer.TYPE) {
894         long val;
895         
896         try {
897            val = ((Long JavaDoc)value.__tojava__(Long.TYPE)).longValue();
898         } catch (ClassCastException JavaDoc e) {
899            throw Py.TypeError("Type not compatible with array type");
900         }
901         
902         if(val < Integer.MIN_VALUE) {
903            throw Py.OverflowError("value too small for " + type.getName());
904         } else if (val > Integer.MAX_VALUE) {
905            throw Py.OverflowError("value too large for " + type.getName());
906         }
907      } else if (type == Long.TYPE) {
908         Object JavaDoc o;
909         try {
910            o = value.__tojava__(Long.TYPE);
911         } catch (ClassCastException JavaDoc e) {
912            throw Py.TypeError("Type not compatible with array type");
913         }
914         
915         if(o == Py.NoConversion) {
916            throw Py.OverflowError("value out of range for long");
917         }
918      }
919      
920         
921         Object JavaDoc o = Py.tojava(value, type);
922         if(o == Py.NoConversion) {
923            throw Py.TypeError("Type not compatible with array type");
924         }
925         
926         Array.set(data, i, o);
927     }
928
929   /**
930    * Sets a slice of the array. <em>value</em> can be a string (for
931    * <code>byte</code> and <code>char</code> types) or PyArray. If a PyArray,
932    * its type must be convertible into the type of the target PyArray.
933    *
934    * @param start start index of the delete slice
935    * @param stop end index of the delete slice
936    * @param step stepping increment of the slice
937    */

938     protected void setslice(int start, int stop, int step, PyObject value) {
939         if(type == Character.TYPE && value instanceof PyString) {
940             char[] chars = null;
941           //if (value instanceof PyString) {
942
if (step != 1) {
943                   throw Py.ValueError(
944                           "invalid bounds for setting from string");
945               }
946               chars = value.toString().toCharArray();
947   
948           //}
949
// else if (value instanceof PyArray &&
950
// ((PyArray)value).type == Character.TYPE) {
951
// PyArray other = (PyArray)value;
952
// chars = (char[])other.delegate.copyArray();
953
// }
954
int insertSpace = chars.length - (stop - start);
955           // adjust the array, either adding space or removing space
956
if(insertSpace > 0) {
957               delegate.makeInsertSpace(start, insertSpace);
958           } else if (insertSpace < 0) {
959               delegate.remove(start, -insertSpace + start - 1);
960           }
961           delegate.replaceSubArray(chars, start);
962              
963         } else {
964             if (value instanceof PyString && type == Byte.TYPE) {
965                 byte[] chars = value.toString().getBytes();
966                 if (chars.length == stop-start && step == 1) {
967                     System.arraycopy(chars, 0, data, start, chars.length);
968                 } else {
969                     throw Py.ValueError(
970                         "invalid bounds for setting from string");
971                 }
972             } else if(value instanceof PyArray){
973                 PyArray array = (PyArray)value;
974                 int insertSpace = array.delegate.getSize() - (stop - start);
975              // adjust the array, either adding space or removing space
976
// ...snapshot in case "value" is "this"
977
Object JavaDoc arrayCopy = array.delegate.copyArray();
978              if(insertSpace > 0) {
979                  delegate.makeInsertSpace(start, insertSpace);
980              } else if (insertSpace < 0) {
981                  delegate.remove(start, -insertSpace + start - 1);
982              }
983              try {
984                  delegate.replaceSubArray(arrayCopy, start);
985              } catch (IllegalArgumentException JavaDoc e) {
986                  throw Py.TypeError("Slice typecode '" + array.typecode +
987                          "' is not compatible with this array (typecode '"
988                          + this.typecode + "')");
989              }
990             }
991         }
992
993     }
994
995     /**
996      * Write all items (as machine values) to the file object <em>f</em>.
997      *
998      * @param f Python builtin file object to write data
999      */

1000    public void tofile(PyObject f) {
1001     
1002     if(!(f instanceof PyFile))
1003        throw Py.TypeError("arg must be open file");
1004        
1005     PyFile file = (PyFile)f;
1006
1007     if (file.mode.indexOf("w") == -1 && file.mode.indexOf("a") == -1) {
1008        throw Py.TypeError("file needs to be in write or append mode");
1009     }
1010
1011     //write via the PyFile
1012
String JavaDoc buffer = tostring();
1013     file.write(buffer);
1014    }
1015    
1016    /**
1017     * Convert the array to an ordinary list with the same items.
1018     *
1019     * @return array contents as a list
1020     */

1021  public PyObject tolist() {
1022     PyList list = new PyList();
1023     
1024     for (int i = 0; i < delegate.getSize(); i++) {
1025        list.append(Py.java2py(Array.get(data, i)));
1026     }
1027     
1028     return list;
1029  }
1030  
1031    /**
1032     * Generic stream writer to write the entire contents of the array to the
1033     * stream as primitive types.
1034     *
1035     * @param os OutputStream to sink the array data to
1036     *
1037     * @return number of primitives successfully written
1038     *
1039     * @throws IOException
1040     */

1041    private int toStream(OutputStream JavaDoc os) throws IOException JavaDoc {
1042     
1043     DataOutputStream JavaDoc dos = new DataOutputStream JavaDoc(os);
1044     
1045     if (type.isPrimitive()) {
1046     
1047        if (type == Boolean.TYPE) {
1048           for (int i = 0; i < delegate.getSize(); i++)
1049              dos.writeBoolean(Array.getBoolean(data, i));
1050        }
1051        else if (type == Byte.TYPE) {
1052           for (int i = 0; i < delegate.getSize(); i++)
1053              dos.writeByte(Array.getByte(data, i));
1054        }
1055        else if (type == Character.TYPE) {
1056           for (int i = 0; i < delegate.getSize(); i++)
1057              dos.writeByte((byte)Array.getChar(data, i));
1058        }
1059        else if(type == Integer.TYPE) {
1060           for (int i = 0; i < delegate.getSize(); i++)
1061              dos.writeInt(Array.getInt(data, i));
1062        }
1063        else if (type == Short.TYPE) {
1064           for (int i = 0; i < delegate.getSize(); i++)
1065              dos.writeShort(Array.getShort(data, i));
1066        }
1067        else if (type == Long.TYPE) {
1068           for (int i = 0; i < delegate.getSize(); i++)
1069              dos.writeLong(Array.getLong(data, i));
1070        }
1071        else if (type == Float.TYPE) {
1072           for (int i = 0; i < delegate.getSize(); i++)
1073              dos.writeFloat(Array.getFloat(data, i));
1074        }
1075        else if (type == Double.TYPE) {
1076           for (int i = 0; i < delegate.getSize(); i++)
1077              dos.writeDouble(Array.getDouble(data, i));
1078        }
1079     }
1080
1081     return dos.size();
1082    }
1083    
1084    /**
1085     * Convert the array to an array of machine values and return the string
1086     * representation (the same sequence of bytes that would be written to a
1087     * file by the {@link #tofile(PyObject) tofile()} method.)
1088     */

1089    public String JavaDoc tostring() {
1090     ByteArrayOutputStream JavaDoc bos = new ByteArrayOutputStream JavaDoc();
1091     
1092     try {
1093        toStream(bos);
1094     } catch (IOException JavaDoc e) {
1095        throw Py.IOError(e);
1096     }
1097        
1098        return new String JavaDoc(bos.toByteArray());
1099    }
1100    
1101}
1102
Popular Tags