C++ 中文周刊 2024-06-02 第159期

2024-07-30 15:21:01 浏览数 (1)

点击「查看原文」跳转到 GitHub 上对应文件,链接就可以点击了

本期文章由 HNY 404 赞助

资讯

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

编译器信息最新动态推荐关注hellogcc公众号 本周更新 2024-05-29 第256期

P3292R0 Provenance and Concurrency

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3292r0.html

这个论文讲了一种场景,这个场景其实也不算啥问题,然后也没提出啥解决方案,也没有啥好解决的方案,当前场景对服用也不是不行

分享给大家浪费一下大家时间

文章

C 23: chrono related changes

https://www.sandordargo.com/blog/2024/05/29/cpp23-chrono

chrono相关改动

• 修复缺陷:自动本地化

代码语言:javascript复制
std::locale::global(std::locale("ru_RU"));
using sec = std::chrono::duration<double>;
auto s_std = std::format("{:%S}", sec(4.2)); // s == "04.200" (not localized)
auto s_std2 = std::format("{:L%S}", sec(4.2)); // s == "04,200" (localized)
std::string s_fmt = fmt::format("{:%S}", sec(4.2));  // s == "04.200"(not localized)

第四行c 20会挂,新版本强制自动本地化,如果你不想要这种行为,自己手动format

  • • 澄清本地化的编码格式兼容问题

对于语言,存在本地编码和文字编码不匹配的问题??

代码语言:javascript复制
std::locale::global(std::locale("Russian.1251"));
auto s = std::format("День недели: {:L}", std::chrono::Monday);

这个就会乱码,因为俄语的星期一有两种符号一个是utf8的一个不是

很抽象

  • • 放松clock要求

现在只要支持now就行

An Extensive Benchmark of C and C Hash Tables

https://jacksonallan.github.io/c_cpp_hash_tables_benchmark/

他这个压测场景和数据非常详细。非常不错

hashmap bm

看图来说 boost unordered map性能不错

多线程的hashmap比如tbb boost concurrency unorderedmap folly map之类 的压测,没有

感觉这个还是挺值得测的

另外这里没有folly f14, 感觉可以加一下 (感谢mwish指出)

Quickly checking whether a string needs escaping

https://lemire.me/blog/2024/05/31/quickly-checking-whether-a-string-needs-escaping/

简单实现可能是这样

代码语言:javascript复制
bool simple_needs_escaping(std::string_view v) {
  for (char c : v) {
    if ((uint8_t(c) < 32) | (c == '"') | (c == '\')) {
      return true;
    }
  }
  return false;
}

优化一下,去掉分枝

代码语言:javascript复制
bool branchless_needs_escaping(std::string_view v) {
  bool b = false;
  for (char c : v) {
    b |= ((uint8_t(c) < 32) | (c == '"') | (c == '\'));
  }
  return b;
}

更自然的,查表

代码语言:javascript复制
static constexpr std::array<uint8_t, 256> json_quotable_character =
    []() constexpr {
  std::array<uint8_t, 256> result{};
  for (int i = 0; i < 32; i  ) {
    result[i] = 1;
  }
  for (int i : {'"', '\'}) {
    result[i] = 1;
  }
  return result;
}
();

bool table_needs_escaping(std::string_view view) {
  uint8_t needs = 0;
  for (uint8_t c : view) {
    needs |= json_quotable_character[c];
  }
  return needs;
}

更更自然的,simd

代码语言:javascript复制
inline bool simd_needs_escaping(std::string_view view) {
  if (view.size() < 16) {
    return simple_needs_escaping(view);
  }
  size_t i = 0;
  __m128i running = _mm_setzero_si128();
  for (; i   15 < view.size(); i  = 16) {
    __m128i word = _mm_loadu_si128((const __m128i *)(view.data()   i));
    running = _mm_or_si128(running, _mm_cmpeq_epi8(word, _mm_set1_epi8(34)));
    running = _mm_or_si128(running, _mm_cmpeq_epi8(word, _mm_set1_epi8(92)));
    running = _mm_or_si128(
        running, _mm_cmpeq_epi8(_mm_subs_epu8(word, _mm_set1_epi8(31)),
                                _mm_setzero_si128()));
  }
  if (i < view.size()) {
    __m128i word =
        _mm_loadu_si128((const __m128i *)(view.data()   view.length() - 16));
    running = _mm_or_si128(running, _mm_cmpeq_epi8(word, _mm_set1_epi8(34)));
    running = _mm_or_si128(running, _mm_cmpeq_epi8(word, _mm_set1_epi8(92)));
    running = _mm_or_si128(
        running, _mm_cmpeq_epi8(_mm_subs_epu8(word, _mm_set1_epi8(31)),
                                _mm_setzero_si128()));
  }
  return _mm_movemask_epi8(running) != 0;
}

性能就不说了。看有没有必要吧,没有必要的话最多无分支版本哈,代码太多了,收益不大。当然性能肯定是simd最快

感兴趣自己玩一下 https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/tree/master/2024/05/30

Function Composition and the Pipe Operator in C 23 – With std::expected

https://www.cppstories.com/2024/pipe-operator/

实现shell管道用法

代码语言:javascript复制
#include <iostream>
#include <functional>
#include <string>
#include <concepts>
#include <random>
#include <expected>

template < typename T >
concept is_expected = requires( T t ) {
    typename T::value_type; // type requirement – nested member name exists
    typename T::error_type; // type requirement – nested member name exists

    requires std::is_constructible_v< bool, T >;
    requires std::same_as< std::remove_cvref_t< decltype(*t) >, typename T::value_type >;
    requires std::constructible_from< T, std::unexpected< typename T::error_type > >; 
};

template < typename T, typename E, typename Function >
requires  std::invocable< Function, T > &&
            is_expected< typename std::invoke_result_t< Function, T > >
constexpr auto operator | ( std::expected< T, E > && ex, Function && f ) 
                            -> typename std::invoke_result_t< Function, T > {
    return ex ? std::invoke( std::forward< Function >( f ), 
            * std::forward< std::expected< T, E > >( ex ) ) : ex;
}

// We have a data structure to process
struct Payload {
    std::string fStr{};
    int  fVal{};
};

// Some error types just for the example
enum class OpErrorType : unsigned char { kInvalidInput, kOverflow, kUnderflow };

// For the pipe-line operation - the expected type is Payload,
// while the 'unexpected' is OpErrorType
using PayloadOrError = std::expected< Payload, OpErrorType >;

PayloadOrError Payload_Proc_1( PayloadOrError && s ) {
    if( ! s )
        return s;

       s->fVal;
    s->fStr  = " proc by 1,";

    std::cout << "I'm in Payload_Proc_1, s = " << s->fStr << "n";

    return s;
}

PayloadOrError Payload_Proc_2( PayloadOrError && s ) {
    if( ! s )
        return s;

       s->fVal;
    s->fStr  = " proc by 2,";

    std::cout << "I'm in Payload_Proc_2, s = " << s->fStr << "n";

    // Emulate the error, at least once in a while ...
    std::mt19937 rand_gen( std::random_device {} () );
    return ( rand_gen() % 2 ) ? s : 
                    std::unexpected { rand_gen() % 2 ? 
                                OpErrorType::kOverflow : OpErrorType::kUnderflow };
}

PayloadOrError Payload_Proc_3( PayloadOrError && s ) {
    if( ! s )
        return s;

    s->fVal  = 3;
    s->fStr  = " proc by 3,";

    std::cout << "I'm in Payload_Proc_3, s = " << s->fStr << "n";
    return s;
}

void Payload_PipeTest() {
    static_assert( is_expected< PayloadOrError > ); // a short-cut to verify the concept
    auto res =  PayloadOrError { Payload { "Start string ", 42 } } |
                        Payload_Proc_1 | Payload_Proc_2 | Payload_Proc_3 ;

    // Do NOT forget to check if there is a value before accessing that value (otherwise UB)                    
    if( res )
        std::cout << "Success! Result of the pipe: fStr == " << res->fStr << " fVal == " << res->fVal;
    else
        switch( res.error() ) {
            case OpErrorType::kInvalidInput:    std::cout << "Error: OpErrorType::kInvalidInputn";     break;
            case OpErrorType::kOverflow:  std::cout << "Error: OpErrorType::kOverflown";      break;
            case OpErrorType::kUnderflow:  std::cout << "Error: OpErrorType::kUnderflown";     break;
            default:                            std::cout << "That's really an unexpected error ...n"; break;
        }
}

int main() { Payload_PipeTest(); }

代码 godbolt https://godbolt.org/z/G1bz96s4r

揭秘C :虚假的零成本抽象

https://zhuanlan.zhihu.com/p/700751030

标题党

Hydra: 窥孔优化泛化

https://zhuanlan.zhihu.com/p/701181704

看不懂

0 人点赞