| /** |
| * 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.avro.io; |
| |
| import java.io.IOException; |
| import java.io.OutputStream; |
| |
| /** |
| * An {@link Encoder} for Avro's binary encoding that does not buffer output. |
| * <p/> |
| * This encoder does not buffer writes, and as a result is slower than |
| * {@link BufferedBinaryEncoder}. However, it is lighter-weight and useful when the |
| * buffering in BufferedBinaryEncoder is not desired and/or the Encoder is |
| * very short lived. |
| * <p/> |
| * To construct, use |
| * {@link EncoderFactory#directBinaryEncoder(OutputStream, BinaryEncoder)} |
| * <p/> |
| * DirectBinaryEncoder is not thread-safe |
| * @see BinaryEncoder |
| * @see EncoderFactory |
| * @see Encoder |
| * @see Decoder |
| */ |
| public class DirectBinaryEncoder extends BinaryEncoder { |
| private OutputStream out; |
| // the buffer is used for writing floats, doubles, and large longs. |
| private final byte[] buf = new byte[12]; |
| |
| /** Create a writer that sends its output to the underlying stream |
| * <code>out</code>. |
| **/ |
| DirectBinaryEncoder(OutputStream out) { |
| configure(out); |
| } |
| |
| DirectBinaryEncoder configure(OutputStream out) { |
| if (null == out) throw new NullPointerException("OutputStream cannot be null!"); |
| this.out = out; |
| return this; |
| } |
| |
| @Override |
| public void flush() throws IOException { |
| out.flush(); |
| } |
| |
| @Override |
| public void writeBoolean(boolean b) throws IOException { |
| out.write(b ? 1 : 0); |
| } |
| |
| /* buffering is slower for ints that encode to just 1 or |
| * two bytes, and and faster for large ones. |
| * (Sun JRE 1.6u22, x64 -server) */ |
| @Override |
| public void writeInt(int n) throws IOException { |
| int val = (n << 1) ^ (n >> 31); |
| if ((val & ~0x7F) == 0) { |
| out.write(val); |
| return; |
| } else if ((val & ~0x3FFF) == 0) { |
| out.write(0x80 | val); |
| out.write(val >>> 7); |
| return; |
| } |
| int len = BinaryData.encodeInt(n, buf, 0); |
| out.write(buf, 0, len); |
| } |
| |
| /* buffering is slower for writeLong when the number is small enough to |
| * fit in an int. |
| * (Sun JRE 1.6u22, x64 -server) */ |
| @Override |
| public void writeLong(long n) throws IOException { |
| long val = (n << 1) ^ (n >> 63); // move sign to low-order bit |
| if ((val & ~0x7FFFFFFFL) == 0) { |
| int i = (int) val; |
| while ((i & ~0x7F) != 0) { |
| out.write((byte)((0x80 | i) & 0xFF)); |
| i >>>= 7; |
| } |
| out.write((byte)i); |
| return; |
| } |
| int len = BinaryData.encodeLong(n, buf, 0); |
| out.write(buf, 0, len); |
| } |
| |
| @Override |
| public void writeFloat(float f) throws IOException { |
| int len = BinaryData.encodeFloat(f, buf, 0); |
| out.write(buf, 0, len); |
| } |
| |
| @Override |
| public void writeDouble(double d) throws IOException { |
| byte[] buf = new byte[8]; |
| int len = BinaryData.encodeDouble(d, buf, 0); |
| out.write(buf, 0, len); |
| } |
| |
| @Override |
| public void writeFixed(byte[] bytes, int start, int len) throws IOException { |
| out.write(bytes, start, len); |
| } |
| |
| @Override |
| protected void writeZero() throws IOException { |
| out.write(0); |
| } |
| |
| @Override |
| public int bytesBuffered() { |
| return 0; |
| } |
| |
| } |