001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.types;
019
020import java.math.BigDecimal;
021import java.math.BigInteger;
022
023import org.apache.hadoop.hbase.util.Order;
024import org.apache.hadoop.hbase.util.OrderedBytes;
025import org.apache.hadoop.hbase.util.PositionedByteRange;
026import org.apache.hadoop.hbase.util.SimplePositionedMutableByteRange;
027import org.apache.yetus.audience.InterfaceAudience;
028
029/**
030 * An {@link Number} of arbitrary precision and variable-length encoding. The
031 * resulting length of encoded values is determined by the numerical (base
032 * 100) precision, not absolute value. Use this data type anywhere you would
033 * expect to use a {@code DECIMAL} type, a {@link BigDecimal}, a
034 * {@link BigInteger}, or any time you've parsed floating precision values
035 * from text. Built on {@link OrderedBytes#encodeNumeric(PositionedByteRange, BigDecimal, Order)}.
036 */
037@InterfaceAudience.Public
038public class OrderedNumeric extends OrderedBytesBase<Number> {
039  /**
040   * @deprecated since 3.0.0 and will be removed in 4.0.0
041   */
042  @Deprecated
043  public static final OrderedNumeric ASCENDING = new OrderedNumeric(Order.ASCENDING);
044  /**
045   * @deprecated since 3.0.0 and will be removed in 4.0.0
046   */
047  @Deprecated
048  public static final OrderedNumeric DESCENDING = new OrderedNumeric(Order.DESCENDING);
049
050  /**
051   * Creates a new {@link Number} of arbitrary precision and variable-length encoding.
052   *
053   * @param order the {@link Order} to use
054   */
055  public OrderedNumeric(Order order) {
056    super(order);
057  }
058
059  @Override
060  public int encodedLength(Number val) {
061    // TODO: this could be done better.
062    PositionedByteRange buff = new SimplePositionedMutableByteRange(100);
063    return encode(buff, val);
064  }
065
066  @Override
067  public Class<Number> encodedClass() {
068    return Number.class;
069  }
070
071  @Override
072  public Number decode(PositionedByteRange src) {
073    if (OrderedBytes.isNumericInfinite(src) || OrderedBytes.isNumericNaN(src)) {
074      return OrderedBytes.decodeNumericAsDouble(src);
075    }
076    return OrderedBytes.decodeNumericAsBigDecimal(src);
077  }
078
079  @Override
080  public int encode(PositionedByteRange dst, Number val) {
081    if (null == val) {
082      return OrderedBytes.encodeNull(dst, order);
083    } else if (val instanceof BigDecimal) {
084      return OrderedBytes.encodeNumeric(dst, (BigDecimal) val, order);
085    } else if (val instanceof BigInteger) {
086      return OrderedBytes.encodeNumeric(dst, new BigDecimal((BigInteger) val), order);
087    } else if (val instanceof Double || val instanceof Float) {
088      return OrderedBytes.encodeNumeric(dst, val.doubleValue(), order);
089    } else {
090      // TODO: other instances of Numeric to consider?
091      return OrderedBytes.encodeNumeric(dst, val.longValue(), order);
092    }
093  }
094
095  /**
096   * Read a {@code long} value from the buffer {@code src}.
097   *
098   * @param src the {@link PositionedByteRange} to read the {@code long} from
099   * @return the {@code long} read from the buffer
100   */
101  public long decodeLong(PositionedByteRange src) {
102    return OrderedBytes.decodeNumericAsLong(src);
103  }
104
105  /**
106   * Write instance {@code val} into buffer {@code dst}.
107   *
108   * @param dst the {@link PositionedByteRange} to write to
109   * @param val the value to write to {@code dst}
110   * @return the number of bytes written
111   */
112  public int encodeLong(PositionedByteRange dst, long val) {
113    return OrderedBytes.encodeNumeric(dst, val, order);
114  }
115
116  /**
117   * Read a {@code double} value from the buffer {@code src}.
118   *
119   * @param src the {@link PositionedByteRange} to read the {@code double} from
120   * @return the {@code double} read from the buffer
121   */
122  public double decodeDouble(PositionedByteRange src) {
123    return OrderedBytes.decodeNumericAsLong(src);
124  }
125
126  /**
127   * Write instance {@code val} into buffer {@code dst}.
128   *
129   * @param dst the {@link PositionedByteRange} to write to
130   * @param val the value to write to {@code dst}
131   * @return the number of bytes written
132   */
133  public int encodeDouble(PositionedByteRange dst, double val) {
134    return OrderedBytes.encodeNumeric(dst, val, order);
135  }
136}