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.internal; 014 015import java.util.*; 016 017/** 018 * Stores a set of ASCII characters for quick lookup. 019 */ 020public final class AsciiSet { 021 private final boolean[] store; 022 023 AsciiSet(boolean[] store) { 024 this.store = Arrays.copyOf(store, store.length); 025 } 026 027 /** 028 * Creates an ASCII set with the specified characters. 029 * 030 * @param chars The characters to keep in this store. 031 * @return A new object. 032 */ 033 public static AsciiSet create(String chars) { 034 return new Builder().chars(chars).build(); 035 } 036 037 /** 038 * Creates a builder for an ASCII set. 039 * 040 * @return A new builder. 041 */ 042 public static AsciiSet.Builder create() { 043 return new Builder(); 044 } 045 046 /** 047 * Copies an existing {@link AsciiSet} so that you can augment it with additional values. 048 * 049 * @return A builder initialized to the same characters in the copied set. 050 */ 051 public AsciiSet.Builder copy() { 052 Builder b = new Builder(); 053 for (int i = 0; i < 128; i++) 054 b.store[i] = store[i]; 055 return b; 056 } 057 058 /** 059 * Builder class for {@link AsciiSet} objects. 060 */ 061 public static class Builder { 062 final boolean[] store = new boolean[128]; 063 064 /** 065 * Adds a range of characters to this set. 066 * 067 * @param start The start character. 068 * @param end The end character. 069 * @return This object (for method chaining). 070 */ 071 public AsciiSet.Builder range(char start, char end) { 072 for (char c = start; c <= end; c++) 073 if (c < 128) 074 store[c] = true; 075 return this; 076 } 077 078 /** 079 * Shortcut for calling multiple ranges. 080 * 081 * @param s Strings of the form "A-Z" where A and Z represent the first and last characters in the range. 082 * @return This object (for method chaining). 083 */ 084 public AsciiSet.Builder ranges(String...s) { 085 for (String ss : s) { 086 if (ss.length() != 3 || ss.charAt(1) != '-') 087 throw new RuntimeException("Value passed to ranges() must be 3 characters"); 088 range(ss.charAt(0), ss.charAt(2)); 089 } 090 return this; 091 } 092 093 /** 094 * Adds a set of characters to this set. 095 * 096 * @param chars The characters to keep in this store. 097 * @return This object (for method chaining). 098 */ 099 public AsciiSet.Builder chars(String chars) { 100 for (int i = 0; i < chars.length(); i++) { 101 char c = chars.charAt(i); 102 if (c < 128) 103 store[c] = true; 104 } 105 return this; 106 } 107 108 /** 109 * Adds a set of characters to this set. 110 * 111 * @param chars The characters to keep in this store. 112 * @return This object (for method chaining). 113 */ 114 public Builder chars(char...chars) { 115 for (int i = 0; i < chars.length; i++) 116 if (chars[i] < 128) 117 store[chars[i]] = true; 118 return this; 119 } 120 121 /** 122 * Create a new {@link AsciiSet} object with the contents of this builder. 123 * 124 * @return A new {link AsciiSet} object. 125 */ 126 public AsciiSet build() { 127 return new AsciiSet(store); 128 } 129 } 130 131 132 /** 133 * Returns <jk>true</jk> if the specified character is in this store. 134 * 135 * @param c The character to check. 136 * @return <jk>true</jk> if the specified character is in this store. 137 */ 138 public boolean contains(char c) { 139 if (c > 127) 140 return false; 141 return store[c]; 142 } 143 144 /** 145 * Returns <jk>true</jk> if the specified character is in this store. 146 * 147 * @param c The character to check. 148 * @return <jk>true</jk> if the specified character is in this store. 149 */ 150 public boolean contains(int c) { 151 if (c < 0 || c > 127) 152 return false; 153 return store[c]; 154 } 155 156 /** 157 * Returns <jk>true</jk> if the specified string contains at least one character in this set. 158 * 159 * @param s The string to test. 160 * @return <jk>true</jk> if the string is not null and contains at least one character in this set. 161 */ 162 public boolean contains(CharSequence s) { 163 if (s == null) 164 return false; 165 for (int i = 0; i < s.length(); i++) 166 if (contains(s.charAt(i))) 167 return true; 168 return false; 169 } 170 171 /** 172 * Returns <jk>true</jk> if the specified string contains only characters in this set. 173 * 174 * @param s The string to test. 175 * @return 176 * <jk>true</jk> if the string contains only characters in this set. 177 * <br>Nulls always return <jk>false</jk>. 178 * <br>Blanks always return <jk>true</jk>. 179 */ 180 public boolean containsOnly(String s) { 181 if (s == null) 182 return false; 183 for (int i = 0; i < s.length(); i++) 184 if (! contains(s.charAt(i))) 185 return false; 186 return true; 187 } 188}