/*
 * 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.jackrabbit.oak.segment;

import static java.util.Arrays.copyOf;
import static java.util.Arrays.fill;

import java.util.Iterator;

import com.google.common.collect.AbstractIterator;

/**
 * A thread-safe, mutable record table.
 */
class MutableRecordNumbers implements RecordNumbers {
    private int[] recordEntries;
    private int size;

    public MutableRecordNumbers() {
        recordEntries = new int[16384];
        fill(recordEntries, -1);
    }

    @Override
    public int getOffset(int recordNumber) {
        int recordEntry;
        recordEntry = recordNumber * 2 >= recordEntries.length
            ? -1
            : recordEntries[recordNumber * 2];

        if (recordEntry == -1) {
            synchronized (this) {
                recordEntry = recordEntries[recordNumber * 2];
            }
        }
        return recordEntry;
    }

    @Override
    public synchronized Iterator<Entry> iterator() {
        return new AbstractIterator<Entry>() {
            int[] entries = copyOf(recordEntries, size * 2);
            int index = 0;

            @Override
            protected Entry computeNext() {
                if (index < entries.length) {
                    return new Entry() {
                        final int recordNumber = index/2;
                        final int offset = entries[index++];
                        final RecordType type = RecordType.values()[entries[index++]];

                        @Override
                        public int getRecordNumber() {
                            return recordNumber;
                        }

                        @Override
                        public int getOffset() {
                            return offset;
                        }

                        @Override
                        public RecordType getType() {
                            return type;
                        }
                    };
                } else {
                    return endOfData();
                }
            }
        };
    }

    /**
     * Return the size of this table.
     *
     * @return the size of this table.
     */
    public synchronized int size() {
        return size;
    }

    /**
     * Add a new offset to this table and generate a record number for it.
     *
     * @param type   the type of the record.
     * @param offset an offset to be added to this table.
     * @return the record number associated to the offset.
     */
    synchronized int addRecord(RecordType type, int offset) {
        if (recordEntries.length <= size * 2) {
            recordEntries = copyOf(recordEntries, recordEntries.length * 2);
            fill(recordEntries, recordEntries.length/2, recordEntries.length, -1);
        }
        recordEntries[2 * size] = offset;
        recordEntries[2 * size + 1] = type.ordinal();
        return size++;
    }

}

@@ -1358,104 +1358,26 @@
 ntry
-;%0A        recordEntry = recordNumber * 2 %3E= recordEntries.length%0A            ? -1%0A            : 
+ = getRecordEntry(
 reco
@@ -1377,33 +1377,34 @@
 ry(recordEntries
-%5B
+, 
 recordNumber * 2
@@ -1399,21 +1399,17 @@
 rdNumber
- * 2%5D
+)
 ;%0A%0A     
@@ -1500,16 +1500,31 @@
 Entry = 
+getRecordEntry(
 recordEn
@@ -1528,17 +1528,18 @@
 dEntries
-%5B
+, 
 recordNu
@@ -1546,13 +1546,9 @@
 mber
- * 2%5D
+)
 ;%0A  
@@ -1596,32 +1596,199 @@
 rdEntry;%0A    %7D%0A%0A
+    private static int getRecordEntry(int%5B%5D entries, int index) %7B%0A        return index * 2 %3E= entries.length%0A            ? -1%0A            : entries%5Bindex * 2%5D;%0A    %7D%0A%0A
     @Override%0A  

Optimise MutableRecordNumbers Proper bounds checking