1/*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "GlobalTypeLookup.h"
8
9#include <new>
10
11#include <String.h>
12
13#include <AutoLocker.h>
14
15#include "StringUtils.h"
16#include "Type.h"
17#include "TypeLookupConstraints.h"
18
19
20struct GlobalTypeCache::TypeEntry {
21	Type*		type;
22	TypeEntry*	fNextByName;
23	TypeEntry*	fNextByID;
24
25	TypeEntry(Type* type)
26		:
27		type(type)
28	{
29		type->AcquireReference();
30	}
31
32	~TypeEntry()
33	{
34		type->ReleaseReference();
35	}
36};
37
38
39struct GlobalTypeCache::TypeEntryHashDefinitionByName {
40	typedef const BString	KeyType;
41	typedef	TypeEntry		ValueType;
42
43	size_t HashKey(const BString& key) const
44	{
45		return StringUtils::HashValue(key);
46	}
47
48	size_t Hash(const TypeEntry* value) const
49	{
50		return HashKey(value->type->Name());
51	}
52
53	bool Compare(const BString& key, const TypeEntry* value) const
54	{
55		return key == value->type->Name();
56	}
57
58	TypeEntry*& GetLink(TypeEntry* value) const
59	{
60		return value->fNextByName;
61	}
62};
63
64
65struct GlobalTypeCache::TypeEntryHashDefinitionByID {
66	typedef const BString	KeyType;
67	typedef	TypeEntry		ValueType;
68
69	size_t HashKey(const BString& key) const
70	{
71		return StringUtils::HashValue(key);
72	}
73
74	size_t Hash(const TypeEntry* value) const
75	{
76		return HashKey(value->type->ID());
77	}
78
79	bool Compare(const BString& key, const TypeEntry* value) const
80	{
81		return key == value->type->ID();
82	}
83
84	TypeEntry*& GetLink(TypeEntry* value) const
85	{
86		return value->fNextByID;
87	}
88};
89
90
91// #pragma mark - GlobalTypeCache
92
93
94GlobalTypeCache::GlobalTypeCache()
95	:
96	fLock("global type cache"),
97	fTypesByName(NULL),
98	fTypesByID(NULL)
99{
100}
101
102
103GlobalTypeCache::~GlobalTypeCache()
104{
105	if (fTypesByName != NULL)
106		fTypesByName->Clear();
107
108	// release all cached type references
109	if (fTypesByID != NULL) {
110		TypeEntry* entry = fTypesByID->Clear(true);
111		while (entry != NULL) {
112			TypeEntry* nextEntry = entry->fNextByID;
113			delete entry;
114			entry = nextEntry;
115		}
116	}
117
118	delete fTypesByName;
119	delete fTypesByID;
120}
121
122
123status_t
124GlobalTypeCache::Init()
125{
126	// check lock
127	status_t error = fLock.InitCheck();
128	if (error != B_OK)
129		return error;
130
131	// create name table
132	fTypesByName = new(std::nothrow) NameTable;
133	if (fTypesByName == NULL)
134		return B_NO_MEMORY;
135
136	error = fTypesByName->Init();
137	if (error != B_OK)
138		return error;
139
140	// create ID table
141	fTypesByID = new(std::nothrow) IDTable;
142	if (fTypesByID == NULL)
143		return B_NO_MEMORY;
144
145	error = fTypesByID->Init();
146	if (error != B_OK)
147		return error;
148
149	return B_OK;
150}
151
152
153Type*
154GlobalTypeCache::GetType(const BString& name,
155	const TypeLookupConstraints &constraints) const
156{
157	TypeEntry* typeEntry = fTypesByName->Lookup(name);
158	if (typeEntry != NULL) {
159		if (constraints.HasTypeKind()
160			&& typeEntry->type->Kind() != constraints.TypeKind())
161			typeEntry = NULL;
162		else if (constraints.HasSubtypeKind()) {
163			if (typeEntry->type->Kind() == TYPE_ADDRESS) {
164					AddressType* type = dynamic_cast<AddressType*>(
165						typeEntry->type);
166					if (type == NULL)
167						typeEntry = NULL;
168					else if (type->AddressKind() != constraints.SubtypeKind())
169						typeEntry = NULL;
170			} else if (typeEntry->type->Kind() == TYPE_COMPOUND) {
171					CompoundType* type = dynamic_cast<CompoundType*>(
172						typeEntry->type);
173					if (type == NULL)
174						typeEntry = NULL;
175					else if (type->CompoundKind() != constraints.SubtypeKind())
176						typeEntry = NULL;
177			}
178		}
179	}
180	return typeEntry != NULL ? typeEntry->type : NULL;
181}
182
183
184Type*
185GlobalTypeCache::GetTypeByID(const BString& id) const
186{
187	TypeEntry* typeEntry = fTypesByID->Lookup(id);
188	return typeEntry != NULL ? typeEntry->type : NULL;
189}
190
191
192status_t
193GlobalTypeCache::AddType(Type* type)
194{
195	const BString& id = type->ID();
196	const BString& name = type->Name();
197
198	if (fTypesByID->Lookup(id) != NULL
199		|| (name.Length() > 0 && fTypesByID->Lookup(name) != NULL)) {
200		return B_BAD_VALUE;
201	}
202
203	TypeEntry* typeEntry = new(std::nothrow) TypeEntry(type);
204	if (typeEntry == NULL)
205		return B_NO_MEMORY;
206
207	fTypesByID->Insert(typeEntry);
208
209	if (name.Length() > 0)
210		fTypesByName->Insert(typeEntry);
211
212	return B_OK;
213}
214
215
216void
217GlobalTypeCache::RemoveType(Type* type)
218{
219	if (TypeEntry* typeEntry = fTypesByID->Lookup(type->ID())) {
220		if (typeEntry->type == type) {
221			fTypesByID->Remove(typeEntry);
222
223			if (type->Name().Length() > 0)
224				fTypesByName->Remove(typeEntry);
225
226			delete typeEntry;
227		}
228	}
229}
230
231
232void
233GlobalTypeCache::RemoveTypes(image_id imageID)
234{
235	AutoLocker<GlobalTypeCache> locker(this);
236
237	for (IDTable::Iterator it = fTypesByID->GetIterator();
238			TypeEntry* typeEntry = it.Next();) {
239		if (typeEntry->type->ImageID() == imageID) {
240			fTypesByID->RemoveUnchecked(typeEntry);
241
242			if (typeEntry->type->Name().Length() > 0)
243				fTypesByName->Remove(typeEntry);
244
245			delete typeEntry;
246		}
247	}
248}
249
250
251// #pragma mark - GlobalTypeLookup
252
253
254GlobalTypeLookup::~GlobalTypeLookup()
255{
256}
257