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
119
120status_t
121GlobalTypeCache::Init()
122{
123	// check lock
124	status_t error = fLock.InitCheck();
125	if (error != B_OK)
126		return error;
127
128	// create name table
129	fTypesByName = new(std::nothrow) NameTable;
130	if (fTypesByName == NULL)
131		return B_NO_MEMORY;
132
133	error = fTypesByName->Init();
134	if (error != B_OK)
135		return error;
136
137	// create ID table
138	fTypesByID = new(std::nothrow) IDTable;
139	if (fTypesByID == NULL)
140		return B_NO_MEMORY;
141
142	error = fTypesByID->Init();
143	if (error != B_OK)
144		return error;
145
146	return B_OK;
147}
148
149
150Type*
151GlobalTypeCache::GetType(const BString& name,
152	const TypeLookupConstraints &constraints) const
153{
154	TypeEntry* typeEntry = fTypesByName->Lookup(name);
155	if (typeEntry != NULL) {
156		if (constraints.HasTypeKind()
157			&& typeEntry->type->Kind() != constraints.TypeKind())
158			typeEntry = NULL;
159		else if (constraints.HasSubtypeKind()) {
160			if (typeEntry->type->Kind() == TYPE_ADDRESS) {
161					AddressType* type = dynamic_cast<AddressType*>(
162						typeEntry->type);
163					if (type == NULL)
164						typeEntry = NULL;
165					else if (type->AddressKind() != constraints.SubtypeKind())
166						typeEntry = NULL;
167			} else if (typeEntry->type->Kind() == TYPE_COMPOUND) {
168					CompoundType* type = dynamic_cast<CompoundType*>(
169						typeEntry->type);
170					if (type == NULL)
171						typeEntry = NULL;
172					else if (type->CompoundKind() != constraints.SubtypeKind())
173						typeEntry = NULL;
174			}
175		}
176	}
177	return typeEntry != NULL ? typeEntry->type : NULL;
178}
179
180
181Type*
182GlobalTypeCache::GetTypeByID(const BString& id) const
183{
184	TypeEntry* typeEntry = fTypesByID->Lookup(id);
185	return typeEntry != NULL ? typeEntry->type : NULL;
186}
187
188
189status_t
190GlobalTypeCache::AddType(Type* type)
191{
192	const BString& id = type->ID();
193	const BString& name = type->Name();
194
195	if (fTypesByID->Lookup(id) != NULL
196		|| (name.Length() > 0 && fTypesByID->Lookup(name) != NULL)) {
197		return B_BAD_VALUE;
198	}
199
200	TypeEntry* typeEntry = new(std::nothrow) TypeEntry(type);
201	if (typeEntry == NULL)
202		return B_NO_MEMORY;
203
204	fTypesByID->Insert(typeEntry);
205
206	if (name.Length() > 0)
207		fTypesByName->Insert(typeEntry);
208
209	return B_OK;
210}
211
212
213void
214GlobalTypeCache::RemoveType(Type* type)
215{
216	if (TypeEntry* typeEntry = fTypesByID->Lookup(type->ID())) {
217		if (typeEntry->type == type) {
218			fTypesByID->Remove(typeEntry);
219
220			if (type->Name().Length() > 0)
221				fTypesByName->Remove(typeEntry);
222
223			delete typeEntry;
224		}
225	}
226}
227
228
229void
230GlobalTypeCache::RemoveTypes(image_id imageID)
231{
232	AutoLocker<GlobalTypeCache> locker(this);
233
234	for (IDTable::Iterator it = fTypesByID->GetIterator();
235			TypeEntry* typeEntry = it.Next();) {
236		if (typeEntry->type->ImageID() == imageID) {
237			fTypesByID->RemoveUnchecked(typeEntry);
238
239			if (typeEntry->type->Name().Length() > 0)
240				fTypesByName->Remove(typeEntry);
241
242			delete typeEntry;
243		}
244	}
245}
246
247
248// #pragma mark - GlobalTypeLookup
249
250
251GlobalTypeLookup::~GlobalTypeLookup()
252{
253}
254