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