001/* 002 * Copyright (c) 2015, 2024, 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 * <p> 076 * Copies in all the other values and sets the length of this array to the length of the other array. 077 * @param otherArray The array to copy from. 078 */ 079 public void fill(int[] otherArray) { 080 if (otherArray.length > array.length) { 081 array = Arrays.copyOf(otherArray,otherArray.length); 082 } else { 083 System.arraycopy(otherArray,0,array,0,otherArray.length); 084 } 085 size = otherArray.length; 086 } 087 088 /** 089 * Overwrites values in this array with the supplied array. 090 * <p> 091 * Copies in all the other values and sets the length of this array to the length of the other array. 092 * @param other The array to copy from. 093 */ 094 public void fill(IntArrayContainer other) { 095 if (other.size > array.length) { 096 array = Arrays.copyOf(other.array,other.size); 097 } else { 098 System.arraycopy(other.array,0,array,0,other.size); 099 } 100 size = other.size; 101 } 102 103 /** 104 * Copies from input to output excluding the values in otherArray. 105 * <p> 106 * This assumes both input and otherArray are sorted. Behaviour is undefined if they aren't. 107 * @param input The input container. 108 * @param otherArray Another (sorted) int array. 109 * @param output The container to write the output to. 110 */ 111 public static void removeOther(IntArrayContainer input, int[] otherArray, IntArrayContainer output) { 112 //logger.info("input.size = " + input.size + ", otherArray.length = " + otherArray.length + ", output.length = " + output.array.length); 113 int newSize = input.size - otherArray.length; 114 if (newSize > output.array.length) { 115 output.grow(newSize); 116 } 117 118 int[] inputArray = input.array; 119 int inputSize = input.size; 120 int[] outputArray = output.array; 121 //logger.info("input = " + Arrays.toString(inputArray)); 122 //logger.info("otherArray = " + Arrays.toString(otherArray)); 123 124 int i = 0; //index into input 125 int j = 0; //index into otherArray 126 int k = 0; //index into output 127 while (i < inputSize) { 128 if (j == otherArray.length) { 129 // Reached end of other, copy from input 130 outputArray[k] = inputArray[i]; 131 i++; 132 k++; 133 } else if (inputArray[i] < otherArray[j]) { 134 // Input less than other, copy input 135 outputArray[k] = inputArray[i]; 136 i++; 137 k++; 138 } else if (inputArray[i] == otherArray[j]) { 139 // skip both 140 i++; 141 j++; 142 } else { 143 // other less than input, skip 144 j++; 145 } 146 } 147 output.size = k; 148 //logger.info("output = " + Arrays.toString(outputArray)); 149 } 150 151 /** 152 * Merges the list of int arrays into a single int array, using the two supplied buffers. 153 * Requires that all arrays in the list are sorted, and that they contain unique values. 154 * @param input A list of int arrays. 155 * @param firstBuffer A buffer. 156 * @param secondBuffer Another buffer. 157 * @return A sorted array containing all the elements from the input. 158 */ 159 public static int[] merge(List<int[]> input, IntArrayContainer firstBuffer, IntArrayContainer secondBuffer) { 160 if (!input.isEmpty()) { 161 firstBuffer.fill(input.get(0)); 162 for (int i = 1; i < input.size(); i++) { 163 merge(firstBuffer,input.get(i),secondBuffer); 164 IntArrayContainer tmp = secondBuffer; 165 secondBuffer = firstBuffer; 166 firstBuffer = tmp; 167 } 168 return firstBuffer.copy(); 169 } else { 170 return new int[0]; 171 } 172 } 173 174 /** 175 * Merges input and otherArray writing to output. 176 * This assumes both input and otherArray are sorted. Behaviour is undefined if they aren't. 177 * @param input The input container. 178 * @param otherArray Another (sorted) int array. 179 * @param output The container to write the output to. 180 */ 181 public static void merge(IntArrayContainer input, int[] otherArray, IntArrayContainer output) { 182 int newSize = input.size + otherArray.length; 183 if (newSize > output.array.length) { 184 output.grow(newSize); 185 } 186 187 int[] inputArray = input.array; 188 int inputSize = input.size; 189 int[] outputArray = output.array; 190 191 int i = 0; //index into input 192 int j = 0; //index into otherArray 193 int k = 0; //index into output 194 while ((i < inputSize) || (j < otherArray.length)) { 195 if (i == inputSize) { 196 // Reached end of input, copy from other 197 outputArray[k] = otherArray[j]; 198 j++; 199 k++; 200 } else if (j == otherArray.length) { 201 // Reached end of other, copy from input 202 outputArray[k] = inputArray[i]; 203 i++; 204 k++; 205 } else if (inputArray[i] < otherArray[j]) { 206 // Input less than other, copy input 207 outputArray[k] = inputArray[i]; 208 i++; 209 k++; 210 } else { 211 // other less than input, copy other 212 outputArray[k] = otherArray[j]; 213 j++; 214 k++; 215 } 216 } 217 output.size = k; 218 assert(k == newSize); 219 //logger.info("input = " + Arrays.toString(inputArray)); 220 //logger.info("otherArray = " + Arrays.toString(otherArray)); 221 //logger.info("output = " + Arrays.toString(outputArray)); 222 } 223}