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