Coverage Summary for Class: SmallCharMatcher (com.google.common.base)

Class Class, % Method, % Line, %
SmallCharMatcher 0% (0/1) 0% (0/7) 0% (0/44)


1 /* 2  * Copyright (C) 2012 The Guava Authors 3  * 4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5  * in compliance with the License. You may obtain a copy of the License at 6  * 7  * http://www.apache.org/licenses/LICENSE-2.0 8  * 9  * Unless required by applicable law or agreed to in writing, software distributed under the License 10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11  * or implied. See the License for the specific language governing permissions and limitations under 12  * the License. 13  */ 14  15 package com.google.common.base; 16  17 import com.google.common.annotations.GwtIncompatible; 18 import com.google.common.annotations.VisibleForTesting; 19 import com.google.common.base.CharMatcher.NamedFastMatcher; 20 import java.util.BitSet; 21  22 /** 23  * An immutable version of CharMatcher for smallish sets of characters that uses a hash table with 24  * linear probing to check for matches. 25  * 26  * @author Christopher Swenson 27  */ 28 @GwtIncompatible // no precomputation is done in GWT 29 @ElementTypesAreNonnullByDefault 30 final class SmallCharMatcher extends NamedFastMatcher { 31  static final int MAX_SIZE = 1023; 32  private final char[] table; 33  private final boolean containsZero; 34  private final long filter; 35  36  private SmallCharMatcher(char[] table, long filter, boolean containsZero, String description) { 37  super(description); 38  this.table = table; 39  this.filter = filter; 40  this.containsZero = containsZero; 41  } 42  43  private static final int C1 = 0xcc9e2d51; 44  private static final int C2 = 0x1b873593; 45  46  /* 47  * This method was rewritten in Java from an intermediate step of the Murmur hash function in 48  * http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp, which contained the 49  * following header: 50  * 51  * MurmurHash3 was written by Austin Appleby, and is placed in the public domain. The author 52  * hereby disclaims copyright to this source code. 53  */ 54  static int smear(int hashCode) { 55  return C2 * Integer.rotateLeft(hashCode * C1, 15); 56  } 57  58  private boolean checkFilter(int c) { 59  return 1 == (1 & (filter >> c)); 60  } 61  62  // This is all essentially copied from ImmutableSet, but we have to duplicate because 63  // of dependencies. 64  65  // Represents how tightly we can pack things, as a maximum. 66  private static final double DESIRED_LOAD_FACTOR = 0.5; 67  68  /** 69  * Returns an array size suitable for the backing array of a hash table that uses open addressing 70  * with linear probing in its implementation. The returned size is the smallest power of two that 71  * can hold setSize elements with the desired load factor. 72  */ 73  @VisibleForTesting 74  static int chooseTableSize(int setSize) { 75  if (setSize == 1) { 76  return 2; 77  } 78  // Correct the size for open addressing to match desired load factor. 79  // Round up to the next highest power of 2. 80  int tableSize = Integer.highestOneBit(setSize - 1) << 1; 81  while (tableSize * DESIRED_LOAD_FACTOR < setSize) { 82  tableSize <<= 1; 83  } 84  return tableSize; 85  } 86  87  static CharMatcher from(BitSet chars, String description) { 88  // Compute the filter. 89  long filter = 0; 90  int size = chars.cardinality(); 91  boolean containsZero = chars.get(0); 92  // Compute the hash table. 93  char[] table = new char[chooseTableSize(size)]; 94  int mask = table.length - 1; 95  for (int c = chars.nextSetBit(0); c != -1; c = chars.nextSetBit(c + 1)) { 96  // Compute the filter at the same time. 97  filter |= 1L << c; 98  int index = smear(c) & mask; 99  while (true) { 100  // Check for empty. 101  if (table[index] == 0) { 102  table[index] = (char) c; 103  break; 104  } 105  // Linear probing. 106  index = (index + 1) & mask; 107  } 108  } 109  return new SmallCharMatcher(table, filter, containsZero, description); 110  } 111  112  @Override 113  public boolean matches(char c) { 114  if (c == 0) { 115  return containsZero; 116  } 117  if (!checkFilter(c)) { 118  return false; 119  } 120  int mask = table.length - 1; 121  int startingIndex = smear(c) & mask; 122  int index = startingIndex; 123  do { 124  if (table[index] == 0) { // Check for empty. 125  return false; 126  } else if (table[index] == c) { // Check for match. 127  return true; 128  } else { // Linear probing. 129  index = (index + 1) & mask; 130  } 131  // Check to see if we wrapped around the whole table. 132  } while (index != startingIndex); 133  return false; 134  } 135  136  @Override 137  void setBits(BitSet table) { 138  if (containsZero) { 139  table.set(0); 140  } 141  for (char c : this.table) { 142  if (c != 0) { 143  table.set(c); 144  } 145  } 146  } 147 }