content: /*
   * 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.github.aaronshan.functions.regexp.re2j;
  
  import io.airlift.slice.Slice;
  import io.airlift.slice.SliceOutput;
  
  /**
   * Utility methods related to {@link Slice} class.
   */
  final class SliceUtils {
  
      private SliceUtils() {
      }
  
      static void appendReplacement(SliceOutput so, Slice replacement, Matcher matcher) {
          int idx = 0;
  
          // Handle the following items:
          // 1. ${name};
          // 2. $0, $1, $123 (group 123, if exists; or group 12, if exists; or group 1);
          // 3. \\, \$, \t (literal 't').
          // 4. Anything that doesn't starts with \ or $ is considered regular bytes
          while (idx < replacement.length()) {
              byte nextByte = replacement.getByte(idx);
              if (nextByte == '$') {
                  idx++;
                  if (idx == replacement.length()) {
                      throw new IllegalArgumentException("Illegal replacement sequence: " + replacement.toStringUtf8());
                  }
                  nextByte = replacement.getByte(idx);
                  int backref;
                  if (nextByte == '{') { // case 1 in the above comment
                      idx++;
                      int startCursor = idx;
                      while (idx < replacement.length()) {
                          nextByte = replacement.getByte(idx);
                          if (nextByte == '}') {
                              break;
                          }
                          idx++;
                      }
                      String groupName = replacement.slice(startCursor, idx - startCursor).toStringUtf8();
                      Integer namedGroupIndex = matcher.pattern().re2().namedGroupIndexes.get(groupName);
                      if (namedGroupIndex == null) {
                          throw new IndexOutOfBoundsException("Illegal replacement sequence: unknown group " + groupName);
                      }
                      backref = namedGroupIndex;
                      idx++;
                  } else { // case 2 in the above comment
                      backref = nextByte - '0';
                      if (backref < 0 || backref > 9) {
                          throw new IllegalArgumentException("Illegal replacement sequence: " + replacement.toStringUtf8());
                      }
                      if (matcher.groupCount() < backref) {
                          throw new IndexOutOfBoundsException("Illegal replacement sequence: unknown group " + backref);
                      }
                      idx++;
                      while (idx < replacement.length()) { // Adaptive group number: find largest group num that is not greater than actual number of groups
                          int nextDigit = replacement.getByte(idx) - '0';
                          if (nextDigit < 0 || nextDigit > 9) {
                              break;
                          }
                          int newBackref = (backref * 10) + nextDigit;
                          if (matcher.groupCount() < newBackref) {
                              break;
                          }
                          backref = newBackref;
                          idx++;
                      }
                  }
                  Slice group = matcher.group(backref);
                  if (group != null) {
                      so.writeBytes(group);
                  }
              } else { // case 3 and 4 in the above comment
                  if (nextByte == '\\') {
                      idx++;
                      if (idx == replacement.length()) {
                          throw new IllegalArgumentException("Illegal replacement sequence: " + replacement.toStringUtf8());
                      }
                      nextByte = replacement.getByte(idx);
                  }
                  so.appendByte(nextByte);
                  idx++;
              }
          }
      }
  }
  