content: /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to you 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 org.apache.calcite.avatica.util;
  
  import java.io.IOException;
  import java.io.PrintWriter;
  import java.io.StringWriter;
  import java.util.AbstractList;
  import java.util.Arrays;
  import java.util.List;
  import java.util.concurrent.CopyOnWriteArrayList;
  
  /** Utilities for creating strings of spaces. */
  public class Spaces {
    /** It doesn't look like this list is ever updated. But it is - when a call to
     * to {@link SpaceList#get} causes an {@link IndexOutOfBoundsException}. */
    @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
    private static final List<String> SPACE_LIST = new SpaceList();
  
    /** The longest possible string of spaces. Fine as long as you don't try
     * to print it.
     *
     * <p>Use with {@link StringBuilder#append(CharSequence, int, int)} to
     * append spaces without doing memory allocation.</p>
     */
    public static final CharSequence MAX = sequence(Integer.MAX_VALUE);
  
    // Utility class. Do not instantiate.
    private Spaces() {}
  
    /** Creates a sequence of {@code n} spaces. */
    public static CharSequence sequence(int n) {
      return new SpaceString(n);
    }
  
    /** Returns a string of {@code n} spaces. */
    public static String of(int n) {
      return SPACE_LIST.get(n);
    }
  
    /** Appends {@code n} spaces to an {@link Appendable}. */
    public static Appendable append(Appendable buf, int n) throws IOException {
      buf.append(MAX, 0, n);
      return buf;
    }
  
    /** Appends {@code n} spaces to a {@link PrintWriter}. */
    public static PrintWriter append(PrintWriter pw, int n) {
      pw.append(MAX, 0, n);
      return pw;
    }
  
    /** Appends {@code n} spaces to a {@link StringWriter}. */
    public static StringWriter append(StringWriter pw, int n) {
      pw.append(MAX, 0, n);
      return pw;
    }
  
    /** Appends {@code n} spaces to a {@link StringBuilder}. */
    public static StringBuilder append(StringBuilder buf, int n) {
      buf.append(MAX, 0, n);
      return buf;
    }
  
    /** Appends {@code n} spaces to a {@link StringBuffer}. */
    public static StringBuffer append(StringBuffer buf, int n) {
      buf.append(MAX, 0, n);
      return buf;
    }
  
    /** Returns a string that is padded on the right with spaces to the given
     * length. */
    public static String padRight(String string, int n) {
      final int x = n - string.length();
      if (x <= 0) {
        return string;
      }
      // Replacing StringBuffer with String would hurt performance.
      //noinspection StringBufferReplaceableByString
      return append(new StringBuilder(string), x).toString();
    }
  
    /** Returns a string that is padded on the left with spaces to the given
     * length. */
    public static String padLeft(String string, int n) {
      final int x = n - string.length();
      if (x <= 0) {
        return string;
      }
      // Replacing StringBuffer with String would hurt performance.
      //noinspection StringBufferReplaceableByString
      return append(new StringBuilder(), x).append(string).toString();
    }
  
    /** A string of spaces. */
    private static class SpaceString implements CharSequence {
      private final int length;
  
      private SpaceString(int length) {
        this.length = length;
      }
  
      // Do not override equals and hashCode to be like String. CharSequence does
      // not require it.
  
      @SuppressWarnings("NullableProblems")
      @Override public String toString() {
        return of(length);
      }
  
      public int length() {
        return length;
      }
  
      public char charAt(int index) {
        return ' ';
      }
  
      public CharSequence subSequence(int start, int end) {
        return new SpaceString(end - start);
      }
    }
  
    /** List whose {@code i}th entry is a string consisting of {@code i} spaces.
     * It populates itself the first time you ask for a particular string, and
     * caches the result. */
    private static class SpaceList extends CopyOnWriteArrayList<String> {
      @Override public String get(int index) {
        for (;;) {
          try {
            return super.get(index);
          } catch (IndexOutOfBoundsException e) {
            if (index < 0) {
              throw e;
            }
            populate(Math.max(16, index + 1));
          }
        }
      }
  
      /**
       * Populates this list with all prefix strings of a given string. All
       * of the prefix strings share the same backing array of chars.
       */
      private synchronized void populate(int newSize) {
        final int size = size();
        if (newSize <= size) {
          return;
        }
        final char[] chars = new char[newSize];
        Arrays.fill(chars, ' ');
        final int length = newSize - size;
        final int offset = size;
  
        // addAll is much more efficient than repeated add for
        // CopyOnWriteArrayList
        addAll(
            new AbstractList<String>() {
              public String get(int index) {
                return String.valueOf(chars, 0, offset + index);
              }
  
              public int size() {
                return length;
              }
            });
      }
    }
  }
  
  // End Spaces.java
  