All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.javascript.jscomp.Xid Maven / Gradle / Ivy

/*
 * Copyright 2016 The Closure Compiler Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.google.javascript.jscomp;

/**
 * A simple utility for shortening identifiers in a stable way. Generates
 * short substitution strings deterministically, using a compact
 * (1 to 6 characters in length) repesentation of a 32-bit hash of the key.
 * The string is suitable to be used as a JavaScript or CSS identifier.
 * Collisions are possible but unlikely, depending on the underlying hash algorithm used.
 *
 * This substitution scheme uses case-sensitive names for maximum
 * compression. Digits are also allowed in all but the first character of a
 * class name. There are a few characters allowed by the CSS grammar that we
 * choose not to use (e.g. the underscore and hyphen), to keep names simple.
 *
 * Xid should maintain as minimal dependencies as possible to ease its
 * integration with other tools, such as server side HTML generators.
 */
public class Xid {

  /** Possible first chars in an identifier */
  private static final String START_CHARS =
      "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

  /** Possible non-first chars in an identifier */
  private static final String CHARS = START_CHARS + "0123456789";

  private static final int START_RADIX = START_CHARS.length();
  private static final int RADIX = CHARS.length();

  private final HashFunction hasher;

  /**
   * Strategy for selecting the underlying hash code function to be used by Xid.
   */
  public interface HashFunction {
    int hashCode(String value);
  }

  private static final HashFunction DEFAULT = new HashFunction() {
    @Override public int hashCode(String value) {
      return value.hashCode();
    }
  };

  public Xid() {
    this.hasher = DEFAULT;
  }

  public Xid(HashFunction hasher) {
    this.hasher = hasher;
  }

  /**
   * Gets the string that should be substituted for {@code key}. The same value will be
   * consistently returned for any particular {@code key}.
   *
   * @param key  the text to be replaced (never null)
   * @return the value to substitute for {@code key}
   */
  public String get(String key) {
    return toString(getAsInt(key));
  }

  /**
   * Returns the underlying integer representation of the given key.
   */
  public int getAsInt(String key) {
    return this.hasher.hashCode(key);
  }

  /**
   * Converts a 32-bit integer to a unique short string whose first character
   * is in {@link #START_CHARS} and whose subsequent characters, if any, are
   * in {@link #CHARS}. The result is 1-6 characters in length.
   */
  static String toString(int i) {
    char[] buf = new char[6];
    int len = 0;

    long l = i - (long) Integer.MIN_VALUE;
    buf[len++] = START_CHARS.charAt((int) (l % START_RADIX));
    i = (int) (l / START_RADIX);

    while (i > 0) {
      buf[len++] = CHARS.charAt(i % RADIX);
      i /= RADIX;
    }

    return new String(buf, 0, len);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy