001/* 002 * Copyright (c) 2015-2020, Oracle and/or its affiliates. All rights reserved. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.tribuo.common.tree.impl; 018 019import java.util.Arrays; 020import java.util.List; 021import java.util.logging.Logger; 022 023/** 024 * An array container which maintains the array and the size. 025 * This class is barely more than a Tuple, it's up to you to maintain the size invariant. 026 */ 027public class IntArrayContainer { 028 private static final Logger logger = Logger.getLogger(IntArrayContainer.class.getName()); 029 030 /** 031 * The array of ints. 032 */ 033 public int[] array; 034 /** 035 * The number of elements in the array. 036 */ 037 public int size; 038 039 /** 040 * Constructs a new int array container with the specified initial backing array size. 041 * @param initialCapacity The initial capacity of the backing array. 042 */ 043 public IntArrayContainer(int initialCapacity) { 044 array = new int[initialCapacity]; 045 size = 0; 046 } 047 048 /** 049 * Grows the backing array, copying the elements. 050 * @param requestedSize The size to grow the array to. 051 */ 052 public void grow(int requestedSize) { 053 if (requestedSize > array.length) { 054 // overflow-conscious code 055 int oldCapacity = array.length; 056 int newCapacity = oldCapacity + (oldCapacity >> 1); 057 if (newCapacity - requestedSize < 0) { 058 newCapacity = requestedSize; 059 } 060 // minCapacity is usually close to size, so this is a win: 061 array = Arrays.copyOf(array, newCapacity); 062 } 063 } 064 065 /** 066 * Returns a copy of the elements in use. 067 * @return A copy of the elements. 068 */ 069 public int[] copy() { 070 return Arrays.copyOf(array,size); 071 } 072 073 /** 074 * Overwrites values from the supplied array into this array. 075 * @param otherArray The array to copy from. 076 */ 077 public void fill(int[] otherArray) { 078 if (otherArray.length > array.length) { 079 array = Arrays.copyOf(otherArray,otherArray.length); 080 } else { 081 System.arraycopy(otherArray,0,array,0,otherArray.length); 082 } 083 size = otherArray.length; 084 } 085 086 /** 087 * Overwrites values in this array with the supplied array. 088 * @param other The array to copy from. 089 */ 090 public void fill(IntArrayContainer other) { 091 if (other.array.length > array.length) { 092 array = Arrays.copyOf(other.array,other.size); 093 } else { 094 System.arraycopy(other.array,0,array,0,other.size); 095 } 096 size = other.size; 097 } 098 099 /** 100 * Copies from input to output excluding the values in otherArray. 101 * <p> 102 * This assumes both input and otherArray are sorted. Behaviour is undefined if they aren't. 103 * @param input The input container. 104 * @param otherArray Another (sorted) int array. 105 * @param output The container to write the output to. 106 */ 107 public static void removeOther(IntArrayContainer input, int[] otherArray, IntArrayContainer output) { 108 //logger.info("input.size = " + input.size + ", otherArray.length = " + otherArray.length + ", output.length = " + output.array.length); 109 int newSize = input.size - otherArray.length; 110 if (newSize > output.array.length) { 111 output.grow(newSize); 112 } 113 114 int[] inputArray = input.array; 115 int inputSize = input.size; 116 int[] outputArray = output.array; 117 //logger.info("input = " + Arrays.toString(inputArray)); 118 //logger.info("otherArray = " + Arrays.toString(otherArray)); 119 120 int i = 0; //index into input 121 int j = 0; //index into otherArray 122 int k = 0; //index into output 123 while (i < inputSize) { 124 if (j == otherArray.length) { 125 // Reached end of other, copy from input 126 outputArray[k] = inputArray[i]; 127 i++; 128 k++; 129 } else if (inputArray[i] < otherArray[j]) { 130 // Input less than other, copy input 131 outputArray[k] = inputArray[i]; 132 i++; 133 k++; 134 } else if (inputArray[i] == otherArray[j]) { 135 // skip both 136 i++; 137 j++; 138 } else { 139 // other less than input, skip 140 j++; 141 } 142 } 143 output.size = k; 144 assert(k == newSize); 145 //logger.info("output = " + Arrays.toString(outputArray)); 146 } 147 148 /** 149 * Merges the list of int arrays into a single int array, using the two supplied buffers. 150 * Requires that all arrays in the list are sorted, and that they contain unique values. 151 * @param input A list of int arrays. 152 * @param firstBuffer A buffer. 153 * @param secondBuffer Another buffer. 154 * @return A sorted array containing all the elements from the input. 155 */ 156 public static int[] merge(List<int[]> input, IntArrayContainer firstBuffer, IntArrayContainer secondBuffer) { 157 if (input.size() > 0) { 158 firstBuffer.fill(input.get(0)); 159 for (int i = 0; i < input.size(); i++) { 160 merge(firstBuffer,input.get(i),secondBuffer); 161 IntArrayContainer tmp = secondBuffer; 162 secondBuffer = firstBuffer; 163 firstBuffer = tmp; 164 } 165 return firstBuffer.copy(); 166 } else { 167 return new int[0]; 168 } 169 } 170 171 /** 172 * Merges input and otherArray writing to output. 173 * This assumes both input and otherArray are sorted. Behaviour is undefined if they aren't. 174 * @param input The input container. 175 * @param otherArray Another (sorted) int array. 176 * @param output The container to write the output to. 177 */ 178 public static void merge(IntArrayContainer input, int[] otherArray, IntArrayContainer output) { 179 int newSize = input.size + otherArray.length; 180 if (newSize > output.array.length) { 181 output.grow(newSize); 182 } 183 184 int[] inputArray = input.array; 185 int inputSize = input.size; 186 int[] outputArray = output.array; 187 188 int i = 0; //index into input 189 int j = 0; //index into otherArray 190 int k = 0; //index into output 191 while ((i < inputSize) || (j < otherArray.length)) { 192 if (i == inputSize) { 193 // Reached end of input, copy from other 194 outputArray[k] = otherArray[j]; 195 j++; 196 k++; 197 } else if (j == otherArray.length) { 198 // Reached end of other, copy from input 199 outputArray[k] = inputArray[i]; 200 i++; 201 k++; 202 } else if (inputArray[i] < otherArray[j]) { 203 // Input less than other, copy input 204 outputArray[k] = inputArray[i]; 205 i++; 206 k++; 207 } else { 208 // other less than input, copy other 209 outputArray[k] = otherArray[j]; 210 j++; 211 k++; 212 } 213 } 214 output.size = k; 215 assert(k == newSize); 216 //logger.info("input = " + Arrays.toString(inputArray)); 217 //logger.info("otherArray = " + Arrays.toString(otherArray)); 218 //logger.info("output = " + Arrays.toString(outputArray)); 219 } 220}