SurrogateUtils.java

/*
 * Copyright (C) 2009-2013 Steve Rowe <sarowe@gmail.com>
 * Copyright (C) 2019-2021 Google, LLC.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */
package de.jflex.ucd;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import java.util.regex.Pattern;

public class SurrogateUtils {

  private static final Pattern SURROGATE_PATTERN =
      Pattern.compile("^cs$|surrogate", Pattern.CASE_INSENSITIVE);

  /** Start (incl) of the surrogate range. */
  private static final int START = 0xD800;

  /** End (incl) of the surrogate range. */
  public static final int END = 0xDFFF;

  public static final CodepointRange SURROGATE_RANGE = CodepointRange.create(START, END);

  /** Returns whether the property represent a surrogate [U+D800-U+DFFF]. */
  public static boolean isSurrogateProperty(String propName) {
    return SURROGATE_PATTERN.matcher(propName).find();
  }

  /**
   * Returns 0, 1, or 2 ranges for the given interval, depending on whether it is contained within;
   * is entirely outside of or starts or ends within; or straddles the surrogate range
   * [0xD800-0xDFFF], respectively.
   */
  public static ImmutableList<CodepointRange> removeSurrogates(
      int startCodePoint, int endCodePoint) {
    Preconditions.checkArgument(startCodePoint <= endCodePoint);
    if (startCodePoint >= START && endCodePoint <= END) {
      return ImmutableList.of();
    }
    if (endCodePoint < START || startCodePoint > END) {
      return ImmutableList.of(CodepointRange.create(startCodePoint, endCodePoint));
    }
    ImmutableList.Builder<CodepointRange> ranges = ImmutableList.builder();
    if (startCodePoint < START) {
      ranges.add(CodepointRange.create(startCodePoint, START - 1));
    }
    if (endCodePoint > END) {
      ranges.add(CodepointRange.create(END + 1, endCodePoint));
    }
    return ranges.build();
  }

  public static boolean containsSurrogate(CodepointRange cp) {
    return isSurrogate(cp.start())
        || isSurrogate(cp.end())
        || (cp.start() <= START && cp.end() >= END);
  }

  private static boolean isSurrogate(int cp) {
    return START <= cp && cp <= END;
  }

  private SurrogateUtils() {}
}