2023/08/12(土)C++20のコルーチンでタスクシステム(?)作ってみた
夏休みの自由研究じゃないけど、ふと思い立ってC++20のコルーチンでタスクシステムっぽいものを書いたらどうなるかやってみた。タスクシステムっていうかつまるところファイバーコンテナだけど。
それなりうまくいった
2016/07/18(月)双2次フィルタでLPF (他)
LPFがほしくて。
工学部だけど、アナログな信号処理とかぜんぜん勉強したことなくて、
解析学とかもまったく苦手だった情報系出身なので、
なんかLPFのサンプルプログラムとか見ても、パラメータをどう求めればいいかよくわかんなくて、
つまりどうすれば目的の関数が得られるだってばよ? 状態だったんだけど、
色々情報を探してさまよううちに↓のページを見つけて
http://www.g200kg.com/jp/docs/makingvst/04.html
RBJ Audio-EQ-Cookbook っていう つよい文書があって、つまりこれでLPFが作れるってことらしい。
理解度はやはりイマイチだけど、とりあえず低音が取り出せるようになった。
リンク先を見るに、HPFとかBPF、EQとかも作れるっぽい。便利。
今回は目的が別のところにあるので、勉強はここまでにして先に進めよう。
以下、とりあえず試したくて即席で書いたソース。
2016/06/16(木)LoadLibraryに渡されたDLLのパスをデバッガで見る x86
ロードされるDLLの一覧がほしいだけなら Dependency Walker 上で、プロファイリングすれば十分なのだけど。
Kernel32.dll は、すべてのプロセスで同じアドレス空間にロードされているため、
あるプログラムで、Kernel32.dll の API に対してGetProcAddress して得た関数アドレスは、実は他のプロセスでも有効。
これを利用して、LoadLibrary に渡される文字列をデバッガから調べてみることにする。
まずは、適当なプログラム(x86)で、LoadLibraryA と LoadLibraryW を GetProcAddress して、アドレスを調べておく。
調べた結果、それぞれ 0x7639A840 と 0x763A4BF0 だった。
デバッグ対象のEXEをVisual Studioでソリューションとして開き、「デバッグ→ステップイン」でプロセスを開始する。
EXEのエントリポイントで止まるので、この状態で「デバッグ→ウィンドウ→逆アセンブル」を開き、
アドレスに先ほど得た 0x7639A840 を、アドレスとして入力しLoadLibrary の先頭にブレークポイントを仕掛ける。
同様に 0x764A5BF0 にもブレークポイントを仕掛ける。
F5で実行を再開。
ブレークしたときLoadLibraryの先頭にいる。
x86の関数呼び出し規約によれば LoadLibrary の第1引数は、ESPレジスタの指しているアドレス+4の位置に格納されている。
LoadLibraryの第1引数はロードしたいDLLへのパスを格納している文字列へのポインタなので、
これを得るための式をウォッチウィンドウに追加することで、何を引数に関数が呼ばれたかがわかる。
(char**)(@esp+4) ← LoadLibraryAが呼ばれたとき (wchar_t**)(@esp+4) ← LoadLibraryWが呼ばれたとき
結果。*1
というようなことをやっていた。
↑のDSPプラグインを他のアプリから使いたかったんだけど、うまく動かないやつがあってどうしてだろうと思って。
ちなみに、ESPレジスタで思い出したけど、
上記のように関数が呼び出されたとき、ESPレジスタの指す先にはリターンアドレスが入っているので、
これを使うことで、関数の呼び出し元のアドレスを得て メモリリークの追跡もできたりした。
過去形なのは最近x64が台頭しつつあるから。*2
void *my_alloc(void *pCaller, size_t size) { ... } #define NAKED __declspec(naked) #define WITH_CALLER(...) { void *CALLER; { __asm mov eax, [esp] __asm push ebp __asm mov ebp, esp __asm mov CALLER, eax } __VA_ARGS__; { __asm pop ebp __asm ret } } NAKED void * operator new(size_t size) WITH_CALLER(my_alloc(CALLER, size));
// WITH_CALLER の 展開後イメージ __declspec(naked) void* operator new(size_t size) { void* pCALLER; __asm mov eax, [esp]; // 関数が呼び出された瞬間、ESPの指す先にあるリターンアドレスをEAXにメモ。 __asm push ebp; // VC++ がローカル変数へのアクセスをEBPを元に行うコードを生成するので、 __asm mov ebp, esp; // それと互換するようにEBPを準備する。 __asm mov pCALLER, eax; // メモったリターンアドレスをローカル変数へ移して my_alloc(pCALLER, size); // それを使って本命の関数呼び出し。 __asm mov esp, ebp; // 使ったものは __asm pop ebp; // 戻しておこう __asm ret; // my_alloc の戻り値がEAXに入ってるはずなので、それがそのまま戻る。 }
my_alloc は呼び出し元のアドレスをつけて呼び出されるので、線形リストなどに時刻・サイズ等とともにメモっておけばよい。
ビルド時 .map ファイルや、逆アセンブルを出力しておけば、__FILE__などなくとも関数を特定できるのでこれで十分。
2015/03/11(水)Comparing floating point numbers with ε
2014/09/27(土)template <T> struct intrusive_tree_base
だいぶ前に書いたC++で木構造どうしようの記事
template <class T> class TreeNode { ... }; の中身は?
template<T> struct TreeNode { TreeNode<T> *parent, *child_left, *child_right; }
とかつくったら、
TreeNode<OBJECT_T *> pObject; の子供のメンバにアクセスするたびに
static_cast<OBJECT_T *>(pObject->child_left)->SomeMember;
みたいに static_cast すんのか?
という疑問に対する一つの答えが
template<T> struct intrusive_tree_base<T> { T *parent, *child_left, *child_right; } struct SomeTreeNode : public intrusive_tree_base<SomeTreeNode> { SomeType SomeMember; };
すればいいじゃないということに気づいた。
というわけで、実際に実装してみた。
intrusive_tree_base
https://gist.github.com/ttsuki/5b0498518f99f1fd2b78
C++11を学ぶにつれて、だんだんこういうかゆいところにも手が届くように、なってきたりする。
2014/01/18(土)x86 で cntlz64
Counting of Leading Zeros.
Number of Leading Zeros. ともいう。
64bitのnlzをx86で求めるにはどうすりゃええんか? と思っていろいろいじってた。
2013/12/21(土)template <class T> class TreeNode { ... }; の中身は?
tree を作ることを考える。
根があって、任意数の子をとれる。
子も任意数の子をとれる。
汎用的なtreeクラスの節、template
どうやったら引き回しやすいか。
まぁ、複数の子っても、たくさんの子を持つか、
あるいはまったく子を持たないかわからないので、
二分木で表現することにする。
思いつくまま定義を書くと、
template<class TValue> class Node { TValue value; Node<T> *parent, *firstChild, *nextSibling; };
みたいになって、それを実装してみたのが
https://gist.github.com/ttsuki/95ceef4cacdc9c5e0294 なのだけど、
いざ使ってみようと思って、
使う側に回ってからTValueにあたる型を作ってて思ったんだけど、
普通、Treeで何らかの構造を表そうと思ったら、
その要素TValueはデータ構造的にツリーになる前提があるわけで
TValue自身がTValue::ナントカ() が自分の親・兄弟にアクセスできないと、
トラヴァーサルしにくいなーということに後から気づいた。
じゃあ、
class 実際に扱いたい型 : public Node<実際に扱いたい型 *> { ctor() : Node(this) { } };
なら?
にしても、parentは、Node<TValue *>の型であって、
それをTValueとして扱うにはダウンキャストがいるのでなんか気持ち悪い。
って考えてると、
class 実際に扱いたい型 { Node<実際に扱いたい型 *> link; ctor() : link(this) { } };
になって、マジで?ってなる。
これだと、でもまぁ、これだとキャストなしに、
自分の親ノードを得るのに return link.parent.value; できるので……。
ただ、GetParent() とか、ApplyAllChildren等を
全部pImplばりに再実装しないといけなくて、
それめんどくさいなぁ。
なんか、お約束のレシピはないのかしら。
2013/11/04(月)template <class T> struct Hoge { }; の T を POD に制約したい
タイトルの通り、template
というわけで、 Hoge
コンパイルエラーを生成できるような、PRECONDITIONAL_ERROR なるものを作ってみた。
STATIC_ASSERTの親戚のような感じで使えるかなー。
今回作ってみたのは、template実体化時にTがPODじゃないとコンパイルエラー。
ついでに、引数に渡された配列の長さがある一定以上ないとコンパイルエラー。
自作コンテナを作るとき、TがPODならコンストラクタもデストラクタも呼ばなくてよいので、
コンテナを clear するときも、for (int i = 0; i < size(); i++) this[i]->~T(); する必要が無いっていう。
以下 gist