blob: 22ae8e320f8ba7e12c09ca4ce1a5108165cecb74 [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.ignite.internal.binary;
import org.apache.ignite.internal.binary.streams.BinaryOutputStream;
/**
* Binary writer schema holder.
*/
public class BinaryWriterSchemaHolder {
/** Maximum offset which fits in 1 byte. */
private static final int MAX_OFFSET_1 = 1 << 8;
/** Maximum offset which fits in 2 bytes. */
private static final int MAX_OFFSET_2 = 1 << 16;
/** Grow step. */
private static final int GROW_STEP = 64;
/** Data. */
private int[] data = new int[GROW_STEP];
/** Index. */
private int idx;
/**
* Push another frame.
*
* @param id Field ID.
* @param off Field offset.
*/
public void push(int id, int off) {
if (idx == data.length) {
int[] data0 = new int[data.length + GROW_STEP];
System.arraycopy(data, 0, data0, 0, data.length);
data = data0;
}
data[idx] = id;
data[idx + 1] = off;
idx += 2;
}
/**
* Build the schema.
*
* @param builder Builder.
* @param fieldCnt Fields count.
*/
public void build(BinarySchema.Builder builder, int fieldCnt) {
for (int curIdx = idx - fieldCnt * 2; curIdx < idx; curIdx += 2)
builder.addField(data[curIdx]);
}
/**
* Write collected frames and pop them.
*
* @param out Output stream.
* @param fieldCnt Count.
* @param compactFooter Whether footer should be written in compact form.
* @return Amount of bytes dedicated to each field offset. Could be 1, 2 or 4.
*/
public int write(BinaryOutputStream out, int fieldCnt, boolean compactFooter) {
int startIdx = idx - fieldCnt * 2;
assert startIdx >= 0;
// Ensure there are at least 8 bytes for each field to allow for unsafe writes.
out.unsafeEnsure(fieldCnt << 3);
int lastOffset = data[idx - 1];
int res;
if (compactFooter) {
if (lastOffset < MAX_OFFSET_1) {
for (int curIdx = startIdx + 1; curIdx < idx; curIdx += 2)
out.unsafeWriteByte((byte)data[curIdx]);
res = BinaryUtils.OFFSET_1;
}
else if (lastOffset < MAX_OFFSET_2) {
for (int curIdx = startIdx + 1; curIdx < idx; curIdx += 2)
out.unsafeWriteShort((short) data[curIdx]);
res = BinaryUtils.OFFSET_2;
}
else {
for (int curIdx = startIdx + 1; curIdx < idx; curIdx += 2)
out.unsafeWriteInt(data[curIdx]);
res = BinaryUtils.OFFSET_4;
}
}
else {
if (lastOffset < MAX_OFFSET_1) {
for (int curIdx = startIdx; curIdx < idx;) {
out.unsafeWriteInt(data[curIdx++]);
out.unsafeWriteByte((byte) data[curIdx++]);
}
res = BinaryUtils.OFFSET_1;
}
else if (lastOffset < MAX_OFFSET_2) {
for (int curIdx = startIdx; curIdx < idx;) {
out.unsafeWriteInt(data[curIdx++]);
out.unsafeWriteShort((short) data[curIdx++]);
}
res = BinaryUtils.OFFSET_2;
}
else {
for (int curIdx = startIdx; curIdx < idx;) {
out.unsafeWriteInt(data[curIdx++]);
out.unsafeWriteInt(data[curIdx++]);
}
res = BinaryUtils.OFFSET_4;
}
}
return res;
}
/**
* Pop current object's frame.
*/
public void pop(int fieldCnt) {
idx = idx - fieldCnt * 2;
}
}