Skip to content

A utility to delete the contents of the pacman's and pikaur's cache directories and leave in mentioned directories only package files that the locally installed packages were installed from.

License

Notifications You must be signed in to change notification settings

kyberdrb/clean_pacman_cache_dir

Repository files navigation

Clear Package Manager's Cache Directories

a.k.a CPMCD - Clean Package Manager's Cache Directories

A utility to delete the contents of the package managers cache directories and leave in mentioned directory only package files, that the locally installed packages were installed from, in order to free up disk space and still make a backup of installation package file available in case of application's or system's undesired behavior.

Currently supported pacmange managers are pacman and pikaur.

The packages that are listed next to IgnorePkg option in the pacman's configuration file - by default at /etc/pacman.conf are excluded from deletion. Package files that belong to the ignored packages and deviate from the locally installed version of installed packages are excluded from automatic deletion and need to be deleted manually if needed.

Maybe it could be useful to make a backup before you run this utility. It may save you precious time when something goes wrong. I tested it on my machine. I don't know yours. Proceed with caution.

Quick Start Guide

  1. Clone the repository

     mkdir "${HOME}/git"
     cd "${HOME}/git"
     git clone https://github.com/kyberdrb/clean_pacman_cache_dir.git
     cd clean_pacman_cache_dir
    
  2. Install dependencies

     sudo pacman --sync --refresh --refresh --needed cmake ninja
    
  3. Build the program:

    To build the release version of the binary executable from this project, run the build script in the root directory of the repository:

     ./build-release.sh
    

    The script will show the path to the executable after it finished building the executable.

  4. [OPTIONAL - RECOMMENDED]
    Check the contents of the pacman's cache directory

     ./helper_scripts/check_free_space_and_content_of_directories_for_package_managers.sh > "/tmp/before.log"
     
     less "/tmp/before.log"
    
  5. Copy the path to the executable given by the build script, paste it again to the terminal and make a dry run first, only to see the list of packages and package files for different package versions, run the program without sudo as a regular user:

     time ./cmake-build-release/clean_pacman_cache_dir
    

    Then run it with elevated priviledges

     time sudo ./cmake-build-release/clean_pacman_cache_dir
    

    or just

     sudo ./cmake-build-release/clean_pacman_cache_dir
    
  6. [OPTIONAL - RECOMMENDED]
    Check the log file printed as the last line of the output in the terminal (usually the last one listed):

     ls -1 "${HOME}/.config/cpmcd/logs/"
    
     less "${HOME}/.config/cpmcd/logs/YEAR_MONTH_DAY-HOUR_MINUTE_SECOND.log"
    
  7. [OPTIONAL - RECOMMENDED]
    Check the content of directories.

    In /var/cache/pacman/pkg/ and other package manager's directories will be only installation package files related only to locally installed version for every package.

    In /var/cache/pacman/pkg/PACKAGE_FILES_FOR_VERSIONS_OTHER_THAN_LOCALLY_INSTALLED will be package files for other versions, build directories and general package manager's safely deletable files

     ./helper_scripts/check_free_space_and_content_of_directories_for_package_managers.sh > "/tmp/after_move.log"
     
     less "/tmp/after_move.log"
    
  8. Delete the directory with collected package files

    • with delayed destruction - throwing deletion candidate files to trash - less trust, more caution, slower, more complicated - possibility to restore packages if needed and delete the rest later

      $ ls -d "/var/cache/pacman/pkg/PACKAGE_FILES_FOR_VERSIONS_OTHER_THAN_LOCALLY_INSTALLED"
      $ sudo chown --recursive "/var/cache/pacman/pkg/PACKAGE_FILES_FOR_VERSIONS_OTHER_THAN_LOCALLY_INSTALLED" --reference "${HOME}"
      $ ls -d "/var/cache/pacman/pkg/PACKAGE_FILES_FOR_VERSIONS_OTHER_THAN_LOCALLY_INSTALLED"
      $ sudo mv "/var/cache/pacman/pkg/PACKAGE_FILES_FOR_VERSIONS_OTHER_THAN_LOCALLY_INSTALLED" "${HOME}/Downloads/"
      $ ls -d "/var/cache/pacman/pkg/PACKAGE_FILES_FOR_VERSIONS_OTHER_THAN_LOCALLY_INSTALLED"
      $ ls -d "${HOME}/Downloads/PACKAGE_FILES_FOR_VERSIONS_OTHER_THAN_LOCALLY_INSTALLED"
      $ du -sh "${HOME}/Downloads/PACKAGE_FILES_FOR_VERSIONS_OTHER_THAN_LOCALLY_INSTALLED"
      $ gio trash "${HOME}/Downloads/PACKAGE_FILES_FOR_VERSIONS_OTHER_THAN_LOCALLY_INSTALLED"
      

      Then empty trash to free up disk space.

    • with immediate destruction - deleting entire directory with deletion candidate files related to packages - more trust, less caution, faster, simpler

      $ sudo rm --recursive --force /var/cache/pacman/pkg/PACKAGE_FILES_FOR_VERSIONS_OTHER_THAN_LOCALLY_INSTALLED/
      

      The disk space will be freed immediately.

  9. Verify the contents of the pacman's cache directory, which will now contain only files for locally installed packages, together with amount of free space on the partition

     ./helper_scripts/check_free_space_and_content_of_directories_for_package_managers.sh > "/tmp/after_removal.log"
     
     less "/tmp/after_removal.log"
    

Contributing

See CONTRIBUTING and CODE_OF_CONDUCT documents.

Sources

Result

PACKAGE FILENAME                                                              PACKAGE NAME                              DOWNLOADED PACKAGE VERSION   INSTALLED PACKAGE VERSION   ARE VERSIONS MATCHING?   KEEP THE PACKAGE?

accounts-qml-module-0.7-4-x86_64.pkg.tar.zst                                  accounts-qml-module                       0.7-4                        0.7-4                       YES                      YES
accountsservice-0.6.55-3-x86_64.pkg.tar.zst                                   accountsservice                           0.6.55-3                     22.08.8-1                   NO                       NO
accountsservice-22.04.62-2-x86_64.pkg.tar.zst                                 accountsservice                           22.04.62-2                   22.08.8-1                   NO                       NO
accountsservice-22.04.62-2-x86_64.pkg.tar.zst.sig                                                                                                                                                         NO
accountsservice-22.08.8-1-x86_64.pkg.tar.zst                                  accountsservice                           22.08.8-1                    22.08.8-1                   YES                      YES
accountsservice-22.08.8-1-x86_64.pkg.tar.zst.sig                                                                                                                                                          YES
acl-2.3.0-1-x86_64.pkg.tar.zst
acl-2.3.1-1-x86_64.pkg.tar.zst
acl-2.3.1-2-x86_64.pkg.tar.zst
acl-2.3.1-2-x86_64.pkg.tar.zst.sig
adobe-source-code-pro-fonts-2.038ro+1.058it+1.018var-1-any.pkg.tar.zst
adobe-source-han-sans-otc-fonts-2.004-1-any.pkg.tar.zst
adobe-source-han-sans-otc-fonts-2.004-1-any.pkg.tar.zst.sig
adobe-source-han-serif-otc-fonts-2.001-1-any.pkg.tar.zst
adobe-source-han-serif-otc-fonts-2.001-1-any.pkg.tar.zst.sig
adwaita-icon-theme-40.0-1-any.pkg.tar.zst
adwaita-icon-theme-40.1.1-1-any.pkg.tar.zst
adwaita-icon-theme-40rc-1-any.pkg.tar.zst
adwaita-icon-theme-41.0-1-any.pkg.tar.zst
adwaita-icon-theme-41.0-1-any.pkg.tar.zst.sig

Internal structural representation - a coarse draft

Iterate all localy installed packages from the local DB and save each entry into a hashmap installedPackages in an instance of class InstalledPackages

class PackagesAndTheirFiles

installedPackages
|-key: "accounts-qml-module"             ('std::string'/class 'PackageName'/std::unique_ptr<PackageName>)
  |-value:                                 (std::unique_ptr<Package>)
    |-locallyInstalledVersion: 0.7-4         (std::string/Version/std::unique_ptr<Version>)
    |-architecture: x86_64                   (std::string/Architecture/std:unique_ptr<Architecture>)
    |-packageVersionsWithTheirRelatedDownloadedFiles (std::map<???, std::vector<???>>)
      |-key: 0.7-4                                (std::string/std::unique_ptr<Version>)
        |-accounts-qml-module-0.7-4-x86_64.pkg.tar.zst (std::vector<std::string/std::unique_ptr<PackageRelatedDownloadedFile>>
|-key: "accountsservice"                 (std::unique_ptr<PackageName>)
  |-value:                                 (std::unique_ptr<Package>)
    |-locallyInstalledVersion: 22.08.8-1     (std::unique_ptr<Version>)
    |-architecture: x86_64                   (std:unique_ptr<Architecture>)
    |-packageVersionsWithTheirRelatedDownloadedFiles (std::map<std::unique_ptr<Version> std::vector<std::unique_ptr<PackageRelatedDownloadedFile>>>)
      |-key: 0.6.55-3                             (std::unique_ptr<Version>)
      | |-value:                                    (std::vector<std::unique_ptr<PackageRelatedDownloadedFile>>)
      |   |-accountsservice-0.6.55-3-x86_64.pkg.tar.zst (std::unique_ptr<PackageRelatedDownloadedFile>)
      |
      |-key: 22.04.62-2                                (std::unique_ptr<Version>)
      | |-value:                                    (std::vector<std::unique_ptr<PackageRelatedDownloadedFile>>)
      |   |-accountsservice-22.04.62-2-x86_64.pkg.tar.zst (std::unique_ptr<PackageRelatedDownloadedFile>)
      |   |-accountsservice-22.04.62-2-x86_64.pkg.tar.zst.sig (std::unique_ptr<PackageRelatedDownloadedFile>)
      |
      |-key: 22.08.8-1                                 (std::unique_ptr<Version>)
      | |-value:                                    (std::vector<std::unique_ptr<PackageRelatedDownloadedFile>>)
      |   |-accountsservice-22.08.8-1-x86_64.pkg.tar.zst (std::unique_ptr<PackageRelatedDownloadedFile>)
      |   |-accountsservice-22.08.8-1-x86_64.pkg.tar.zst.sig (std::unique_ptr<PackageRelatedDownloadedFile>)
|-key: "acl"
  |-value:
    |-...
  • class PackageName will use overloaded less-than-operator i.e. operator<, because the class is only used as a key in a installedPackages map, in order to indicate that the class is used as a key
  • class Version will use custom comparator functor class VersionComparator, because its used as a key in a map packageVersionsWithTheirRelatedDownloadedFiles and as a field in the PackagesAndTheirFiles to indicate variability of usage of the class
    • I'll use operator< from standard string, because the alpm_pkg_vercmp function from alpm.h ignores package release versions, and I want to do a complete comparison of Versions
  • ignoredPackageNamesInTextFormat - keep package files that are listed next to IgnorePkg option in the pacman's configuration file

Algorithms

Algorithm 1 - Composite

  • Is it true that after each word of package filename in its filename comes a delimiter (likely a dash '-') followed by a number? So I can iterate the package filename until I hit a number and then go back two characters (or remove/pop_back last two characters) and get the package filename? Which will then serve me as a key to the map and the actual filename as the value?
  • Not every installed package has its downloaded package that it was installed from but every downloaded package has its installed package.
  1. iterate through all locally installed packages with libalpm library (1195 entries)

    1. create an instance of package with its locallyInstalledVersion

      // inside the iteration loop
      std::string locallyInstalledVersion = alpm_pkg_get_version(pkg);
      auto package = std::make_unique<Package>(locallyInstalledVersion);
      
    2. save each package to the packages with the filename of the package being a text key and the package instance being the value (map?)

      // structure declaration - before the iteration loop
      std::map<
          std::string              // package filename
          std::unique_ptr<Package> // package instance
      > packages;
      
      ...
      
      // inside the iteration loop
      packages.emplace_back(alpm_pkg_get_name(pkg), std::move(package));
      
  2. iterate through all files of the pacman's cache directory with the std::filesystem library (7284/7293 files)

    1. save the filename of the file to a variable filename

    2. save the extension of the file to a variable extension

    3. if the extension equals to ".part"

      1. add the filename to the set of packageFilesDesignatedForDeletion

        // structure declaration - before the iteration loop
        std::set<
            std::string              // package filename
        > packageFilesDesignatedForDeletion;
        
        ...
        
        // inside the iteration loop
        packageFilesDesignatedForDeletion.emplace(filename);
        
      2. continue

    4. Build the regular expression pattern with the help of the Architecture class that accumulated all available versions from the previous loop.

    5. shorten the filename only to package filename and version by removing the trailing text with a regular expression, and save the result into a variable packageNameAndVersion

    6. separate the package filename and version by tokenizing the packageNameAndVersion by dash - delimiter into tokens vector through token string

    7. initialize a text variables packageName and packageVersion to empty text

    8. iterate tokens

       For each token
           if the first character of the token is not a number
               append the token to the packageName
               continue
           append the token to the packageVersion
      
    9. remove the dash - at the end of packageName and packageVersion

    10. Use the packageName to find the matching key in the installedPackages collection When the key is found (and thus the package is locally installed on the system), add a new entry to packageVersionsWithTheirRelatedDownloadedFiles using the downloadedPackageVersion a key

    11. When the key is missing (nullptr) (and thus the package had been uninstalled from the system), add the filename to the collection packageFilesDesignatedForDeletion

  3. Iterate all entries in packageFilesDesignatedForDeletion

    1. Move all entries into a separate directory PACKAGE_CEMETERY inside the pacman's cache directory
  4. Iterate all entries in installedPackages

    1. For each installedPackage
      1. if the package is in the list of IgnoredPkgs in the pacman's configuration file - likely in /etc/pacman.conf (parse or read with libalpm?)
        1. continue (skip the deletion of the package - the packages are ignored for good reasons - either they have a strong systemic effect on the system and may cause malfunction of the system, or they are licensed with other than open-source license which may after update stop functioning)
      2. call moveAllPackageFilesInNonlocalVersionToSeparateDirectory, where the destination directory will be provided as a parameter?/as an attribute in the class PackagesAndTheirFiles?
  5. Run the algorithm again to check whether each installed package has exactly one package file that matches the local version of the installed package, and with an optional signature file.

Algorithm 2 - Tokenization

The version of the algorithm with a tokenization

1. find all non-alphanumeric characters and save them into `dividers` - a data structure that will hold only one unique copy `(set`?)
2. tokenize the filename by all characters in `dividers`, i.e. iterate the filename text by characters one-by-one and
   1. save the tokens , i.e. alphanumeric words, and the character they are divided with, into a resizable array (`vector`?) - because number of tokens for each file may be different. For example
3. initialize a text variable `cumulativePackageName` to empty text
4. iterate the resizable array of tokens
   1. append current token to the `cumulativePackageName`
   2. check if the `packages` contains and entry that is exactly matching the key stored in `cumulativePackageName`
      1. if yes, add current file to the collection of files for matching `package`

Algorithm 3 - Compound Substring Key Find with Partial Match

  1. Add each filename of every file in pacman's cache directory into a map<ExtendedInstallationPackageFile, PackageWithPartialFilename>, with ExtendedInstallationPackageFile being the filename of the file (without absolute path - only the filename), and PackageWithPartialFilename being empty/null
  2. Find all locally installed packages, form a partial filename as prefix by compounding the filename, version and architecture of the package in the format "PACKAGE_NAME-PACKAGE_VERSION-PACKAGE_ARCHITECTURE", and searching for all keys with such prefix in ExtendedInstallationPackageFile. For all found keys assign for the value of PackageWithPartialFilename the compound package filename.
    • When no package file was found a given package, report it?/download it only to the pacmans cache dir? (with alpm? or from archive.archlinux.com by building the URL and webscraping all links that partially match with the compound package filename and downloading all files from the links with curl and adding the package filenames manually to the map so that the package files for the locally installed package will be preserved?)
  3. Go through each package filename in the map and move to a separate directory FORMER_PACKAGE_VERSIONS such package files that have their values of PackageWithPartialFilename empty/null.
  • lookup and handle packages within pikaur cache directory /var/cache/pikaur which likely references to /var/cache/private/pikaur (only accessible with superuser/sudo/root) priviledges

Notes

  • '2.0.1' is the last working version - but without the fix for printing partially downloaded files

  • regex for main.cpp to search for variables to encapsulate in classes: [std::|\.]find

    • for 'Package' class at line with

      auto matchingPackage = installedPackages.find(packageWithInferredName);
      
      • try out all possible combinations how to search in a std::set of unique pointers:
        • std::find (with overloaded equality operator - direct and dereferenced unique pointer comparison)
        • std::find_if (with comparator in separate struct as predicate; with lambda as predicate - direct and dereferenced unique pointer comparison)
        • std::any_of (with comparator in separate struct as predicate; with lambda as predicate - direct and dereferenced unique pointer comparison)
    • for line 153 (on upstream branch main): integrate the 'PackageName' class to the 'Package' class by composition (maybe)

Ways of finding an element of custom type in a std::vector

  • when comparing two unique pointers without dereferencing, i. e. comparing unique pointers directly without '*' or '->', only the public equality operator friend function is used

  • seems like the public member equality operator (or any operator defined as a member function) is used only when the unique pointer objects (or any other pointer to object) are dereferenced on the both sides of the comparison

  • looks like defining any operator as a public friend (i. e. non-member) function with const parameters is the most compatible option: trading of compatibility and stable functionality in multiple context on the one hand with encapsulation on the other.

  • std::find

    • public friend function - all params const (the only one that worked for me for smart pointers)
    • TODO overloading global std::operator==
  • std::find_if

    • direct comparison in main
      • lambda
        • public friend function - all params const (the only one that works)
      • comparator
        • direct comparison in comparator
          • public friend function - all params const
    • dereferenced comparison
      • lambda
        • public friend function - all params non-const
        • public friend function - all params const
        • public member const function - const parameter
        • public member non-const function - const parameter
        • public member const function - non-const parameter
        • public member non-const function - non-const param
      • comparator
        • dereferenced comparison in comparator
          • public friend function - all params non-const
          • public friend function - all params const
          • public member const function - const parameter
          • public member non-const function - const parameter
          • public member const function - non-const parameter
          • public member non-const function - non-const param
  • std::any_of

    • direct comparison in main
      • lambda
        • public friend function - all params const (the only one that works)
      • comparator
        • direct comparison in comparator
    • dereferenced comparison
      • lambda
        • public friend function - all params non-const
        • public friend function - all params const
        • public member const function - const parameter
        • public member non-const function - const parameter
        • public member const function - non-const parameter
        • public member non-const function - non-const param
      • comparator
        • dereferenced comparison in comparator
          • public friend function - all params non-const
          • public friend function - all params const
          • public member const function - const parameter
          • public member non-const function - const parameter
          • public member const function - non-const parameter
          • public member non-const function - non-const param
  • TODO std::binary_search

    • TODO friend operator<
    • TODO member operator<
    • TODO std::operator<
    • TODO std::less - for ascending lexicographic order
    • TODO std::greater - for descending lexicographic order
    • TODO custom comparator

Example code

IgnoredPackageName.h

// FOR DIRECT COMPARISON OF SMART POINTERS

    // Fails to find an element in a vector of unique pointers, because the parameters are not constant
    //  because the third parameter in 'std::find' takes a reference to a constant type 'const _Tp& __val'
    //  and in this function are defined parameters as references to the type of element the vector holds
    //  not as reference to the constant element type that the vector holds,
    //  therefore the types for parameters for the equality operator in the class
    //  and the type of the third parameter in the 'std::find'
    //  need to match in their constant modifiers in order to accurately find an element in the vector,
    //  even though the type of elements the vector holds are NOT constant
//    friend bool operator==(std::unique_ptr<IgnoredPackageName>& oneIgnoredPackageName, std::unique_ptr<IgnoredPackageName>& anotherIgnoredPackageName) {
//        return oneIgnoredPackageName->name == anotherIgnoredPackageName->name;
//    }

    // Fails to find an element in a vector of unique pointers, because the 'std::find' needs to have access to the
    //  internal structure for the type of elements it compares
    //  therefore the equality operator needs to be declared as public 'friend' i.e. nonmember function
    //  even though it is defined in the namespace of this class
//    bool operator==(const std::unique_ptr<IgnoredPackageName>& otherIgnoredPackageName) const {
//        return this->name == otherIgnoredPackageName->name;
//    }

    // Successfully finds an element in a vector of unique pointers because
    //  1. the 'std::find' function has access to the internal structure of the elements that it compares
    //     for equality with the equality operator 'operator=='
    //  2. and the types for parameters for the equality operator in the class
    //     and the type of the third parameter in the 'std::find'
    //     are matching in their constant modifiers for the type of elements the vector holds
    friend bool operator==(const std::unique_ptr<IgnoredPackageName>& oneIgnoredPackageName, const std::unique_ptr<IgnoredPackageName>& anotherIgnoredPackageName) {
        return oneIgnoredPackageName->name == anotherIgnoredPackageName->name;
    }

// FOR COMPARISON OF DEREFERENCED (SMART) POINTERS (I. E. COMPARING OBJECTS not pointers to objects nor pointers to pointers)

    // Successfully finds an element in a vector of unique pointers for dereferenced unique_ptrs
//    friend bool operator==(IgnoredPackageName& oneIgnoredPackageName, IgnoredPackageName& anotherIgnoredPackageName) {
//        return oneIgnoredPackageName.name == anotherIgnoredPackageName.name;
//    }

    // Successfully finds an element in a vector of unique pointers for dereferenced unique_ptrs
//    friend bool operator==(const IgnoredPackageName& oneIgnoredPackageName, const IgnoredPackageName& anotherIgnoredPackageName) {
//        return oneIgnoredPackageName.name == anotherIgnoredPackageName.name;
//    }

    // Successfully finds an element in a vector of unique pointers for dereferenced unique_ptrs
//    bool operator==(const IgnoredPackageName& otherIgnoredPackageName) const {
//        return this->name == otherIgnoredPackageName.name;
//    }

    // Successfully finds an element in a vector of unique pointers for dereferenced unique_ptrs
//    bool operator==(IgnoredPackageName& otherIgnoredPackageName) const {
//        return this->name == otherIgnoredPackageName.name;
//    }

    // Successfully finds an element in a vector of unique pointers for dereferenced unique_ptrs
//    bool operator==(const IgnoredPackageName& otherIgnoredPackageName) {
//        return this->name == otherIgnoredPackageName.name;
//    }

    // Successfully finds an element in a vector of unique pointers for dereferenced unique_ptrs
//    bool operator==(IgnoredPackageName& otherIgnoredPackageName) {
//        return this->name == otherIgnoredPackageName.name;
//    }
main.cpp

// FOR LAMBDA PREDICATE

        auto ignoredPackageNameCandidate = std::make_unique<IgnoredPackageName>(std::move(packageNameCopy));
        bool isPackageNameIgnored =
                std::find_if(
                        ignoredPackageNames.begin(),
                        ignoredPackageNames.end(),
                        [&ignoredPackageNameCandidate](const std::unique_ptr<IgnoredPackageName>& ignoredPackageName) {
                            return ignoredPackageNameCandidate == ignoredPackageName;
//                            return *ignoredPackageNameCandidate == *ignoredPackageName;
                        }
                ) != ignoredPackageNames.end();

//        bool isPackageNameIgnored =
//                std::any_of(
//                        ignoredPackageNames.begin(),
//                        ignoredPackageNames.end(),
//                        [&ignoredPackageNameCandidate](const std::unique_ptr<IgnoredPackageName>& ignoredPackageName) {
//                            return ignoredPackageNameCandidate == ignoredPackageName;
////                            return *ignoredPackageNameCandidate == *ignoredPackageName;
//                        }
//                );

// FOR COMAPRATOR PREDICATE...

        auto ignoredPackageNameCandidate = std::make_unique<IgnoredPackageName>(std::move(packageNameCopy));
        bool isPackageNameIgnored =
                std::find_if(
                        ignoredPackageNames.begin(),
                        ignoredPackageNames.end(),
                        IgnoredPackageNamesEqualityComparator(ignoredPackageNameCandidate)
                ) != ignoredPackageNames.end();

//        bool isPackageNameIgnored =
//                std::any_of(
//                        ignoredPackageNames.begin(),
//                        ignoredPackageNames.end(),
//                        IgnoredPackageNamesEqualityComparator(ignoredPackageNameCandidate)
//                );

// ...AND THE COMPARATOR

#pragma once

#include "IgnoredPackageName.h"

// Comparator for std::map with unique_ptr keys didn't work for std::vector with unique_ptr elements...
//struct IgnoredPackageNamesEqualityComparator {
//    bool operator()(const PackageName& firstPackageName, const PackageName& secondPackageName) const {
//        return firstPackageName == secondPackageName;
//    }
//};

// ...using Predicate instead (pre C++11 solution)
struct IgnoredPackageNamesEqualityComparator {
    const std::unique_ptr<IgnoredPackageName>& ignoredPackageName;

    explicit IgnoredPackageNamesEqualityComparator(const std::unique_ptr<IgnoredPackageName>& packageName) :
        ignoredPackageName(packageName)
    {}

    bool operator()(const std::unique_ptr<IgnoredPackageName>& otherPackageName) const {
//        return (ignoredPackageName == otherPackageName);
        return (*ignoredPackageName == *otherPackageName);
    }
};

Ways of finding an element of custom type in a std::set

  • Client: main.cpp
  • Comparator: lambda/PackageComparator.h/internal comparison logic in overloaded operator< or specialized std::less function (the default function/functor that std::set uses to compare elements)
  • Element of custom type in std::set: Package (Package.h)

PACKAGE (INSTANCE OF CUSTOM TYPE) TO FIND

// main.cpp

#include "Package.h"

<~snip~>

std::string inferredPackageNameAsText = packageNameAndVersion;
auto packageWithInferredName = std::make_unique<Package>(std::move(inferredPackageNameAsText));

STRATEGIES TO FIND A PACKAGE (AN INSTANCE OF CUSTOM TYPE)

  • set::find - passing unique ptr ref

    // main.cpp
    
    std::set<std::unique_ptr<Package>> installedPackages{};
    
    <~snip~>
    
    auto matchingPackage = installedPackages.find(packageWithInferredName);
    
    • overloading operator<

      • public friend operator< with all const params of reference type to const unique_ptr with dereferenced comparison by -> within the operator function without specialized std::less

        // Package.h
        
        friend bool operator<(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
            return onePackage->name < anotherPackage->name;
        }
        
      • public friend operator< with all const params of reference type to const unique_ptr with dereferenced comparison by -> within the operator function with specialized std::less (unnecessary to specialize 'std::less' - the public friend operator< in mentioned format is enough to ensure ordering of elements in the std::set)

            // Package.h
        
            // WORKS for direct comparison with and without overloading 'std::less' funcion
            friend bool operator<(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
                return onePackage->name < anotherPackage->name;
            }
        
            // Doesn't work - compiles but fails to find the searched for element at runtime
            //    friend bool operator<(std::unique_ptr<Package>& onePackage, std::unique_ptr<Package>& anotherPackage) {
            //        return onePackage->name < anotherPackage->name;
            //    }
        
            // Doesn't work - compiles but fails to find the searched for element at runtime
            //    bool operator<(const std::unique_ptr<Package>& package) const {
            //        // TODO maybe replace the 'getName()' function with only fields?
            //
            //        assert(this->getName() == this->name);
            //        assert(this->getName() == Package::name);
            //        assert(this->name == Package::name);
            //
            //        return this->getName() < package->getName();
            //        //        return this->name < package->getName();
            //        //        return Package::name < package->getName();
            //        //        return this->name < package->name;
            //        //        return Package::name < package->name;
            //    }
        

        And then specialize the std::less function outside of the class as a non-member function, e. g. under the class block in the header file

          // Package.h
        
          // overload the 'less' functor in order to enable lookup ('find') in a 'set' or a 'map' with instances of this class as a key, or with any custom object-type key
          namespace std {
              template<>
              struct less<unique_ptr<Package>> {
                  bool operator() (const unique_ptr<Package>& onePackage, const unique_ptr<Package>& anotherPackage) const {
                      return onePackage < anotherPackage;
                  }
              };
          }
        
      • overloading the global std::operator< outside (e.g. under) the class definition:

        // Package.h
        
        namespace std {
            inline bool operator<(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
                return onePackage->getName() < anotherPackage->getName();
            }
        }
        
    • defining a custom comparator

      and passing the custom comparator as a second template argument at initialization

      • comparator functor class added as a second template parameter at 'std::set' construction - direct comparison of unique ptrs passed by reference - public friend operator< with all const params of reference type to const unique_ptr (with specialized 'std::less' with dereference by -> or without specialized 'std::less' with defined public friend operator< with all const params of reference type to unique_ptr - see examples above)

        // main.cpp - changing only 'std::set' declaration leaving 'set::find' as is
        
        #include "PackageComparator.h"
        
        <~snip~>
        
        std::set<std::unique_ptr<Package>, PackageComparator> installedPackages;
        
        <~snip~>
        
        auto matchingPackage = installedPackages.find(packageWithInferredName);
        

        Define the separate custom comparator:

        // PackageComparator.h
        
        #pragma once
        
        #include "Package.h"
        
        struct PackageComparator {
            bool operator()(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) const {
                // DIRECT COMPARISON - works only with 'friend bool operator<(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage)'
                return onePackage < anotherPackage;
            }
        };
        

        Define comparator function for matching compared types for the class, that the element type in std::set is defined in:

        // Package.h
        
        friend bool operator<(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
            return onePackage->name < anotherPackage->name;
        }
        

        Or overload the global std::operator== outside (e.g. under) the class definition:

        // Package.h
        namespace std {
            inline bool operator<(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
                return onePackage->getName() < anotherPackage->getName();
            }
        }
        
      • TODO comparator functor class - directly passed unique ptrs - dereferenced comparison with *

        Doesn't work with overloaded std::operator< as inline bool operator<(const Package& onePackage, Package& anotherPackage) - error: no match for ‘operator<’ (operand types are ‘Package’ and ‘Package’)

      • TODO comparator functor class - directly passed unique ptrs - dereferenced comparison with -> with an accessor function

      • comparator lambda added as a second template parameter at 'std::set' construction - direct comparison of unique ptrs passed by reference - public friend operator< with all const params of reference type to const unique_ptr without specialized 'std::less'

          // main.cpp - changing 'std::set' declaration
        
          auto packageComparatorLambda = [](const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
              return onePackage < anotherPackage;
          };
          std::set<std::unique_ptr<Package>, decltype(packageComparatorLambda)> installedPackages(packageComparatorLambda);
        

        Define public friend operator< for the comparison of directly passed unique pointers

          // Package.h
        
          friend bool operator<(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
              return onePackage->name < anotherPackage->name;
          }
        
      • TODO comparator lambda - comparison of dereferenced unique pointers by * + public friend/member operator<

      • TODO comparator lambda - comparison of dereferenced unique pointers by ->

      • comparator function added as a second template parameter at 'std::set' construction - direct comparison of unique ptrs passed by reference - public friend operator< with all const params of reference type to const unique_ptr without specialized 'std::less'

        // main.cpp - changing 'std::set' declaration
        
        std::set<std::unique_ptr<Package>, decltype(PackageComparatorFunction)*> installedPackages(comparePackages);
        //std::set<std::unique_ptr<Package>, decltype(PackageComparatorFunction)*> installedPackages; // C++20 and newer
        

        or

        std::set<std::unique_ptr<Package>, decltype(&PackageComparatorFunction)> installedPackages(&comparePackages);
        //std::set<std::unique_ptr<Package>, decltype(&PackageComparatorFunction)> installedPackages;  // C++20 and newer
        

        leaving 'set::find' as is

        auto matchingPackage = installedPackages.find(packageWithInferredName);
        

        Define comparator function outside of the class block, e. g. underneath as a non-member function at the end of the header file

        // Package.h
        
        inline bool comparePackages(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
            return onePackage < anotherPackage;
        }
        

        Then define public friend operator< for the direct unique pointer comparison

        // Package.h
        
        friend bool operator<(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
            return onePackage->name < anotherPackage->name;
        }
        
      • TODO comparator function - comparison of dereferenced unique pointers by * + public friend/member operator<

      • TODO comparator function - comparison of dereferenced unique pointers by ->

      • specialized 'std::less' with dereferenced comparison within by -> - without public friend operator< - the standalone std::less function is enough to find a matching element in std::set that holds elements of custom type when lookup is performed with specialized find function set::find instead of other methods [O(log(n) vs O(n)]. The std::less functor relies on the public friend/member operator< of the another dereferenced type that are given as return values from the accessor methods.

          // Package.h
        
          // overload the 'less' functor in order to enable lookup ('find') in a 'set' or a 'map' with instances of this class as a key, or with any custom object-type key
          namespace std {
              template<>
              struct less<unique_ptr<Package>> {
                  bool operator() (const unique_ptr<Package>& onePackage, const unique_ptr<Package>& anotherPackage) const {
                      return onePackage->getName() < anotherPackage->getName();
                  }
              };
          }
        
    • specializing std::less

      • directly passed unique pointer to set::find with specialized 'std::less' with direct comparison

      • directly passed unique pointer to set::find with specialized 'std::less' with dereferenced comparison by '*' with public friend/member operator< with specialized 'std::less' with dereferenced comparison by '*'

        Specialize the std::less function with parameter types matching the type of elemenents the std::set holds

          // Package.h
        
          // overload the 'less' functor in order to enable lookup ('find') in a 'set' or a 'map' with instances of this class as a key, or with any custom object-type key
          namespace std {
              template<>
              struct less<unique_ptr<Package>> {
                  bool operator() (const unique_ptr<Package>& onePackage, const unique_ptr<Package>& anotherPackage) const {
                      return *onePackage < *anotherPackage;
                  }
              };
          }
        

        Choose one of the belowmentioned functions to overload operator< as friend or member function with parameter types matching the type of dereferenced smart pointer.

        All of the belowmentioned functions work for dereferenced comparison together with overloaded 'std::less' funcion for cutom type or with custom comparator without 'std::less' specialization

          // Package.h
        
          bool operator<(const Package& package) const {
              // TODO maybe replace the 'getName()' function with only fields?
        
              assert(this->getName() == this->name);
              assert(this->getName() == Package::name);
              assert(this->name == Package::name);
        
              return this->getName() < package.getName();
          //        return this->name < package.getName();
          //        return Package::name < package.getName();
          //        return this->name < package.name;
          //        return Package::name < package.name;
          }
        
          bool operator<(const Package& package) {
              // TODO maybe replace the 'getName()' function with only fields?
        
              assert(this->getName() == this->name);
              assert(this->getName() == Package::name);
              assert(this->name == Package::name);
        
          //        return this->getName() < package.getName();
              return this->name < package.getName();
          //        return Package::name < package.getName();
          //        return this->name < package.name;
          //        return Package::name < package.name;
          }
        
          bool operator<(Package& package) const {
              // TODO maybe replace the 'getName()' function with only fields?
        
              assert(this->getName() == this->name);
              assert(this->getName() == Package::name);
              assert(this->name == Package::name);
        
          //        return this->getName() < package.getName();
          //        return this->name < package.getName();
          //        return Package::name < package.getName();
              return this->name < package.name;
          //        return Package::name < package.name;
          }
        
        
          bool operator<(Package& package) {
              // TODO maybe replace the 'getName()' function with only fields?
        
              assert(this->getName() == this->name);
              assert(this->getName() == Package::name);
              assert(this->name == Package::name);
        
          //        return this->getName() < package.getName();
          //        return this->name < package.getName();
          //        return Package::name < package.getName();
          //        return this->name < package.name;
              return Package::name < package.name;
          }
        
          friend bool operator<(Package& onePackage, Package& anotherPackage) {
              return onePackage.name < anotherPackage.name;
          }
        
          friend bool operator<(const Package& onePackage, const Package& anotherPackage) {
              return onePackage.name < anotherPackage.name;
          }
        
          friend bool operator<(const Package& onePackage, Package& anotherPackage) {
              return onePackage.name < anotherPackage.name;
          }
        
          friend bool operator<(Package& onePackage, const Package& anotherPackage) {
              return onePackage.name < anotherPackage.name;
          }
        
      • TODO directly passed unique pointer to set::find with specialized 'std::less' with dereferened comparison with -> and an accessor function

    • std::integral_constant as comparator

  • std::find

      // main.cpp
    
      std::set<std::unique_ptr<Package>> installedPackages{};
    
    • passing unique pointer directly - direct comparison of unique pointers (allegedly slower that the specialized 'find' function 'std::set::find' - O(log(n)) vs O(n), and, in fact, the progrm intuitively takes longer, althogh I didn't measure it exactly).

      // main.cpp
      
      auto matchingPackage = std::find(installedPackages.begin(), installedPackages.end(), packageWithInferredName);
      

      The mentioned std::find function finds the element by overloading the operator== as a public friend function with all params of refrence type to unique pointer to Package (or any element of custom type in general) (assuming the element with given key or element feature compared in the operator== function exist in the std::set)

      // Package.h
      
      //   WORKS for direct comparison in 'std::find', 'std::find_if', 'std::any_of'
      friend bool operator==(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
          return onePackage->name == anotherPackage->name;
      }
      
      // Doesn't work
      friend bool operator==(std::unique_ptr<Package>& onePackage, std::unique_ptr<Package>& anotherPackage) {
          return onePackage->name == anotherPackage->name;
      }
      
      // Doesn't work
      bool operator==(const std::unique_ptr<Package>& package) const {
          // TODO maybe replace the 'getName()' function with only fields?
          return this->getName() == package->getName();
      //    return this->name == package.getName();
      //    return this->name < package.name;
      //    return Package::name == package.getName();
      //    return Package::name == package.name;
      }
      

      Or overload the global std::operator== outside (e.g. under) the class definition:

      // Package.h
      
      namespace std {
          inline bool operator==(const std::unique_ptr<Package>& onePackage, const Package& anotherPackage) {
              return onePackage->getName() == anotherPackage.getName();
          }
      }
      
    • passing dereferenced unique pointer - comparison of unique pointer and the passed underlying instance the uniqe pointer holds

      // main.cpp
      
      auto matchingPackage = std::find(installedPackages.begin(), installedPackages.end(), *packageWithInferredName);
      

      This version of std::find works only with 'friend bool operator==(const std::unique_ptr& onePackage, const Package& anotherPackage)' in 'Package.h'

      // Package.h
      
      // WORKS only for 'std::find'
      friend bool operator==(const std::unique_ptr<Package>& onePackage, const Package& anotherPackage) {
          return onePackage->name == anotherPackage.name;
      }
      
      // Doesn't work - error: no match for ‘operator==’ (operand types are ‘const std::unique_ptr<Package>’ and ‘const Package’)
      //    friend bool operator==(std::unique_ptr<Package>& onePackage, Package& anotherPackage) {
      //        return onePackage->name == anotherPackage.name;
      //    }
      
      // Doesn't work - error: no match for ‘operator==’ (operand types are ‘const std::unique_ptr<Package>’ and ‘const Package’)
      //    bool operator==(const Package& otherPackage) const {
      //        return this->name == otherPackage.name;
      //    }
      
      // Doesn't work - error: no match for ‘operator==’ (operand types are ‘const std::unique_ptr<Package>’ and ‘const Package’)
      //    bool operator==(Package& otherPackage) {
      //        return this->name == otherPackage.name;
      //    }
      

      Or overload the global std::operator== outside (e.g. under) the class definition:

      // Package.h
      
      namespace std {
          inline bool operator==(const std::unique_ptr<Package>& onePackage, const Package& anotherPackage) {
              return onePackage->getName() == anotherPackage.getName();
          }
      }
      ``
      
      
  • std::find_if

    // main.cpp
    
    std::set<std::unique_ptr<Package>> installedPackages{};
    
    • std::find_if with lambda comparator

      • lambda with direct comparison

        // main.cpp
        
        auto matchingPackage = std::find_if(installedPackages.begin(), installedPackages.end(),
                [&packageWithInferredName](const std::unique_ptr<Package>& currentInstalledPackage) {
                    return packageWithInferredName == currentInstalledPackage;
                }
        );
        

        Works only with friend bool operator==(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) in 'Package.h'

        // Package.h
        
        //   WORKS for direct comparison in 'std::find', 'std::find_if', 'std::any_of'
        friend bool operator==(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
            return onePackage->name == anotherPackage->name;
        }
        

        Or overload the global std::operator== outside (e.g. under) the class definition:

        // Package.h
        
        namespace std {
            inline bool operator==(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
                return onePackage->getName() == anotherPackage->getName();
            }
        }
        
      • lambda with dereferenced comparison by *

        // main.cpp
        
        auto matchingPackage = std::find_if(installedPackages.begin(), installedPackages.end(),
                [&packageWithInferredName](const std::unique_ptr<Package>& currentInstalledPackage) {
                    return *packageWithInferredName == *currentInstalledPackage;
                }
        );
        

        Works only with any of the operator== mentioned below

        // Package.h
        
        friend bool operator==(const Package& onePackage, const Package& anotherPackage) {
            return onePackage.name == anotherPackage.name;
        }
        
        friend bool operator==(const Package& onePackage, Package& anotherPackage) {
            return onePackage.name == anotherPackage.name;
        }
        
        friend bool operator==(Package& onePackage, const Package& anotherPackage) {
            return onePackage.name == anotherPackage.name;
        }
        
        friend bool operator==(Package& onePackage, Package& anotherPackage) {
            return onePackage.name == anotherPackage.name;
        }
        
        bool operator==(const Package& otherPackage) const {
            return this->name == otherPackage.name;
        }
        
        bool operator==(const Package& otherPackage) {
            return this->name == otherPackage.name;
        }
        
        bool operator==(Package& otherPackage) const {
            return this->name == otherPackage.name;
        }
        
        bool operator==(Package& otherPackage) {
            return this->name == otherPackage.name;
        }
        

        Doesn't work with overloaded std::operator== as inline bool operator==(const Package& onePackage, const Package& anotherPackage) - error: no match for ‘operator==’ (operand types are ‘Package’ and ‘Package’)

      • lambda with dereferenced comparison by -> - delegating comparison

        // main.cpp
        
        auto matchingPackage = std::find_if(installedPackages.begin(), installedPackages.end(),
                [&packageWithInferredName](const std::unique_ptr<Package>& currentInstalledPackage) {
                    return packageWithInferredName->getName() == currentInstalledPackage->getName();
                }
        );
        
      • passing dereferenced unique pointer to lambda in std::find_if - COULDN'T MAKE IT WORK

        auto matchingPackage = std::find_if(installedPackages.begin(), installedPackages.end(),
                [&packageWithInferredName](const Package& currentInstalledPackage) {
                    return packageWithInferredName == *currentInstalledPackage; // works only with 'friend bool operator==(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage)' in 'Package.h'
        //            return *packageWithInferredName == *currentInstalledPackage; // works only with 'friend bool operator==(const Package& onePackage, const Package& anotherPackage)' in 'Package.h'
        //            return packageWithInferredName->getName() == currentInstalledPackage->getName();
                }
        );
        
        • error: binding reference of type ‘Package&’ to ‘const Package’ discards qualifiers when a value from first function is declared as const and this value is passed through a parameter to another function which take the same parameter type without const
        • when forgetting to add constness of the second parameter of public friend operator== function or of first parameer of public member operator== function
        • or
        • error: no match for call to ‘(main()::<lambda(const Package&)>) (const std::unique_ptr<Package>&)’
        • note: no known conversion for argument 1 from ‘const std::unique_ptr<Package>’ to ‘const Package&’
        • Possible solution would be to define an implicit?/(explicit? casted to Package& with static_cast?) conversion constructor Package::Package(const std::unique_ptr<Package> uniquePtr) but that would only slow things down and make the code less readable and expressive. Let's keep it simple ;)
    • std::find_if with comparator predicate

      // main.cpp
      
      #include "PackageComparatorPredicate.h"
      
      • passing unique pointer to comparator predicate directly

        // main.cpp
        
        auto matchingPackage = std::find_if(
                installedPackages.begin(),
                installedPackages.end(),
                PackageComparatorPredicate(packageWithInferredName));
        
        • comparator predicate with direct comparison

          // PackageComparatorPredicate.h
          
          #pragma once
          
          #include "Package.h"
          
          struct PackageComparatorPredicate {
              const std::unique_ptr<Package>& package;
          
              explicit PackageComparatorPredicate(const std::unique_ptr<Package>& packageToFind) :
                      package(packageToFind)
              {}
          
              bool operator()(const std::unique_ptr<Package>& otherPackage) const {
                  return (this->package == otherPackage);
              }
          };
          
          

          For direct comparison of unique pointers is effective only function that overloads the operator== as public friend function with all const params (public friend operator== without const parameters and any of the public member function for operator== don't find anything):

          // Package.h
          
          friend bool operator==(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
              return onePackage->name == anotherPackage->name;
          }
          

          Or overload the global std::operator== outside (e.g. under) the class definition:

          // Package.h
          
          namespace std {
              inline bool operator==(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
                  return onePackage->getName() == anotherPackage->getName();
              }
          }
          
        • comparator predicate with dereferenced comparison by *

          // PackageComparatorPredicate.h
          
          #pragma once
          
          #include "Package.h"
          
          struct PackageComparatorPredicate {
              const std::unique_ptr<Package>& package;
          
              explicit PackageComparatorPredicate(const std::unique_ptr<Package>& packageToFind) :
                      package(packageToFind)
              {}
          
              bool operator()(const std::unique_ptr<Package>& otherPackage) const {
                  return (*(this->package) == *otherPackage);
              }
          };
          
          

          For comparison of dereferenced unique pointers use one of the belowmentioned functions to overloading operator==

          // Package.h
          
          friend bool operator==(const Package& onePackage, const Package& anotherPackage) {
              return onePackage.name == anotherPackage.name;
          }
          
          friend bool operator==(const Package& onePackage, Package& anotherPackage) {
              return onePackage.name == anotherPackage.name;
          }
          
          friend bool operator==(Package& onePackage, const Package& anotherPackage) {
              return onePackage.name == anotherPackage.name;
          }
          
          friend bool operator==(Package& onePackage, Package& anotherPackage) {
              return onePackage.name == anotherPackage.name;
          }
          
          bool operator==(const Package& otherPackage) const {
              return this->name == otherPackage.name;
          }
          
          bool operator==(const Package& otherPackage) {
              return this->name == otherPackage.name;
          }
          
          bool operator==(Package& otherPackage) const {
              return this->name == otherPackage.name;
          }
          
          bool operator==(Package& otherPackage) {
              return this->name == otherPackage.name;
          }
          

          Doesn't work with overloaded std::operator== as inline bool operator==(const Package& onePackage, const Package& anotherPackage) - error: no match for ‘operator==’ (operand types are ‘Package’ and ‘Package’)

        • comparator predicate with dereferenced comparison by -> - delegating comparison to the return type of the function we're sending the message to, so we need to overload operator== in the class that the type is defined in or that the type refers to. For the concrete implementations of overloaded operator== for particular types see mentioned examples in this section.

          // PackageComparatorPredicate.h
          
          #pragma once
          
          #include "Package.h"
          
          struct PackageComparatorPredicate {
              const std::unique_ptr<Package>& package;
          
              explicit PackageComparatorPredicate(const std::unique_ptr<Package>& packageToFind) :
                      package(packageToFind)
              {}
          
              bool operator()(const std::unique_ptr<Package>& otherPackage) const {
                  return (this->package->getName() == otherPackage->getName());
              }
          };
          
          
      • passing dereferenced unique pointer to comparator predicate

        // main.cpp
        
        auto matchingPackage = std::find_if(
                installedPackages.begin(),
                installedPackages.end(),
                PackageComparatorPredicate(*packageWithInferredName));
        
        • comparator predicate with direct comparison - comparison of dereferenced member variable (instance with features to search by) with smart pointer

          // PackageComparatorPredicate.h
          
          #pragma once
          
          #include "Package.h"
          
          struct PackageComparatorPredicate {
              const Package& package;
          
              explicit PackageComparatorPredicate(const Package& packageToFind) :
                      package(packageToFind)
              {}
          
              bool operator()(const std::unique_ptr<Package>& otherPackage) const {
                  return this->package == otherPackage;
              }
          };
          

          The overloaded operator== needs to be implemented as const function with all const operands (parameters)

          // Package.h
          
          friend bool operator==(const Package& onePackage, const std::unique_ptr<Package>& anotherPackage) {
              return onePackage->name == anotherPackage.name;
          }
          
          bool operator==(const std::unique_ptr<Package>& otherPackage) const {
              return this->name == otherPackage->name;
          }
          

          Or overload the global std::operator== outside (e.g. under) the class definition:

          // Package.h
          
          namespace std {
              inline bool operator==(const Package& onePackage, const std::unique_ptr<Package>& anotherPackage) {
                  return onePackage->getName() == anotherPackage.getName();
              }
          }
          
        • comparator predicate with comparison of member variable of reference type (instance with features to search by) with dereferenced smart pointer

          // PackageComparatorPredicate.h
          
          #pragma once
          
          #include "Package.h"
          
          struct PackageComparatorPredicate {
              const Package& package;
          
              explicit PackageComparatorPredicate(const Package& packageToFind) :
                      package(packageToFind)
              {}
          
              bool operator()(const std::unique_ptr<Package>& otherPackage) const {
                  return (this->package == *otherPackage);
              }
          };
          

          The comparator predicate in this case uses the operator== with operand types const Package and Package. When const is added to the second parameter of the friend operator== overload as well (or the single parameter from member overload function), everything works as intended. Problems occured during compilation, when I ommitted the const qualifier for mentioned operands at mentioned position which produces an error error: binding reference of type ‘Package&’ to ‘const Package’ discards qualifiers

          // Package.h
          
          friend bool operator==(const Package& onePackage, const Package& anotherPackage) {
              return onePackage.name == anotherPackage.name;
          }
          
          friend bool operator==(const Package& onePackage, Package& anotherPackage) {
              return onePackage.name == anotherPackage.name;
          }
          
          bool operator==(const Package& otherPackage) const {
              return this->name == otherPackage.name;
          }
          
          bool operator==(Package& otherPackage) const {
              return this->name == otherPackage.name;
          }
          

          Doesn't work with overloaded std::operator== as inline bool operator==(const Package& onePackage, Package& anotherPackage) - error: no match for ‘operator==’ (operand types are ‘const Package’ and ‘Package’)

        • comparator predicate with comparison of member variable of reference type (instance with features to search by) with smart pointer - both dereferenced to call an accessor function (-> for unique pointer, . for reference) to delegating the comparison from the original reference type to the type returned by the accessor function. The returned type needs to have the operator== overloaded instead of the original type. For the concrete implementations of overloaded operator== for particular use cases see mentioned examples in this section.

          // PackageComparatorPredicate.h
          
          #pragma once
          
          #include "Package.h"
          
          struct PackageComparatorPredicate {
              const Package& package;
          
              explicit PackageComparatorPredicate(const Package& packageToFind) :
                      package(packageToFind)
              {}
          
              bool operator()(const std::unique_ptr<Package>& otherPackage) const {
                  return (this->package.getName() == otherPackage->getName());
              }
          };
          
        • comparator predicate with dereferenced comparison by -> - delegating comparison to the return type of the function we're sending the message to, so we need to overload operator== in the class that the type is defined in or that the type refers to. For the concrete implementations of overloaded operator== for particular types see mentioned examples in this section.

          // PackageComparatorPredicate.h
          
          #pragma once
          
          #include "Package.h"
          
          struct PackageComparatorPredicate {
              const std::unique_ptr<Package>& package;
          
              explicit PackageComparatorPredicate(const std::unique_ptr<Package>& packageToFind) :
                      package(packageToFind)
              {}
          
              bool operator()(const std::unique_ptr<Package>& otherPackage) const {
                  return (this->package->getName() == otherPackage->getName());
              }
          };
          
  • std::any_of

    // main.cpp
    
    std::set<std::unique_ptr<Package>> installedPackages{};
    
    • std::any_of with lambda comparator

      • lambda with direct comparison

        // main.cpp
        
        bool isPackageWithInferredNameFoundAsTest = std::any_of(installedPackages.begin(), installedPackages.end(),
                [&packageWithInferredName](const std::unique_ptr<Package>& currentInstalledPackage) {
                    return packageWithInferredName == currentInstalledPackage;
                }
        );
        

        Works only with friend bool operator==(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) in 'Package.h'

        // Package.h
        
        //   WORKS for direct comparison in 'std::find', 'std::any_of', 'std::any_of'
        friend bool operator==(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
            return onePackage->name == anotherPackage->name;
        }
        

        Or overload the global std::operator== outside (e.g. under) the class definition:

        // Package.h
        
        namespace std {
            inline bool operator==(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
                return onePackage->getName() == anotherPackage->getName();
            }
        }
        
      • lambda with dereferenced comparison by *

        // main.cpp
        
        bool isPackageWithInferredNameFoundAsTest = std::any_of(installedPackages.begin(), installedPackages.end(),
                [&packageWithInferredName](const std::unique_ptr<Package>& currentInstalledPackage) {
                    return *packageWithInferredName == *currentInstalledPackage;
                }
        );
        

        Works only with any of the operator== mentioned below

        // Package.h
        
        friend bool operator==(const Package& onePackage, const Package& anotherPackage) {
            return onePackage.name == anotherPackage.name;
        }
        
        friend bool operator==(const Package& onePackage, Package& anotherPackage) {
            return onePackage.name == anotherPackage.name;
        }
        
        friend bool operator==(Package& onePackage, const Package& anotherPackage) {
            return onePackage.name == anotherPackage.name;
        }
        
        friend bool operator==(Package& onePackage, Package& anotherPackage) {
            return onePackage.name == anotherPackage.name;
        }
        
        bool operator==(const Package& otherPackage) const {
            return this->name == otherPackage.name;
        }
        
        bool operator==(const Package& otherPackage) {
            return this->name == otherPackage.name;
        }
        
        bool operator==(Package& otherPackage) const {
            return this->name == otherPackage.name;
        }
        
        bool operator==(Package& otherPackage) {
            return this->name == otherPackage.name;
        }
        

        Doesn't work with overloaded std::operator== as inline bool operator==(const Package& onePackage, const Package& anotherPackage) - error: no match for ‘operator==’ (operand types are ‘Package’ and ‘Package’)

      • lambda with dereferenced comparison by -> - delegating comparison

        // main.cpp
        
        bool isPackageWithInferredNameFoundAsTest = std::any_of(installedPackages.begin(), installedPackages.end(),
                [&packageWithInferredName](const std::unique_ptr<Package>& currentInstalledPackage) {
                    return packageWithInferredName->getName() == currentInstalledPackage->getName();
                }
        );
        
      • passing dereferenced unique pointer to lambda in std::any_of - COULDN'T MAKE IT WORK

        bool isPackageWithInferredNameFoundAsTest = std::any_of(installedPackages.begin(), installedPackages.end(),
                [&packageWithInferredName](const Package& currentInstalledPackage) {
                    return packageWithInferredName == *currentInstalledPackage; // works only with 'friend bool operator==(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage)' in 'Package.h'
        //            return *packageWithInferredName == *currentInstalledPackage; // works only with 'friend bool operator==(const Package& onePackage, const Package& anotherPackage)' in 'Package.h'
        //            return packageWithInferredName->getName() == currentInstalledPackage->getName();
                }
        );
        
        • error: binding reference of type ‘Package&’ to ‘const Package’ discards qualifiers when a value from first function is declared as const and this value is passed through a parameter to another function which take the same parameter type without const
        • when forgetting to add constness of the second parameter of public friend operator== function or of first parameer of public member operator== function
        • or
        • error: no match for call to ‘(main()::<lambda(const Package&)>) (const std::unique_ptr<Package>&)’
        • note: no known conversion for argument 1 from ‘const std::unique_ptr<Package>’ to ‘const Package&’
        • Possible solution would be to define an implicit?/(explicit? casted to Package& with static_cast?) conversion constructor Package::Package(const std::unique_ptr<Package> uniquePtr) but that would only slow things down and make the code less readable and expressive. Let's keep it simple ;)
    • std::any_of with comparator predicate

      // main.cpp
      
      #include "PackageComparatorPredicate.h"
      
      • passing unique pointer to comparator predicate directly

        // main.cpp
        
        bool isPackageWithInferredNameFoundAsTest = std::any_of(
                installedPackages.begin(),
                installedPackages.end(),
                PackageComparatorPredicate(packageWithInferredName));
        
        • comparator predicate with direct comparison

          // PackageComparatorPredicate.h
          
          #pragma once
          
          #include "Package.h"
          
          struct PackageComparatorPredicate {
              const std::unique_ptr<Package>& package;
          
              explicit PackageComparatorPredicate(const std::unique_ptr<Package>& packageToFind) :
                      package(packageToFind)
              {}
          
              bool operator()(const std::unique_ptr<Package>& otherPackage) const {
                  return (this->package == otherPackage);
              }
          };
          
          

          For direct comparison of unique pointers is effective only function that overloads the operator== as public friend function with all const params (public friend operator== without const parameters and any of the public member function for operator== don't find anything):

          // Package.h
          
          friend bool operator==(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
              return onePackage->name == anotherPackage->name;
          }
          

          Or overload the global std::operator== outside (e.g. under) the class definition:

          // Package.h
          
          namespace std {
              inline bool operator==(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
                  return onePackage->getName() == anotherPackage->getName();
              }
          }
          
        • comparator predicate with dereferenced comparison by *

          // PackageComparatorPredicate.h
          
          #pragma once
          
          #include "Package.h"
          
          struct PackageComparatorPredicate {
              const std::unique_ptr<Package>& package;
          
              explicit PackageComparatorPredicate(const std::unique_ptr<Package>& packageToFind) :
                      package(packageToFind)
              {}
          
              bool operator()(const std::unique_ptr<Package>& otherPackage) const {
                  return (*(this->package) == *otherPackage);
              }
          };
          
          

          For comparison of dereferenced unique pointers use one of the belowmentioned functions to overloading operator==

          // Package.h
          
          friend bool operator==(const Package& onePackage, const Package& anotherPackage) {
              return onePackage.name == anotherPackage.name;
          }
          
          friend bool operator==(const Package& onePackage, Package& anotherPackage) {
              return onePackage.name == anotherPackage.name;
          }
          
          friend bool operator==(Package& onePackage, const Package& anotherPackage) {
              return onePackage.name == anotherPackage.name;
          }
          
          friend bool operator==(Package& onePackage, Package& anotherPackage) {
              return onePackage.name == anotherPackage.name;
          }
          
          bool operator==(const Package& otherPackage) const {
              return this->name == otherPackage.name;
          }
          
          bool operator==(const Package& otherPackage) {
              return this->name == otherPackage.name;
          }
          
          bool operator==(Package& otherPackage) const {
              return this->name == otherPackage.name;
          }
          
          bool operator==(Package& otherPackage) {
              return this->name == otherPackage.name;
          }
          

          Doesn't work with overloaded std::operator== as inline bool operator==(const Package& onePackage, const Package& anotherPackage) - error: no match for ‘operator==’ (operand types are ‘Package’ and ‘Package’)

        • comparator predicate with dereferenced comparison by -> - delegating comparison to the return type of the function we're sending the message to, so we need to overload operator== in the class that the type is defined in or that the type refers to. For the concrete implementations of overloaded operator== for particular types see mentioned examples in this section.

          // PackageComparatorPredicate.h
          
          #pragma once
          
          #include "Package.h"
          
          struct PackageComparatorPredicate {
              const std::unique_ptr<Package>& package;
          
              explicit PackageComparatorPredicate(const std::unique_ptr<Package>& packageToFind) :
                      package(packageToFind)
              {}
          
              bool operator()(const std::unique_ptr<Package>& otherPackage) const {
                  return (this->package->getName() == otherPackage->getName());
              }
          };
          
          
      • passing dereferenced unique pointer to comparator predicate

        // main.cpp
        
        bool isPackageWithInferredNameFoundAsTest = std::any_of(
                installedPackages.begin(),
                installedPackages.end(),
                PackageComparatorPredicate(*packageWithInferredName));
        
        • comparator predicate with direct comparison - comparison of dereferenced member variable (instance with features to search by) with smart pointer

          // PackageComparatorPredicate.h
          
          #pragma once
          
          #include "Package.h"
          
          struct PackageComparatorPredicate {
              const Package& package;
          
              explicit PackageComparatorPredicate(const Package& packageToFind) :
                      package(packageToFind)
              {}
          
              bool operator()(const std::unique_ptr<Package>& otherPackage) const {
                  return this->package == otherPackage;
              }
          };
          

          The overloaded operator== needs to be implemented as const function with all const operands (parameters)

          // Package.h
          
          friend bool operator==(const Package& onePackage, const std::unique_ptr<Package>& anotherPackage) {
              return onePackage->name == anotherPackage.name;
          }
          
          bool operator==(const std::unique_ptr<Package>& otherPackage) const {
              return this->name == otherPackage->name;
          }
          

          Or overload the global std::operator== outside (e.g. under) the class definition:

          // Package.h
          
          namespace std {
              inline bool operator==(const Package& onePackage, const std::unique_ptr<Package>& anotherPackage) {
                  return onePackage->getName() == anotherPackage.getName();
              }
          }
          
        • comparator predicate with comparison of member variable of reference type (instance with features to search by) with dereferenced smart pointer

          // PackageComparatorPredicate.h
          
          #pragma once
          
          #include "Package.h"
          
          struct PackageComparatorPredicate {
              const Package& package;
          
              explicit PackageComparatorPredicate(const Package& packageToFind) :
                      package(packageToFind)
              {}
          
              bool operator()(const std::unique_ptr<Package>& otherPackage) const {
                  return (this->package == *otherPackage);
              }
          };
          

          The comparator predicate in this case uses the operator== with operand types const Package and Package. When const is added to the second parameter of the friend operator== overload as well (or the single parameter from member overload function), everything works as intended. Problems occured during compilation, when I ommitted the const qualifier for mentioned operands at mentioned position which produces an error error: binding reference of type ‘Package&’ to ‘const Package’ discards qualifiers

          // Package.h
          
          friend bool operator==(const Package& onePackage, const Package& anotherPackage) {
              return onePackage.name == anotherPackage.name;
          }
          
          friend bool operator==(const Package& onePackage, Package& anotherPackage) {
              return onePackage.name == anotherPackage.name;
          }
          
          bool operator==(const Package& otherPackage) const {
              return this->name == otherPackage.name;
          }
          
          bool operator==(Package& otherPackage) const {
              return this->name == otherPackage.name;
          }
          

          Doesn't work with overloaded std::operator== as inline bool operator==(const Package& onePackage, Package& anotherPackage) - error: no match for ‘operator==’ (operand types are ‘const Package’ and ‘Package’)

        • comparator predicate with comparison of member variable of reference type (instance with features to search by) with smart pointer - both dereferenced to call an accessor function (-> for unique pointer, . for reference) to delegating the comparison from the original reference type to the type returned by the accessor function. The returned type needs to have the operator== overloaded instead of the original type. For the concrete implementations of overloaded operator== for particular use cases see mentioned examples in this section.

          // PackageComparatorPredicate.h
          
          #pragma once
          
          #include "Package.h"
          
          struct PackageComparatorPredicate {
              const Package& package;
          
              explicit PackageComparatorPredicate(const Package& packageToFind) :
                      package(packageToFind)
              {}
          
              bool operator()(const std::unique_ptr<Package>& otherPackage) const {
                  return (this->package.getName() == otherPackage->getName());
              }
          };
          
        • comparator predicate with dereferenced comparison by -> - delegating comparison to the return type of the function we're sending the message to, so we need to overload operator== in the class that the type is defined in or that the type refers to. For the concrete implementations of overloaded operator== for particular types see mentioned examples in this section.

          // PackageComparatorPredicate.h
          
          #pragma once
          
          #include "Package.h"
          
          struct PackageComparatorPredicate {
              const std::unique_ptr<Package>& package;
          
              explicit PackageComparatorPredicate(const std::unique_ptr<Package>& packageToFind) :
                      package(packageToFind)
              {}
          
              bool operator()(const std::unique_ptr<Package>& otherPackage) const {
                  return (this->package->getName() == otherPackage->getName());
              }
          };
          
  • std::binary_search

    • std::binary_search with std::set inicialized without custom comparator as a second template parameter - using the default std::less and operator< for comparing and sorting elements of custom type
    // main.cpp
    
    std::set<std::unique_ptr<Package>> installedPackages{};
    
  • Converting current time to human readable format

    • https://duckduckgo.com/?t=ffab&q=c%2B%2B+date+time+timestamp&ia=web

    • with ctime header - C-style: https://www.softwaretestinghelp.com/date-and-time-in-cpp/

    • with chrono header - C++ style (preferred): https://stackoverflow.com/questions/58603446/convert-timestamp-to-the-formatted-date-time-using-c

    • https://duckduckgo.com/?q=c%2B%2B+chrono+date+time+timestamp&t=ffab&ia=web

    • https://stackoverflow.com/questions/17223096/outputting-date-and-time-in-c-using-stdchronoame < package.getName(); // return Package::name < package.getName(); // return this->name < package.name; return Package::name < package.name; }

            friend bool operator<(Package& onePackage, Package& anotherPackage) {
                return onePackage.name < anotherPackage.name;
            }
      
            friend bool operator<(const Package& onePackage, const Package& anotherPackage) {
                return onePackage.name < anotherPackage.name;
            }
      
            friend bool operator<(const Package& onePackage, Package& anotherPackage) {
                return onePackage.name < anotherPackage.name;
            }
      
            friend bool operator<(Package& onePackage, const Package& anotherPackage) {
                return onePackage.name < anotherPackage.name;
            }
            ```
      
      • public friend operator< with all const params of reference type to const unique_ptr with dereferenced comparison by -> within the operator function with specialized std::less (unnecessary to specialize 'std::less' - the public friend operator< in mentioned format is enough to ensure ordering of elements in the std::set)

        Standalone specialized std:less functor doesn't find an element of custom type for std::binary_search, even though the functor is specialized for the custom type the std::set holds.

        // Package.h
        
        friend bool operator<(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
            return onePackage->name < anotherPackage->name;
        }
        
        <~snip~>
        
        namespace std {
            template<>
            struct less<unique_ptr<Package>> {
                bool operator() (const unique_ptr<Package>& onePackage, const unique_ptr<Package>& anotherPackage) const {
                    return onePackage < anotherPackage;
                }
            };
        }
        
      • specializing std::less with dereferenced comparison - COULDN'T MAKE IT WORK with operator< in any version

        // Package.h
        
        bool operator<(const Package& package) const {
            // TODO maybe replace the 'getName()' function with only fields?
        
            assert(this->getName() == this->name);
            assert(this->getName() == Package::name);
            assert(this->name == Package::name);
        
            return this->getName() < package.getName();
        //    return this->name < package.getName();
        //    return Package::name < package.getName();
        //    return this->name < package.name;
        //    return Package::name < package.name;
        }
        
        bool operator<(const Package& package) {
            // TODO maybe replace the 'getName()' function with only fields?
        
            assert(this->getName() == this->name);
            assert(this->getName() == Package::name);
            assert(this->name == Package::name);
        
            return this->getName() < package.getName();
            return this->name < package.getName();
            return Package::name < package.getName();
            return this->name < package.name;
            return Package::name < package.name;
        }
        
        bool operator<(Package& package) const {
            // TODO maybe replace the 'getName()' function with only fields?
        
            assert(this->getName() == this->name);
            assert(this->getName() == Package::name);
            assert(this->name == Package::name);
        
        //    return this->getName() < package.getName();
        //    return this->name < package.getName();
        //    return Package::name < package.getName();
            return this->name < package.name;
        //    return Package::name < package.name;
        }
        
        bool operator<(Package& package) {
            // TODO maybe replace the 'getName()' function with only fields?
        
            assert(this->getName() == this->name);
            assert(this->getName() == Package::name);
            assert(this->name == Package::name);
        
        //    return this->getName() < package.getName();
        //    return this->name < package.getName();
        //    return Package::name < package.getName();
        //    return this->name < package.name;
            return Package::name < package.name;
        }
        
        friend bool operator<(Package& onePackage, Package& anotherPackage) {
            return onePackage.name < anotherPackage.name;
        }
        
        friend bool operator<(const Package& onePackage, const Package& anotherPackage) {
            return onePackage.name < anotherPackage.name;
        }
        
        friend bool operator<(const Package& onePackage, Package& anotherPackage) {
            return onePackage.name < anotherPackage.name;
        }
        
        friend bool operator<(Package& onePackage, const Package& anotherPackage) {
            return onePackage.name < anotherPackage.name;
        }
        
        <~snip~>
        
        namespace std {
            template<>
            struct less<unique_ptr<Package>> {
                bool operator() (const unique_ptr<Package>& onePackage, const unique_ptr<Package>& anotherPackage) const {
                    return *onePackage < *anotherPackage;
                }
            };
        }
        
    • directly passing unique pointer to binary search with custom comparator

      // main.cpp
      
      #include "PackageComparator.h"
      
      <~snip~>
      
      bool packageWithInferredNameIsMissingAsTest = std::binary_search(installedPackages.begin(), installedPackages.end(), packageWithInferredName, PackageComparator());
      
      • direct comparison of unique pointers in comparator

        #pragma once
        
        #include "Package.h"
        
        struct PackageComparator {
            bool operator()(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) const {
                // DIRECT COMPARISON - works only with 'friend bool operator<(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage)'
                return onePackage < anotherPackage;
            }
        };
        
        // Package.h
        
        friend bool operator<(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
            return onePackage->name < anotherPackage->name;
        }
        
      • comparison of dereferenced unique pointers in comparator by * and -> with an accessor method didn't work with any version of overloaded operator<. Maybe because of the mystical std::binary_search ForwardIterator limitation? See examples above.

    • passing dereferenced unique pointer to binary search - COULDN'T MAKE IT WORK with operator< in both required versions

      // main.cpp
      
      bool packageWithInferredNameIsMissingAsTest = std::binary_search(installedPackages.begin(), installedPackages.end(), *packageWithInferredName);
      
      // Package.h
      
      // for 'stl_algo.h'
      friend bool operator<(const Package& onePackage, const std::unique_ptr<Package>& anotherPackage) {
          return onePackage.name < anotherPackage->name;
      }
      
      // for 'predefined_ops.h'
      friend bool operator<(const std::unique_ptr<Package>& onePackage, const Package& anotherPackage) {
          return onePackage->name < anotherPackage.name;
      }
      
    • passing dereferenced unique pointer to binary search with custom comparator - COULDN'T MAKE IT WORK for any version of comparison in comparator with any version of overloaded operator<

      // main.cpp
      
      #include "PackageComparator.h"
      
      <~snip~>
      
      bool packageWithInferredNameIsMissingAsTest = std::binary_search(installedPackages.begin(), installedPackages.end(), *packageWithInferredName, PackageComparator())
      
      // PackageComparator.h
      
      #pragma once
      
      #include "Package.h"
      
      //struct PackageComparator {
      //    bool operator()(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) const {
      //        // DIRECT COMPARISON - works only with 'friend bool operator<(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage)'
      ////        return onePackage < anotherPackage;
      //
      //        // DEREFERENCED COMPARISON without accessor method - works with
      //        //  - 'bool operator<(const Package& package) const'
      //        //  - 'bool operator<(Package& package)'
      //        //  - 'friend bool operator<(Package& onePackage, Package& anotherPackage)'
      ////        return *onePackage < *anotherPackage;
      //
      //        // DEREFERENCED COMPARISON with accessor method - delegating comparison from 'operator<' functions in this class ('Package') element to compared field within the 'Package' element
      //        //  which has 'operator<' implemented, leaving the 'Package' class intact. works without overloading 'std::less' in 'Package' class
      //        //  Works out of the box for 'std::string'.
      //        //  For custom type at least public friend 'operator<' with all const params needs to be implemented
      //        return onePackage->getName() < anotherPackage->getName();
      //    }
      //};
      
      struct PackageComparator {
          bool operator()(const Package& onePackage, const std::unique_ptr<Package>& anotherPackage) const {
              // DIRECT COMPARISON - works only with 'friend bool operator<(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage)'
              return onePackage < anotherPackage;
      
              // DEREFERENCED COMPARISON without accessor method - works with
              //  - 'bool operator<(const Package& package) const'
              //  - 'bool operator<(Package& package)'
              //  - 'friend bool operator<(Package& onePackage, Package& anotherPackage)'
      //        return onePackage < *anotherPackage;
      
              // DEREFERENCED COMPARISON with accessor method - delegating comparison from 'operator<' functions in this class ('Package') element to compared field within the 'Package' element
              //  which has 'operator<' implemented, leaving the 'Package' class intact. works without overloading 'std::less' in 'Package' class
              //  Works out of the box for 'std::string'.
              //  For custom type at least public friend 'operator<' with all const params needs to be implemented
      //        return onePackage.getName() < anotherPackage->getName();
          }
      
          bool operator()(const std::unique_ptr<Package>& onePackage, const Package& anotherPackage) const {
              // DIRECT COMPARISON - works only with 'friend bool operator<(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage)'
              return onePackage < anotherPackage;
      
              // DEREFERENCED COMPARISON without accessor method - works with
              //  - 'bool operator<(const Package& package) const'
              //  - 'bool operator<(Package& package)'
              //  - 'friend bool operator<(Package& onePackage, Package& anotherPackage)'
      //        return *onePackage < anotherPackage;
      
              // DEREFERENCED COMPARISON with accessor method - delegating comparison from 'operator<' functions in this class ('Package') element to compared field within the 'Package' element
              //  which has 'operator<' implemented, leaving the 'Package' class intact. works without overloading 'std::less' in 'Package' class
              //  Works out of the box for 'std::string'.
              //  For custom type at least public friend 'operator<' with all const params needs to be implemented
      //        return onePackage->getName() < anotherPackage.getName();
          }
      };
      
      
      // Package.h
      
      // FOR DIRECT COMPARISON
          // for 'stl_algo.h'
      //    friend bool operator<(const Package& onePackage, const std::unique_ptr<Package>& anotherPackage) {
      //        return onePackage.name < anotherPackage->name;
      //    }
      //
      //    // for 'predefined_ops.h'
      //    friend bool operator<(const std::unique_ptr<Package>& onePackage, const Package& anotherPackage) {
      //        return onePackage->name < anotherPackage.name;
      //    }
      
      // FOR DEREFERENCED COMPARISON without accessor method
      //    bool operator<(const Package& package) const {
      //        // TODO maybe replace the 'getName()' function with only fields?
      //
      //        assert(this->getName() == this->name);
      //        assert(this->getName() == Package::name);
      //        assert(this->name == Package::name);
      //
      //        return this->getName() < package.getName();
      ////        return this->name < package.getName();
      ////        return Package::name < package.getName();
      ////        return this->name < package.name;
      ////        return Package::name < package.name;
      //    }
      
      //    bool operator<(const Package& package) {
      //        // TODO maybe replace the 'getName()' function with only fields?
      //
      //        assert(this->getName() == this->name);
      //        assert(this->getName() == Package::name);
      //        assert(this->name == Package::name);
      //
      ////        return this->getName() < package.getName();
      //        return this->name < package.getName();
      ////        return Package::name < package.getName();
      ////        return this->name < package.name;
      ////        return Package::name < package.name;
      //    }
      
      //    bool operator<(Package& package) const {
      //        // TODO maybe replace the 'getName()' function with only fields?
      //
      //        assert(this->getName() == this->name);
      //        assert(this->getName() == Package::name);
      //        assert(this->name == Package::name);
      //
      ////        return this->getName() < package.getName();
      ////        return this->name < package.getName();
      ////        return Package::name < package.getName();
      //        return this->name < package.name;
      ////        return Package::name < package.name;
      //    }
      
      //    bool operator<(Package& package) {
      //        // TODO maybe replace the 'getName()' function with only fields?
      //
      //        assert(this->getName() == this->name);
      //        assert(this->getName() == Package::name);
      //        assert(this->name == Package::name);
      //
      ////        return this->getName() < package.getName();
      ////        return this->name < package.getName();
      ////        return Package::name < package.getName();
      ////        return this->name < package.name;
      //        return Package::name < package.name;
      //    }
      
      //    friend bool operator<(Package& onePackage, Package& anotherPackage) {
      //        return onePackage.name < anotherPackage.name;
      //    }
      
      //    friend bool operator<(const Package& onePackage, const Package& anotherPackage) {
      //        return onePackage.name < anotherPackage.name;
      //    }
      
      //    friend bool operator<(const Package& onePackage, Package& anotherPackage) {
      //        return onePackage.name < anotherPackage.name;
      //    }
      
      //    friend bool operator<(Package& onePackage, const Package& anotherPackage) {
      //        return onePackage.name < anotherPackage.name;
      //    }
      
    • std::binary_search with std::set inicialized with custom comparator as a second template parameter - overloading the default std::less and operator< for comparing and sorting elements of custom type

      std::set<std::unique_ptr<Package>> installedPackages{}; // WORKS - with at least overloaded public friend 'operator<' with all const params of reference type to constant unique_ptr to Package
      
      //std::set<std::unique_ptr<Package, PackageComparator>> installedPackages; // doesn't work - using PackageComparator as a second template argument for 'unique_ptr' as default deleter instead of using it as a second template argument for 'set' as a comparator
      //std::set<std::unique_ptr<Package>, PackageComparator> installedPackages; // WORKS - thanks https://www.codegrepper.com/code-examples/cpp/c%2B%2B+custom+comparator+for+elements+in+set
      
      //auto packageComparator = std::make_unique<PackageComparator>();
      //std::set<std::unique_ptr<Package>, PackageComparator> installedPackages(*packageComparator); // WORKS
      
      //auto packageComparatorLambda = [](const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
      //    return onePackage < anotherPackage;
      //};
      //std::set<std::unique_ptr<Package>, decltype(packageComparatorLambda)> installedPackages(packageComparatorLambda); // WORKS
      
      //std::set<std::unique_ptr<Package>, decltype(comparePackages)*> installedPackages(comparePackages); // WORKS
      //std::set<std::unique_ptr<Package>, decltype(comparePackages)*> installedPackages; // Doesn't work - fails at runtime - Works only for C++20 and newer
      //std::set<std::unique_ptr<Package>, decltype(&comparePackages)> installedPackages(&comparePackages); // WORKS
      //std::set<std::unique_ptr<Package>, decltype(&comparePackages)> installedPackages; // Doesn't work - fails at runtime - Works only for C++20 and newer
      

      It doesn't matter which one of the initializations for std::set I use, the std::binary_search doesn't find anything.

      std::binary_search for std::set works only when the class, that the type of elements in std::set are defined in, has overloaded operator< as a public friend function with all const params of the same type that the elements the std::set holds or with a globally overloaded std::operator< with the same mentioned parameter list

Entire code excerpts

main.cpp ('std::set' initialization with optional comparator initialization excerpts + finding a package)

<~snip~>

    std::set<std::unique_ptr<Package>> installedPackages{};

    std::set<std::unique_ptr<Package, PackageComparator>> installedPackages; // doesn't work - using PackageComparator as a second template argument for 'unique_ptr' as default deleter instead of using it as a second template argument for 'set' as a comparator
    std::set<std::unique_ptr<Package>, PackageComparator> installedPackages; // WORKS - thanks https://www.codegrepper.com/code-examples/cpp/c%2B%2B+custom+comparator+for+elements+in+set

    auto packageComparator = std::make_unique<PackageComparator>();
    std::set<std::unique_ptr<Package>, PackageComparator> installedPackages(*packageComparator); // WORKS

    auto packageComparatorLambda = [](const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
        return onePackage < anotherPackage;
    };
    std::set<std::unique_ptr<Package>, decltype(packageComparatorLambda)> installedPackages(packageComparatorLambda); // WORKS

    std::set<std::unique_ptr<Package>, decltype(comparePackages)*> installedPackages(comparePackages); // WORKS
    std::set<std::unique_ptr<Package>, decltype(comparePackages)*> installedPackages; // Doesn't work - fails at runtime - Works only for C++20 and newer
    std::set<std::unique_ptr<Package>, decltype(&comparePackages)> installedPackages(&comparePackages); // WORKS
    std::set<std::unique_ptr<Package>, decltype(&comparePackages)> installedPackages; // Doesn't work - fails at runtime - Works only for C++20 and newer

    auto packageComparator = std::make_unique<PackageComparator>();
    std::set<std::unique_ptr<Package>> installedPackages(*packageComparator); // still doesn't work

<~snip~>

            std::string inferredPackageNameAsText = packageNameAndVersion;
            auto packageWithInferredName = std::make_unique<Package>(std::move(inferredPackageNameAsText));

            while ( packageWithInferredName->hasStillSomethingInPackageName() ) {
                // search for the matching package element in the 'installedPackages' by 'packageWithInferredName'
                // 'set::find'
                auto matchingPackage = installedPackages.find(packageWithInferredName);

                // 'std::find' (direct and dereferenced comparison in 'operator==' in class for custom element type)
//                auto matchingPackage = std::find(installedPackages.begin(), installedPackages.end(), packageWithInferredName);  // works only with 'friend bool operator==(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage)' in 'Package.h'
//                auto matchingPackage = std::find(installedPackages.begin(), installedPackages.end(), *packageWithInferredName); // works only with 'friend bool operator==(const std::unique_ptr<Package>& onePackage, const Package& anotherPackage)' in 'Package.h'

                // 'std::find_if' with lambda (passing directly) - (direct and dereferenced comparison in lambda)
//                auto matchingPackage = std::find_if(installedPackages.begin(), installedPackages.end(),
//                        [&packageWithInferredName](const std::unique_ptr<Package>& currentInstalledPackage) {
//                            return packageWithInferredName == currentInstalledPackage; // works only with 'friend bool operator==(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage)' in 'Package.h'
////                            return *packageWithInferredName == *currentInstalledPackage; // works with 'friend bool operator==(const Package& onePackage, const Package& anotherPackage)' and 'operator==' const member functions in 'Package.h'
////                            return packageWithInferredName->getName() == currentInstalledPackage->getName();
//                        }
//                );

                // Couldn't make it work
//                auto matchingPackage = std::find_if(installedPackages.begin(), installedPackages.end(),
//                        [&packageWithInferredName](const Package& currentInstalledPackage) {
//                            return packageWithInferredName == *currentInstalledPackage; // works only with 'friend bool operator==(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage)' in 'Package.h'
////                            return *packageWithInferredName == *currentInstalledPackage; // works only with 'friend bool operator==(const Package& onePackage, const Package& anotherPackage)' in 'Package.h'
////                            return packageWithInferredName->getName() == currentInstalledPackage->getName();
//                        }
//                );

                // 'std::find_if' with comparator predicate (directly pass to comparator predicate - direct and dereferenced comparison in comparator predicate)
//                auto matchingPackage = std::find_if(
//                        installedPackages.begin(),
//                        installedPackages.end(),
//                        PackageComparatorPredicate(packageWithInferredName));

                // 'std::find_if' with comparator predicate (pass dereferenced unique ptr to comparator predicate - direct and dereferenced comparison in comparator predicate)
//                auto matchingPackage = std::find_if(
//                        installedPackages.begin(),
//                        installedPackages.end(),
//                        PackageComparatorPredicate(*packageWithInferredName));

                // 'std::any_of' with lambda (direct and dereferenced comparison in lambda)
//                bool isPackageWithInferredNameFoundAsTest = std::any_of(installedPackages.begin(), installedPackages.end(),
//                                                                        [&packageWithInferredName](const std::unique_ptr<Package>& currentInstalledPackage) {
////                            return packageWithInferredName == currentInstalledPackage; // works only with 'friend bool operator==(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage)' in 'Package.h'
////                            return *packageWithInferredName == *currentInstalledPackage; // works only with 'friend bool operator==(const Package& onePackage, const Package& anotherPackage)' in 'Package.h'
//                            return packageWithInferredName->getName() == currentInstalledPackage->getName();
//                        }
//                );

                // 'std::any_of' with comparator predicate (directly pass to comparator predicate - direct and dereferenced comparison in comparator predicate)
//                bool isPackageWithInferredNameFoundAsTest = std::any_of(
//                        installedPackages.begin(),
//                        installedPackages.end(),
//                        PackageComparatorPredicate(packageWithInferredName));

                // 'std::any_of' with comparator predicate (pass dereferenced unique ptr to comparator predicate - direct and dereferenced comparison in comparator predicate)
//                bool isPackageWithInferredNameFoundAsTest = std::any_of(
//                        installedPackages.begin(),
//                        installedPackages.end(),
//                        PackageComparatorPredicate(*packageWithInferredName));

                // 'std::binary_search'
                bool isPackageWithInferredNameFoundAsTest = std::binary_search(installedPackages.begin(), installedPackages.end(), packageWithInferredName);  // WORKS with overloaded public friend 'operator<' with all const args and even with 'installedPackages' set initialized as 'std::set<std::unique_ptr<Package>> installedPackages{};' with only default comparator. Binary search works only on ordered datastructures. The order is attained by the overloaded 'operator<' as a public friend function with all const params, which gets called at insertion to the 'std::set' - `emplace()`/`push_back()`. That's why the lookup actually finds a matching element of custom type in 'std::set'
//                bool isPackageWithInferredNameFoundAsTest = std::binary_search(installedPackages.begin(), installedPackages.end(), packageWithInferredName, PackageComparator());

//                bool isPackageWithInferredNameFoundAsTest = std::binary_search(installedPackages.begin(), installedPackages.end(), *packageWithInferredName);
//                bool isPackageWithInferredNameFoundAsTest = std::binary_search(installedPackages.begin(), installedPackages.end(), *packageWithInferredName, PackageComparator());

                // For debugging purposes - because the gdb debugger in CLion 2022.1 produces an error when
                //  trying to show the values for STL containers and smartpointer instances.
                //  Instead it shows an error message saying "Cannot instantiate printer for default visualizer"
//                std::cout << *packageWithInferredName << "\n";

                // if key was NOT found, strip the coumpound package key by one character - or word  from the end and perform lookup again
                // comment out for 'std::any_of' and 'std::binary_search'
                bool packageWithInferredNameIsMissing = matchingPackage == installedPackages.end();

                bool packageWithInferredNameIsMissingAsTest = !isPackageWithInferredNameFoundAsTest;
                assert(packageWithInferredNameIsMissing == packageWithInferredNameIsMissingAsTest);

<~snip~>
PackageComparator.h

#pragma once

#include "Package.h"

struct PackageComparator {
    bool operator()(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) const {
        // DIRECT COMPARISON - works only with 'friend bool operator<(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage)'
        return onePackage < anotherPackage;

        // DEREFERENCED COMPARISON without accessor method - works with
        //  - 'bool operator<(const Package& package) const'
        //  - 'bool operator<(Package& package)'
        //  - 'friend bool operator<(Package& onePackage, Package& anotherPackage)'
//        return *onePackage < *anotherPackage;

        // DEREFERENCED COMPARISON with accessor method - delegating comparison from 'operator<' functions in this class ('Package') element to compared field within the 'Package' element
        //  which has 'operator<' implemented, leaving the 'Package' class intact. works without overloading 'std::less' in 'Package' class
        //  Works out of the box for 'std::string'.
        //  For custom type at least public friend 'operator<' with all const params needs to be implemented
//        return onePackage->getName() < anotherPackage->getName();
    }
};

//struct PackageComparator {
//    bool operator()(const Package& onePackage, const std::unique_ptr<Package>& anotherPackage) const {
//        // DIRECT COMPARISON - works only with 'friend bool operator<(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage)'
////        return onePackage < anotherPackage;
//
//        // DEREFERENCED COMPARISON without accessor method - works with
//        //  - 'bool operator<(const Package& package) const'
//        //  - 'bool operator<(Package& package)'
//        //  - 'friend bool operator<(Package& onePackage, Package& anotherPackage)'
////        return onePackage < *anotherPackage;
//
//        // DEREFERENCED COMPARISON with accessor method - delegating comparison from 'operator<' functions in this class ('Package') element to compared field within the 'Package' element
//        //  which has 'operator<' implemented, leaving the 'Package' class intact. works without overloading 'std::less' in 'Package' class
//        //  Works out of the box for 'std::string'.
//        //  For custom type at least public friend 'operator<' with all const params needs to be implemented
//        return onePackage.getName() < anotherPackage->getName();
//    }
//
//    bool operator()(const std::unique_ptr<Package>& onePackage, const Package& anotherPackage) const {
//        // DIRECT COMPARISON - works only with 'friend bool operator<(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage)'
////        return onePackage < anotherPackage;
//
//        // DEREFERENCED COMPARISON without accessor method - works with
//        //  - 'bool operator<(const Package& package) const'
//        //  - 'bool operator<(Package& package)'
//        //  - 'friend bool operator<(Package& onePackage, Package& anotherPackage)'
////        return *onePackage < anotherPackage;
//
//        // DEREFERENCED COMPARISON with accessor method - delegating comparison from 'operator<' functions in this class ('Package') element to compared field within the 'Package' element
//        //  which has 'operator<' implemented, leaving the 'Package' class intact. works without overloading 'std::less' in 'Package' class
//        //  Works out of the box for 'std::string'.
//        //  For custom type at least public friend 'operator<' with all const params needs to be implemented
//        return onePackage->getName() < anotherPackage.getName();
//    }
//};


Package.h ('operator<' overloads, 'std::less' specializations and 'operator==' overloads)

<~snip~>

// MEMBER OPERATORS

// FOR DIRECT (SMART) POINTER COMPARISON FOR 'SET::FIND'
//  Functions in this section work for dereferenced comparison together with overloaded 'std::less' funcion for cutom type
//  or with custom comparator without 'std::less' overload
//  except the
//  'friend bool operator<(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage)'
//  which works with and without 'std::less' overload

    // WORKS for direct comparison with and without overloading 'std::less' funcion
//    friend bool operator<(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
//        return onePackage->name < anotherPackage->name;
//    }

    // Doesn't work - compiles but fails to find the searched for element at runtime when used as a standalone function
//    friend bool operator<(std::unique_ptr<Package>& onePackage, std::unique_ptr<Package>& anotherPackage) {
//        return onePackage->name < anotherPackage->name;
//    }

    // Doesn't work - compiles but fails to find the searched for element at runtime
//    bool operator<(const std::unique_ptr<Package>& package) const {
//        // TODO maybe replace the 'getName()' function with only fields?
//
//        assert(this->getName() == this->name);
//        assert(this->getName() == Package::name);
//        assert(this->name == Package::name);
//
//        return this->getName() < package->getName();
//        //        return this->name < package->getName();
//        //        return Package::name < package->getName();
//        //        return this->name < package->name;
//        //        return Package::name < package->name;
//    }

// FOR DIRECT (SMART) POINTER COMPARISON FOR 'STD::FIND', 'STD::FIND_IF' (lambda or predicate comparator), 'STD::ANY_OF' (lambda or predicate comparator)

//   WORKS for direct comparison in 'std::find', 'std::find_if', 'std::any_of'
//    friend bool operator==(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
//        return onePackage->name == anotherPackage->name;
//    }

    // Doesn't work
//    friend bool operator==(std::unique_ptr<Package>& onePackage, std::unique_ptr<Package>& anotherPackage) {
//        return onePackage->name == anotherPackage->name;
//    }

    // Doesn't work
//    bool operator==(const std::unique_ptr<Package>& package) const {
//        // TODO maybe replace the 'getName()' function with only fields?
//        return this->getName() == package->getName();
////        return this->name == package.getName();
////        return this->name < package.name;
////        return Package::name == package.getName();
////        return Package::name == package.name;
//    }

// ------------------------------------------------------------------------------------------------
// ================================================================================================
// ------------------------------------------------------------------------------------------------

// FOR DEREFERENCED (SMART) POINTER COMPARISON FOR 'SET::FIND'
//  Functions in this section work for dereferenced comparison together with overloaded 'std::less' funcion for cutom type
//  or with custom comparator without 'std::less' overload,
//  but I couldn't make the element lookup work for 'std::binary_search'

//    bool operator<(const Package& package) const {
//        // TODO maybe replace the 'getName()' function with only fields?
//
//        assert(this->getName() == this->name);
//        assert(this->getName() == Package::name);
//        assert(this->name == Package::name);
//
//        return this->getName() < package.getName();
////        return this->name < package.getName();
////        return Package::name < package.getName();
////        return this->name < package.name;
////        return Package::name < package.name;
//    }

//    bool operator<(const Package& package) {
//        // TODO maybe replace the 'getName()' function with only fields?
//
//        assert(this->getName() == this->name);
//        assert(this->getName() == Package::name);
//        assert(this->name == Package::name);
//
////        return this->getName() < package.getName();
//        return this->name < package.getName();
////        return Package::name < package.getName();
////        return this->name < package.name;
////        return Package::name < package.name;
//    }

//    bool operator<(Package& package) const {
//        // TODO maybe replace the 'getName()' function with only fields?
//
//        assert(this->getName() == this->name);
//        assert(this->getName() == Package::name);
//        assert(this->name == Package::name);
//
////        return this->getName() < package.getName();
////        return this->name < package.getName();
////        return Package::name < package.getName();
//        return this->name < package.name;
////        return Package::name < package.name;
//    }

//    bool operator<(Package& package) {
//        // TODO maybe replace the 'getName()' function with only fields?
//
//        assert(this->getName() == this->name);
//        assert(this->getName() == Package::name);
//        assert(this->name == Package::name);
//
////        return this->getName() < package.getName();
////        return this->name < package.getName();
////        return Package::name < package.getName();
////        return this->name < package.name;
//        return Package::name < package.name;
//    }

//    friend bool operator<(Package& onePackage, Package& anotherPackage) {
//        return onePackage.name < anotherPackage.name;
//    }

//    friend bool operator<(const Package& onePackage, const Package& anotherPackage) {
//        return onePackage.name < anotherPackage.name;
//    }

//    friend bool operator<(const Package& onePackage, Package& anotherPackage) {
//        return onePackage.name < anotherPackage.name;
//    }

//    friend bool operator<(Package& onePackage, const Package& anotherPackage) {
//        return onePackage.name < anotherPackage.name;
//    }

// FOR 'STD::BINARY_SEARCH' WITH PASSED DEREFERENCED SMART POINTER - COULDN'T MAKE IT WORK

    // for 'stl_algo.h'
//    friend bool operator<(const Package& onePackage, const std::unique_ptr<Package>& anotherPackage) {
//        return onePackage.name < anotherPackage->name;
//    }
//
//    // for 'predefined_ops.h'
//    friend bool operator<(const std::unique_ptr<Package>& onePackage, const Package& anotherPackage) {
//        return onePackage->name < anotherPackage.name;
//    }

// FOR DEREFERENCED (SMART) POINTER COMPARISON FOR 'STD::FIND'

    // WORKS only for 'std::find'
//    friend bool operator==(const std::unique_ptr<Package>& onePackage, const Package& anotherPackage) {
//        return onePackage->name == anotherPackage.name;
//    }

    // Doesn't work - error: no match for ‘operator==’ (operand types are ‘const std::unique_ptr<Package>’ and ‘const Package’)
//    friend bool operator==(std::unique_ptr<Package>& onePackage, Package& anotherPackage) {
//        return onePackage->name == anotherPackage.name;
//    }

    // Doesn't work - error: no match for ‘operator==’ (operand types are ‘const std::unique_ptr<Package>’ and ‘const Package’)
//    bool operator==(const Package& otherPackage) const {
//        return this->name == otherPackage.name;
//    }

    // Doesn't work - error: no match for ‘operator==’ (operand types are ‘const std::unique_ptr<Package>’ and ‘const Package’)
//    bool operator==(Package& otherPackage) {
//        return this->name == otherPackage.name;
//    }

// FOR DEREFERENCED (SMART) POINTER COMPARISON FOR LAMBDA COMPARATOR OR PREDICATE COMPARATOR FOR 'STD::FIND_IF', 'STD::ANY_OF' WITH SEARCHED ELEMENT PASSED DIRECTLY

    // WORKS
    // ... but doesn't work for 'std::find'  - error: no match for ‘operator==’ (operand types are ‘const std::unique_ptr<Package>’ and ‘const Package’)
//    friend bool operator==(const Package& onePackage, const Package& anotherPackage) {
//        return onePackage.name == anotherPackage.name;
//    }

    // WORKS - the exact candidate function for comparison with comparator predicate with dereferenced comparison with '*'
//    friend bool operator==(const Package& onePackage, Package& anotherPackage) {
//        return onePackage.name == anotherPackage.name;
//    }

    // Doesn't work - 'error: binding reference of type ‘Package&’ to ‘const Package’ discards qualifiers'
//    friend bool operator==(Package& onePackage, const Package& anotherPackage) {
//        return onePackage.name == anotherPackage.name;
//    }

    // Doesn't work for passing searched element to the comparator predicate as dereferenced smart pointer and comparing them directly
    //  - error: passing ‘const Package’ as ‘this’ argument discards qualifiers [-fpermissive]
//    friend bool operator==(Package& onePackage, Package& anotherPackage) {
//        return onePackage.name == anotherPackage.name;
//    }

    // WORKS
//    bool operator==(const Package& otherPackage) const {
//        return this->name == otherPackage.name;
//    }

//    // Doesn't work - 'error: passing ‘const Package’ as ‘this’ argument discards qualifiers [-fpermissive]'
//    bool operator==(const Package& otherPackage) {
//        return this->name == otherPackage.name;
//    }

    // WORKS
//    bool operator==(Package& otherPackage) const {
//        return this->name == otherPackage.name;
//    }

    // Doesn't work for passing searched element to the comparator predicate as dereferenced smart pointer and comparing them directly
    //  - error: passing ‘const Package’ as ‘this’ argument discards qualifiers [-fpermissive]
//    bool operator==(Package& otherPackage) {
//        return this->name == otherPackage.name;
//    }

// FOR DEREFERENCED (SMART) POINTER COMPARISON FOR LAMBDA COMPARATOR OR PREDICATE COMPARATOR FOR 'STD::FIND_IF', 'STD::ANY_OF' WITH SEARCHED ELEMENT PASSED AS ALREADY DEREFERENCED

    // WORKS for comparing dereferenced smart pointer (i.e. the instance) with directly passed smart pointer in the comparator predicate
//    friend bool operator==(const Package& onePackage, const std::unique_ptr<Package>& anotherPackage) {
//        return onePackage->name == anotherPackage.name;
//    }

    // Doesn't work
    //  - error: no match for ‘operator==’ (operand types are ‘const Package’ and ‘const std::unique_ptr<Package>’) - missing 'const' for all parameters of function
    //  - PackageComparatorPredicate.h:51:33: error: binding reference of type ‘std::unique_ptr<Package>&’ to ‘const std::unique_ptr<Package>’ discards qualifiers
//    friend bool operator==(Package& anotherPackage, std::unique_ptr<Package>& onePackage) {
//        return onePackage->name == anotherPackage.name;
//    }

    // Doesn't work
    //  - error: no match for ‘operator==’ (operand types are ‘const Package’ and ‘const std::unique_ptr<Package>’) - missing 'const' for all parameters of function
//    friend bool operator==(const Package& anotherPackage, std::unique_ptr<Package>& onePackage) {
//        return onePackage->name == anotherPackage.name;
//    }

    // Doesn't work
    //  - error: no match for ‘operator==’ (operand types are ‘const Package’ and ‘const std::unique_ptr<Package>’) - missing 'const' for all parameters of function
//    friend bool operator==(Package& anotherPackage, const std::unique_ptr<Package>& onePackage) {
//        return onePackage->name == anotherPackage.name;
//    }

    // WORKS for comparing dereferenced smart pointer (i.e. the instance) with directly passed smart pointer in the comparator predicate
//    bool operator==(const std::unique_ptr<Package>& otherPackage) const {
//        return this->name == otherPackage->name;
//    }

    // Doesn't work - ‘const Package’ is not derived from ‘const std::pair<_T1, _T2>’
    //  the function needs to be 'const'
//    bool operator==(const std::unique_ptr<Package>& otherPackage) {
//        return this->name == otherPackage->name;
//    }

    // Doesn't work - ‘const Package’ is not derived from ‘const std::pair<_T1, _T2>’
    //  the operand needs to be 'const'
//    bool operator==(std::unique_ptr<Package>& otherPackage) const {
//        return this->name == otherPackage->name;
//    }

    // Doesn't work - missing 'const' for parameter
    //  - error: no match for ‘operator==’ (operand types are ‘const Package’ and ‘const std::unique_ptr<Package>’)
    //  - PackageComparatorPredicate.h:51:33: error: binding reference of type ‘std::unique_ptr<Package>&’ to ‘const std::unique_ptr<Package>’ discards qualifiers
//    bool operator==(std::unique_ptr<Package>& otherPackage) {
//        return this->name == otherPackage->name;
//    }

<~snip~>

// NON-MEMBER OPERATORS/COMPARATORS - OVERLOADED/SPECIALIZED FUNCTIONS/FUNCTORS FROM 'STD'

// DIRECT COMPARISON WITH SPECIALIZED 'STD::LESS' FUNCTOR FOR 'SET::FIND'

// overload the 'less' functor in order to enable lookup ('find') in a 'set' or a 'map' with instances of this class as a key, or with any custom object-type key
//namespace std {
//    template<>
//    struct less<unique_ptr<Package>> {
//        bool operator() (const unique_ptr<Package>& onePackage, const unique_ptr<Package>& anotherPackage) const {
//            return onePackage < anotherPackage;
//        }
//    };
//}

// DEREFERENCED COMPARISON WITH SPECIALIZED 'STD::LESS' FUNCTOR FOR 'SET::FIND'

// overload the 'less' functor in order to enable lookup ('find') in a 'set' or a 'map' with instances of this class as a key, or with any custom object-type key
//namespace std {
//    template<>
//    struct less<unique_ptr<Package>> {
//        bool operator() (const unique_ptr<Package>& onePackage, const unique_ptr<Package>& anotherPackage) const {
//            return onePackage->getName() < anotherPackage->getName();
//        }
//    };
//}

// overload the 'less' functor in order to enable lookup ('find') in a 'set' or a 'map' with instances of this class as a key, or with any custom object-type key
//namespace std {
//    template<>
//    struct less<unique_ptr<Package>> {
//        bool operator() (const unique_ptr<Package>& onePackage, const unique_ptr<Package>& anotherPackage) const {
//            return *onePackage < *anotherPackage;
//        }
//    };
//}

// 'STD::FIND', 'STD::FIND_IF' - DIRECTLY PASSING AN UNIQUE POINTER

//namespace std {
//    inline bool operator==(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
//        return onePackage->getName() == anotherPackage->getName();
//    }
//}

// 'STD::FIND' - PASSING A DEREFERENCED UNIQUE POINTER - DOESN'T WORK FOR 'STD::FIND_IF' with dereferenced unique ptr comparison

//namespace std {
//    inline bool operator==(const std::unique_ptr<Package>& onePackage, const Package& anotherPackage) {
//        return onePackage->getName() == anotherPackage.getName();
//    }
//}

// 'STD::FIND_IF' - DIRECTLY PASSING A UNIQUE POINTER - DOESN'T WORK FOR COMPARATOR PREDICATE WITH DEREFERENCED COMPARISON
//   error: no match for ‘operator==’ (operand types are ‘Package’ and ‘Package’)

//namespace std {
//    inline bool operator==(const Package& onePackage, const Package& anotherPackage) {
//        return onePackage.getName() == anotherPackage.getName();
//    }
//}

// 'STD::FIND_IF' - PASSING A DEREFERENCED UNIQUE POINTER - DIRECT COMPARISON

//namespace std {
//    inline bool operator==(const Package& onePackage, const std::unique_ptr<Package>& anotherPackage) {
//        return onePackage->getName() == anotherPackage.getName();
//    }
//}

// 'STD::FIND_IF' - PASSING A DEREFERENCED UNIQUE POINTER - DEREFERENCED COMPARISON WITH '*' - DOESN'T WORK

//namespace std {
//    inline bool operator==(const Package& onePackage, Package& anotherPackage) {
//        return onePackage.getName() == anotherPackage.getName();
//    }
//}

// 'SET::FIND', 'STD::BINARY_SEARCH' - DIRECTLY PASSING AN UNIQUE POINTER

namespace std {
    inline bool operator<(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
        return onePackage->getName() < anotherPackage->getName();
    }
}

//namespace std {
//    inline bool operator<(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
//        return *onePackage < *anotherPackage;
//    }
//}

// 'SET::FIND' - DIRECTLY PASSING AN UNIQUE POINTER - DEREFERENCED COMPARISON IN COMPARATOR - COULDN'T MAKE IT WORK

//namespace std {
//    inline bool operator<(const Package& onePackage, Package& anotherPackage) {
//        return onePackage.getName() == anotherPackage.getName();
//    }
//}

// 'STD::BINARY_SEARCH' - PASSING A DEREFERENCED UNIQUE POINTER

//namespace std {
//    inline bool operator<(const Package& onePackage, const std::unique_ptr<Package>& anotherPackage) {
//        return onePackage.getName() < anotherPackage->getName();
//    }
//}
//
//namespace std {
//    inline bool operator<(const std::unique_ptr<Package>& onePackage, const Package& anotherPackage) {
//        return onePackage->getName() < anotherPackage.getName();
//    }
//}

// LAMBDA COMPARATOR FOR SECOND TEMPLATE PARAMETER

//inline bool comparePackages(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage) {
//    return onePackage < anotherPackage;
//}
PackageComparatorPredicate.h

#pragma once

#include "Package.h"

// using Predicate instead (reusable; no modification of the compared class)

// FOR PASSING SMART POINTER TO COMPARATOR PREDICATE DIRECTLY

struct PackageComparatorPredicate {
    const std::unique_ptr<Package>& package;

    explicit PackageComparatorPredicate(const std::unique_ptr<Package>& packageToFind) :
            package(packageToFind)
    {}

    bool operator()(const std::unique_ptr<Package>& otherPackage) const {
        // DIRECT COMPARISON - works only with 'friend bool operator==(const std::unique_ptr<Package>& onePackage, const std::unique_ptr<Package>& anotherPackage)'
        return (this->package == otherPackage);

        // DEREFERENCED COMPARISON without accessor method - works with
        //  - 'friend bool operator==(Package& onePackage, Package& anotherPackage)' (with/without const for parameters)
        //  - and member function 'bool operator==(Package& otherPackage)' (with/without const for function/parameters)
//        return (*(this->package) == *otherPackage);

        // DEREFERENCED COMPARISON with accessor method - delegating comparison from 'Package' element to compared field within the 'Package' element
//        return (this->package->getName() == otherPackage->getName());
    }
};

// FOR PASSING DEREFERENCED SMART POINTER TO COMPARATOR PREDICATE

//struct PackageComparatorPredicate {
//    const Package& package;
//
//    explicit PackageComparatorPredicate(const Package& packageToFind) :
//            package(packageToFind)
//    {}
//
//    bool operator()(const std::unique_ptr<Package>& otherPackage) const {
//        // COMPARISON OF SEARCHED DEREFERENCED MEMBER VARIABLE WITH SMART POINTER
//        //  - works with 'friend bool operator==(Package& onePackage, std::unique_ptr<Package>& anotherPackage)'
////        return this->package == otherPackage;
//
//        // COMPARISON OF MEMBER VARIABLE REFERENCE WITH DEREFERENCED SMART POINTER
//        //  - 'friend bool operator==(Package& onePackage, Package& anotherPackage)' (with/without const for parameters)
//        //  - and member function 'bool operator==(Package& otherPackage)' (with/without const for function/parameters)
////        return (this->package == *otherPackage);
//
//        // DEREFERENCED COMPARISON with accessor method - delegating comparison from 'Package' element to compared field within the 'Package' element
//        return (this->package.getName() == otherPackage->getName());
//    }
//};

Ressurection merge log

[laptop@laptop clean_pacman_cache_dir]$ git status
On branch encapsulate_container_variables_to_separate_classes
Your branch is up to date with 'origin/encapsulate_container_variables_to_separate_classes'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   clean_pacman_cache_dir-class_diagram.puml

no changes added to commit (use "git add" and/or "git commit -a")
[laptop@laptop clean_pacman_cache_dir]$ git branch
  backport-encapsulate_ignored_package_name_to_class
  backport-fix_for_package_from_inferred_name
  backport-fix_for_partially_downloaded_package_file
  backports
* encapsulate_container_variables_to_separate_classes
  encapsulate_relating_package_files_to_packages
  find_element_of_custom_type_in_set
  main
  packageVersion_from_string_to_PackageVersion
  refactoring_Package_class
[laptop@laptop clean_pacman_cache_dir]$ git status
On branch encapsulate_container_variables_to_separate_classes
Your branch is up to date with 'origin/encapsulate_container_variables_to_separate_classes'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   clean_pacman_cache_dir-class_diagram.puml

no changes added to commit (use "git add" and/or "git commit -a")
[laptop@laptop clean_pacman_cache_dir]$ git status
On branch encapsulate_container_variables_to_separate_classes
Your branch is up to date with 'origin/encapsulate_container_variables_to_separate_classes'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   clean_pacman_cache_dir-class_diagram.puml

no changes added to commit (use "git add" and/or "git commit -a")
[laptop@laptop clean_pacman_cache_dir]$ git add -A
[laptop@laptop clean_pacman_cache_dir]$ git commit -m "Update relationships in UML class diagram"
[encapsulate_container_variables_to_separate_classes 92bd00e] Update relationships in UML class diagram
 1 file changed, 62 insertions(+), 60 deletions(-)
[laptop@laptop clean_pacman_cache_dir]$ git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 2 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 784 bytes | 784.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To github.com:kyberdrb/clean_pacman_cache_dir.git
   2905f8b..92bd00e  encapsulate_container_variables_to_separate_classes -> encapsulate_container_variables_to_separate_classes
[laptop@laptop clean_pacman_cache_dir]$ cm
cmake       cmake-gui   cmp         cmsutil     cmuwmtopbm  cmx2raw     cmx2text    cmx2xhtml
[laptop@laptop clean_pacman_cache_dir]$ ls
cmake-build-debug
cmake-build-release
AbsolutePath.cpp
AbsolutePath.h
clean_pacman_cache_dir-class_diagram.puml
clean_pacman_cache_dir.drawio
clean_pacman_cache_dir.drawio.png
CMakeLists.txt
ExtendedInstallationPackageFile.cpp
ExtendedInstallationPackageFile.h
FileMover.cpp
FileMover.h
Filename.cpp
Filename.h
IgnoredPackageNameComparatorPredicate.h
IgnoredPackageName.cpp
IgnoredPackageName.h
IgnoredPackageNames.cpp
IgnoredPackageNames.h
LICENSE
LocallyInstalledPackage.cpp
LocallyInstalledPackage.h
LocallyInstalledPackages.cpp
LocallyInstalledPackages.h
main.cpp
MatchFinderForPackageFilesToLocallyInstalledPackages.cpp
MatchFinderForPackageFilesToLocallyInstalledPackages.h
MoverOfInstallationPackageFiles.cpp
MoverOfInstallationPackageFiles.h
Package.cpp
Package.h
PackageNameAndVersion.cpp
PackageNameAndVersion.h
PackageName.cpp
PackageName.h
PackageNameMissing.cpp
PackageNameMissing.h
PackageVersion.cpp
PackageVersion.h
PackageWithInferredName.cpp
PackageWithInferredName.h
README.md
Refactoring_Package_due_to_using_a_subset_of_features_for_packageWithInferredName_of_original_Package_type_and_initializing_the_rest_to_undefined_values-Class_diagram.puml
Refactoring_PackageFile_due_to_referencing_of_member_variable_to_temporary_value-Class_diagram.puml
SimpleInstallationPackageFile.cpp
SimpleInstallationPackageFile.h
SimpleInstallationPackageFileType.h
[laptop@laptop clean_pacman_cache_dir]$ git status
On branch encapsulate_container_variables_to_separate_classes
Your branch is up to date with 'origin/encapsulate_container_variables_to_separate_classes'.

nothing to commit, working tree clean
[laptop@laptop clean_pacman_cache_dir]$ git branch
  backport-encapsulate_ignored_package_name_to_class
  backport-fix_for_package_from_inferred_name
  backport-fix_for_partially_downloaded_package_file
  backports
* encapsulate_container_variables_to_separate_classes
  encapsulate_relating_package_files_to_packages
  find_element_of_custom_type_in_set
  main
  packageVersion_from_string_to_PackageVersion
  refactoring_Package_class
[laptop@laptop clean_pacman_cache_dir]$ git status
On branch encapsulate_container_variables_to_separate_classes
Your branch is up to date with 'origin/encapsulate_container_variables_to_separate_classes'.

nothing to commit, working tree clean
[laptop@laptop clean_pacman_cache_dir]$ man cmake
[laptop@laptop clean_pacman_cache_dir]$ git status
On branch encapsulate_container_variables_to_separate_classes
Your branch is up to date with 'origin/encapsulate_container_variables_to_separate_classes'.

nothing to commit, working tree clean
[laptop@laptop clean_pacman_cache_dir]$ git branch
  backport-encapsulate_ignored_package_name_to_class
  backport-fix_for_package_from_inferred_name
  backport-fix_for_partially_downloaded_package_file
  backports
* encapsulate_container_variables_to_separate_classes
  encapsulate_relating_package_files_to_packages
  find_element_of_custom_type_in_set
  main
  packageVersion_from_string_to_PackageVersion
  refactoring_Package_class
[laptop@laptop clean_pacman_cache_dir]$ git status
On branch encapsulate_container_variables_to_separate_classes
Your branch is up to date with 'origin/encapsulate_container_variables_to_separate_classes'.

nothing to commit, working tree clean
[laptop@laptop clean_pacman_cache_dir]$ git branc
git: 'branc' is not a git command. See 'git --help'.
[laptop@laptop clean_pacman_cache_dir]$ git branch
  backport-encapsulate_ignored_package_name_to_class
  backport-fix_for_package_from_inferred_name
  backport-fix_for_partially_downloaded_package_file
  backports
* encapsulate_container_variables_to_separate_classes
  encapsulate_relating_package_files_to_packages
  find_element_of_custom_type_in_set
  main
  packageVersion_from_string_to_PackageVersion
  refactoring_Package_class
[laptop@laptop clean_pacman_cache_dir]$ git checkout backports
Switched to branch 'backports'
Your branch is up to date with 'origin/backports'.
[laptop@laptop clean_pacman_cache_dir]$ git status
On branch backports
Your branch is up to date with 'origin/backports'.

nothing to commit, working tree clean
[laptop@laptop clean_pacman_cache_dir]$ git pull
Already up to date.
[laptop@laptop clean_pacman_cache_dir]$ git merge --no-ff encapsulate_container_variables_to_separate_classes --message="Encapsulate container variables to separate classes"
Merge made by the 'ort' strategy.
 CMakeLists.txt                                           |   2 +-
 FileMover.cpp                                            |   6 +-
 IgnoredPackageNameComparatorPredicate.h                  |  22 +++++++
 IgnoredPackageNames.cpp                                  |  70 ++++++++++++++++++++++
 IgnoredPackageNames.h                                    |  22 +++++++
 LocallyInstalledPackage.cpp                              |   4 +-
 LocallyInstalledPackage.h                                |  23 ++++++--
 LocallyInstalledPackages.cpp                             | 143 +++++++++++++++++++++++++++++++++++++++++++++
 LocallyInstalledPackages.h                               |  49 ++++++++++++++++
 MatchFinderForPackageFilesToLocallyInstalledPackages.cpp | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 MatchFinderForPackageFilesToLocallyInstalledPackages.h   |  26 +++++++++
 MoverOfInstallationPackageFiles.cpp                      |  31 ++++++++++
 MoverOfInstallationPackageFiles.h                        |  22 +++++++
 Package.h                                                |   8 ---
 PackageNameMissing.cpp                                   |  13 +++++
 PackageNameMissing.h                                     |  23 ++++++++
 PackageWithInferredName.cpp                              |   2 +-
 PackageWithInferredName.h                                |   8 +--
 README.md                                                |  19 +++++-
 clean_pacman_cache_dir-class_diagram.puml                | 211 +++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
 main.cpp                                                 | 343 +++++++++--------------------------------------------------------------------------------------------------
 21 files changed, 838 insertions(+), 385 deletions(-)
 create mode 100644 IgnoredPackageNameComparatorPredicate.h
 create mode 100644 IgnoredPackageNames.cpp
 create mode 100644 IgnoredPackageNames.h
 create mode 100644 LocallyInstalledPackages.cpp
 create mode 100644 LocallyInstalledPackages.h
 create mode 100644 MatchFinderForPackageFilesToLocallyInstalledPackages.cpp
 create mode 100644 MatchFinderForPackageFilesToLocallyInstalledPackages.h
 create mode 100644 MoverOfInstallationPackageFiles.cpp
 create mode 100644 MoverOfInstallationPackageFiles.h
 create mode 100644 PackageNameMissing.cpp
 create mode 100644 PackageNameMissing.h
[laptop@laptop clean_pacman_cache_dir]$ git status
On branch backports
Your branch is ahead of 'origin/backports' by 10 commits.
  (use "git push" to publish your local commits)

nothing to commit, working tree clean
[laptop@laptop clean_pacman_cache_dir]$ git push
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 234 bytes | 234.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
To github.com:kyberdrb/clean_pacman_cache_dir.git
   ca15638..9ad61b8  backports -> backports
[laptop@laptop clean_pacman_cache_dir]$ git status
On branch backports
Your branch is up to date with 'origin/backports'.

nothing to commit, working tree clean
[laptop@laptop clean_pacman_cache_dir]$ git pull
Already up to date.
[laptop@laptop clean_pacman_cache_dir]$
[laptop@laptop clean_pacman_cache_dir]$
[laptop@laptop clean_pacman_cache_dir]$
[laptop@laptop clean_pacman_cache_dir]$ git status
On branch backports
Your branch is up to date with 'origin/backports'.

nothing to commit, working tree clean
[laptop@laptop clean_pacman_cache_dir]$ git branch
  backport-encapsulate_ignored_package_name_to_class
  backport-fix_for_package_from_inferred_name
  backport-fix_for_partially_downloaded_package_file
* backports
  encapsulate_container_variables_to_separate_classes
  encapsulate_relating_package_files_to_packages
  find_element_of_custom_type_in_set
  main
  packageVersion_from_string_to_PackageVersion
  refactoring_Package_class
[laptop@laptop clean_pacman_cache_dir]$ git checkout main
Switched to branch 'main'
Your branch is up to date with 'origin/main'.
[laptop@laptop clean_pacman_cache_dir]$ git status
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean
[laptop@laptop clean_pacman_cache_dir]$ git pull
Already up to date.
[laptop@laptop clean_pacman_cache_dir]$ git tag
1.0.0
1.0.1
2.0.0
2.0.1
2.1.0
2.2.0
2.3.1
2.3.2
2.3.3
2.3.4
2.3.5
2.3.6
[laptop@laptop clean_pacman_cache_dir]$ git branch
  backport-encapsulate_ignored_package_name_to_class
  backport-fix_for_package_from_inferred_name
  backport-fix_for_partially_downloaded_package_file
  backports
  encapsulate_container_variables_to_separate_classes
  encapsulate_relating_package_files_to_packages
  find_element_of_custom_type_in_set
* main
  packageVersion_from_string_to_PackageVersion
  refactoring_Package_class
[laptop@laptop clean_pacman_cache_dir]$ git pull
Already up to date.
[laptop@laptop clean_pacman_cache_dir]$ git merge --no-ff backports --message="Encapsulate container variables to separate classes"
Auto-merging CMakeLists.txt
CONFLICT (content): Merge conflict in CMakeLists.txt
Auto-merging IgnoredPackageNames.cpp
CONFLICT (add/add): Merge conflict in IgnoredPackageNames.cpp
Auto-merging IgnoredPackageNames.h
CONFLICT (add/add): Merge conflict in IgnoredPackageNames.h
Auto-merging LocallyInstalledPackages.cpp
CONFLICT (add/add): Merge conflict in LocallyInstalledPackages.cpp
Auto-merging LocallyInstalledPackages.h
CONFLICT (add/add): Merge conflict in LocallyInstalledPackages.h
Auto-merging Package.cpp
CONFLICT (content): Merge conflict in Package.cpp
Auto-merging Package.h
CONFLICT (content): Merge conflict in Package.h
CONFLICT (modify/delete): PackageFile.cpp deleted in backports and modified in HEAD.  Version HEAD of PackageFile.cpp left in tree.
CONFLICT (modify/delete): PackageFile.h deleted in backports and modified in HEAD.  Version HEAD of PackageFile.h left in tree.
Auto-merging PackageName.cpp
CONFLICT (add/add): Merge conflict in PackageName.cpp
Auto-merging PackageName.h
CONFLICT (add/add): Merge conflict in PackageName.h
Auto-merging PackageVersion.cpp
CONFLICT (add/add): Merge conflict in PackageVersion.cpp
Auto-merging PackageVersion.h
CONFLICT (add/add): Merge conflict in PackageVersion.h
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Auto-merging main.cpp
CONFLICT (content): Merge conflict in main.cpp
Automatic merge failed; fix conflicts and then commit the result.
[laptop@laptop clean_pacman_cache_dir]$ git status
On branch main
Your branch is up to date with 'origin/main'.

You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Changes to be committed:
	new file:   AbsolutePath.cpp
	new file:   AbsolutePath.h
	new file:   ExtendedInstallationPackageFile.cpp
	new file:   ExtendedInstallationPackageFile.h
	new file:   FileMover.cpp
	new file:   FileMover.h
	new file:   Filename.cpp
	new file:   Filename.h
	new file:   IgnoredPackageName.cpp
	new file:   IgnoredPackageName.h
	new file:   IgnoredPackageNameComparatorPredicate.h
	new file:   LICENSE
	new file:   LocallyInstalledPackage.cpp
	new file:   LocallyInstalledPackage.h
	new file:   MatchFinderForPackageFilesToLocallyInstalledPackages.cpp
	new file:   MatchFinderForPackageFilesToLocallyInstalledPackages.h
	new file:   MoverOfInstallationPackageFiles.cpp
	new file:   MoverOfInstallationPackageFiles.h
	new file:   PackageNameAndVersion.cpp
	new file:   PackageNameAndVersion.h
	new file:   PackageNameMissing.cpp
	new file:   PackageNameMissing.h
	new file:   PackageWithInferredName.cpp
	new file:   PackageWithInferredName.h
	new file:   Refactoring_PackageFile_due_to_referencing_of_member_variable_to_temporary_value-Class_diagram.puml
	new file:   Refactoring_Package_due_to_using_a_subset_of_features_for_packageWithInferredName_of_original_Package_type_and_initializing_the_rest_to_undefined_values-Class_diagram.puml
	new file:   SimpleInstallationPackageFile.cpp
	new file:   SimpleInstallationPackageFile.h
	new file:   SimpleInstallationPackageFileType.h
	new file:   clean_pacman_cache_dir-class_diagram.puml
	new file:   clean_pacman_cache_dir.drawio
	new file:   clean_pacman_cache_dir.drawio.png

Unmerged paths:
  (use "git add/rm <file>..." as appropriate to mark resolution)
	both modified:   CMakeLists.txt
	both added:      IgnoredPackageNames.cpp
	both added:      IgnoredPackageNames.h
	both added:      LocallyInstalledPackages.cpp
	both added:      LocallyInstalledPackages.h
	both modified:   Package.cpp
	both modified:   Package.h
	deleted by them: PackageFile.cpp
	deleted by them: PackageFile.h
	both added:      PackageName.cpp
	both added:      PackageName.h
	both added:      PackageVersion.cpp
	both added:      PackageVersion.h
	both modified:   README.md
	both modified:   main.cpp

[laptop@laptop clean_pacman_cache_dir]$ pwd
/home/laptop/git/kyberdrb/clean_pacman_cache_dir
[laptop@laptop clean_pacman_cache_dir]$ ls -l PackageFile.cpp
-rw-r--r-- 1 laptop users 870 Jul  5 00:31 PackageFile.cpp
[laptop@laptop clean_pacman_cache_dir]$ gio trash PackageFile.cpp PackageFile.h
[laptop@laptop clean_pacman_cache_dir]$
[laptop@laptop clean_pacman_cache_dir]$
[laptop@laptop clean_pacman_cache_dir]$
[laptop@laptop clean_pacman_cache_dir]$ git status
On branch main
Your branch is up to date with 'origin/main'.

You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Changes to be committed:
	new file:   AbsolutePath.cpp
	new file:   AbsolutePath.h
	new file:   ExtendedInstallationPackageFile.cpp
	new file:   ExtendedInstallationPackageFile.h
	new file:   FileMover.cpp
	new file:   FileMover.h
	new file:   Filename.cpp
	new file:   Filename.h
	new file:   IgnoredPackageName.cpp
	new file:   IgnoredPackageName.h
	new file:   IgnoredPackageNameComparatorPredicate.h
	new file:   LICENSE
	new file:   LocallyInstalledPackage.cpp
	new file:   LocallyInstalledPackage.h
	new file:   MatchFinderForPackageFilesToLocallyInstalledPackages.cpp
	new file:   MatchFinderForPackageFilesToLocallyInstalledPackages.h
	new file:   MoverOfInstallationPackageFiles.cpp
	new file:   MoverOfInstallationPackageFiles.h
	new file:   PackageNameAndVersion.cpp
	new file:   PackageNameAndVersion.h
	new file:   PackageNameMissing.cpp
	new file:   PackageNameMissing.h
	new file:   PackageWithInferredName.cpp
	new file:   PackageWithInferredName.h
	new file:   Refactoring_PackageFile_due_to_referencing_of_member_variable_to_temporary_value-Class_diagram.puml
	new file:   Refactoring_Package_due_to_using_a_subset_of_features_for_packageWithInferredName_of_original_Package_type_and_initializing_the_rest_to_undefined_values-Class_diagram.puml
	new file:   SimpleInstallationPackageFile.cpp
	new file:   SimpleInstallationPackageFile.h
	new file:   SimpleInstallationPackageFileType.h
	new file:   clean_pacman_cache_dir-class_diagram.puml
	new file:   clean_pacman_cache_dir.drawio
	new file:   clean_pacman_cache_dir.drawio.png

Unmerged paths:
  (use "git add/rm <file>..." as appropriate to mark resolution)
	both modified:   CMakeLists.txt
	both added:      IgnoredPackageNames.cpp
	both added:      IgnoredPackageNames.h
	both added:      LocallyInstalledPackages.cpp
	both added:      LocallyInstalledPackages.h
	both modified:   Package.cpp
	both modified:   Package.h
	deleted by them: PackageFile.cpp
	deleted by them: PackageFile.h
	both added:      PackageName.cpp
	both added:      PackageName.h
	both added:      PackageVersion.cpp
	both added:      PackageVersion.h
	both modified:   README.md
	both modified:   main.cpp

[laptop@laptop clean_pacman_cache_dir]$ git add --all
[laptop@laptop clean_pacman_cache_dir]$
[laptop@laptop clean_pacman_cache_dir]$
[laptop@laptop clean_pacman_cache_dir]$ git status
On branch main
Your branch is up to date with 'origin/main'.

All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:
	new file:   AbsolutePath.cpp
	new file:   AbsolutePath.h
	modified:   CMakeLists.txt
	new file:   ExtendedInstallationPackageFile.cpp
	new file:   ExtendedInstallationPackageFile.h
	new file:   FileMover.cpp
	new file:   FileMover.h
	new file:   Filename.cpp
	new file:   Filename.h
	new file:   IgnoredPackageName.cpp
	new file:   IgnoredPackageName.h
	new file:   IgnoredPackageNameComparatorPredicate.h
	modified:   IgnoredPackageNames.cpp
	modified:   IgnoredPackageNames.h
	new file:   LICENSE
	new file:   LocallyInstalledPackage.cpp
	new file:   LocallyInstalledPackage.h
	modified:   LocallyInstalledPackages.cpp
	modified:   LocallyInstalledPackages.h
	new file:   MatchFinderForPackageFilesToLocallyInstalledPackages.cpp
	new file:   MatchFinderForPackageFilesToLocallyInstalledPackages.h
	new file:   MoverOfInstallationPackageFiles.cpp
	new file:   MoverOfInstallationPackageFiles.h
	modified:   Package.cpp
	modified:   Package.h
	deleted:    PackageFile.cpp
	deleted:    PackageFile.h
	modified:   PackageName.cpp
	modified:   PackageName.h
	new file:   PackageNameAndVersion.cpp
	new file:   PackageNameAndVersion.h
	new file:   PackageNameMissing.cpp
	new file:   PackageNameMissing.h
	modified:   PackageVersion.cpp
	modified:   PackageVersion.h
	new file:   PackageWithInferredName.cpp
	new file:   PackageWithInferredName.h
	modified:   README.md
	new file:   Refactoring_PackageFile_due_to_referencing_of_member_variable_to_temporary_value-Class_diagram.puml
	new file:   Refactoring_Package_due_to_using_a_subset_of_features_for_packageWithInferredName_of_original_Package_type_and_initializing_the_rest_to_undefined_values-Class_diagram.puml
	new file:   SimpleInstallationPackageFile.cpp
	new file:   SimpleInstallationPackageFile.h
	new file:   SimpleInstallationPackageFileType.h
	new file:   clean_pacman_cache_dir-class_diagram.puml
	new file:   clean_pacman_cache_dir.drawio
	new file:   clean_pacman_cache_dir.drawio.png
	modified:   main.cpp

[laptop@laptop clean_pacman_cache_dir]$ git commit --message="Bring project back to life..." --message="...Conform to SOLID principles, delegate functionalities to separate classes according to SRP/encapsulation/autonomy for more cohesion, less coupling, making the intentions and meaning of the classes and operations clearer; refactoring to making further planned changes easier to implement with less mental effort"
[main 7006f1b] Bring project back to life...
[laptop@laptop clean_pacman_cache_dir]$ git push
Enumerating objects: 34, done.
Counting objects: 100% (34/34), done.
Delta compression using up to 2 threads
Compressing objects: 100% (12/12), done.
Writing objects: 100% (12/12), 1.94 KiB | 1.94 MiB/s, done.
Total 12 (delta 11), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (11/11), completed with 11 local objects.
To github.com:kyberdrb/clean_pacman_cache_dir.git
   6bb11e5..7006f1b  main -> main
[laptop@laptop clean_pacman_cache_dir]$ git status
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean
[laptop@laptop clean_pacman_cache_dir]$ git branch
  backport-encapsulate_ignored_package_name_to_class
  backport-fix_for_package_from_inferred_name
  backport-fix_for_partially_downloaded_package_file
  backports
  encapsulate_container_variables_to_separate_classes
  encapsulate_relating_package_files_to_packages
  find_element_of_custom_type_in_set
* main
  packageVersion_from_string_to_PackageVersion
  refactoring_Package_class
[laptop@laptop clean_pacman_cache_dir]$
[laptop@laptop clean_pacman_cache_dir]$
[laptop@laptop clean_pacman_cache_dir]$ git tag --message="Ressurection" --annotate "3.0.0"
[laptop@laptop clean_pacman_cache_dir]$ git tag
1.0.0
1.0.1
2.0.0
2.0.1
2.1.0
2.2.0
2.3.1
2.3.2
2.3.3
2.3.4
2.3.5
2.3.6
3.0.0
[laptop@laptop clean_pacman_cache_dir]$ git push --tags
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 160 bytes | 160.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
To github.com:kyberdrb/clean_pacman_cache_dir.git
 * [new tag]         3.0.0 -> 3.0.0
[laptop@laptop clean_pacman_cache_dir]$ git branch
  backport-encapsulate_ignored_package_name_to_class
  backport-fix_for_package_from_inferred_name
  backport-fix_for_partially_downloaded_package_file
  backports
  encapsulate_container_variables_to_separate_classes
  encapsulate_relating_package_files_to_packages
  find_element_of_custom_type_in_set
* main
  packageVersion_from_string_to_PackageVersion
  refactoring_Package_class
[laptop@laptop clean_pacman_cache_dir]$
[laptop@laptop clean_pacman_cache_dir]$ date
Tue Jul  5 03:06:57 PM CEST 2022

Possible experiments

  • std::set with custom comparator given as a second template parameter at initialization
  • std::find_if/std::any_of
    • passing unique pointer to std::any_of directly
      • lambda
        • public friend function - all params const (the only one that works) - 'std::set' encapsulated in class
      • comparator predicate
        • direct comparison in comparator
          • public friend function - all params const - 'std::set' encapsulated in class

Testing algorithm on cache directories accessible only for root

Permission modification - switch to user - FOR DEBUGGING PURPOSES

sudo chown --dereference laptop:users "$(dirname "$(sudo realpath "/var/cache/pikaur")")"

Permission restoration - back to root

sudo chown --dereference root:root "$(dirname "$(sudo realpath "/var/cache/pikaur")")"

Sources

About

A utility to delete the contents of the pacman's and pikaur's cache directories and leave in mentioned directories only package files that the locally installed packages were installed from.

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published