001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.console.views; 018 019/** 020 * The categorical pill palette's slot function. 021 * 022 * <p> 023 * A {@code pill} column marked {@link Render#categorical()} colours each distinct value from a fixed palette of 024 * {@link #SIZE} colours. The browser picks the slot with the hash documented on {@link #slot(String)}; this class is 025 * the same function in Java, for parity tests and for server-side code that wants to know which slot a value gets 026 * (for example to build a legend). The renderer does not call it at runtime. 027 * 028 * <p> 029 * {@link #SIZE} is part of the colour contract: changing it recolours every categorical value. 030 * 031 * @since 10.0.0 032 */ 033public final class PillPalette { 034 035 /** The number of palette slots (theme tokens {@code --jc-pill-cat-1-*} through {@code --jc-pill-cat-10-*}). */ 036 public static final int SIZE = 10; 037 038 private static final int FNV_OFFSET = 0x811c9dc5; 039 private static final int FNV_PRIME = 0x01000193; 040 041 /** 042 * Returns the palette slot for a value. 043 * 044 * <p> 045 * FNV-1a, 32-bit, over the UTF-16 code units of the exact string (no case folding, no trimming), then 046 * {@code (hash mod SIZE) + 1} with the hash treated as unsigned. Matching is case-sensitive: {@code "Pet"} and 047 * {@code "PET"} are different values with independent slots. A <jk>null</jk> value hashes as the empty string. 048 * 049 * <p> 050 * Reports only the hash slot, never a slot pinned with {@link Render#category(String,int)}. 051 * 052 * @param value The cell value as displayed. Can be <jk>null</jk>. 053 * @return The slot, from 1 to {@link #SIZE} inclusive. 054 */ 055 public static int slot(String value) { 056 var h = FNV_OFFSET; 057 if (value != null) 058 for (var i = 0; i < value.length(); i++) 059 h = (h ^ value.charAt(i)) * FNV_PRIME; 060 return Integer.remainderUnsigned(h, SIZE) + 1; 061 } 062 063 private PillPalette() {} 064}