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;
022import org.apache.hadoop.hbase.util.Order;
023import org.apache.hadoop.hbase.util.OrderedBytes;
024import org.apache.hadoop.hbase.util.PositionedByteRange;
025import org.apache.hadoop.hbase.util.SimplePositionedMutableByteRange;
026import org.apache.yetus.audience.InterfaceAudience;
027
028/**
029 * An {@link Number} of arbitrary precision and variable-length encoding. The resulting length of
030 * encoded values is determined by the numerical (base 100) precision, not absolute value. Use this
031 * data type anywhere you would expect to use a {@code DECIMAL} type, a {@link BigDecimal}, a
032 * {@link BigInteger}, or any time you've parsed floating precision values from text. Built on
033 * {@link OrderedBytes#encodeNumeric(PositionedByteRange, BigDecimal, Order)}.
034 */
035@InterfaceAudience.Public
036public class OrderedNumeric extends OrderedBytesBase<Number> {
037
038  public static final OrderedNumeric ASCENDING = new OrderedNumeric(Order.ASCENDING);
039  public static final OrderedNumeric DESCENDING = new OrderedNumeric(Order.DESCENDING);
040
041  protected OrderedNumeric(Order order) {
042    super(order);
043  }
044
045  @Override
046  public int encodedLength(Number val) {
047    // TODO: this could be done better.
048    PositionedByteRange buff = new SimplePositionedMutableByteRange(100);
049    return encode(buff, val);
050  }
051
052  @Override
053  public Class<Number> encodedClass() {
054    return Number.class;
055  }
056
057  @Override
058  public Number decode(PositionedByteRange src) {
059    if (OrderedBytes.isNumericInfinite(src) || OrderedBytes.isNumericNaN(src)) {
060      return OrderedBytes.decodeNumericAsDouble(src);
061    }
062    return OrderedBytes.decodeNumericAsBigDecimal(src);
063  }
064
065  @Override
066  public int encode(PositionedByteRange dst, Number val) {
067    if (null == val) {
068      return OrderedBytes.encodeNull(dst, order);
069    } else if (val instanceof BigDecimal) {
070      return OrderedBytes.encodeNumeric(dst, (BigDecimal) val, order);
071    } else if (val instanceof BigInteger) {
072      return OrderedBytes.encodeNumeric(dst, new BigDecimal((BigInteger) val), order);
073    } else if (val instanceof Double || val instanceof Float) {
074      return OrderedBytes.encodeNumeric(dst, val.doubleValue(), order);
075    } else {
076      // TODO: other instances of Numeric to consider?
077      return OrderedBytes.encodeNumeric(dst, val.longValue(), order);
078    }
079  }
080
081  /**
082   * Read a {@code long} value from the buffer {@code src}.
083   */
084  public long decodeLong(PositionedByteRange src) {
085    return OrderedBytes.decodeNumericAsLong(src);
086  }
087
088  /**
089   * Write instance {@code val} into buffer {@code dst}.
090   */
091  public int encodeLong(PositionedByteRange dst, long val) {
092    return OrderedBytes.encodeNumeric(dst, val, order);
093  }
094
095  /**
096   * Read a {@code double} value from the buffer {@code src}.
097   */
098  public double decodeDouble(PositionedByteRange src) {
099    return OrderedBytes.decodeNumericAsLong(src);
100  }
101
102  /**
103   * Write instance {@code val} into buffer {@code dst}.
104   */
105  public int encodeDouble(PositionedByteRange dst, double val) {
106    return OrderedBytes.encodeNumeric(dst, val, order);
107  }
108}