/* * Copyright 2011, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: * Oliver Tappe * Ingo Weinhold */ #include #include #include #include #include #include namespace BPackageKit { // #pragma mark - PackageInfo struct BPackageInfoSet::PackageInfo : public BPackageInfo { PackageInfo* hashNext; PackageInfo* listNext; PackageInfo(const BPackageInfo& other) : BPackageInfo(other), listNext(NULL) { } void DeleteList() { PackageInfo* info = this; while (info != NULL) { PackageInfo* next = info->listNext; delete info; info = next; } } }; // #pragma mark - PackageInfoHashDefinition struct BPackageInfoSet::PackageInfoHashDefinition { typedef const char* KeyType; typedef PackageInfo ValueType; size_t HashKey(const char* key) const { return BString::HashValue(key); } size_t Hash(const PackageInfo* value) const { return value->Name().HashValue(); } bool Compare(const char* key, const PackageInfo* value) const { return value->Name() == key; } PackageInfo*& GetLink(PackageInfo* value) const { return value->hashNext; } }; // #pragma mark - PackageMap struct BPackageInfoSet::PackageMap : public BReferenceable, public BOpenHashTable { PackageMap() : fCount(0) { } ~PackageMap() { DeleteAllPackageInfos(); } static PackageMap* Create() { PackageMap* map = new(std::nothrow) PackageMap; if (map == NULL || map->Init() != B_OK) { delete map; return NULL; } return map; } PackageMap* Clone() const { PackageMap* newMap = Create(); if (newMap == NULL) return NULL; ObjectDeleter newMapDeleter(newMap); for (BPackageInfoSet::Iterator it(this); it.HasNext();) { const BPackageInfo* info = it.Next(); if (newMap->AddNewPackageInfo(*info) != B_OK) return NULL; } return newMapDeleter.Detach(); } void AddPackageInfo(PackageInfo* info) { if (PackageInfo* oldInfo = Lookup(info->Name())) { info->listNext = oldInfo->listNext; oldInfo->listNext = info; } else Insert(info); fCount++; } status_t AddNewPackageInfo(const BPackageInfo& oldInfo) { PackageInfo* info = new(std::nothrow) PackageInfo(oldInfo); if (info == NULL) return B_NO_MEMORY; ObjectDeleter infoDeleter(info); status_t error = info->InitCheck(); if (error != B_OK) return error; AddPackageInfo(infoDeleter.Detach()); return B_OK; } void DeleteAllPackageInfos() { PackageInfo* info = Clear(true); while (info != NULL) { PackageInfo* next = info->hashNext; info->DeleteList(); info = next; } } uint32 CountPackageInfos() const { return fCount; } private: uint32 fCount; }; // #pragma mark - Iterator BPackageInfoSet::Iterator::Iterator(const PackageMap* map) : fMap(map), fNextInfo(map != NULL ? map->GetIterator().Next() : NULL) { } bool BPackageInfoSet::Iterator::HasNext() const { return fNextInfo != NULL; } const BPackageInfo* BPackageInfoSet::Iterator::Next() { BPackageInfo* result = fNextInfo; if (fNextInfo != NULL) { if (fNextInfo->listNext != NULL) { // get next in list fNextInfo = fNextInfo->listNext; } else { // get next in hash table PackageMap::Iterator iterator = fMap->GetIterator(fNextInfo->Name()); iterator.Next(); fNextInfo = iterator.Next(); } } return result; } // #pragma mark - BPackageInfoSet BPackageInfoSet::BPackageInfoSet() : fPackageMap(NULL) { } BPackageInfoSet::~BPackageInfoSet() { if (fPackageMap != NULL) fPackageMap->ReleaseReference(); } BPackageInfoSet::BPackageInfoSet(const BPackageInfoSet& other) : fPackageMap(other.fPackageMap) { if (fPackageMap != NULL) fPackageMap->AcquireReference(); } status_t BPackageInfoSet::AddInfo(const BPackageInfo& info) { if (!_CopyOnWrite()) return B_NO_MEMORY; return fPackageMap->AddNewPackageInfo(info); } void BPackageInfoSet::MakeEmpty() { if (fPackageMap == NULL || fPackageMap->CountPackageInfos() == 0) return; // If our map is shared, just set it to NULL. if (fPackageMap->CountReferences() != 1) { fPackageMap->ReleaseReference(); fPackageMap = NULL; return; } // Our map is not shared -- make it empty. fPackageMap->DeleteAllPackageInfos(); } uint32 BPackageInfoSet::CountInfos() const { if (fPackageMap == NULL) return 0; return fPackageMap->CountPackageInfos(); } BPackageInfoSet::Iterator BPackageInfoSet::GetIterator() const { return Iterator(fPackageMap); } BPackageInfoSet& BPackageInfoSet::operator=(const BPackageInfoSet& other) { if (other.fPackageMap == fPackageMap) return *this; if (fPackageMap != NULL) fPackageMap->ReleaseReference(); fPackageMap = other.fPackageMap; if (fPackageMap != NULL) fPackageMap->AcquireReference(); return *this; } bool BPackageInfoSet::_CopyOnWrite() { if (fPackageMap == NULL) { fPackageMap = PackageMap::Create(); return fPackageMap != NULL; } if (fPackageMap->CountReferences() == 1) return true; PackageMap* newMap = fPackageMap->Clone(); if (newMap == NULL) return false; fPackageMap->ReleaseReference(); fPackageMap = newMap; return true; } } // namespace BPackageKit