前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++ 中文周刊 2024-06-02 第159期

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

作者头像
王很水
发布2024-07-30 15:21:01
1140
发布2024-07-30 15:21:01
举报
文章被收录于专栏:C++ 动态新闻推送

点击「查看原文」跳转到 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::kInvalidInput\n";     break;
            case OpErrorType::kOverflow:  std::cout << "Error: OpErrorType::kOverflow\n";      break;
            case OpErrorType::kUnderflow:  std::cout << "Error: OpErrorType::kUnderflow\n";     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

看不懂

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-06-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 CPP每周推送 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 资讯
  • 文章
    • C++23: chrono related changes
      • An Extensive Benchmark of C and C++ Hash Tables
        • Quickly checking whether a string needs escaping
          • Function Composition and the Pipe Operator in C++23 – With std::expected
            • 揭秘C++:虚假的零成本抽象
              • Hydra: 窥孔优化泛化
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档