過年前有個工作需求,需要跨平台的AES硬體加速功能,研究了一下幾種方案
– Openssl (增加相依性,加上編譯時需要設定改來改去)
– Runtime JIT (先判斷CPU種類,然後根據CPU類型生成組合語言,小小的玩意哪需要玩這麼大)
– libkcapi – Linux Kernel Crypto API User Space Interface Library
覺得最後一種方式不錯,不過我只需要AES,其他地方可以拿掉
因此對這Project進行二次加工,產生了KCAES這個專案
不過在進行AES CBC運算時,發現長度超過64K就會報錯,只好對超過64K的Block進行二次加工
不需要其他的相依性,只要把檔案放進自己的專案,加入編譯即可
Summary about C++17 Part 3
去英國晃了一圈,回來還是寫點東西,免得生疏了
static_assert
沒什麼好說的,就是static_assert改成允許單參數,直接看程式碼
Before C++17
1 | static_assert(sizeof(short) == 2, "sizeof(short) == 2") |
After C++17
1 | static_assert(sizeof(short) == 2) |
Inline Variables
對Header-Only library特別有用,不過我不喜歡Header-Only library
原先如果要定義一個變數,要在header宣告,在source code裡面定義
現在可以直接寫在header裡了
Before C++17:
1 | // foo.h |
After C++17:
1 | // foo.h |
constexpr labmda
原先C++14辦不到,C++17允許的能力
1 | constexpr int Func(int x) |
不過我還沒想到這東西可以做啥
capture [*this]
原本我還搞不懂capture [this]
和capture [*this]
有什麼不同,自己寫了一個範例之後搞懂了
1 | #include <string> |
capture [*this]
相當於上面的[self = *this]
,會將原有的物件複製一份
而[this]
不會
More Attributes
C++11引進了Attribute,在C++17增加了更多attributes,如[[fallthrough]]等
就是把GCC/VC的attribute標準化,不多做解釋了
Rest
至於STL的加強就不特別寫了, Guaranteed Copy Elision可能要另外寫
就先寫到這了
Reference
Summary about C++17 Part 2
if constexpr
以往我們可能寫出類似這樣的程式碼
1 | #include <string> |
如今我們可以寫成這樣
1 | #include <string> |
省去了很多的冗於
如果配合variant
來使用,程式碼可以寫成這樣
1 | #include <string> |
Class Deduction guide
在c++17之前,寫了很多這樣子的程式碼
1 | std::mutex m; |
為什麼函數可以推導出型別,而類型不行,於是C++17放寬了這條件
1 | std::lock_guard lock(m); |
當然,也是有explicit class deduction guide的,請參考reference
template <auto>
目前看起來沒什麼用的feature
未用c++17前程式碼長這樣
1 | template <typename T, T v> |
用了C++17後
1 | template <auto v> |
nested namespace
早該有的東西, 結果拖到這麼後面才加進來
1 | namespace X { |
現在可以寫成
1 | namespace X::Y { |
Fold expression
以加法為範例
在c++17之前的寫法
1 | template<typename T> |
把sum寫成兩部分,雖然不是不行,不過總覺得被切割加重學習負擔
用上if constexpr
1 | template<typename T, typename... Args> |
好一點了,用上Fold expression會變成怎樣
1 | template<typename ...Args> |
跟if constexpr
方法比是更精簡了一點,不過多了一堆語法規則,實在不太划算
Reference
— A Tour of C++ 17: If Constexpr
— C++17中的deduction guide
— C++17 Fold Expressions
Summary about C++17 Part 1
對於C++17特性的文章已經有很多了,歸納自己的想法寫成幾篇文章
if / switch init
覺得很有用的特性之一
在沒有C++17之前,程式碼大概長這樣
1 | void test() { |
在C++17之後
1 | void test() { |
Structure Binding
在沒有Structure Binding時,程式碼大概長這樣
1 | std::tuple<int, double> stuff(); |
或者是
1 | int i; |
不過都比不上
1 | auto [i, d] = stuff(); |
傳統的
1 | errcode doSomething(obj *out_value); |
之後會變成
1 | std::tuple<obj, errcode> doSomething(); |
有點golang的感覺
不過看看以下程式碼
1 | struct Foo |
結果出乎意料,不是大家所想的copy by value,而是copy by reference
Compiler大概做的是像這樣
1 | int main() |
還有下面這個範例
1 | struct X { int i = 0; }; |
– c++
編譯不過,因為這是bind to const reference
– auto & [d] = makeX()
編譯不過,因為left reference不能bind to right value
– f++
編譯不過,理由同第一條
Reference
Difference between auto and decltype(auto)
看看以下程式有什麼不一樣
1 | #include <iostream> |
和
1 | template <typename T> |
差異就在於auto和decltype的用途不太一樣,auto會去掉reference,而decltype(auto)不會
C++11’s solution
C++11也可以達到decltype(auto)的方式,不過寫法比較繁瑣
1 | template <typename T> |
Introduction to cgroup
cgroup是linux用來限制program使用Computer resource的一種方法
也是Docker的基礎
首先先安裝cgroup
1 | $ sudo apt install cgroup-bin |
不用看也知道他絕對吃滿cpu resource
所以該怎麼限制,例如只讓他吃20%的CPU
先建立cgroup的群組
1 | $ cd /sys/fs/cgroup/cpu # 管理CPU資源的地方 |
接著把我們程式限制的規則加入群組 以下動作需要root權限,sudo無法執行
1 | $ echo 20000 > calm/cpu.cfs_quota_us # 預設值是100000,20000正好是20% |
接著我們就能看到程式CPU使用率就只剩20%了
Another method
也可以用自定義規則的方式
1 | $ sudo cgcreate -g cpu:calm # 一樣是建立 cpu calm |
如果要執行程式的話
1 | $ sudo cgexec -g cpu:calm python busy.py |
跟上面有同樣的效果
Define custom error_code in C++11
之前大概有寫過C++11 error_code的文章,不過覺得不夠清楚
這篇當作補充
定義Error
為了示範,僅定義幾個錯誤
1 | #include <system_error> |
定義Error Category
定義Error的Domain,需要繼承自std::error_category
,範例如下
1 | class MyErrCategory : std::error_category { |
make_error_code
定義完Error Class和Category Class之後,就可以寫出make_error_code
1 | std::error_code make_error_code(MyErrC e) |
helper structure
不過就算這樣還是有點麻煩,我們希望寫出這樣的程式碼
1 | std:error_code err = MyErrC::FileNotFound; |
因此需要一個helper structure
1 | namespace std |
因此上面那行程式碼就能通過編譯了
Reference
Type deduction in C++ Range-Base Loop
自從C++11有了auto和decltype之後,整個coding style有了很大的改變
現在我們有一個字串統計的map,該怎麼走訪這個map才好
1 | map<string, int> wordCount; |
pre-C++11
沒別招了
1 | for (map<string, int>::iterator it = wordCount.begin(); |
雖然可以用typename簡化map<string, int>::iterator
不過大同小異,看起來也不怎麼美觀
C++11
auto被賦予了新生命,於是可以寫出這樣的程式碼
1 | for (auto &p : wordCount) { |
C++17引進了structure binding進一步簡化
C++17
1 | for (auto &[word, count] : wordCount) { |
Parse string in C++
不管從哪個角度看,切割字串都不是件簡單的工作
即便是簡單的字串格式
The simplest Example
先來個C語言處理方式
1 | #include <stdio.h> |
C++的版本
1 | #include <sstream> |
看起來相差無幾,也沒需要動用到其他武器的地方
不過如果情況更複雜該怎麼辦
More Complex issue
例如輸入的字串是Tom: 42
如果什麼都不改的話,name會得到Tom:
,不是我們想要的
如果改C語言的版本Parse string的字串
1 | sscanf(str, "%s: %d", name, &value); |
結果也不是我們想要的
看看C++的版本,不改的話結果一樣
如果改成這樣
1 | int value; |
很顯然地也不對
Strtok
如果不動用重型武器,這是我唯一想得出來的方法
1 | #include <stdio.h> |
雖然解決了問題,不過程式碼支離破碎,維護起來也是麻煩透頂
萬一字串變成 Tom: 42, 123
該怎麼辦
Boost Spirit
這世上不缺聰明人,想到了優雅到爆炸的作法
在C++內嵌DSL Parser解決問題,而使用的就是Boost Spirit
不過要說缺點的話,出錯Debug很麻煩
1 | #include <string> |
就如同上面說的如果要修改字串成Tom: 42, 123
我們可以將Parser寫成
1 | bool r = qi::phrase_parse(iter, end, |
高明的不得了
Rule & Grammer
當要Parse的字串越來越複雜,就可以自己定義Grammer和Rule了
1 | #include <string> |
經過測試,如果省略後面Skipper
的模板定義,整個Grammer不會正常運作
Reference
– Home of The Boost.Spirit Library
– Parsing with Spirit Qi
– spirit.Qi in boost
Introduction to Woboq CodeBrowser
最近都在猛K機器學習, 有點荒廢了寫作
終於有時間可以寫點東西, 常常有在網路上看程式碼的需求,
於是就有新的工具誕生了
Build Woboq CodeBrowser
1 | $ sudo apt install clang llvm libclang-dev |
Take an example
1 | $ git clone https://github.com/basiliscos/cpp-bredis |
值得注意的是, 這邊用cmake的out of build不起作用
所以就只能在root directory放在一起
之後就可以直接用Browser來看程式碼了