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 org.apache.hadoop.hbase.util.Order; 021import org.apache.hadoop.hbase.util.PositionedByteRange; 022import org.apache.hadoop.hbase.util.SimplePositionedMutableByteRange; 023import org.apache.yetus.audience.InterfaceAudience; 024 025/** 026 * Wraps an existing {@link DataType} implementation as a fixed-length version of itself. This has 027 * the useful side-effect of turning an existing {@link DataType} which is not {@code skippable} 028 * into a {@code skippable} variant. 029 */ 030@InterfaceAudience.Public 031public class FixedLengthWrapper<T> implements DataType<T> { 032 033 protected final DataType<T> base; 034 protected final int length; 035 036 /** 037 * Create a fixed-length version of the {@code wrapped}. 038 * @param base the {@link DataType} to restrict to a fixed length. 039 * @param length the maximum length (in bytes) for encoded values. 040 */ 041 public FixedLengthWrapper(DataType<T> base, int length) { 042 this.base = base; 043 this.length = length; 044 } 045 046 /** 047 * Retrieve the maximum length (in bytes) of encoded values. 048 */ 049 public int getLength() { 050 return length; 051 } 052 053 @Override 054 public boolean isOrderPreserving() { 055 return base.isOrderPreserving(); 056 } 057 058 @Override 059 public Order getOrder() { 060 return base.getOrder(); 061 } 062 063 @Override 064 public boolean isNullable() { 065 return base.isNullable(); 066 } 067 068 @Override 069 public boolean isSkippable() { 070 return true; 071 } 072 073 @Override 074 public int encodedLength(T val) { 075 return length; 076 } 077 078 @Override 079 public Class<T> encodedClass() { 080 return base.encodedClass(); 081 } 082 083 @Override 084 public int skip(PositionedByteRange src) { 085 src.setPosition(src.getPosition() + this.length); 086 return this.length; 087 } 088 089 @Override 090 public T decode(PositionedByteRange src) { 091 if (src.getRemaining() < length) { 092 throw new IllegalArgumentException( 093 "Not enough buffer remaining. src.offset: " + src.getOffset() + " src.length: " 094 + src.getLength() + " src.position: " + src.getPosition() + " max length: " + length); 095 } 096 // create a copy range limited to length bytes. boo. 097 PositionedByteRange b = new SimplePositionedMutableByteRange(length); 098 src.get(b.getBytes()); 099 return base.decode(b); 100 } 101 102 @Override 103 public int encode(PositionedByteRange dst, T val) { 104 if (dst.getRemaining() < length) { 105 throw new IllegalArgumentException( 106 "Not enough buffer remaining. dst.offset: " + dst.getOffset() + " dst.length: " 107 + dst.getLength() + " dst.position: " + dst.getPosition() + " max length: " + length); 108 } 109 int written = base.encode(dst, val); 110 if (written > length) { 111 throw new IllegalArgumentException( 112 "Length of encoded value (" + written + ") exceeds max length (" + length + ")."); 113 } 114 // TODO: is the zero-padding appropriate? 115 for (; written < length; written++) { 116 dst.put((byte) 0x00); 117 } 118 return written; 119 } 120}