This is an automated email from the ASF dual-hosted git repository.

clesaec pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/avro.git


The following commit(s) were added to refs/heads/master by this push:
     new 373503573 AVRO-2307: [java] list of primitive (#2389)
373503573 is described below

commit 37350357335d906aea23cfcacdbd1c1f4eda090d
Author: Christophe Le Saec <[email protected]>
AuthorDate: Thu Aug 17 11:05:17 2023 +0200

    AVRO-2307: [java] list of primitive (#2389)
    
    * AVRO-2307: list of primitive
---
 .../java/org/apache/avro/generic/GenericData.java  | 134 +++--
 .../org/apache/avro/generic/PrimitivesArrays.java  | 609 +++++++++++++++++++++
 .../apache/avro/generic/GenericDataArrayTest.java  |  44 ++
 .../apache/avro/generic/PrimitivesArraysTest.java  | 280 ++++++++++
 4 files changed, 1022 insertions(+), 45 deletions(-)

diff --git 
a/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java 
b/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java
index 2f2a103eb..6db0a40ee 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java
@@ -317,30 +317,16 @@ public class GenericData {
     }
   }
 
-  /** Default implementation of an array. */
-  @SuppressWarnings(value = "unchecked")
-  public static class Array<T> extends AbstractList<T> implements 
GenericArray<T>, Comparable<GenericArray<T>> {
-    private static final Object[] EMPTY = new Object[0];
+  public static abstract class AbstractArray<T> extends AbstractList<T>
+      implements GenericArray<T>, Comparable<GenericArray<T>> {
     private final Schema schema;
-    private int size;
-    private Object[] elements = EMPTY;
 
-    public Array(int capacity, Schema schema) {
-      if (schema == null || !Type.ARRAY.equals(schema.getType()))
-        throw new AvroRuntimeException("Not an array schema: " + schema);
-      this.schema = schema;
-      if (capacity != 0)
-        elements = new Object[capacity];
-    }
+    protected int size = 0;
 
-    public Array(Schema schema, Collection<T> c) {
+    public AbstractArray(Schema schema) {
       if (schema == null || !Type.ARRAY.equals(schema.getType()))
         throw new AvroRuntimeException("Not an array schema: " + schema);
       this.schema = schema;
-      if (c != null) {
-        elements = new Object[c.size()];
-        addAll(c);
-      }
     }
 
     @Override
@@ -354,22 +340,26 @@ public class GenericData {
     }
 
     @Override
-    public void clear() {
-      // Let GC do its work
-      Arrays.fill(elements, 0, size, null);
+    public void reset() {
       size = 0;
     }
 
     @Override
-    public void reset() {
-      size = 0;
+    public int compareTo(GenericArray<T> that) {
+      return GenericData.get().compare(this, that, this.getSchema());
     }
 
     @Override
-    public void prune() {
-      if (size < elements.length) {
-        Arrays.fill(elements, size, elements.length, null);
+    public boolean equals(final Object o) {
+      if (!(o instanceof Collection)) {
+        return false;
       }
+      return GenericData.get().compare(this, o, this.getSchema()) == 0;
+    }
+
+    @Override
+    public int hashCode() {
+      return super.hashCode();
     }
 
     @Override
@@ -384,7 +374,7 @@ public class GenericData {
 
         @Override
         public T next() {
-          return (T) elements[position++];
+          return AbstractArray.this.get(position++);
         }
 
         @Override
@@ -394,6 +384,57 @@ public class GenericData {
       };
     }
 
+    @Override
+    public void reverse() {
+      int left = 0;
+      int right = size - 1;
+
+      while (left < right) {
+        this.swap(left, right);
+
+        left++;
+        right--;
+      }
+    }
+
+    protected abstract void swap(int index1, int index2);
+  }
+
+  /** Default implementation of an array. */
+  @SuppressWarnings(value = "unchecked")
+  public static class Array<T> extends AbstractArray<T> {
+    private static final Object[] EMPTY = new Object[0];
+
+    private Object[] elements = EMPTY;
+
+    public Array(int capacity, Schema schema) {
+      super(schema);
+      if (capacity != 0)
+        elements = new Object[capacity];
+    }
+
+    public Array(Schema schema, Collection<T> c) {
+      super(schema);
+      if (c != null) {
+        elements = new Object[c.size()];
+        addAll(c);
+      }
+    }
+
+    @Override
+    public void clear() {
+      // Let GC do its work
+      Arrays.fill(elements, 0, size, null);
+      size = 0;
+    }
+
+    @Override
+    public void prune() {
+      if (size < elements.length) {
+        Arrays.fill(elements, size, elements.length, null);
+      }
+    }
+
     @Override
     public T get(int i) {
       if (i >= size)
@@ -442,23 +483,10 @@ public class GenericData {
     }
 
     @Override
-    public int compareTo(GenericArray<T> that) {
-      return GenericData.get().compare(this, that, this.getSchema());
-    }
-
-    @Override
-    public void reverse() {
-      int left = 0;
-      int right = elements.length - 1;
-
-      while (left < right) {
-        Object tmp = elements[left];
-        elements[left] = elements[right];
-        elements[right] = tmp;
-
-        left++;
-        right--;
-      }
+    protected void swap(final int index1, final int index2) {
+      Object tmp = elements[index1];
+      elements[index1] = elements[index2];
+      elements[index2] = tmp;
     }
   }
 
@@ -1499,8 +1527,24 @@ public class GenericData {
     } else if (old instanceof Collection) {
       ((Collection<?>) old).clear();
       return old;
-    } else
+    } else {
+      if (schema.getElementType().getType() == Type.INT) {
+        return new PrimitivesArrays.IntArray(size, schema);
+      }
+      if (schema.getElementType().getType() == Type.BOOLEAN) {
+        return new PrimitivesArrays.BooleanArray(size, schema);
+      }
+      if (schema.getElementType().getType() == Type.LONG) {
+        return new PrimitivesArrays.LongArray(size, schema);
+      }
+      if (schema.getElementType().getType() == Type.FLOAT) {
+        return new PrimitivesArrays.FloatArray(size, schema);
+      }
+      if (schema.getElementType().getType() == Type.DOUBLE) {
+        return new PrimitivesArrays.DoubleArray(size, schema);
+      }
       return new GenericData.Array<Object>(size, schema);
+    }
   }
 
   /**
diff --git 
a/lang/java/avro/src/main/java/org/apache/avro/generic/PrimitivesArrays.java 
b/lang/java/avro/src/main/java/org/apache/avro/generic/PrimitivesArrays.java
new file mode 100644
index 000000000..d34ce0f5b
--- /dev/null
+++ b/lang/java/avro/src/main/java/org/apache/avro/generic/PrimitivesArrays.java
@@ -0,0 +1,609 @@
+/*
+ * 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
+ *
+ *     https://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.generic;
+
+import org.apache.avro.AvroRuntimeException;
+import org.apache.avro.Schema;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+public class PrimitivesArrays {
+
+  public static class IntArray extends GenericData.AbstractArray<Integer> {
+    private static final int[] EMPTY = new int[0];
+
+    private int[] elements = EMPTY;
+
+    public IntArray(int capacity, Schema schema) {
+      super(schema);
+      if (!Schema.Type.INT.equals(schema.getElementType().getType()))
+        throw new AvroRuntimeException("Not a int array schema: " + schema);
+      if (capacity != 0)
+        elements = new int[capacity];
+    }
+
+    public IntArray(Schema schema, Collection<Integer> c) {
+      super(schema);
+      if (c != null) {
+        elements = new int[c.size()];
+        addAll(c);
+      }
+    }
+
+    @Override
+    public void clear() {
+      size = 0;
+    }
+
+    @Override
+    public Integer get(int i) {
+      return this.getInt(i);
+    }
+
+    /**
+     * Direct primitive int access.
+     * 
+     * @param i : index.
+     * @return value at index.
+     */
+    public int getInt(int i) {
+      if (i >= size)
+        throw new IndexOutOfBoundsException("Index " + i + " out of bounds.");
+      return elements[i];
+    }
+
+    @Override
+    public void add(int location, Integer o) {
+      if (o == null) {
+        return;
+      }
+      this.add(location, o.intValue());
+    }
+
+    public void add(int location, int o) {
+      if (location > size || location < 0) {
+        throw new IndexOutOfBoundsException("Index " + location + " out of 
bounds.");
+      }
+      if (size == elements.length) {
+        // Increase size by 1.5x + 1
+        final int newSize = size + (size >> 1) + 1;
+        elements = Arrays.copyOf(elements, newSize);
+      }
+      System.arraycopy(elements, location, elements, location + 1, size - 
location);
+      elements[location] = o;
+      size++;
+    }
+
+    @Override
+    public Integer set(int i, Integer o) {
+      if (o == null) {
+        return null;
+      }
+      return this.set(i, o.intValue());
+    }
+
+    public int set(int i, int o) {
+      if (i >= size)
+        throw new IndexOutOfBoundsException("Index " + i + " out of bounds.");
+      int response = elements[i];
+      elements[i] = o;
+      return response;
+    }
+
+    @Override
+    public Integer remove(int i) {
+      if (i >= size)
+        throw new IndexOutOfBoundsException("Index " + i + " out of bounds.");
+      int result = elements[i];
+      --size;
+      System.arraycopy(elements, i + 1, elements, i, (size - i));
+      return result;
+    }
+
+    @Override
+    public Integer peek() {
+      return (size < elements.length) ? elements[size] : null;
+    }
+
+    @Override
+    protected void swap(final int index1, final int index2) {
+      int tmp = elements[index1];
+      elements[index1] = elements[index2];
+      elements[index2] = tmp;
+    }
+  }
+
+  public static class LongArray extends GenericData.AbstractArray<Long> {
+    private static final long[] EMPTY = new long[0];
+
+    private long[] elements = EMPTY;
+
+    public LongArray(int capacity, Schema schema) {
+      super(schema);
+      if (!Schema.Type.LONG.equals(schema.getElementType().getType()))
+        throw new AvroRuntimeException("Not a long array schema: " + schema);
+      if (capacity != 0)
+        elements = new long[capacity];
+    }
+
+    public LongArray(Schema schema, Collection<Long> c) {
+      super(schema);
+      if (c != null) {
+        elements = new long[c.size()];
+        addAll(c);
+      }
+    }
+
+    @Override
+    public void clear() {
+      size = 0;
+    }
+
+    @Override
+    public Long get(int i) {
+      return getLong(i);
+    }
+
+    /**
+     * Direct primitive int access.
+     * 
+     * @param i : index.
+     * @return value at index.
+     */
+    public long getLong(int i) {
+      if (i >= size)
+        throw new IndexOutOfBoundsException("Index " + i + " out of bounds.");
+      return elements[i];
+    }
+
+    @Override
+    public void add(int location, Long o) {
+      if (o == null) {
+        return;
+      }
+      this.add(location, o.longValue());
+    }
+
+    public void add(int location, long o) {
+      if (location > size || location < 0) {
+        throw new IndexOutOfBoundsException("Index " + location + " out of 
bounds.");
+      }
+      if (size == elements.length) {
+        // Increase size by 1.5x + 1
+        final int newSize = size + (size >> 1) + 1;
+        elements = Arrays.copyOf(elements, newSize);
+      }
+      System.arraycopy(elements, location, elements, location + 1, size - 
location);
+      elements[location] = o;
+      size++;
+    }
+
+    @Override
+    public Long set(int i, Long o) {
+      if (o == null) {
+        return null;
+      }
+      return this.set(i, o.longValue());
+    }
+
+    public long set(int i, long o) {
+      if (i >= size)
+        throw new IndexOutOfBoundsException("Index " + i + " out of bounds.");
+      long response = elements[i];
+      elements[i] = o;
+      return response;
+    }
+
+    @Override
+    public Long remove(int i) {
+      if (i >= size)
+        throw new IndexOutOfBoundsException("Index " + i + " out of bounds.");
+      long result = elements[i];
+      --size;
+      System.arraycopy(elements, i + 1, elements, i, (size - i));
+      return result;
+    }
+
+    @Override
+    public Long peek() {
+      return (size < elements.length) ? elements[size] : null;
+    }
+
+    @Override
+    protected void swap(final int index1, final int index2) {
+      long tmp = elements[index1];
+      elements[index1] = elements[index2];
+      elements[index2] = tmp;
+    }
+  }
+
+  public static class BooleanArray extends GenericData.AbstractArray<Boolean> {
+    private static final byte[] EMPTY = new byte[0];
+
+    private byte[] elements = EMPTY;
+
+    public BooleanArray(int capacity, Schema schema) {
+      super(schema);
+      if (!Schema.Type.BOOLEAN.equals(schema.getElementType().getType()))
+        throw new AvroRuntimeException("Not a boolean array schema: " + 
schema);
+      if (capacity != 0)
+        elements = new byte[1 + (capacity / Byte.SIZE)];
+    }
+
+    public BooleanArray(Schema schema, Collection<Boolean> c) {
+      super(schema);
+
+      if (c != null) {
+        elements = new byte[1 + (c.size() / 8)];
+        if (c instanceof BooleanArray) {
+          BooleanArray other = (BooleanArray) c;
+          this.size = other.size;
+          System.arraycopy(other.elements, 0, this.elements, 0, 
other.elements.length);
+        } else {
+          addAll(c);
+        }
+      }
+    }
+
+    @Override
+    public void clear() {
+      size = 0;
+    }
+
+    @Override
+    public Boolean get(int i) {
+      return this.getBoolean(i);
+    }
+
+    /**
+     * Direct primitive int access.
+     * 
+     * @param i : index.
+     * @return value at index.
+     */
+    public boolean getBoolean(int i) {
+      if (i >= size)
+        throw new IndexOutOfBoundsException("Index " + i + " out of bounds.");
+      return (elements[i / 8] & (1 << (i % 8))) > 0;
+    }
+
+    @Override
+    public boolean add(final Boolean o) {
+      if (o == null) {
+        return false;
+      }
+      return this.add(o.booleanValue());
+    }
+
+    public boolean add(final boolean o) {
+      if (this.size == elements.length * 8) {
+        final int newLength = elements.length + (elements.length >> 1) + 1;
+        elements = Arrays.copyOf(elements, newLength);
+      }
+      this.size++;
+      this.set(this.size - 1, o);
+      return true;
+    }
+
+    @Override
+    public void add(int location, Boolean o) {
+      if (o == null) {
+        return;
+      }
+      this.add(location, o.booleanValue());
+    }
+
+    public void add(int location, boolean o) {
+      if (location > size || location < 0) {
+        throw new IndexOutOfBoundsException("Index " + location + " out of 
bounds.");
+      }
+      if (size == elements.length * 8) {
+        // Increase size by 1.5x + 1
+        final int newLength = elements.length + (elements.length >> 1) + 1;
+        elements = Arrays.copyOf(elements, newLength);
+      }
+      size++;
+      for (int index = this.size / 8; index > (location / 8); index--) {
+        elements[index] <<= 1;
+        if (index > 0 && (elements[index - 1] & (1 << Byte.SIZE)) > 0) {
+          elements[index] |= 1;
+        }
+      }
+      byte pos = (byte) (1 << (location % Byte.SIZE));
+      byte highbits = (byte) ~(pos + (pos - 1));
+      byte lowbits = (byte) (pos - 1);
+      byte currentHigh = (byte) ((elements[location / 8] & highbits) << 1);
+      byte currentLow = (byte) (elements[location / 8] & lowbits);
+      if (o) {
+        elements[location / 8] = (byte) (currentHigh | currentLow | pos);
+      } else {
+        elements[location / 8] = (byte) (currentHigh | currentLow);
+      }
+
+    }
+
+    @Override
+    public Boolean set(int i, Boolean o) {
+      if (o == null) {
+        return null;
+      }
+      return this.set(i, o.booleanValue());
+    }
+
+    public boolean set(int i, boolean o) {
+      if (i >= size)
+        throw new IndexOutOfBoundsException("Index " + i + " out of bounds.");
+      boolean response = (elements[i / 8] & (1 << (i % 8))) > 0;
+      if (o) {
+        elements[i / 8] |= 1 << (i % 8);
+      } else {
+        elements[i / 8] &= 0xFF - (1 << (i % 8));
+      }
+      return response;
+    }
+
+    @Override
+    public Boolean remove(int i) {
+      if (i >= size)
+        throw new IndexOutOfBoundsException("Index " + i + " out of bounds.");
+      boolean result = (elements[(i / 8)] & (1 << (i % 8))) > 0;
+      --size;
+
+      byte memo = 0;
+      if ((i / 8) + 1 < elements.length) {
+        memo = (byte) ((1 & (elements[(i / 8) + 1])) << 7);
+      }
+      for (int index = (i / 8) + 1; index <= (size / 8); index++) {
+        elements[index] = (byte) ((elements[index] & 0xff) >>> 1);
+        if (index + 1 < elements.length && (elements[index + 1] & 1) == 1) {
+          elements[index] |= 1 << (Byte.SIZE - 1);
+        }
+      }
+      // 87654321 => <memo>8764321
+      byte start = (byte) ((1 << ((i + 1) % 8)) - 1);
+      byte end = (byte) ~start;
+      elements[i / 8] = (byte) ((((start & 0xff) >>> 1) & elements[i / 8]) // 
1234
+          | (end & (elements[i / 8] >> 1)) // 876
+          | memo);
+
+      return result;
+    }
+
+    @Override
+    public Boolean peek() {
+      return (size < elements.length * Byte.SIZE) ? (elements[(size / 8)] & (1 
<< (size % 8))) > 0 : null;
+    }
+
+    @Override
+    protected void swap(final int index1, final int index2) {
+      boolean tmp = this.get(index1);
+      this.set(index1, this.get(index2));
+      this.set(index2, tmp);
+    }
+  }
+
+  public static class FloatArray extends GenericData.AbstractArray<Float> {
+    private static final float[] EMPTY = new float[0];
+
+    private float[] elements = EMPTY;
+
+    public FloatArray(int capacity, Schema schema) {
+      super(schema);
+      if (!Schema.Type.FLOAT.equals(schema.getElementType().getType()))
+        throw new AvroRuntimeException("Not a float array schema: " + schema);
+      if (capacity != 0)
+        elements = new float[capacity];
+    }
+
+    public FloatArray(Schema schema, Collection<Float> c) {
+      super(schema);
+      if (c != null) {
+        elements = new float[c.size()];
+        addAll(c);
+      }
+    }
+
+    @Override
+    public void clear() {
+      size = 0;
+    }
+
+    @Override
+    public Float get(int i) {
+      return this.getFloat(i);
+    }
+
+    /**
+     * Direct primitive int access.
+     * 
+     * @param i : index.
+     * @return value at index.
+     */
+    public float getFloat(int i) {
+      if (i >= size)
+        throw new IndexOutOfBoundsException("Index " + i + " out of bounds.");
+      return elements[i];
+    }
+
+    @Override
+    public void add(int location, Float o) {
+      if (o == null) {
+        return;
+      }
+      this.add(location, o.floatValue());
+    }
+
+    public void add(int location, float o) {
+      if (location > size || location < 0) {
+        throw new IndexOutOfBoundsException("Index " + location + " out of 
bounds.");
+      }
+      if (size == elements.length) {
+        // Increase size by 1.5x + 1
+        final int newSize = size + (size >> 1) + 1;
+        elements = Arrays.copyOf(elements, newSize);
+      }
+      System.arraycopy(elements, location, elements, location + 1, size - 
location);
+      elements[location] = o;
+      size++;
+    }
+
+    @Override
+    public Float set(int i, Float o) {
+      if (o == null) {
+        return null;
+      }
+      return this.set(i, o.floatValue());
+    }
+
+    public float set(int i, float o) {
+      if (i >= size)
+        throw new IndexOutOfBoundsException("Index " + i + " out of bounds.");
+      float response = elements[i];
+      elements[i] = o;
+      return response;
+    }
+
+    @Override
+    public Float remove(int i) {
+      if (i >= size)
+        throw new IndexOutOfBoundsException("Index " + i + " out of bounds.");
+      float result = elements[i];
+      --size;
+      System.arraycopy(elements, i + 1, elements, i, (size - i));
+      return result;
+    }
+
+    @Override
+    public Float peek() {
+      return (size < elements.length) ? elements[size] : null;
+    }
+
+    @Override
+    protected void swap(final int index1, final int index2) {
+      float tmp = this.get(index1);
+      this.set(index1, this.get(index2));
+      this.set(index2, tmp);
+    }
+  }
+
+  public static class DoubleArray extends GenericData.AbstractArray<Double> {
+    private static final double[] EMPTY = new double[0];
+
+    private double[] elements = EMPTY;
+
+    public DoubleArray(int capacity, Schema schema) {
+      super(schema);
+      if (!Schema.Type.DOUBLE.equals(schema.getElementType().getType()))
+        throw new AvroRuntimeException("Not a double array schema: " + schema);
+      if (capacity != 0)
+        elements = new double[capacity];
+    }
+
+    public DoubleArray(Schema schema, Collection<Double> c) {
+      super(schema);
+      if (c != null) {
+        elements = new double[c.size()];
+        addAll(c);
+      }
+    }
+
+    @Override
+    public void clear() {
+      size = 0;
+    }
+
+    @Override
+    public Double get(int i) {
+      return this.getDouble(i);
+    }
+
+    /**
+     * Direct primitive int access.
+     * 
+     * @param i : index.
+     * @return value at index.
+     */
+    public double getDouble(int i) {
+      if (i >= size)
+        throw new IndexOutOfBoundsException("Index " + i + " out of bounds.");
+      return elements[i];
+    }
+
+    @Override
+    public void add(int location, Double o) {
+      if (o == null) {
+        return;
+      }
+      this.add(location, o.floatValue());
+    }
+
+    public void add(int location, double o) {
+      if (location > size || location < 0) {
+        throw new IndexOutOfBoundsException("Index " + location + " out of 
bounds.");
+      }
+      if (size == elements.length) {
+        // Increase size by 1.5x + 1
+        final int newSize = size + (size >> 1) + 1;
+        elements = Arrays.copyOf(elements, newSize);
+      }
+      System.arraycopy(elements, location, elements, location + 1, size - 
location);
+      elements[location] = o;
+      size++;
+    }
+
+    @Override
+    public Double set(int i, Double o) {
+      if (o == null) {
+        return null;
+      }
+      return this.set(i, o.floatValue());
+    }
+
+    public double set(int i, double o) {
+      if (i >= size)
+        throw new IndexOutOfBoundsException("Index " + i + " out of bounds.");
+      double response = elements[i];
+      elements[i] = o;
+      return response;
+    }
+
+    @Override
+    public Double remove(int i) {
+      if (i >= size)
+        throw new IndexOutOfBoundsException("Index " + i + " out of bounds.");
+      double result = elements[i];
+      --size;
+      System.arraycopy(elements, i + 1, elements, i, (size - i));
+      return result;
+    }
+
+    @Override
+    public Double peek() {
+      return (size < elements.length) ? elements[size] : null;
+    }
+
+    @Override
+    protected void swap(final int index1, final int index2) {
+      double tmp = this.get(index1);
+      this.set(index1, this.get(index2));
+      this.set(index2, tmp);
+    }
+  }
+
+}
diff --git 
a/lang/java/avro/src/test/java/org/apache/avro/generic/GenericDataArrayTest.java
 
b/lang/java/avro/src/test/java/org/apache/avro/generic/GenericDataArrayTest.java
new file mode 100644
index 000000000..a4ffebac0
--- /dev/null
+++ 
b/lang/java/avro/src/test/java/org/apache/avro/generic/GenericDataArrayTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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
+ *
+ *     https://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.generic;
+
+import org.apache.avro.Schema;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class GenericDataArrayTest {
+
+  @Test
+  void test() {
+    GenericData.Array<String> array = new GenericData.Array<>(10,
+        Schema.createArray(Schema.create(Schema.Type.STRING)));
+    array.add("One");
+    array.add("Two");
+    array.add("Two");
+    array.add("Three");
+    array.add(4, "Four");
+    array.remove(1);
+    Assertions.assertEquals(4, array.size());
+    Assertions.assertEquals("One", array.get(0));
+    Assertions.assertEquals("Two", array.get(1));
+    Assertions.assertEquals("Three", array.get(2));
+    Assertions.assertEquals("Four", array.get(3));
+  }
+
+}
diff --git 
a/lang/java/avro/src/test/java/org/apache/avro/generic/PrimitivesArraysTest.java
 
b/lang/java/avro/src/test/java/org/apache/avro/generic/PrimitivesArraysTest.java
new file mode 100644
index 000000000..7d199bf92
--- /dev/null
+++ 
b/lang/java/avro/src/test/java/org/apache/avro/generic/PrimitivesArraysTest.java
@@ -0,0 +1,280 @@
+/*
+ * 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
+ *
+ *     https://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.generic;
+
+import org.apache.avro.Schema;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class PrimitivesArraysTest {
+
+  @Test
+  void booleanArray() {
+    PrimitivesArrays.BooleanArray ba = new PrimitivesArrays.BooleanArray(4,
+        Schema.createArray(Schema.create(Schema.Type.BOOLEAN)));
+
+    Assertions.assertEquals(0, ba.size());
+    for (int i = 1; i < 100; i++) {
+      if (i % 3 == 0 || i % 5 == 0) {
+        ba.add(true);
+      } else {
+        ba.add(false);
+      }
+    }
+    Assertions.assertEquals(99, ba.size());
+    for (int i = 1; i < 100; i++) {
+      if (i % 3 == 0 || i % 5 == 0) {
+        Assertions.assertTrue(ba.get(i - 1), "Error for " + i);
+      } else {
+        Assertions.assertFalse(ba.get(i - 1), "Error for " + i);
+      }
+    }
+    Assertions.assertFalse(ba.remove(12));
+    Assertions.assertEquals(98, ba.size());
+    for (int i = 13; i < 99; i++) {
+      if ((i + 1) % 3 == 0 || (i + 1) % 5 == 0) {
+        Assertions.assertTrue(ba.get(i - 1), "After delete, Error for " + i);
+      } else {
+        Assertions.assertFalse(ba.get(i - 1), "After delete, Error for " + i);
+      }
+    }
+
+    ba.add(12, false);
+    Assertions.assertEquals(99, ba.size());
+    for (int i = 1; i < 100; i++) {
+      if (i % 3 == 0 || i % 5 == 0) {
+        Assertions.assertTrue(ba.get(i - 1), "Error for " + i);
+      } else {
+        Assertions.assertFalse(ba.get(i - 1), "Error for " + i);
+      }
+    }
+    Assertions.assertFalse(ba.remove(12));
+    ba.add(12, true);
+    for (int i = 1; i < 100; i++) {
+      if (i % 3 == 0 || i % 5 == 0 || i == 13) {
+        Assertions.assertTrue(ba.get(i - 1), "Error for " + i);
+      } else {
+        Assertions.assertFalse(ba.get(i - 1), "Error for " + i);
+      }
+    }
+    ba.add(99, true);
+    Assertions.assertTrue(ba.get(99), "Error for 99");
+    ba.remove(99);
+    ba.reverse();
+    for (int i = 1; i < 100; i++) {
+      if (i % 3 == 0 || i % 5 == 0 || i == 13) {
+        Assertions.assertTrue(ba.get(99 - i), "Error for " + i);
+      } else {
+        Assertions.assertFalse(ba.get(99 - i), "Error for " + i);
+      }
+    }
+  }
+
+  @Test
+  void booleanArrayIterator() {
+    PrimitivesArrays.BooleanArray ba = new PrimitivesArrays.BooleanArray(4,
+        Schema.createArray(Schema.create(Schema.Type.BOOLEAN)));
+    boolean[] model = new boolean[] { true, false, false, true, true, true, 
false, false, true, false, false };
+    for (boolean x : model) {
+      ba.add(x);
+    }
+    Assertions.assertEquals(model.length, ba.size());
+    int index = 0;
+    for (Boolean b : ba) {
+      Assertions.assertEquals(model[index], b);
+      index++;
+    }
+  }
+
+  @Test
+  void intArray() {
+    final PrimitivesArrays.IntArray intArray = new PrimitivesArrays.IntArray(4,
+        Schema.createArray(Schema.create(Schema.Type.INT)));
+    for (int i = 1; i <= 100; i++) {
+      intArray.add(i);
+    }
+    Assertions.assertEquals(100, intArray.size());
+    for (int i = 1; i <= 100; i++) {
+      Assertions.assertEquals(i, intArray.get(i - 1));
+    }
+
+    int expectedValue = 1;
+    for (Integer value : intArray) {
+      Assertions.assertEquals(expectedValue, value);
+      expectedValue++;
+    }
+
+    intArray.remove(40);
+    Assertions.assertEquals(99, intArray.size());
+    for (int i = 1; i <= 99; i++) {
+      if (i <= 40) {
+        Assertions.assertEquals(i, intArray.get(i - 1));
+      } else {
+        Assertions.assertEquals(i + 1, intArray.get(i - 1));
+      }
+    }
+    intArray.add(40, 41);
+    Assertions.assertEquals(100, intArray.size());
+    for (int i = 1; i <= 100; i++) {
+      Assertions.assertEquals(i, intArray.get(i - 1));
+    }
+    intArray.set(40, 25);
+    Assertions.assertEquals(25, intArray.get(40));
+
+    Assertions.assertEquals(0, intArray.peek());
+    intArray.set(40, 41);
+    intArray.reverse();
+    Assertions.assertEquals(100, intArray.size());
+    for (int i = 1; i <= 100; i++) {
+      Assertions.assertEquals(101 - i, intArray.get(i - 1));
+    }
+  }
+
+  @Test
+  void longArray() {
+    final PrimitivesArrays.LongArray longArray = new 
PrimitivesArrays.LongArray(4,
+        Schema.createArray(Schema.create(Schema.Type.LONG)));
+    for (long i = 1; i <= 100; i++) {
+      longArray.add(i);
+    }
+    Assertions.assertEquals(100l, longArray.size());
+    for (int i = 1; i <= 100; i++) {
+      Assertions.assertEquals(i, longArray.get(i - 1));
+    }
+
+    int expectedValue = 1;
+    for (Long value : longArray) {
+      Assertions.assertEquals(expectedValue, value);
+      expectedValue++;
+    }
+
+    longArray.remove(40);
+    Assertions.assertEquals(99, longArray.size());
+    for (int i = 1; i <= 99; i++) {
+      if (i <= 40) {
+        Assertions.assertEquals(i, longArray.get(i - 1));
+      } else {
+        Assertions.assertEquals(i + 1, longArray.get(i - 1));
+      }
+    }
+    longArray.add(40, 41);
+    Assertions.assertEquals(100, longArray.size());
+    for (int i = 1; i <= 100; i++) {
+      Assertions.assertEquals(i, longArray.get(i - 1));
+    }
+    longArray.set(40, 25);
+    Assertions.assertEquals(25, longArray.get(40));
+
+    Assertions.assertEquals(0, longArray.peek());
+    longArray.set(40, 41);
+    longArray.reverse();
+    Assertions.assertEquals(100, longArray.size());
+    for (int i = 1; i <= 100; i++) {
+      Assertions.assertEquals(101 - i, longArray.get(i - 1));
+    }
+  }
+
+  @Test
+  void floatArray() {
+    final PrimitivesArrays.FloatArray floatArray = new 
PrimitivesArrays.FloatArray(4,
+        Schema.createArray(Schema.create(Schema.Type.FLOAT)));
+    for (int i = 1; i <= 100; i++) {
+      floatArray.add(i * 3.3f);
+    }
+    Assertions.assertEquals(100, floatArray.size());
+    for (int i = 1; i <= 100; i++) {
+      Assertions.assertEquals(i * 3.3f, floatArray.get(i - 1));
+    }
+
+    float expectedValue = 1.0f;
+    for (Float value : floatArray) {
+      Assertions.assertEquals(expectedValue * 3.3f, value);
+      expectedValue++;
+    }
+
+    floatArray.remove(40);
+    Assertions.assertEquals(99, floatArray.size());
+    for (int i = 1; i <= 99; i++) {
+      if (i <= 40) {
+        Assertions.assertEquals(i * 3.3f, floatArray.get(i - 1));
+      } else {
+        Assertions.assertEquals((i + 1) * 3.3f, floatArray.get(i - 1));
+      }
+    }
+    floatArray.add(40, 41 * 3.3f);
+    Assertions.assertEquals(100, floatArray.size());
+    for (int i = 1; i <= 100; i++) {
+      Assertions.assertEquals(i * 3.3f, floatArray.get(i - 1));
+    }
+    floatArray.set(40, 25.2f);
+    Assertions.assertEquals(25.2f, floatArray.get(40));
+
+    Assertions.assertEquals(0.0f, floatArray.peek());
+    floatArray.set(40, 41 * 3.3f);
+    floatArray.reverse();
+    Assertions.assertEquals(100, floatArray.size());
+    for (int i = 1; i <= 100; i++) {
+      Assertions.assertEquals((101 - i) * 3.3f, floatArray.get(i - 1));
+    }
+  }
+
+  @Test
+  void doubleArray() {
+    final PrimitivesArrays.DoubleArray doubleArray = new 
PrimitivesArrays.DoubleArray(4,
+        Schema.createArray(Schema.create(Schema.Type.DOUBLE)));
+    for (int i = 1; i <= 100; i++) {
+      doubleArray.add(i * 3.0d);
+    }
+    Assertions.assertEquals(100, doubleArray.size());
+    for (int i = 1; i <= 100; i++) {
+      Assertions.assertEquals(i * 3.0d, doubleArray.get(i - 1));
+    }
+
+    double expectedValue = 1.0f;
+    for (Double value : doubleArray) {
+      Assertions.assertEquals(expectedValue * 3.0d, value);
+      expectedValue++;
+    }
+
+    doubleArray.remove(40);
+    Assertions.assertEquals(99, doubleArray.size());
+    for (int i = 1; i <= 99; i++) {
+      if (i <= 40) {
+        Assertions.assertEquals(i * 3.0d, doubleArray.get(i - 1));
+      } else {
+        Assertions.assertEquals((i + 1) * 3.0d, doubleArray.get(i - 1));
+      }
+    }
+    doubleArray.add(40, 41 * 3.0d);
+    Assertions.assertEquals(100, doubleArray.size());
+    for (int i = 1; i <= 100; i++) {
+      Assertions.assertEquals(i * 3.0d, doubleArray.get(i - 1));
+    }
+    doubleArray.set(40, 25.2d);
+    Assertions.assertEquals(25.2d, doubleArray.get(40));
+
+    Assertions.assertEquals(0.0d, doubleArray.peek());
+    doubleArray.set(40, 41 * 3.0d);
+    doubleArray.reverse();
+    Assertions.assertEquals(100, doubleArray.size());
+    for (int i = 1; i <= 100; i++) {
+      Assertions.assertEquals((101 - i) * 3.0d, doubleArray.get(i - 1));
+    }
+  }
+}


Reply via email to