001    /*
002     * Copyright (C) 2008-2010 by Holger Arndt
003     *
004     * This file is part of the Universal Java Matrix Package (UJMP).
005     * See the NOTICE file distributed with this work for additional
006     * information regarding copyright ownership and licensing.
007     *
008     * UJMP is free software; you can redistribute it and/or modify
009     * it under the terms of the GNU Lesser General Public License as
010     * published by the Free Software Foundation; either version 2
011     * of the License, or (at your option) any later version.
012     *
013     * UJMP is distributed in the hope that it will be useful,
014     * but WITHOUT ANY WARRANTY; without even the implied warranty of
015     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016     * GNU Lesser General Public License for more details.
017     *
018     * You should have received a copy of the GNU Lesser General Public
019     * License along with UJMP; if not, write to the
020     * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
021     * Boston, MA  02110-1301  USA
022     */
023    
024    package org.ujmp.core.objectmatrix.impl;
025    
026    import java.io.Flushable;
027    import java.io.IOException;
028    import java.util.Collections;
029    import java.util.HashSet;
030    import java.util.Set;
031    
032    import org.ujmp.core.Coordinates;
033    import org.ujmp.core.Matrix;
034    import org.ujmp.core.exceptions.MatrixException;
035    import org.ujmp.core.objectmatrix.stub.AbstractSparseObjectMatrix;
036    
037    public class BufferedObjectMatrix extends AbstractSparseObjectMatrix implements Flushable {
038            private static final long serialVersionUID = 7750549087897737457L;
039    
040            private Matrix inputBuffer = null;
041    
042            private Set<Coordinates> outputBuffer = null;
043    
044            private int outputBufferSize = Integer.MAX_VALUE;
045    
046            private Matrix original = null;
047    
048            private Thread writeThread = null;
049    
050            private static final EmptyObject EMPTYOBJECT = new EmptyObject();
051    
052            public BufferedObjectMatrix(Matrix original) {
053                    this.original = original;
054                    setInputBufferSize(0);
055                    setOutputBufferSize(Integer.MAX_VALUE);
056                    writeThread = new WriteThread();
057                    writeThread.start();
058            }
059    
060            public BufferedObjectMatrix(Matrix original, int outputBufferSize) {
061                    this.original = original;
062                    setInputBufferSize(0);
063                    setOutputBufferSize(outputBufferSize);
064            }
065    
066            public BufferedObjectMatrix(Matrix original, int outputBufferSize, int inputBufferSize) {
067                    this.original = original;
068                    setInputBufferSize(inputBufferSize);
069                    setOutputBufferSize(outputBufferSize);
070            }
071    
072            public synchronized long[] getSize() {
073                    return inputBuffer.getSize();
074            }
075    
076            public synchronized Object getObject(long... coordinates) throws MatrixException {
077                    Object o = null;
078                    o = inputBuffer.getAsObject(coordinates);
079                    if (o == null) {
080                            o = original.getAsObject(coordinates);
081                            if (o == null) {
082                                    inputBuffer.setAsObject(EMPTYOBJECT, coordinates);
083                            } else {
084                                    inputBuffer.setAsObject(o, coordinates);
085                            }
086                    } else if (o == EMPTYOBJECT) {
087                            return null;
088                    }
089                    return o;
090            }
091    
092            public synchronized long getValueCount() {
093                    return original.getValueCount();
094            }
095    
096            public synchronized void setObject(Object value, long... coordinates) throws MatrixException {
097                    inputBuffer.setAsObject(value, coordinates);
098                    outputBuffer.add(new Coordinates(coordinates));
099            }
100    
101            public synchronized void setInputBufferSize(int numElements) {
102                    if (numElements < 1) {
103                            inputBuffer = new VolatileSparseObjectMatrix(original.getSize());
104                    } else {
105                            inputBuffer = new DefaultSparseObjectMatrix(numElements, original.getSize());
106                    }
107            }
108    
109            public synchronized void setOutputBufferSize(int numElements) {
110                    try {
111                            flush();
112                            outputBuffer = Collections.synchronizedSet(new HashSet<Coordinates>());
113                            outputBufferSize = numElements;
114                    } catch (IOException e) {
115                            throw new MatrixException("could not set output buffer", e);
116                    }
117            }
118    
119            public synchronized void flush() throws IOException {
120                    while (outputBuffer != null && outputBuffer.size() != 0) {
121                            try {
122                                    outputBuffer.wait();
123                            } catch (InterruptedException e) {
124                                    throw new MatrixException("could not flush buffer", e);
125                            }
126                    }
127            }
128    
129            public synchronized int getOutputBufferSize() {
130                    return outputBufferSize;
131            }
132    
133            class WriteThread extends Thread {
134    
135                    public void run() {
136                            while (true) {
137                                    try {
138                                            while (outputBuffer != null && !outputBuffer.isEmpty()) {
139                                                    Coordinates c = outputBuffer.iterator().next();
140                                                    outputBuffer.remove(c);
141                                                    double value = inputBuffer.getAsDouble(c.co);
142                                                    original.setAsDouble(value, c.co);
143                                            }
144                                            Thread.sleep(100);
145                                    } catch (Exception e) {
146                                            throw new MatrixException("error writing to matrix", e);
147                                    }
148                            }
149                    }
150            }
151    
152            public boolean contains(long... coordinates) {
153                    return inputBuffer.contains(coordinates) || original.contains(coordinates);
154            }
155    
156            public boolean isReadOnly() {
157                    return original.isReadOnly();
158            }
159    
160    }
161    
162    class EmptyObject {
163    }