001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.common.internal; 014 015import java.util.*; 016 017/** 018 * Stores a set of ASCII characters for quick lookup. 019 */ 020public final class AsciiSet { 021 022 //----------------------------------------------------------------------------------------------------------------- 023 // Static 024 //----------------------------------------------------------------------------------------------------------------- 025 026 /** 027 * Creates an ASCII set with the specified characters. 028 * 029 * @param chars The characters to keep in this store. 030 * @return A new object. 031 */ 032 public static AsciiSet create(String chars) { 033 return new Builder().chars(chars).build(); 034 } 035 036 /** 037 * Creates a builder for an ASCII set. 038 * 039 * @return A new builder. 040 */ 041 public static AsciiSet.Builder create() { 042 return new Builder(); 043 } 044 045 //----------------------------------------------------------------------------------------------------------------- 046 // Builder 047 //----------------------------------------------------------------------------------------------------------------- 048 049 /** 050 * Builder class. 051 */ 052 public static class Builder { 053 final boolean[] store = new boolean[128]; 054 055 /** 056 * Adds a range of characters to this set. 057 * 058 * @param start The start character. 059 * @param end The end character. 060 * @return This object. 061 */ 062 public AsciiSet.Builder range(char start, char end) { 063 for (char c = start; c <= end; c++) 064 if (c < 128) 065 store[c] = true; 066 return this; 067 } 068 069 /** 070 * Shortcut for calling multiple ranges. 071 * 072 * @param s Strings of the form "A-Z" where A and Z represent the first and last characters in the range. 073 * @return This object. 074 */ 075 public AsciiSet.Builder ranges(String...s) { 076 for (String ss : s) { 077 if (ss.length() != 3 || ss.charAt(1) != '-') 078 throw new RuntimeException("Value passed to ranges() must be 3 characters"); 079 range(ss.charAt(0), ss.charAt(2)); 080 } 081 return this; 082 } 083 084 /** 085 * Adds a set of characters to this set. 086 * 087 * @param chars The characters to keep in this store. 088 * @return This object. 089 */ 090 public AsciiSet.Builder chars(String chars) { 091 for (int i = 0; i < chars.length(); i++) { 092 char c = chars.charAt(i); 093 if (c < 128) 094 store[c] = true; 095 } 096 return this; 097 } 098 099 /** 100 * Adds a set of characters to this set. 101 * 102 * @param chars The characters to keep in this store. 103 * @return This object. 104 */ 105 public Builder chars(char...chars) { 106 for (int i = 0; i < chars.length; i++) 107 if (chars[i] < 128) 108 store[chars[i]] = true; 109 return this; 110 } 111 112 /** 113 * Create a new {@link AsciiSet} object with the contents of this builder. 114 * 115 * @return A new {link AsciiSet} object. 116 */ 117 public AsciiSet build() { 118 return new AsciiSet(store); 119 } 120 } 121 122 //----------------------------------------------------------------------------------------------------------------- 123 // Instance 124 //----------------------------------------------------------------------------------------------------------------- 125 126 private final boolean[] store; 127 128 AsciiSet(boolean[] store) { 129 this.store = Arrays.copyOf(store, store.length); 130 } 131 132 /** 133 * Copies an existing {@link AsciiSet} so that you can augment it with additional values. 134 * 135 * @return A builder initialized to the same characters in the copied set. 136 */ 137 public AsciiSet.Builder copy() { 138 Builder b = new Builder(); 139 for (int i = 0; i < 128; i++) 140 b.store[i] = store[i]; 141 return b; 142 } 143 144 145 /** 146 * Returns <jk>true</jk> if the specified character is in this store. 147 * 148 * @param c The character to check. 149 * @return <jk>true</jk> if the specified character is in this store. 150 */ 151 public boolean contains(char c) { 152 if (c > 127) 153 return false; 154 return store[c]; 155 } 156 157 /** 158 * Returns <jk>true</jk> if the specified character is in this store. 159 * 160 * @param c The character to check. 161 * @return <jk>true</jk> if the specified character is in this store. 162 */ 163 public boolean contains(int c) { 164 if (c < 0 || c > 127) 165 return false; 166 return store[c]; 167 } 168 169 /** 170 * Returns <jk>true</jk> if the specified string contains at least one character in this set. 171 * 172 * @param s The string to test. 173 * @return <jk>true</jk> if the string is not null and contains at least one character in this set. 174 */ 175 public boolean contains(CharSequence s) { 176 if (s == null) 177 return false; 178 for (int i = 0; i < s.length(); i++) 179 if (contains(s.charAt(i))) 180 return true; 181 return false; 182 } 183 184 /** 185 * Returns <jk>true</jk> if the specified string contains only characters in this set. 186 * 187 * @param s The string to test. 188 * @return 189 * <jk>true</jk> if the string contains only characters in this set. 190 * <br>Nulls always return <jk>false</jk>. 191 * <br>Blanks always return <jk>true</jk>. 192 */ 193 public boolean containsOnly(String s) { 194 if (s == null) 195 return false; 196 for (int i = 0; i < s.length(); i++) 197 if (! contains(s.charAt(i))) 198 return false; 199 return true; 200 } 201}