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.util.Iterator; 021import java.util.NoSuchElementException; 022import org.apache.hadoop.hbase.util.PositionedByteRange; 023import org.apache.yetus.audience.InterfaceAudience; 024 025/** 026 * An {@link Iterator} over encoded {@code Struct} members. 027 * <p> 028 * This iterates over each serialized {@code Struct} field from the specified {@code DataTypes<?>[]} 029 * definition. It allows you to read the field or skip over its serialized bytes using 030 * {@link #next()} and {@link #skip()}, respectively. This is in contrast to the {@code Struct} 031 * method which allow you to {@link Struct#decode(PositionedByteRange)} or 032 * {@link Struct#skip(PositionedByteRange)} over the entire {@code Struct} at once. 033 * </p> 034 * <p> 035 * This iterator may also be used to read bytes from any {@code Struct} for which the specified 036 * {@code DataType<?>[]} is a prefix. For example, if the specified {@code Struct} definition has a 037 * {@link RawInteger} and a {@link RawStringTerminated} field, you may parse the serialized output 038 * of a {@code Struct} whose fields are {@link RawInteger}, {@link RawStringTerminated}, and 039 * {@link RawBytes}. The iterator would return a number followed by a {@code String}. The trailing 040 * {@code byte[]} would be ignored. 041 * </p> 042 */ 043@InterfaceAudience.Public 044public class StructIterator implements Iterator<Object> { 045 046 protected final PositionedByteRange src; 047 protected int idx = 0; 048 @SuppressWarnings("rawtypes") 049 protected final DataType[] types; 050 051 /** 052 * Construct {@code StructIterator} over the values encoded in {@code src} using the specified 053 * {@code types} definition. 054 * @param src The buffer from which to read encoded values. 055 * @param types The sequence of types to use as the schema for this {@code Struct}. 056 */ 057 public StructIterator(PositionedByteRange src, @SuppressWarnings("rawtypes") DataType[] types) { 058 this.src = src; 059 this.types = types; 060 } 061 062 @Override 063 public boolean hasNext() { 064 // hasNext can return true when position == length in the case of a 065 // nullable field trailing a struct. 066 return idx < types.length && src.getPosition() <= src.getLength(); 067 } 068 069 @Override 070 public void remove() { 071 throw new UnsupportedOperationException(); 072 } 073 074 @Override 075 public Object next() { 076 if (!hasNext()) { 077 throw new NoSuchElementException(); 078 } 079 DataType<?> t = types[idx++]; 080 if (src.getPosition() == src.getLength() && t.isNullable()) { 081 return null; 082 } 083 return t.decode(src); 084 } 085 086 /** 087 * Bypass the next encoded value. 088 * @return the number of bytes skipped. 089 */ 090 public int skip() { 091 if (!hasNext()) { 092 throw new NoSuchElementException(); 093 } 094 DataType<?> t = types[idx++]; 095 if (src.getPosition() == src.getLength() && t.isNullable()) { 096 return 0; 097 } 098 return t.skip(src); 099 } 100}