View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.types;
19  
20  import java.util.Iterator;
21  import java.util.NoSuchElementException;
22  
23  import org.apache.hadoop.hbase.classification.InterfaceAudience;
24  import org.apache.hadoop.hbase.classification.InterfaceStability;
25  import org.apache.hadoop.hbase.util.PositionedByteRange;
26  
27  /**
28   * An {@link Iterator} over encoded {@code Struct} members.
29   * <p>
30   * This iterates over each serialized {@code Struct} field from the specified
31   * {@code DataTypes<?>[]} definition. It allows you to read the field or skip
32   * over its serialized bytes using {@link #next()} and {@link #skip()},
33   * respectively. This is in contrast to the {@code Struct} method which allow
34   * you to {@link Struct#decode(PositionedByteRange)} or
35   * {@link Struct#skip(PositionedByteRange)} over the entire {@code Struct} at
36   * once.
37   * </p>
38   * <p>
39   * This iterator may also be used to read bytes from any {@code Struct} for
40   * which the specified {@code DataType<?>[]} is a prefix. For example, if the
41   * specified {@code Struct} definition has a {@link RawInteger} and a
42   * {@link RawStringTerminated} field, you may parse the serialized output
43   * of a {@code Struct} whose fields are {@link RawInteger},
44   * {@link RawStringTerminated}, and {@link RawBytes}. The iterator would
45   * return a number followed by a {@code String}. The trailing {@code byte[]}
46   * would be ignored.
47   * </p>
48   */
49  @InterfaceAudience.Public
50  @InterfaceStability.Evolving
51  public class StructIterator implements Iterator<Object> {
52  
53    protected final PositionedByteRange src;
54    protected int idx = 0;
55    @SuppressWarnings("rawtypes")
56    protected final DataType[] types;
57  
58    /**
59     * Construct {@code StructIterator} over the values encoded in {@code src}
60     * using the specified {@code types} definition.
61     * @param src The buffer from which to read encoded values.
62     * @param types The sequence of types to use as the schema for this
63     *          {@code Struct}.
64     */
65    public StructIterator(PositionedByteRange src, @SuppressWarnings("rawtypes") DataType[] types) {
66      this.src = src;
67      this.types = types;
68    }
69  
70    @Override
71    public boolean hasNext() {
72      // hasNext can return true when position == length in the case of a
73      // nullable field trailing a struct.
74      return idx < types.length && src.getPosition() <= src.getLength();
75    }
76  
77    @Override
78    public void remove() { throw new UnsupportedOperationException(); }
79  
80    @Override
81    public Object next() {
82      if (!hasNext()) throw new NoSuchElementException();
83      DataType<?> t = types[idx++];
84      if (src.getPosition() == src.getLength() && t.isNullable()) return null;
85      return t.decode(src);
86    }
87  
88    /**
89     * Bypass the next encoded value.
90     * @return the number of bytes skipped.
91     */
92    public int skip() {
93      if (!hasNext()) throw new NoSuchElementException();
94      DataType<?> t = types[idx++];
95      if (src.getPosition() == src.getLength() && t.isNullable()) return 0;
96      return t.skip(src);
97    }
98  }