Todo

Generalize this code

Info

#include <iostream>
#include <format>
#include <ranges>
#include <print>
#include <set>
#include <vector>
#include <unordered_map>
 
auto cmp = [](auto const& entry1, auto const& entry2) -> bool {
    if (auto cmp = entry1.rank <=> entry2.rank; std::is_neq(cmp)) {
        return std::is_gt(cmp);
    }
    if (auto cmp = entry1.id <=> entry2.id; std::is_neq(cmp)) {
        return std::is_lt(cmp);
    }
    return 0;
};
 
class Leaderboard {
private:
    class Entry {
    public:
        int id;
        int rank;
    };
 
    std::set<Entry, decltype(cmp)> entries;
    using It = decltype(entries)::iterator;
    std::unordered_map<int, It> userToEntryMap;
 
public:
    void insert(int id) {
        auto const& [mapIt, isInserted] = userToEntryMap.try_emplace(id);
        if (!isInserted) {
            throw std::invalid_argument(std::format(
                "argument id `{}` already exists in leaderboard",
                id
            ));
        }
        auto const& [entryIt, _] = entries.emplace(id, 0);
        mapIt->second = entryIt;
    }
 
    void update(int id, int rank) {
        auto mapIt = userToEntryMap.find(id);
        if (mapIt == userToEntryMap.end()) {
            throw std::invalid_argument(std::format(
                "argument id `{}` doesn't exist in leaderboard",
                id
            ));
        }
        auto entryIt = mapIt->second;
        
        auto nodeHandle = entries.extract(entryIt);
        nodeHandle.value().rank = rank;
        mapIt->second = entries.insert(std::move(nodeHandle)).position;
    }
 
    std::vector<int> top(int k) const {
        return entries
            | std::views::take(k)
            | std::views::transform([](auto const& entry) { return entry.id; })
            | std::ranges::to<std::vector>();
    }
 
    std::vector<int> nearbyUsers(int id, int k) const {
        auto mapIt = userToEntryMap.find(id);
        if (mapIt == userToEntryMap.end()) {
            throw std::invalid_argument(std::format(
                "argument id `{}` doesn't exist in leaderboard",
                id
            ));
        }
        auto entryIt = mapIt->second;
 
        auto endIt = std::ranges::next(entryIt, (k + 1) / 2, entries.end());
        auto startIt = std::ranges::prev(endIt, k, entries.begin());
 
        return std::ranges::subrange {startIt, entries.end()}
            | std::views::take(k)
            | std::views::transform([](auto const& entry) { return entry.id; })
            | std::ranges::to<std::vector>();
    }
};
 
int main() {
    auto leaderboard = Leaderboard {};
    auto print_vector = [](auto const& vec) {
        for (auto const& element: vec) {
            std::print("{} ", element);
        }
        std::println();
    };
 
    leaderboard.insert(2);
    leaderboard.insert(3);
    leaderboard.update(2, 3);
    leaderboard.insert(1);
    leaderboard.insert(6);
    leaderboard.update(1, 5);
    print_vector(leaderboard.top(1));
    print_vector(leaderboard.top(2));
    print_vector(leaderboard.top(3));
    print_vector(leaderboard.top(4));
    leaderboard.update(2, 9);
    print_vector(leaderboard.top(5));
    leaderboard.update(3, 11);
    print_vector(leaderboard.top(5));
    leaderboard.update(6, 8);
    print_vector(leaderboard.top(5));
    print_vector(leaderboard.nearbyUsers(6, 1));
    print_vector(leaderboard.nearbyUsers(6, 2));
    print_vector(leaderboard.nearbyUsers(6, 3));
    print_vector(leaderboard.nearbyUsers(6, 4));
    print_vector(leaderboard.nearbyUsers(6, 5));
    print_vector(leaderboard.nearbyUsers(6, 6));
    leaderboard.update(6, 2);
    print_vector(leaderboard.top(4));
    print_vector(leaderboard.nearbyUsers(6, 1));
    print_vector(leaderboard.nearbyUsers(6, 2));
    print_vector(leaderboard.nearbyUsers(6, 3));
    print_vector(leaderboard.nearbyUsers(6, 4));
    print_vector(leaderboard.nearbyUsers(6, 5));
    print_vector(leaderboard.nearbyUsers(6, 6));
}