001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package org.openimaj.data.dataset; 031 032import java.util.AbstractList; 033 034import org.openimaj.data.identity.Identifiable; 035import org.openimaj.data.identity.IdentifiableObject; 036import org.openimaj.io.InputStreamObjectReader; 037import org.openimaj.io.ObjectReader; 038 039/** 040 * Base class for {@link ListDataset}s in which each instance is read with an 041 * {@link InputStreamObjectReader}. 042 * 043 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 044 * 045 * @param <INSTANCE> 046 * the type of instances in the dataset 047 * @param <SOURCE> 048 * the type of object that provides the data to create the instance 049 */ 050public abstract class ReadableListDataset<INSTANCE, SOURCE> extends AbstractList<INSTANCE> 051 implements 052 ListDataset<INSTANCE> 053{ 054 protected ObjectReader<INSTANCE, SOURCE> reader; 055 056 /** 057 * Construct with the given {@link ObjectReader}. 058 * 059 * @param reader 060 * the {@link InputStreamObjectReader}. 061 */ 062 public ReadableListDataset(ObjectReader<INSTANCE, SOURCE> reader) { 063 this.reader = reader; 064 } 065 066 @Override 067 public INSTANCE getRandomInstance() { 068 return getInstance((int) (Math.random() * size())); 069 } 070 071 @Override 072 public INSTANCE get(int index) { 073 return this.getInstance(index); 074 } 075 076 /** 077 * Get an identifier for the instance at the given index. By default this 078 * just returns the index converted to a {@link String}, but sub-classes 079 * should override to to something more sensible if possible. 080 * 081 * @param index 082 * the index 083 * @return the identifier of the instance at the given index 084 */ 085 public String getID(int index) { 086 return index + ""; 087 } 088 089 /** 090 * Get the index of the instance with the given ID, or -1 if it can't be 091 * found. 092 * 093 * @param id 094 * the ID string 095 * @return the index; or -1 if not found. 096 */ 097 public int indexOfID(String id) { 098 for (int i = 0; i < size(); i++) { 099 if (getID(i).equals(id)) 100 return i; 101 } 102 return -1; 103 } 104 105 @Override 106 public final int size() { 107 return numInstances(); 108 } 109 110 private class WrappedListDataset extends AbstractList<IdentifiableObject<INSTANCE>> 111 implements 112 ListDataset<IdentifiableObject<INSTANCE>> 113 { 114 private final ReadableListDataset<INSTANCE, SOURCE> internal; 115 116 WrappedListDataset(ReadableListDataset<INSTANCE, SOURCE> internal) { 117 this.internal = internal; 118 } 119 120 @Override 121 public IdentifiableObject<INSTANCE> getRandomInstance() { 122 final int index = (int) (Math.random() * size()); 123 124 return getInstance(index); 125 } 126 127 @Override 128 public IdentifiableObject<INSTANCE> getInstance(int index) { 129 return new IdentifiableObject<INSTANCE>(internal.getID(index), internal.getInstance(index)); 130 } 131 132 @Override 133 public IdentifiableObject<INSTANCE> get(int index) { 134 return getInstance(index); 135 } 136 137 @Override 138 public int size() { 139 return internal.size(); 140 } 141 142 @Override 143 public int numInstances() { 144 return internal.size(); 145 } 146 } 147 148 /** 149 * Create a view of this dataset in which the instances are wrapped up in 150 * {@link IdentifiableObject}s. The {@link #getID(int)} method is used to 151 * determine the identifier. 152 * 153 * @return a view of this dataset with {@link Identifiable}-wrapped 154 * instances 155 */ 156 public ListDataset<IdentifiableObject<INSTANCE>> toIdentifiable() { 157 return new WrappedListDataset(this); 158 } 159}