Home | History | Annotate | Download | only in base
      1 /**
      2  * Copyright (c) 2006-2007, Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.android.mail.common.base;
     18 
     19 import java.util.HashMap;
     20 import java.util.Map;
     21 
     22 /**
     23  * Simple helper class to build a "sparse" array of objects based on the indexes that were added to
     24  * it. The array will be from 0 to the maximum index given. All non-set indexes will contain null
     25  * (so it's not really a sparse array, just a pseudo sparse array). The builder can also return a
     26  * CharEscaper based on the generated array.
     27  *
     28  * @author sven (at) google.com (Sven Mawson)
     29  */
     30 public class CharEscaperBuilder {
     31   /**
     32    * Simple decorator that turns an array of replacement char[]s into a CharEscaper, this results in
     33    * a very fast escape method.
     34    */
     35   private static class CharArrayDecorator extends CharEscaper {
     36     private final char[][] replacements;
     37     private final int replaceLength;
     38 
     39     CharArrayDecorator(char[][] replacements) {
     40       this.replacements = replacements;
     41       this.replaceLength = replacements.length;
     42     }
     43 
     44     /*
     45      * Overriding escape method to be slightly faster for this decorator. We test the replacements
     46      * array directly, saving a method call.
     47      */
     48     @Override public String escape(String s) {
     49       int slen = s.length();
     50       for (int index = 0; index < slen; index++) {
     51         char c = s.charAt(index);
     52         if (c < replacements.length && replacements[c] != null) {
     53           return escapeSlow(s, index);
     54         }
     55       }
     56       return s;
     57     }
     58 
     59     @Override protected char[] escape(char c) {
     60       return c < replaceLength ? replacements[c] : null;
     61     }
     62   }
     63 
     64   // Replacement mappings.
     65   private final Map<Character, String> map;
     66 
     67   // The highest index we've seen so far.
     68   private int max = -1;
     69 
     70   /**
     71    * Construct a new sparse array builder.
     72    */
     73   public CharEscaperBuilder() {
     74     this.map = new HashMap<Character, String>();
     75   }
     76 
     77   /**
     78    * Add a new mapping from an index to an object to the escaping.
     79    */
     80   public CharEscaperBuilder addEscape(char c, String r) {
     81     map.put(c, r);
     82     if (c > max) {
     83       max = c;
     84     }
     85     return this;
     86   }
     87 
     88   /**
     89    * Add multiple mappings at once for a particular index.
     90    */
     91   public CharEscaperBuilder addEscapes(char[] cs, String r) {
     92     for (char c : cs) {
     93       addEscape(c, r);
     94     }
     95     return this;
     96   }
     97 
     98   /**
     99    * Convert this builder into an array of char[]s where the maximum index is the value of the
    100    * highest character that has been seen. The array will be sparse in the sense that any unseen
    101    * index will default to null.
    102    *
    103    * @return a "sparse" array that holds the replacement mappings.
    104    */
    105   public char[][] toArray() {
    106     char[][] result = new char[max + 1][];
    107     for (Map.Entry<Character, String> entry : map.entrySet()) {
    108       result[entry.getKey()] = entry.getValue().toCharArray();
    109     }
    110     return result;
    111   }
    112 
    113   /**
    114    * Convert this builder into a char escaper which is just a decorator around the underlying array
    115    * of replacement char[]s.
    116    *
    117    * @return an escaper that escapes based on the underlying array.
    118    */
    119   public CharEscaper toEscaper() {
    120     return new CharArrayDecorator(toArray());
    121   }
    122 }