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.db.ModificationLog;
18 import org.eclipse.jdt.internal.core.nd.db.ModificationLog.Tag;
19 import org.eclipse.jdt.internal.core.nd.db.Database;
20 import org.eclipse.jdt.internal.core.nd.db.EmptyString;
21 import org.eclipse.jdt.internal.core.nd.db.IString;
22 
23 /**
24  * Declares a Nd field of type string. Can be used in place of  {@link Field}&lt{@link String}&gt in order to
25  * avoid extra GC overhead.
26  */
27 public class FieldString extends BaseField implements IDestructableField {
28 	public static final int RECORD_SIZE = Database.STRING_SIZE;
29 	private static final char[] EMPTY_CHAR_ARRAY = new char[0];
30 	private final Tag putTag;
31 	private final Tag destructTag;
32 
FieldString(String structName, int fieldNumber)33 	public FieldString(String structName, int fieldNumber) {
34 		this.putTag = ModificationLog.createTag("Writing field " + fieldNumber + ", a " + getClass().getSimpleName() //$NON-NLS-1$//$NON-NLS-2$
35 				+ " in struct " + structName); //$NON-NLS-1$
36 		this.destructTag = ModificationLog
37 				.createTag("Destructing field " + fieldNumber + ", a " + getClass().getSimpleName() //$NON-NLS-1$//$NON-NLS-2$
38 						+ " in struct " + structName); //$NON-NLS-1$
39 	}
40 
get(Nd nd, long address)41 	public IString get(Nd nd, long address) {
42 		Database db = nd.getDB();
43 		long namerec = db.getRecPtr(address + this.offset);
44 
45 		if (namerec == 0) {
46 			return EmptyString.create();
47 		}
48 		return db.getString(namerec);
49 	}
50 
put(Nd nd, long address, char[] newString)51 	public void put(Nd nd, long address, char[] newString) {
52 		Database db = nd.getDB();
53 		db.getLog().start(this.putTag);
54 		try {
55 			if (newString == null) {
56 				newString = EMPTY_CHAR_ARRAY;
57 			}
58 			IString name= get(nd, address);
59 			if (name.compare(newString, true) != 0) {
60 				name.delete();
61 				if (newString != null && newString.length > 0) {
62 					db.putRecPtr(address + this.offset, db.newString(newString).getRecord());
63 				} else {
64 					db.putRecPtr(address + this.offset, 0);
65 				}
66 			}
67 		} finally {
68 			db.getLog().end(this.putTag);
69 		}
70 	}
71 
put(Nd nd, long address, String newString)72 	public void put(Nd nd, long address, String newString) {
73 		put(nd, address, newString.toCharArray());
74 	}
75 
76 	@Override
destruct(Nd nd, long address)77 	public void destruct(Nd nd, long address) {
78 		Database db = nd.getDB();
79 		db.getLog().start(this.destructTag);
80 		try {
81 			get(nd, address).delete();
82 			nd.getDB().putRecPtr(address + this.offset, 0);
83 		} finally {
84 			db.getLog().end(this.destructTag);
85 		}
86 	}
87 
88 	@Override
getRecordSize()89 	public int getRecordSize() {
90 		return RECORD_SIZE;
91 	}
92 }
93