/* * 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.jena.tdb.base.record; import static java.lang.String.format; import java.util.Arrays; import org.apache.jena.atlas.lib.Bytes ; import org.apache.jena.tdb.sys.SystemTDB ; /** A record is pair of key and value. It may be all key, in which case value is null. */ final public class Record //implements Comparable<Record> { /* * Records of fixed size (controlled by the factory). */ public static final Record NO_REC = null ; final private byte[] key ; final private byte[] value ; public Record(byte[] key, byte[] value) { this.key = key ; this.value = value ; if ( SystemTDB.Checking ) { if ( value != null && value.length == 0 ) throw new RecordException("Zero length value") ; } } public byte[] getKey() { return key ; } public byte[] getValue() { return value ; } // public boolean eq(Record record) // { // return eq(this, record) ; // } // // public boolean lt(Record record) // { // return lt(this, record) ; // } // // public boolean le(Record record) // { // return le(this, record) ; // } // // public boolean ge(Record record) // { // return ge(this, record) ; // } // // public boolean gt(Record record) // { // return gt(this, record) ; // } public boolean hasSeparateValue() { return value!=null ; } @Override public int hashCode() { return Arrays.hashCode(key) ^ Arrays.hashCode(value) ; } @Override public boolean equals(Object other) { if ( this == other ) return true ; if ( ! ( other instanceof Record ) ) return false ; Record r = (Record)other ; return compareByKeyValue(this, r) == 0 ; } @Override public String toString() { if ( value == null ) return str(key) ; return str(key)+":"+str(value) ; } /** Is the key of record1 == key of record2 */ public static boolean keyEQ(Record record1, Record record2) { int x = compareByKey(record1, record2) ; return x == 0 ; } /** Is the key of record1 != key of record2 */ public static boolean keyNE(Record record1, Record record2) { int x = compareByKey(record1, record2) ; return x != 0 ; } /** Is the key of record1 < key of record2 */ public static boolean keyLT(Record record1, Record record2) { int x = compareByKey(record1, record2) ; return x < 0 ; } /** Is the key of record1 <= key of record2 */ public static boolean keyLE(Record record1, Record record2) { int x = compareByKey(record1, record2) ; return x <= 0 ; } /** Is the key of record1 >= key of record2 */ public static boolean keyGE(Record record1, Record record2) { int x = compareByKey(record1, record2) ; return x >= 0 ; } /** Is the key of record1 > key of record2 */ public static boolean keyGT(Record record1, Record record2) { int x = compareByKey(record1, record2) ; return x > 0 ; } /** Is (key, value) of record1 equal to (key,value) of record2 */ public static boolean equals(Record record1, Record record2) { int x = compareByKeyValue(record1, record2) ; return x == 0 ; } static public String str(byte[] b) { StringBuilder str = new StringBuilder() ; for ( byte aB : b ) { str.append( format( "%02x", aB ) ); } return str.toString() ; } public static int compareByKey(Record record1, Record record2) { checkKeyCompatible(record1, record2) ; return Bytes.compare(record1.key, record2.key) ; } public static int compareByKeyValue(Record record1, Record record2) { checkCompatible(record1, record2) ; int x = Bytes.compare(record1.key, record2.key) ; if ( x == 0 ) { if ( record1.value != null ) x = Bytes.compare(record1.value, record2.value) ; } return x ; } static void checkCompatible(Record record1, Record record2) { if ( ! compatible(record1, record2, true) ) throw new RecordException(format("Incompatible: %s, %s", record1, record2)) ; } static void checkKeyCompatible(Record record1, Record record2) { if ( ! compatible(record1, record2, false) ) throw new RecordException(format("Incompatible: %s, %s", record1, record2)) ; } static boolean compatible(Record record1, Record record2, boolean checkValue) { if ( record1.key.length != record2.key.length ) return false ; if ( checkValue ) { if ( record1.value == null && record2.value == null ) return true ; if ( record1.value == null ) return false ; if ( record2.value == null ) return false ; if ( record1.value.length != record2.value.length ) return false; } return true ; } // private static int compare(byte[] x1, byte[] x2) // { // for ( int i = 0 ; i < x1.length ; i++ ) // { // byte b1 = x1[i] ; // byte b2 = x2[i] ; // if ( b1 == b2 ) // continue ; // // Treat as unsigned values in the bytes. // return (b1&0xFF) - (b2&0xFF) ; // } // return 0 ; // } }