Replace C++ comparison operators with <=>

This commit is contained in:
Oliver Hamlet
2025-06-11 22:13:53 +01:00
parent 4ffd62572d
commit 4e088e4dce
22 changed files with 211 additions and 646 deletions
-51
View File
@@ -45,55 +45,4 @@ std::vector<MessageContent> 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); }
}
+16 -21
View File
@@ -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;
}
}
-34
View File
@@ -35,38 +35,4 @@ std::string Group::GetName() const { return name_; }
std::string Group::GetDescription() const { return description_; }
std::vector<std::string> 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); }
}
-30
View File
@@ -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);
}
}
-36
View File
@@ -54,40 +54,4 @@ MessageType Message::GetType() const { return type_; }
std::vector<MessageContent> 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); }
}
-33
View File
@@ -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<MessageContent> SelectMessageContent(
const std::vector<MessageContent> content,
std::string_view language) {
@@ -57,73 +57,4 @@ std::string PluginCleaningData::GetCleaningUtility() const { return utility_; }
std::vector<MessageContent> 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);
}
}
+10 -23
View File
@@ -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); }
}
+2
View File
@@ -615,6 +615,8 @@ mod ffi {
pub fn boxed_clone(&self) -> Box<Filename>;
pub fn cmp(&self, other: &Filename) -> i8;
pub fn eq(&self, other: &Filename) -> bool;
pub fn ne(&self, other: &Filename) -> bool;
+9 -1
View File
@@ -446,7 +446,7 @@ impl From<Box<File>> 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;
+1
View File
@@ -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"
@@ -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
<https://www.gnu.org/licenses/>.
*/
#ifndef LOOT_TESTS_API_INTERFACE_METADATA_FILENAME_TEST
#define LOOT_TESTS_API_INTERFACE_METADATA_FILENAME_TEST
#include <gtest/gtest.h>
#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
@@ -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");