]> PatchyGit - patchyircd.git/commitdiff
map: use <=> for case insensitive comparisons
authorEgor <egor@patchysicp.xyz>
Sun, 1 Feb 2026 12:36:25 +0000 (14:36 +0200)
committerEgor <egor@patchysicp.xyz>
Sun, 1 Feb 2026 12:36:25 +0000 (14:36 +0200)
src/common.hpp
src/map.cpp

index bb04b8f..2a88544 100644 (file)
@@ -29,6 +29,7 @@
 /* C++ standard */
 #include <algorithm>
 #include <charconv>
+#include <compare>
 #include <deque>
 #include <functional>
 #include <iostream>
index 0134dac..18cfb9c 100644 (file)
@@ -3,42 +3,71 @@
 #include "common.hpp"
 #include "map.hpp"
 #include "ircdata.hpp"
-static int istrcmp(const char *a, const char *b) {
-       unsigned char cha, chb;
-       int diff;
-       do {
-               cha = *a++;
-               chb = *b++;
-               if (chb >= 'A' && chb <= 'Z')
-                       chb |= 0x20;
-               diff = cha - chb;
-       } while (!diff && cha && chb);
-       return diff;
-}
-template<auto cmp=strcmp>
-static size_t ent_find(map_base *root, const char *key, int *found)
+
+template<typename A, typename B>
+class Comparisons {
+       friend constexpr bool operator==(const A& lhs, const B& rhs) noexcept(noexcept(lhs <=> rhs)) { return lhs <=> rhs == 0; }
+       friend constexpr bool operator!=(const A& lhs, const B& rhs) noexcept(noexcept(lhs <=> rhs)) { return lhs <=> rhs != 0; }
+       friend constexpr bool operator< (const A& lhs, const B& rhs) noexcept(noexcept(lhs <=> rhs)) { return lhs <=> rhs <  0; }
+       friend constexpr bool operator<=(const A& lhs, const B& rhs) noexcept(noexcept(lhs <=> rhs)) { return lhs <=> rhs <= 0; }
+       friend constexpr bool operator> (const A& lhs, const B& rhs) noexcept(noexcept(lhs <=> rhs)) { return lhs <=> rhs >  0; }
+       friend constexpr bool operator>=(const A& lhs, const B& rhs) noexcept(noexcept(lhs <=> rhs)) { return lhs <=> rhs >= 0; }
+
+       friend constexpr bool operator==(const B& lhs, const A& rhs) noexcept(noexcept(lhs <=> rhs)) { return lhs <=> rhs == 0; }
+       friend constexpr bool operator!=(const B& lhs, const A& rhs) noexcept(noexcept(lhs <=> rhs)) { return lhs <=> rhs != 0; }
+       friend constexpr bool operator< (const B& lhs, const A& rhs) noexcept(noexcept(lhs <=> rhs)) { return lhs <=> rhs <  0; }
+       friend constexpr bool operator<=(const B& lhs, const A& rhs) noexcept(noexcept(lhs <=> rhs)) { return lhs <=> rhs <= 0; }
+       friend constexpr bool operator> (const B& lhs, const A& rhs) noexcept(noexcept(lhs <=> rhs)) { return lhs <=> rhs >  0; }
+       friend constexpr bool operator>=(const B& lhs, const A& rhs) noexcept(noexcept(lhs <=> rhs)) { return lhs <=> rhs >= 0; }
+};
+
+class LowercasingView : Comparisons<std::string_view, LowercasingView> {
+       std::string_view sv;
+public:
+       explicit constexpr LowercasingView(std::string_view sv) :sv(sv) {}
+       friend constexpr std::strong_ordering operator<=>(std::string_view lhs, LowercasingView rhs) noexcept {
+               size_t len = std::min(lhs.size(), rhs.sv.size());
+               const char *a = lhs.data();
+               const char *b = rhs.sv.data();
+               unsigned char cha, chb;
+               while (len--) {
+                       cha = *a++;
+                       chb = *b++;
+                       if (chb >= 'A' && chb <= 'Z')
+                               chb |= 0x20;
+                       if (auto diff = cha <=> chb; diff != 0)
+                               return diff;
+               }
+               return lhs.size() <=> rhs.sv.size();
+       }
+       friend constexpr std::strong_ordering operator<=>(LowercasingView lhs, std::string_view rhs) noexcept {
+               return rhs <=> lhs;
+       }
+};
+
+static size_t ent_find(map_base *root, auto key, int *found)
 {
        auto it = std::partition_point(root->ptr, root->ptr + root->len,
-                       [key](const auto &p){ return cmp(p.key, key) < 0; });
-       *found = it != root->ptr + root->len && !cmp(it->key, key);
+                       [key](const auto &p){ return std::string_view(p.key) < key; });
+       *found = it != root->ptr + root->len && std::string_view(it->key) == key;
        return it - root->ptr;
 }
 void *map_base::_get(const char *key)
 {
        int found;
-       size_t i = ent_find(this, key, &found);
+       size_t i = ent_find(this, std::string_view(key), &found);
        return found ? ptr[i].value : 0;
 }
 void *map_base::_iget(const char *key)
 {
        int found;
-       size_t i = ent_find<istrcmp>(this, key, &found);
+       size_t i = ent_find(this, LowercasingView(key), &found);
        return found ? ptr[i].value : 0;
 }
 void map_base::_set(const char *key, const void *value, void **oldvalue)
 {
        int found;
-       size_t i = ent_find(this, key, &found);
+       size_t i = ent_find(this, std::string_view(key), &found);
        if (found) {
                if (oldvalue)
                        *oldvalue = ptr[i].value;