さよなら備忘録

「なにをいまさら」と言われそうな些細なことのメモがわり

Macのターミナルを少し弄る

ターミナルで git コマンドを補完するようにした。
下記記事を参考に bash-completion をインストール。

ターミナルでgitのコマンドを補完したりブランチ名を表示する - macでgitを便利に使うために - | PPl@ce

設定も済ましても補完が効かないと思ったら、Homebrew でインストールしていない git を使っていたので下記記事を参考に git をインストールしたら無事に補完できました。

brew - なんかやばいらしいのでgitのバージョン上げる - Qiita


あと本稿とは関係ないですが、超初歩的な内容ですがためになったのでメモ。

ターミナルでのカーソル移動

Macのターミナルで単語ごとにカーソル移動をする方法 - Qiita

出力内容の色

[Mac] ターミナルの$前の出力内容をカスタマイズする - YoheiM .NET

enum class を範囲for文でループさせる

C++11で導入された enum class を static_cast で整数型にキャストしてむりくりfor文でループさせてるコードを見かけました。軽く調べたところ begin(), end(), operator*(), operator++()を定義すれば範囲for文で使えるようになるようです。

#include <iostream>

using namespace std;

enum class Dir { Top, Down, Left, Right, Max };

Dir begin(Dir) { return Dir::Top; }
Dir end(Dir) { return Dir::Max; }
Dir operator*(Dir dir) { return dir; }
Dir operator++(Dir& dir) {
    return dir = Dir(underlying_type<Dir>::type(dir) + 1);
}

ostream& operator<<(ostream& os, Dir dir) {
    switch (dir) {
        case Dir::Top:   return os << "Top";
        case Dir::Down:  return os << "Down";
        case Dir::Left:  return os << "Left";
        case Dir::Right: return os << "Right";
        default: return os;
    }
}

int main() {
    for (auto dir : Dir()) {
        cout << dir << endl;
    }
}

適用前のfor文は下のような感じでした。だいぶすっきりしましたね。

for (int i = static_cast<int>(Dir::Top); i < static_cast<int>(Dir::Max); ++i) {
  cout << static_cast<Dir>(i) << end;
}

『初めてのRuby』読了

趣味でRubyを触ろうと思い、参考書として購入しました。

初めてのRuby

初めてのRuby

Rubyの基礎の基礎といえる文法などの解説が200項程度にまとまってるので、ある程度のプログラミングの知識があるかたはすんなり読み進められるでしょう。
(序文にも書かれていますが、プログラミング初心者向けではありません)

Rubyをより深く、より丁寧に学習するには他に適した参考書があると思いますが、Rubyの基礎文法を簡単に振り返るのによい書籍だと思います。

Windows で Git のプロキシ設定をする

HOMEディレクトリ(だいたいの場合は C:\Users\《ユーザー名》 )に .gitconfig を作成し、プロキシサーバーのアドレスとポートは環境にあわせて設定する。コマンドでやる方法もあるようだが今回は割愛。

.gitconfig

[http]
proxy=http://《address》:《port》


Windows で設定されているプロキシ設定を確認したいが、インターネットオプションから表示できない場合はコマンドプロンプトから確認するには以下のコマンドを実行する。未設定の場合は表示されないかも。

reg query "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyServer

Boostライブラリで文字列から半角・全角スペースを削除する

Boost String Algorithms ライブラリを使って指定した文字を削除する。
サンプルは視認しやすくするため、全角スペースをアンダースコアに置換しています。

#include <iostream>
#include <boost/algorithm/string.hpp>
using namespace std;
using namespace boost;
int main() {
  string s1 = " _ _   "; // 半角・全角スペースのみを含む文字列
  string s2 = " s t_r_";
  string set = " _";
  
  // 半角・全角スペースのみで構成される文字列を判定
  cout << all(s1, is_any_of(set)) << endl; // true
  cout << all(s2, is_any_of(set)) << endl; // false    

  // 半角・全角スペースを文字列から削除する
  find_format_all(s2, token_finder(is_any_of(set)), empty_formatter(""));
  cout << s2 << endl; // str
}

Boostライブラリでbase64へのコンバートとデコード

エンコード結果を標準出力にコピーする。

#include <iostream>
#include <sstream>
#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/transform_width.hpp>

using namespace std;
using namespace boost::archive::iterators;
using InputItr  = istreambuf_iterator<char>;
using OutputItr = ostream_iterator<char>;
using EncodeItr = base64_from_binary<transform_width<InputItr, 6, 8>>;
using DecodeItr = transform_width<binary_from_base64<InputItr>, 8, 6, char>;

template <typename InputStream, typename OutputStream>
inline OutputStream& encode(InputStream& is, OutputStream& os) {
  copy(EncodeItr(InputItr(is)), EncodeItr(InputItr()), OutputItr(os));
  return os;
}

template <typename InputStream, typename OutputStream>
inline OutputStream& decode(InputStream& is, OutputStream& os) {
  copy(DecodeItr(InputItr(is)), DecodeItr(InputItr()), OutputItr(os));
  return os;
}

int main() {
  stringstream ss;
  ss << "abcdefg";
  encode(ss, cout); // YWJjZGVmZw
}

Windowsで時刻を手動変更したときのC++への影響

結論から書くとどうしてこうなるのか全くわかってません。
各仕様や実装の誤解が多分にあると思われるのでご注意下さい。


Windows環境で時刻を手動で変更したときにC++の時間関連のプログラムにどう影響があるかコードを動かしてみました。
検証方法は単純にデバッグでステップ実行しつつ、時刻を変更してどうなるか見てみるだけです。

動作環境はWindows7コンパイラはVisualStudio2013。

clock()

プログラム起動からの経過時刻を取得するC言語の関数。
以下のコードで(1)実行後に時刻を巻き戻すると、(2)で負数が返された。
時刻の変更の影響を受けているようです。

#include <ctime>
#include <iostream>
using namespace std;
int main() {
  cout << clock() / CLOCKS_PER_SEC << endl; // (1)
  cout << clock() / CLOCKS_PER_SEC << endl; // (2)
}
GetTickCount()

システム起動からの経過時刻を取得するWindowsAPI。
(1)実行後に時刻を巻き戻しても(2)は正常に経過した値が返されました。
時刻の変更の影響を受けていないようです。

#include <iostream>
#include <windows.h>
using namespace std;
int main() {
  cout << GetTickCount() << endl; // (1)
  cout << GetTickCount() << endl; // (2)
}
steady_clock

C++11で追加された時刻が逆行しないことが保証されるクロック。
(1)実行後に時刻を巻き戻したら、(2)で負数が返された。
逆行しないことが保証されているので影響しないと予想していましたが、こちらも影響を受けるようです。
steady_clockに対する自分の認識が間違っている可能性が大ですが…

#include <chrono>
#include <iostream>
using namespace std;
using namespace std::chrono;
int main() {
  auto begin = steady_clock::now(); // (1)
  cout << duration_cast<seconds>(steady_clock::now() - begin).count() << endl; // (2)
}


thread::sleep_until() へパラメータとなる場合も検証してみました。
(1)で再開時刻を取得したあとに時刻を巻き戻すと、5秒経ってもsleepから戻ってきませんでした。

#include <chrono>
#include <thread>
using namespace std;
using namespace std::chrono;
int main() {
  auto t = steady_clock::now() + seconds(5); // (1)
  this_thread::sleep_until(t);
}

steady_clock の実装は system_clock を public 継承しているだけだったので、
VisualStudioでは steady_clock と system_clock に差はないのかもしれませんね…



とりあえずWindowsAPI以外は全て影響を受けるようです。
マルチプラットフォームで時刻の手動変更の影響を受けないような関数は標準にないのかな…?
Boostライブラリのchronoがどうなっているかも調べたほうがよいのかもしれません。