summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apt-pkg/cacheiterators.h268
-rw-r--r--apt-pkg/contrib/perf.h153
-rw-r--r--apt-pkg/depcache.cc2
-rw-r--r--apt-pkg/edsp.cc2
-rw-r--r--apt-pkg/pkgcache.h66
-rw-r--r--apt-pkg/solver3.cc91
-rw-r--r--apt-pkg/solver3.h82
7 files changed, 402 insertions, 262 deletions
diff --git a/apt-pkg/cacheiterators.h b/apt-pkg/cacheiterators.h
index cc2179bf7..059dc1366 100644
--- a/apt-pkg/cacheiterators.h
+++ b/apt-pkg/cacheiterators.h
@@ -53,7 +53,7 @@ template<typename Str, typename Itr> class APT_PUBLIC pkgCache::Iterator {
* basic methods from the actual structure.
* \return Pointer to the first structure of this type
*/
- Str* OwnerPointer() const { return static_cast<Itr const*>(this)->OwnerPointer(); }
+ constexpr Str* OwnerPointer() const noexcept { return static_cast<Itr const*>(this)->OwnerPointer(); }
protected:
Str *S;
@@ -67,25 +67,25 @@ template<typename Str, typename Itr> class APT_PUBLIC pkgCache::Iterator {
using pointer = Str*;
using reference = Str&;
// Iteration
- inline bool end() const {return Owner == 0 || S == OwnerPointer();}
+ constexpr bool end() const noexcept {return Owner == 0 || S == OwnerPointer();}
// Comparison
- inline bool operator ==(const Itr &B) const {return S == B.S;}
- inline bool operator !=(const Itr &B) const {return S != B.S;}
+ constexpr bool operator ==(const Itr &B) const noexcept {return S == B.S;}
+ constexpr bool operator !=(const Itr &B) const noexcept {return S != B.S;}
// Accessors
- inline Str *operator ->() {return S;}
- inline Str const *operator ->() const {return S;}
- inline operator Str *() {return S == OwnerPointer() ? 0 : S;}
- inline operator Str const *() const {return S == OwnerPointer() ? 0 : S;}
- inline Str &operator *() {return *S;}
- inline Str const &operator *() const {return *S;}
- inline pkgCache *Cache() const {return Owner;}
+ constexpr Str *operator ->() noexcept {return S;}
+ constexpr Str const *operator ->() const noexcept {return S;}
+ constexpr operator Str *() noexcept {return S == OwnerPointer() ? 0 : S;}
+ constexpr operator Str const *() const noexcept {return S == OwnerPointer() ? 0 : S;}
+ constexpr Str &operator *() noexcept {return *S;}
+ constexpr Str const &operator *() const noexcept {return *S;}
+ constexpr pkgCache *Cache() const noexcept {return Owner;}
// Mixed stuff
- inline bool IsGood() const { return S && Owner && ! end();}
- inline unsigned long Index() const {return S - OwnerPointer();}
- inline map_pointer<Str> MapPointer() const {return map_pointer<Str>(Index()) ;}
+ constexpr bool IsGood() const noexcept { return S && Owner && ! end();}
+ constexpr unsigned long Index() const noexcept {return S - OwnerPointer();}
+ constexpr map_pointer<Str> MapPointer() const noexcept {return map_pointer<Str>(Index()) ;}
void ReMap(void const * const oldMap, void * const newMap) {
if (Owner == 0 || S == 0)
@@ -94,8 +94,8 @@ template<typename Str, typename Itr> class APT_PUBLIC pkgCache::Iterator {
}
// Constructors - look out for the variable assigning
- inline Iterator() : S(0), Owner(0) {}
- inline Iterator(pkgCache &Owner,Str *T = 0) : S(T), Owner(&Owner) {}
+ constexpr Iterator() noexcept : S(0), Owner(0) {}
+ constexpr Iterator(pkgCache &Owner,Str *T = 0) noexcept : S(T), Owner(&Owner) {}
};
/*}}}*/
// Group Iterator /*{{{*/
@@ -107,12 +107,12 @@ class APT_PUBLIC pkgCache::GrpIterator: public Iterator<Group, GrpIterator> {
long HashIndex;
public:
- inline Group* OwnerPointer() const {
+ constexpr Group* OwnerPointer() const noexcept {
return (Owner != 0) ? Owner->GrpP : 0;
}
// This constructor is the 'begin' constructor, never use it.
- explicit inline GrpIterator(pkgCache &Owner) : Iterator<Group, GrpIterator>(Owner), HashIndex(-1) {
+ explicit inline GrpIterator(pkgCache &Owner) noexcept : Iterator<Group, GrpIterator>(Owner), HashIndex(-1) {
S = OwnerPointer();
operator++();
}
@@ -120,9 +120,9 @@ class APT_PUBLIC pkgCache::GrpIterator: public Iterator<Group, GrpIterator> {
GrpIterator& operator++();
inline GrpIterator operator++(int) { GrpIterator const tmp(*this); operator++(); return tmp; }
- inline const char *Name() const {return S->Name == 0?0:Owner->StrP + S->Name;}
- inline PkgIterator PackageList() const;
- inline VerIterator VersionsInSource() const;
+ constexpr const char *Name() const noexcept {return S->Name == 0?0:Owner->StrP + S->Name;}
+ constexpr PkgIterator PackageList() const noexcept;
+ constexpr VerIterator VersionsInSource() const noexcept;
PkgIterator FindPkg(std::string_view Arch = {"any", 3}) const;
/** \brief find the package with the "best" architecture
@@ -135,11 +135,11 @@ class APT_PUBLIC pkgCache::GrpIterator: public Iterator<Group, GrpIterator> {
PkgIterator NextPkg(PkgIterator const &Pkg) const;
// Constructors
- inline GrpIterator(pkgCache &Owner, Group *Trg) : Iterator<Group, GrpIterator>(Owner, Trg), HashIndex(0) {
+ constexpr GrpIterator(pkgCache &Owner, Group *Trg) noexcept : Iterator<Group, GrpIterator>(Owner, Trg), HashIndex(0) {
if (S == 0)
S = OwnerPointer();
}
- inline GrpIterator() : Iterator<Group, GrpIterator>(), HashIndex(0) {}
+ constexpr GrpIterator() noexcept : Iterator<Group, GrpIterator>(), HashIndex(0) {}
};
/*}}}*/
@@ -148,12 +148,12 @@ class APT_PUBLIC pkgCache::PkgIterator: public Iterator<Package, PkgIterator> {
long HashIndex;
public:
- inline Package* OwnerPointer() const {
+ inline Package* OwnerPointer() const noexcept {
return (Owner != 0) ? Owner->PkgP : 0;
}
// This constructor is the 'begin' constructor, never use it.
- explicit inline PkgIterator(pkgCache &Owner) : Iterator<Package, PkgIterator>(Owner), HashIndex(-1) {
+ explicit inline PkgIterator(pkgCache &Owner) noexcept : Iterator<Package, PkgIterator>(Owner), HashIndex(-1) {
S = OwnerPointer();
operator++();
}
@@ -164,16 +164,16 @@ class APT_PUBLIC pkgCache::PkgIterator: public Iterator<Package, PkgIterator> {
enum OkState {NeedsNothing,NeedsUnpack,NeedsConfigure};
// Accessors
- inline const char *Name() const { return Group().Name(); }
- inline bool Purge() const {return S->CurrentState == pkgCache::State::Purge ||
+ constexpr const char *Name() const noexcept { return Group().Name(); }
+ constexpr bool Purge() const noexcept {return S->CurrentState == pkgCache::State::Purge ||
(S->CurrentVer == 0 && S->CurrentState == pkgCache::State::NotInstalled);}
- inline const char *Arch() const {return S->Arch == 0?0:Owner->StrP + S->Arch;}
- inline APT_PURE GrpIterator Group() const { return GrpIterator(*Owner, Owner->GrpP + S->Group);}
+ constexpr const char *Arch() const noexcept {return S->Arch == 0?0:Owner->StrP + S->Arch;}
+ constexpr APT_PURE GrpIterator Group() const noexcept { return GrpIterator(*Owner, Owner->GrpP + S->Group);}
- inline VerIterator VersionList() const APT_PURE;
- inline VerIterator CurrentVer() const APT_PURE;
- inline DepIterator RevDependsList() const APT_PURE;
- inline PrvIterator ProvidesList() const APT_PURE;
+ constexpr VerIterator VersionList() const noexcept APT_PURE;
+ constexpr VerIterator CurrentVer() const noexcept APT_PURE;
+ constexpr DepIterator RevDependsList() const noexcept APT_PURE;
+ constexpr PrvIterator ProvidesList() const noexcept APT_PURE;
OkState State() const APT_PURE;
const char *CurVersion() const APT_PURE;
@@ -182,18 +182,18 @@ class APT_PUBLIC pkgCache::PkgIterator: public Iterator<Package, PkgIterator> {
std::string FullName(bool const &Pretty = false) const;
// Constructors
- inline PkgIterator(pkgCache &Owner,Package *Trg) : Iterator<Package, PkgIterator>(Owner, Trg), HashIndex(0) {
+ constexpr PkgIterator(pkgCache &Owner,Package *Trg) noexcept : Iterator<Package, PkgIterator>(Owner, Trg), HashIndex(0) {
if (S == 0)
S = OwnerPointer();
}
- inline PkgIterator() : Iterator<Package, PkgIterator>(), HashIndex(0) {}
+ constexpr PkgIterator() noexcept : Iterator<Package, PkgIterator>(), HashIndex(0) {}
};
/*}}}*/
// SourceVersion Iterator /*{{{*/
class APT_PUBLIC pkgCache::SrcVerIterator : public Iterator<SourceVersion, SrcVerIterator>
{
public:
- inline SourceVersion *OwnerPointer() const
+ constexpr SourceVersion *OwnerPointer() const noexcept
{
return (Owner != 0) ? Owner->SrcVerP : 0;
}
@@ -202,22 +202,22 @@ class APT_PUBLIC pkgCache::SrcVerIterator : public Iterator<SourceVersion, SrcVe
inline SrcVerIterator& operator++() {if (S != Owner->SrcVerP) S = Owner->SrcVerP + S->NextSourceVersion; return *this;}
inline SrcVerIterator operator++(int) { SrcVerIterator const tmp(*this); operator++(); return tmp; }
#endif
- inline APT_PURE GrpIterator Group() const { return GrpIterator(*Owner, Owner->GrpP + S->Group); }
- inline const char *VerStr() const { return S->VerStr == 0 ? 0 : Owner->StrP + S->VerStr; }
+ constexpr APT_PURE GrpIterator Group() const noexcept { return GrpIterator(*Owner, Owner->GrpP + S->Group); }
+ constexpr const char *VerStr() const noexcept { return S->VerStr == 0 ? 0 : Owner->StrP + S->VerStr; }
- inline SrcVerIterator(pkgCache &Owner, SourceVersion *Trg = 0) : Iterator<SourceVersion, SrcVerIterator>(Owner, Trg)
+ constexpr SrcVerIterator(pkgCache &Owner, SourceVersion *Trg = 0) noexcept : Iterator<SourceVersion, SrcVerIterator>(Owner, Trg)
{
if (S == 0)
S = OwnerPointer();
}
- inline SrcVerIterator() : Iterator<SourceVersion, SrcVerIterator>() {}
+ constexpr SrcVerIterator() noexcept : Iterator<SourceVersion, SrcVerIterator>() {}
};
/*}}}*/
// Version Iterator /*{{{*/
class APT_PUBLIC pkgCache::VerIterator : public Iterator<Version, VerIterator> {
public:
- inline Version* OwnerPointer() const {
+ inline Version* OwnerPointer() const noexcept {
return (Owner != 0) ? Owner->VerP : 0;
}
@@ -225,7 +225,7 @@ class APT_PUBLIC pkgCache::VerIterator : public Iterator<Version, VerIterator> {
inline VerIterator& operator++() {if (S != Owner->VerP) S = Owner->VerP + S->NextVer; return *this;}
inline VerIterator operator++(int) { VerIterator const tmp(*this); operator++(); return tmp; }
- inline VerIterator NextInSource()
+ constexpr VerIterator NextInSource() noexcept
{
if (S != Owner->VerP)
S = Owner->VerP + S->NextInSource;
@@ -238,35 +238,35 @@ class APT_PUBLIC pkgCache::VerIterator : public Iterator<Version, VerIterator> {
This method should be used to identify if two pseudo versions are
referring to the same "real" version */
- inline bool SimilarVer(const VerIterator &B) const {
+ constexpr bool SimilarVer(const VerIterator &B) const noexcept {
return (B.end() == false && S->Hash == B->Hash && strcmp(VerStr(), B.VerStr()) == 0);
}
// Accessors
- inline const char *VerStr() const {return S->VerStr == 0?0:Owner->StrP + S->VerStr;}
- inline const char *Section() const {return S->Section == 0?0:Owner->StrP + S->Section;}
+ constexpr const char *VerStr() const noexcept {return S->VerStr == 0?0:Owner->StrP + S->VerStr;}
+ constexpr const char *Section() const noexcept {return S->Section == 0?0:Owner->StrP + S->Section;}
/** \brief source version this version comes from
Always contains the version string, even if it is the same as the binary version */
- SrcVerIterator SourceVersion() const { return SrcVerIterator(*Owner, Owner->SrcVerP + S->SourceVersion); }
+ constexpr SrcVerIterator SourceVersion() const noexcept { return SrcVerIterator(*Owner, Owner->SrcVerP + S->SourceVersion); }
/** \brief source package name this version comes from
Always contains the name, even if it is the same as the binary name */
- inline const char *SourcePkgName() const { return SourceVersion().Group().Name(); }
+ constexpr const char *SourcePkgName() const noexcept { return SourceVersion().Group().Name(); }
/** \brief source version this version comes from
Always contains the version string, even if it is the same as the binary version */
- inline const char *SourceVerStr() const { return SourceVersion().VerStr(); }
- inline const char *Arch() const {
+ constexpr const char *SourceVerStr() const noexcept { return SourceVersion().VerStr(); }
+ constexpr const char *Arch() const noexcept {
if ((S->MultiArch & pkgCache::Version::All) == pkgCache::Version::All)
return "all";
return S->ParentPkg == 0?0:Owner->StrP + ParentPkg()->Arch;
}
- inline PkgIterator ParentPkg() const {return PkgIterator(*Owner,Owner->PkgP + S->ParentPkg);}
+ constexpr PkgIterator ParentPkg() const noexcept {return PkgIterator(*Owner,Owner->PkgP + S->ParentPkg);}
- inline DescIterator DescriptionList() const;
+ constexpr DescIterator DescriptionList() const noexcept;
DescIterator TranslatedDescriptionForLanguage(std::string_view lang) const;
DescIterator TranslatedDescription() const;
- inline DepIterator DependsList() const;
- inline PrvIterator ProvidesList() const;
- inline VerFileIterator FileList() const;
+ constexpr DepIterator DependsList() const noexcept;
+ constexpr PrvIterator ProvidesList() const noexcept;
+ constexpr VerFileIterator FileList() const noexcept;
bool Downloadable() const;
inline const char *PriorityType() const {return Owner->Priority(S->Priority);}
const char *MultiArchType() const APT_PURE;
@@ -300,17 +300,17 @@ class APT_PUBLIC pkgCache::VerIterator : public Iterator<Version, VerIterator> {
}
#endif
- inline VerIterator(pkgCache &Owner,Version *Trg = 0) : Iterator<Version, VerIterator>(Owner, Trg) {
+ constexpr VerIterator(pkgCache &Owner,Version *Trg = 0) noexcept : Iterator<Version, VerIterator>(Owner, Trg) {
if (S == 0)
S = OwnerPointer();
}
- inline VerIterator() : Iterator<Version, VerIterator>() {}
+ constexpr VerIterator() noexcept : Iterator<Version, VerIterator>() {}
};
/*}}}*/
// Description Iterator /*{{{*/
class APT_PUBLIC pkgCache::DescIterator : public Iterator<Description, DescIterator> {
public:
- inline Description* OwnerPointer() const {
+ constexpr Description* OwnerPointer() const noexcept {
return (Owner != 0) ? Owner->DescP : 0;
}
@@ -322,12 +322,12 @@ class APT_PUBLIC pkgCache::DescIterator : public Iterator<Description, DescItera
int CompareDesc(const DescIterator &B) const;
// Accessors
- inline const char *LanguageCode() const {return Owner->StrP + S->language_code;}
- inline const char *md5() const {return Owner->StrP + S->md5sum;}
- inline DescFileIterator FileList() const;
+ constexpr const char *LanguageCode() const noexcept {return Owner->StrP + S->language_code;}
+ constexpr const char *md5() const noexcept {return Owner->StrP + S->md5sum;}
+ constexpr DescFileIterator FileList() const noexcept;
- inline DescIterator() : Iterator<Description, DescIterator>() {}
- inline DescIterator(pkgCache &Owner,Description *Trg = 0) : Iterator<Description, DescIterator>(Owner, Trg) {
+ constexpr DescIterator() noexcept : Iterator<Description, DescIterator>() {}
+ constexpr DescIterator(pkgCache &Owner,Description *Trg = 0) noexcept : Iterator<Description, DescIterator>(Owner, Trg) {
if (S == 0)
S = Owner.DescP;
}
@@ -339,7 +339,7 @@ class APT_PUBLIC pkgCache::DepIterator : public Iterator<Dependency, DepIterator
DependencyData * S2;
public:
- inline Dependency* OwnerPointer() const {
+ constexpr Dependency* OwnerPointer() const noexcept {
return (Owner != 0) ? Owner->DepP : 0;
}
@@ -348,12 +348,12 @@ class APT_PUBLIC pkgCache::DepIterator : public Iterator<Dependency, DepIterator
inline DepIterator operator++(int) { DepIterator const tmp(*this); operator++(); return tmp; }
// Accessors
- inline const char *TargetVer() const {return S2->Version == 0?0:Owner->StrP + S2->Version;}
- inline PkgIterator TargetPkg() const {return PkgIterator(*Owner,Owner->PkgP + S2->Package);}
- inline PkgIterator SmartTargetPkg() const {PkgIterator R(*Owner,0);SmartTargetPkg(R);return R;}
- inline VerIterator ParentVer() const {return VerIterator(*Owner,Owner->VerP + S->ParentVer);}
- inline PkgIterator ParentPkg() const {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[uint32_t(S->ParentVer)].ParentPkg);}
- inline bool Reverse() const {return Type == DepRev;}
+ constexpr const char *TargetVer() const noexcept {return S2->Version == 0?0:Owner->StrP + S2->Version;}
+ constexpr PkgIterator TargetPkg() const noexcept {return PkgIterator(*Owner,Owner->PkgP + S2->Package);}
+ inline PkgIterator SmartTargetPkg() const noexcept {PkgIterator R(*Owner,0);SmartTargetPkg(R);return R;}
+ constexpr VerIterator ParentVer() const noexcept {return VerIterator(*Owner,Owner->VerP + S->ParentVer);}
+ constexpr PkgIterator ParentPkg() const noexcept {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[uint32_t(S->ParentVer)].ParentPkg);}
+ constexpr bool Reverse() const noexcept {return Type == DepRev;}
bool IsCritical() const APT_PURE;
bool IsNegative() const APT_PURE;
bool IsIgnorable(PrvIterator const &Prv) const APT_PURE;
@@ -361,7 +361,7 @@ class APT_PUBLIC pkgCache::DepIterator : public Iterator<Dependency, DepIterator
/* MultiArch can be translated to SingleArch for an resolver and we did so,
by adding dependencies to help the resolver understand the problem, but
sometimes it is needed to identify these to ignore them… */
- inline bool IsMultiArchImplicit() const APT_PURE {
+ constexpr bool IsMultiArchImplicit() const APT_PURE {
return (S2->CompareOp & pkgCache::Dep::MultiArchImplicit) == pkgCache::Dep::MultiArchImplicit;
}
/* This covers additionally negative dependencies, which aren't arch-specific,
@@ -390,11 +390,11 @@ class APT_PUBLIC pkgCache::DepIterator : public Iterator<Dependency, DepIterator
map_pointer<Dependency> &NextRevDepends;
map_pointer<Dependency> &NextDepends;
map_pointer<pkgCache::DependencyData> &NextData;
- DependencyProxy const * operator->() const { return this; }
- DependencyProxy * operator->() { return this; }
+ constexpr DependencyProxy const * operator->() const noexcept { return this; }
+ constexpr DependencyProxy * operator->() noexcept { return this; }
};
- inline DependencyProxy operator->() const {return (DependencyProxy) { S2->Version, S2->Package, S->ID, S2->Type, S2->CompareOp, S->ParentVer, S->DependencyData, S->NextRevDepends, S->NextDepends, S2->NextData };}
- inline DependencyProxy operator->() {return (DependencyProxy) { S2->Version, S2->Package, S->ID, S2->Type, S2->CompareOp, S->ParentVer, S->DependencyData, S->NextRevDepends, S->NextDepends, S2->NextData };}
+ constexpr DependencyProxy operator->() const noexcept {return (DependencyProxy) { S2->Version, S2->Package, S->ID, S2->Type, S2->CompareOp, S->ParentVer, S->DependencyData, S->NextRevDepends, S->NextDepends, S2->NextData };}
+ constexpr DependencyProxy operator->() {return (DependencyProxy) { S2->Version, S2->Package, S->ID, S2->Type, S2->CompareOp, S->ParentVer, S->DependencyData, S->NextRevDepends, S->NextDepends, S2->NextData };}
void ReMap(void const * const oldMap, void * const newMap)
{
Iterator<Dependency, DepIterator>::ReMap(oldMap, newMap);
@@ -406,17 +406,17 @@ class APT_PUBLIC pkgCache::DepIterator : public Iterator<Dependency, DepIterator
// for a nice printable representation you likely want APT::PrettyDep instead
friend std::ostream& operator<<(std::ostream& out, DepIterator D);
- inline DepIterator(pkgCache &Owner, Dependency *Trg, Version* = 0) :
+ constexpr DepIterator(pkgCache &Owner, Dependency *Trg, Version* = 0) noexcept :
Iterator<Dependency, DepIterator>(Owner, Trg), Type(DepVer), S2(Trg == 0 ? Owner.DepDataP : (Owner.DepDataP + Trg->DependencyData)) {
if (S == 0)
S = Owner.DepP;
}
- inline DepIterator(pkgCache &Owner, Dependency *Trg, Package*) :
+ constexpr DepIterator(pkgCache &Owner, Dependency *Trg, Package*) noexcept :
Iterator<Dependency, DepIterator>(Owner, Trg), Type(DepRev), S2(Trg == 0 ? Owner.DepDataP : (Owner.DepDataP + Trg->DependencyData)) {
if (S == 0)
S = Owner.DepP;
}
- inline DepIterator() : Iterator<Dependency, DepIterator>(), Type(DepVer), S2(0) {}
+ constexpr DepIterator() noexcept : Iterator<Dependency, DepIterator>(), Type(DepVer), S2(0) {}
};
/*}}}*/
// Provides iterator /*{{{*/
@@ -424,7 +424,7 @@ class APT_PUBLIC pkgCache::PrvIterator : public Iterator<Provides, PrvIterator>
enum {PrvVer, PrvPkg} Type;
public:
- inline Provides* OwnerPointer() const {
+ constexpr Provides* OwnerPointer() const noexcept {
return (Owner != 0) ? Owner->ProvideP : 0;
}
@@ -437,11 +437,11 @@ class APT_PUBLIC pkgCache::PrvIterator : public Iterator<Provides, PrvIterator>
inline PrvIterator operator++(int) { PrvIterator const tmp(*this); operator++(); return tmp; }
// Accessors
- inline const char *Name() const {return ParentPkg().Name();}
- inline const char *ProvideVersion() const {return S->ProvideVersion == 0?0:Owner->StrP + S->ProvideVersion;}
- inline PkgIterator ParentPkg() const {return PkgIterator(*Owner,Owner->PkgP + S->ParentPkg);}
- inline VerIterator OwnerVer() const {return VerIterator(*Owner,Owner->VerP + S->Version);}
- inline PkgIterator OwnerPkg() const {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[uint32_t(S->Version)].ParentPkg);}
+ constexpr const char *Name() const noexcept {return ParentPkg().Name();}
+ constexpr const char *ProvideVersion() const noexcept {return S->ProvideVersion == 0?0:Owner->StrP + S->ProvideVersion;}
+ constexpr PkgIterator ParentPkg() const noexcept {return PkgIterator(*Owner,Owner->PkgP + S->ParentPkg);}
+ constexpr VerIterator OwnerVer() const noexcept {return VerIterator(*Owner,Owner->VerP + S->Version);}
+ constexpr PkgIterator OwnerPkg() const noexcept {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[uint32_t(S->Version)].ParentPkg);}
/* MultiArch can be translated to SingleArch for an resolver and we did so,
by adding provides to help the resolver understand the problem, but
@@ -450,13 +450,13 @@ class APT_PUBLIC pkgCache::PrvIterator : public Iterator<Provides, PrvIterator>
{ return (S->Flags & pkgCache::Flag::MultiArchImplicit) == pkgCache::Flag::MultiArchImplicit; }
- inline PrvIterator() : Iterator<Provides, PrvIterator>(), Type(PrvVer) {}
- inline PrvIterator(pkgCache &Owner, Provides *Trg, Version*) :
+ constexpr PrvIterator() noexcept : Iterator<Provides, PrvIterator>(), Type(PrvVer) {}
+ constexpr PrvIterator(pkgCache &Owner, Provides *Trg, Version*) noexcept :
Iterator<Provides, PrvIterator>(Owner, Trg), Type(PrvVer) {
if (S == 0)
S = Owner.ProvideP;
}
- inline PrvIterator(pkgCache &Owner, Provides *Trg, Package*) :
+ constexpr PrvIterator(pkgCache &Owner, Provides *Trg, Package*) noexcept :
Iterator<Provides, PrvIterator>(Owner, Trg), Type(PrvPkg) {
if (S == 0)
S = Owner.ProvideP;
@@ -466,7 +466,7 @@ class APT_PUBLIC pkgCache::PrvIterator : public Iterator<Provides, PrvIterator>
// Release file /*{{{*/
class APT_PUBLIC pkgCache::RlsFileIterator : public Iterator<ReleaseFile, RlsFileIterator> {
public:
- inline ReleaseFile* OwnerPointer() const {
+ constexpr ReleaseFile* OwnerPointer() const noexcept {
return (Owner != 0) ? Owner->RlsFileP : 0;
}
@@ -475,27 +475,27 @@ class APT_PUBLIC pkgCache::RlsFileIterator : public Iterator<ReleaseFile, RlsFil
inline RlsFileIterator operator++(int) { RlsFileIterator const tmp(*this); operator++(); return tmp; }
// Accessors
- inline const char *FileName() const {return S->FileName == 0?0:Owner->StrP + S->FileName;}
- inline const char *Archive() const {return S->Archive == 0?0:Owner->StrP + S->Archive;}
- inline const char *Version() const {return S->Version == 0?0:Owner->StrP + S->Version;}
- inline const char *Origin() const {return S->Origin == 0?0:Owner->StrP + S->Origin;}
- inline const char *Codename() const {return S->Codename ==0?0:Owner->StrP + S->Codename;}
- inline const char *Label() const {return S->Label == 0?0:Owner->StrP + S->Label;}
- inline const char *Site() const {return S->Site == 0?0:Owner->StrP + S->Site;}
- inline bool Flagged(pkgCache::Flag::ReleaseFileFlags const flag) const {return (S->Flags & flag) == flag; }
+ constexpr const char *FileName() const noexcept {return S->FileName == 0?0:Owner->StrP + S->FileName;}
+ constexpr const char *Archive() const noexcept {return S->Archive == 0?0:Owner->StrP + S->Archive;}
+ constexpr const char *Version() const noexcept {return S->Version == 0?0:Owner->StrP + S->Version;}
+ constexpr const char *Origin() const noexcept {return S->Origin == 0?0:Owner->StrP + S->Origin;}
+ constexpr const char *Codename() const noexcept {return S->Codename ==0?0:Owner->StrP + S->Codename;}
+ constexpr const char *Label() const noexcept {return S->Label == 0?0:Owner->StrP + S->Label;}
+ constexpr const char *Site() const noexcept {return S->Site == 0?0:Owner->StrP + S->Site;}
+ constexpr bool Flagged(pkgCache::Flag::ReleaseFileFlags const flag) const noexcept {return (S->Flags & flag) == flag; }
std::string RelStr();
// Constructors
- inline RlsFileIterator() : Iterator<ReleaseFile, RlsFileIterator>() {}
- explicit inline RlsFileIterator(pkgCache &Owner) : Iterator<ReleaseFile, RlsFileIterator>(Owner, Owner.RlsFileP) {}
- inline RlsFileIterator(pkgCache &Owner,ReleaseFile *Trg) : Iterator<ReleaseFile, RlsFileIterator>(Owner, Trg) {}
+ constexpr RlsFileIterator() noexcept : Iterator<ReleaseFile, RlsFileIterator>() {}
+ explicit constexpr RlsFileIterator(pkgCache &Owner) noexcept : Iterator<ReleaseFile, RlsFileIterator>(Owner, Owner.RlsFileP) {}
+ constexpr RlsFileIterator(pkgCache &Owner,ReleaseFile *Trg) noexcept : Iterator<ReleaseFile, RlsFileIterator>(Owner, Trg) {}
};
/*}}}*/
// Package file /*{{{*/
class APT_PUBLIC pkgCache::PkgFileIterator : public Iterator<PackageFile, PkgFileIterator> {
public:
- inline PackageFile* OwnerPointer() const {
+ constexpr PackageFile* OwnerPointer() const noexcept {
return (Owner != 0) ? Owner->PkgFileP : 0;
}
@@ -504,32 +504,32 @@ class APT_PUBLIC pkgCache::PkgFileIterator : public Iterator<PackageFile, PkgFil
inline PkgFileIterator operator++(int) { PkgFileIterator const tmp(*this); operator++(); return tmp; }
// Accessors
- inline const char *FileName() const {return S->FileName == 0?0:Owner->StrP + S->FileName;}
- inline pkgCache::RlsFileIterator ReleaseFile() const {return RlsFileIterator(*Owner, Owner->RlsFileP + S->Release);}
- inline const char *Archive() const {return S->Release == 0 ? Component() : ReleaseFile().Archive();}
- inline const char *Version() const {return S->Release == 0 ? NULL : ReleaseFile().Version();}
- inline const char *Origin() const {return S->Release == 0 ? NULL : ReleaseFile().Origin();}
- inline const char *Codename() const {return S->Release == 0 ? NULL : ReleaseFile().Codename();}
- inline const char *Label() const {return S->Release == 0 ? NULL : ReleaseFile().Label();}
- inline const char *Site() const {return S->Release == 0 ? NULL : ReleaseFile().Site();}
- inline bool Flagged(pkgCache::Flag::ReleaseFileFlags const flag) const {return S->Release== 0 ? false : ReleaseFile().Flagged(flag);}
- inline bool Flagged(pkgCache::Flag::PkgFFlags const flag) const {return (S->Flags & flag) == flag;}
- inline const char *Component() const {return S->Component == 0?0:Owner->StrP + S->Component;}
- inline const char *Architecture() const {return S->Architecture == 0?0:Owner->StrP + S->Architecture;}
- inline const char *IndexType() const {return S->IndexType == 0?0:Owner->StrP + S->IndexType;}
+ constexpr const char *FileName() const noexcept {return S->FileName == 0?0:Owner->StrP + S->FileName;}
+ constexpr pkgCache::RlsFileIterator ReleaseFile() const noexcept {return RlsFileIterator(*Owner, Owner->RlsFileP + S->Release);}
+ constexpr const char *Archive() const noexcept {return S->Release == 0 ? Component() : ReleaseFile().Archive();}
+ constexpr const char *Version() const noexcept {return S->Release == 0 ? NULL : ReleaseFile().Version();}
+ constexpr const char *Origin() const noexcept {return S->Release == 0 ? NULL : ReleaseFile().Origin();}
+ constexpr const char *Codename() const noexcept {return S->Release == 0 ? NULL : ReleaseFile().Codename();}
+ constexpr const char *Label() const noexcept {return S->Release == 0 ? NULL : ReleaseFile().Label();}
+ constexpr const char *Site() const noexcept {return S->Release == 0 ? NULL : ReleaseFile().Site();}
+ constexpr bool Flagged(pkgCache::Flag::ReleaseFileFlags const flag) const noexcept {return S->Release== 0 ? false : ReleaseFile().Flagged(flag);}
+ constexpr bool Flagged(pkgCache::Flag::PkgFFlags const flag) const noexcept {return (S->Flags & flag) == flag;}
+ constexpr const char *Component() const noexcept {return S->Component == 0?0:Owner->StrP + S->Component;}
+ constexpr const char *Architecture() const noexcept {return S->Architecture == 0?0:Owner->StrP + S->Architecture;}
+ constexpr const char *IndexType() const noexcept {return S->IndexType == 0?0:Owner->StrP + S->IndexType;}
std::string RelStr();
// Constructors
- inline PkgFileIterator() : Iterator<PackageFile, PkgFileIterator>() {}
- explicit inline PkgFileIterator(pkgCache &Owner) : Iterator<PackageFile, PkgFileIterator>(Owner, Owner.PkgFileP) {}
- inline PkgFileIterator(pkgCache &Owner,PackageFile *Trg) : Iterator<PackageFile, PkgFileIterator>(Owner, Trg) {}
+ constexpr PkgFileIterator() noexcept : Iterator<PackageFile, PkgFileIterator>() {}
+ explicit constexpr PkgFileIterator(pkgCache &Owner) noexcept : Iterator<PackageFile, PkgFileIterator>(Owner, Owner.PkgFileP) {}
+ constexpr PkgFileIterator(pkgCache &Owner,PackageFile *Trg) noexcept : Iterator<PackageFile, PkgFileIterator>(Owner, Trg) {}
};
/*}}}*/
// Version File /*{{{*/
class APT_PUBLIC pkgCache::VerFileIterator : public pkgCache::Iterator<VerFile, VerFileIterator> {
public:
- inline VerFile* OwnerPointer() const {
+ constexpr VerFile* OwnerPointer() const noexcept {
return (Owner != 0) ? Owner->VerFileP : 0;
}
@@ -538,16 +538,16 @@ class APT_PUBLIC pkgCache::VerFileIterator : public pkgCache::Iterator<VerFile,
inline VerFileIterator operator++(int) { VerFileIterator const tmp(*this); operator++(); return tmp; }
// Accessors
- inline PkgFileIterator File() const {return PkgFileIterator(*Owner, Owner->PkgFileP + S->File);}
+ constexpr PkgFileIterator File() const noexcept {return PkgFileIterator(*Owner, Owner->PkgFileP + S->File);}
- inline VerFileIterator() : Iterator<VerFile, VerFileIterator>() {}
- inline VerFileIterator(pkgCache &Owner,VerFile *Trg) : Iterator<VerFile, VerFileIterator>(Owner, Trg) {}
+ constexpr VerFileIterator() noexcept : Iterator<VerFile, VerFileIterator>() {}
+ constexpr VerFileIterator(pkgCache &Owner,VerFile *Trg) noexcept : Iterator<VerFile, VerFileIterator>(Owner, Trg) {}
};
/*}}}*/
// Description File /*{{{*/
class APT_PUBLIC pkgCache::DescFileIterator : public Iterator<DescFile, DescFileIterator> {
public:
- inline DescFile* OwnerPointer() const {
+ constexpr DescFile* OwnerPointer() const noexcept {
return (Owner != 0) ? Owner->DescFileP : 0;
}
@@ -556,36 +556,36 @@ class APT_PUBLIC pkgCache::DescFileIterator : public Iterator<DescFile, DescFile
inline DescFileIterator operator++(int) { DescFileIterator const tmp(*this); operator++(); return tmp; }
// Accessors
- inline PkgFileIterator File() const {return PkgFileIterator(*Owner, Owner->PkgFileP + S->File);}
+ constexpr PkgFileIterator File() const noexcept {return PkgFileIterator(*Owner, Owner->PkgFileP + S->File);}
- inline DescFileIterator() : Iterator<DescFile, DescFileIterator>() {}
- inline DescFileIterator(pkgCache &Owner,DescFile *Trg) : Iterator<DescFile, DescFileIterator>(Owner, Trg) {}
+ constexpr DescFileIterator() noexcept : Iterator<DescFile, DescFileIterator>() {}
+ constexpr DescFileIterator(pkgCache &Owner,DescFile *Trg) noexcept : Iterator<DescFile, DescFileIterator>(Owner, Trg) {}
};
/*}}}*/
// Inlined Begin functions can't be in the class because of order problems /*{{{*/
-inline pkgCache::PkgIterator pkgCache::GrpIterator::PackageList() const
+constexpr pkgCache::PkgIterator pkgCache::GrpIterator::PackageList() const noexcept
{return PkgIterator(*Owner,Owner->PkgP + S->FirstPackage);}
- inline pkgCache::VerIterator pkgCache::GrpIterator::VersionsInSource() const
+ constexpr pkgCache::VerIterator pkgCache::GrpIterator::VersionsInSource() const noexcept
{
return VerIterator(*Owner, Owner->VerP + S->VersionsInSource);
}
-inline pkgCache::VerIterator pkgCache::PkgIterator::VersionList() const
+constexpr pkgCache::VerIterator pkgCache::PkgIterator::VersionList() const noexcept
{return VerIterator(*Owner,Owner->VerP + S->VersionList);}
-inline pkgCache::VerIterator pkgCache::PkgIterator::CurrentVer() const
+constexpr pkgCache::VerIterator pkgCache::PkgIterator::CurrentVer() const noexcept
{return VerIterator(*Owner,Owner->VerP + S->CurrentVer);}
-inline pkgCache::DepIterator pkgCache::PkgIterator::RevDependsList() const
+constexpr pkgCache::DepIterator pkgCache::PkgIterator::RevDependsList() const noexcept
{return DepIterator(*Owner,Owner->DepP + S->RevDepends,S);}
-inline pkgCache::PrvIterator pkgCache::PkgIterator::ProvidesList() const
+constexpr pkgCache::PrvIterator pkgCache::PkgIterator::ProvidesList() const noexcept
{return PrvIterator(*Owner,Owner->ProvideP + S->ProvidesList,S);}
-inline pkgCache::DescIterator pkgCache::VerIterator::DescriptionList() const
+constexpr pkgCache::DescIterator pkgCache::VerIterator::DescriptionList() const noexcept
{return DescIterator(*Owner,Owner->DescP + S->DescriptionList);}
-inline pkgCache::PrvIterator pkgCache::VerIterator::ProvidesList() const
+constexpr pkgCache::PrvIterator pkgCache::VerIterator::ProvidesList() const noexcept
{return PrvIterator(*Owner,Owner->ProvideP + S->ProvidesList,S);}
-inline pkgCache::DepIterator pkgCache::VerIterator::DependsList() const
+constexpr pkgCache::DepIterator pkgCache::VerIterator::DependsList() const noexcept
{return DepIterator(*Owner,Owner->DepP + S->DependsList,S);}
-inline pkgCache::VerFileIterator pkgCache::VerIterator::FileList() const
+constexpr pkgCache::VerFileIterator pkgCache::VerIterator::FileList() const noexcept
{return VerFileIterator(*Owner,Owner->VerFileP + S->FileList);}
-inline pkgCache::DescFileIterator pkgCache::DescIterator::FileList() const
+constexpr pkgCache::DescFileIterator pkgCache::DescIterator::FileList() const noexcept
{return DescFileIterator(*Owner,Owner->DescFileP + S->FileList);}
/*}}}*/
#endif
diff --git a/apt-pkg/contrib/perf.h b/apt-pkg/contrib/perf.h
new file mode 100644
index 000000000..7a56d5149
--- /dev/null
+++ b/apt-pkg/contrib/perf.h
@@ -0,0 +1,153 @@
+/*
+ * Performance measurements
+ *
+ * Copyright (C) 2026 Julian Andres Klode <jak@debian.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef APT_PERF_H
+#define APT_PERF_H
+#if defined(APT_COMPILING_APT) && defined(__linux__)
+#include <apt-pkg/macros.h>
+
+#include <array>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <sstream>
+
+#include <fcntl.h>
+#include <linux/perf_event.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+namespace APT
+{
+
+/**
+ * \brief A scoped object that will log the performance counters.
+ *
+ * Set the "APT_PERFORMANCE_LOG" environment variable to produce a
+ * JSONL file with records for various contexts, such as the solver.
+ */
+class PerformanceContext
+{
+ struct measurement
+ {
+ uint32_t type;
+ uint64_t config;
+ const char *name;
+ };
+
+ static constexpr std::array<measurement, 10> measurements{
+ measurement{PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS, "instructions"},
+ measurement{PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES, "cpu_cycles"},
+ measurement{PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES, "ref_cpu_cycles"},
+ measurement{PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES, "cache_references"},
+ measurement{PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES, "cache_misses"},
+ measurement{PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS, "branch_instructions"},
+ measurement{PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES, "branch_misses"},
+ measurement{PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, "cpu_clock"},
+ measurement{PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS, "page_faults"},
+ measurement{PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS, "cpu_migrations"},
+ };
+
+ /// Output filename
+ std::string out;
+ /// Name of the context
+ std::string name;
+ /// FDs to communicate with the kernel
+ std::array<int, measurements.size()> fds;
+
+ // Wrapper for the system call
+ static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
+ int cpu, int group_fd, unsigned long flags)
+ {
+ return syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags);
+ }
+
+ // Wrapper for the system call
+ static int open_perf_counter(uint32_t type, uint64_t config)
+ {
+ struct perf_event_attr pe;
+ memset(&pe, 0, sizeof(struct perf_event_attr));
+ pe.type = type;
+ pe.size = sizeof(struct perf_event_attr);
+ pe.config = config;
+ pe.disabled = 1;
+ pe.exclude_kernel = 1;
+ pe.exclude_hv = 1;
+
+ int fd = perf_event_open(&pe, 0, -1, -1, 0);
+ return fd;
+ }
+
+ public:
+ /// Construct a new scoped performance context
+ PerformanceContext(std::string name) : name(name)
+ {
+ if (auto out = getenv("APT_PERFORMANCE_LOG"))
+ this->out = out;
+ if (likely(out.empty()))
+ return;
+ for (size_t i = 0; i < measurements.size(); ++i)
+ fds[i] = open_perf_counter(measurements[i].type, measurements[i].config);
+ for (auto fd : fds)
+ must_succeed(fd == -1 || ioctl(fd, PERF_EVENT_IOC_RESET, 0) != -1);
+ for (auto fd : fds)
+ must_succeed(fd == -1 || ioctl(fd, PERF_EVENT_IOC_ENABLE, 0) != -1);
+ }
+ /// Collect the results and store them in the specified performance file
+ ~PerformanceContext()
+ {
+ if (likely(out.empty()))
+ return;
+ for (auto fd : fds)
+ must_succeed(fd == -1 || ioctl(fd, PERF_EVENT_IOC_DISABLE, 0) != -1);
+
+ std::array<long long, measurements.size()> values;
+ for (size_t i = 0; i < measurements.size(); ++i)
+ must_succeed(fds[i] == -1 || read(fds[i], &values[i], sizeof(values[i])) == sizeof(values[i]));
+ for (auto fd : fds)
+ must_succeed(fd == -1 || close(fd) == 0);
+
+ std::stringstream ss;
+ ss.imbue(std::locale::classic());
+ ss << "{\"context\": " << '"' << name << '"';
+ for (size_t i = 0; i < measurements.size(); ++i)
+ {
+ ss << ", ";
+ ss << '"' << measurements[i].name << '"' << ": " << values[i];
+ }
+
+ ss << "}\n";
+
+ std::string entry = ss.str();
+
+ // Atomically append a line to the JSONL file, allowing all users to read it
+ int fd = open(out.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666);
+ must_succeed(fd != -1);
+ must_succeed(flock(fd, LOCK_EX) == 0);
+ must_succeed(write(fd, entry.c_str(), entry.size()) == static_cast<ssize_t>(entry.size()));
+ must_succeed(flock(fd, LOCK_UN) == 0);
+ must_succeed(close(fd) == 0);
+ }
+};
+
+} // namespace APT
+
+#else
+namespace APT
+{
+struct PerformanceContext
+{
+ PerformanceContext(const char *) {};
+ ~PerformanceContext() {};
+};
+} // namespace APT
+#endif
+#endif
diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc
index f7f508f85..2a9ef50d2 100644
--- a/apt-pkg/depcache.cc
+++ b/apt-pkg/depcache.cc
@@ -19,6 +19,7 @@
#include <apt-pkg/error.h>
#include <apt-pkg/fileutl.h>
#include <apt-pkg/macros.h>
+#include <apt-pkg/perf.h>
#include <apt-pkg/pkgcache.h>
#include <apt-pkg/prettyprinters.h>
#include <apt-pkg/progress.h>
@@ -225,6 +226,7 @@ bool pkgDepCache::CheckConsistency(char const *const msgtag) /*{{{*/
/* This allocats the extension buffers and initializes them. */
bool pkgDepCache::Init(OpProgress * const Prog)
{
+ APT::PerformanceContext perf{"pkgDepCache::Init"};
// Suppress mark updates during this operation (just in case) and
// run a mark operation when Init terminates.
ActionGroup actions(*this);
diff --git a/apt-pkg/edsp.cc b/apt-pkg/edsp.cc
index 2d7fdcc3c..5a9808ff4 100644
--- a/apt-pkg/edsp.cc
+++ b/apt-pkg/edsp.cc
@@ -15,6 +15,7 @@
#include <apt-pkg/error.h>
#include <apt-pkg/fileutl.h>
#include <apt-pkg/packagemanager.h>
+#include <apt-pkg/perf.h>
#include <apt-pkg/pkgcache.h>
#include <apt-pkg/pkgsystem.h>
#include <apt-pkg/prettyprinters.h>
@@ -796,6 +797,7 @@ bool EDSP::ResolveExternal(const char* const solver, pkgDepCache &Cache,
unsigned int const flags, OpProgress *Progress) {
if (strstr(solver, "3.") == solver)
{
+ APT::PerformanceContext context{"APT::Solver"};
APT::Solver::DependencySolver s(Cache.GetCache(), Cache.GetPolicy(), (EDSP::Request::Flags)flags);
FileFd output;
bool res = true;
diff --git a/apt-pkg/pkgcache.h b/apt-pkg/pkgcache.h
index 042d928e1..27719b75b 100644
--- a/apt-pkg/pkgcache.h
+++ b/apt-pkg/pkgcache.h
@@ -98,21 +98,21 @@ typedef uint16_t map_fileid_t;
template <typename T> class map_pointer {
uint32_t val;
public:
- map_pointer() noexcept : val(0) {}
- map_pointer(std::nullptr_t) noexcept : val(0) {}
- explicit map_pointer(uint32_t n) noexcept : val(n) {}
- explicit operator uint32_t() noexcept { return val; }
- explicit operator bool() noexcept { return val != 0; }
+ constexpr map_pointer() noexcept : val(0) {}
+ constexpr map_pointer(std::nullptr_t) noexcept : val(0) {}
+ explicit constexpr map_pointer(uint32_t n) noexcept : val(n) {}
+ explicit constexpr operator uint32_t() const noexcept { return val; }
+ explicit constexpr operator bool() const noexcept { return val != 0; }
};
-template<typename T> inline T *operator +(T *p, map_pointer<T> m) { return p + uint32_t(m); }
-template<typename T> inline bool operator ==(map_pointer<T> u, map_pointer<T> m) { return uint32_t(u) == uint32_t(m); }
-template<typename T> inline bool operator !=(map_pointer<T> u, map_pointer<T> m) { return uint32_t(u) != uint32_t(m); }
-template<typename T> inline bool operator <(map_pointer<T> u, map_pointer<T> m) { return uint32_t(u) < uint32_t(m); }
-template<typename T> inline bool operator >(map_pointer<T> u, map_pointer<T> m) { return uint32_t(u) > uint32_t(m); }
-template<typename T> inline uint32_t operator -(map_pointer<T> u, map_pointer<T> m) { return uint32_t(u) - uint32_t(m); }
-template<typename T> bool operator ==(map_pointer<T> m, std::nullptr_t) { return uint32_t(m) == 0; }
-template<typename T> bool operator !=(map_pointer<T> m, std::nullptr_t) { return uint32_t(m) != 0; }
+template<typename T> constexpr T *operator +(T *p, map_pointer<T> m) noexcept { return p + uint32_t(m); }
+template<typename T> constexpr bool operator ==(map_pointer<T> u, map_pointer<T> m) noexcept{ return uint32_t(u) == uint32_t(m); }
+template<typename T> constexpr bool operator !=(map_pointer<T> u, map_pointer<T> m) noexcept{ return uint32_t(u) != uint32_t(m); }
+template<typename T> constexpr bool operator <(map_pointer<T> u, map_pointer<T> m) noexcept { return uint32_t(u) < uint32_t(m); }
+template<typename T> constexpr bool operator >(map_pointer<T> u, map_pointer<T> m) noexcept { return uint32_t(u) > uint32_t(m); }
+template<typename T> constexpr uint32_t operator -(map_pointer<T> u, map_pointer<T> m) noexcept { return uint32_t(u) - uint32_t(m); }
+template<typename T> constexpr bool operator ==(map_pointer<T> m, std::nullptr_t) noexcept { return uint32_t(m) == 0; }
+template<typename T> constexpr bool operator !=(map_pointer<T> m, std::nullptr_t) noexcept { return uint32_t(m) != 0; }
// same as the previous, but documented to be to a string item
typedef map_pointer<char> map_stringitem_t;
@@ -262,18 +262,18 @@ class APT_PUBLIC pkgCache /*{{{*/
return {name, len};
}
- Header &Head() {return *HeaderP;}
- inline GrpIterator GrpBegin();
- inline GrpIterator GrpEnd();
- inline PkgIterator PkgBegin();
- inline PkgIterator PkgEnd();
- inline PkgFileIterator FileBegin();
- inline PkgFileIterator FileEnd();
- inline RlsFileIterator RlsFileBegin();
- inline RlsFileIterator RlsFileEnd();
+ constexpr Header &Head() noexcept {return *HeaderP;}
+ inline GrpIterator GrpBegin() noexcept;
+ constexpr GrpIterator GrpEnd() noexcept;
+ inline PkgIterator PkgBegin() noexcept;
+ constexpr PkgIterator PkgEnd() noexcept;
+ inline PkgFileIterator FileBegin() noexcept;
+ constexpr PkgFileIterator FileEnd() noexcept;
+ inline RlsFileIterator RlsFileBegin() noexcept;
+ constexpr RlsFileIterator RlsFileEnd() noexcept;
- inline bool MultiArchCache() const { return MultiArchEnabled; }
- inline char const * NativeArch();
+ constexpr bool MultiArchCache() const noexcept { return MultiArchEnabled; }
+ constexpr char const * NativeArch() const noexcept;
// Make me a function
pkgVersioningSystem *VS;
@@ -822,29 +822,29 @@ struct pkgCache::Provides
};
/*}}}*/
-inline char const * pkgCache::NativeArch()
+constexpr char const * pkgCache::NativeArch() const noexcept
{ return StrP + HeaderP->Architecture; }
#include <apt-pkg/cacheiterators.h>
- inline pkgCache::GrpIterator pkgCache::GrpBegin()
+ inline pkgCache::GrpIterator pkgCache::GrpBegin() noexcept
{
return GrpIterator(*this);
}
- inline pkgCache::GrpIterator pkgCache::GrpEnd()
+ constexpr pkgCache::GrpIterator pkgCache::GrpEnd() noexcept
{
return GrpIterator(*this, GrpP);}
-inline pkgCache::PkgIterator pkgCache::PkgBegin()
+inline pkgCache::PkgIterator pkgCache::PkgBegin() noexcept
{return PkgIterator(*this);}
-inline pkgCache::PkgIterator pkgCache::PkgEnd()
+constexpr pkgCache::PkgIterator pkgCache::PkgEnd() noexcept
{return PkgIterator(*this,PkgP);}
-inline pkgCache::PkgFileIterator pkgCache::FileBegin()
+inline pkgCache::PkgFileIterator pkgCache::FileBegin() noexcept
{return PkgFileIterator(*this,PkgFileP + HeaderP->FileList);}
-inline pkgCache::PkgFileIterator pkgCache::FileEnd()
+constexpr pkgCache::PkgFileIterator pkgCache::FileEnd() noexcept
{return PkgFileIterator(*this,PkgFileP);}
-inline pkgCache::RlsFileIterator pkgCache::RlsFileBegin()
+inline pkgCache::RlsFileIterator pkgCache::RlsFileBegin() noexcept
{return RlsFileIterator(*this,RlsFileP + HeaderP->RlsFileList);}
-inline pkgCache::RlsFileIterator pkgCache::RlsFileEnd()
+constexpr pkgCache::RlsFileIterator pkgCache::RlsFileEnd() noexcept
{return RlsFileIterator(*this,RlsFileP);}
diff --git a/apt-pkg/solver3.cc b/apt-pkg/solver3.cc
index e4449339e..6d818ed67 100644
--- a/apt-pkg/solver3.cc
+++ b/apt-pkg/solver3.cc
@@ -18,8 +18,6 @@
* classic APT solver.
*/
-#define APT_COMPILING_APT
-
#include <config.h>
#include <apt-pkg/algorithms.h>
@@ -59,7 +57,7 @@ Solver::Solver(pkgCache &cache)
Solver::~Solver() = default;
// This function determines if a work item is less important than another.
-bool Solver::Work::operator<(Solver::Work const &b) const
+constexpr bool Solver::Work::operator<(Solver::Work const &b) const noexcept
{
if ((not clause->optional && size < 2) != (not b.clause->optional && b.size < 2))
return not b.clause->optional && b.size < 2;
@@ -87,7 +85,7 @@ std::string APT::Solver::Clause::toString(pkgCache &cache, bool pretty, bool sho
out.append(dep.TargetPkg().FullName(true));
if (dep.TargetVer())
out.append(" (").append(dep.CompType()).append(" ").append(dep.TargetVer()).append(")");
- if (!(dep->CompareOp & pkgCache::Dep::Or))
+ if (not(dep->CompareOp & pkgCache::Dep::Or))
break;
out.append(" | ");
}
@@ -130,7 +128,7 @@ std::string Solver::Work::toString(pkgCache &cache) const
return out.str();
}
-inline Var Solver::bestReason(Clause const *clause, Var var) const
+constexpr Var Solver::bestReason(Clause const *clause, Var var) const noexcept
{
if (not clause)
return Var{};
@@ -145,7 +143,7 @@ inline Var Solver::bestReason(Clause const *clause, Var var) const
return clause->reason;
}
-inline LiftedBool Solver::value(Lit lit) const
+constexpr LiftedBool Solver::value(Lit lit) const noexcept
{
return lit.sign() ? ~(*this)[lit.var()].assignment : (*this)[lit.var()].assignment;
}
@@ -376,7 +374,7 @@ bool Solver::Enqueue(Lit lit, const Clause *reason)
bool Solver::Propagate()
{
- while (!propQ.empty())
+ while (not propQ.empty())
{
Var var = propQ.front();
propQ.pop();
@@ -391,11 +389,8 @@ bool Solver::Propagate()
Discover(lit.var());
for (auto clause : watches(lit))
- {
- if (Propagate(clause, lit))
- continue;
- return false;
- }
+ if (not Propagate(clause, lit))
+ return false;
}
return true;
}
@@ -420,37 +415,31 @@ bool Solver::Propagate(const Clause *clause, Lit p)
}
// Check if the clause is unit, conflict, or undecided
- Lit unit;
- for (auto sol : clause->solutions)
+ auto not_false = [&](auto lit) noexcept { return value(lit) != LiftedBool::False; };
+ auto head = std::ranges::find_if(clause->solutions, not_false);
+ auto find_tail = [&]() noexcept { return std::ranges::find_last_if(clause->solutions, not_false); };
+ if (head == clause->solutions.end())
{
- if (value(sol) == LiftedBool::False)
- continue;
- if (not unit.empty() || clause->optional)
- {
- // We found a second solution, so we are undecided
- if (p == clause->reason)
- return AddWork(Work{clause, decisionLevel()});
- return true;
- }
-
- unit = sol;
+ // Conflict clause. If this clause is non-optional; reject its "reason".
+ if (not clause->optional)
+ return Enqueue(~clause->reason, clause);
}
-
- // The clause is now either unit or conflict
- if (not unit.empty())
+ else if (value(clause->reason) != LiftedBool::True)
{
- // Unit clause. If it is an active clause, enqueue the unit literal.
- if (value(clause->reason) == LiftedBool::True)
- return Enqueue(unit, clause);
- return true;
+ // Inactive clause, nothing to do
+ }
+ else if (not clause->optional && head == find_tail().begin())
+ {
+ // Unit clause. Enqueue the only possible solution
+ return Enqueue(*head, clause);
}
else
{
- // Conflict clause. If this clause is non-optional; reject it's "reason".
- if (not clause->optional)
- return Enqueue(~clause->reason, clause);
- return true;
+ // Undecided clause. If this is an activation, queue it for solving
+ if (p == clause->reason)
+ return AddWork(Work{clause, decisionLevel()});
}
+ return true;
}
void Solver::UndoOne()
@@ -596,20 +585,11 @@ bool Solver::Solve()
<< "(try it: " << candidate->toString(cache) << ")\n";
must_succeed(Assume(*candidate, item.clause));
}
- else if (item.clause->optional)
- {
- if (unlikely(debug >= 1))
- std::cerr << item.toString(cache) << "\n";
- }
else
{
- abort();
+ assert(item.clause->optional);
if (unlikely(debug >= 1))
std::cerr << item.toString(cache) << "\n";
- // Enqueue produces the right error message for us here, given that reason has been assigned true already...
- assert(value(item.clause->reason) == LiftedBool::True);
- must_succeed(not Enqueue(~item.clause->reason, item.clause));
- assert(value(item.clause->reason) == LiftedBool::True);
}
// Must push to trail after any Assume() above.
trail.push_back(Trail{Var(), item});
@@ -791,7 +771,11 @@ DependencySolver::DependencySolver(pkgCache &cache, pkgDepCache::Policy &policy,
DependencySolver::~DependencySolver() = default;
-static bool SameOrGroup(pkgCache::DepIterator a, pkgCache::DepIterator b)
+// This is called in the hot path of Discover() as we are trying to determine if a dependency
+// is the same in all packages.
+// Marking it constexpr causes it to be inlined, which significantly improves solver performance,
+// around 5%; but it produces more LL cache misses.
+constexpr bool SameOrGroup(pkgCache::DepIterator a, pkgCache::DepIterator b) noexcept
{
while (1)
{
@@ -831,14 +815,14 @@ const Clause *DependencySolver::RegisterClause(Clause &&clause)
earlierDep.end() || (earlierDep->CompareOp & pkgCache::Dep::Or) ||
earlierDep.TargetPkg() != dep.TargetPkg())
continue;
- if (std::none_of(earlierClause->solutions.begin(), earlierClause->solutions.end(), [&clause](auto earlierSol)
+ if (std::none_of(earlierClause->solutions.begin(), earlierClause->solutions.end(), [&clause](auto earlierSol) noexcept
{ return std::ranges::contains(clause.solutions,
earlierSol); }))
continue;
if (earlierClause->optional == clause.optional)
{
- std::erase_if(earlierClause->solutions, [&clause, this](auto earlierSol)
+ std::erase_if(earlierClause->solutions, [&clause, this](auto earlierSol) noexcept
{ return not std::ranges::contains(clause.solutions,
earlierSol); });
@@ -848,7 +832,7 @@ const Clause *DependencySolver::RegisterClause(Clause &&clause)
else if (clause.optional)
{
// If say a Depends has fewer solution than a Recommends, remove the Recommend's extranous ones.
- std::erase_if(clause.solutions, [&earlierClause, this](auto sol)
+ std::erase_if(clause.solutions, [&earlierClause, this](auto sol) noexcept
{ return not std::ranges::contains(earlierClause->solutions,
sol); });
@@ -1023,7 +1007,7 @@ void DependencySolver::RegisterCommonDependencies(pkgCache::PkgIterator Pkg)
dep.GlobOr(start, end); // advances dep
bool allHaveDep = true;
- for (auto ver = Pkg.VersionList()++; allHaveDep && not ver.end(); ver++)
+ for (auto ver = ++Pkg.VersionList(); allHaveDep && not ver.end(); ver++)
{
bool haveDep = false;
for (auto otherDep = ver.DependsList(); not haveDep && not otherDep.end();)
@@ -1068,9 +1052,9 @@ Clause DependencySolver::TranslateOrGroup(pkgCache::DepIterator start, pkgCache:
}
else
{
- auto all = start.AllTargets();
+ std::unique_ptr<pkgCache::Version *[]> all(start.AllTargets());
- for (auto tgt = all; *tgt; ++tgt)
+ for (auto tgt = all.get(); *tgt; ++tgt)
{
pkgCache::VerIterator tgti(cache, *tgt);
@@ -1078,7 +1062,6 @@ Clause DependencySolver::TranslateOrGroup(pkgCache::DepIterator start, pkgCache:
std::cerr << "Adding work to item " << reason.toString(cache) << " -> " << tgti.ParentPkg().FullName() << "=" << tgti.VerStr() << (clause.negative ? " (negative)" : "") << "\n";
clause.solutions.push_back(Var(pkgCache::VerIterator(cache, *tgt)));
}
- delete[] all;
std::stable_sort(clause.solutions.begin() + begin, clause.solutions.end(), CompareProviders3{cache, policy, start.TargetPkg(), *this});
}
if (start == end)
diff --git a/apt-pkg/solver3.h b/apt-pkg/solver3.h
index af1d749eb..380aa3ad6 100644
--- a/apt-pkg/solver3.h
+++ b/apt-pkg/solver3.h
@@ -56,8 +56,8 @@ class ContiguousCacheMap
data_ = new V[size]{};
}
- V &operator[](const K *key) { return data_[key->ID]; }
- const V &operator[](const K *key) const { return data_[key->ID]; }
+ constexpr V &operator[](const K *key) noexcept { return data_[key->ID]; }
+ constexpr const V &operator[](const K *key) const noexcept { return data_[key->ID]; }
~ContiguousCacheMap() { delete[] data_; }
// Delete copy constructors for memory safety (rule of 3)
@@ -136,45 +136,45 @@ struct Var
{
uint32_t value;
- explicit constexpr Var(uint32_t value = 0) : value{value} {}
- explicit Var(pkgCache::PkgIterator const &Pkg) : value(uint32_t(Pkg.MapPointer()) << 1) {}
- explicit Var(pkgCache::VerIterator const &Ver) : value(uint32_t(Ver.MapPointer()) << 1 | 1) {}
+ explicit constexpr Var(uint32_t value = 0) noexcept : value{value} {}
+ explicit Var(pkgCache::PkgIterator const &Pkg) noexcept : value(uint32_t(Pkg.MapPointer()) << 1) {}
+ explicit Var(pkgCache::VerIterator const &Ver) noexcept : value(uint32_t(Ver.MapPointer()) << 1 | 1) {}
- inline constexpr bool isVersion() const { return value & 1; }
- inline constexpr uint32_t mapPtr() const { return value >> 1; }
+ constexpr bool isVersion() const noexcept { return value & 1; }
+ constexpr uint32_t mapPtr() const noexcept { return value >> 1; }
// \brief Return the package, if any, otherwise 0.
- map_pointer<pkgCache::Package> Pkg() const
+ constexpr map_pointer<pkgCache::Package> Pkg() const noexcept
{
return isVersion() ? 0 : map_pointer<pkgCache::Package>{mapPtr()};
}
// \brief Return the version, if any, otherwise 0.
- map_pointer<pkgCache::Version> Ver() const
+ constexpr map_pointer<pkgCache::Version> Ver() const noexcept
{
return isVersion() ? map_pointer<pkgCache::Version>{mapPtr()} : 0;
}
// \brief Return the package iterator if storing a package, or an empty one
- pkgCache::PkgIterator Pkg(pkgCache &cache) const
+ constexpr pkgCache::PkgIterator Pkg(pkgCache &cache) const noexcept
{
return isVersion() ? pkgCache::PkgIterator() : pkgCache::PkgIterator(cache, cache.PkgP + Pkg());
}
// \brief Return the version iterator if storing a package, or an empty end.
- pkgCache::VerIterator Ver(pkgCache &cache) const
+ constexpr pkgCache::VerIterator Ver(pkgCache &cache) const noexcept
{
return isVersion() ? pkgCache::VerIterator(cache, cache.VerP + Ver()) : pkgCache::VerIterator();
}
// \brief Return a package, cast from version if needed
- pkgCache::PkgIterator CastPkg(pkgCache &cache) const
+ constexpr pkgCache::PkgIterator CastPkg(pkgCache &cache) const noexcept
{
return isVersion() ? Ver(cache).ParentPkg() : Pkg(cache);
}
// \brief Check if there is no reason.
- constexpr bool empty() const { return value == 0; }
+ constexpr bool empty() const noexcept { return value == 0; }
constexpr bool operator!=(Var const other) const noexcept { return value != other.value; }
constexpr bool operator==(Var const other) const noexcept { return value == other.value; }
/// \brief Negate
- constexpr Lit operator~() const;
+ constexpr Lit operator~() const noexcept;
std::string toString(pkgCache &cache) const
{
@@ -196,21 +196,21 @@ struct Lit
private:
friend struct std::hash<Lit>;
// Private constructor from a number, to be used with operator~
- explicit constexpr Lit(int32_t value) : value{value} {}
+ explicit constexpr Lit(int32_t value) noexcept : value{value} {}
int32_t value;
public:
- constexpr Lit() : value{0} {}
+ constexpr Lit() noexcept : value{0} {}
// SAFETY: value must be 31 bit, one bit is needed for the sign.
- constexpr Lit(Var var) : value{static_cast<int32_t>(var.value)} {}
+ constexpr Lit(Var var) noexcept : value{static_cast<int32_t>(var.value)} {}
// Accessors
- constexpr Var var() const { return Var(std::abs(value)); }
- constexpr bool sign() const { return value < 0; }
- constexpr Lit operator~() const { return Lit(-value); }
+ constexpr Var var() const noexcept { return Var(std::abs(value)); }
+ constexpr bool sign() const noexcept { return value < 0; }
+ constexpr Lit operator~() const noexcept { return Lit(-value); }
// Properties
- constexpr bool empty() const { return value == 0; }
+ constexpr bool empty() const noexcept { return value == 0; }
constexpr bool operator!=(Lit const other) const noexcept { return value != other.value; }
constexpr bool operator==(Lit const other) const noexcept { return value == other.value; }
@@ -250,12 +250,12 @@ struct Clause
std::string toString(pkgCache &cache, bool pretty = false, bool showMerged = true) const;
};
-constexpr Lit Solver::Var::operator~() const
+constexpr Lit Solver::Var::operator~() const noexcept
{
return ~Lit(*this);
}
-inline LiftedBool operator~(LiftedBool value)
+constexpr LiftedBool operator~(LiftedBool value) noexcept
{
switch (value)
{
@@ -307,29 +307,29 @@ class Solver
ContiguousCacheMap<pkgCache::Version, State> verStates;
// \brief Helper function for safe access to package state.
- inline State &operator[](const pkgCache::Package *P)
+ constexpr State &operator[](const pkgCache::Package *P) noexcept
{
return pkgStates[P];
}
- inline const State &operator[](const pkgCache::Package *P) const
+ constexpr const State &operator[](const pkgCache::Package *P) const noexcept
{
return pkgStates[P];
}
// \brief Helper function for safe access to version state.
- inline State &operator[](const pkgCache::Version *V)
+ constexpr State &operator[](const pkgCache::Version *V) noexcept
{
return verStates[V];
}
- inline const State &operator[](const pkgCache::Version *V) const
+ constexpr const State &operator[](const pkgCache::Version *V) const noexcept
{
return verStates[V];
}
// \brief Helper function for safe access to either state.
- inline State &operator[](Var r);
- inline const State &operator[](Var r) const;
+ constexpr State &operator[](Var r) noexcept;
+ constexpr const State &operator[](Var r) const noexcept;
- inline std::vector<const Clause *> &watches(Lit lit);
+ constexpr std::vector<const Clause *> &watches(Lit lit) noexcept;
// \brief Heap of the remaining work.
//
@@ -375,8 +375,8 @@ class Solver
{
return static_cast<level_type>(trailLim.size());
}
- inline Var bestReason(Clause const *clause, Var var) const;
- inline LiftedBool value(Lit lit) const;
+ constexpr Var bestReason(Clause const *clause, Var var) const noexcept;
+ constexpr LiftedBool value(Lit lit) const noexcept;
public:
// \brief Revert to the previous decision level.
@@ -425,7 +425,7 @@ class Solver
* It is a brute force solver with heuristics, conflicts learning, and 2**32 levels
* of backtracking.
*/
-class DependencySolver : public Solver
+class DependencySolver final : public Solver
{
friend class CompareProviders3;
@@ -461,12 +461,12 @@ class DependencySolver : public Solver
}
// GetCandidateVer() with caching
- mutable ContiguousCacheMap<pkgCache::Package, pkgCache::VerIterator> candidates;
+ mutable FastContiguousCacheMap<pkgCache::Package, pkgCache::Version *> candidates;
pkgCache::VerIterator GetCandidateVer(pkgCache::PkgIterator pkg) const
{
- if (candidates[pkg].end())
+ if (candidates[pkg] == 0)
candidates[pkg] = policy.GetCandidateVer(pkg);
- return candidates[pkg];
+ return pkgCache::VerIterator(cache, candidates[pkg]);
}
// \brief Discover variables
@@ -514,9 +514,9 @@ struct APT::Solver::Solver::Work
/// Number of valid choices at insertion time
size_t size{0};
- bool operator<(APT::Solver::Solver::Work const &b) const;
+ constexpr bool operator<(APT::Solver::Solver::Work const &b) const noexcept;
std::string toString(pkgCache &cache) const;
- inline Work(const Clause *clause, level_type level) : clause(clause), level(level) {}
+ constexpr Work(const Clause *clause, level_type level) noexcept : clause(clause), level(level) {}
};
/**
@@ -582,7 +582,7 @@ struct APT::Solver::Solver::Trail
std::optional<Work> work;
};
-inline APT::Solver::Solver::State &APT::Solver::Solver::operator[](APT::Solver::Var r)
+constexpr APT::Solver::Solver::State &APT::Solver::Solver::operator[](APT::Solver::Var r) noexcept
{
if (auto P = r.Pkg())
return (*this)[cache.PkgP + P];
@@ -591,7 +591,7 @@ inline APT::Solver::Solver::State &APT::Solver::Solver::operator[](APT::Solver::
return *rootState.get();
}
-inline const APT::Solver::Solver::State &APT::Solver::Solver::operator[](APT::Solver::Var r) const
+constexpr const APT::Solver::Solver::State &APT::Solver::Solver::operator[](APT::Solver::Var r) const noexcept
{
return const_cast<Solver &>(*this)[r];
}
@@ -612,7 +612,7 @@ struct std::hash<APT::Solver::Lit>
std::size_t operator()(const APT::Solver::Lit &v) const noexcept { return hash_value(v.value); }
};
-inline std::vector<const APT::Solver::Clause *> &APT::Solver::Solver::watches(Lit lit)
+constexpr std::vector<const APT::Solver::Clause *> &APT::Solver::Solver::watches(Lit lit) noexcept
{
return (*this)[lit.var()].watches[lit.sign()];
}