blob: f903aad47736fcf9a2316829b994416bb78d9a54 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.iotdb.tsfile.encoding.encoder;
import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class DoubleBUFFEncoder extends Encoder {
private static final int lenlen = 10;
private static final int perlen = 5;
private static final int maxlen = 16;
private static final int[] len = {0, 5, 8, 11, 15, 18, 21, 25, 28, 31, 35};
private static final double eps = 1e-4;
private int maxFloatLength;
private boolean first;
private long minValue, maxValue;
private int countA, countB;
private List<Double> li;
private byte buffer = 0;
protected long bitsLeft = Byte.SIZE;
private void reset() {
maxFloatLength = 0;
first = true;
li = new ArrayList<>();
buffer = 0;
bitsLeft = Byte.SIZE;
}
public DoubleBUFFEncoder() {
super(TSEncoding.BUFF);
reset();
}
@Override
public void encode(double value, ByteArrayOutputStream out) {
if (first) {
minValue = (long) Math.floor(value);
maxValue = (long) Math.ceil(value);
first = false;
} else {
minValue = Math.min(minValue, (long) Math.floor(value));
maxValue = Math.max(maxValue, (long) Math.ceil(value));
}
double tmp = value;
tmp -= Math.floor(tmp + eps);
int curFloatLength = 0;
while (tmp > eps && curFloatLength < maxlen) {
curFloatLength++;
tmp *= 10;
tmp -= Math.floor(tmp + eps);
}
maxFloatLength = Math.max(maxFloatLength, curFloatLength);
li.add(value);
}
@Override
public void flush(ByteArrayOutputStream out) throws IOException {
if (first) {
writeBits(li.size(), Integer.SIZE, out);
flushBits(out);
reset();
return;
}
calc();
writeBits(li.size(), Integer.SIZE, out);
writeBits(countA, Integer.SIZE, out);
writeBits(countB, Integer.SIZE, out);
writeBits(minValue, Long.SIZE, out);
for (double value : li) {
long partA = (long) Math.floor(value) - minValue;
writeBits(partA, countA, out);
double partB = value - Math.floor(value);
for (int i = 0; i < countB; i++) {
partB *= 2;
if (partB >= 1) {
writeBit(out);
partB -= 1;
} else skipBit(out);
}
}
flushBits(out);
reset();
}
protected void writeBits(long value, int len, ByteArrayOutputStream out) {
if (len == 0) return;
writeBits(value >>> 1, len - 1, out);
if ((value & 1) == 0) skipBit(out);
else writeBit(out);
}
protected void flushBits(ByteArrayOutputStream out) {
while (bitsLeft != Byte.SIZE) skipBit(out);
}
/** Stores a 0 and increases the count of bits by 1 */
protected void skipBit(ByteArrayOutputStream out) {
bitsLeft--;
flipByte(out);
}
/** Stores a 1 and increases the count of bits by 1 */
protected void writeBit(ByteArrayOutputStream out) {
buffer |= (1 << (bitsLeft - 1));
bitsLeft--;
flipByte(out);
}
protected void flipByte(ByteArrayOutputStream out) {
if (bitsLeft == 0) {
out.write(buffer);
buffer = 0;
bitsLeft = Byte.SIZE;
}
}
@Override
public int getOneItemMaxSize() {
if (first) return 0;
calc();
return countA + countB;
}
@Override
public long getMaxByteSize() {
if (first) return 0;
calc();
return (countA + countB) * li.size() + Integer.SIZE * 3 + Long.SIZE;
}
private void calc() {
maxFloatLength = Math.min(maxFloatLength, maxlen);
countA = Long.SIZE - Long.numberOfLeadingZeros(maxValue - minValue);
if (maxFloatLength > lenlen) countB = len[lenlen] + perlen * (maxFloatLength - lenlen);
else countB = len[maxFloatLength];
}
}