
spreadsheet.xlsx.internal.CompactSheet Maven / Gradle / Ivy
/*
* Copyright 2018 National Bank of Belgium
*
* Licensed under the EUPL, Version 1.1 or - as soon they will be approved
* by the European Commission - subsequent versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the Licence is distributed on an "AS IS" basis,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Licence for the specific language governing permissions and
* limitations under the Licence.
*/
package spreadsheet.xlsx.internal;
import ec.util.spreadsheet.Cell;
import ec.util.spreadsheet.Sheet;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import lombok.AccessLevel;
import org.checkerframework.checker.index.qual.NonNegative;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
*
* @author Philippe Charles
*/
@lombok.RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public final class CompactSheet extends Sheet {
private static final int CELL_BYTES = Byte.BYTES + Double.BYTES;
private static final int VALUE_OFFSET = Byte.BYTES;
private final int rowCount;
private final int columnCount;
private final String name;
private final ByteBuffer data;
private final List sharedStrings;
private final List localStrings;
@Deprecated
private final FlyweightCell flyweightCell = new FlyweightCell();
@Override
public int getRowCount() {
return rowCount;
}
@Override
public int getColumnCount() {
return columnCount;
}
@Override
public Cell getCell(int rowIdx, int columnIdx) throws IndexOutOfBoundsException {
int index = getIndex(rowIdx, columnIdx);
return getTypeAt(index) != Type.NULL ? flyweightCell.withValue(index) : null;
}
@Override
public Object getCellValue(int rowIdx, int columnIdx) throws IndexOutOfBoundsException {
int index = getIndex(rowIdx, columnIdx);
return getValueAt(index);
}
@Override
public String getName() {
return name;
}
@Override
public String toString() {
return "CompactSheet[" + rowCount + "x" + columnCount + "]";
}
private int getIndex(int rowIdx, int columnIdx) {
if (columnIdx >= columnCount) {
throw new IndexOutOfBoundsException();
}
return (rowIdx * columnCount + columnIdx) * CELL_BYTES;
}
private Type getTypeAt(int index) {
return Type.of(data.get(index));
}
private Object getValueAt(int index) {
switch (getTypeAt(index)) {
case DATE:
return getDateAt(index);
case NULL:
return null;
case NUMBER:
return getNumberAt(index);
case SHARED_STRING:
return getSharedStringAt(index);
case LOCAL_STRING:
return getLocalStringAt(index);
default:
throw new RuntimeException();
}
}
private Date getDateAt(int index) {
return new Date(data.getLong(index + VALUE_OFFSET));
}
private double getNumberAt(int index) {
return data.getDouble(index + VALUE_OFFSET);
}
private String getSharedStringAt(int index) {
return sharedStrings.get(data.getInt(index + VALUE_OFFSET));
}
private String getLocalStringAt(int index) {
return localStrings.get(data.getInt(index + VALUE_OFFSET));
}
private enum Type {
NULL, NUMBER, DATE, SHARED_STRING, LOCAL_STRING;
private static final Type[] VALUES = values();
public static Type of(int ordinal) {
return VALUES[ordinal];
}
}
@NonNull
public static Builder builder(
@NonNegative int rowCount, @NonNegative int columnCount,
@NonNull String name, @NonNull List sharedStrings) {
return new Builder(rowCount, columnCount, name, sharedStrings);
}
@Deprecated
private final class FlyweightCell extends Cell implements Serializable {
private int index = -1;
private CompactSheet.Type type = CompactSheet.Type.NULL;
@NonNull
FlyweightCell withValue(int index) {
this.index = index;
this.type = getTypeAt(index);
return this;
}
@Override
public boolean isDate() {
return type == CompactSheet.Type.DATE;
}
@Override
public boolean isNumber() {
return type == CompactSheet.Type.NUMBER;
}
@Override
public boolean isString() {
switch (type) {
case SHARED_STRING:
case LOCAL_STRING:
return true;
}
return false;
}
@Override
public Date getDate() {
if (!isDate()) {
throw new UnsupportedOperationException();
}
return getDateAt(index);
}
@Override
public Number getNumber() {
if (!isNumber()) {
throw new UnsupportedOperationException();
}
return getNumberAt(index);
}
@Override
public String getString() {
switch (type) {
case SHARED_STRING:
return getSharedStringAt(index);
case LOCAL_STRING:
return getLocalStringAt(index);
default:
throw new UnsupportedOperationException();
}
}
@Override
public Type getType() {
switch (type) {
case DATE:
return Type.DATE;
case NUMBER:
return Type.NUMBER;
case SHARED_STRING:
case LOCAL_STRING:
return Type.STRING;
default:
throw new RuntimeException();
}
}
@Override
public Object getValue() {
return getValueAt(index);
}
@Override
public String toString() {
return index + "";
}
}
public static boolean isOverflow(int rowCount, int columnCount) {
long result = (long) rowCount * (long) columnCount * CELL_BYTES;
return (int) result != result;
}
public static final class Builder {
private final int rowCount;
private final int columnCount;
private final String name;
private final ByteBuffer data;
private final List sharedStrings;
private List localStrings;
private Builder(int rowCount, int columnCount, String name, List sharedStrings) {
this.rowCount = rowCount;
this.columnCount = columnCount;
this.name = Objects.requireNonNull(name);
this.sharedStrings = Objects.requireNonNull(sharedStrings);
this.data = ByteBuffer.allocate(rowCount * columnCount * CELL_BYTES);
this.localStrings = null;
}
private int getIndex(int i, int j) {
if (j >= columnCount) {
throw new IndexOutOfBoundsException();
}
return (i * columnCount + j) * CELL_BYTES;
}
public Builder putNull(int i, int j) {
int index = getIndex(i, j);
data.put(index, (byte) Type.NULL.ordinal());
return this;
}
public Builder putNumber(int i, int j, double number) {
int index = getIndex(i, j);
data.put(index, (byte) Type.NUMBER.ordinal());
data.putDouble(index + VALUE_OFFSET, number);
return this;
}
public Builder putDate(int i, int j, long date) {
int index = getIndex(i, j);
data.put(index, (byte) Type.DATE.ordinal());
data.putLong(index + VALUE_OFFSET, date);
return this;
}
public Builder putSharedString(int i, int j, int stringIndex) {
int index = getIndex(i, j);
data.put(index, (byte) Type.SHARED_STRING.ordinal());
data.putInt(index + VALUE_OFFSET, stringIndex);
return this;
}
public Builder putString(int i, int j, String string) {
if (localStrings == null) {
localStrings = new ArrayList<>();
}
int index = getIndex(i, j);
data.put(index, (byte) Type.LOCAL_STRING.ordinal());
data.putInt(index + VALUE_OFFSET, localStrings.size());
localStrings.add(string);
return this;
}
public CompactSheet build() {
return new CompactSheet(rowCount, columnCount, name, data,
sharedStrings, localStrings != null ? localStrings : Collections.emptyList());
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy