From 59044862a902913700c3e7062ac8cfa43811c420 Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Wed, 17 Oct 2018 14:04:18 -0400
Subject: [PATCH] registered_cache: Deduplicate results of ListEntry and
 ListEntryFilter Prevents a Entry from appearing in the list twice if the user
 has it installed in two places (e.g. User NAND and SDMC)

---
 src/core/file_sys/registered_cache.cpp | 11 +++++++++++
 src/core/file_sys/registered_cache.h   |  7 +++++--
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index 1febb398e1..d1dea5e826 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -2,6 +2,7 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include <algorithm>
 #include <regex>
 #include <mbedtls/sha256.h>
 #include "common/assert.h"
@@ -30,6 +31,10 @@ bool operator<(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs)
     return (lhs.title_id < rhs.title_id) || (lhs.title_id == rhs.title_id && lhs.type < rhs.type);
 }
 
+bool operator==(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs) {
+    return std::tie(lhs.title_id, lhs.type) == std::tie(rhs.title_id, rhs.type);
+}
+
 static bool FollowsTwoDigitDirFormat(std::string_view name) {
     static const std::regex two_digit_regex("000000[0-9A-F]{2}", std::regex_constants::ECMAScript |
                                                                      std::regex_constants::icase);
@@ -593,6 +598,9 @@ std::vector<RegisteredCacheEntry> RegisteredCacheUnion::ListEntries() const {
             },
             [](const CNMT& c, const ContentRecord& r) { return true; });
     }
+
+    std::sort(out.begin(), out.end());
+    out.erase(std::unique(out.begin(), out.end()), out.end());
     return out;
 }
 
@@ -616,6 +624,9 @@ std::vector<RegisteredCacheEntry> RegisteredCacheUnion::ListEntriesFilter(
                 return true;
             });
     }
+
+    std::sort(out.begin(), out.end());
+    out.erase(std::unique(out.begin(), out.end()), out.end());
     return out;
 }
 } // namespace FileSys
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h
index 5ddacba475..aeb1c69bac 100644
--- a/src/core/file_sys/registered_cache.h
+++ b/src/core/file_sys/registered_cache.h
@@ -50,6 +50,9 @@ constexpr u64 GetUpdateTitleID(u64 base_title_id) {
 // boost flat_map requires operator< for O(log(n)) lookups.
 bool operator<(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs);
 
+// std unique requires operator== to identify duplicates.
+bool operator==(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs);
+
 /*
  * A class that catalogues NCAs in the registered directory structure.
  * Nintendo's registered format follows this structure:
@@ -60,8 +63,8 @@ bool operator<(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs)
  *         | 00
  *         | 01 <- Actual content split along 4GB boundaries. (optional)
  *
- * (This impl also supports substituting the nca dir for an nca file, as that's more convenient when
- * 4GB splitting can be ignored.)
+ * (This impl also supports substituting the nca dir for an nca file, as that's more convenient
+ * when 4GB splitting can be ignored.)
  */
 class RegisteredCache {
     friend class RegisteredCacheUnion;
-- 
GitLab