IdentifierMap.java
1 /* 2 * Copyright (C) 2022 github.com/REAndroid 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.reandroid.identifiers; 17 18 import java.util.*; 19 20 class IdentifierMap<CHILD extends Identifier> extends Identifier 21 implements Comparator<CHILD> { 22 private final Object mLock = new Object(); 23 private final Map<Integer, CHILD> idMap; 24 private final Map<String, CHILD> nameMap; 25 private boolean mCaseInsensitive; 26 private int maxId; 27 28 public IdentifierMap(int id, String name){ 29 super(id, name); 30 this.idMap = new HashMap<>(); 31 this.nameMap = new HashMap<>(); 32 this.mCaseInsensitive = CASE_INSENSITIVE_FS; 33 } 34 35 public int getMaxId(){ 36 return maxId; 37 } 38 public List<CHILD> listDuplicates(){ 39 List<CHILD> results = new ArrayList<>(); 40 Map<String, CHILD> uniques = new HashMap<>(); 41 for(CHILD item : getItems()){ 42 String name = item.getName(); 43 if(isCaseInsensitive()){ 44 name = name.toLowerCase(); 45 } 46 if(uniques.containsKey(name)){ 47 results.add(item); 48 results.add(uniques.get(name)); 49 }else { 50 uniques.put(name, item); 51 } 52 } 53 results.sort(this); 54 return results; 55 } 56 public boolean hasDuplicates(){ 57 Set<String> uniques = new HashSet<>(); 58 for(CHILD item : getItems()){ 59 String name = item.getName(); 60 if(uniques.contains(name)){ 61 return true; 62 }else { 63 uniques.add(name); 64 } 65 } 66 return false; 67 } 68 public List<String> listNames(){ 69 List<String> results = new ArrayList<>(size()); 70 for(CHILD item : list()){ 71 results.add(item.getName()); 72 } 73 return results; 74 } 75 public List<CHILD> list(){ 76 List<CHILD> childList = new ArrayList<>(getItems()); 77 childList.sort(this); 78 return childList; 79 } 80 public Collection<CHILD> getItems(){ 81 synchronized (mLock){ 82 return this.idMap.values(); 83 } 84 } 85 public void clear(){ 86 synchronized (mLock){ 87 this.idMap.clear(); 88 this.nameMap.clear(); 89 } 90 } 91 public CHILD getByTag(Object tag){ 92 for(CHILD item : getItems()){ 93 if(Objects.equals(tag, item.getTag())){ 94 return item; 95 } 96 } 97 return null; 98 } 99 public int size(){ 100 synchronized (mLock){ 101 return this.idMap.size(); 102 } 103 } 104 public CHILD get(String childName){ 105 synchronized (mLock){ 106 return this.nameMap.get(childName); 107 } 108 } 109 public CHILD get(int childId){ 110 synchronized (mLock){ 111 return this.idMap.get(childId); 112 } 113 } 114 public void remove(CHILD entry){ 115 synchronized (mLock){ 116 if(entry == null){ 117 return; 118 } 119 this.idMap.remove(entry.getId()); 120 this.nameMap.remove(entry.getName()); 121 } 122 } 123 public CHILD add(CHILD child){ 124 synchronized (mLock){ 125 if(child == null){ 126 return null; 127 } 128 child.setParent(this); 129 Integer entryId = child.getId(); 130 CHILD exist = this.idMap.get(entryId); 131 if(exist != null){ 132 if(exist.getName() == null){ 133 exist.setName(child.getName()); 134 addNameMap(exist); 135 } 136 return exist; 137 } 138 this.idMap.put(entryId, child); 139 if(entryId > maxId){ 140 maxId = entryId; 141 } 142 addNameMap(child); 143 return child; 144 } 145 } 146 public void reloadNameMap(){ 147 synchronized (mLock){ 148 this.nameMap.clear(); 149 for(CHILD child : idMap.values()){ 150 addNameMap(child); 151 } 152 } 153 } 154 private void addNameMap(CHILD child){ 155 String childName = child.getName(); 156 if(childName == null){ 157 return; 158 } 159 CHILD exist = this.nameMap.get(childName); 160 if(exist != null){ 161 return; 162 } 163 this.nameMap.put(childName, child); 164 } 165 private boolean isCaseInsensitive(){ 166 return mCaseInsensitive; 167 } 168 void setCaseInsensitive(boolean caseInsensitive){ 169 mCaseInsensitive = caseInsensitive; 170 } 171 @Override 172 public int compare(CHILD child1, CHILD child2) { 173 return child1.compareTo(child2); 174 } 175 @Override 176 public String toString(){ 177 return super.toString() + " entries = " + size(); 178 } 179 }