2017年10月13日

[git]間違ってcommitしてpushまでしてしまっても怒らない

ぼーっとしていると、gitの操作を間違うことがある。

昨日は、branchを作るのを忘れたまま作業してしまい、そのままcommitし、pushまでしてしまったのだ。
自分しか使っていないのでなんとでもなるのだが、あまり気持ちがよいものではない。


pushする前であればresetでもやるとよかろうが、pushしてしまうと、できないことはないらしいが、取り消さない方が良いそうだ。
まあ、そういう気はするな。

しかし、それをやってしまうことはあるだろうから、グループ内で運用する場合であっても怒らないような文化にした方がよいだろう。
やってしまいがちな操作を禁止して、やらかしたら怒る、というやり方は萎縮させてしまうだけだと思うので、手順を決めておきたい。


結局、こうやった。

  1. やってしまったcommitをrevertで戻す
  2. その状態でpush
  3. ブランチを新しく作って移動
  4. 1のrevertをrevert
  5. その状態でpush

どうせpushするつもりだったんだから、もうそれでいいや、という運用だ。

commit履歴のコメントが「最初のコメント」「Revert 最初のコメント」「Revert Revert 最初のコメント」と並んでしまうのだが、やらかしたんだな、くらいでスルーしてしまえばよい。


しかし、コメントに「Revert」と入るだけだったら、本当にRevertしたのか、コメントの文字列に書いただけなのか区別できん気がするのだけど、そこまで管理してるのかな?

[btc]bitFlyerのP2WSHアドレス

さっき、bitFlyerからメールが来た。
私はbitFlyerにアカウントを作っているので、アナウンスがあるとメールが送られてくるのだ。


いつも bitFlyer をご利用いただきありがとうございます。 P2WSH 方式の Segwit に対応いたしましたのでお知らせいたします。
 
【P2WSH 方式の Segwit に対応】
お客様が bitFlyer アカウントからビットコインを外部のビットコイン・アドレスへ送付する際のトランザクションを P2WSH(Pay to Witness Script Hash)方式の Segwit に対応しました。当社が世界初*で採用した P2WSH は数ある Segwit の実装方式で安全性及び技術的難易度が高いもので、アドレスが「bc1」で始まることが特徴です。


ほー。


この話は、BIP141と、BIP173に関連したものだ。


まず、「P2WSH方式のSegwit」から。

今のところ、Segwitの表現方法は4つある。
https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#examples

  • P2WPKH
  • P2WPKH nested in BIP16 P2SH
  • P2WSH
  • P2WSH nested in BIP16 P2SH

P2PKHのSegwit版がP2WPKH、P2SHのSegwit版がP2WSHと、名前に「W」が入る。
それに「nested in BIP16 P2SH」が付くかどうかだ。

P2SHというのは、「マルチシグ」が代表格で、複数の人が署名するようなタイプのアドレスだったり、個人じゃなくてスクリプトに署名したり、するタイプのアドレスだ。
個人向けの非SegwitアドレスがP2PKHで、そうじゃなく非SegwitアドレスがP2SHと思っておけばよいかな。


Segwitは、アドレスの方式ではなく、トランザクションの構成などを表すもの。
トランザクションの構成が違うから、アドレスも区別できるようにした、というところかな。

しかし、いきなり「明日からSegwitのアドレスだけにします」と言われても、他のアプリは急に対応できない。
だから、まずは純粋なSegwitのトランザクションではなく、P2SHの皮をかぶせたSegwitトランザクションを作ろう、ということになったんじゃなかろうか。
経緯は知らないが、構成としてはそうなっている。
それが「nested in BIP16 P2SH」とついているタイプのアドレスだ。

アドレスを見ただけでは、それがP2SHなのか、Segwitのnested in BIP16 P2SHなのかは区別が付かない。
区別が付かないから、従来のアプリもP2SHとして処理できる、というわけだ。


ただ、皮をかぶせている分、トランザクションのサイズは大きくなっている。
トランザクションのサイズが大きくなると、手数料に反映されてしまう(基本的に、トランザクションのバイト数で手数料が決まるので)。
だから、どこかでnested inじゃないアドレスを作って普及させねば、という課題があったのだろう。
そこで出てきたのが、BIP173だ。


今までのP2PKHやP2SHのアドレスは、秘密鍵にハッシュ計算を何回か行って作り出すものだ。
BIP173で使うBech32という方式?はそれとは異なる。
どう異なるかは、ここで書くにはとても足りないので、BIPを読んでほしい。
けっして、けっして私が理解できなかったわけではないぞ。。。。

BIPに、アドレスの例が載っている。
https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#examples

価値がある方のblockchainであるmainnetで使えるアドレスは「bc1」で始まっているのが分かるだろう。
bitFlyerのメールだけでは詳細が書かれていなかったのだが、たぶん、これを指しているのだと思う。

BitcoinのMainnetは「bc」、Testnetは「tb」で始まる。
これが「Human Readable Part」と呼ばれる部分だ。
まあ、直訳すれば、人間が読める部分、だな。

その次の「1」は単なるセパレータで、それから後ろが実際のデータ部になる。


Bech32になると、QRコードなんかで表現しやすいらしい。
だからというわけでもないけど、そのうちアドレスはBech32がメインになっていくのかもしれんね。

私ももうちょっと勉強しよう。
リファレンス実装があったので、仕様をよく読まずにC言語でmainnetとtestnetに限定したバージョンを作ったのだけど、regtestのことは考慮になくてね・・・。

2017年10月12日

[btc]systemctlでbitcoindを起動させておく

当たり前だが、bitcoindは起動していない間はblockchainの同期を行ってくれない。
testnetしか使わない私だが、作業するたびに同期時間がかかるのは嫌なので、VMを立ち上げたときは起動したままにしているし、クラウド上のものもそうしている。

ただ、Linux自体を再起動したときに起動し忘れることが多々ある。
うちではUbuntuを使っていて、serviceよりもsystemctlを使うような感じがしたので、メモを残しておく。


Sample init scripts and service configuration for bitcoind

bitcoindのgithubに、簡単な説明が書かれているので、基本的にはこれに従う。


説明では、データを/var/lib/bitcoindに置くようだが、既に運用しているデータフォルダがあるし、ユーザも1人しかいないので、そっちを使い回すことにする。

systemdの場合はここに書いてあったが、Ubuntu16.02には /usr/lib/systemd/system というディレクトリが無かった。
作るほどでもないと思うので、 /etc/systemd/system に bitcoind.serviceというファイルを置いた。
個人のものをsystemd/systemに置くのもどうかと思うが、一人だと迷惑はかからんだろう。


ファイルの中身も、githubにサンプルが上がっている。
bitcoin/bitcoind.service at master · bitcoin/bitcoin

PIDは何番でもいいし、wallet機能はいるし、さっき書いたようにユーザも固定したいのでそこら辺だけ変更している。
UserとGroupが個人のもので、今運用しているのだったら、ExecStartは「/usr/bin/bitcoind -daemon」くらいで済んでしまう。

他の設定は、変更してもよいのだろうけど、このままでも困りそうにないので残した。


あとは、これだけやれば起動した。

$ sudo systemctl enable bitcoind.service
$ sudo systemctl start bitcoind.service

reloadするようなコマンドを打たないとダメだったような気がするのだけど、動いてるな・・・。
まあ、reloadせんといかんときはメッセージが出てきた気がするので、それに従えばいいんじゃなかろうかね。

2017年10月11日

[c/c++]gccの-Dオプションで文字列を指定する

以前、INIファイル形式を読込みたいので、ライブラリを使った記事を書いた。

コメントとして「#」を許容させるためにあれこれやっていたのだが、ソースを見ると行頭の「;」と「#」はコメント扱いのようだ。。。
https://github.com/benhoyt/inih/blob/master/ini.c#L125

マクロの「INI_INLINE_COMMENT_PREFIXES」は、インラインだから、行の途中で見つかった場合にコメントとする文字のようだ。


前回はMakefile自体を変更したが、よそのgithubに入っているMakefileを変更するのは避けたい。
そういうときは変数が使えるようになっていると、なんとかできる。
inihでは「EXTRACCFLAGS」が外部用に用意されているようだった。

$ EXTRACCFLAGS="-g -O2 -D'INI_INLINE_COMMENT_PREFIXES=\"#\"' -DINI_STOP_ON_FIRST_ERROR=1" make -f Makefile.static

文字列は、シングルクオーテーションで囲むのがよさそうだった。
Makefile中ではないので、#をエスケープしなくても大丈夫だ。


シングルクオーテーションで囲むのは、-Dで関数マクロ形式を指定する場合の説明に載っていたやり方を真似しただけなので、もしかしたら文字列はもっと簡単なやり方があるのかもしれん。

2017年10月9日

[zybo]これまでの復習

久しぶりにZyboを触ろうとしたが、どういうものだったか、何を調べてきたのかすら記憶に残っていないので、復習しておこう。



まず、CPU?として、XilinxのZYNQ-7000シリーズである、Z-7010が搭載されている。
PS部としてARM Cortex-A9(650MHz)が2つ。
PL部として7-series Artix FPGA相当のものが搭載されている。

PS部とPL部は、EMIO, AMBAなどのバスでつながっているようだ。


ARMのA9が載るだけあって、周辺も充実している。
RJ45もあるし、HDMI(I/O)、Dsub9のVGA、MIC IN, LINE, INもあるし、タクトスイッチやスライドスイッチ、GPIOのポート(Pmod)もある。
USBは、Type-Aもあるし、microBを使えばFTDIが載っているのでUSBシリアル変換でコンソールとして使うこともできる。

microSDカードもささり、そこから起動させるようなこともできるのだ。


なかなかよいのだが、発売がもう3年くらい前になるためか、情報があまり更新されていない。
FPGAの勉強用であれば、もうちょっと最近発売されているボードの方がおすすめだと思う。

Xilinxが発売しているボードであれば、Vivadoなどの開発環境で最初から設定が入っていそうだから、本筋にすぐ入っていけるのではなかろうか。
私なんか、おかげで、新しいPetaLinux(Xilinxが提供しているLinux環境)をZyboで動かすために数ヶ月かかってしまったぞ。

まあ、それはそれで勉強になってよいのだけどね。


おかげで、まだVHDLとかVerilogとかにはほとんど手を出していない。


FPGAというと、なんとなく組込みジャンルで考えていたのだが、ZyboみたいにOSが載る環境で使えてしまうと、もっと違う使い方をした方がよいような気がしてくる。

もちろん機器の制御もできるけれども、ハードウェアに近い部分でロジックを作ることもできるのだ。
そうなると、柔軟な並列演算処理装置、という見方もできよう。
GPUで仮想通貨のマイニングしたり、ディープラーニングの演算をさせたりするような、そんなイメージだ。

私はCortex-M系のマイコンを使うことが多かったのだが、A系だと電池で動かすこともないだろうし、動作クロックもそうとう高い。
Linuxを載せたとしたら、デバイスの制御にはデバイスドライバを介することになるだろう。
割り込み処理ですれスケジューリングされてしまうはずだ。


そうなると、少々のことであればPL部を使う必要がないはず。
PS部からGPIOで制御した方が、自由がききやすいと思う。
そうなっていないということは、A9とOSが載った環境ですら難しいことをPL部にやってもらうのがよいのではなかろうか。

ということで、結果的に「FPGAのFPGAっぽい部分をがんばるべし」という結論になった。
何をがんばればよいのかわからんけど、GPIOみたいなものの制御ではなく、並列でロジックを書けるようになるとか、そういう方向がよいのかな?

[xilinx]SDx 2017.2が出ていた

3連休なので、FPGAのことをやることにした。

最後にFPGA関連で更新したのがは、PetaLinuxをPC-Linuxでビルドする話の最終回で、ちょうど1ヶ月前(2017/09/09)だった。
あれからVivadoなども起動せずにいたのだが、今日Xilinx Information Centerを起動すると、SDx 2017.2が出ていた。
リリース日が09/05になっているから、単に私が見逃していただけのようだ。

image

Xilinxのすごいところは、リリースノート(pdf)なんかも日本語版を用意するところだ。
過去の分から作りやすいだけなのかもしれないが、いやいや、すごいもんですよ。


さて、いまSDxをインストールしているのだが、これにはVivado 2017.2も含んでいる。
使ったこと無いけど、Vivado HLSも含んでいる。
リリースノートからすると、XSDKに入っているのと同じARMのToolchainを含んでいるそうだ。
だから、XSDKでできることがSDxでもできるのであれば、SDxだけあればよいはずだ。


SDxがインストールできるのは、Zybo購入時にSDSoCのライセンスを購入しているからだ。
つまり、WebPACKではないので、WebTalkをオフにすることができる。
まあ、仕事で使っているわけでも無いし、変な動作をしないなら気にしないのだけどね。


あとは、私がこれらを使いこなせるかどうかなのだが・・・まだ全然ダメだ。
まずは、LED以外のチュートリアルを動かして遊んでみよう。


SDxでインストールされたVivadoを起動すると、ウィンドウの名前は「Vivado 2017.2_sdx」という名前になっていた。
微妙に違いがあるのかもしれん。

Vivado 2017.2で使ったことのあるプロジェクトがRecentとして出てきたので、そこら辺は共通なのか。
ただ、IPのリビジョンが微妙に上がっていたようで、そこはUpgradeした(プロジェクトをVivado 2017.1で作ったままだったかもしれない)。


Upgradeしたあとは、Bitstreamを作り直す。
プログレスを示すくるくるが出てくるようになった。
できれば、右下に出てくるか、最小化しないようにできるとありがたいのだが、まあぜいたくは言うまい。

いまRunning synth_designが実行されているようなのだが、とても長い。。。
そんなにPCの性能は悪くないと思うのだが、うたた寝しても良いくらいの時間はかかっているだろう。

ようやく終わって、Exportしなおして、Launch SDKすると、SDxが起動した。
以前、XSDKで作っていたプロジェクトが表示されている。


ということは、SDxがインストールされていれば、VivadoとXSDKは個別にインストールしなくてよいということになるな。


ついでに、SDxのチュートリアルをやっておこう。
SDxのリリースノートから、ug1028-sdsoc-intro-tutorial.pdfというSDSoC環境チュートリアルがたどれたのだ。

チュートリアルをやりたいというよりは、SDxでZyboを使ったデバッグができるのかを試したかったので「6.デバッグ」だけにする。


説明はZC702ボードになっているが、Zynq-7000デバイスであればよいらしい。
Zyboはそうなので、動くのだろう。
スタンドアロンアプリケーションをダウンロードして実行するところまで行えるそうだ。

ボードの設定は、SDカードがどうのこうの書かれているが、microUSBで電源とUARTを確保し、起動モードはJTAGにした。
以前System Debugをした感じからすると、他のモードでも動くんじゃないかと思うが、演習に関係するところだけ確認させたいのでそうしているようだ。


次は、スタンドアロンプロジェクトの作成。
書いてあるとおりにやっていくだけだ。
最後に「Build Project」するのだが、これが重くて長い。。。
15分以上やっているが、まだ25%だ。

結局、26分くらいかかりました。

image

すごいスペックというわけではないけど、けっこうよいスペックじゃないかと思うのだが、どうだろうか。
ウイルス対策ソフトがDefenderなので、そこで時間かかったりするのかもしれん。


デバッグは、Eclipseでデバッグするときの要領でよいが、選択するのは「Launch on Hardware(SDSoC Debugger)」だ。
似たような項目がたくさんあるので、赤文字のところを気にしておこう。
選択すると、パースペクティブを変更するか聞いてくるので、Debugに切り替える。
そうすると、mainで止まった状態が表示される。

ZyboのUARTというかシリアルポートというか、それをターミナルにつないでおく。
私はTeraTermにした。


ブレークポイントで止まった状態なので、再開アイコンをクリックする。
そうすると、ターミナルに何か出てきて、SDxの方は_exitで停止した。
ブレークポイント一覧を見ると、mainと_exitに設定されていたので、これでよいようだ。

Testing 1024 iterations of 32x32 inting point mmultadd...
Average number of CPU cycles running mmultadd in software: 1145442
Average number of CPU cycles running mmultadd in hardware: 19192
Speed up: 59.6833
TEST PASSED


何をやったのかはわからんが、行列演算で使いそうな計算をPL側に持っていったことで高速化したとか、そんな感じではなかろうか。
まったくVivadoに触ってないし、FPGA Programなんかもやっていないから、うまいこと使いこなせると私のようなソフト屋さんには便利そうだ。

2017年10月7日

jqコマンド

最近、JSON-RPCで指示を出して、その結果を取得するようなプログラムを作った。
ネットでよくある、JSON整形してくれるページで結果を確認したので、まあ間違ってはいないようだ。


JSON形式は、あまりお好きではない。
理由は、コンマだ・・・。

最後のデータにコンマを許可しないというルール故に、出力するときはひどく面倒なのだ。
まず、1行目の先頭にコンマがあってはならないので、1行目は普通に出力する。
2行目があるなら、コンマを出力してから2行目を出力することになる。
そして、それを繰り返していき、最後のデータの場合はコンマ無しで終わらせる。


順番にデータを掃き出すときはそこまで困らないのだが、嫌なのはforなどでぐるぐると掃き出したい場合だ。
コンマを出力する処理を、行の出力を行う前に置くか、後に置くか。。。
前に置くと、1行目だけコンマ出力をスキップする、という処理がいるし、後に置くと「次のデータがあるか」をチェックする処理がいる。
それが嫌だったら、1行目の出力と2行目以降の出力を分け、forですぐにコンマ出力するようにしておけばよいが、コンマのためだけに処理を分けるのも腹立たしい。

最後のデータにコンマを許可するか、あるいはコンマを無くしてしまう構造だったら悩まなくて済むと思うのだ。
まあ、データ構造に文句を言っても仕方ないのだが・・・。


JSON形式で出力するのが面倒であることを書きたいだけの記事なのだが、それだけでは何なのでjqコマンドのことを書こう。

Ubuntuではapt-getでinstallすることになるが、jqというJSON形式のデータを整形したり加工したりできるコマンドがある。
非常に多機能なのだが、自作で掃き出したJSON形式の改行やスペースが見づらかったとしても、引数無しでjqコマンドを通すだけで見やすくなる。

$ ./cli/lightning-cli getinfo
{ "id" : "02d030cf51591116155597cee2cbf8bb432fa01b691c055d329b51c838fd754130", "port" : 9735, "network" : "testnet", "version" : "v0.5.2-2016-11-21-964-geedbd1d", "blockheight" : 1209621 }


$ ./cli/lightning-cli getinfo | jq
{
   "id": "02d030cf51591116155597cee2cbf8bb432fa01b691c055d329b51c838fd754130",
   "port": 9735,
   "network": "testnet",
   "version": "v0.5.2-2016-11-21-964-geedbd1d",
   "blockheight": 1209621
}

ほら、この通り!
カラーが使えるコンソールであれば、パラメータとデータで色分けもしてくれるし、データも数値か文字列かで色が変わってくれるので、見やすい。


いま見ているgithubのサイトで、よくわからない使い方をしているので、なにやっているのか見ておきたい。

https://github.com/ElementsProject/lightning#receiving-and-receiving-payments

route=$(cli/lightning-cli getroute <recipient_id> <amount> 1 | jq --raw-output .route -)

cli/lightning-cliコマンドが何を出力するのかはあまり関係ないのだが、例がないと分かりづらいので載せておこう。

{ "route" :
         [
                 { "id" : "aaa", "channel" : "1207790:27:0", "msatoshi" : 101023561, "delay" : 92 },
                 { "id" : "bbb", "channel" : "1207703:21:0", "msatoshi" : 100511006, "delay" : 56 },
                 { "id" : "ccc", "channel" : "1207785:11:0", "msatoshi" : 100001001, "delay" : 46 },
                 { "id" : "ddd", "channel" : "1207779:2:0", "msatoshi" : 100000000, "delay" : 36 } ] }

コマンドの1行としては、「route=$(中身)」が外側で、その中身がjqの結果になるのだと思う。
では、cli/lightning-cliコマンドが出力した内容をjj.txtというファイルに保存したとすると、こうなるはず。
青文字が結果だ。

$ cat jj.txt | jq --raw-output .route-
[
   {
     "id": "aaa",
     "channel": "1207790:27:0",
     "msatoshi": 101023561,
     "delay": 92
   },
   {
     "id": "bbb",
     "channel": "1207703:21:0",
     "msatoshi": 100511006,
     "delay": 56
   },
   {
     "id": "ccc",
     "channel": "1207785:11:0",
     "msatoshi": 100001001,
     "delay": 46
   },
   {
     "id": "ddd",
     "channel": "1207779:2:0",
     "msatoshi": 100000000,
     "delay": 36
   }
]

「route」要素だけを出力したことになるのかな?
ただ、これを環境変数?に代入して、echoなどで掃き出しても、改行が残らないのだ。

$ route=$(cat jj.txt | jq --raw-output .route -)
$ echo $route
[ { "id": "aaa", "channel": "1207790:27:0", "msatoshi": 101023561, "delay": 92 }, { "id": "bbb", "channel": "1207703:21:0", "msatoshi": 100511006, "delay": 56 }, { "id": "ccc", "channel": "1207785:11:0", "msatoshi": 100001001, "delay": 46 }, { "id": "ddd", "channel": "1207779:2:0", "msatoshi": 100000000, "delay": 36 } ]

最後のハイフンがそういう意味なのかと思ったけど、ハイフンを外しても結果が変わらんかった。
tarコマンドで、標準出力とか標準入力とかを使うときにハイフンを付けるのと同じ意味のように思う。
じゃあ、パイプじゃなくてもいいやん、というか、パイプで書いているからハイフンがなくても動いているのかもしれん。


とにかく、何が言いたかったかというと、バイナリデータ最高!、ということでした。。。

2017年10月6日

AzureでVM作った後にNSGを変更する

まったくの個人メモです。

Azureの使い方がよくわかってないけど、がんばってVMをたくさん作った後で、設定するネットワークセキュリティグループを間違えていたのに気付いたときの変更方法。



  1. 変更したいVMをクリック
  2. 左から「ネットワーク」をクリック
  3. 上に出ているネットワークインターフェイスをクリック
  4. 左から「ネットワークセキュリティグループ」をクリック
  5. 上の「編集」をクリック
  6. 現在のネットワークセキュリティグループが表示されるので、クリックし、気に入ったものをクリック
  7. 上の「保存」をクリック


ネットワークインターフェイス名が分かっているなら、リソース一覧から選択した方が早いな。

2017年10月5日

[md]markdownで改行しようとスペース2つ付けたらMD009

Visual Studio Codeをしばしば使っている。

markdownに便利なExtensionsもあるので、適当にインストールしているのだが、それからLINTのようなものが働いて動的に指摘が入るようになった。
あまり慣れていないので助かる。

指摘と言っても、エラーになるわけではないから、無視してもよい。
pyCharmでpythonを書いたときに指摘されるような、あんな感じだ。


指摘を見ていると、改行しようとして行末にスペースを2つ入れているところに何か出ていた。

image

スペースをつなげるなって?
でも、markdownの改行は、行末にスペース2つじゃなかったっけ。。。


https://github.com/DavidAnson/markdownlint/blob/master/doc/Rules.md#md009
https://github.com/markdownlint/markdownlint/blob/master/docs/RULES.md#md009---trailing-spaces

改行についてはbr_spacesというオプションで指定することで回避できそうだが、デフォルトは0だし、vscodeのオプションにはそれっぽいものが出てこなかった。
今回は、MD009はfalse設定にすることで、見過ごすことにしよう。。。


デフォルトが0ということは、markdownの改行はあまりやらないのか、他の手段を使っているということなのか。
英語だと、段落になるまでずらずらつなげて書くのかもしれないけど、日本語だと「ここで別の行にしたいが、段落を変えたいわけではない」ということがあると思うので、そういう違いなのかもしれん。

2017年10月2日

[c++]boost::tie ?

前にboostを使って最短経路を求める(1,2,3,4,5)というのをやった。
そのときは目的を達成できてよかったのだが、今になってよくわかっていないところがあることに気付いた。

サンプルソースのここで並び替えを行っているのだが、本業ではこの箇所で辺(edge)に載っているデータを使って計算するようにしていた。

bool found;
graph_t::edge_descriptor e; boost::tie(e, found) = edge(v, p[v], g);

これで、foundがtrueになれば、該当するedgeの番号がeに入ったことになるらしい。

しかし、別の箇所では

boost::tie(e1, inserted) = boost::add_edge(v1, v2, graph);

などとしている。

単に戻り値をeやe1に入れるだけなら、boost::tieなどいらないはずだ。
そもそも、boost::tieってなんだ??


http://www.boost.org/doc/libs/1_65_1/libs/tuple/doc/tuple_users_guide.html

tupleは要素数固定のデータ集、でよいのかな?
そして、tieはtupleだけど要素が固定値ではないもの・・・?


std::pairは2つ限定だし、std::tupleはC++11からのようだから、boostにあったtupleがC++11に入ったのかな?
よく見ると、std::tieもC++11にあるそうだ。
boostのtieとstdのtieは同じものだろうか?

いろいろ疑問はあるが、今回はboost::tieの使い方を知りたいだけだ。
消極的だが、やむを得ん。


int i; char c; double d; 
tie(i, c, d) = make_tuple(1,'a', 5.5);

左辺にtieを置いても、ちゃんと使えるようだ。

ということは、最初に挙げた例のfoundやinsertedも、単に変数として使っているだけか。

いや、この引数がboost::tie::inserted、みたいな役割を持っていて、それによって何か結果が変わってくるんじゃないかと心配していたのだ。
自分でbool変数を作っているのだし、それはないか。


これで終わらせようとしたが、さすがにサンプルコードくらいは書かねばなるまい。

/*
 * $ g++ -o tst tietie.cpp
 */
#include <iostream>
#include "boost/tuple/tuple.hpp"

int main(void)
{
    int a;
    std::string b;
    boost::tie(a, b) = boost::make_tuple(123, "yoshio");
    std::cout << a << ", " << b << std::endl;
    return 0;
}

123, yoshio


まあ、そのまんまですな。。。

なんというか、局所的な構造体っぽい使い方ができるのかな?
ただ、戻り値を構造体にするとなると、構造体を定義して、実装側と使う人がincludeなどで共通の構造体を使わないといかんけど、tieだと型と順番が揃っていればよい。

けど、だったら構造体でもいいんじゃないの、という気がするが、構造体が増えていくのも面倒な気がする。
型は同じだけど用途が異なるので、中身が同じ構造体を別に用意する、みたいなことはしなくてよいか。


なんとなく、gcc -Sでアセンブラ展開すると、700行近くなった。
試しに、2行追加してみる。

/*
 * $ g++ -o tst tietie.cpp
 */
#include <iostream>
#include "boost/tuple/tuple.hpp"

int main(void)
{
    int a;
    std::string b;
    boost::tie(a, b) = boost::make_tuple(123, "yoshio");
    std::cout << a << ", " << b << std::endl;

    boost::tie(b, a) = boost::make_tuple("yoshio", 123);
    std::cout << a << ", " << b << std::endl;

    return 0;
}

これをアセンブラ展開すると、1200行ちょっとになる。
順番が違うから、それに応じたコードを生成するしかないのか。


では、同じtieの並びで変数が違ったらどうなる?

/*
 * $ g++ -o tst tietie.cpp
 */
#include <iostream>
#include "boost/tuple/tuple.hpp"

int main(void)
{
    int a;
    std::string b;
    boost::tie(a, b) = boost::make_tuple(123, "yoshio");
    std::cout << a << ", " << b << std::endl;

    int m;
    std::string n;
    boost::tie(m, n) = boost::make_tuple(123, "yoshio");
    std::cout << a << ", " << b << std::endl;

    return 0;
}

これは、750行程度だった。

変数mを、int型からuint8_t型に変更すると、972行。
uint64_tにしても同じだった。

C++のテンプレートは、基本的にマクロの拡張のようなものだったと思うので、uint8_tはint内に収まるから、途中は全部int型で処理して最後にキャストしてやろう、みたいなことはできないのだろう。

まあ、今回は最適化したわけでもないし、アセンブラにして眺めただけなので、違いは出てくるかもしれんが、コードサイズが大きくなることを心配するのであれば、そこら辺は実装側で気をつけねばならんだろうな。