All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opendaylight.yangtools.concepts.WritableObjects Maven / Gradle / Ivy

There is a newer version: 14.0.4
Show newest version
/*
 * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
package org.opendaylight.yangtools.concepts;

import static com.google.common.base.Preconditions.checkArgument;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.eclipse.jdt.annotation.NonNullByDefault;

/**
 * Utility methods for working with {@link WritableObject}s.
 */
@NonNullByDefault
public final class WritableObjects {
    private WritableObjects() {
        // Hidden on purpose
    }

    /**
     * Shorthand for {@link #writeLong(DataOutput, long, int)} with zero flags.
     *
     * @param out Data output
     * @param value long value to write
     * @throws IOException if an I/O error occurs
     * @throws NullPointerException if {@code out} is {@code null}
     */
    public static void writeLong(final DataOutput out, final long value) throws IOException {
        writeLong(out, value, 0);
    }

    /**
     * Write a long value into a {@link DataOutput}, compressing potential zero bytes. This method is useful for
     * serializing counters and similar, which have a wide range, but typically do not use it. The value provided is
     * treated as unsigned.
     *
     * 

* This methods writes the number of trailing non-zero in the value. It then writes the minimum required bytes * to reconstruct the value by left-padding zeroes. Inverse operation is performed by {@link #readLong(DataInput)} * or a combination of {@link #readLongHeader(DataInput)} and {@link #readLongBody(DataInput, byte)}. * *

* Additionally the caller can use the top four bits (i.e. {@code 0xF0}) for caller-specific flags. These will be * ignored by {@link #readLong(DataInput)}, but can be extracted via {@link #readLongHeader(DataInput)}. * * @param out Data output * @param value long value to write * @param flags flags to store * @throws IOException if an I/O error occurs * @throws NullPointerException if {@code out} is {@code null} */ public static void writeLong(final DataOutput out, final long value, final int flags) throws IOException { checkArgument((flags & 0xFFFFFF0F) == 0, "Invalid flags %s", flags); final int bytes = valueBytes(value); out.writeByte(bytes | flags); writeValue(out, value, bytes); } /** * Read a long value from a {@link DataInput} which was previously written via {@link #writeLong(DataOutput, long)}. * * @param in Data input * @return long value extracted from the data input * @throws IOException if an I/O error occurs * @throws NullPointerException if {@code in} is {@code null} */ public static long readLong(final DataInput in) throws IOException { return readLongBody(in, readLongHeader(in)); } /** * Read the header of a compressed long value. The header may contain user-defined flags, which can be extracted * via {@link #longHeaderFlags(byte)}. * * @param in Data input * @return Header of next value * @throws IOException if an I/O error occurs * @throws NullPointerException if {@code in} is {@code null} */ public static byte readLongHeader(final DataInput in) throws IOException { return in.readByte(); } /** * Extract user-defined flags from a compressed long header. This will return {code 0} if the long value originates * from {@link #writeLong(DataOutput, long)}. * * @param header Value header, as returned by {@link #readLongHeader(DataInput)} * @return User-defined flags */ public static int longHeaderFlags(final byte header) { return header & 0xF0; } /** * Read a long value from a {@link DataInput} as hinted by the result of {@link #readLongHeader(DataInput)}. * * @param in Data input * @param header Value header, as returned by {@link #readLongHeader(DataInput)} * @return long value * @throws IOException if an I/O error occurs * @throws NullPointerException if {@code in} is {@code null} */ public static long readLongBody(final DataInput in, final byte header) throws IOException { int bytes = header & 0xF; if (bytes >= 8) { return in.readLong(); } if (bytes <= 0) { return 0; } long value = 0; if (bytes >= 4) { bytes -= 4; value = (in.readInt() & 0xFFFFFFFFL) << bytes * Byte.SIZE; } if (bytes >= 2) { bytes -= 2; value |= in.readUnsignedShort() << bytes * Byte.SIZE; } if (bytes > 0) { value |= in.readUnsignedByte(); } return value; } /** * Write two consecutive long values. These values can be read back using {@link #readLongHeader(DataInput)}, * {@link #readFirstLong(DataInput, byte)} and {@link #readSecondLong(DataInput, byte)}. * *

This is a more efficient way of serializing two longs than {@link #writeLong(DataOutput, long)}. This is * achieved by using the flags field to hold the length of the second long -- hence saving one byte. * * @param out Data output * @param value0 first long value to write * @param value1 second long value to write * @throws IOException if an I/O error occurs * @throws NullPointerException if {@code out} is {@code null} */ public static void writeLongs(final DataOutput out, final long value0, final long value1) throws IOException { final int clen = WritableObjects.valueBytes(value1); writeLong(out, value0, clen << 4); WritableObjects.writeValue(out, value1, clen); } /** * Read first long value from an input. * * @param in Data input * @param header Value header, as returned by {@link #readLongHeader(DataInput)} * @return First long specified in {@link #writeLongs(DataOutput, long, long)} * @throws IOException if an I/O error occurs * @throws NullPointerException if input is null */ public static long readFirstLong(final DataInput in, final byte header) throws IOException { return WritableObjects.readLongBody(in, header); } /** * Read second long value from an input. * * @param in Data input * @param header Value header, as returned by {@link #readLongHeader(DataInput)} * @return Second long specified in {@link #writeLongs(DataOutput, long, long)} * @throws IOException if an I/O error occurs * @throws NullPointerException if {@code in} is {@code null} */ public static long readSecondLong(final DataInput in, final byte header) throws IOException { return WritableObjects.readLongBody(in, (byte)(header >> 4)); } private static void writeValue(final DataOutput out, final long value, final int bytes) throws IOException { if (bytes < 8) { int left = bytes; if (left >= 4) { left -= 4; out.writeInt((int)(value >>> left * Byte.SIZE)); } if (left >= 2) { left -= 2; out.writeShort((int)(value >>> left * Byte.SIZE)); } if (left > 0) { out.writeByte((int)(value & 0xFF)); } } else { out.writeLong(value); } } private static int valueBytes(final long value) { // This is a binary search for the first match. Note that we need to mask bits from the most significant one. // It completes completes in three to four mask-and-compare operations. if ((value & 0xFFFFFFFF00000000L) != 0) { if ((value & 0xFFFF000000000000L) != 0) { return (value & 0xFF00000000000000L) != 0 ? 8 : 7; } return (value & 0x0000FF0000000000L) != 0 ? 6 : 5; } else if ((value & 0x00000000FFFFFFFFL) != 0) { if ((value & 0x00000000FFFF0000L) != 0) { return (value & 0x00000000FF000000L) != 0 ? 4 : 3; } return (value & 0x000000000000FF00L) != 0 ? 2 : 1; } else { return 0; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy