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

jetbrains.exodus.bindings.LongBinding Maven / Gradle / Ivy

There is a newer version: 9.8.0.76914
Show newest version
/**
 * Copyright 2010 - 2022 JetBrains s.r.o.
 *
 * Licensed 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
 *
 * https://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 jetbrains.exodus.bindings;

import jetbrains.exodus.ArrayByteIterable;
import jetbrains.exodus.ByteIterable;
import jetbrains.exodus.ByteIterator;
import jetbrains.exodus.util.LightOutputStream;
import org.jetbrains.annotations.NotNull;

import java.io.ByteArrayInputStream;

/**
 * {@linkplain ComparableBinding} for {@linkplain Long} values.
 *
 * In addition to typical {@linkplain #longToEntry(long)} and {@linkplain #entryToLong(ByteIterable)} methods operating
 * with {@code ByteIterables} of length {@code 8}, {@code LongBinding} has a pair of methods for
 * serialization/deserialization of non-negative values to/from compressed entries:
 * {@linkplain #longToCompressedEntry(long)} and {@linkplain #compressedEntryToLong(ByteIterable)}. The lower the value,
 * the shorter the compressed entry. In some cases, compressed entries let you significantly decrease database size.
 * Serialization of non-negative integers and longs to compressed entries also saves the order of values.
 *
 * @see ComparableBinding
 */
public class LongBinding extends ComparableBinding {

    public static final LongBinding BINDING = new LongBinding();

    private LongBinding() {
    }

    @Override
    public Long readObject(@NotNull final ByteArrayInputStream stream) {
        return BindingUtils.readLong(stream);
    }

    @Override
    public void writeObject(@NotNull final LightOutputStream output, @NotNull final Comparable object) {
        output.writeUnsignedLong((Long) object ^ 0x8000000000000000L);
    }

    /**
     * De-serializes {@linkplain ByteIterable} entry to a {@code long} value.
     * The entry should be an output of {@linkplain #longToEntry(long)}.
     *
     * @param entry {@linkplain ByteIterable} instance
     * @return de-serialized value
     * @see #longToEntry(long)
     * @see #compressedEntryToLong(ByteIterable)
     * @see #longToCompressedEntry(long)
     * @see #compressedEntryToSignedLong(ByteIterable)
     * @see #signedLongToCompressedEntry(long)
     */
    public static long entryToLong(@NotNull final ByteIterable entry) {
        return (Long) BINDING.entryToObject(entry);
    }

    /**
     * Serializes {@code long} value to the {@linkplain ArrayByteIterable} entry.
     *
     * @param object value to serialize
     * @return {@linkplain ArrayByteIterable} entry
     * @see #entryToLong(ByteIterable)
     * @see #compressedEntryToLong(ByteIterable)
     * @see #longToCompressedEntry(long)
     * @see #compressedEntryToSignedLong(ByteIterable)
     * @see #signedLongToCompressedEntry(long)
     */
    public static ArrayByteIterable longToEntry(final long object) {
        return BINDING.objectToEntry(object);
    }

    /**
     * De-serializes compressed {@linkplain ByteIterable} entry to an unsigned {@code long} value.
     * The entry should be an output of {@linkplain #longToCompressedEntry(long)}.
     *
     * @param entry {@linkplain ByteIterable} instance
     * @return de-serialized value
     * @see #entryToLong(ByteIterable)
     * @see #longToEntry(long)
     * @see #longToCompressedEntry(long)
     * @see #compressedEntryToSignedLong(ByteIterable)
     * @see #signedLongToCompressedEntry(long)
     */
    public static long compressedEntryToLong(@NotNull final ByteIterable entry) {
        return readCompressed(entry.iterator());
    }

    /**
     * Serializes unsigned {@code long} value to the compressed {@linkplain ArrayByteIterable} entry.
     *
     * @param object non-negative value to serialize
     * @return {@linkplain ArrayByteIterable} entry
     * @see #entryToLong(ByteIterable)
     * @see #longToEntry(long)
     * @see #compressedEntryToLong(ByteIterable)
     * @see #compressedEntryToSignedLong(ByteIterable)
     * @see #signedLongToCompressedEntry(long)
     */
    public static ArrayByteIterable longToCompressedEntry(final long object) {
        if (object < 0) {
            throw new IllegalArgumentException();
        }
        final LightOutputStream output = new LightOutputStream(4);
        writeCompressed(output, object);
        return output.asArrayByteIterable();
    }

    /**
     * De-serializes compressed {@linkplain ByteIterable} entry to a signed {@code long} value.
     * The entry should be an output of {@linkplain #signedLongToCompressedEntry(long)}.
     * 

ZigZag encoding is used, * so it doesn't save the order of values like other {@code ComparableBindings} do. * * @param entry {@linkplain ByteIterable} instance * @return de-serialized value * @see #entryToLong(ByteIterable) * @see #longToEntry(long) * @see #compressedEntryToLong(ByteIterable) * @see #longToCompressedEntry(long) * @see #signedLongToCompressedEntry(long) */ public static long compressedEntryToSignedLong(@NotNull final ByteIterable entry) { final long result = compressedEntryToLong(entry); return (result >> 1) ^ (((result & 1) << 63) >> 63); } /** * Serializes signed {@code long} value in the range {@code [Long.MIN_VALUE/2..Long.MAX_VALUE/2]} * to the compressed {@linkplain ArrayByteIterable} entry. *

ZigZag encoding is used, * so it doesn't save the order of values like other {@code ComparableBindings} do. * * @param object value to serialize in the range {@code [Long.MIN_VALUE/2..Long.MAX_VALUE/2]} * @return {@linkplain ArrayByteIterable} entry * @see #entryToLong(ByteIterable) * @see #longToEntry(long) * @see #compressedEntryToLong(ByteIterable) * @see #longToCompressedEntry(long) * @see #compressedEntryToSignedLong(ByteIterable) */ public static ArrayByteIterable signedLongToCompressedEntry(final long object) { return longToCompressedEntry((object << 1) ^ (object >> 63)); } public static void writeUnsignedLong(final long l, final int bytesPerLong, @NotNull final LightOutputStream output) { int bits = bytesPerLong << 3; while (bits > 0) { output.write((int) (l >> (bits -= 8) & 0xff)); } } public static long entryToUnsignedLong(@NotNull final ByteIterator bi, final int length) { long result = 0; for (int i = 0; i < length; ++i) { result = (result << 8) + ((int) bi.next() & 0xff); } return result; } public static long entryToUnsignedLong(@NotNull final byte[] bytes, final int offset, final int length) { long result = 0; for (int i = 0; i < length; ++i) { result = (result << 8) + ((int) bytes[offset + i] & 0xff); } return result; } public static long readCompressed(@NotNull final ByteIterator iterator) { final int firstByte = iterator.next() & 0xff; long result = firstByte & 0xf; int byteLen = firstByte >> 4; while (--byteLen >= 0) { result = (result << 8) + (iterator.next() & 0xff); } return result; } public static long readCompressed(@NotNull final ByteArrayInputStream iterator) { final int firstByte = iterator.read() & 0xff; long result = firstByte & 0xf; int byteLen = firstByte >> 4; while (--byteLen >= 0) { result = (result << 8) + (iterator.read() & 0xff); } return result; } public static void writeCompressed(@NotNull final LightOutputStream output, long l) { writeCompressed(output, l, new int[8]); } public static void writeCompressed(@NotNull final LightOutputStream output, long l, final int[] bytes) { for (int i = 0; i < 8; ++i) { bytes[i] = (int) (l & 0xff); l >>= 8; } int byteLen = 8; while (byteLen > 0 && bytes[byteLen - 1] == 0) { --byteLen; } int firstByte = byteLen << 4; if (byteLen > 0) { final int upperByte = bytes[byteLen - 1]; if (upperByte < 16) { firstByte = (((firstByte >> 4) - 1) << 4) + upperByte; --byteLen; } } output.write(firstByte); while (--byteLen >= 0) { output.write(bytes[byteLen]); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy