From 4e088e4dce52af5548fb09444e7e4780a9397fb8 Mon Sep 17 00:00:00 2001 From: Oliver Hamlet Date: Thu, 8 May 2025 11:31:44 +0100 Subject: [PATCH] Replace C++ comparison operators with <=> --- cpp/cmake/tests.cmake | 1 + cpp/include/loot/metadata/file.h | 48 ++--------- cpp/include/loot/metadata/filename.h | 52 +++--------- cpp/include/loot/metadata/group.h | 49 ++--------- cpp/include/loot/metadata/location.h | 49 ++--------- cpp/include/loot/metadata/message.h | 48 ++--------- cpp/include/loot/metadata/message_content.h | 49 ++--------- .../loot/metadata/plugin_cleaning_data.h | 56 ++----------- cpp/include/loot/metadata/tag.h | 54 ++++--------- cpp/src/api/metadata/file.cpp | 51 ------------ cpp/src/api/metadata/filename.cpp | 37 ++++----- cpp/src/api/metadata/group.cpp | 34 -------- cpp/src/api/metadata/location.cpp | 30 ------- cpp/src/api/metadata/message.cpp | 36 --------- cpp/src/api/metadata/message_content.cpp | 33 -------- cpp/src/api/metadata/plugin_cleaning_data.cpp | 69 ---------------- cpp/src/api/metadata/tag.cpp | 33 +++----- cpp/src/lib.rs | 2 + cpp/src/metadata.rs | 10 ++- cpp/src/tests/api/interface/main.cpp | 1 + .../api/interface/metadata/filename_test.h | 81 +++++++++++++++++++ .../tests/api/interface/metadata/tag_test.h | 34 ++++++++ 22 files changed, 211 insertions(+), 646 deletions(-) create mode 100644 cpp/src/tests/api/interface/metadata/filename_test.h diff --git a/cpp/cmake/tests.cmake b/cpp/cmake/tests.cmake index f5d1ddc7..579ad375 100644 --- a/cpp/cmake/tests.cmake +++ b/cpp/cmake/tests.cmake @@ -48,6 +48,7 @@ set(LIBLOOT_SRC_TESTS_INTERFACE_H_FILES "${CMAKE_SOURCE_DIR}/src/tests/api/interface/game_interface_test.h" "${CMAKE_SOURCE_DIR}/src/tests/api/interface/is_compatible_test.h" "${CMAKE_SOURCE_DIR}/src/tests/api/interface/metadata/file_test.h" + "${CMAKE_SOURCE_DIR}/src/tests/api/interface/metadata/filename_test.h" "${CMAKE_SOURCE_DIR}/src/tests/api/interface/metadata/group_test.h" "${CMAKE_SOURCE_DIR}/src/tests/api/interface/metadata/location_test.h" "${CMAKE_SOURCE_DIR}/src/tests/api/interface/metadata/message_test.h" diff --git a/cpp/include/loot/metadata/file.h b/cpp/include/loot/metadata/file.h index 1ab3fda7..84d7bc11 100644 --- a/cpp/include/loot/metadata/file.h +++ b/cpp/include/loot/metadata/file.h @@ -98,6 +98,11 @@ public: */ LOOT_API std::string GetConstraint() const; + /** + * Compares two File objects. + */ + LOOT_API auto operator<=>(const File& rhs) const = default; + private: Filename name_; std::string display_; @@ -105,49 +110,6 @@ private: std::string condition_; std::string constraint_; }; - -/** - * Check if two File objects are equal by comparing their fields. - * @returns True if the objects' fields are equal, false otherwise. - */ -LOOT_API bool operator==(const File& lhs, const File& rhs); - -/** - * Check if two File objects are not equal. - * @returns True if the File objects are not equal, false otherwise. - */ -LOOT_API bool operator!=(const File& lhs, const File& rhs); - -/** - * A less-than operator implemented with no semantics so that File objects can - * be stored in sets. - * @returns True if the first File is less than the second File, false - * otherwise. - */ -LOOT_API bool operator<(const File& lhs, const File& rhs); - -/** - * Check if the first File object is greater than the second File object. - * @returns True if the second File object is less than the first File object, - * false otherwise. - */ -LOOT_API bool operator>(const File& lhs, const File& rhs); - -/** - * Check if the first File object is less than or equal to the second File - * object. - * @returns True if the first File object is not greater than the second File - * object, false otherwise. - */ -LOOT_API bool operator<=(const File& lhs, const File& rhs); - -/** - * Check if the first File object is greater than or equal to the second File - * object. - * @returns True if the first File object is not less than the second File - * object, false otherwise. - */ -LOOT_API bool operator>=(const File& lhs, const File& rhs); } #endif diff --git a/cpp/include/loot/metadata/filename.h b/cpp/include/loot/metadata/filename.h index fb5d2b47..ffb62b9e 100644 --- a/cpp/include/loot/metadata/filename.h +++ b/cpp/include/loot/metadata/filename.h @@ -24,6 +24,7 @@ #ifndef LOOT_METADATA_FILENAME #define LOOT_METADATA_FILENAME +#include #include #include @@ -53,55 +54,26 @@ public: private: std::string filename_; - LOOT_API friend bool operator==(const Filename& lhs, const Filename& rhs); + LOOT_API friend std::weak_ordering operator<=>(const Filename& lhs, + const Filename& rhs); - LOOT_API friend bool operator<(const Filename& lhs, const Filename& rhs); + LOOT_API friend bool operator==(const Filename& lhs, const Filename& rhs); }; +/** + * Compare two Filename objects. + * + * Filenames are compared case-insensitively. + */ +LOOT_API std::weak_ordering operator<=>(const Filename& lhs, + const Filename& rhs); + /** * Check if two Filename objects are equal by comparing their fields. * @returns True if the filenames are case-insensitively equal and all other * fields are case-sensitively equal, false otherwise. */ LOOT_API bool operator==(const Filename& lhs, const Filename& rhs); - -/** - * Check if two Filename objects are not equal. - * @returns True if the Filename objects are not equal, false otherwise. - */ -LOOT_API bool operator!=(const Filename& lhs, const Filename& rhs); - -/** - * A less-than operator implemented with no semantics so that Filename objects - * can be stored in sets. - * @returns True if this Filename is less than the given Filename, false - * otherwise. - */ -LOOT_API bool operator<(const Filename& lhs, const Filename& rhs); - -/** - * Check if the first Filename object is greater than the second Filename - * object. - * @returns True if the second Filename object is less than the first Filename - * object, false otherwise. - */ -LOOT_API bool operator>(const Filename& lhs, const Filename& rhs); - -/** - * Check if the first Filename object is less than or equal to the second - * Filename object. - * @returns True if the first Filename object is not greater than the second - * Filename object, false otherwise. - */ -LOOT_API bool operator<=(const Filename& lhs, const Filename& rhs); - -/** - * Check if the first Filename object is greater than or equal to the second - * Filename object. - * @returns True if the first Filename object is not less than the second - * Filename object, false otherwise. - */ -LOOT_API bool operator>=(const Filename& lhs, const Filename& rhs); } #endif diff --git a/cpp/include/loot/metadata/group.h b/cpp/include/loot/metadata/group.h index 2320dfe2..49ea4435 100644 --- a/cpp/include/loot/metadata/group.h +++ b/cpp/include/loot/metadata/group.h @@ -79,55 +79,16 @@ public: */ LOOT_API std::vector GetAfterGroups() const; + /** + * Compares two Group objects. + */ + LOOT_API auto operator<=>(const Group& rhs) const = default; + private: std::string name_{DEFAULT_NAME}; std::string description_; std::vector afterGroups_; }; - -/** - * Check if two Group objects are equal by comparing their names. - * @returns True if the objects' fields are equal, false otherwise. - */ -LOOT_API bool operator==(const Group& lhs, const Group& rhs); - -/** - * Check if two Group objects are not equal. - * @returns True if the Group objects are not equal, false otherwise. - */ -LOOT_API bool operator!=(const Group& lhs, const Group& rhs); - -/** - * A less-than operator implemented with no semantics so that Group objects - * can be stored in sets. - * @returns True if the first Group is less than the second Group, false - * otherwise. - */ -LOOT_API bool operator<(const Group& lhs, const Group& rhs); - -/** - * Check if the first Group object is greater than the second Group - * object. - * @returns True if the second Group object is less than the first Group - * object, false otherwise. - */ -LOOT_API bool operator>(const Group& lhs, const Group& rhs); - -/** - * Check if the first Group object is less than or equal to the second - * Group object. - * @returns True if the first Group object is not greater than the second - * Group object, false otherwise. - */ -LOOT_API bool operator<=(const Group& lhs, const Group& rhs); - -/** - * Check if the first Group object is greater than or equal to the second - * Group object. - * @returns True if the first Group object is not less than the second - * Group object, false otherwise. - */ -LOOT_API bool operator>=(const Group& lhs, const Group& rhs); } #endif diff --git a/cpp/include/loot/metadata/location.h b/cpp/include/loot/metadata/location.h index e8b0adf4..9956eeeb 100644 --- a/cpp/include/loot/metadata/location.h +++ b/cpp/include/loot/metadata/location.h @@ -63,54 +63,15 @@ public: */ LOOT_API std::string GetName() const; + /** + * Compares two Location objects. + */ + LOOT_API auto operator<=>(const Location& rhs) const = default; + private: std::string url_; std::string name_; }; - -/** - * Check if two Location objects are equal by comparing their fields. - * @returns True if the objects' fields are equal, false otherwise. - */ -LOOT_API bool operator==(const Location& lhs, const Location& rhs); - -/** - * Check if two Location objects are not equal. - * @returns True if the Location objects are not equal, false otherwise. - */ -LOOT_API bool operator!=(const Location& lhs, const Location& rhs); - -/** - * A less-than operator implemented with no semantics so that Location objects - * can be stored in sets. - * @returns True if the first Location is less than the second Location, false - * otherwise. - */ -LOOT_API bool operator<(const Location& lhs, const Location& rhs); - -/** - * Check if the first Location object is greater than the second Location - * object. - * @returns True if the second Location object is less than the first Location - * object, false otherwise. - */ -LOOT_API bool operator>(const Location& lhs, const Location& rhs); - -/** - * Check if the first Location object is less than or equal to the second - * Location object. - * @returns True if the first Location object is not greater than the second - * Location object, false otherwise. - */ -LOOT_API bool operator<=(const Location& lhs, const Location& rhs); - -/** - * Check if the first Location object is greater than or equal to the second - * Location object. - * @returns True if the first Location object is not less than the second - * Location object, false otherwise. - */ -LOOT_API bool operator>=(const Location& lhs, const Location& rhs); } #endif diff --git a/cpp/include/loot/metadata/message.h b/cpp/include/loot/metadata/message.h index ca805eb7..fab146d2 100644 --- a/cpp/include/loot/metadata/message.h +++ b/cpp/include/loot/metadata/message.h @@ -90,54 +90,16 @@ public: */ LOOT_API std::string GetCondition() const; + /** + * Compares two Message objects. + */ + LOOT_API auto operator<=>(const Message& rhs) const = default; + private: MessageType type_{MessageType::say}; std::vector content_; std::string condition_; }; - -/** - * Check if two Message objects are equal by comparing their fields. - * @returns True if the objects' fields are equal, false otherwise. - */ -LOOT_API bool operator==(const Message& lhs, const Message& rhs); - -/** - * Check if two Message objects are not equal. - * @returns True if the Message objects are not equal, false otherwise. - */ -LOOT_API bool operator!=(const Message& lhs, const Message& rhs); - -/** - * A less-than operator implemented with no semantics so that Message objects - * can be stored in sets. - * @returns Returns true if the first Message is less than the second Message, - * and false otherwise. - */ -LOOT_API bool operator<(const Message& lhs, const Message& rhs); - -/** - * Check if the first Message object is greater than the second Message object. - * @returns True if the second Message object is less than the first Message - * object, false otherwise. - */ -LOOT_API bool operator>(const Message& lhs, const Message& rhs); - -/** - * Check if the first Message object is less than or equal to the second - * Message object. - * @returns True if the first Message object is not greater than the second - * Message object, false otherwise. - */ -LOOT_API bool operator<=(const Message& lhs, const Message& rhs); - -/** - * Check if the first Message object is greater than or equal to the second - * Message object. - * @returns True if the first Message object is not less than the second - * Message object, false otherwise. - */ -LOOT_API bool operator>=(const Message& lhs, const Message& rhs); } #endif diff --git a/cpp/include/loot/metadata/message_content.h b/cpp/include/loot/metadata/message_content.h index b5498757..b0655e0e 100644 --- a/cpp/include/loot/metadata/message_content.h +++ b/cpp/include/loot/metadata/message_content.h @@ -71,55 +71,16 @@ public: */ LOOT_API std::string GetLanguage() const; + /** + * Compares two MessageContent objects. + */ + LOOT_API auto operator<=>(const MessageContent& rhs) const = default; + private: std::string text_; std::string language_{DEFAULT_LANGUAGE}; }; -/** - * Check if two MessageContent objects are equal by comparing their fields. - * @returns True if the objects' fields are equal, false otherwise. - */ -LOOT_API bool operator==(const MessageContent& lhs, const MessageContent& rhs); - -/** - * Check if two MessageContent objects are not equal. - * @returns True if the MessageContent objects are not equal, false otherwise. - */ -LOOT_API bool operator!=(const MessageContent& lhs, const MessageContent& rhs); - -/** - * A less-than operator implemented with no semantics so that MessageContent - * objects can be stored in sets. - * @returns True if the first MessageContent is less than the second - * MessageContent, false otherwise. - */ -LOOT_API bool operator<(const MessageContent& lhs, const MessageContent& rhs); - -/** - * Check if the first MessageContent object is greater than the second - * MessageContent object. - * @returns True if the second MessageContent object is less than the first - * MessageContent object, false otherwise. - */ -LOOT_API bool operator>(const MessageContent& lhs, const MessageContent& rhs); - -/** - * Check if the first MessageContent object is less than or equal to the second - * MessageContent object. - * @returns True if the first MessageContent object is not greater than the - * second MessageContent object, false otherwise. - */ -LOOT_API bool operator<=(const MessageContent& lhs, const MessageContent& rhs); - -/** - * Check if the first MessageContent object is greater than or equal to the - * second MessageContent object. - * @returns True if the first MessageContent object is not less than the second - * MessageContent object, false otherwise. - */ -LOOT_API bool operator>=(const MessageContent& lhs, const MessageContent& rhs); - /** * Choose a MessageContent object from a vector given a language. * @param content diff --git a/cpp/include/loot/metadata/plugin_cleaning_data.h b/cpp/include/loot/metadata/plugin_cleaning_data.h index 87f10132..719749ef 100644 --- a/cpp/include/loot/metadata/plugin_cleaning_data.h +++ b/cpp/include/loot/metadata/plugin_cleaning_data.h @@ -122,6 +122,11 @@ public: */ LOOT_API std::vector GetDetail() const; + /** + * Compares two PluginCleaningData objects. + */ + LOOT_API auto operator<=>(const PluginCleaningData& rhs) const = default; + private: uint32_t crc_{0}; unsigned int itm_{0}; @@ -130,57 +135,6 @@ private: std::string utility_; std::vector detail_; }; - -/** - * Check if two PluginCleaningData objects are equal by comparing their - * fields. - * @returns True if the objects' fields are equal, false otherwise. - */ -LOOT_API bool operator==(const PluginCleaningData& lhs, - const PluginCleaningData& rhs); - -/** - * Check if two MessageContent objects are not equal. - * @returns True if the MessageContent objects are not equal, false otherwise. - */ -LOOT_API bool operator!=(const PluginCleaningData& lhs, - const PluginCleaningData& rhs); - -/** - * A less-than operator implemented with no semantics so that - * PluginCleaningData objects can be stored in sets. - * @returns True if the first PluginCleaningData is less than the second - * PluginCleaningData, false otherwise. - */ -LOOT_API bool operator<(const PluginCleaningData& lhs, - const PluginCleaningData& rhs); - -/** - * Check if the first PluginCleaningData object is greater than the second - * PluginCleaningData object. - * @returns True if the second PluginCleaningData object is less than the first - * PluginCleaningData object, false otherwise. - */ -LOOT_API bool operator>(const PluginCleaningData& lhs, - const PluginCleaningData& rhs); - -/** - * Check if the first PluginCleaningData object is less than or equal to the - * second PluginCleaningData object. - * @returns True if the first PluginCleaningData object is not greater than the - * second PluginCleaningData object, false otherwise. - */ -LOOT_API bool operator<=(const PluginCleaningData& lhs, - const PluginCleaningData& rhs); - -/** - * Check if the first PluginCleaningData object is greater than or equal to the - * second PluginCleaningData object. - * @returns True if the first PluginCleaningData object is not less than the - * second PluginCleaningData object, false otherwise. - */ -LOOT_API bool operator>=(const PluginCleaningData& lhs, - const PluginCleaningData& rhs); } #endif diff --git a/cpp/include/loot/metadata/tag.h b/cpp/include/loot/metadata/tag.h index a88521bc..7e11548d 100644 --- a/cpp/include/loot/metadata/tag.h +++ b/cpp/include/loot/metadata/tag.h @@ -24,6 +24,7 @@ #ifndef LOOT_METADATA_TAG #define LOOT_METADATA_TAG +#include #include #include @@ -73,53 +74,28 @@ public: */ LOOT_API std::string GetCondition() const; + /** + * Check if two Tag objects are equal. + * @returns True if the objects' fields are equal, false otherwise. + */ + LOOT_API bool operator==(const Tag& rhs) const = default; + private: std::string name_; bool addTag_{true}; std::string condition_; + + LOOT_API friend std::strong_ordering operator<=>(const Tag& lhs, + const Tag& rhs); }; /** - * Check if two Tag objects are equal. - * @returns True if the objects' fields are equal, false otherwise. + * Compares two Tag objects. + * + * Tag objects that suggest additions are considered less than those that + * suggest removals. */ -LOOT_API bool operator==(const Tag& lhs, const Tag& rhs); - -/** - * Check if two Tag objects are not equal. - * @returns True if the Tag objects are not equal, false otherwise. - */ -LOOT_API bool operator!=(const Tag& lhs, const Tag& rhs); - -/** - * A less-than operator implemented with no semantics so that Tag objects - * can be stored in sets. - * @returns True if the first Tag is less than the second Tag, false otherwise. - */ -LOOT_API bool operator<(const Tag& lhs, const Tag& rhs); - -/** - * Check if the first Tag object is greater than the second Tag object. - * @returns True if the second Tag object is less than the first Tag object, - * false otherwise. - */ -LOOT_API bool operator>(const Tag& lhs, const Tag& rhs); - -/** - * Check if the first Tag object is less than or equal to the second Tag - * object. - * @returns True if the first Tag object is not greater than the second Tag - * object, false otherwise. - */ -LOOT_API bool operator<=(const Tag& lhs, const Tag& rhs); - -/** - * Check if the first Tag object is greater than or equal to the second Tag - * object. - * @returns True if the first Tag object is not less than the second Tag - * object, false otherwise. - */ -LOOT_API bool operator>=(const Tag& lhs, const Tag& rhs); +LOOT_API std::strong_ordering operator<=>(const Tag& lhs, const Tag& rhs); } #endif diff --git a/cpp/src/api/metadata/file.cpp b/cpp/src/api/metadata/file.cpp index c872aff5..b04d0456 100644 --- a/cpp/src/api/metadata/file.cpp +++ b/cpp/src/api/metadata/file.cpp @@ -45,55 +45,4 @@ std::vector File::GetDetail() const { return detail_; } std::string File::GetCondition() const { return condition_; } std::string File::GetConstraint() const { return constraint_; } - -bool operator==(const File& lhs, const File& rhs) { - return lhs.GetDisplayName() == rhs.GetDisplayName() && - lhs.GetCondition() == rhs.GetCondition() && - lhs.GetConstraint() == rhs.GetConstraint() && - lhs.GetName() == rhs.GetName() && lhs.GetDetail() == rhs.GetDetail(); -} - -bool operator!=(const File& lhs, const File& rhs) { return !(lhs == rhs); } - -bool operator<(const File& lhs, const File& rhs) { - if (lhs.GetDisplayName() < rhs.GetDisplayName()) { - return true; - } - - if (rhs.GetDisplayName() < lhs.GetDisplayName()) { - return false; - } - - if (lhs.GetCondition() < rhs.GetCondition()) { - return true; - } - - if (rhs.GetCondition() < lhs.GetCondition()) { - return false; - } - - if (lhs.GetConstraint() < rhs.GetConstraint()) { - return true; - } - - if (rhs.GetConstraint() < lhs.GetConstraint()) { - return false; - } - - if (lhs.GetName() < rhs.GetName()) { - return true; - } - - if (rhs.GetName() < lhs.GetName()) { - return false; - } - - return lhs.GetDetail() < rhs.GetDetail(); -} - -bool operator>(const File& lhs, const File& rhs) { return rhs < lhs; } - -bool operator<=(const File& lhs, const File& rhs) { return !(lhs > rhs); } - -bool operator>=(const File& lhs, const File& rhs) { return !(lhs < rhs); } } diff --git a/cpp/src/api/metadata/filename.cpp b/cpp/src/api/metadata/filename.cpp index 0552c7f1..457426f1 100644 --- a/cpp/src/api/metadata/filename.cpp +++ b/cpp/src/api/metadata/filename.cpp @@ -33,27 +33,22 @@ Filename::Filename(std::string_view filename) : filename_(filename) {} Filename::operator std::string() const { return filename_; } +std::weak_ordering operator<=>(const Filename& lhs, const Filename& rhs) { + auto result = loot::rust::new_filename(lhs.filename_) + ->cmp(*loot::rust::new_filename(rhs.filename_)); + + if (result > 0) { + return std::weak_ordering::greater; + } + + if (result == 0) { + return std::weak_ordering::equivalent; + } + + return std::weak_ordering::less; +} + bool operator==(const Filename& lhs, const Filename& rhs) { - return loot::rust::new_filename(lhs.filename_) - ->eq(*loot::rust::new_filename(rhs.filename_)); -} - -bool operator!=(const Filename& lhs, const Filename& rhs) { - return !(lhs == rhs); -} - -bool operator<(const Filename& lhs, const Filename& rhs) { - return loot::rust::new_filename(lhs.filename_) - ->lt(*loot::rust::new_filename(rhs.filename_)); -} - -bool operator>(const Filename& lhs, const Filename& rhs) { return rhs < lhs; } - -bool operator<=(const Filename& lhs, const Filename& rhs) { - return !(lhs > rhs); -} - -bool operator>=(const Filename& lhs, const Filename& rhs) { - return !(lhs < rhs); + return (lhs <=> rhs) == std::weak_ordering::equivalent; } } diff --git a/cpp/src/api/metadata/group.cpp b/cpp/src/api/metadata/group.cpp index 4205d17f..f38f5357 100644 --- a/cpp/src/api/metadata/group.cpp +++ b/cpp/src/api/metadata/group.cpp @@ -35,38 +35,4 @@ std::string Group::GetName() const { return name_; } std::string Group::GetDescription() const { return description_; } std::vector Group::GetAfterGroups() const { return afterGroups_; } - -bool operator==(const Group& lhs, const Group& rhs) { - return lhs.GetName() == rhs.GetName() && - lhs.GetDescription() == rhs.GetDescription() && - lhs.GetAfterGroups() == rhs.GetAfterGroups(); -} - -bool operator!=(const Group& lhs, const Group& rhs) { return !(lhs == rhs); } - -bool operator<(const Group& lhs, const Group& rhs) { - if (lhs.GetName() < rhs.GetName()) { - return true; - } - - if (rhs.GetName() < lhs.GetName()) { - return false; - } - - if (lhs.GetDescription() < rhs.GetDescription()) { - return true; - } - - if (rhs.GetDescription() < lhs.GetDescription()) { - return false; - } - - return lhs.GetAfterGroups() < rhs.GetAfterGroups(); -} - -bool operator>(const Group& lhs, const Group& rhs) { return rhs < lhs; } - -bool operator<=(const Group& lhs, const Group& rhs) { return !(lhs > rhs); } - -bool operator>=(const Group& lhs, const Group& rhs) { return !(lhs < rhs); } } diff --git a/cpp/src/api/metadata/location.cpp b/cpp/src/api/metadata/location.cpp index 7b540212..7f8f072e 100644 --- a/cpp/src/api/metadata/location.cpp +++ b/cpp/src/api/metadata/location.cpp @@ -31,34 +31,4 @@ Location::Location(std::string_view url, std::string_view name) : std::string Location::GetURL() const { return url_; } std::string Location::GetName() const { return name_; } - -bool operator==(const Location& lhs, const Location& rhs) { - return lhs.GetURL() == rhs.GetURL() && lhs.GetName() == rhs.GetName(); -} - -bool operator!=(const Location& lhs, const Location& rhs) { - return !(lhs == rhs); -} - -bool operator<(const Location& lhs, const Location& rhs) { - if (lhs.GetURL() < rhs.GetURL()) { - return true; - } - - if (rhs.GetURL() < lhs.GetURL()) { - return false; - } - - return lhs.GetName() < rhs.GetName(); -} - -bool operator>(const Location& lhs, const Location& rhs) { return rhs < lhs; } - -bool operator<=(const Location& lhs, const Location& rhs) { - return !(lhs > rhs); -} - -bool operator>=(const Location& lhs, const Location& rhs) { - return !(lhs < rhs); -} } diff --git a/cpp/src/api/metadata/message.cpp b/cpp/src/api/metadata/message.cpp index d3b457e1..60703870 100644 --- a/cpp/src/api/metadata/message.cpp +++ b/cpp/src/api/metadata/message.cpp @@ -54,40 +54,4 @@ MessageType Message::GetType() const { return type_; } std::vector Message::GetContent() const { return content_; } std::string Message::GetCondition() const { return condition_; } - -bool operator==(const Message& lhs, const Message& rhs) { - return lhs.GetType() == rhs.GetType() && - lhs.GetCondition() == rhs.GetCondition() && - lhs.GetContent() == rhs.GetContent(); -} - -bool operator!=(const Message& lhs, const Message& rhs) { - return !(lhs == rhs); -} - -bool operator<(const Message& lhs, const Message& rhs) { - if (lhs.GetType() < rhs.GetType()) { - return true; - } - - if (rhs.GetType() < lhs.GetType()) { - return false; - } - - if (lhs.GetCondition() < rhs.GetCondition()) { - return true; - } - - if (rhs.GetCondition() < lhs.GetCondition()) { - return false; - } - - return lhs.GetContent() < rhs.GetContent(); -} - -bool operator>(const Message& lhs, const Message& rhs) { return rhs < lhs; } - -bool operator<=(const Message& lhs, const Message& rhs) { return !(lhs > rhs); } - -bool operator>=(const Message& lhs, const Message& rhs) { return !(lhs < rhs); } } diff --git a/cpp/src/api/metadata/message_content.cpp b/cpp/src/api/metadata/message_content.cpp index c184af48..c1b675cc 100644 --- a/cpp/src/api/metadata/message_content.cpp +++ b/cpp/src/api/metadata/message_content.cpp @@ -33,39 +33,6 @@ std::string MessageContent::GetText() const { return text_; } std::string MessageContent::GetLanguage() const { return language_; } -bool operator==(const MessageContent& lhs, const MessageContent& rhs) { - return lhs.GetText() == rhs.GetText() && - lhs.GetLanguage() == rhs.GetLanguage(); -} - -bool operator!=(const MessageContent& lhs, const MessageContent& rhs) { - return !(lhs == rhs); -} - -bool operator<(const MessageContent& lhs, const MessageContent& rhs) { - if (lhs.GetText() < rhs.GetText()) { - return true; - } - - if (rhs.GetText() < lhs.GetText()) { - return false; - } - - return lhs.GetLanguage() < rhs.GetLanguage(); -} - -bool operator>(const MessageContent& lhs, const MessageContent& rhs) { - return rhs < lhs; -} - -bool operator<=(const MessageContent& lhs, const MessageContent& rhs) { - return !(lhs > rhs); -} - -bool operator>=(const MessageContent& lhs, const MessageContent& rhs) { - return !(lhs < rhs); -} - std::optional SelectMessageContent( const std::vector content, std::string_view language) { diff --git a/cpp/src/api/metadata/plugin_cleaning_data.cpp b/cpp/src/api/metadata/plugin_cleaning_data.cpp index 3664d327..3033e4cf 100644 --- a/cpp/src/api/metadata/plugin_cleaning_data.cpp +++ b/cpp/src/api/metadata/plugin_cleaning_data.cpp @@ -57,73 +57,4 @@ std::string PluginCleaningData::GetCleaningUtility() const { return utility_; } std::vector PluginCleaningData::GetDetail() const { return detail_; } - -bool operator==(const PluginCleaningData& lhs, const PluginCleaningData& rhs) { - return lhs.GetCRC() == rhs.GetCRC() && - lhs.GetITMCount() == rhs.GetITMCount() && - lhs.GetDeletedReferenceCount() == rhs.GetDeletedReferenceCount() && - lhs.GetDeletedNavmeshCount() == rhs.GetDeletedNavmeshCount() && - lhs.GetCleaningUtility() == rhs.GetCleaningUtility() && - lhs.GetDetail() == rhs.GetDetail(); -} - -bool operator!=(const PluginCleaningData& lhs, const PluginCleaningData& rhs) { - return !(lhs == rhs); -} - -bool operator<(const PluginCleaningData& lhs, const PluginCleaningData& rhs) { - if (lhs.GetCRC() < rhs.GetCRC()) { - return true; - } - - if (rhs.GetCRC() < lhs.GetCRC()) { - return false; - } - - if (lhs.GetCleaningUtility() < rhs.GetCleaningUtility()) { - return true; - } - - if (rhs.GetCleaningUtility() < lhs.GetCleaningUtility()) { - return false; - } - - if (lhs.GetITMCount() < rhs.GetITMCount()) { - return true; - } - - if (rhs.GetITMCount() < lhs.GetITMCount()) { - return false; - } - - if (lhs.GetDeletedReferenceCount() < rhs.GetDeletedReferenceCount()) { - return true; - } - - if (rhs.GetDeletedReferenceCount() < lhs.GetDeletedReferenceCount()) { - return false; - } - - if (lhs.GetDeletedNavmeshCount() < rhs.GetDeletedNavmeshCount()) { - return true; - } - - if (rhs.GetDeletedNavmeshCount() < lhs.GetDeletedNavmeshCount()) { - return false; - } - - return lhs.GetDetail() < rhs.GetDetail(); -} - -bool operator>(const PluginCleaningData& lhs, const PluginCleaningData& rhs) { - return rhs < lhs; -} - -bool operator<=(const PluginCleaningData& lhs, const PluginCleaningData& rhs) { - return !(lhs > rhs); -} - -bool operator>=(const PluginCleaningData& lhs, const PluginCleaningData& rhs) { - return !(lhs < rhs); -} } diff --git a/cpp/src/api/metadata/tag.cpp b/cpp/src/api/metadata/tag.cpp index 65fb2090..d3d84169 100644 --- a/cpp/src/api/metadata/tag.cpp +++ b/cpp/src/api/metadata/tag.cpp @@ -36,33 +36,20 @@ std::string Tag::GetName() const { return name_; } std::string Tag::GetCondition() const { return condition_; } -bool operator==(const Tag& lhs, const Tag& rhs) { - return lhs.IsAddition() == rhs.IsAddition() && - lhs.GetName() == rhs.GetName() && - lhs.GetCondition() == rhs.GetCondition(); -} - -bool operator!=(const Tag& lhs, const Tag& rhs) { return !(lhs == rhs); } - -bool operator<(const Tag& lhs, const Tag& rhs) { +std::strong_ordering operator<=>(const Tag& lhs, const Tag& rhs) { if (lhs.IsAddition() != rhs.IsAddition()) { - return lhs.IsAddition() && !rhs.IsAddition(); + if (lhs.IsAddition()) { + return std::strong_ordering::less; + } + + return std::strong_ordering::greater; } - if (lhs.GetName() < rhs.GetName()) { - return true; + auto nameOrder = lhs.GetName() <=> rhs.GetName(); + if (nameOrder != std::strong_ordering::equal) { + return nameOrder; } - if (rhs.GetName() < lhs.GetName()) { - return false; - } - - return lhs.GetCondition() < rhs.GetCondition(); + return lhs.GetCondition() <=> rhs.GetCondition(); } - -bool operator>(const Tag& lhs, const Tag& rhs) { return rhs < lhs; } - -bool operator<=(const Tag& lhs, const Tag& rhs) { return !(lhs > rhs); } - -bool operator>=(const Tag& lhs, const Tag& rhs) { return !(lhs < rhs); } } diff --git a/cpp/src/lib.rs b/cpp/src/lib.rs index d1be5b61..4ddfde59 100644 --- a/cpp/src/lib.rs +++ b/cpp/src/lib.rs @@ -615,6 +615,8 @@ mod ffi { pub fn boxed_clone(&self) -> Box; + pub fn cmp(&self, other: &Filename) -> i8; + pub fn eq(&self, other: &Filename) -> bool; pub fn ne(&self, other: &Filename) -> bool; diff --git a/cpp/src/metadata.rs b/cpp/src/metadata.rs index 72c11ad5..ca568850 100644 --- a/cpp/src/metadata.rs +++ b/cpp/src/metadata.rs @@ -446,7 +446,7 @@ impl From> for libloot::metadata::File { } } -#[derive(Clone, Debug, PartialEq, PartialOrd)] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] #[repr(transparent)] pub struct Filename(libloot::metadata::Filename); @@ -459,6 +459,14 @@ impl Filename { Box::new(Self(self.0.clone())) } + #[expect( + clippy::as_conversions, + reason = "Ordering is repr(i8) but provides no way to convert to i8 without 'as'" + )] + pub fn cmp(&self, other: &Self) -> i8 { + Ord::cmp(self, other) as i8 + } + delegate! { to self.0 { pub fn as_str(&self) -> &str; diff --git a/cpp/src/tests/api/interface/main.cpp b/cpp/src/tests/api/interface/main.cpp index f278e612..936dccb8 100644 --- a/cpp/src/tests/api/interface/main.cpp +++ b/cpp/src/tests/api/interface/main.cpp @@ -26,6 +26,7 @@ #include "loot/api.h" #include "tests/api/interface/metadata/file_test.h" +#include "tests/api/interface/metadata/filename_test.h" #include "tests/api/interface/metadata/group_test.h" #include "tests/api/interface/metadata/location_test.h" #include "tests/api/interface/metadata/message_content_test.h" diff --git a/cpp/src/tests/api/interface/metadata/filename_test.h b/cpp/src/tests/api/interface/metadata/filename_test.h new file mode 100644 index 00000000..b92ce0e5 --- /dev/null +++ b/cpp/src/tests/api/interface/metadata/filename_test.h @@ -0,0 +1,81 @@ +/* LOOT + +A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and +Fallout: New Vegas. + +Copyright (C) 2014-2016 WrinklyNinja + +This file is part of LOOT. + +LOOT is free software: you can redistribute +it and/or modify it under the terms of the GNU General Public License +as published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +LOOT is distributed in the hope that it will +be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with LOOT. If not, see +. +*/ + +#ifndef LOOT_TESTS_API_INTERFACE_METADATA_FILENAME_TEST +#define LOOT_TESTS_API_INTERFACE_METADATA_FILENAME_TEST + +#include + +#include "loot/metadata/filename.h" + +namespace loot::test { +TEST(Filename, defaultConstructorShouldInitialiseEmptyString) { + Filename filename; + + EXPECT_EQ("", std::string(filename)); +} + +TEST(Filename, stringConstructorShouldStoreGivenString) { + Filename filename("name"); + + EXPECT_EQ("name", std::string(filename)); +} + +TEST(Filename, equalityShouldBeCaseInsensitive) { + Filename filename1("name"); + Filename filename2("name"); + + EXPECT_TRUE(filename1 == filename2); + + filename1 = Filename("name"); + filename2 = Filename("Name"); + + EXPECT_TRUE(filename1 == filename2); + + filename1 = Filename("name1"); + filename2 = Filename("name2"); + + EXPECT_FALSE(filename1 == filename2); +} + +TEST(Filename, orderingShouldBeWeakAndCaseInsensitivelyLexicographical) { + Filename filename1("name"); + Filename filename2("name"); + + EXPECT_EQ(std::weak_ordering::equivalent, filename1 <=> filename2); + + filename1 = Filename("name"); + filename2 = Filename("Name"); + + EXPECT_EQ(std::weak_ordering::equivalent, filename1 <=> filename2); + + filename1 = Filename("name1"); + filename2 = Filename("name2"); + + EXPECT_EQ(std::weak_ordering::less, filename1 <=> filename2); + +} +} + +#endif diff --git a/cpp/src/tests/api/interface/metadata/tag_test.h b/cpp/src/tests/api/interface/metadata/tag_test.h index 39836935..079b2281 100644 --- a/cpp/src/tests/api/interface/metadata/tag_test.h +++ b/cpp/src/tests/api/interface/metadata/tag_test.h @@ -47,6 +47,40 @@ TEST(Tag, dataConstructorShouldSetFieldsToGivenValues) { EXPECT_EQ("condition", tag.GetCondition()); } +TEST(Tag, orderingShouldCompareNamesAndConditionsLexicographically) { + Tag tag1("name", true, "condition"); + Tag tag2("name", true, "condition"); + + EXPECT_EQ(std::weak_ordering::equivalent, tag1 <=> tag2); + + tag1 = Tag("name"); + tag2 = Tag("Name"); + + EXPECT_EQ(std::weak_ordering::greater, tag1 <=> tag2); + + tag1 = Tag("name", true, "condition"); + tag2 = Tag("name", true, "Condition"); + + EXPECT_EQ(std::weak_ordering::greater, tag1 <=> tag2); + + tag1 = Tag("name1"); + tag2 = Tag("name2"); + + EXPECT_EQ(std::weak_ordering::less, tag1 <=> tag2); + + tag1 = Tag("name", true, "condition1"); + tag2 = Tag("name", true, "condition2"); + + EXPECT_EQ(std::weak_ordering::less, tag1 <=> tag2); +} + +TEST(Tag, orderingShouldMakeAdditionsLessThanRemovals) { + Tag tag1("name", true); + Tag tag2("name", false); + + EXPECT_EQ(std::weak_ordering::less, tag1 <=> tag2); +} + TEST(Tag, equalityShouldBeCaseSensitiveOnNameAndCondition) { Tag tag1("name", true, "condition"); Tag tag2("name", true, "condition");