C++ 中文周刊 第112期

周刊项目地址

公众号

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

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

提交 issue

不想上班,本周内容极少。有点不想发了

资讯

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

编译器信息最新动态推荐关注hellogcc公众号 本周更新 200期

200期,不容易

文章

#include <stdfloat>

int main() {
    std::float16_t   f16 = .42f16;
    std::bfloat16_t bf16 = .42bf16;
    std::float32_t   f32 = .42f32;
    std::float64_t   f64 = .42f64;
    std::float128_t f128 = .42f128;
}

更多的浮点类型


#include <stdint.h>
#include <bit>
#include <functional>

inline size_t bit_floor(size_t i) {
    constexpr int num_bits = sizeof(i) * 8;
    return size_t(1) << (num_bits - std::countl_zero(i) - 1);
}
inline size_t bit_ceil(size_t i) {
    constexpr int num_bits = sizeof(i) * 8;
    return size_t(1) << (num_bits - std::countl_zero(i - 1));
}

template<typename It, typename T, typename Cmp>
It branchless_lower_bound(It begin, It end, const T & value, Cmp && compare) {
    std::size_t length = end - begin;
    if (length == 0)
        return end;
    std::size_t step = bit_floor(length);
    if (step != length && compare(begin[step], value))
    {
        length -= step + 1;
        if (length == 0)
            return end;
        step = bit_ceil(length);
        begin = end - step;
    }
    for (step /= 2; step != 0; step /= 2)
    {
        if (compare(begin[step], value))
            begin += step;
    }
    return begin + compare(*begin, value);
}

template<typename It, typename T>
It branchless_lower_bound(It begin, It end, const T & value) {
    return branchless_lower_bound(begin, end, value, std::less<>{});
}

要比std::lower_bound快一点. TODO这里没有压测数据,后面补上

介绍 https://github.com/ada-url/ada 这个库的一些技巧,SIMD with a register

看代码

ada_really_inline size_t find_authority_delimiter_special(std::string_view view) noexcept {
  auto has_zero_byte = [](uint64_t v) {
    return ((v - 0x0101010101010101) & ~(v)&0x8080808080808080);
  };
  auto index_of_first_set_byte = [](uint64_t v) {
    return ((((v - 1) & 0x101010101010101) * 0x101010101010101) >> 56) - 1;
  };
  auto broadcast = [](uint8_t v) -> uint64_t { return 0x101010101010101 * v; };
  size_t i = 0;
  uint64_t mask1 = broadcast('@');
  uint64_t mask2 = broadcast('/');
  uint64_t mask3 = broadcast('?');
  uint64_t mask4 = broadcast('\\');

  for (; i + 7 < view.size(); i += 8) {
    uint64_t word{};
    memcpy(&word, view.data() + i, sizeof(word));
    word = swap_bytes_if_big_endian(word);
    uint64_t xor1 = word ^ mask1;
    uint64_t xor2 = word ^ mask2;
    uint64_t xor3 = word ^ mask3;
    uint64_t xor4 = word ^ mask4;
    uint64_t is_match = has_zero_byte(xor1) | has_zero_byte(xor2) | has_zero_byte(xor3) | has_zero_byte(xor4);
    if (is_match) {
      return i + index_of_first_set_byte(is_match);
    }
  }

  if (i < view.size()) {
    uint64_t word{};
    memcpy(&word, view.data() + i, view.size() - i);
    word = swap_bytes_if_big_endian(word);
    uint64_t xor1 = word ^ mask1;
    uint64_t xor2 = word ^ mask2;
    uint64_t xor3 = word ^ mask3;
    uint64_t xor4 = word ^ mask4;
    uint64_t is_match = has_zero_byte(xor1) | has_zero_byte(xor2) | has_zero_byte(xor3) | has_zero_byte(xor4);
    if (is_match) {
      return i + index_of_first_set_byte(is_match);
    }
  }

  return view.size();
}

简单来说就是八字节来用一个比较搞定,把信息编进一个8字节里,也就是一个SIMD with a regester的含义了。这里还比较复杂,输入的是view,多个,按八字节拆分了

这里考虑一下一般场景

int find_authority_delimiter_special_reference(uint64_t word) noexcept {
  auto has_zero_byte = [](uint64_t v) {
    return ((v - 0x0101010101010101) & ~(v)&0x8080808080808080);
  };
  auto index_of_first_set_byte = [](uint64_t v) {
    return ((((v - 1) & 0x101010101010101) * 0x101010101010101) >> 56) - 1;
  };
  auto broadcast = [](uint8_t v) -> uint64_t { return 0x101010101010101 * v; };
  uint64_t mask1 = broadcast('@');
  uint64_t mask2 = broadcast('/');
  uint64_t mask3 = broadcast('?');
  uint64_t mask4 = broadcast('\\');

  uint64_t xor1 = word ^ mask1;
  uint64_t xor2 = word ^ mask2;
  uint64_t xor3 = word ^ mask3;
  uint64_t xor4 = word ^ mask4;
  uint64_t is_match = has_zero_byte(xor1) | has_zero_byte(xor2) | has_zero_byte(xor3) | has_zero_byte(xor4);
  if (is_match) {
      return index_of_first_set_byte(is_match);
  }

  return -1;
}

作为网址相关解析的字符,这里完全可以极端一些,只考虑ascii码,这样范围又小了一些,更快了一些

然后作者手把手给你推导出这坨代码

long int find_authority_delimiter_special_better(uint64_t word) noexcept {
  auto broadcast = [](uint8_t v) -> uint64_t { return 0x101010101010101 * v; };

  uint64_t mask = broadcast(0x7f);
  uint64_t lo7bits = word & mask;

  uint64_t x0 = (lo7bits ^ broadcast('@')) + mask;
  uint64_t x1 = (lo7bits ^ broadcast('/')) + mask;
  uint64_t x2 = (lo7bits ^ broadcast('?')) + mask;
  uint64_t x3 = (lo7bits ^ broadcast('\\')) + mask;

  uint64_t t0 = ((x0 & x1 & x2 & x3) | word);
  uint64_t t1 = t0 & broadcast(0x80);
  uint64_t t2 = t1 ^ broadcast(0x80);

  if (t2 != 0) {
    return __builtin_ctzl(t2) / 8;
  }

  return -1;
}

把生成的汇编扔进 https://uica.uops.info/

能看出吞吐更快

这个推导逻辑我没有看懂。有看懂的哥们可以留言告诉我

天书,彻底看不懂了

介绍各种平台futex的行为/接口/表现。不多说

理解协程的代码转换。这个很多文章都有说过。还是值得一看的

enum IpAddr {
    V4(String),
    V6(String),
}

let home = IpAddr::V4(String::from("127.0.0.1"));
struct InvalidIP {};

struct IPv4 {
  std::string value;
};

struct IPv6 {
  std::string value;
};

using IPType = std::variant<InvalidIP, IPv4, IPv6>;


IPType ipType = InvalidIP{};

if (IPv4 *ip = std::get_if<IPv4>(&ipType)) {
    std::cout << ip->value << std::endl;
} else if (IPv6 *ip = std::get_if<IPv6>(&ipType)) {
    std::cout << ip->value << std::endl;
} else if (InvalidIP *ip = std::get_if<InvalidIP>(&ipType)) {
    std::cout << "Invalid IP" << std::endl;
}

简洁型还是差点意思

常识了, 直接贴代码了

#include <cstdarg>
#include <iostream>

void printV(size_t count, ...) {
    va_list args;
    va_start(args, count);
    for(size_t i = 0; i < count; ++i) {
      std::cout << va_arg(args, int);
      std::cout << " ";
    }
    std::cout << '\n';
    va_end(args);
}


template <typename T>
void printT(T item) {
  std::cout << item << ' ';
}

template <typename T, typename... Args>
void printT(T item, Args... args) {
  printT(item);
  printT(args...);
  std::cout << '\n';
}

int main() {
  printV(4, 3, 2, 1);
  printV(3, 8.2, 2, 1.1);
  printV(5, 23, 32, 8, 11, 9);
  printT(3, 2, 1);
  printT(8.2, 2, 1.1, "duck");
  printT(23, 32, 8, 11, 9);
}

va_list很少见了

视频

封装c api用的

开源项目需要人手

新项目介绍/版本更新

本文永久链接

如果有疑问评论最好在上面链接到评论区里评论,这样方便搜索,微信公众号有点封闭/知乎吞评论

看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!也可以帮忙点赞收藏转发!多谢支持! 觉得写的不错那就给点吧, 在线乞讨 微信转账