Skip to content

Commit 1bbe998

Browse files
committed
SonarQube cleanup
1 parent c0a0baf commit 1bbe998

File tree

4 files changed

+218
-136
lines changed

4 files changed

+218
-136
lines changed

src/main/java/org/hdf5javalib/datatype/FloatingPointDatatype.java

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -318,40 +318,71 @@ private long getRawField(long workingBits, int size, int location) {
318318

319319
/**
320320
* 3. Interprets the components to handle special cases and calculate the final double value.
321-
* CC: 7
321+
* CC: 3 (Refactored from 17)
322322
*/
323323
private double interpretComponents(ComponentValues components) {
324+
// Special case: Exponent is all 1s (NaN or Infinity)
324325
boolean allExponentBitsSet = this.exponentSize > 0 &&
325-
components.rawExponent() == ((1L << this.exponentSize) - 1); // +1 for &&
326+
components.rawExponent() == ((1L << this.exponentSize) - 1);
326327

327-
// Check for NaN or Infinity (Special Exponent Case)
328-
if (allExponentBitsSet) { // +1
329-
if (components.rawMantissa() != 0) return Double.NaN; // +1
330-
return (components.sign() == 1) ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY; // +1 (ternary)
328+
if (allExponentBitsSet) {
329+
return handleInfinityOrNaN(components);
331330
}
332331

333-
// Check for True Zero
334-
boolean isTrueZero = (this.exponentSize == 0 || components.rawExponent() == 0) && // +1 for ||
335-
(this.mantissaSize == 0 || components.rawMantissa() == 0); // +1 for ||
336-
if (isTrueZero) return components.sign() * 0.0; // +1
337-
338-
// Normal and Denormalized Cases
339-
int exponent = (int) (components.rawExponent() - this.exponentBias);
332+
// Handle Zero, Denormalized, and Normalized cases based on the exponent value
333+
if (components.rawExponent() == 0) {
334+
return handleZeroOrDenormalized(components);
335+
} else {
336+
return handleNormalized(components);
337+
}
338+
}
340339

341-
boolean isDenormalizedSource = (this.exponentSize > 0 && components.rawExponent() == 0 && components.rawMantissa() != 0); // +1 for &&
340+
/**
341+
* Handles the case where the exponent bits are all set, returning NaN or Infinity.
342+
*
343+
* @param components The extracted sign, exponent, and mantissa.
344+
* @return Double.NaN, Double.POSITIVE_INFINITY, or Double.NEGATIVE_INFINITY.
345+
*/
346+
private double handleInfinityOrNaN(ComponentValues components) {
347+
// Mantissa != 0 -> NaN
348+
if (components.rawMantissa() != 0) {
349+
return Double.NaN;
350+
}
351+
// Mantissa == 0 -> Infinity
352+
return (components.sign() == 1) ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY;
353+
}
342354

343-
double mantissaValue;
344-
if (isDenormalizedSource) { // +1
345-
mantissaValue = (this.mantissaSize == 0) ? 0.0 : (double) components.rawMantissa() / (1L << this.mantissaSize); // +1 (ternary)
346-
exponent = 1 - this.exponentBias;
347-
} else {
348-
// Normalized number: implicit leading 1
349-
mantissaValue = 1.0;
350-
if (this.mantissaSize > 0) { // +1
351-
mantissaValue = 1.0 + (double) components.rawMantissa() / (1L << this.mantissaSize);
352-
}
355+
/**
356+
* Handles cases where the raw exponent is zero, which can be a true zero or a denormalized number.
357+
*
358+
* @param components The extracted sign, exponent, and mantissa.
359+
* @return The calculated double value for zero or denormalized numbers.
360+
*/
361+
private double handleZeroOrDenormalized(ComponentValues components) {
362+
// True Zero
363+
if (components.rawMantissa() == 0) {
364+
return components.sign() * 0.0;
353365
}
354366

367+
// Denormalized number
368+
double mantissaValue = (this.mantissaSize == 0) ? 0.0 : (double) components.rawMantissa() / (1L << this.mantissaSize);
369+
int exponent = 1 - this.exponentBias;
370+
return components.sign() * mantissaValue * Math.pow(2, exponent);
371+
}
372+
373+
/**
374+
* Handles the calculation for a standard, normalized floating-point number.
375+
*
376+
* @param components The extracted sign, exponent, and mantissa.
377+
* @return The calculated double value for a normalized number.
378+
*/
379+
private double handleNormalized(ComponentValues components) {
380+
int exponent = (int) (components.rawExponent() - this.exponentBias);
381+
// Normalized number: implicit leading 1
382+
double mantissaValue = 1.0;
383+
if (this.mantissaSize > 0) {
384+
mantissaValue += (double) components.rawMantissa() / (1L << this.mantissaSize);
385+
}
355386
return components.sign() * mantissaValue * Math.pow(2, exponent);
356387
}
357388

src/main/java/org/hdf5javalib/hdffile/infrastructure/fractalheap/FractalHeap.java

Lines changed: 100 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -334,100 +334,142 @@ private static Block readDirectBlock(SeekableByteChannel channel, FractalHeapHea
334334
return db;
335335
}
336336

337-
private static Block readIndirectBlock(SeekableByteChannel channel, FractalHeapHeader header, FixedPointDatatype sizeOfOffset, FixedPointDatatype sizeOfLength, HdfFixedPoint address, long expectedBlockOffset, long iblockSize, int passedNrows) throws IOException, InvocationTargetException, InstantiationException, IllegalAccessException {
338-
if (address.isUndefined()) {
339-
throw new IOException("Invalid indirect block address");
337+
//<editor-fold desc="Refactored readIndirectBlock Helper Methods">
338+
private static int calculateNrows(FractalHeapHeader header, long iblockSize, int passedNrows) throws InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
339+
if (iblockSize <= 0) {
340+
return passedNrows;
340341
}
341-
channel.position(address.getInstance(Long.class));
342-
IndirectBlock ib = new IndirectBlock();
343-
int nrows;
342+
344343
long startingBlockSize = header.startingBlockSize.getInstance(Long.class);
345-
if (iblockSize > 0) {
346-
long covered = 0;
347-
long current = startingBlockSize;
348-
int nr = 0;
349-
while (covered < iblockSize) {
350-
covered += (long) header.tableWidth * current;
351-
current *= 2;
352-
nr++;
353-
}
354-
nrows = (short) nr;
355-
} else {
356-
nrows = passedNrows;
357-
}
358-
int plusSize = 0;
359-
ib.nrows = nrows;
344+
long covered = 0;
345+
long current = startingBlockSize;
346+
int nr = 0;
347+
while (covered < iblockSize) {
348+
covered += (long) header.tableWidth * current;
349+
current *= 2;
350+
nr++;
351+
}
352+
return nr;
353+
}
354+
355+
private static int calculateChildrenEntriesSize(FractalHeapHeader header, int nrows, FixedPointDatatype sizeOfOffset, FixedPointDatatype sizeOfLength) {
356+
int entriesSize = 0;
360357
for (short r = 0; r < nrows; r++) {
361358
for (int c = 0; c < header.tableWidth; c++) {
362-
plusSize += sizeOfOffset.getSize();
359+
entriesSize += sizeOfOffset.getSize();
363360
boolean isDirect = r < header.maxDblockRows;
364361
if (header.hasFilters && isDirect) {
365-
plusSize += sizeOfLength.getSize();
366-
plusSize += 4;
362+
entriesSize += sizeOfLength.getSize();
363+
entriesSize += 4; // filter mask
367364
}
368365
}
369366
}
370-
plusSize += 4; // checksum
371-
372-
int headerSize = 4 + 1 + sizeOfOffset.getSize() + header.offsetBytes.getSize() + plusSize;
373-
ByteBuffer headerBuffer = ByteBuffer.allocate(headerSize).order(ByteOrder.LITTLE_ENDIAN);
374-
int bytesRead = channel.read(headerBuffer);
375-
if ( headerSize != bytesRead)
376-
throw new IllegalStateException("Incorrect bytesRead: " + bytesRead + ": expected " + headerSize);
377-
headerBuffer.flip();
367+
return entriesSize;
368+
}
378369

379-
String sig = new String(Arrays.copyOfRange(headerBuffer.array(), 0, 4), StandardCharsets.US_ASCII);
380-
if (!Objects.equals(sig, "FHIB")) {
381-
throw new IOException("Invalid indirect block signature");
370+
private static void readAndVerifyIndirectBlockHeader(ByteBuffer blockBuffer, long expectedBlockOffset, FixedPointDatatype sizeOfOffset, FixedPointDatatype offsetBytes) throws IOException, InvocationTargetException, InstantiationException, IllegalAccessException {
371+
byte[] signatureBytes = new byte[4];
372+
blockBuffer.get(signatureBytes);
373+
String sig = new String(signatureBytes, StandardCharsets.US_ASCII);
374+
if (!"FHIB".equals(sig)) {
375+
throw new IOException("Invalid indirect block signature: " + sig);
382376
}
383-
headerBuffer.position(4);
384-
byte version = headerBuffer.get();
377+
378+
byte version = blockBuffer.get();
385379
if (version != 0) {
386-
throw new IOException("Unsupported version");
380+
throw new IOException("Unsupported version: " + version);
387381
}
388-
HdfFixedPoint heapHeader = HdfReadUtils.readHdfFixedPointFromBuffer(sizeOfOffset, headerBuffer);
382+
383+
HdfFixedPoint heapHeader = HdfReadUtils.readHdfFixedPointFromBuffer(sizeOfOffset, blockBuffer);
389384
if (heapHeader.isUndefined()) {
390385
throw new IOException("Invalid heap header address in indirect block");
391386
}
392-
HdfFixedPoint blockOffset = HdfReadUtils.readHdfFixedPointFromBuffer(header.offsetBytes, headerBuffer);
387+
388+
HdfFixedPoint blockOffset = HdfReadUtils.readHdfFixedPointFromBuffer(offsetBytes, blockBuffer);
393389
if (blockOffset.getInstance(Long.class) != expectedBlockOffset) {
394390
throw new IOException("Block offset mismatch");
395391
}
396-
headerBuffer.position(4 + 1 + sizeOfOffset.getSize() + header.offsetBytes.getSize());
397-
ib.blockOffset = blockOffset.getInstance(Long.class);
398-
ib.children = new ArrayList<>();
392+
}
393+
394+
private static List<ChildInfo> parseChildInfos(ByteBuffer blockBuffer, FractalHeapHeader header, int nrows, long startOffset, FixedPointDatatype sizeOfOffset, FixedPointDatatype sizeOfLength) throws InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
399395
List<ChildInfo> childInfos = new ArrayList<>();
400-
long currentOffset = expectedBlockOffset; // expectedBlockOffset;
396+
long currentOffset = startOffset;
397+
long startingBlockSize = header.startingBlockSize.getInstance(Long.class);
398+
401399
for (short r = 0; r < nrows; r++) {
402400
long rowBlockSize = startingBlockSize * (1L << r);
403401
for (int c = 0; c < header.tableWidth; c++) {
404-
HdfFixedPoint childAddress = HdfReadUtils.readHdfFixedPointFromBuffer(sizeOfOffset, headerBuffer);
402+
HdfFixedPoint childAddress = HdfReadUtils.readHdfFixedPointFromBuffer(sizeOfOffset, blockBuffer);
405403
HdfFixedPoint childFilteredSize = sizeOfOffset.undefined();
406404
long childFilterMask = 0;
405+
407406
boolean isDirect = r < header.maxDblockRows;
408407
if (header.hasFilters && isDirect) {
409-
childFilteredSize = HdfReadUtils.readHdfFixedPointFromBuffer(sizeOfLength, headerBuffer);
410-
childFilterMask = headerBuffer.getInt();
408+
childFilteredSize = HdfReadUtils.readHdfFixedPointFromBuffer(sizeOfLength, blockBuffer);
409+
childFilterMask = Integer.toUnsignedLong(blockBuffer.getInt());
411410
}
411+
412412
if (!childAddress.isUndefined()) {
413-
ChildInfo info = new ChildInfo(childAddress, currentOffset, isDirect, childFilteredSize, childFilterMask, rowBlockSize);
414-
childInfos.add(info);
413+
childInfos.add(new ChildInfo(childAddress, currentOffset, isDirect, childFilteredSize, childFilterMask, rowBlockSize));
415414
}
416415
currentOffset += rowBlockSize;
417416
}
418417
}
419-
ib.checksum = Integer.toUnsignedLong(headerBuffer.getInt());
418+
return childInfos;
419+
}
420+
421+
private static List<Block> readChildren(SeekableByteChannel channel, FractalHeapHeader header, List<ChildInfo> childInfos, FixedPointDatatype sizeOfOffset, FixedPointDatatype sizeOfLength) throws IOException, InvocationTargetException, InstantiationException, IllegalAccessException {
422+
List<Block> children = new ArrayList<>();
420423
for (ChildInfo info : childInfos) {
421-
if (!info.address.isUndefined()) {
422-
Block child;
423-
if (info.isDirect) {
424-
child = readDirectBlock(channel, header, info.address, sizeOfOffset, info.blockOffset, info.filteredSize, info.filterMask);
425-
} else {
426-
child = readIndirectBlock(channel, header, sizeOfOffset, sizeOfLength, info.address, info.blockOffset, info.blockSize, (short) 0);
427-
}
428-
ib.children.add(child);
424+
Block child;
425+
if (info.isDirect) {
426+
child = readDirectBlock(channel, header, info.address, sizeOfOffset, info.blockOffset, info.filteredSize, info.filterMask);
427+
} else {
428+
child = readIndirectBlock(channel, header, sizeOfOffset, sizeOfLength, info.address, info.blockOffset, info.blockSize, 0);
429429
}
430+
children.add(child);
431+
}
432+
return children;
433+
}
434+
//</editor-fold>
435+
436+
private static Block readIndirectBlock(SeekableByteChannel channel, FractalHeapHeader header, FixedPointDatatype sizeOfOffset, FixedPointDatatype sizeOfLength, HdfFixedPoint address, long expectedBlockOffset, long iblockSize, int passedNrows) throws IOException, InvocationTargetException, InstantiationException, IllegalAccessException {
437+
if (address.isUndefined()) {
438+
throw new IOException("Invalid indirect block address");
439+
}
440+
channel.position(address.getInstance(Long.class));
441+
442+
// 1. Determine the number of rows in this indirect block.
443+
int nrows = calculateNrows(header, iblockSize, passedNrows);
444+
445+
// 2. Calculate the total size of the child entries section.
446+
int childrenEntriesSize = calculateChildrenEntriesSize(header, nrows, sizeOfOffset, sizeOfLength);
447+
448+
// 3. Read the entire block's header, entries, and checksum into a buffer.
449+
int headerPortionSize = 4 + 1 + sizeOfOffset.getSize() + header.offsetBytes.getSize(); // sig+ver+heapAddr+blockOffset
450+
int totalSizeToRead = headerPortionSize + childrenEntriesSize + 4; // 4 for checksum
451+
ByteBuffer blockBuffer = ByteBuffer.allocate(totalSizeToRead).order(ByteOrder.LITTLE_ENDIAN);
452+
int bytesRead = channel.read(blockBuffer);
453+
if (totalSizeToRead != bytesRead) {
454+
throw new IllegalStateException("Incorrect bytesRead: " + bytesRead + ": expected " + totalSizeToRead);
430455
}
456+
blockBuffer.flip();
457+
458+
// 4. Verify the block's header fields. The buffer position is advanced past the header.
459+
readAndVerifyIndirectBlockHeader(blockBuffer, expectedBlockOffset, sizeOfOffset, header.offsetBytes);
460+
461+
// 5. Parse child information from the buffer. The buffer position is advanced past the entries.
462+
List<ChildInfo> childInfos = parseChildInfos(blockBuffer, header, nrows, expectedBlockOffset, sizeOfOffset, sizeOfLength);
463+
464+
// 6. Create the block object and read the checksum from the end of the buffer.
465+
IndirectBlock ib = new IndirectBlock();
466+
ib.nrows = nrows;
467+
ib.blockOffset = expectedBlockOffset;
468+
ib.checksum = Integer.toUnsignedLong(blockBuffer.getInt());
469+
470+
// 7. Recursively read all children based on the parsed info.
471+
ib.children = readChildren(channel, header, childInfos, sizeOfOffset, sizeOfLength);
472+
431473
return ib;
432474
}
433475

src/main/java/org/hdf5javalib/hdfjava/HdfDataset.java

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -340,8 +340,8 @@ private ByteBuffer readAndDecodeChunk(HdfGroupForChunkBTreeEntry entry, Seekable
340340

341341
private void copyDataFromChunk(ByteBuffer chunkBuffer, ByteBuffer resultBuffer, long[] chunkOffset, long[] chunkActualSize, ChunkedReadContext context) {
342342
long[] localIdx = new long[context.dimensions()];
343-
boolean done = false;
344-
while (!done) {
343+
// Loop using do-while and a helper for incrementing, starting with {0,0,...}
344+
do {
345345
long[] globalIdx = new long[context.dimensions()];
346346
for (int i = 0; i < context.dimensions(); i++) {
347347
globalIdx[i] = chunkOffset[i] + localIdx[i];
@@ -359,21 +359,28 @@ private void copyDataFromChunk(ByteBuffer chunkBuffer, ByteBuffer resultBuffer,
359359
resultBuffer.put(chunkBuffer.get());
360360
}
361361
}
362+
} while (incrementLocalIndex(localIdx, chunkActualSize));
363+
}
362364

363-
// Increment local index (odometer)
364-
int pos = context.dimensions() - 1;
365-
while (pos >= 0) {
366-
localIdx[pos]++;
367-
if (localIdx[pos] < chunkActualSize[pos]) {
368-
break;
369-
}
370-
localIdx[pos] = 0;
371-
pos--;
372-
}
373-
if (pos < 0) {
374-
done = true;
365+
/**
366+
* Increments a multi-dimensional index array in an "odometer" fashion. This helper method
367+
* encapsulates the complex iteration logic, reducing the cognitive complexity of the calling method.
368+
*
369+
* @param localIdx The current index array to increment (mutated in place).
370+
* @param chunkActualSize The maximum size of each dimension.
371+
* @return {@code true} if the index was successfully incremented within bounds, {@code false} if it has rolled over the end.
372+
*/
373+
private boolean incrementLocalIndex(long[] localIdx, long[] chunkActualSize) {
374+
int pos = localIdx.length - 1;
375+
while (pos >= 0) {
376+
localIdx[pos]++;
377+
if (localIdx[pos] < chunkActualSize[pos]) {
378+
return true; // Still within bounds
375379
}
380+
localIdx[pos] = 0; // Reset and carry over
381+
pos--;
376382
}
383+
return false; // Reached the end
377384
}
378385

379386

0 commit comments

Comments
 (0)