
com.apple.foundationdb.tuple.TupleOrdering Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fdb-extensions Show documentation
Show all versions of fdb-extensions Show documentation
Extensions to the FoundationDB Java API.
The newest version!
/*
* TupleOrdering.java
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2024 Apple Inc. and the FoundationDB project authors
*
* 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
*
* 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 com.apple.foundationdb.tuple;
import com.apple.foundationdb.annotation.API;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.List;
/**
* Helper methods for encoding {@link Tuple}s in ways that implement SQL-like ordering.
*/
@API(API.Status.UNSTABLE)
public class TupleOrdering {
/**
* Extended tuple code used to represent a null for `NULLS LAST`.
* Does not need to be a fully supported tuple code since ordered encoding is treated as a byte array.
*/
static final byte NULL_LAST = (byte)0xFE;
/**
* Direction of ordering.
* {@link #ASC_NULLS_FIRST} corresponds to the default {@code Tuple} packing and is included for completeness.
*/
public enum Direction {
ASC_NULLS_FIRST(false, false, "↑"),
ASC_NULLS_LAST(false, true, "↗"),
DESC_NULLS_FIRST(true, true, "↙"),
DESC_NULLS_LAST(true, false, "↓");
private final boolean inverted;
private final boolean counterflowNulls;
private final String arrowIndicator;
Direction(boolean inverted, boolean counterflowNulls, String arrowIndicator) {
this.inverted = inverted;
this.counterflowNulls = counterflowNulls;
this.arrowIndicator = arrowIndicator;
}
/**
* Get whether the byte ordering is inverted, that is, the opposite of the default unordered byte comparison of packed {@code Tuple}s.
* @return {@code true} if byte order is inverted
*/
public boolean isInverted() {
return inverted;
}
/**
* Get whether {@code null} values sort at the opposite end as in the default {@code Tuple} packing.
* @return {@code true} if nulls come at the end when ascending
*/
public boolean isCounterflowNulls() {
return counterflowNulls;
}
/**
* Returns a string that symbolizes the meaning of this enum constant.
* @return the arrow indicator
*/
public String getArrowIndicator() {
return arrowIndicator;
}
/**
* Get whether values are ordered ascending.
* This is the opposite of {@link #isInverted()}, viewed from the name of the enum, as opposed to what encoding
* would need to do.
* @return {@code true} if greater values from first
*/
public boolean isAscending() {
return !inverted;
}
/**
* Get whether values are ordered descending.
* This is the same as {@link #isInverted()}, viewed from the name of the enum, as opposed to what encoding
* would need to do.
* @return {@code true} if greater values from first
*/
public boolean isDescending() {
return inverted;
}
/**
* Get whether null values come earlier.
* This corresponds to the second part of the enum name.
* @return {@code true} if nulls values come before non-null values
*/
public boolean isNullsFirst() {
return inverted == counterflowNulls;
}
/**
* Get whether null values come later.
* This corresponds to the second part of the enum name.
* @return {@code true} if nulls values come after non-null values
*/
public boolean isNullsLast() {
return inverted != counterflowNulls;
}
@Nonnull
public Direction reverseDirection() {
switch (this) {
case ASC_NULLS_FIRST:
return DESC_NULLS_LAST;
case ASC_NULLS_LAST:
return DESC_NULLS_FIRST;
case DESC_NULLS_FIRST:
return ASC_NULLS_LAST;
case DESC_NULLS_LAST:
return ASC_NULLS_FIRST;
default:
throw new IllegalArgumentException("cannot reverse this direction");
}
}
}
private TupleOrdering() {
}
/**
* Encode the given tuple in a way that unordered byte comparison respects the given direction.
* @param tuple tuple to encode
* @param direction direction of desired ordering
* @return a byte string that compares properly
*/
@Nonnull
public static byte[] pack(@Nonnull Tuple tuple, @Nonnull Direction direction) {
final byte[] packed = direction.isCounterflowNulls() ? packNullsLast(tuple.elements) : tuple.pack();
return direction.isInverted() ? invert(packed) : packed;
}
/**
* Decode the result of {@link #pack}, recovering the original tuple.
* @param packed comparable byte string encoding
* @param direction direction used by encoding
* @return tuple that would encode that way
*/
@Nonnull
public static Tuple unpack(@Nonnull byte[] packed, @Nonnull Direction direction) {
final byte[] bytes = direction.isInverted() ? uninvert(packed) : packed;
return direction.isCounterflowNulls() ? Tuple.fromList(unpackNullsLast(bytes)) : Tuple.fromBytes(bytes);
}
@Nonnull
static byte[] packNullsLast(@Nonnull List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy