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 24 namespace BPackageKit { 25 26 27 // #pragma mark - PackageInfo 28 29 30 struct 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 56 struct 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 85 struct 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 168 private: 169 uint32 fCount; 170 }; 171 172 173 // #pragma mark - Iterator 174 175 176 BPackageInfoSet::Iterator::Iterator(const PackageMap* map) 177 : 178 fMap(map), 179 fNextInfo(map != NULL ? map->GetIterator().Next() : NULL) 180 { 181 } 182 183 184 bool 185 BPackageInfoSet::Iterator::HasNext() const 186 { 187 return fNextInfo != NULL; 188 } 189 190 191 const BPackageInfo* 192 BPackageInfoSet::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 216 BPackageInfoSet::BPackageInfoSet() 217 : 218 fPackageMap(NULL) 219 { 220 } 221 222 223 BPackageInfoSet::~BPackageInfoSet() 224 { 225 if (fPackageMap != NULL) 226 fPackageMap->ReleaseReference(); 227 } 228 229 230 BPackageInfoSet::BPackageInfoSet(const BPackageInfoSet& other) 231 : 232 fPackageMap(other.fPackageMap) 233 { 234 if (fPackageMap != NULL) 235 fPackageMap->AcquireReference(); 236 } 237 238 239 status_t 240 BPackageInfoSet::AddInfo(const BPackageInfo& info) 241 { 242 if (!_CopyOnWrite()) 243 return B_NO_MEMORY; 244 245 return fPackageMap->AddNewPackageInfo(info); 246 } 247 248 249 void 250 BPackageInfoSet::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 267 uint32 268 BPackageInfoSet::CountInfos() const 269 { 270 if (fPackageMap == NULL) 271 return 0; 272 273 return fPackageMap->CountPackageInfos(); 274 } 275 276 277 BPackageInfoSet::Iterator 278 BPackageInfoSet::GetIterator() const 279 { 280 return Iterator(fPackageMap); 281 } 282 283 284 BPackageInfoSet& 285 BPackageInfoSet::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 302 bool 303 BPackageInfoSet::_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