001/* =========================================================== 002 * Orson Charts : a 3D chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C)opyright 2013-2022, by David Gilbert. All rights reserved. 006 * 007 * https://github.com/jfree/orson-charts 008 * 009 * This program is free software: you can redistribute it and/or modify 010 * it under the terms of the GNU General Public License as published by 011 * the Free Software Foundation, either version 3 of the License, or 012 * (at your option) any later version. 013 * 014 * This program is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public License 020 * along with this program. If not, see <http://www.gnu.org/licenses/>. 021 * 022 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 023 * Other names may be trademarks of their respective owners.] 024 * 025 * If you do not wish to be bound by the terms of the GPL, an alternative 026 * commercial license can be purchased. For details, please see visit the 027 * Orson Charts home page: 028 * 029 * http://www.object-refinery.com/orsoncharts/index.html 030 * 031 */ 032 033package org.jfree.chart3d.data; 034 035import java.io.Serializable; 036import java.util.ArrayList; 037import java.util.List; 038 039import org.jfree.chart3d.internal.Args; 040 041/** 042 * A list of {@code (key, value)} pairs. 043 * <br><br> 044 * This is the basic structure of the data required for a pie chart. 045 * <br><br> 046 * NOTE: This class is serializable, but the serialization format is subject 047 * to change in future releases and should not be relied upon for persisting 048 * instances of this class. 049 * 050 * @param <K> the key type (must implement Comparable). 051 * @param <T> the value type. 052 */ 053@SuppressWarnings("serial") 054public final class DefaultKeyedValues<K extends Comparable<K>, T> 055 implements KeyedValues<K, T>, Serializable { 056 057 /** Storage for the data items. */ 058 private List<KeyedValue<K, T>> data; 059 060 /** 061 * Creates a new (empty) list of keyed values. 062 */ 063 public DefaultKeyedValues() { 064 this(new ArrayList<>()); 065 } 066 067 /** 068 * Creates a new instance with the specified keys (each associated with 069 * a {@code null} value). There is usually no need to specify any 070 * keys in advance, so you will normally use the default constructor. This 071 * constructor is provided for the convenience of some internal code. 072 * 073 * @param keys the keys ({@code null} not permitted). 074 */ 075 public DefaultKeyedValues(List<K> keys) { 076 Args.nullNotPermitted(keys, "keys"); 077 this.data = new ArrayList<>(); 078 for (K key : keys) { 079 this.data.add(new DefaultKeyedValue<>(key, null)); 080 } 081 } 082 083 /** 084 * Clears all the data. 085 */ 086 public void clear() { 087 this.data.clear(); 088 } 089 090 /** 091 * Adds a value or, if there is an existing value with the same key, updates 092 * an existing value. 093 * 094 * @param key the key ({@code null} not permitted) 095 * @param value the value. 096 */ 097 public void put(K key, T value) { 098 Args.nullNotPermitted(key, "key"); 099 DefaultKeyedValue<K, T> dkv; 100 int index = getIndex(key); 101 if (index >= 0) { 102 dkv = (DefaultKeyedValue<K, T>) this.data.get(index); 103 dkv.setValue(value); 104 } else { 105 this.data.add(new DefaultKeyedValue<>(key, value)); 106 } 107 } 108 109 /** 110 * Removes the item with the specified key, if there is one. 111 * 112 * @param key the key ({@code null} not permitted). 113 */ 114 public void remove(K key) { 115 Args.nullNotPermitted(key, "key"); 116 int index = getIndex(key); 117 if (index >= 0) { 118 remove(index); 119 } 120 } 121 122 /** 123 * Removes the item with the specified index. 124 * 125 * @param index the index. 126 */ 127 public void remove(int index) { 128 this.data.remove(index); 129 } 130 131 /** 132 * Returns the key for the item with the specified index. 133 * 134 * @param index the item index. 135 * 136 * @return The key. 137 */ 138 @Override 139 public K getKey(int index) { 140 KeyedValue<K, T> kv = this.data.get(index); 141 return kv.getKey(); 142 } 143 144 /** 145 * Returns the index of the item with the specified key, or {@code -1} 146 * if there is no such item. 147 * 148 * @param key the key ({@code null} not permitted). 149 * 150 * @return The item index, or {@code -1}. 151 */ 152 @Override 153 public int getIndex(K key) { 154 Args.nullNotPermitted(key, "key"); 155 for (int i = 0; i < this.data.size(); i++) { 156 KeyedValue<K, T> kv = this.data.get(i); 157 if (kv.getKey().equals(key)) { 158 return i; 159 } 160 } 161 return -1; 162 } 163 164 /** 165 * Returns a list of all the keys. Note that the list will be a copy, so 166 * modifying it will not impact this data structure. 167 * 168 * @return A list of keys (possibly empty, but never {@code null}). 169 */ 170 @Override 171 public List<K> getKeys() { 172 List<K> keys = new ArrayList<>(); 173 for (KeyedValue<K, T> kv : this.data) { 174 keys.add(kv.getKey()); 175 } 176 return keys; 177 } 178 179 /** 180 * Returns the value with the specified key. 181 * 182 * @param key the key ({@code null} not permitted). 183 * 184 * @return The value (possibly {@code null}). 185 */ 186 @Override 187 public T getValue(K key) { 188 // arg checking is performed by getIndex() 189 int index = getIndex(key); 190 if (index < 0) { 191 return null; 192 } 193 return getValue(index); 194 } 195 196 /** 197 * Returns the number of items in the list. 198 * 199 * @return The number of items in the list. 200 */ 201 @Override 202 public int getItemCount() { 203 return this.data.size(); 204 } 205 206 /** 207 * Returns the value for the specified item. 208 * 209 * @param item the item index. 210 * 211 * @return The value (possibly {@code null}). 212 */ 213 @Override 214 public T getValue(int item) { 215 KeyedValue<K, T> kv = this.data.get(item); 216 return kv.getValue(); 217 } 218 219 /** 220 * Returns the value for the specified item, as a double primitive, 221 * provided that the data value is an instance of {@code Number}. 222 * 223 * @param item the item index. 224 * 225 * @return The value. 226 */ 227 @Override 228 public double getDoubleValue(int item) { 229 T n = getValue(item); 230 if (n != null && n instanceof Number) { 231 return ((Number) n).doubleValue(); 232 } 233 return Double.NaN; 234 } 235 236 /** 237 * Tests this instance for equality with an arbitrary object. 238 * 239 * @param obj the object to test against ({@code null} permitted). 240 * 241 * @return A boolean. 242 */ 243 @Override 244 public boolean equals(Object obj) { 245 if (obj == this) { 246 return true; 247 } 248 if (!(obj instanceof DefaultKeyedValues<?, ?>)) { 249 return false; 250 } 251 DefaultKeyedValues<?, ?> that = (DefaultKeyedValues<?, ?>) obj; 252 if (!this.data.equals(that.data)) { 253 return false; 254 } 255 return true; 256 } 257}