From 10e1bc52678bd81eb2c9dd1de8661ecef0d22ee0 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 16 Jul 2011 14:02:49 +0200 Subject: [PATCH] BRepositoryCache: Add iteration, etc. * Remove InitCheck() and the initializing constructor. * Rename PackageCount() to CountPackages(). * Use BOpenHashTable instead of HashMap for the internal PackageMap. * Allow multiple packages with the same name. Equally named packages are in a singly linked list after the first package with that name. * Add an Iterator inner class and a GetIterator() method, so one can now iterate through the packages in the repository. --- headers/os/package/RepositoryCache.h | 38 ++++- src/bin/pkgman/command_list_repos.cpp | 2 +- src/kits/package/RepositoryCache.cpp | 211 +++++++++++++++++++++----- 3 files changed, 211 insertions(+), 40 deletions(-) diff --git a/headers/os/package/RepositoryCache.h b/headers/os/package/RepositoryCache.h index 49c8232283..cb49150b25 100644 --- a/headers/os/package/RepositoryCache.h +++ b/headers/os/package/RepositoryCache.h @@ -15,14 +15,18 @@ namespace BPackageKit { +class BPackageInfo; + + class BRepositoryCache { +public: + class Iterator; + public: BRepositoryCache(); - BRepositoryCache(const BEntry& entry); virtual ~BRepositoryCache(); status_t SetTo(const BEntry& entry); - status_t InitCheck() const; const BRepositoryInfo& Info() const; const BEntry& Entry() const; @@ -30,14 +34,19 @@ public: void SetIsUserSpecific(bool isUserSpecific); - uint32 PackageCount() const; + uint32 CountPackages() const; + Iterator GetIterator() const; private: + struct PackageInfo; + struct PackageInfoHashDefinition; struct PackageMap; + struct RepositoryContentHandler; + struct StandardErrorOutput; + + friend class Iterator; private: - status_t fInitStatus; - BEntry fEntry; BRepositoryInfo fInfo; bool fIsUserSpecific; @@ -46,6 +55,25 @@ private: }; +class BRepositoryCache::Iterator { +public: + Iterator(); + + bool HasNext() const; + const BPackageInfo* Next(); + +private: + Iterator(const BRepositoryCache* cache); + +private: + friend class BRepositoryCache; + +private: + const BRepositoryCache* fCache; + PackageInfo* fNextInfo; +}; + + } // namespace BPackageKit diff --git a/src/bin/pkgman/command_list_repos.cpp b/src/bin/pkgman/command_list_repos.cpp index d7d1b5c6c4..7df6012571 100644 --- a/src/bin/pkgman/command_list_repos.cpp +++ b/src/bin/pkgman/command_list_repos.cpp @@ -116,7 +116,7 @@ command_list_repos(int argc, const char* const* argv) repoCache.Info().Summary().String()); printf("\t\tarch: %s\n", BPackageInfo::kArchitectureNames[ repoCache.Info().Architecture()]); - printf("\t\tpkg-count: %lu\n", repoCache.PackageCount()); + printf("\t\tpkg-count: %lu\n", repoCache.CountPackages()); printf("\t\torig-url: %s\n", repoCache.Info().OriginalBaseURL().String()); printf("\t\torig-prio: %u\n", repoCache.Info().Priority()); diff --git a/src/kits/package/RepositoryCache.cpp b/src/kits/package/RepositoryCache.cpp index 9b1dc4e160..811839c675 100644 --- a/src/kits/package/RepositoryCache.cpp +++ b/src/kits/package/RepositoryCache.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include @@ -36,14 +36,100 @@ using BPrivate::HashableString; using namespace BHPKG; -namespace { +// #pragma mark - PackageInfo -typedef ::BPrivate::HashMap PackageHashMap; +struct BRepositoryCache::PackageInfo : public BPackageInfo { + PackageInfo* hashNext; + PackageInfo* listNext; -struct RepositoryContentHandler : BRepositoryContentHandler { + PackageInfo(const BPackageInfo& other) + : + BPackageInfo(other), + listNext(NULL) + { + } +}; + + +// #pragma mark - PackageInfoHashDefinition + + +struct BRepositoryCache::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 BRepositoryCache::PackageMap + : public BOpenHashTable { + + PackageMap() + : + fCount(0) + { + } + + ~PackageMap() + { + PackageInfo* info = Clear(true); + while (info != NULL) { + PackageInfo* next = info->hashNext; + delete info; + info = next; + } + } + + void AddPackageInfo(PackageInfo* info) + { + if (PackageInfo* oldInfo = Lookup(info->Name())) { + info->listNext = oldInfo->listNext; + oldInfo->listNext = info; + } else + Insert(info); + + fCount++; + } + + uint32 CountPackageInfos() const + { + return fCount; + } + +private: + uint32 fCount; +}; + + +// #pragma mark - RepositoryContentHandler + + +struct BRepositoryCache::RepositoryContentHandler : BRepositoryContentHandler { RepositoryContentHandler(BRepositoryInfo* repositoryInfo, - PackageHashMap* packageMap) + PackageMap* packageMap) : fRepositoryInfo(repositoryInfo), fPackageMap(packageMap) @@ -154,11 +240,21 @@ struct RepositoryContentHandler : BRepositoryContentHandler { if (result != B_OK) return result; - if (fPackageMap->ContainsKey(fPackageInfo.Name())) - return B_NAME_IN_USE; - result = fPackageMap->Put(fPackageInfo.Name(), fPackageInfo); - if (result != B_OK) + PackageInfo* info = new(std::nothrow) PackageInfo(fPackageInfo); + if (info == NULL) + return B_NO_MEMORY; + + result = info->InitCheck(); + if (result != B_OK) { + delete info; return result; + } + + if (PackageInfo* oldInfo = fPackageMap->Lookup(info->Name())) { + info->listNext = oldInfo->listNext; + oldInfo->listNext = info; + } else + fPackageMap->Insert(info); fPackageInfo.Clear(); break; @@ -185,11 +281,14 @@ struct RepositoryContentHandler : BRepositoryContentHandler { private: BRepositoryInfo* fRepositoryInfo; BPackageInfo fPackageInfo; - PackageHashMap* fPackageMap; + PackageMap* fPackageMap; }; -class StandardErrorOutput : public BErrorOutput { +// #pragma mark - StandardErrorOutput + + +class BRepositoryCache::StandardErrorOutput : public BErrorOutput { virtual void PrintErrorVarArgs(const char* format, va_list args) { vfprintf(stderr, format, args); @@ -197,28 +296,61 @@ class StandardErrorOutput : public BErrorOutput { }; -} // anonymous namespace +// #pragma mark - Iterator -struct BRepositoryCache::PackageMap : public PackageHashMap { -}; - - -BRepositoryCache::BRepositoryCache() +BRepositoryCache::Iterator::Iterator() : - fInitStatus(B_NO_INIT), - fIsUserSpecific(false), - fPackageMap(new (std::nothrow) PackageMap) + fCache(NULL), + fNextInfo(NULL) { } -BRepositoryCache::BRepositoryCache(const BEntry& entry) +BRepositoryCache::Iterator::Iterator(const BRepositoryCache* cache) + : + fCache(cache), + fNextInfo(fCache->fPackageMap->GetIterator().Next()) +{ +} + +bool +BRepositoryCache::Iterator::HasNext() const +{ + return fNextInfo != NULL; +} + + +const BPackageInfo* +BRepositoryCache::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 + = fCache->fPackageMap->GetIterator(fNextInfo->Name()); + iterator.Next(); + fNextInfo = iterator.Next(); + } + } + + return result; +} + + +// #pragma mark - BRepositoryCache + + +BRepositoryCache::BRepositoryCache() : fIsUserSpecific(false), - fPackageMap(new (std::nothrow) PackageMap) + fPackageMap(NULL) { - fInitStatus = SetTo(entry); } @@ -228,13 +360,6 @@ BRepositoryCache::~BRepositoryCache() } -status_t -BRepositoryCache::InitCheck() const -{ - return fInitStatus; -} - - const BEntry& BRepositoryCache::Entry() const { @@ -266,14 +391,25 @@ BRepositoryCache::SetIsUserSpecific(bool isUserSpecific) status_t BRepositoryCache::SetTo(const BEntry& entry) { + // unset + if (fPackageMap != NULL) { + delete fPackageMap; + fPackageMap = NULL; + } + + fEntry.Unset(); + + // create the package map + fPackageMap = new (std::nothrow) PackageMap; if (fPackageMap == NULL) return B_NO_MEMORY; - status_t result = fPackageMap->InitCheck(); + + status_t result = fPackageMap->Init(); if (result != B_OK) return result; + // get cache file path fEntry = entry; - fPackageMap->Clear(); BPath repositoryCachePath; if ((result = entry.GetPath(&repositoryCachePath)) != B_OK) @@ -301,12 +437,19 @@ BRepositoryCache::SetTo(const BEntry& entry) uint32 -BRepositoryCache::PackageCount() const +BRepositoryCache::CountPackages() const { if (fPackageMap == NULL) return 0; - return fPackageMap->Size(); + return fPackageMap->CountPackageInfos(); +} + + +BRepositoryCache::Iterator +BRepositoryCache::GetIterator() const +{ + return Iterator(this); }