1/* 2 * Copyright 2011, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Oliver Tappe <zooey@hirschkaefer.de> 7 * Ingo Weinhold <ingo_weinhold@gmx.de> 8 */ 9 10 11#include <package/PackageInfoSet.h> 12 13#include <new> 14 15#include <Referenceable.h> 16 17#include <AutoDeleter.h> 18 19#include <util/OpenHashTable.h> 20 21#include <package/PackageInfo.h> 22 23 24namespace BPackageKit { 25 26 27// #pragma mark - PackageInfo 28 29 30struct BPackageInfoSet::PackageInfo : public BPackageInfo { 31 PackageInfo* hashNext; 32 PackageInfo* listNext; 33 34 PackageInfo(const BPackageInfo& other) 35 : 36 BPackageInfo(other), 37 listNext(NULL) 38 { 39 } 40 41 void DeleteList() 42 { 43 PackageInfo* info = this; 44 while (info != NULL) { 45 PackageInfo* next = info->listNext; 46 delete info; 47 info = next; 48 } 49 } 50}; 51 52 53// #pragma mark - PackageInfoHashDefinition 54 55 56struct BPackageInfoSet::PackageInfoHashDefinition { 57 typedef const char* KeyType; 58 typedef PackageInfo ValueType; 59 60 size_t HashKey(const char* key) const 61 { 62 return BString::HashValue(key); 63 } 64 65 size_t Hash(const PackageInfo* value) const 66 { 67 return value->Name().HashValue(); 68 } 69 70 bool Compare(const char* key, const PackageInfo* value) const 71 { 72 return value->Name() == key; 73 } 74 75 PackageInfo*& GetLink(PackageInfo* value) const 76 { 77 return value->hashNext; 78 } 79}; 80 81 82// #pragma mark - PackageMap 83 84 85struct BPackageInfoSet::PackageMap : public BReferenceable, 86 public BOpenHashTable<PackageInfoHashDefinition> { 87 88 PackageMap() 89 : 90 fCount(0) 91 { 92 } 93 94 ~PackageMap() 95 { 96 DeleteAllPackageInfos(); 97 } 98 99 static PackageMap* Create() 100 { 101 PackageMap* map = new(std::nothrow) PackageMap; 102 if (map == NULL || map->Init() != B_OK) { 103 delete map; 104 return NULL; 105 } 106 107 return map; 108 } 109 110 PackageMap* Clone() const 111 { 112 PackageMap* newMap = Create(); 113 if (newMap == NULL) 114 return NULL; 115 ObjectDeleter<PackageMap> newMapDeleter(newMap); 116 117 for (BPackageInfoSet::Iterator it(this); it.HasNext();) { 118 const BPackageInfo* info = it.Next(); 119 if (newMap->AddNewPackageInfo(*info) != B_OK) 120 return NULL; 121 } 122 123 return newMapDeleter.Detach(); 124 } 125 126 void AddPackageInfo(PackageInfo* info) 127 { 128 if (PackageInfo* oldInfo = Lookup(info->Name())) { 129 info->listNext = oldInfo->listNext; 130 oldInfo->listNext = info; 131 } else 132 Insert(info); 133 134 fCount++; 135 } 136 137 status_t AddNewPackageInfo(const BPackageInfo& oldInfo) 138 { 139 PackageInfo* info = new(std::nothrow) PackageInfo(oldInfo); 140 if (info == NULL) 141 return B_NO_MEMORY; 142 ObjectDeleter<PackageInfo> infoDeleter(info); 143 144 status_t error = info->InitCheck(); 145 if (error != B_OK) 146 return error; 147 148 AddPackageInfo(infoDeleter.Detach()); 149 150 return B_OK; 151 } 152 153 void DeleteAllPackageInfos() 154 { 155 PackageInfo* info = Clear(true); 156 while (info != NULL) { 157 PackageInfo* next = info->hashNext; 158 info->DeleteList(); 159 info = next; 160 } 161 } 162 163 uint32 CountPackageInfos() const 164 { 165 return fCount; 166 } 167 168private: 169 uint32 fCount; 170}; 171 172 173// #pragma mark - Iterator 174 175 176BPackageInfoSet::Iterator::Iterator(const PackageMap* map) 177 : 178 fMap(map), 179 fNextInfo(map != NULL ? map->GetIterator().Next() : NULL) 180{ 181} 182 183 184bool 185BPackageInfoSet::Iterator::HasNext() const 186{ 187 return fNextInfo != NULL; 188} 189 190 191const BPackageInfo* 192BPackageInfoSet::Iterator::Next() 193{ 194 BPackageInfo* result = fNextInfo; 195 196 if (fNextInfo != NULL) { 197 if (fNextInfo->listNext != NULL) { 198 // get next in list 199 fNextInfo = fNextInfo->listNext; 200 } else { 201 // get next in hash table 202 PackageMap::Iterator iterator 203 = fMap->GetIterator(fNextInfo->Name()); 204 iterator.Next(); 205 fNextInfo = iterator.Next(); 206 } 207 } 208 209 return result; 210} 211 212 213// #pragma mark - BPackageInfoSet 214 215 216BPackageInfoSet::BPackageInfoSet() 217 : 218 fPackageMap(NULL) 219{ 220} 221 222 223BPackageInfoSet::~BPackageInfoSet() 224{ 225 if (fPackageMap != NULL) 226 fPackageMap->ReleaseReference(); 227} 228 229 230BPackageInfoSet::BPackageInfoSet(const BPackageInfoSet& other) 231 : 232 fPackageMap(other.fPackageMap) 233{ 234 if (fPackageMap != NULL) 235 fPackageMap->AcquireReference(); 236} 237 238 239status_t 240BPackageInfoSet::AddInfo(const BPackageInfo& info) 241{ 242 if (!_CopyOnWrite()) 243 return B_NO_MEMORY; 244 245 return fPackageMap->AddNewPackageInfo(info); 246} 247 248 249void 250BPackageInfoSet::MakeEmpty() 251{ 252 if (fPackageMap == NULL || fPackageMap->CountPackageInfos() == 0) 253 return; 254 255 // If our map is shared, just set it to NULL. 256 if (fPackageMap->CountReferences() != 1) { 257 fPackageMap->ReleaseReference(); 258 fPackageMap = NULL; 259 return; 260 } 261 262 // Our map is not shared -- make it empty. 263 fPackageMap->DeleteAllPackageInfos(); 264} 265 266 267uint32 268BPackageInfoSet::CountInfos() const 269{ 270 if (fPackageMap == NULL) 271 return 0; 272 273 return fPackageMap->CountPackageInfos(); 274} 275 276 277BPackageInfoSet::Iterator 278BPackageInfoSet::GetIterator() const 279{ 280 return Iterator(fPackageMap); 281} 282 283 284BPackageInfoSet& 285BPackageInfoSet::operator=(const BPackageInfoSet& other) 286{ 287 if (other.fPackageMap == fPackageMap) 288 return *this; 289 290 if (fPackageMap != NULL) 291 fPackageMap->ReleaseReference(); 292 293 fPackageMap = other.fPackageMap; 294 295 if (fPackageMap != NULL) 296 fPackageMap->AcquireReference(); 297 298 return *this; 299} 300 301 302bool 303BPackageInfoSet::_CopyOnWrite() 304{ 305 if (fPackageMap == NULL) { 306 fPackageMap = PackageMap::Create(); 307 return fPackageMap != NULL; 308 } 309 310 if (fPackageMap->CountReferences() == 1) 311 return true; 312 313 PackageMap* newMap = fPackageMap->Clone(); 314 if (newMap == NULL) 315 return false; 316 317 fPackageMap->ReleaseReference(); 318 fPackageMap = newMap; 319 return true; 320} 321 322 323} // namespace BPackageKit 324