Make more classes hashable and comparable (#3363)

Signed-off-by: Julien Jerphanion <git@jjerphan.xyz>
Co-authored-by: Klaim <Klaim@users.noreply.github.com>
This commit is contained in:
Julien Jerphanion 2024-07-29 11:06:45 +02:00 committed by GitHub
parent 154012f256
commit b09f1d162f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 327 additions and 0 deletions

View File

@ -15,6 +15,7 @@
#include <fmt/format.h>
#include "mamba/specs/error.hpp"
#include "mamba/util/tuple_hash.hpp"
namespace mamba::specs
{
@ -124,6 +125,17 @@ namespace mamba::specs
*/
[[nodiscard]] auto contains(BuildNumber point) const -> bool;
// TODO(C++20): replace by the `= default` implementation of `operator==`
[[nodiscard]] auto operator==(const BuildNumberSpec& other) const -> bool
{
return m_predicate == other.m_predicate;
}
[[nodiscard]] auto operator!=(const BuildNumberSpec& other) const -> bool
{
return !(*this == other);
}
private:
BuildNumberPredicate m_predicate;
@ -155,4 +167,13 @@ struct fmt::formatter<mamba::specs::BuildNumberSpec>
format(const ::mamba::specs::BuildNumberSpec& spec, format_context& ctx) -> decltype(ctx.out());
};
template <>
struct std::hash<mamba::specs::BuildNumberSpec>
{
auto operator()(const mamba::specs::BuildNumberSpec& spec) const -> std::size_t
{
return mamba::util::hash_vals(spec.str());
}
};
#endif

View File

@ -15,6 +15,7 @@
#include "mamba/specs/error.hpp"
#include "mamba/specs/glob_spec.hpp"
#include "mamba/specs/regex_spec.hpp"
#include "mamba/util/tuple_hash.hpp"
namespace mamba::specs
{
@ -51,6 +52,17 @@ namespace mamba::specs
[[nodiscard]] auto str() const -> const std::string&;
// TODO(C++20): replace by the `= default` implementation of `operator==`
[[nodiscard]] auto operator==(const ChimeraStringSpec& other) const -> bool
{
return m_spec == other.m_spec;
}
[[nodiscard]] auto operator!=(const ChimeraStringSpec& other) const -> bool
{
return !(*this == other);
}
private:
Chimera m_spec;
@ -66,4 +78,13 @@ struct fmt::formatter<mamba::specs::ChimeraStringSpec>
format(const ::mamba::specs::ChimeraStringSpec& spec, format_context& ctx) -> decltype(ctx.out());
};
template <>
struct std::hash<mamba::specs::ChimeraStringSpec>
{
auto operator()(const mamba::specs::ChimeraStringSpec& spec) const -> std::size_t
{
return mamba::util::hash_vals(spec.str());
}
};
#endif

View File

@ -43,6 +43,17 @@ namespace mamba::specs
[[nodiscard]] auto str() const -> const std::string&;
// TODO(C++20): replace by the `= default` implementation of `operator==`
[[nodiscard]] auto operator==(const GlobSpec& other) const -> bool
{
return m_pattern == other.m_pattern;
}
[[nodiscard]] auto operator!=(const GlobSpec& other) const -> bool
{
return !(*this == other);
}
private:
std::string m_pattern = std::string(free_pattern);
@ -57,4 +68,13 @@ struct fmt::formatter<mamba::specs::GlobSpec>
auto format(const ::mamba::specs::GlobSpec& spec, format_context& ctx) -> decltype(ctx.out());
};
template <>
struct std::hash<mamba::specs::GlobSpec>
{
auto operator()(const mamba::specs::GlobSpec& spec) const -> std::size_t
{
return std::hash<std::string>{}(spec.str());
}
};
#endif

View File

@ -22,6 +22,7 @@
#include "mamba/specs/version_spec.hpp"
#include "mamba/util/flat_set.hpp"
#include "mamba/util/heap_optional.hpp"
#include "mamba/util/tuple_hash.hpp"
namespace mamba::specs
{
@ -135,6 +136,28 @@ namespace mamba::specs
*/
[[nodiscard]] auto contains_except_channel(const PackageInfo& pkg) const -> bool;
// TODO(C++20): replace by the `= default` implementation of `operator==`
[[nodiscard]] auto operator==(const MatchSpec& other) const -> bool
{
return m_channel == other.m_channel //
&& m_version == other.m_version //
&& m_name == other.m_name //
&& m_build_string == other.m_build_string //
&& m_name_space == other.m_name_space //
&& m_build_number == other.m_build_number //
&& m_extra == other.m_extra;
}
[[nodiscard]] auto operator!=(const MatchSpec& other) const -> bool
{
return !(*this == other);
}
auto extra_members_hash() const -> std::size_t
{
return mamba::util::hash_vals(m_extra);
}
private:
struct ExtraMembers
@ -150,7 +173,29 @@ namespace mamba::specs
std::string features = {};
string_set track_features = {};
bool optional = false;
// TODO(C++20): replace by the `= default` implementation of `operator==`
[[nodiscard]] auto operator==(const ExtraMembers& other) const -> bool
{
return filename == other.filename //
&& subdirs == other.subdirs //
&& md5 == other.md5 //
&& sha256 == other.sha256 //
&& license == other.license //
&& license_family == other.license_family //
&& features == other.features //
&& track_features == other.track_features //
&& optional == other.optional;
}
[[nodiscard]] auto operator!=(const ExtraMembers& other) const -> bool
{
return !(*this == other);
}
friend struct std::hash<ExtraMembers>;
};
friend struct std::hash<MatchSpec::ExtraMembers>;
std::optional<UnresolvedChannel> m_channel;
VersionSpec m_version;
@ -255,4 +300,41 @@ namespace mamba::specs
return true;
}
}
template <>
struct std::hash<mamba::specs::MatchSpec>
{
auto operator()(const mamba::specs::MatchSpec& spec) const -> std::size_t
{
return mamba::util::hash_vals(
spec.channel(),
spec.version(),
spec.name(),
spec.build_string(),
spec.name_space(),
spec.build_number(),
spec.extra_members_hash()
);
}
};
template <>
struct std::hash<mamba::specs::MatchSpec::ExtraMembers>
{
auto operator()(const mamba::specs::MatchSpec::ExtraMembers& extra) const -> std::size_t
{
return mamba::util::hash_vals(
extra.filename,
extra.subdirs,
extra.md5,
extra.sha256,
extra.license,
extra.license_family,
extra.features,
extra.track_features,
extra.optional
);
}
};
#endif

View File

@ -15,6 +15,7 @@
#include "mamba/specs/error.hpp"
#include "mamba/specs/platform.hpp"
#include "mamba/util/tuple_hash.hpp"
namespace mamba::specs
{
@ -81,4 +82,47 @@ namespace mamba::specs
void from_json(const nlohmann::json& j, PackageInfo& pkg);
}
template <>
struct std::hash<mamba::specs::PackageInfo>
{
auto operator()(const mamba::specs::PackageInfo& pkg) const -> std::size_t
{
auto seed = std::size_t(0);
seed = mamba::util::hash_vals(
seed,
pkg.name,
pkg.version,
pkg.build_string,
pkg.build_number,
pkg.channel,
pkg.package_url,
pkg.platform,
pkg.filename,
pkg.license,
pkg.md5,
pkg.sha256,
pkg.signatures
);
seed = mamba::util::hash_combine_val_range(
seed,
pkg.track_features.begin(),
pkg.track_features.end()
);
seed = mamba::util::hash_combine_val_range(
seed,
pkg.dependencies.begin(),
pkg.dependencies.end()
);
seed = mamba::util::hash_combine_val_range(seed, pkg.constrains.begin(), pkg.constrains.end());
seed = mamba::util::hash_combine_val_range(
seed,
pkg.defaulted_keys.begin(),
pkg.defaulted_keys.end()
);
seed = mamba::util::hash_vals(seed, pkg.noarch, pkg.size, pkg.timestamp, pkg.package_type);
return seed;
}
};
#endif

View File

@ -47,6 +47,18 @@ namespace mamba::specs
[[nodiscard]] auto str() const -> const std::string&;
// TODO(C++20): replace by the `= default` implementation of `operator==`
[[nodiscard]] auto operator==(const RegexSpec& other) const -> bool
{
return m_raw_pattern == other.m_raw_pattern
&& m_pattern.flags() == other.m_pattern.flags();
}
[[nodiscard]] auto operator!=(const RegexSpec& other) const -> bool
{
return !(*this == other);
}
private:
std::regex m_pattern;

View File

@ -17,6 +17,7 @@
#include "mamba/specs/error.hpp"
#include "mamba/specs/platform.hpp"
#include "mamba/util/flat_set.hpp"
#include "mamba/util/tuple_hash.hpp"
namespace mamba::specs
{
@ -111,6 +112,18 @@ namespace mamba::specs
[[nodiscard]] auto str() const -> std::string;
[[nodiscard]] auto operator==(const UnresolvedChannel& other) const -> bool
{
return m_location == other.m_location //
&& m_platform_filters == other.m_platform_filters //
&& m_type == other.m_type;
}
[[nodiscard]] auto operator!=(const UnresolvedChannel& other) const -> bool
{
return !(*this == other);
}
private:
std::string m_location = std::string(unknown_channel);
@ -137,4 +150,13 @@ struct fmt::formatter<mamba::specs::UnresolvedChannel>
auto format(const UnresolvedChannel& uc, format_context& ctx) const -> format_context::iterator;
};
template <>
struct std::hash<mamba::specs::UnresolvedChannel>
{
auto operator()(const mamba::specs::UnresolvedChannel& uc) const -> std::size_t
{
return mamba::util::hash_vals(uc.location(), uc.platform_filters(), static_cast<int>(uc.type()));
}
};
#endif

View File

@ -17,6 +17,7 @@
#include "mamba/specs/error.hpp"
#include "mamba/specs/version.hpp"
#include "mamba/util/flat_bool_expr_tree.hpp"
#include "mamba/util/tuple_hash.hpp"
namespace mamba::specs
{
@ -195,6 +196,16 @@ namespace mamba::specs
*/
[[nodiscard]] auto expression_size() const -> std::size_t;
[[nodiscard]] auto operator==(const VersionSpec& other) const -> bool
{
return m_tree == other.m_tree;
}
[[nodiscard]] auto operator!=(const VersionSpec& other) const -> bool
{
return !(*this == other);
}
private:
tree_type m_tree;
@ -234,4 +245,23 @@ struct fmt::formatter<mamba::specs::VersionSpec>
auto format(const ::mamba::specs::VersionSpec& spec, format_context& ctx) -> decltype(ctx.out());
};
template <>
struct std::hash<mamba::specs::VersionPredicate>
{
auto operator()(const mamba::specs::VersionPredicate& pred) const -> std::size_t
{
return mamba::util::hash_vals(pred.str());
}
};
template <>
struct std::hash<mamba::specs::VersionSpec>
{
auto operator()(const mamba::specs::VersionSpec& spec) const -> std::size_t
{
return mamba::util::hash_vals(spec.str());
}
};
#endif

View File

@ -38,6 +38,19 @@ namespace mamba::util
branch_type data;
std::size_t left_child = 0;
std::size_t right_child = 0;
// TODO(C++20): replace by the `= default` implementation of `operator==`
[[nodiscard]] auto operator==(const branch_node& other) const -> bool
{
return data == other.data //
&& left_child == other.left_child //
&& right_child == other.right_child;
}
[[nodiscard]] auto operator!=(const branch_node& other) const -> bool
{
return !(*this == other);
}
};
using leaf_node = leaf_type;
@ -90,6 +103,17 @@ namespace mamba::util
[[nodiscard]] auto right(idx_type idx) const -> idx_type;
[[nodiscard]] auto root() const -> idx_type;
// TODO(C++20): replace by the `= default` implementation of `operator==`
[[nodiscard]] auto operator==(const flat_binary_tree& other) const -> bool
{
return m_nodes == other.m_nodes && m_root == other.m_root;
}
[[nodiscard]] auto operator!=(const flat_binary_tree& other) const -> bool
{
return !(*this == other);
}
template <typename Visitor>
void dfs_raw(Visitor&& visitor, idx_type start) const;

View File

@ -173,6 +173,17 @@ namespace mamba::util
template <typename UnaryFunc>
void infix_for_each(UnaryFunc&& func) const;
// TODO(C++20): replace by the `= default` implementation of `operator==`
[[nodiscard]] auto operator==(const self_type& other) const -> bool
{
return m_tree == other.m_tree;
}
[[nodiscard]] auto operator!=(const self_type& other) const -> bool
{
return !(*this == other);
}
private:
using idx_type = typename tree_type::idx_type;

View File

@ -12,6 +12,8 @@
#include <utility>
#include <vector>
#include "mamba/util/tuple_hash.hpp"
namespace mamba::util
{
@ -557,4 +559,14 @@ namespace mamba::util
return out;
}
}
template <typename Key, typename Compare, typename Allocator>
struct std::hash<mamba::util::flat_set<Key, Compare, Allocator>>
{
auto operator()(const mamba::util::flat_set<Key, Compare, Allocator>& set) const -> std::size_t
{
return mamba::util::hash_vals(set);
}
};
#endif

View File

@ -68,6 +68,20 @@ namespace mamba::util
void reset();
[[nodiscard]] auto operator==(const heap_optional& other) const -> bool
{
if (has_value() && other.has_value())
{
return *m_ptr == *other;
}
return !has_value() && !other.has_value();
}
[[nodiscard]] auto operator!=(const heap_optional& other) const -> bool
{
return !(*this == other);
}
private:
std::unique_ptr<element_type> m_ptr = nullptr;
@ -236,4 +250,18 @@ namespace mamba::util
m_ptr = nullptr;
}
}
template <typename T>
struct std::hash<mamba::util::heap_optional<T>>
{
std::size_t operator()(const mamba::util::heap_optional<T>& opt) const
{
if (opt.has_value())
{
return std::hash<T>{}(*opt);
}
return 0;
}
};
#endif