1 package org.opentrafficsim.kpi.sampling;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Collections;
6 import java.util.Iterator;
7 import java.util.LinkedHashMap;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Spliterator;
11 import java.util.stream.Stream;
12
13 import org.djunits.Throw;
14
15
16
17
18
19
20
21
22
23
24
25 public class ListTable extends AbstractTable
26 {
27
28
29 private List<Record> records = Collections.synchronizedList(new ArrayList<>());
30
31
32 private Map<Column<?>, Integer> columnNumbers = new LinkedHashMap<>();
33
34
35 private Map<String, Integer> idNumbers = new LinkedHashMap<>();
36
37
38
39
40
41
42
43 public ListTable(final String id, final String description, final Collection<Column<?>> columns)
44 {
45 super(id, description, columns);
46 for (int index = 0; index < getColumns().size(); index++)
47 {
48 Column<?> column = getColumns().get(index);
49 this.columnNumbers.put(column, index);
50 this.idNumbers.put(column.getId(), index);
51 }
52 Throw.when(getNumberOfColumns() != this.idNumbers.size(), IllegalArgumentException.class,
53 "Duplicate column ids are not allowed.");
54 }
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 @Override
77 public Iterator<Record> iterator()
78 {
79 return this.records.iterator();
80 }
81
82
83 @Override
84 public boolean isEmpty()
85 {
86 return this.records.isEmpty();
87 }
88
89
90
91
92
93
94 public void addRecord(final Map<Column<?>, Object> data)
95 {
96 Throw.whenNull(data, "Data may not be null.");
97 Throw.when(data.size() != getNumberOfColumns(), IllegalArgumentException.class,
98 "Number of data columns doesn't match number of table columns.");
99 Object[] dataObjects = new Object[getNumberOfColumns()];
100 for (int index = 0; index < getColumns().size(); index++)
101 {
102 Column<?> column = getColumns().get(index);
103 Throw.when(!data.containsKey(column), IllegalArgumentException.class, "Missing data for column %s", column.getId());
104 Object value = data.get(column);
105 Throw.when(!column.getValueType().isAssignableFrom(value.getClass()), IllegalArgumentException.class,
106 "Data value for column %s is not of type %s, but of type %s.", column.getId(), column.getValueType(), value
107 .getClass());
108 dataObjects[index] = value;
109 }
110 this.records.add(new ListRecord(dataObjects));
111 }
112
113
114
115
116
117
118 public void addRecordByColumnIds(final Map<String, Object> data)
119 {
120 Throw.whenNull(data, "Data may not be null.");
121 Throw.when(data.size() != getNumberOfColumns(), IllegalArgumentException.class,
122 "Number of data columns doesn't match number of table columns.");
123 Object[] dataObjects = new Object[getNumberOfColumns()];
124 for (int index = 0; index < getColumns().size(); index++)
125 {
126 Column<?> column = getColumns().get(index);
127 Throw.when(!data.containsKey(column.getId()), IllegalArgumentException.class, "Missing data for column %s", column
128 .getId());
129 Object value = data.get(column.getId());
130 Class<?> dataClass = value.getClass();
131 Throw.when(!column.getValueType().isAssignableFrom(dataClass), IllegalArgumentException.class,
132 "Data value for column %s is not of type %s, but of type %s.", column.getId(), column.getValueType(),
133 dataClass);
134 dataObjects[index] = value;
135 }
136 this.records.add(new ListRecord(dataObjects));
137 }
138
139
140
141
142
143
144
145 public void addRecord(final Object[] data)
146 {
147 Throw.whenNull(data, "Data may not be null.");
148 Throw.when(data.length != getNumberOfColumns(), IllegalArgumentException.class,
149 "Number of data columns doesn't match number of table columns.");
150 Object[] dataObjects = new Object[getNumberOfColumns()];
151 for (int index = 0; index < getColumns().size(); index++)
152 {
153 Column<?> column = getColumns().get(index);
154 Class<?> dataClass = data[index].getClass();
155 Throw.when(!column.getValueType().isAssignableFrom(dataClass), IllegalArgumentException.class,
156 "Data value for column %s is not of type %s, but of type %s.", column.getId(), column.getValueType(),
157 dataClass);
158 dataObjects[index] = data[index];
159 }
160 this.records.add(new ListRecord(dataObjects));
161 }
162
163
164 public class ListRecord implements Record
165 {
166
167
168 private final Object[] values;
169
170
171
172
173
174 public ListRecord(final Object[] values)
175 {
176 this.values = values;
177 }
178
179
180 @SuppressWarnings({"unchecked", "synthetic-access"})
181 @Override
182 public <T> T getValue(final Column<T> column)
183 {
184 return (T) this.values[ListTable.this.columnNumbers.get(column)];
185 }
186
187
188 @SuppressWarnings("synthetic-access")
189 @Override
190 public Object getValue(final String id)
191 {
192 return this.values[ListTable.this.idNumbers.get(id)];
193 }
194
195 }
196
197 }