tmuxの画面が更新されないときに

sshログインした環境でtmuxをよく使っているのだが, ときどき何かのことで画面が更新されなくなる. フリーズしているわけではなく, tmuxコマンドは動く. コマンドをうつなどすると結果が表示されず(そもそも打ち込んだコマンドも見えない), 別のペインに移動して戻ってくると更新されているといった具合だ.

未だに原因不明なのだが, 下記を参考に試したところ僕の場合はうまくいった.

github.com

Ctrl-bを押し, 続けてDを押す (Ctrl-bはデフォルト).

@NHDaly Did you try Prefix key + Capital D (detach other sessions) . It happens to me when I am generally moving from one wifi to other . The terminal feels like its stuck .

それにしても"semi-zombie"とは面白い表現だ.

C++のgetlineでstringをsplitする際の注意点2

C++のgetlineでstringをsplitする際の注意点 - bettamodokiのメモのつづき. Pythonのsplit関数の挙動を確認してみた.

print("aaa,bbb,ccc".split(','))  # => ['aaa', 'bbb', 'ccc']
print("aaa,bbb,,ccc".split(','))  # => ['aaa', 'bbb', '', 'ccc']
print("aaa,bbb,ccc,".split(','))  # => ['aaa', 'bbb', 'ccc', '']
print("aaa".split(','))  # => ['aaa']
print("".split(','))  # => ['']

空文字を与えた場合, 空のリストではなく空文字を要素とするリストを返す. つまり, 文字列inputに含まれるdelimiterの数+1の要素を持つリストを常に返す.

https://docs.python.jp/3/library/stdtypes.html#str.split

というわけで少しだけ改変を加えた.

#include <iostream>
#include <string>
#include <sstream>
#include <vector>

std::vector<std::string> split(const std::string& input, char delimiter)
{
    std::istringstream stream(input);
    std::string field;
    std::vector<std::string> result;
    while (std::getline(stream, field, delimiter)) {
        result.push_back(field);
    }
    if (input.empty() || input.back() == delimiter) {
        result.push_back("");
    }
    return result;
}

void test(const std::string& input)
{
    std::cout << "'" << input << "'" << " => [";
    for (const std::string& s : split(input, ',')) {
        std::cout << "'" << s << "', ";
    }
    std::cout << "]" << std::endl;
}

int main()
{
    test("aaa,bbb,ccc");
    test("aaa,bbb,,ccc");
    test("aaa,bbb,ccc,");
    test("aaa");
    test("");
}

結果は以下の通り.

'aaa,bbb,ccc' => ['aaa', 'bbb', 'ccc', ]
'aaa,bbb,,ccc' => ['aaa', 'bbb', '', 'ccc', ]
'aaa,bbb,ccc,' => ['aaa', 'bbb', 'ccc', '', ]
'aaa' => ['aaa', ]
'' => ['', ]

https://onlinegdb.com/rk7jOW0-7

上に書いた通り, 空文字を入力とした場合の挙動が異なるため, いずれにせよ自分が何を求めているのかに注意して使うほうが良い.

C++のgetlineでstringをsplitする際の注意点

C++においてstringをある文字で分割したい場合に, getlineを使って実装する例が検索するとよく出てくるが特殊な場合に罠に陥るので注意. 例えば以下のような実装(https://faithandbrave.hateblo.jp/entry/2014/05/01/171631 を一部改変).

#include <iostream>
#include <string>
#include <sstream>
#include <vector>

std::vector<std::string> split(const std::string& input, char delimiter)
{
    std::istringstream stream(input);

    std::string field;
    std::vector<std::string> result;
    while (std::getline(stream, field, delimiter)) {
        result.push_back(field);
    }
    return result;
}

int main()
{
    const std::string input = "aaa,bbb,ccc";

    for (const std::string& s : split(input, ',')) {
        std::cout << "'" << s << "'" << std::endl;
    }
}

これはうまくいき, aaa, bbb, cccの3つに分割される.

だが, inputを"aaa,bbb,ccc,"とした場合は要素数は4ではなく3になり, 上の例と同じ結果になってしまう. "aaa,bbb,ccc, "のように空白を置けば4つ目の要素" "が正しくとれる.

末尾以外に空文字列を入れた場合には正しく動作するので厄介 (inputが"aaa,bbb,,ccc"など).

https://onlinegdb.com/BJDaGpcWm

追記:

そもそもinputが空文字列""であった場合の動作はどうあるべきなのだろうか. この例でいえば, 空文字列に対しては空のベクトルを返すため, 空文字からなる長さ1のベクトルは扱うことができない. delimiterを含む文字列を要素とする場合のように, 明示的にquoteするとかしなければいずれにせよ, 空文字は正しく扱うことができないと考えたほうが良いのだろう.

Cythonのconst_iterator

CythonのC++対応についてはだいぶ怪しいところがある. また, const対応についても同じくである.

constは関数引数内では利用できるため, std::vector const&を引数とする関数を作成したときに, const_iteratorでループを書く必要があった. ここで通常のC++の通り, cdef vector[hoge].const_iterator it = vec.begin()とするとエラーで落ちる. const_iteratorをとってきたいときは, const_beginを利用する必要があるようだ. end()もまあ同様.

https://github.com/cython/cython/blob/master/Cython/Includes/libcpp/vector.pxd#L60

何も考えずにRustに入門する5

Rustではソースコード中のコメントからドキュメントを作成できる.

"cargo doc"コマンドがそれだが, 上の例だと"error: cannot document a package where a library and a binary have the same name. Consider renaming one or marking the target as `doc = false`"と言われて怒られる. これは実行可能ファイルとライブラリが混在しており, 名前が同じためおこる. そこで以下のように"Cargo.toml"に追記して, 実行可能ファイルの呼び名をかえて, ドキュメントの生成もしないようにする.

[[bin]]
name = "main"
doc = false
path = "src/main.rs"

これでドキュメントの生成が可能になったのであとはコメントを追加していく.

pub mod example {
    //! This is a module as an example.

    /// Displays a message.
    ///
    /// # Examples
    ///
    /// ```
    /// # use bar::example;
    /// example::hello();
    /// ```
    pub fn hello() {
        println!("Hello, world!");
    }
}

"//!"はそれを囲むモジュールの説明であり, "///"はそれにつづく関数の説明になる.

"```"で囲むことでコードを埋めこむことができる. コードスニペット中の"#"以下の行は実行はするがドキュメント上は見せないという意味になる. このコードはドキュメントとしてだけでなく, "cargo test"としたときに実際に実行されテストにかけられる. これを記述した上で先のように"cargo test"すると"Doc-tests"のところでテストが行なわれていることがわかる.

ひとつ注意として, 上のコードで"use bar::example;"としているが, この前に"extern crate bar"などとしてはいけない. その行があると, "error[E0432]: unresolved import `bar`" "Maybe a missing `extern crate bar;`?"というあべこべなエラーになる. これはむしろ"extern"していることで生じたエラーのようだ.

https://github.com/rust-lang/rust/issues/39341

何も考えずにRustに入門する4

Rustにはそもそもユニットテストフレームワークがあるようだ. "cargo test"とするとテストが実行される.

今回は自前で"src/lib.rs"を用意したので, このままだと何もテストされない. というわけでユニットテストを書いてみる.

#[macro_use] extern crate log;

pub mod example {
    pub fn hello() {
        debug!("This is a debug message.");
        error!("This is an error message");
        println!("Hello, world!");
    }

    #[cfg(test)]
    mod tests {
        use super::*;

        #[test]
        fn test_hello() {
            hello();
        }
    }
}

"#[test]"をつけるとテスト時に呼び出されるようになる. このテストでは"hello"の中で"panic!"が呼ばれないことを確認する. あとは"assert!"なり"assert_eq!"なりをがしがし書いていけば良い.

何も考えずにRustに入門する3

"main"から呼び出す自前の関数はクレートとして分けておきたい. ライブラリとして切り出せそうなものは"main.rs"とは別のファイルにまとめることにする.

まず, "src/lib.rs"というファイルを作成し, 自前の関数などはこちらに記述する. 上の例の場合,

#[macro_use] extern crate log;

pub mod example {
    pub fn hello() {
        debug!("This is a debug message.");
        error!("This is an error message");
        println!("Hello, world!");
    }
}

クレートの中にモジュール"example"を作成し, その中で"hello"関数を作成した. これを"src/main.rs"から呼び出すには,

extern crate env_logger;

extern crate bar;
use bar::example;

fn main() {
    env_logger::init();

    example::hello();
}