C++ 中文周刊 第141期

2024-07-30 14:45:18 浏览数 (2)

周刊项目地址 https://github.com/wanghenshui/cppweeklynews

RSS https://github.com/wanghenshui/cppweeklynews/releases.atom

欢迎投稿,推荐或自荐文章/软件/资源等

请提交 issue https://github.com/wanghenshui/cppweeklynews/issues

最近在找工作准备面试题,更新可能有些拖沓,见谅

本期文章由 黄亮Anthony HNY 赞助

资讯

标准委员会动态/ide/编译器信息放在这里

clion新增AI助手 https://www.jetbrains.com/clion/whatsnew/

编译器信息最新动态推荐关注hellogcc公众号 OSDT Weekly 2023-12-06 第231期

文章

  • • 现代C 语言核心特性解析C 23标准补充 - 免费电子书 https://zhuanlan.zhihu.com/p/670502105

感兴趣的可以看一下。很短

  • • Outline: 代码分离编译优化 https://zhuanlan.zhihu.com/p/669417318

抽出相同的二进制,节省二进制大小。和inline逻辑相反

可能会有性能衰退

原理?如何找出重复的二进制序列?后缀树爆搜

也可以从不同角度来做,比如IR层

具体很细节。感兴趣的可以看看

  • • HotColdSplitting: 代码分离之性能优化 https://zhuanlan.zhihu.com/p/670400568

借助outline做冷热分离,有性能提升,还挺有意思的,算是PGO一部分吧,拿到profile来分析

  • • For processing strings, streams in C can be slow https://lemire.me/blog/2023/10/19/for-processing-strings-streams-in-c-can-be-slow/

stream就是垃圾 strstream没人用。感觉后面会演进个spanstream出来

  • • Parsing 8-bit integers quickly https://lemire.me/blog/2023/11/28/parsing-8-bit-integers-quickly/

lamire博士新活

常规

代码语言:javascript复制
int parse_uint8_naive(const char *str, size_t len, uint8_t *num) {
  uint32_t n = 0;
  for (size_t i = 0, r = len & 0x3; i < r; i  ) {
    uint8_t d = (uint8_t)(str[i] - '0');
    if (d > 9)
     return 0;
    n = n * 10   d;
  }
  *num = (uint8_t)n;
  return n < 256 && len && len < 4;
}

当然c 可以用from chars加速

代码语言:javascript复制
int parse_uint8_fromchars(const char *str, size_t len, uint8_t *num) {
  auto [p, ec] = std::from_chars(str, str   len, *num);
  return (ec == std::errc());
}

能不能更快?这是u8场景,考虑SWAR,组成一个int来处理

代码语言:javascript复制
int parse_uint8_fastswar(const char *str, size_t len, 
    uint8_t *num) {
  if(len == 0 || len > 3) { return 0; }
  union { uint8_t as_str[4]; uint32_t as_int; } digits;
  memcpy(&digits.as_int, str, sizeof(digits));
  digits.as_int ^= 0x30303030lu;
  digits.as_int <<= ((4 - len) * 8);
  uint32_t all_digits = 
    ((digits.as_int | (0x06060606   digits.as_int)) & 0xF0F0F0F0) 
       == 0;
  *num = (uint8_t)((0x640a01 * digits.as_int) >> 24);
  return all_digits 
   & ((__builtin_bswap32(digits.as_int) <= 0x020505));
}

评论区bob给了个更快的

代码语言:javascript复制
int parse_uint8_fastswar_bob(const char *str, size_t len, uint8_t *num) {
  union { uint8_t as_str[4]; uint32_t as_int; } digits;
  memcpy(&digits.as_int, str, sizeof(digits));
  digits.as_int ^= 0x303030lu;
  digits.as_int <<= (len ^ 3) * 8;
  *num = (uint8_t)((0x640a01 * digits.as_int) >> 16);
  return ((((digits.as_int   0x767676) | digits.as_int) & 0x808080) == 0) 
   && ((len ^ 3) < 3) 
   && __builtin_bswap32(digits.as_int) <= 0x020505ff;
}

压测代码在这里 https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/tree/master/2023/11/28 感兴趣可以玩一玩

  • • Nerd Snipe: Small Integer Parsing https://blog.loadzero.com/blog/parse-int-nerdsnipe/

场景 完美hash,4bytes字符串做key,如何快速算hash?

直接把字符串当成int来算

代码语言:javascript复制
#define SIZE 512
uint8_t lut[SIZE] = {};

// multiply, shift, mask
uint32_t simple_hash(uint32_t u) {
    uint64_t h = (uint64_t) u * 0x43ff9fb13510940a;
    h = (h >> 32) % SIZE;
    return (uint32_t) h;
}

// generate, cast and hash
void build_lut() {
    char strings[256*4];
    memset(strings, 0, sizeof(strings));
    char *iter = strings;
    for (int i = 0; i < 256;   i) {
        sprintf(iter, "%d", i);
        iter  = 4;
    }

    iter = strings;
    for (int i = 0; i < 256;   i) {
        unsigned c = *(unsigned*) iter;
        iter  = 4;
        unsigned idx = simple_hash(c);
        lut[idx] = i;
    }
}

视频

cppcon2023 工作日开始更新视频了,这周好玩的列一下

  • • A Long Journey of Changing std::sort Implementation at Scale - Danila Kutenin - CppCon 2023 https://www.youtube.com/watch?v=cMRyQkrjEeI

这个作者danlark在llvm比较活跃

这个视频非常值得一看,列举了sort的改进优化,各个系统的差异,以及nth_element的副作用问题

很多库写的median算法实际是错的!

https://godbolt.org/z/9xWoYTfMP

代码语言:javascript复制

int median(std::vector<int>& 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;
}

由于nth_element不保证整体有序,只保证n的位置是对的,所以第二次的计算可能改变第一次的结果

然而社区很多median实现都是错的

  • • Customization Methods: Connecting User and C Library Code - Inbal Levi - CppCon 2023 https://www.youtube.com/watch?v=mdh9GLWXWyY

介绍了一些查找逻辑的设计,从swap到ADL,到CPO tag_invoke 再到最近的讨论,有Custom function设计

还算有意思 。但有句讲句tag_invoke很扭曲,cpo也是

  • • Variable Monitoring with Declarative Interfaces - Nikolaj Fogh - Meeting C 2023 https://www.youtube.com/watch?v=AJDbu1kaj5g

介绍一个库 https://github.com/nfogh/monitoring/

代码语言:javascript复制
auto myMonitor = Monitor([](int i){ return i > 0; }, [](bool valid){ std::cout << "Valid: " << valid << std::endl; }]);
int variable = 0;
myMonitor(variable); // Prints Valid: 0
variable = 1;
myMonitor(variable); // Prints Valid: 1

不过不知道有啥用途。signal handler类似的玩意

比如监控内存,真到了瓶颈,直接在发现的位置条件判断也不是不行

或者类似bvar之类的玩意,把数据导出 回调交给别的组件

不知道什么场景能用上

有意思的项目

  • • https://github.com/sunxfancy/vscode-llvm 在vscode里拿到llvm compiler explore类似的效果。检查IR,查看CFG之类的,很厉害
  • • asteria https://github.com/lhmouse/asteria 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群753302367和作者对线 (原来的群被举报了)
  • • Unilang https://github.com/linuxdeepin/unilang deepin的一个通用编程语言,点子有点意思,也缺人,感兴趣的可以github讨论区或者deepin论坛看一看。这里也挂着长期推荐了
  • • https://gitee.com/okstar-org/ok-edu-desktop 一个IM通信软件,做IM的可以关注,现在正在做全面整合阶段,开始组建商业团队阶段,年底开始融资,你参加了就快发财了,会的快来

互动环节

公众号终于收到了广告,不容易,预计19号发,挂一周。提前预告一下,大家别生气

最近面了好多工作,真有点迷茫了自己未来要做什么,年前就休息吧。随便看看了

引用链接

[1] vwei@nvidia.com: mailto:vwei@nvidia.com

0 人点赞