2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 package org.opendaylight.yangtools.xsd.regex;
23 * @version $Id: CaseInsensitiveMap.java 834653 2009-11-10 20:32:39Z mrglavas $
25 final class CaseInsensitiveMap {
27 private static final int CHUNK_SHIFT = 10; /* 2^10 = 1k */
28 private static final int CHUNK_SIZE = (1<<CHUNK_SHIFT);
29 private static final int CHUNK_MASK = (CHUNK_SIZE-1);
30 private static final int INITIAL_CHUNK_COUNT = 64; /* up to 0xFFFF */
32 private static final int[][][] caseInsensitiveMap;
34 private static final int LOWER_CASE_MATCH = 1;
35 private static final int UPPER_CASE_MATCH = 2;
38 * Return a list of code point characters (not including the input value)
39 * that can be substituted in a case insensitive match
41 static int[] get(int codePoint) {
42 return (codePoint < 0x10000) ? getMapping(codePoint) : null;
45 private static int[] getMapping(int codePoint) {
46 int chunk = codePoint >>> CHUNK_SHIFT;
47 int offset = codePoint & CHUNK_MASK;
49 return caseInsensitiveMap[chunk][offset];
53 caseInsensitiveMap = new int[INITIAL_CHUNK_COUNT][CHUNK_SIZE][];
55 for (int i=0; i<0x10000; i++) {
56 lc = Character.toLowerCase((char) i);
57 uc = Character.toUpperCase((char) i);
59 // lower/upper case value is not the same as code point
60 if (lc != uc || lc != i) {
61 int[] map = new int[2];
66 map[index++] = LOWER_CASE_MATCH;
67 int[] lcMap = getMapping(lc);
69 map = updateMap(i, map, lc, lcMap, LOWER_CASE_MATCH);
74 if (index == map.length) {
75 map = expandMap(map, 2);
78 map[index++] = UPPER_CASE_MATCH;
79 int[] ucMap = getMapping(uc);
81 map = updateMap(i, map, uc, ucMap, UPPER_CASE_MATCH);
90 private static int[] expandMap(int[] srcMap, int expandBy) {
91 final int oldLen = srcMap.length;
92 int[] newMap = new int[oldLen + expandBy];
94 System.arraycopy(srcMap, 0, newMap, 0, oldLen);
98 private static void set(int codePoint, int[] map) {
99 int chunk = codePoint >>> CHUNK_SHIFT;
100 int offset = codePoint & CHUNK_MASK;
102 caseInsensitiveMap[chunk][offset] = map;
105 private static int[] updateMap(int codePoint, int[] codePointMap,
106 int ciCodePoint, int[] ciCodePointMap, int matchType) {
107 for (int i=0; i<ciCodePointMap.length; i+=2) {
108 int c = ciCodePointMap[i];
109 int[] cMap = getMapping(c);
111 if (contains(cMap, ciCodePoint, matchType)) {
112 if (!contains(cMap, codePoint)) {
113 cMap = expandAndAdd(cMap, codePoint, matchType);
116 if (!contains(codePointMap, c)) {
117 codePointMap = expandAndAdd(codePointMap, c,matchType);
123 if (!contains(ciCodePointMap, codePoint)) {
124 ciCodePointMap = expandAndAdd(ciCodePointMap, codePoint, matchType);
125 set(ciCodePoint, ciCodePointMap);
131 private static boolean contains(int[] map, int codePoint) {
132 for (int i=0; i<map.length; i += 2) {
133 if (map[i] == codePoint) {
140 private static boolean contains(int[] map, int codePoint, int matchType) {
141 for (int i=0; i<map.length; i += 2) {
142 if (map[i] == codePoint && map[i+1] == matchType) {
149 private static int[] expandAndAdd(int[] srcMap, int codePoint, int matchType) {
150 final int oldLen = srcMap.length;
151 int[] newMap = new int[oldLen + 2];
153 System.arraycopy(srcMap, 0, newMap, 0, oldLen);
154 newMap[oldLen] = codePoint;
155 newMap[oldLen+1] = matchType;