日記

内容の正しさは保証しません

emscriptenのインストール

環境

  • OS: Windows10 Pro
  • ターミナル: msys2上のmintty
  • python: msysのpython3.8.7-1

インストールの手順

公式サイト1に書いてあるように、

git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install latest
./emsdk activate latest
source ./emsdk_env.sh

とする。しかし3行目で

[Errno 22] Invalid argument: '\\\\?\\\\C:\\hogehagehoge.....

となって失敗するので、クローンしたらemsdk.pyのfix_potentially_long_windows_pathname関数の

pathname = os.path.normpath(pathname.replace('/', '\\'))

コメントアウトする(試してないけどこれは関係ないかも?)。そして

return '\\\\?\\' + pathname

return pathname

に置き換える。

今回詰まった原因は多分

  1. \\\\?\\を処理できない
  2. /homeは良いけど\\homeはエラーになるように、/\\に置換できないことがある

の2点なので、if not WINDOWSif not WINDOWS or MSYSにしても同じだと思うけど、なぜか失敗した。

もし同じことが起きたら、作業しやすいようにdownload_even_if_existsFalseにする。むだにダウンロードし直さなくなる。あと、インストールに失敗したnodeなどはディレクトリを削除するとアンインストールできる。

markdownをhtmlに変換して脚注を表示する

Githubwikiでドキュメントを公開しようとしたら、脚注が使用できなかったので、htmlに変換することにした。変換にはPandocを用いた。

pandoc -f markdown -t html --template=template --mathjax ファイル名.md > ファイル名.html

ついでに、

を行った。

外観

Githubと外観を合わせるために、Githubからcssをコピーしてtemplateから参照するようにする。

Pandocを使ってMarkdownを整形されたHTMLに変換する - Qiita

githubのmarkdown-cssをぶっこ抜く方法 - Qiita

ツールチップ

jqueryを使ってhtmlを書き換える。

$(() => {
    $(".footnote-ref").each((i, x) => {
        $(x).wrap("<span class='tooltip'></span>");
        
        let foot_note = $("#fn" + (i + 1) + "> p")
            .text()
            .replace("↩︎", "");
        $(x).after("<span class='tooltip-frame'><span class='tooltip-text'>" + foot_note + "</span></span>");
    });
});

jQuery 日本語リファレンス

ツールチップの実装は省略。

数式

pandocに--mathjaxを与えるだけで、$$数式$$で囲まれた数式が表示される。

$$ i = \sqrt{-1} $$


i = \sqrt{-1}
と表示される。

インデックス付きtransform

jsのように添え字が欲しいことがあったので書いた。

#include <type_traits>
#include <algorithm>

struct result_of
{
    template <class T, class R>
    struct y {
        using type = R;
        static inline constexpr bool value = T::value;
    };
    
    template <class C, class F, class... Args>
    static auto f() -> y<std::false_type, std::invoke_result_t<F&, Args...>>;
    
    template <class C, class F, class... Args>
    static auto f() -> y<std::true_type, std::invoke_result_t<F&, Args..., C>>;
};

template <class C, class F, class... Args>
using result_of_t = decltype(result_of::f<C, F, Args...>());

//添え字を与えてくれるstd::transform
template <
    template <class...> class C, 
    class... Args,
    class F,
    class R = result_of_t<std::size_t, F, typename C<Args...>::value_type>
>
static inline auto transform(C<Args...> const& t, F&& f)
{
    //Cはテンプレート引数を省略できるとする
    auto u = C<typename R::type>(t.size());
    
    if constexpr (R::value)
    {
        std::transform(t.begin(), t.end(), u.begin(), [&f](auto const& x) {
            static size_t i = 0;
            return f(x, i++);
        });
    }
    else {
        std::transform(t.begin(), t.end(), u.begin(), f);
    }
    return u;
}

result_of_t<C, F, Args...>::valueはファンクタをArgs..., Cで呼び出せるならtrue, そうでないときはfalseとなる。またresult_of_t<C, F, Args...>::typeはファンクタの返り値の型である。

#include <iostream>
#include <vector>
int main() {
    auto v = transform(std::vector{2, 4, 6, 8}, [](auto x, auto i) {
        std::cout << i << ":" << x * i << std::endl;
        return x * i; 
    });
}

結果

0:0
1:4
2:12
3:24

ノート 12月

std::moveとstd::forward

  • 関数テンプレートでは, 引数がT&&のときにX&&およびX&を与えることができる
    • このとき, TはX&と推論され, &&は無視して結局X&となる
  • そのせいでT&&(rvalue reference)特有の処理がそのままではできなくなる
  • std::moveはT&をT&&にstatic_castする
  • std::forwardはそのどちらか分からないT&&をキャストして元に戻す
    • この関数を使うことでT&&を受け取る関数を呼び出せる

参照

本の虫: rvalue reference 完全解説

//使ったことないので自信なし

ノート 8/10

最近Javascriptに興味があってPixi,jsを使ってみた。初めて使う言語なので書き方がおかしいかも

基本的なコード

PixiJS API Documentation

JSONで読み込む

  • スプライトシートを扱いたいときに必要
const app = new PIXI.Application();
document.body.appendChild(app.view);

app.loader
.add('imgs', './img.json')
.load((loader, resources) => {
    const imgs = resources['img'].textures;
    img = new PIXI.Sprite(imgs['001']);
    app.renderer.resize(img.width, img.height);
    app.stage.addChild(img);
});

参照

選択した画像を読み込んで表示する

<input id="file" type="file"></input>
const app = new PIXI.Application();
document.body.appendChild(app.view);

var $ = function (x) { return document.getElementById(x); };
$('file')
.addEventListener('change', (e) => {
    var file = e.target.files[0];
    if (!file.type.includes('image')) {
        return;
    }
    var reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = function () { //ファイル名と拡張子と最終更新日時が同じファイルは同一と見なされて読み込まれない
        var name = file.name + file.type + file.size + file.lastModifiedDate;
        app.loader
        .add(name, reader.result)
        .load((loader, resources) => {
            img = new PIXI.Sprite(resources[name].texture);
            app.renderer.resize(img.width, img.height);
            app.stage.removeChild();
            app.stage.addChild(img);
        });
    };
},
false);

ノート 7/24

std::transformは処理を適用・結果を格納するコンテナの範囲をイテレータとして受け取る関数だが、一々

std::vector<int> w(v.size());
std::transform(v.begin(), v.end(), w.begin(), w.end(), f);

と書くのが面倒な上、二行も使う。 そこで、コンテナvの参照と関数fから上記の処理をしてwを返すようなラッパが欲しい。

テンプレートテンプレート

クラステンプレート(名前だけでは不完全な型)をテンプレートで表すにはテンプレートテンプレートを使う。

template <class T>
sturct A {
    T t;
};

//Tとしてstruct Aを指定できる
template <template <class> class T>
struct B {
    T<double> t;
};

実引数からクラステンプレートを推論させる

template <template <class> class T, class U>
void f(T<U>);
  • 上記の関数fにA<int>{}を与えた場合、T=A, U=intと判断される。

実装する

template <
    template <class...> class C
    class... Args,
    class F,
    class R = typename std::invoke_result_t<F&, typename C<Args...>::value_type const&>
>
auto transform(C<Args...> const& t, F&& f)
{
    //Args...の中でR以外のパラメータは省略可能と仮定する
    auto u = C<R>(t.size()); 
    std::transform(t.begin(), t.end(), u.begin(), f);
    return u;
}
  • template <class...> class Cは任意のコンテナを表すことができる
  • Args...はCのテンプレート引数
  • Fはファンクタ
  • RはFをCの要素に適用して返ってくる値の型
  • transform関数の第一引数では上で述べた推論を利用している。例えばstd::vector<int, std::allocator<int>>{}を与えればC=std::vector, Args...=int, std::allocator<int>になる。

欠点

  • std::mapは引数にstd::pair<S, T>を取らないためC<R>の実体化に失敗してコンパイルエラー.何か工夫が必要

参考

transformをラップして変換後のオブジェクトを返すようにしてみる - Qiita

ノート 6/16

最近勉強できてなくてstd::vectorで詰まったので覚えたことを書く。

std::vectorを使うための条件
1 Tのコピーコンストラクタが定義されていて外部から呼び出し可能である
2 Tに代入演算子が定義され利用可能
3 Tのデストラクタが外部から呼び出し可能

コピーコンストラクタ:初期化に使われる
T(T const&) (またはT(T&&))

std::vector v(n);
とするとn回デフォルトコンストラクタが呼び出される。vの寿命が尽きた後、n回デストラクタが呼ばれる。

std::vector v(n, t) (tはT型オブジェクト)
コピーコンストラクタがn回呼ばれる。tの寿命が終わればデストラクタが呼び出される。またvの寿命も尽きればn回デストラクタが呼ばれる。