1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.collections4.trie.analyzer;
18
19 import org.apache.commons.collections4.trie.KeyAnalyzer;
20
21
22
23
24
25
26
27
28
29 public class StringKeyAnalyzer extends KeyAnalyzer<String> {
30
31 private static final long serialVersionUID = -7032449491269434877L;
32
33
34 public static final StringKeyAnalyzer INSTANCE = new StringKeyAnalyzer();
35
36
37 public static final int LENGTH = Character.SIZE + 1;
38
39
40 private static final int MSB = 0x8000;
41
42
43 private static int mask(final int bit) {
44 return MSB >>> bit;
45 }
46
47
48
49
50
51
52 @Deprecated
53 public StringKeyAnalyzer() {
54
55 }
56
57 @Override
58 public int bitIndex(final String key, final int offsetInBits, final int lengthInBits,
59 final String other, final int otherOffsetInBits, final int otherLengthInBits) {
60
61 if (offsetInBits % LENGTH != 0 || otherOffsetInBits % LENGTH != 0
62 || lengthInBits % LENGTH != 0 || otherLengthInBits % LENGTH != 0) {
63 throw new IllegalArgumentException("The offsets and lengths must be at Character boundaries");
64 }
65
66 final int beginIndex1 = offsetInBits / LENGTH;
67 final int beginIndex2 = otherOffsetInBits / LENGTH;
68
69 final int endIndex1 = beginIndex1 + lengthInBits / LENGTH;
70 final int endIndex2 = other == null ? beginIndex2 : beginIndex2 + otherLengthInBits / LENGTH;
71
72 final int length = Math.max(endIndex1, endIndex2);
73
74 for (int i = 0; i < length; i++) {
75 final int index1 = beginIndex1 + i;
76 final int index2 = beginIndex2 + i;
77
78 if (index1 < endIndex1 && other != null && index2 < endIndex2) {
79 final char k = key.charAt(index1);
80 final char f = other.charAt(index2);
81
82 if (k != f) {
83 final int x = k ^ f;
84 return i * LENGTH + 1 + Integer.numberOfLeadingZeros(x) - (LENGTH - 1);
85 }
86 } else {
87
88 return i * LENGTH;
89 }
90 }
91
92 if (lengthInBits == 0 && (other == null || otherLengthInBits == 0)) {
93 return NULL_BIT_KEY;
94 }
95
96
97 return EQUAL_BIT_KEY;
98 }
99
100 @Override
101 public int bitsPerElement() {
102 return LENGTH;
103 }
104
105 @Override
106 public boolean isBitSet(final String key, final int bitIndex, final int lengthInBits) {
107 if (key == null || bitIndex >= lengthInBits) {
108 return false;
109 }
110
111 final int index = bitIndex / LENGTH;
112 final int bit = bitIndex % LENGTH;
113
114 if (bit == 0) {
115 return true;
116 }
117 return (key.charAt(index) & mask(bit - 1)) != 0;
118 }
119
120 @Override
121 public boolean isPrefix(final String prefix, final int offsetInBits,
122 final int lengthInBits, final String key) {
123 if (offsetInBits % LENGTH != 0 || lengthInBits % LENGTH != 0) {
124 throw new IllegalArgumentException(
125 "Cannot determine prefix outside of Character boundaries");
126 }
127
128 final String s1 = prefix.substring(offsetInBits / LENGTH, lengthInBits / LENGTH);
129 return key.startsWith(s1);
130 }
131
132 @Override
133 public int lengthInBits(final String key) {
134 return key != null ? key.length() * LENGTH : 0;
135 }
136 }