记录 | 大学里的最后一段时光 #日记楼

今天加班了。因为发现了一个很严重的缺陷:当项目使用 io_uring 的方式,向下方的 mooncake 缓存传递 msg_key 来获得 value 的时候,顶层的队列析构时需要显式通知下面释放内存,否则在新的 WQ 出现时,调用底层 mooncake 有可能会因为没有显式通知底层导致 memory 被 pin 住没有释放,造成写入失败。于是增加了一个单测,来 hack 掉这样的一种情况。后面再看他们如何显式通知下方 mooncake 缓存进行释放。此外修复了异步状态下获取到不正确的 key 的问题,采用版本控制的手段进行(对的就是增加版本号然后 epoll 一个个轮询)。

今天还完成了一个 dockerfile 和 dev-container.json 准备用于项目在 ubuntu20.04 和 ubuntu22.04 之间的分发。因为目前需求的节点具有两种不同的系统,因此我们的打包需要兼顾两种系统不同的 ABI 和 syscall。docker+k8s 就好了。

3304. 找出第 K 个字符 I

简单题不想多想,brute-force 就好了。

C++
class Solution {
public:
    char kthCharacter(int k) {
        string str;
        string word = "a";
        for(int i = 0; i < 9; i++){
            str = word;
            for(auto x : word){
                str += (x + 1);
            }
            word = str;
        }
        char ans = str[k - 1];
        return ans;
    }
};

今天没有图了 :bilibili_aojiao: 明天再贴,因为想睡觉 :face_with_spiral_eyes:

Mark: 来自 :carrot: 群:Introducing maple trees

5 Likes

hack!

2 Likes

0 ms runtime :blush:

char kthCharacter(int k) {
    int op = 0;
    while (k > 1) {
        op++;
        int n = int(log2(k));
        k -= int(pow(2, n)) == k ? int(pow(2, n)) / 2 : int(pow(2, n));
    }
    return char(op % 26 + 'a');
}
2 Likes

2025 年 7 月 6 日 星期日 天气:晴
今天在 tuple hash 的过程中遇到了问题。原生的 std::tuple 并不支持 hash。那么我们就自己来写一个吧,顺便学习一下相关的奇怪知识。

以下实现是作者自己的理解,可能有误,望读者批评指正!

首先我们知道,对于一个哈希的重载,std::hash 是一个结构体,我们需要重载他的 () 来实现自己的哈希函数。我们的大概想法如下:

template<typename T>
struct std::hash<T> {
    std::size_t operator()(const T & arg) const {
        return my_hash(arg);
    }
};

那么对于一个 tuple,因为他的模板特化时模板参数不定长,我们就需要采用变长模板来实现我们的 hash 结构体重载 operator()。这样我们大概为:

template<typename ... T>
struct std::hash<std::tuple<T...>> {
    std::size_t operator()(const std::tuple<T...> & arg) const {
        // variadic template deal;
    }
};

这样我们就需要思考如何递归地解决我们的模板展开。我们需要通过实现递归式地展开直到到达模板的末尾,通过 hash_combine 的方式来一个个组合成我们的最终 hash 值。首先我们先定义 hash_combine, 他将获得 tuple 中含有的基本类型

template <typename T>
inline void hash_combine(std::size_t& seed, const T& val) {
    std::hash<T> hasher;
    seed ^= hasher(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}

接下来我们需要一个个地取值放入其中。我们可以通过:

template<std::size_t I = 0, typename ... T>
typename std::enable_if<(I < sizeof...(T)), void>::type
my_hash(std::size_t & seed, const std::tuple<T...> & tup) {
    hash_combine(seed, std::get<I>(tup));
    my_hash<I + 1, T...>(seed, tup);
}

首先学习一下 std::enable_if<B,T>。在 cppreference 上你可以看到:

If B is true, std::enable_if has a public member typedef type, equal to T; otherwise, there is no member typedef.

This metafunction is a convenient way to leverage SFINAE prior to C++20’s concepts, in particular for conditionally removing functions from the candidate set based on type traits, allowing separate function overloads or specializations based on those different type traits.

当 B(表达式)为 true 的时候,我们的 std::enable_if 将会具有 public 成员类型 T, 否则将不会具有类型的定义。这样,我们的元方程就可以使用 SFINAE(“Substitution Failure Is Not An Error”,替代失败并不是错误) 特性(其实我还没弄懂这到底是个什么),特别是基于类型萃取来讲函数从候选集合中移除(这里涉及到重载决议),允许不同的函数重载/特化基于不同的类型萃取。

说了一大段废话,其实就是:符合 B 的时候,函数出现并返回 T 类型。否则函数不会出现(不会被重载选择)。

这样在最后我们补充一个递归终点:

template <std::size_t Index = 0, typename... Types>
inline typename std::enable_if<Index == sizeof...(Types), void>::type
my_hash(std::size_t&, const std::tuple<Types...>&) {
}

这样,在 index 没有到达模板参数长度时,我们将采取前面的函数,持续递归。否则什么都不做。
最后补充上我们的结构体。在 C++11 的标准下就可以运行。可以尝试使用查看:

compiler explorer 1 C+±11 version
compiler explorer 2 boost mimic

C++-11 Version
template <typename T>
inline void hash_combine(std::size_t& seed, const T& val) {
    std::hash<T> hasher;
    seed ^= hasher(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}

template <std::size_t Index = 0, typename... Types>
inline typename std::enable_if<Index == sizeof...(Types), void>::type
my_hash(std::size_t&, const std::tuple<Types...>&) {
}

template<std::size_t I = 0, typename ... T>
typename std::enable_if<(I < sizeof...(T)), void>::type
my_hash(std::size_t & seed, const std::tuple<T...> & tup) {
    hash_combine(seed, std::get<I>(tup));
    my_hash<I + 1, T...>(seed, tup);
}

template <typename ... T>
struct std::hash<std::tuple<T...> > {
    std::size_t operator()(const tuple<T...> & tup) const {
        std::size_t seed = 0;
        my_hash(seed, tup);
        return seed;
    }
};

实际上这已经很接近我们 boost 库的实现,在 boost 库中,我们的 enable_if 采用的是通过 std::tuple_size<T>::size 来实现。

Boost Implementation(戏仿)
template<class T>
void hash_combine(std::size_t & seed, T element) {
    std::hash<T> hasher;
    seed ^= hasher(element) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}

template<std::size_t I, typename T>
typename std::enable_if<(I == std::tuple_size<T>::value), void>::type
    hash_combine_tuple_like(std::size_t &, T const &)
{
}

template<std::size_t I, typename T>
typename std::enable_if<(I < std::tuple_size<T>::value), void>::type
    hash_combine_tuple_like(std::size_t & seed, T const & v) 
{
    hash_combine(seed, std::get<I>(v));
    hash_combine_tuple_like<I+1>(seed, v);
}

template <class T>
std::size_t hash_tuple(T const & v) {
    std::size_t seed = 0;
    hash_combine_tuple_like<0>(seed, v);
    return seed;
}

template <class T>
struct hash_tup {
    std::size_t operator()(T const & val) const {
        return hash_tuple<T>(val);
    }
};

参考资料: boost container.hash

挖坑:后面再学习闭包,闭包展开,折叠表达式等相关技巧。

今日每日一题:

1865. 找出和为指定值的下标对

C++
class FindSumPairs {
private:
    vector<int> nums1, nums2;
    unordered_map<int, int> cnt;

public:
    FindSumPairs(vector<int>& nums1, vector<int>& nums2) {
        this->nums1 = nums1;
        this->nums2 = nums2;
        for (int num: nums2) {
            ++cnt[num];
        }
    }
    
    void add(int index, int val) {
        cnt[nums2[index]]--;
        nums2[index] += val;
        cnt[nums2[index]]++;
    }
    
    int count(int tot) {
        int ans = 0;
        for (int num: nums1) {
            int res = tot - num;
            if (cnt.count(res)) {
                ans += cnt[res];
            }
        }
        return ans;
    }
};
4 Likes

斯~挂梯子才能上,我还以为维护呢试了两天,主动屏蔽国内了吗

3 Likes

看样子是的:pleading_face:
往好处想 或许没那么容易被时间了 可以更好地防盒()

4 Likes

std::make_index_sequence !

2 Likes

先挖坑~后面再补 :face_savoring_food:

1 Like

“We are all in the gutter, but some of us are looking at the stars.”

晚安,塬友们。我们终将一步步,走向属于我们自己的彼岸。

X: @mikoshi_illust

7 Likes