content: // Copyright 2010 The Go Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style
  // license that can be found in the LICENSE file.
  
  package com.github.aaronshan.functions.regexp.re2j;
  
  import io.airlift.slice.Slice;
  
  import static com.github.aaronshan.functions.regexp.re2j.MachineInput.EOF;
  
  /**
   * Various constants and helper utilities.
   */
  abstract class Utils {
  
      static final int[] EMPTY_INTS = {};
      static final int EMPTY_BEGIN_LINE = 0x01;
      static final int EMPTY_END_LINE = 0x02;
      static final int EMPTY_BEGIN_TEXT = 0x04;
      static final int EMPTY_END_TEXT = 0x08;
      static final int EMPTY_WORD_BOUNDARY = 0x10;
      static final int EMPTY_NO_WORD_BOUNDARY = 0x20;
      static final int EMPTY_ALL = -1;  // (impossible)
      private static final String METACHARACTERS = "\\.+*?()|[]{}^$";
  
      private Utils() {
      }  // uninstantiable
  
      // Returns true iff |c| is an ASCII letter or decimal digit.
      static boolean isalnum(int c) {
          return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z';
      }
  
      // If |c| is an ASCII hex digit, returns its value, otherwise -1.
      static int unhex(int c) {
          if ('0' <= c && c <= '9') {
              return c - '0';
          }
          if ('a' <= c && c <= 'f') {
              return c - 'a' + 10;
          }
          if ('A' <= c && c <= 'F') {
              return c - 'A' + 10;
          }
          return -1;
      }
  
      //// EMPTY_* flags
  
      // Appends a RE2 literal to |out| for rune |rune|,
      // with regexp metacharacters escaped.
      static void escapeRune(StringBuilder out, int rune) {
          if (com.github.aaronshan.functions.regexp.re2j.Unicode.isPrint(rune)) {
              if (METACHARACTERS.indexOf((char) rune) >= 0) {
                  out.append('\\');
              }
              out.appendCodePoint(rune);
              return;
          }
  
          switch (rune) {
              case '"':
                  out.append("\\\"");
                  break;
              case '\\':
                  out.append("\\\\");
                  break;
              case '\t':
                  out.append("\\t");
                  break;
              case '\n':
                  out.append("\\n");
                  break;
              case '\r':
                  out.append("\\r");
                  break;
              case '\b':
                  out.append("\\b");
                  break;
              case '\f':
                  out.append("\\f");
                  break;
              default: {
                  String s = Integer.toHexString(rune);
                  if (rune < 0x100) {
                      out.append("\\x");
                      if (s.length() == 1) {
                          out.append('0');
                      }
                      out.append(s);
                  } else {
                      out.append("\\x{").append(s).append('}');
                  }
                  break;
              }
          }
      }
  
      // Returns the array of runes in the specified Java UTF-16 string.
      static int[] stringToRunes(String str) {
          int charlen = str.length();
          int runelen = str.codePointCount(0, charlen);
          int[] runes = new int[runelen];
          int r = 0, c = 0;
          while (c < charlen) {
              int rune = str.codePointAt(c);
              runes[r++] = rune;
              c += Character.charCount(rune);
          }
          return runes;
      }
  
      // Returns the Java UTF-16 string containing the single rune |r|.
      static String runeToString(int r) {
          char c = (char) r;
          return r == c
                  ? String.valueOf(c)
                  : new String(Character.toChars(c));
      }
  
      // Returns a new copy of the specified subarray.
      static int[] subarray(int[] array, int start, int end) {
          int[] r = new int[end - start];
          for (int i = start; i < end; ++i) {
              r[i - start] = array[i];
          }
          return r;
      }
  
      // Returns a new copy of the specified subarray.
      static byte[] subarray(byte[] array, int start, int end) {
          byte[] r = new byte[end - start];
          for (int i = start; i < end; ++i) {
              r[i - start] = array[i];
          }
          return r;
      }
  
      // Returns the index of the first occurrence of array |target| within
      // array |source| after |fromIndex|, or -1 if not found.
      static int indexOf(Slice source, Slice target, int fromIndex) {
          if (fromIndex >= source.length()) {
              return target.length() == 0 ? source.length() : -1;
          }
          if (fromIndex < 0) {
              fromIndex = 0;
          }
          if (target.length() == 0) {
              return fromIndex;
          }
  
          byte first = target.getByte(0);
          for (int i = fromIndex, max = source.length() - target.length(); i <= max;
               i++) {
              // Look for first byte.
              if (source.getByte(i) != first) {
                  while (++i <= max && source.getByte(i) != first) {
                  }
              }
  
              // Found first byte, now look at the rest of v2.
              if (i <= max) {
                  int j = i + 1;
                  int end = j + target.length() - 1;
                  for (int k = 1; j < end && source.getByte(j) == target.getByte(k); j++, k++) {
                  }
  
                  if (j == end) {
                      return i;  // found whole array
                  }
              }
          }
          return -1;
      }
  
      // isWordByte reports whether b is consider a ``word character''
      // during the evaluation of the \b and \B zero-width assertions.
      // These assertions are ASCII-only: the word characters are [A-Za-z0-9_].
      static boolean isWordByte(byte b) {
          return ('A' <= b && b <= 'Z' ||
                  'a' <= b && b <= 'z' ||
                  '0' <= b && b <= '9' ||
                  b == '_');
      }
  
      static boolean isRuneStart(byte b) {
          return (b & 0xC0) != 0x80;  // 10xxxxxx
      }
  
      // emptyOpContext returns the zero-width assertions satisfied at the position
      // between the bytes b1 and b2, a bitmask of EMPTY_* flags.
      // Passing b1 == -1 indicates that the position is at the beginning of the text.
      // Passing b2 == -1 indicates that the position is at the end of the text.
      // TODO(adonovan): move to Machine.
      static int emptyOpContext(byte b1, byte b2) {
          int op = 0;
          if (b1 == EOF) {
              op |= EMPTY_BEGIN_TEXT | EMPTY_BEGIN_LINE;
          }
          if (b1 == '\n') {
              op |= EMPTY_BEGIN_LINE;
          }
          if (b2 == EOF) {
              op |= EMPTY_END_TEXT | EMPTY_END_LINE;
          }
          if (b2 == '\n') {
              op |= EMPTY_END_LINE;
          }
          if (isWordByte(b1) != isWordByte(b2)) {
              op |= EMPTY_WORD_BOUNDARY;
          } else {
              op |= EMPTY_NO_WORD_BOUNDARY;
          }
          return op;
      }
  
      static boolean arrayFirstElementsEqual(int[] a, int[] a2, int length) {
          if (a == a2) {
              return true;
          }
  
          if (a == null || a2 == null) {
              return false;
          }
  
          if (a.length < length || a2.length < length) {
              return false;
          }
  
          for (int i = 0; i < length; i++)
              if (a[i] != a2[i])
                  return false;
  
          return true;
      }
  
  }
  