int (final @NotNull UserDataHolderEx context, final @NotNull String name, int colorsCount) { int colorIndex; while (true) { Object data = context.getUserData(USED_COLOR); Object newColors; if (data == null) { colorIndex = hashColor(name, colorsCount); newColors = new UsedColor(name, colorIndex); // put an object instead of array to save space } else if (data instanceof UsedColor) { UsedColor usedColor = (UsedColor)data; if (usedColor.name.equals(name)) { colorIndex = usedColor.index; newColors = null; // found, no need to create new } else { int hashedIndex = hashColor(name, colorsCount); if (hashedIndex == usedColor.index) hashedIndex = (hashedIndex + 1) % colorsCount; colorIndex = hashedIndex; UsedColor newColor = new UsedColor(name, colorIndex); newColors = new UsedColor[]{usedColor, newColor}; } } else { colorIndex = -1; int hashedIndex = hashColor(name, colorsCount); int[] index2usage = new int[colorsCount]; UsedColor[] usedColors = (UsedColor[])data; for (UsedColor usedColor : usedColors) { int index = usedColor.index; index2usage[index]++; if (usedColor.name.equals(name)) { colorIndex = index; break; } } if (colorIndex == -1) { int minIndex1 = indexOfMin(index2usage, hashedIndex, colorsCount); int minIndex2 = indexOfMin(index2usage, 0, hashedIndex); colorIndex = index2usage[minIndex1] <= index2usage[minIndex2] ? minIndex1 : minIndex2; UsedColor newColor = new UsedColor(name, colorIndex); newColors = ArrayUtil.append(usedColors, newColor); } else { newColors = null; } } if (newColors == null || context.replace(USED_COLOR, data, newColors)) { break; } } return colorIndex; }