Package org.apache.avro.io

Source Code of org.apache.avro.io.BinaryData$Decoders

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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 org.apache.avro.io;

import java.util.Map;
import java.io.ByteArrayInputStream;
import java.io.IOException;

import org.apache.avro.Schema;
import org.apache.avro.Schema.Field;
import org.apache.avro.AvroRuntimeException;
import org.apache.avro.generic.GenericDatumReader;

/** Utilities for binary-encoded data. */
public class BinaryData {

  private BinaryData() {}                      // no public ctor

  private static class Buffer extends ByteArrayInputStream {
    public Buffer() { super(new byte[0]); }
    public byte[] buf() { return buf; }
    public int pos() { return pos; }
    public void skip(int i) { this.pos += i; }
    public void set(byte[] buf, int pos) {
      this.buf = buf;
      this.pos = pos;
      this.count = buf.length;
    }
  }

  private static class Decoders {
    private final Buffer b1, b2;
    private final Decoder d1, d2;
    public Decoders() {
      this.b1 = new Buffer();
      this.b2 = new Buffer();
      this.d1 = new BinaryDecoder(b1);
      this.d2 = new BinaryDecoder(b2);
    }
  }

  private static final ThreadLocal<Decoders> DECODERS
    = new ThreadLocal<Decoders>() {
    @Override protected Decoders initialValue() { return new Decoders(); }
  };

  /** Compare binary encoded data.  If equal, return zero.  If greater-than,
   * return 1, if less than return -1. Order is consistent with that of {@link
   * org.apache.avro.generic.GenericData#compare(Object, Object, Schema)}.*/
  public static int compare(byte[] b1, int s1,
                            byte[] b2, int s2,
                            Schema schema) {
    Decoders decoders = DECODERS.get();
    decoders.b1.set(b1, s1);
    decoders.b2.set(b2, s2);
    try {
      return compare(decoders, schema);
    } catch (IOException e) {
      throw new AvroRuntimeException(e);
    }
  }

  /** If equal, return the number of bytes consumed.  If greater than, return
   * GT, if less than, return LT. */
  private static int compare(Decoders d, Schema schema) throws IOException {
    Decoder d1 = d.d1; Decoder d2 = d.d2;
    switch (schema.getType()) {
    case RECORD: {
      for (Map.Entry<String, Field> entry : schema.getFields().entrySet()) {
        Field field = entry.getValue();
        if (field.order() == Field.Order.IGNORE) {
          GenericDatumReader.skip(field.schema(), d1);
          GenericDatumReader.skip(field.schema(), d2);
          continue;
        }
        int c = compare(d, field.schema());
        if (c != 0)
          return (field.order() != Field.Order.DESCENDING) ? c : -c;
      }
      return 0;
    }
    case ENUM: case INT: case LONG: {
      long l1 = d1.readLong();
      long l2 = d2.readLong();
      return l1 == l2 ? 0 : (l1 > l2 ? 1 : -1);
    }
    case ARRAY: {
      long i = 0;                                 // position in array
      long r1 = 0, r2 = 0;                        // remaining in current block
      long l1 = 0, l2 = 0;                        // total array length
      while (true) {
        if (r1 == 0) {                            // refill blocks(s)
          r1 = d1.readLong();
          if (r1 < 0) { r1 = -r1; d1.readLong(); }
          l1 += r1;
        }
        if (r2 == 0) {
          r2 = d2.readLong();
          if (r2 < 0) { r2 = -r2; d2.readLong(); }
          l2 += r2;
        }
        if (r1 == 0 || r2 == 0)                   // empty block: done
          return (l1 == l2) ? 0 : ((l1 > l2) ? 1 : -1);
        long l = Math.min(l1, l2);
        while (i < l) {                           // compare to end of block
          int c = compare(d, schema.getElementType());
          if (c != 0) return c;
          i++; r1--; r2--;
        }
      }
    }
    case MAP:
      throw new AvroRuntimeException("Can't compare maps!");
    case UNION: {
      int i1 = d1.readInt();
      int i2 = d2.readInt();
      if (i1 == i2) {
        return compare(d, schema.getTypes().get(i1));
      } else {
        return i1 - i2;
      }
    }
    case FIXED: {
      int size = schema.getFixedSize();
      int c = compareBytes(d.b1.buf(), d.b1.pos(), size,
                           d.b2.buf(), d.b2.pos(), size);
      d.b1.skip(size);
      d.b2.skip(size);
      return c;
    }
    case STRING: case BYTES: {
      int l1 = d1.readInt();
      int l2 = d2.readInt();
      int c = compareBytes(d.b1.buf(), d.b1.pos(), l1,
                           d.b2.buf(), d.b2.pos(), l2);
      d.b1.skip(l1);
      d.b2.skip(l2);
      return c;
    }
    case FLOAT: {
      float f1 = d1.readFloat();
      float f2 = d2.readFloat();
      return (f1 == f2) ? 0 : ((f1 > f2) ? 1 : -1);
    }
    case DOUBLE: {
      double f1 = d1.readDouble();
      double f2 = d2.readDouble();
      return (f1 == f2) ? 0 : ((f1 > f2) ? 1 : -1);
    }
    case BOOLEAN:
      boolean b1 = d1.readBoolean();
      boolean b2 = d2.readBoolean();
      return (b1 == b2) ? 0 : (b1 ? 1 : -1);
    case NULL:
      return 0;
    default:
      throw new AvroRuntimeException("Unexpected schema to compare!");
    }
  }

  /** Lexicographically compare bytes.  If equal, return zero.  If greater-than,
   * return a positive value, if less than return a negative value. */
  public static int compareBytes(byte[] b1, int s1, int l1,
                                 byte[] b2, int s2, int l2) {
    int end1 = s1 + l1;
    int end2 = s2 + l2;
    for (int i = s1, j = s2; i < end1 && j < end2; i++, j++) {
      int a = (b1[i] & 0xff);
      int b = (b2[j] & 0xff);
      if (a != b) {
        return a - b;
      }
    }
    return l1 - l2;
  }

}
TOP

Related Classes of org.apache.avro.io.BinaryData$Decoders

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.