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 public int[] array; 031 public int size; 032 033 /** 034 * Constructs a new int array container with the specified initial backing array size. 035 * @param initialCapacity The initial capacity of the backing array. 036 */ 037 public IntArrayContainer(int initialCapacity) { 038 array = new int[initialCapacity]; 039 size = 0; 040 } 041 042 /** 043 * Grows the backing array, copying the elements. 044 * @param requestedSize The size to grow the array to. 045 */ 046 public void grow(int requestedSize) { 047 if (requestedSize > array.length) { 048 // overflow-conscious code 049 int oldCapacity = array.length; 050 int newCapacity = oldCapacity + (oldCapacity >> 1); 051 if (newCapacity - requestedSize < 0) { 052 newCapacity = requestedSize; 053 } 054 // minCapacity is usually close to size, so this is a win: 055 array = Arrays.copyOf(array, newCapacity); 056 } 057 } 058 059 /** 060 * Returns a copy of the elements in use. 061 * @return A copy of the elements. 062 */ 063 public int[] copy() { 064 return Arrays.copyOf(array,size); 065 } 066 067 /** 068 * Overwrites values from the supplied array into this array. 069 * @param otherArray The array to copy from. 070 */ 071 public void fill(int[] otherArray) { 072 if (otherArray.length > array.length) { 073 array = Arrays.copyOf(otherArray,otherArray.length); 074 } else { 075 System.arraycopy(otherArray,0,array,0,otherArray.length); 076 } 077 size = otherArray.length; 078 } 079 080 /** 081 * Overwrites values in this array with the supplied array. 082 * @param other The array to copy from. 083 */ 084 public void fill(IntArrayContainer other) { 085 if (other.array.length > array.length) { 086 array = Arrays.copyOf(other.array,other.size); 087 } else { 088 System.arraycopy(other.array,0,array,0,other.size); 089 } 090 size = other.size; 091 } 092 093 /** 094 * Copies from input to output excluding the values in otherArray. 095 * <p> 096 * This assumes both input and otherArray are sorted. Behaviour is undefined if they aren't. 097 * @param input The input container. 098 * @param otherArray Another (sorted) int array. 099 * @param output The container to write the output to. 100 */ 101 public static void removeOther(IntArrayContainer input, int[] otherArray, IntArrayContainer output) { 102 //logger.info("input.size = " + input.size + ", otherArray.length = " + otherArray.length + ", output.length = " + output.array.length); 103 int newSize = input.size - otherArray.length; 104 if (newSize > output.array.length) { 105 output.grow(newSize); 106 } 107 108 int[] inputArray = input.array; 109 int inputSize = input.size; 110 int[] outputArray = output.array; 111 //logger.info("input = " + Arrays.toString(inputArray)); 112 //logger.info("otherArray = " + Arrays.toString(otherArray)); 113 114 int i = 0; //index into input 115 int j = 0; //index into otherArray 116 int k = 0; //index into output 117 while (i < inputSize) { 118 if (j == otherArray.length) { 119 // Reached end of other, copy from input 120 outputArray[k] = inputArray[i]; 121 i++; 122 k++; 123 } else if (inputArray[i] < otherArray[j]) { 124 // Input less than other, copy input 125 outputArray[k] = inputArray[i]; 126 i++; 127 k++; 128 } else if (inputArray[i] == otherArray[j]) { 129 // skip both 130 i++; 131 j++; 132 } else { 133 // other less than input, skip 134 j++; 135 } 136 } 137 output.size = k; 138 assert(k == newSize); 139 //logger.info("output = " + Arrays.toString(outputArray)); 140 } 141 142 /** 143 * Merges the list of int arrays into a single int array, using the two supplied buffers. 144 * Requires that all arrays in the list are sorted, and that they contain unique values. 145 * @param input A list of int arrays. 146 * @param firstBuffer A buffer. 147 * @param secondBuffer Another buffer. 148 * @return A sorted array containing all the elements from the input. 149 */ 150 public static int[] merge(List<int[]> input, IntArrayContainer firstBuffer, IntArrayContainer secondBuffer) { 151 if (input.size() > 0) { 152 firstBuffer.fill(input.get(0)); 153 for (int i = 0; i < input.size(); i++) { 154 merge(firstBuffer,input.get(i),secondBuffer); 155 IntArrayContainer tmp = secondBuffer; 156 secondBuffer = firstBuffer; 157 firstBuffer = tmp; 158 } 159 return firstBuffer.copy(); 160 } else { 161 return new int[0]; 162 } 163 } 164 165 /** 166 * Merges input and otherArray writing to output. 167 * This assumes both input and otherArray are sorted. Behaviour is undefined if they aren't. 168 * @param input The input container. 169 * @param otherArray Another (sorted) int array. 170 * @param output The container to write the output to. 171 */ 172 public static void merge(IntArrayContainer input, int[] otherArray, IntArrayContainer output) { 173 int newSize = input.size + otherArray.length; 174 if (newSize > output.array.length) { 175 output.grow(newSize); 176 } 177 178 int[] inputArray = input.array; 179 int inputSize = input.size; 180 int[] outputArray = output.array; 181 182 int i = 0; //index into input 183 int j = 0; //index into otherArray 184 int k = 0; //index into output 185 while ((i < inputSize) || (j < otherArray.length)) { 186 if (i == inputSize) { 187 // Reached end of input, copy from other 188 outputArray[k] = otherArray[j]; 189 j++; 190 k++; 191 } else if (j == otherArray.length) { 192 // Reached end of other, copy from input 193 outputArray[k] = inputArray[i]; 194 i++; 195 k++; 196 } else if (inputArray[i] < otherArray[j]) { 197 // Input less than other, copy input 198 outputArray[k] = inputArray[i]; 199 i++; 200 k++; 201 } else { 202 // other less than input, copy other 203 outputArray[k] = otherArray[j]; 204 j++; 205 k++; 206 } 207 } 208 output.size = k; 209 assert(k == newSize); 210 //logger.info("input = " + Arrays.toString(inputArray)); 211 //logger.info("otherArray = " + Arrays.toString(otherArray)); 212 //logger.info("output = " + Arrays.toString(outputArray)); 213 } 214}