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 package com.android.mail.lib.base;
     17 
     18 import java.util.HashMap;
     19 import java.util.Map;
     20 
     21 /**
     22  * Simple helper class to build a "sparse" array of objects based on the indexes that were added to
     23  * it. The array will be from 0 to the maximum index given. All non-set indexes will contain null
     24  * (so it's not really a sparse array, just a pseudo sparse array). The builder can also return a
     25  * CharEscaper based on the generated array.
     26  *
     27  * @author sven (at) google.com (Sven Mawson)
     28  */
     29 public class CharEscaperBuilder {
     30   /**
     31    * Simple decorator that turns an array of replacement char[]s into a CharEscaper, this results in
     32    * a very fast escape method.
     33    */
     34   private static class CharArrayDecorator extends CharEscaper {
     35     private final char[][] replacements;
     36     private final int replaceLength;
     37 
     38     CharArrayDecorator(char[][] replacements) {
     39       this.replacements = replacements;
     40       this.replaceLength = replacements.length;
     41     }
     42 
     43     /*
     44      * Overriding escape method to be slightly faster for this decorator. We test the replacements
     45      * array directly, saving a method call.
     46      */
     47     @Override public String escape(String s) {
     48       int slen = s.length();
     49       for (int index = 0; index < slen; index++) {
     50         char c = s.charAt(index);
     51         if (c < replacements.length && replacements[c] != null) {
     52           return escapeSlow(s, index);
     53         }
     54       }
     55       return s;
     56     }
     57 
     58     @Override protected char[] escape(char c) {
     59       return c < replaceLength ? replacements[c] : null;
     60     }
     61   }
     62 
     63   // Replacement mappings.
     64   private final Map<Character, String> map;
     65 
     66   // The highest index we've seen so far.
     67   private int max = -1;
     68 
     69   /**
     70    * Construct a new sparse array builder.
     71    */
     72   public CharEscaperBuilder() {
     73     this.map = new HashMap<Character, String>();
     74   }
     75 
     76   /**
     77    * Add a new mapping from an index to an object to the escaping.
     78    */
     79   public CharEscaperBuilder addEscape(char c, String r) {
     80     map.put(c, r);
     81     if (c > max) {
     82       max = c;
     83     }
     84     return this;
     85   }
     86 
     87   /**
     88    * Add multiple mappings at once for a particular index.
     89    */
     90   public CharEscaperBuilder addEscapes(char[] cs, String r) {
     91     for (char c : cs) {
     92       addEscape(c, r);
     93     }
     94     return this;
     95   }
     96 
     97   /**
     98    * Convert this builder into an array of char[]s where the maximum index is the value of the
     99    * highest character that has been seen. The array will be sparse in the sense that any unseen
    100    * index will default to null.
    101    *
    102    * @return a "sparse" array that holds the replacement mappings.
    103    */
    104   public char[][] toArray() {
    105     char[][] result = new char[max + 1][];
    106     for (Map.Entry<Character, String> entry : map.entrySet()) {
    107       result[entry.getKey()] = entry.getValue().toCharArray();
    108     }
    109     return result;
    110   }
    111 
    112   /**
    113    * Convert this builder into a char escaper which is just a decorator around the underlying array
    114    * of replacement char[]s.
    115    *
    116    * @return an escaper that escapes based on the underlying array.
    117    */
    118   public CharEscaper toEscaper() {
    119     return new CharArrayDecorator(toArray());
    120   }
    121 }