001/***************************************************************************** 002 * Copyright by The HDF Group. * 003 * Copyright by the Board of Trustees of the University of Illinois. * 004 * All rights reserved. * 005 * * 006 * This file is part of the HDF Java Products distribution. * 007 * The full copyright notice, including terms governing use, modification, * 008 * and redistribution, is contained in the files COPYING and Copyright.html. * 009 * COPYING can be found at the root of the source code distribution tree. * 010 * Or, see https://support.hdfgroup.org/products/licenses.html * 011 * If you do not have access to either file, you may request a copy from * 012 * help@hdfgroup.org. * 013 ****************************************************************************/ 014 015package hdf.object; 016 017/** 018 * A CompoundDS is a dataset with compound datatype. 019 * <p> 020 * A compound datatype is an aggregation of one or more datatypes. Each member 021 * of a compound type has a name which is unique within that type, and a 022 * datatype of that member in a compound datum. Compound datatypes can be nested, 023 * i.e. members of a compound datatype can be some other compound datatype. 024 * <p> 025 * For more details on compound datatypes, 026 * see <b> <a href="https://support.hdfgroup.org/HDF5/doc/UG/HDF5_Users_Guide-Responsive%20HTML5/index.html">HDF5 User's Guide</a> </b> 027 * <p> 028 * Since Java cannot handle C-structured compound data, data in a compound dataset 029 * is loaded in to an Java List. Each element of the list is a data array that 030 * corresponds to a compound field. The data is read/written by compound field. 031 * <p> 032 * For example, if compound dataset "comp" has the following nested structure, 033 * and member datatypes 034 * 035 * <pre> 036 * comp --> m01 (int) 037 * comp --> m02 (float) 038 * comp --> nest1 --> m11 (char) 039 * comp --> nest1 --> m12 (String) 040 * comp --> nest1 --> nest2 --> m21 (long) 041 * comp --> nest1 --> nest2 --> m22 (double) 042 * </pre> 043 * 044 * The data object is a Java list of six arrays: {int[], float[], char[], 045 * Stirng[], long[] and double[]}. 046 * 047 * 048 * @version 1.1 9/4/2007 049 * @author Peter X. Cao 050 */ 051public abstract class CompoundDS extends Dataset implements CompoundDataFormat { 052 private static final long serialVersionUID = -4880399929644095662L; 053 054 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CompoundDS.class); 055 056 /** 057 * A single character to separate the names of nested compound fields. An 058 * extended ASCII character, 0x95, is used to avoid common characters in 059 * compound names. 060 */ 061 public static final String SEPARATOR = "\u0095"; 062 063 /** 064 * The number of members of the compound dataset. 065 */ 066 protected int numberOfMembers; 067 068 /** 069 * The names of members of the compound dataset. 070 */ 071 protected String[] memberNames; 072 073 /** 074 * Returns array containing the total number of elements of the members of 075 * this compound dataset. 076 * <p> 077 * For example, a compound dataset COMP has members of A, B and C as 078 * 079 * <pre> 080 * COMP { 081 * int A; 082 * float B[5]; 083 * double C[2][3]; 084 * } 085 * </pre> 086 * 087 * memberOrders is an integer array of {1, 5, 6} to indicate that member A 088 * has one element, member B has 5 elements, and member C has 6 elements. 089 */ 090 protected int[] memberOrders; 091 092 /** 093 * The dimension sizes of each member. 094 * <p> 095 * The i-th element of the Object[] is an integer array (int[]) that 096 * contains the dimension sizes of the i-th member. 097 */ 098 protected transient Object[] memberDims; 099 100 /** 101 * The datatypes of compound members. 102 */ 103 protected Datatype[] memberTypes; 104 105 /** 106 * The array to store flags to indicate if a member of this compound 107 * dataset is selected for read/write. 108 * <p> 109 * If a member is selected, the read/write will perform on the member. 110 * Applications such as HDFView will only display the selected members of 111 * the compound dataset. 112 * 113 * <pre> 114 * For example, if a compound dataset has four members 115 * String[] memberNames = {"X", "Y", "Z", "TIME"}; 116 * and 117 * boolean[] isMemberSelected = {true, false, false, true}; 118 * members "X" and "TIME" are selected for read and write. 119 * </pre> 120 */ 121 protected boolean[] isMemberSelected; 122 123 /** 124 * Constructs a CompoundDS object with the given file, dataset name and path. 125 * <p> 126 * The dataset object represents an existing dataset in the file. For 127 * example, new H5CompoundDS(file, "dset1", "/g0/") constructs a dataset 128 * object that corresponds to the dataset, "dset1", at group "/g0/". 129 * <p> 130 * This object is usually constructed at FileFormat.open(), which loads the 131 * file structure and object information into memory. It is rarely used 132 * elsewhere. 133 * 134 * @param theFile 135 * the file that contains the dataset. 136 * @param dsName 137 * the name of the CompoundDS, e.g. "compDS". 138 * @param dsPath 139 * the full path of the CompoundDS, e.g. "/g1". 140 */ 141 public CompoundDS(FileFormat theFile, String dsName, String dsPath) { 142 this(theFile, dsName, dsPath, null); 143 } 144 145 /** 146 * @deprecated Not for public use in the future.<br> 147 * Using {@link #CompoundDS(FileFormat, String, String)} 148 * 149 * @param theFile 150 * the file that contains the dataset. 151 * @param dsName 152 * the name of the CompoundDS, e.g. "compDS". 153 * @param dsPath 154 * the full path of the CompoundDS, e.g. "/g1". 155 * @param oid 156 * the oid of the CompoundDS. 157 */ 158 @Deprecated 159 public CompoundDS(FileFormat theFile, String dsName, String dsPath, long[] oid) { 160 super(theFile, dsName, dsPath, oid); 161 162 numberOfMembers = 0; 163 memberNames = null; 164 isMemberSelected = null; 165 memberTypes = null; 166 } 167 168 /** 169 * Returns the number of members of the compound dataset. 170 * 171 * @return the number of members of the compound dataset. 172 */ 173 @Override 174 public final int getMemberCount() { 175 return numberOfMembers; 176 } 177 178 /** 179 * Returns the number of selected members of the compound dataset. 180 * 181 * Selected members are the compound fields which are selected for 182 * read/write. 183 * <p> 184 * For example, in a compound datatype of {int A, float B, char[] C}, 185 * users can choose to retrieve only {A, C} from the dataset. In this 186 * case, getSelectedMemberCount() returns two. 187 * 188 * @return the number of selected members. 189 */ 190 @Override 191 public final int getSelectedMemberCount() { 192 int count = 0; 193 194 if (isMemberSelected != null) { 195 for (int i = 0; i < isMemberSelected.length; i++) { 196 if (isMemberSelected[i]) { 197 count++; 198 } 199 } 200 } 201 log.trace("count of selected members={}", count); 202 203 return count; 204 } 205 206 /** 207 * Returns the names of the members of the compound dataset. The names of 208 * compound members are stored in an array of Strings. 209 * <p> 210 * For example, for a compound datatype of {int A, float B, char[] C} 211 * getMemberNames() returns ["A", "B", "C"}. 212 * 213 * @return the names of compound members. 214 */ 215 @Override 216 public final String[] getMemberNames() { 217 return memberNames; 218 } 219 220 /** 221 * Returns an array of the names of the selected members of the compound dataset. 222 * 223 * @return an array of the names of the selected members of the compound dataset. 224 */ 225 public final String[] getSelectedMemberNames() { 226 if (isMemberSelected == null) { 227 log.debug("getSelectedMemberNames(): isMemberSelected array is null"); 228 log.trace("getSelectedMemberNames(): finish"); 229 return memberNames; 230 } 231 232 int idx = 0; 233 String[] names = new String[getSelectedMemberCount()]; 234 for (int i = 0; i < isMemberSelected.length; i++) { 235 if (isMemberSelected[i]) { 236 names[idx++] = memberNames[i]; 237 } 238 } 239 240 return names; 241 } 242 243 /** 244 * Checks if a member of the compound dataset is selected for read/write. 245 * 246 * @param idx 247 * the index of compound member. 248 * 249 * @return true if the i-th memeber is selected; otherwise returns false. 250 */ 251 @Override 252 public final boolean isMemberSelected(int idx) { 253 if ((isMemberSelected != null) && (isMemberSelected.length > idx)) { 254 return isMemberSelected[idx]; 255 } 256 else { 257 return false; 258 } 259 } 260 261 /** 262 * Selects the i-th member for read/write. 263 * 264 * @param idx 265 * the index of compound member. 266 */ 267 @Override 268 public final void selectMember(int idx) { 269 if ((isMemberSelected != null) && (isMemberSelected.length > idx)) { 270 isMemberSelected[idx] = true; 271 } 272 } 273 274 /** 275 * Selects/deselects all members. 276 * 277 * @param selectAll 278 * The indicator to select or deselect all members. If true, all 279 * members are selected for read/write. If false, no member is 280 * selected for read/write. 281 */ 282 @Override 283 public final void setAllMemberSelection(boolean selectAll) { 284 if (isMemberSelected == null) { 285 return; 286 } 287 288 for (int i = 0; i < isMemberSelected.length; i++) { 289 isMemberSelected[i] = selectAll; 290 } 291 } 292 293 /** 294 * Returns array containing the total number of elements of the members of 295 * the compound dataset. 296 * <p> 297 * For example, a compound dataset COMP has members of A, B and C as 298 * 299 * <pre> 300 * COMP { 301 * int A; 302 * float B[5]; 303 * double C[2][3]; 304 * } 305 * </pre> 306 * 307 * getMemberOrders() will return an integer array of {1, 5, 6} to indicate 308 * that member A has one element, member B has 5 elements, and member C has 309 * 6 elements. 310 * 311 * @return the array containing the total number of elements of the members 312 * of compound. 313 */ 314 @Override 315 public final int[] getMemberOrders() { 316 return memberOrders; 317 } 318 319 /** 320 * Returns array containing the total number of elements of the selected 321 * members of the compound dataset. 322 * 323 * <p> 324 * For example, a compound dataset COMP has members of A, B and C as 325 * 326 * <pre> 327 * COMP { 328 * int A; 329 * float B[5]; 330 * double C[2][3]; 331 * } 332 * </pre> 333 * 334 * If A and B are selected, getSelectedMemberOrders() returns an array of 335 * {1, 5} 336 * 337 * @return array containing the total number of elements of the selected 338 * members of compound. 339 */ 340 @Override 341 public final int[] getSelectedMemberOrders() { 342 log.trace("getSelectedMemberOrders(): start"); 343 344 if (isMemberSelected == null) { 345 log.debug("getSelectedMemberOrders(): isMemberSelected array is null"); 346 log.trace("getSelectedMemberOrders(): finish"); 347 return memberOrders; 348 } 349 350 int idx = 0; 351 int[] orders = new int[getSelectedMemberCount()]; 352 for (int i = 0; i < isMemberSelected.length; i++) { 353 if (isMemberSelected[i]) { 354 orders[idx++] = memberOrders[i]; 355 } 356 } 357 358 log.trace("getSelectedMemberOrders(): finish"); 359 360 return orders; 361 } 362 363 /** 364 * Returns the dimension sizes of the i-th member. 365 * <p> 366 * For example, a compound dataset COMP has members of A, B and C as 367 * 368 * <pre> 369 * COMP { 370 * int A; 371 * float B[5]; 372 * double C[2][3]; 373 * } 374 * </pre> 375 * 376 * getMemberDims(2) returns an array of {2, 3}, while getMemberDims(1) 377 * returns an array of {5}, and getMemberDims(0) returns null. 378 * 379 * @param i the i-th member 380 * 381 * @return the dimension sizes of the i-th member, null if the compound 382 * member is not an array. 383 */ 384 @Override 385 public final int[] getMemberDims(int i) { 386 if (memberDims == null) { 387 return null; 388 } 389 return (int[]) memberDims[i]; 390 } 391 392 /** 393 * Returns an array of datatype objects of compound members. 394 * <p> 395 * Each member of a compound dataset has its own datatype. The datatype of a 396 * member can be atomic or other compound datatype (nested compound). 397 * Sub-classes set up the datatype objects at init(). 398 * <p> 399 * 400 * @return the array of datatype objects of the compound members. 401 */ 402 @Override 403 public final Datatype[] getMemberTypes() { 404 return memberTypes; 405 } 406 407 /** 408 * Returns an array of datatype objects of selected compound members. 409 * 410 * @return an array of datatype objects of selected compound members. 411 */ 412 @Override 413 public final Datatype[] getSelectedMemberTypes() { 414 log.trace("getSelectedMemberTypes(): start"); 415 416 if (isMemberSelected == null) { 417 log.debug("getSelectedMemberTypes(): isMemberSelected array is null"); 418 log.trace("getSelectedMemberTypes(): finish"); 419 return memberTypes; 420 } 421 422 int idx = 0; 423 Datatype[] types = new Datatype[getSelectedMemberCount()]; 424 for (int i = 0; i < isMemberSelected.length; i++) { 425 if (isMemberSelected[i]) { 426 types[idx++] = memberTypes[i]; 427 } 428 } 429 430 log.trace("getSelectedMemberTypes(): finish"); 431 432 return types; 433 } 434 435 /** 436 * @deprecated Not implemented for compound dataset. 437 */ 438 @Deprecated 439 @Override 440 public Dataset copy(Group pgroup, String name, long[] dims, Object data) 441 throws Exception { 442 throw new UnsupportedOperationException( 443 "Writing a subset of a compound dataset to a new dataset is not implemented."); 444 } 445}