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 }