Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: fb46e3b9332511eb90338b2921dacfb44941e008 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
/*******************************************************************************
 * Copyright (c) 2007, 2008 Symbian Software Systems and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * Andrew Ferguson (Symbian) - Initial implementation
 *******************************************************************************/
package org.eclipse.cdt.internal.core.pdom.db;

import java.util.HashSet;
import java.util.Set;

import org.eclipse.core.runtime.CoreException;

/**
 * DBProperties is a bare-bones implementation of a String->String mapping. It is neither
 * a Map or a Properties subclass, because of their more general applications.
 */
public class DBProperties {
	static final int PROP_INDEX = 0;
	static final int RECORD_SIZE = 4;
	
	protected BTree index;
	protected Database db;
	protected int record;
	
	/**
	 * Allocate storage for a new DBProperties record in the specified database
	 * @param db
	 * @throws CoreException
	 */
	public DBProperties(Database db) throws CoreException {
		this.record= db.malloc(RECORD_SIZE);
		this.index= new BTree(db, record + PROP_INDEX, DBProperty.getComparator(db));
		this.db= db;
	}
	
	/**
	 * Creates an object for accessing an existing DBProperties record at the specified location of the specified database
	 * @param db
	 * @param record
	 * @throws CoreException
	 */
	public DBProperties(Database db, int record) throws CoreException {
		this.record= record;
		this.index= new BTree(db, record + PROP_INDEX, DBProperty.getComparator(db));
		this.db= db;
	}
	
	/**
	 * Read the named property from this properties storage
	 * @param key a case-sensitive identifier for a property, or null
	 * @return the value associated with the key, or null if either no such property is set, or the specified key was null
	 * @throws CoreException
	 */
	public String getProperty(String key) throws CoreException {
		if(key!=null) {
			DBProperty existing= DBProperty.search(db, index, key);
			if(existing!=null) {
				return existing.getValue().getString();
			}
		}
		return null;
	}
	
	/**
	 * Read the named property from this properties storage, returning the default value if there is no such property
	 * @param key a case-sensitive identifier for a property, or null
	 * @param defaultValue a value to return in case the specified key was null
	 * @return the value associated with the key, or the specified default value if either no such property is set, or
	 * the specified key was null
	 * @throws CoreException
	 */
	public String getProperty(String key, String defaultValue) throws CoreException {
		String val= getProperty(key);
		return (val == null) ? defaultValue : val;
	}

	/**
	 * Returns the Set of property names stored in this object
	 * @return the Set of property names stored in this object
	 * @throws CoreException
	 */
	public Set<String> getKeySet() throws CoreException {
		return DBProperty.getKeySet(db, index);
	}

	/**
	 * Write the key, value mapping to the properties. If a mapping for the
	 * same key already exists, it is overwritten.
	 * @param key a non-null property name
	 * @param value a value to associate with the key. may not be null.
	 * @throws CoreException
	 * @throws NullPointerException if key is null
	 */
	public void setProperty(String key, String value) throws CoreException {
		removeProperty(key);
		DBProperty newProperty= new DBProperty(db, key, value);
		index.insert(newProperty.getRecord());
	}

	/**
	 * Deletes a property from this DBProperties object
	 * @param key
	 * @return whether a property with matching key existed and was removed, or false if the key was null
	 * @throws CoreException
	 */
	public boolean removeProperty(String key) throws CoreException {
		if(key!=null) {
			DBProperty existing= DBProperty.search(db, index, key);
			if(existing != null) {
				index.delete(existing.getRecord());
				existing.delete();
				return true;
			}
		}
		return false;
	}
	
	/**
	 * Deletes all properties, does not delete the record associated with the object itself - that is
	 * it can be re-populated.
	 * @throws CoreException
	 */
	@SuppressWarnings("hiding")
	public void clear() throws CoreException {
		index.accept(new IBTreeVisitor(){
			public int compare(int record) throws CoreException {
				return 0;
			}
			public boolean visit(int record) throws CoreException {
				new DBProperty(db, record).delete();
				return false; // there should never be duplicates
			}
		});
	}
	
	/**
	 * Deletes all properties stored in this object and the record associated with this object itself.
	 * <br><br>
	 * <b>The behaviour of objects of this class after calling this method is undefined</b>
	 * @throws CoreException
	 */
	public void delete() throws CoreException {
		clear();
		db.free(record);
	}

	public int getRecord() {
		return record;
	}
	
	private static class DBProperty {
		static final int KEY = 0;
		static final int VALUE = 4;
		@SuppressWarnings("hiding")
		static final int RECORD_SIZE = 8;
		
		Database db;
		int record;
		
		public int getRecord() {
			return record;
		}
		
		/**
		 * Allocates and initializes a record in the specified database for a DBProperty record
		 * @param db
		 * @param key a non-null property name
		 * @param value a non-null property value
		 * @throws CoreException
		 */
		DBProperty(Database db, String key, String value) throws CoreException {
			assert key!=null;
			assert value!=null;
			IString dbkey= db.newString(key);
			IString dbvalue= db.newString(value);
			this.record= db.malloc(RECORD_SIZE);
			db.putInt(record + KEY, dbkey.getRecord());
			db.putInt(record + VALUE, dbvalue.getRecord());
			this.db= db;
		}
		
		/**
		 * Returns an object for accessing an existing DBProperty record at the specified location in the
		 * specified database
		 * @param db
		 * @param record
		 */
		DBProperty(Database db, int record) {
			this.record= record;
			this.db= db;
		}
		
		public IString getKey() throws CoreException {
			return db.getString(db.getInt(record + KEY));
		}
		
		public IString getValue() throws CoreException {
			return db.getString(db.getInt(record + VALUE));
		}
		
		public static IBTreeComparator getComparator(final Database db) {
			return new IBTreeComparator() {
				public int compare(int record1, int record2) throws CoreException {
					IString left= db.getString(db.getInt(record1 + KEY));
					IString right= db.getString(db.getInt(record2 + KEY));
					return left.compare(right, true);
				}
			};
		}
		
		public static DBProperty search(final Database db, final BTree index, final String key) throws CoreException {
			final DBProperty[] result= new DBProperty[1];
			index.accept(new IBTreeVisitor(){
				public int compare(int record) throws CoreException {
					return db.getString(db.getInt(record + KEY)).compare(key, true);
				}
				public boolean visit(int record) throws CoreException {
					result[0] = new DBProperty(db, record);
					return false; // there should never be duplicates
				}
			});
			return result[0];
		}
		
		public static Set<String> getKeySet(final Database db, final BTree index) throws CoreException {
			final Set<String> result= new HashSet<String>();
			index.accept(new IBTreeVisitor(){
				public int compare(int record) throws CoreException {
					return 0;
				}
				public boolean visit(int record) throws CoreException {
					result.add(new DBProperty(db, record).getKey().getString());
					return true; // there should never be duplicates
				}
			});
			return result;
		}
		
		public void delete() throws CoreException {
			db.getString(db.getInt(record + KEY)).delete();
			db.getString(db.getInt(record + VALUE)).delete();
			db.free(record);
		}
	}
}

Back to the top