1 /******************************************************************************* 2 * Copyright (c) 2015, 2016 Google, Inc and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * Stefan Xenos (Google) - Initial implementation 13 *******************************************************************************/ 14 package org.eclipse.jdt.internal.core.nd.field; 15 16 import org.eclipse.jdt.internal.core.nd.Nd; 17 import org.eclipse.jdt.internal.core.nd.NdNode; 18 import org.eclipse.jdt.internal.core.nd.db.BTree; 19 import org.eclipse.jdt.internal.core.nd.db.ModificationLog; 20 import org.eclipse.jdt.internal.core.nd.db.ModificationLog.Tag; 21 import org.eclipse.jdt.internal.core.nd.db.Database; 22 import org.eclipse.jdt.internal.core.nd.db.EmptyString; 23 import org.eclipse.jdt.internal.core.nd.db.IString; 24 25 /** 26 * Represents a search key into a global search index. 27 */ 28 public class FieldSearchKey<T> extends BaseField implements IDestructableField { 29 FieldSearchIndex<?> searchIndex; 30 private final Tag destructTag; 31 private final Tag putTag; 32 FieldSearchKey(FieldSearchIndex<?> searchIndex, String structName, int fieldNumber)33 private FieldSearchKey(FieldSearchIndex<?> searchIndex, String structName, int fieldNumber) { 34 if (searchIndex != null) { 35 if (searchIndex.searchKey != null && searchIndex.searchKey != this) { 36 throw new IllegalArgumentException( 37 "Attempted to construct a FieldSearchKey referring to a search index that is " //$NON-NLS-1$ 38 + "already in use by a different key"); //$NON-NLS-1$ 39 } 40 searchIndex.searchKey = this; 41 } 42 this.searchIndex = searchIndex; 43 setFieldName("field " + fieldNumber + ", a " + getClass().getSimpleName() //$NON-NLS-1$//$NON-NLS-2$ 44 + " in struct " + structName); //$NON-NLS-1$ 45 this.putTag = ModificationLog.createTag("Writing " + getFieldName()); //$NON-NLS-1$ 46 this.destructTag = ModificationLog.createTag("Destructing " + getFieldName()); //$NON-NLS-1$ 47 } 48 49 /** 50 * Creates a search key attribute in the given struct which stores an entry in the given global search index 51 */ create(StructDef<B> builder, FieldSearchIndex<B> searchIndex)52 public static <T, B extends NdNode> FieldSearchKey<T> create(StructDef<B> builder, 53 FieldSearchIndex<B> searchIndex) { 54 FieldSearchKey<T> result = new FieldSearchKey<T>(searchIndex, builder.getStructName(), builder.getNumFields()); 55 56 builder.add(result); 57 builder.addDestructableField(result); 58 59 return result; 60 } 61 put(Nd nd, long address, String newString)62 public void put(Nd nd, long address, String newString) { 63 put(nd, address, newString.toCharArray()); 64 } 65 66 /** 67 * Sets the value of the key and inserts it into the index if it is not already present 68 */ put(Nd nd, long address, char[] newString)69 public void put(Nd nd, long address, char[] newString) { 70 Database db = nd.getDB(); 71 db.getLog().start(this.putTag); 72 try { 73 cleanup(nd, address); 74 75 BTree btree = this.searchIndex.get(nd, Database.DATA_AREA_OFFSET); 76 db.putRecPtr(address + this.offset, db.newString(newString).getRecord()); 77 btree.insert(address); 78 } finally { 79 db.getLog().end(this.putTag); 80 } 81 } 82 get(Nd nd, long address)83 public IString get(Nd nd, long address) { 84 Database db = nd.getDB(); 85 long namerec = db.getRecPtr(address + this.offset); 86 87 if (namerec == 0) { 88 return EmptyString.create(); 89 } 90 return db.getString(namerec); 91 } 92 93 @Override destruct(Nd nd, long address)94 public void destruct(Nd nd, long address) { 95 Database db = nd.getDB(); 96 db.getLog().start(this.destructTag); 97 try { 98 cleanup(nd, address); 99 } finally { 100 db.getLog().end(this.destructTag); 101 } 102 } 103 cleanup(Nd nd, long address)104 private void cleanup(Nd nd, long address) { 105 boolean isInIndex = isInIndex(nd, address); 106 107 if (isInIndex) { 108 // Remove this entry from the search index 109 this.searchIndex.get(nd, Database.DATA_AREA_OFFSET).delete(address); 110 111 get(nd, address).delete(); 112 nd.getDB().putRecPtr(address + this.offset, 0); 113 } 114 } 115 116 /** 117 * Clears this key and removes it from the search index 118 */ removeFromIndex(Nd nd, long address)119 public void removeFromIndex(Nd nd, long address) { 120 cleanup(nd, address); 121 } 122 123 /** 124 * Returns true iff this key is currently in the index 125 */ isInIndex(Nd nd, long address)126 public boolean isInIndex(Nd nd, long address) { 127 long fieldAddress = address + this.offset; 128 Database db = nd.getDB(); 129 long namerec = db.getRecPtr(fieldAddress); 130 131 boolean isInIndex = namerec != 0; 132 return isInIndex; 133 } 134 135 @Override getRecordSize()136 public int getRecordSize() { 137 return FieldString.RECORD_SIZE; 138 } 139 } 140