From bdc7fbba6bf60e18d227cd652c55194d13ddee99 Mon Sep 17 00:00:00 2001 From: Ted Mostly Date: Fri, 15 Dec 2023 22:28:35 +0800 Subject: [PATCH] 142 (#84) --- README.md | 6 +- posts/130.md | 2 +- posts/142.md | 525 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 529 insertions(+), 4 deletions(-) create mode 100644 posts/142.md diff --git a/README.md b/README.md index 385aae8..4c18c45 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ RSS使用仓库的release RSS [链接](https://github.com/wanghenshui/cppweeklyn ## 2023 -| [141](./posts/141.md) | | | | | | | | | | +| [141](./posts/141.md) | [142](./posts/142.md) | | | | | | | | | | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | | [131](./posts/131.md) | [132](./posts/132.md) | [133](./posts/133.md) | [134](./posts/134.md) | [135](./posts/135.md) | [136](./posts/136.md) | [137](./posts/137.md) | [138](./posts/138.md) | [139](./posts/139.md) | [140](./posts/140.md) | | [121](./posts/121.md) | [122](./posts/122.md) | [123](./posts/123.md) | [124](./posts/124.md) | [125](./posts/125.md) | [126](./posts/126.md) | [127](./posts/127.md) | [128](./posts/128.md) | [129](./posts/129.md) | [130](./posts/130.md) | @@ -88,8 +88,8 @@ RSS使用仓库的release RSS [链接](https://github.com/wanghenshui/cppweeklyn - Amnesia x2 - fengyiee木马 - 陈青松 -- 黄亮Anthony x4 +- 黄亮Anthony x5 - Captain - Anien - jerry -- HNY \ No newline at end of file +- HNY x2 \ No newline at end of file diff --git a/posts/130.md b/posts/130.md index 3c08d5e..80fb069 100644 --- a/posts/130.md +++ b/posts/130.md @@ -210,7 +210,7 @@ template #### [False sharing and 128-byte alignment/padding](https://stackoverflow.com/questions/29199779/false-sharing-and-128-byte-alignment-padding) -为啥用128,之前不是64么?CPU进化了我超 +为啥用128,之前不是64么?cacheline 不是64吗 CPU进化了我超 > "Intel® 64 and IA-32 architectures optimization reference manual", in section 3.7.3 "Hardware Prefetching for Second-Level Cache", about the Intel Core microarchitecture: diff --git a/posts/142.md b/posts/142.md new file mode 100644 index 0000000..daff419 --- /dev/null +++ b/posts/142.md @@ -0,0 +1,525 @@ +--- +layout: post +title: 第142期 +--- +# C++ 中文周刊 第142期 + + +[周刊项目地址](https://github.com/wanghenshui/cppweeklynews) + +公众号 + + + +qq群 [手机qq点击进入](https://qm.qq.com/q/6NGizNPyG4) + +RSS https://github.com/wanghenshui/cppweeklynews/releases.atom + +欢迎投稿,推荐或自荐文章/软件/资源等 + +请[提交 issue](https://github.com/wanghenshui/cppweeklynews/issues) + + +文章大部分来自 + +https://discu.eu/weekly/candcpp/2023/49/ + +https://www.meetingcpp.com/blog/blogroll/items/Meeting-Cpp-weekly-Blogroll-408.html + +本期文章由 黄亮Anthony 赞助 + +--- + + +## 资讯 + +标准委员会动态/ide/编译器信息放在这里 + +编译器信息最新动态推荐关注hellogcc公众号 [OSDT Weekly 2023-12-13 第232期 ](https://mp.weixin.qq.com/s/p9umOpwJCBMSHr9y3zVTqw) + +另外PLCT有rsicv竞赛,感兴趣的可以参加一下 rvspoc.org + +boost发布1.84版本,c++03全部抛弃,windows只支持win10及以上 + +新增redis cobalt库之前讲过 + +另外asio移除了execution相关设计。。 + +PFR支持fieldname 反射,要求c++20 https://github.com/boostorg/pfr/pull/129/files + +效果 https://godbolt.org/z/xbo7bos86 + +```c++ +#include +#include +#include +#include + +struct Any { + Any() {}; +}; + +struct XClass { + int member1; + Any this_is_a_name; // not constexpr constructible + std::reference_wrapper c; // not default constructible +}; + +int main() { + char buf[32] {0}; + constexpr auto first = boost::pfr::get_name<0, XClass>(); + memcpy(buf, first.data(), first.size()); + puts(buf); + + static_assert("member1" == boost::pfr::get_name<0, XClass>()); + static_assert("this_is_a_name" == boost::pfr::get_name<1, XClass>()); + static_assert("c" == boost::pfr::get_name<2, XClass>()); +} +``` + +Unordered支持concurrent_flat_set以及并发visit + +其他的没啥说的。自己看吧 + +https://www.boost.org/users/history/version_1_84_0.html + +## 文章 + + +- [Text Editor Data Structures](https://cdacamar.github.io/data%20structures/algorithms/benchmarking/text%20editors/c++/editor-data-structures/) +- [Text Editor Data Structures: Rethinking Undo](https://cdacamar.github.io/data%20structures/algorithms/benchmarking/text%20editors/c++/rethinking-undo/) + +代码在这里 https://github.com/cdacamar/fredbuf + +手把手教你实现编辑器 + + + +- [Measuring the size of the cache line empirically](https://lemire.me/blog/2023/12/12/measuring-the-size-of-the-cache-line-empirically/) + +在130期咱们就聊过,如果cacheline 64,设置align 128能降低影响。lemire给了一种简单的测试方法,拷贝数组 + +https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/blob/master/2023/12/12/cacheline.c + +小于cacheline,带宽没啥区别,受cacheline影响了,大于cacheline,越大越快,理论上加入cacheline 64 拷贝128,应该获得翻倍的速度,但是实际上并不是 + +建议大家自己玩玩,测一下效果。在m1表现也不太一样,但是小于cacheline拷贝速度不变这个现象是不变的 + +- [A Bug in the Priority Scheduler for Coroutines](https://www.modernescpp.com/index.php/a-bug-in-the-priority-scheduler-for-coroutines/) + +140期的调度器实现有bug,问题代码 + +```c++ +class Scheduler { + + std::priority_queue, Comperator> _prioTasks; + + public: + void emplace(int prio, std::coroutine_handle<> task) { + _prioTasks.push(std::make_pair(prio, task)); + } +}; +Task createTask(const std::string& name) { + std::cout << name << " start\n"; + co_await std::suspend_always(); + for (int i = 0; i <= 3; ++i ) { + std::cout << name << " execute " << i << "\n"; // (5) + co_await std::suspend_always(); + } + co_await std::suspend_always(); + std::cout << name << " finish\n"; +} + +scheduler1.emplace(0, createTask("TaskA").get_handle()); +``` + +看出来哪里有问题没有?createtask 的name的生命周期问题 + +- [In C++, how can I make a member function default parameter depend on this?](https://devblogs.microsoft.com/oldnewthing/20231206-00/?p=109108) + +成员函数参数不能直接用this + +```c++ +struct Sample +{ + int increment; + void add(int v = increment); // not allowed + void notify_all(Sample* source = this); // not allowed +}; +``` + +猥琐绕过 + +```c++ +struct Sample +{ + int increment; + + void add(int v); + void add() { add(increment); } + + void notify_all(Sample* source); + void notify_all() { notify_all(this); } +}; + +Sample s; + +s.add(2); // adds 2 +s.add(); // adds s.increment + +s.notify_all(); // uses source = s +s.notify_all(other); // uses source = other +``` + +- [Higher quality random floats](https://www.corsix.org/content/higher-quality-random-floats) + +随机浮点数 + +比如 这个实现 https://dotat.at/@/2023-06-23-random-double.html + +```c++ +double pcg64_random_double(pcg64_t *rng) { + return (double)(pcg64_random(rng) >> 11) * 0x1.0p-53; +} +``` + +luajit是这样的 + +```c++ +uint64_t lj_prng_u64d(PRNGState *rs) { + uint64_t z, r = 0; + TW223_STEP(rs, z, r) + /* Returns a double bit pattern in the range 1.0 <= d < 2.0. */ + return (r & 0x000fffffffffffffull) | 0x3ff0000000000000ull; +} +/* Then to give d in [0, 1) range: */ +U64double u; +double d; +u.u64 = lj_prng_u64d(rs); +d = u.d - 1.0; +``` + +lemire博士的golang版本 + +```go +// toFloat64 -> [0,1) +func toFloat64(seed *uint64) float64 { + x := splitmix64(seed) + x &= 0x1fffffffffffff // %2**53 + return float64(x) / float64(0x1fffffffffffff) +} +``` + +原理是这个 https://www.zhihu.com/question/25037345/answer/29879012 + + +01之间 + +```c++ +double rand_between_zero_and_one() { + double d; + uint64_t x = rand_u64() >> 11; /* 53-bit uniform integer */ + uint64_t e = 1022; + do { + if (rand_u64() & 1) break; /* 1-bit uniform integer */ + e -= 1; + } while (e > 1022-75); + x = ((x + 1) >> 1) + (e << 52); + memcpy(&d, &x, sizeof(d)); + return d; +} +``` +优化 + +```c++ +double rand_between_zero_and_one() { + double d; + uint64_t x = rand_u64(); + uint64_t e = __builtin_ctzll(x) - 11ull; + if ((int64_t)e >= 0) e = __builtin_ctzll(rand_u64()); + x = (((x >> 11) + 1) >> 1) - ((e - 1011ull) << 52); + memcpy(&d, &x, sizeof(d)); + return d; +} +``` + +主要是要懂浮点数格式以及如何恰当的均匀分布 + + +- [Six Handy Operations for String Processing in C++20/23 ](https://www.cppstories.com/2023/six-handy-ops-for-string-processing/) + +contains + +```c++ +#include +#include + +int main(){ + const std::string url = "https://isocpp.org"; + + if (url.contains("https") && + url.contains(".org") && + url.contains("isocpp")) + std::cout << "you're using the correct site!\n"; +} + +``` + +starts_with(), ends_with() + +insert range + +```c++ +#include +#include +#include + +int main() { + const auto source = {'l', 'i', 'b', '_'}; + std::string target{"__cpp_containers_ranges"}; + + const auto pos = target.find("container"); + auto iter = std::next(target.begin(), pos); + +#ifdef __cpp_lib_containers_ranges + target.insert_range(iter, source); +#else + target.insert(iter, source.begin(), source.end()); +#endif + + std::cout << target; +} + +``` + + +spanstream + +```c++ +#include +#include +#include // << new headeer! + +void* operator new(std::size_t sz){ + std::cout << "Allocating: " << sz << '\n'; + return std::malloc(sz); +} + +int main() { + std::cout << "start...\n"; + std::stringstream ss; + ss << "one string that doesn't fit into SSO"; + ss << "another string that hopefully won't fit"; + + std::cout << "spanstream:\n"; + char buffer[128] { 0 }; + std::span spanBuffer(buffer); + std::basic_spanstream ss2(spanBuffer); + ss2 << "one string that doesn't fit into SSO"; + ss2 << "another string that hopefully won't fit"; + + std::cout << buffer; +} + +``` + +- [How Many Lines of C it Takes to Execute a + b in Python?](https://codeconfessions.substack.com/p/cpython-dynamic-dispatch-internals) + +想了解cpython的可以看看 + +- [C++23: The rise of new streams](https://www.sandordargo.com/blog/2023/12/06/cpp23-strtream-strstream-replacement) + +介绍spanstream的, 直接贴代码了 + +```c++ +#include +#include +#include +#include + +void printSpan(auto spanToPrint) { + for (size_t i = 0; i < spanToPrint.size(); ++i) { + std::cout << spanToPrint[i]; + } +} + +void useSpanbuf() { + std::array charArray; + std::span charArraySpan(charArray); + std::spanbuf buf; + + char c = 'a'; + for (size_t i = 0; i < 16; ++i) { + charArraySpan[i] = c; + ++c; + } + + buf.span(charArraySpan); + + // we can easily print a span got from the buffer + std::span bufview = buf.span(); + std::cout << "bufview: "; + for (size_t i = 0; i < 16; ++i) { + std::cout << bufview[i]; + } + std::cout << '\n'; +} + +void useSpanstream() { + std::array charArray; + std::ospanstream oss(charArray); + + oss << "Fortytwo is " << 42; + // copying the contents to a span + std::string s{oss.span().data(),size_t(oss.span().size())}; + assert(s == "Fortytwo is 42"); +} + + +int main() { + useSpanbuf(); + useSpanstream(); + + return 0; +} +``` + +Raymond chen环节。我直接贴连接了。window是我不懂 + +- [How can I work around the absence of default parameters in the Windows Runtime?](https://devblogs.microsoft.com/oldnewthing/20231213-00/?p=109144) +- [How do I specify an optional parameter to a Windows Runtime method?](https://devblogs.microsoft.com/oldnewthing/20231214-00/?p=109146) + + +linux环节 + +- [消失的内存之共享内存shmem](https://zhuanlan.zhihu.com/p/666268134) + +shmem tmpfs 比较经典 + +- [使用pidfd实现Linux跨进程传递文件描述符](https://zhuanlan.zhihu.com/p/672314758) + +linux 5.6引入的,有意思 + +## 视频 + +- [C++ Horizons - Bryce Adelstein Lelbach - Meeting C++ 2023](https://www.youtube.com/watch?v=og4_Tm-Hkjw) + +姚奕正qds推荐 + +> 把 reflection/injection, pattern matching, senders都说了一遍,可以算是一个完全的新c++ + + +- [C++ Weekly - Ep 406 - Why Avoid Pointer Arithmetic?](https://www.youtube.com/watch?v=MsujPM2wDmk) + +在指针上做计算风险高,这也是为啥要引入span stringview,不用`char *` 信息丢失太多 + +cppcon2023 + + +cpponsea 2023 + +- [Lightning Talk: I Need a Different Variant in C++ - Robert Allan Hennigan Leahy](https://www.youtube.com/watch?v=Wgpm79yRLoI) + + +考虑一个场景, +```c++ +std::variant foo(); + +std::variant bar(){ + auto v = foo(); + ... +} +``` + +显然涉及到从std::variant不同参数的转换,怎么写? + + +```c++ +template +constexpr To variant_cast(From&& from) { + return std::visit([](auto&& a) constexpr noexcept( + std::is_nothrow_constructible_v< + To, + std::in_place_type_t>, + decltype(a) + >) -> To { + return To( + std::in_place_type>, + std::forward(a)); + }, + std::foward(from) + ); +} +``` + +存在一个问题,就是从`std::variant`到`std::variant` 没法转,太safe了,得放宽一点 + +```c++ + + +template +struct visitor { + template + requires std::constructible_from>,T> + constexpr To operator()(T&& t) const noexcept( + std::is_nothrow_constructible_v>,T>){ + return To( + std::in_place_type>, + std::forward(t)); + } + template + constexpr To operator()(T&& t) const noexcept { + std::unreachable(); + } + +}; + +template +constexpr To uncheck_variant_cast(From&& from) { + return std::visit(visitor{}, std::forward(from)); +} +``` +其实就是舍弃内部值本来的类型,用From硬推,匹配不到就失败 + +问题来了,如果是`std::variant`怎么办? + +别琢磨了,能做,不支持,去他妈的,你就非得这么写吗,No + +## 有意思的项目 + +- [asteria](https://github.com/lhmouse/asteria) 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群753302367和作者对线 (原来的群被举报了) +- [Unilang](https://github.com/linuxdeepin/unilang) deepin的一个通用编程语言,点子有点意思,也缺人,感兴趣的可以github讨论区或者deepin论坛看一看。这里也挂着长期推荐了 + +- https://github.com/couchbase/fleece 一种json实现,说是性能很好,但没有和bson cbor的横向对比。有空测一下 + +## 互动环节 + +上一期提到的有问题的代码 + +```c++ + +int median(std::vector& v) { + int mid = v.size() / 2; + std::nth_element(v.begin(), v.begin() + mid, v.end()); + int result = v[mid]; + if (v.size() % 2 == 0) { + std::nth_element(v.begin(), v.begin() + mid - 1, v.end()); + result = (v[mid] + v[mid-1])/2; + // result = (result + v[mid-1]) /2; + } + return result; +} + +``` + +周星星指出,完全可以第二个std::nth_element改成 std::max_element(begin,begin+mid) + +确实是一个思路,或者更极端一点,偶数也不特殊处理就好了 + +huring指出这个问题在macbook m1上不复现我的提供的 10,10,29,18,10,10,10,10,13,32无法复现 + +只能说和平台也有点关系,巧合而已 + + +突击提问:如何实现nth_element?最近面试刚被问到,我没上来优化的部分。已经自罚十个深蹲了 +