アリスは物理転送機を持っている

まだまだ続くアリプラシリーズ。目次は後で作成します。既に自分で何を書いているのか忘れているし。
ひとまず、物理転送機を作ったところで、かつて流行ったオブジェクトパターンの再発明なのかなぁと思ったりします。このシリーズ、特にパターンを使っている訳ではなくて、自分がいままで業務で使ったパターンを書き残しているので、

  1. アリス&プラダという組み合わせで、C++ で現実をモデル化してみる。
  2. C++ でのコードを書いてみる。
  3. そういえば、オブジェクトパターンでこんなのがあったよなぁ。

という流れになっています。

さて、物理転送機、というのは別のところにコピーを作れるっていう方法です。今回は、ひとつの棚にプラダを入れて、そして取り出して、もう一度棚に入れる、という動作になります。取り出すっていうのは、いわゆる永続化なんですが、C++ の場合は単なるバイナリデータとして扱えますよって話です。

// for アリスは物理転送機を持っている

#include <string.h>
#include <iostream>
#include <string>
using namespace std;

class ISerialize {
	// シリアライズ化
	void *Serialize();
	// データから復元
	static void Serialize( void * );
};

class Bag : public ISerialize 
{
public:
	// 利用フラグ
	bool used ;
	// 持ち主の名前
	char ownerName[30];
	// ブランド名
	char brandName[30];
public:
	// コンストラクタ
	Bag() : used(false) {
		ownerName[0] = '\0';
		brandName[0] = '\0';
	}
	// アクセッサ
	bool getUsed() { return used; }
	string getOwnerName() { return ownerName; }
	void setOwnerName( string name ) {
		if ( ownerName[0] == '\0' ) {
			strcpy( ownerName, (const char*)name.c_str() );
		}
		
	}
	string getBrandName() { return brandName; }
	void setBrandName( string name ) {
		if ( brandName[0] == '\0' ) {
			strcpy( brandName, (const char*)name.c_str() );
		}
	}
	// 利用する
	virtual void Use() {
		this->used = true;
	}
	// シリアライズ
	virtual void *Serialize() {
		int size = sizeof(Bag);
		void *data = new char[size];
		memcpy( data,this, size );
		return data;
	}
	// 逆シリアライズ
	static Bag *Serialize(void *data) {
		Bag *bag = (Bag*)data;
		return bag;
	}
};
class Prada : public Bag 
{
public:
	Prada() : Bag() {
		strcpy( brandName, "Prada" );
	}
};
class Tiffany : public Bag 
{
public:
	Tiffany() : Bag() {
		strcpy( brandName, "Tiffany" );
	}
};


class Alice 
{
private:
	Bag *bag;
public:
	Alice() : bag(NULL) {
	}
	void Present( Bag *b ) 
	{
		if ( this->bag == NULL ) {
			this->bag = b;
			this->bag->setOwnerName("Alice");
		}
	}
	void *SaveMyBag() {
		void *data = bag->Serialize();
		bag = NULL;
		return data;
	}
	void LoadMyBag(void *data) {
		if ( this->bag == NULL ) {
			Bag *bag = Bag::Serialize( data );
			this->bag = bag;
		}
	}
	string GetBrandName() {
		if ( bag == NULL ) {
			return "none";
		} else {
			return bag->getBrandName();
		}
	}
};


int main(void)
{
	Alice alice;

	Bag *bag = new Prada();
	// アリスにプラダをプレゼント
	alice.Present( bag );
	cout << "alice's bag brand is " << alice.GetBrandName() << endl;
	// 一度、棚から降ろして持っていない状態にする
	void *prada = alice.SaveMyBag();
	cout << "alice's bag brand is " << alice.GetBrandName() << endl;
	// アリスにティファニーをプレゼント
	bag = new Tiffany();
	alice.Present( bag );
	cout << "alice's bag brand is " << alice.GetBrandName() << endl;
	// ティファニーを棚卸して
	void *tiffany = alice.SaveMyBag();
	// 再び、プラダを棚に入れる
	alice.LoadMyBag( prada );
	cout << "alice's bag brand is " << alice.GetBrandName() << endl;

	return 0;
}

ひとまず実行すると、こんな感じ。

D:\work\blog\src\alice>a
alice's bag brand is Prada
alice's bag brand is none
alice's bag brand is Tiffany
alice's bag brand is Prada

ここでは、永続化ということでシリアライズがミソです。インターフェースにしてあるのは、気分の問題でして、シリアライズのコードはこんなに簡単。

	// シリアライズ
	virtual void *Serialize() {
		int size = sizeof(Bag);
		void *data = new char[size];
		memcpy( data,this, size );
		return data;
	}
	// 逆シリアライズ
	static Bag *Serialize(void *data) {
		Bag *bag = (Bag*)data;
		return bag;
	}

クラスのバイトデータを保持しているだけなんですが、実はこの技が使えるのは C/C++ だけなんですね。Java, C#, VB なんてのは使えません。シリアライズする時に何らかのフォーマッティング(大抵は XML なんですが)を使わない限り無理です。

この手のシリアライズ、C++ が得意とするとこで、データの読み書きがバイナリで直接行われるために非常に高速に動きます。っていうか、もともと C言語の struct 互換の動きになっているので、こういう風に動くわけでして、フォーマットを気にせずに単純に sizeof(…) でバイトデータを書き込めるのが得意なのですね。

# 勿論、このバイナリコードが人にとっては謎な値なので、XML フォーマットというのが流行りなわけですが。後、構造体/クラスをバイナリのままやり取りする方法は、固定長のデータしか無理なんですよね。なので、文字列のところで string じゃなくて char name[30] となっているのはそれが理由です。

データ構造を気にしなくて、高速に読み書きができるので、利用どころとしてはデータのヘッダ部分なんかに良く使われます。そう BMP 形式のヘッダとか、struct なんとかで読みだした後に、データ長を算出するときなんか、struct で読み込めば一発です、という話ですね。

カテゴリー: C++ | アリスは物理転送機を持っている はコメントを受け付けていません

誰かが使ったらアリスに知らせろ(2)

前回のソースはインターフェースを使っている例なんですが、実は C++ の場合はメンバ関数のポインタを使えるのでインタフェースは必要ありません…と言いますから、インタフェースの代わりになります。Java だと定番のリスナーパターンというとでインターフェースを利用、C# の場合はデリゲートを使います。このあたり、リスナーパターンは言語によって違った実装ができるという訳で。

メンバ関数を使って書き直したのが次のコードです。

// for 誰かが使ったらアリスに知らせろ

#include <iostream>
#include <list>
using namespace std;

class Person ;

class INotify {
protected:
	Person *person ;
	// メンバ関数ポインタ
	void (Person::*onTatch)();
public:	
	// メンバ関数の登録
	void setCatcher(Person *per, void (Person::*catcher)()) {
		person = per;
		onTatch = catcher;
	}
	// 呼出し
	virtual void OnTatch( void *bag ) {
		if ( onTatch != NULL ) {
			(person->*onTatch)();
		}
	}
};

class Bag : public INotify {
protected:
	void *_mark;
public:
	Bag() : _mark(NULL) {}
	virtual void setMark( void *mark ) {
		// 1回だけマークできる
		if ( _mark == NULL ) {
			_mark = mark;
		}
	}
	virtual void *getMark() {
		return _mark;
	}
	virtual void Used( void *user ) {
		if ( _mark != NULL && _mark != user ) {
			OnTatch( this );
		}
	}
};

class Prada : public Bag {};
class Tiffany : public Bag {};

class Person
{
private:
	list<Bag*> bags;
public:
	Person() {
	}
	void Present( Bag *bag ) 
	{
		if ( dynamic_cast<Prada*>(bag) != NULL &&
             bag->getMark() == NULL ) 
		{
			bag->setMark( this );
			// メンバ関数の登録
			bag->setCatcher( this, &Person::onTatch );
			bags.push_back( bag );
		}
	}
	int CountBags() 
	{
		return bags.size();
	}
	void Use( Bag *bag ) {
		bag->Used( this );
	}
	void onTatch() {
		cout << "who use my Prada bag!!!" << endl;
	}
};

int main(void)
{
	Person alice;
	Person lolita;
	
	Prada *bag = new Prada();
	// アリスにプレゼント
	alice.Present( bag );
	// アリスが使う分には問題なし
	alice.Use( bag );
	// 同じ鞄をロリータにプレゼント
	lolita.Present( bag );
	// ロリータが鞄を使うと...
	lolita.Use( bag );

	return 0;
}

これも実行すると、次のように誰が使ったんじゃッ!!!ってことになります。

D:\work\blog\src\alice>a
who use my Prada bag!!!

関数ポインタ、メンバ関数ポインタの書き方はちょっと難しくてコンパイルエラーとの格闘になります。慣れると関数部分をポインタにするだけだなぁ、慣れない場合はちょっと意味不明な感じがしますね。配列の配列のポインタなんかと一緒です。

カテゴリー: C++ | 誰かが使ったらアリスに知らせろ(2) はコメントを受け付けていません

誰かが使ったらアリスに知らせろ

怒涛のアリプラシリーズをもうひとつ。

鞄に対してマーキングをするのは消極的な手段でして、マーキングを上書きされてしまったり、マーキング自体を無視して Use メソッドを呼び出したりするとアリスはお手上げです。なので、もっと積極的に違法な Use メソッドが呼び出されたら、アラートメッセージがアリスに届くようにします。
そう、mvvm パターンの INotifyPropertyChanged と同じです。

// for 誰かが使ったらアリスに知らせろ

#include <iostream>
#include <list>
using namespace std;

class ICatch {
public:
	virtual void OnTatch( void *bag ) = 0;
};

class INotify {
protected:
	ICatch *catcher;
public:	
	void setCatcher( ICatch *user ) {
		catcher = user;
	}
	virtual void OnTatch( void *bag ) {
		if ( catcher != NULL ) {
			catcher->OnTatch( bag );
		}
	}
};

class Bag : public INotify {
protected:
	void *_mark;
public:
	Bag() : _mark(NULL) {}
	virtual void setMark( void *mark ) {
		// 1回だけマークできる
		if ( _mark == NULL ) {
			_mark = mark;
		}
	}
	virtual void *getMark() {
		return _mark;
	}
	virtual void Used( void *user ) {
		if ( _mark != NULL && _mark != user ) {
			OnTatch( this );
		}
	}
};

class Prada : public Bag {};
class Tiffany : public Bag {};

class Alice : public ICatch
{
private:
	list<Bag*> bags;
public:
	Alice() {
	}
	void Present( Bag *bag ) 
	{
		if ( dynamic_cast<Prada*>(bag) != NULL &&
             bag->getMark() == NULL ) 
		{
			bag->setMark( this );
			bag->setCatcher( this );
			bags.push_back( bag );
		}
	}
	int CountBags() 
	{
		return bags.size();
	}
	void Use( Bag *bag ) {
		bag->Used( this );
	}
	virtual void OnTatch( void *bag ) {
		cout << "who use my Prada bag!!!" << endl;
	}
};

class Lolita 
{
private:
	list<Bag*> bags;
public:
	void Present( Bag *bag ) 
	{
		bag->setMark( this );
		bags.push_back( bag );
	}
	void Use( Bag *bag ) {
		bag->Used( this );
	}
};

int main(void)
{
	Alice alice;
	Lolita lolita;
	
	Prada *bag = new Prada();
	// アリスにプレゼント
	alice.Present( bag );
	// アリスが使う分には問題なし
	alice.Use( bag );
	// 同じ鞄をロリータにプレゼント
	lolita.Present( bag );
	// ロリータが鞄を使うと...
	lolita.Use( bag );

	return 0;
}

鞄(Bag)のほうには、INotiry インターフェースを仕込んでおきます。アラートメッセージをを受け取る側(Alice)のほうは、ICatch インターフェースで受け取りの関数を用意しておきます。C++ で2つのインターフェースを使っているのは C# のデリゲートの機能がないので、こうなっています。static な関数ポインタを用意してもいいのですが、どうせならば、Alice のメソッドとして用意したいところですよね。
実は、モノである鞄(Bag)に機能を仕掛けておいて、人であるアリスに通知する、ってのがいい感じかなと。

これを実行すると、

D:\work\blog\src\alice>a
who use my Prada bag!!!

誰か私のバッグを使ったッ!!!って怒ります。ロリータからは Use メソッドの中身は見れないし、そもそも Lolita は ICatch を継承してないのでアラートメッセージを受け取りません。

似たようなパターンとしては、

  • Bag クラスのデストラクタに仕込んで、なんで、私の鞄を捨てるのよッ!!!とか。
  • List を改造して、なんで、私の鞄を持っているのよッ!!!とか

ができます。鞄というオブジェクトはひとつなので、Alice::bags と Lolita::bags の両方にあるってのは妙な感じですよね。実際は、ポインタが使われているので、鞄そのものが置いてあるというよりも、鞄を示すタグ(所有権)を撮り廻しているっていう意味になりますが。鞄そのものは実体なのでひとつしかないけど、ポインタ(指し示すもの)は、いくらでもできるから list のようにポインタのコレクションの場合は、所有自体を制限させるのはできないのかなと。写真みたいなものですから。肖像権を主張できても、対象そのものを写真で写すこを制限するのは難しい、っていう意味ですね。

カテゴリー: C++ | 誰かが使ったらアリスに知らせろ はコメントを受け付けていません

アリスはロリータと鞄を共有しない

引き続き、アリプラシリーズ。

ルイスが鞄をプレゼントする相手は、アリスだったりロリータだったりするわけですが、間違ってロリータにプレゼントしたものをアリスに渡したときの反応はどうでしょうか?ってな設定が次のコードです。

// for アリスはロリータと鞄を共有しない

#include <iostream>
#include <list>
using namespace std;

class Bag {
protected:
	void *_mark;
public:
	Bag() : _mark(NULL) {}
	virtual void setMark( void *mark ) {
		_mark = mark;
	}
	virtual void *getMark() {
		return _mark;
	}
};

class Prada : public Bag {};
class Tiffany : public Bag {};

class Alice
{
private:
	list<Bag*> bags;
public:
	Alice() {
	}
	void Present( Bag *bag ) 
	{
		if ( dynamic_cast<Prada*>(bag) != NULL &&
             bag->getMark() == NULL ) 
		{
			bag->setMark( this );
			bags.push_back( bag );
		}
	}
	int CountBags() 
	{
		return bags.size();
	}
};

class Lolita 
{
private:
	list<Bag*> bags;
public:
	void Present( Bag *bag ) 
	{
		bag->setMark( this );
		bags.push_back( bag );
	}
};

int main(void)
{
	Alice alice;
	Lolita lolita;
	
	cout << "alice has " << alice.CountBags() << " bags." << endl;
	alice.Present(new Prada());
	cout << "alice has " << alice.CountBags() << " bags." << endl;
	alice.Present(new Tiffany());
	cout << "alice has " << alice.CountBags() << " bags." << endl;
	// 一度ロリータにあげる
	Bag *bag = new Prada();
	lolita.Present( bag );
	// そしてアリスにプレゼント
	alice.Present(bag); 
	cout << "alice has " << alice.CountBags() << " bags." << endl;
	bag = new Prada();
	alice.Present(bag);
	cout << "alice has " << alice.CountBags() << " bags." << endl;

	// 実は、アリスにプレゼントしたものをロリータにあげることもできる
	lolita.Present( bag );

	return 0;
}

バッグ自体にマーキングを付けているので、自分の鞄かどうかは分かるので、一度ロリータにプレゼントされた鞄を拒否ることができます。

が、問題は、アリスにプレゼントした鞄はロリータによってマーキングが上書きされてしまうので、その鞄はロリータのものになってしまうんですねぇ。困った。

これを防ぐには、Bag クラスの mark の処を次のように1回だけ書くように直します。

class Bag {
protected:
	void *_mark;
public:
	Bag() : _mark(NULL) {}
	virtual void setMark( void *mark ) {
		if ( _mark == NULL ) {
			_mark = mark;
		}
	}
	virtual void *getMark() {
		return _mark;
	}
};

ええ、何処かでみたようなコピーワンスの処理ですね。似たような感じで Use メソッドの中でカウンタを減らせば、ユーズワンス、の処理も可能です。ただし、コピーワンスの機能も、コピー対象(Prada とか DVD とか)を扱うモノ(Lolita とかビデオ機器とか)が Used をきちんと呼び出さなければ、利用は可能なのです。
このあたりのコピーワンスのガードを確実に呼び出させるためには、例えば初期の暗号解読のためのキーの読み出し自体にコピーワンスのガードを入れるとか、利用に必須なものに対してガードを入れ込みます。実は似たようところでは、SNS のログイン機能とか、ゲームソフトのコピーガードの仕方とかも似た方式です。最初にガードを置きます。
なので、実は最初にガードを置かずに、本体の所々にガードを分散させるってのもアリなんですよね。確か、販売 DVD のコピーガードはこの方式になっています。

カテゴリー: C++ | アリスはロリータと鞄を共有しない はコメントを受け付けていません

アリスは同じ鞄を抱えない

更にアリプラシリーズ。

同じ鞄をプレゼントした場合は、アリスは貰わない…と言いますから、同じ鞄なんだからなんでもう一度プレゼントするの?というコードです。

// for アリスは同じ鞄を抱えない
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;

class Bag {
protected:
	bool used;
public:
	virtual bool getUsed() { return used; }  
	virtual void Used() { this->used = true; }  
};

class Prada : public Bag {};
class Tiffany : public Bag {};

class Alice
{
private:
	list<Bag*> bags;
public:
	Alice() {
	}
	void Present( Bag *bag ) 
	{
		if ( find(bags.begin(),bags.end(),bag) == bags.end() &&
             dynamic_cast<Prada*>(bag) != NULL ) {
			bags.push_back( bag );
		}
	}
	int CountBags() 
	{
		return bags.size();
	}
};

int main(void)
{
	Alice alice;
	
	cout << "alice has " << alice.CountBags() << " bags." << endl;
	Bag *bag = new Prada();
	alice.Present(bag);
	cout << "alice has " << alice.CountBags() << " bags." << endl;
	alice.Present(new Tiffany());
	cout << "alice has " << alice.CountBags() << " bags." << endl;
	alice.Present(bag); // 同じものをプレゼントする
	cout << "alice has " << alice.CountBags() << " bags." << endl;
	alice.Present(new Prada());
	cout << "alice has " << alice.CountBags() << " bags." << endl;

	return 0;
}

実行するとこんな感じ。

D:\work\blog\src\alice>a
alice has 0 bags.
alice has 1 bags.
alice has 1 bags.
alice has 1 bags.
alice has 2 bags.

プレゼントすると、一度、タンス(bags)を find 関数で照合します。何故か知らないけど、タンス(bags)にあったものが再び Present される訳で、変なのという感じなのですが、bags には追加しません。
データベースで言うところの、同じ名前だったらデータベースに insert しない処理ってのと同じですね。

SELECT @COUNT = count(*) FROM bags WHERE ...
IF @COUNT = 0 THEN
  INSERT bags VALUES ( ... )
END IF

のようなものです。重複チェックをして挿入ってな具合。これは、bags にある量が多くなるとだんだんと遅くなっていきます。いわゆる O(n) の確率。ただし、find のアルゴリズムを変えていけば O(log n) だっけ? になります。ハッシュテーブルとかバイナリツリーとかを使います。大変ですよね。不安ですね。

しかし、ちょっと工夫すると、一発で貰った鞄かどうかが分かります。Bag クラス自体にマーキングを示す mark 変数を用意して、これに自分のポインターを入れておきます。そうすると、mark を調べるだけで一発で分かりますよね。

class Bag {
protected:
	void *_mark;
public:
	Bag() : _mark(NULL) {}
	virtual void setMark( void *mark ) {
		_mark = mark;
	}
	virtual void *getMark() {
		return _mark;
	}
};

特性を知って、ちょっとクラスに工夫を加えるとうまくいくっていうパターンです。

カテゴリー: C++ | アリスは同じ鞄を抱えない はコメントを受け付けていません

アリスはプラダの鞄を蒐集する

自分でも主旨がよくわからないけれどもアリプラシリーズの続き。アリス・イン・ワンダーランドとプラダを着た悪魔に似ているような似てないような…という関係は後付けで。

アリスに Prada をプレゼントすると貰うけど、Tiffany をプレゼントしても貰わない、ってのが次のコードです。Prada と Tiffany のクラスを一度 dynamic_cast してみてチェックする訳ですね。

// for アリスはプラダの鞄を蒐集する
#include <iostream>
#include <list>
using namespace std;

class Bag {
protected:
	bool used;
public:
	virtual bool getUsed() { return used; }  
	virtual void Used() { this->used = true; }  
};

class Prada : public Bag {};
class Tiffany : public Bag {};

class Alice
{
private:
	list<Bag*> bags;
public:
	Alice() {
	}
	void Present( Bag *bag ) 
	{
		if ( dynamic_cast<Prada*>(bag) != NULL ) 
		{
			bags.push_back( bag );
		}
	}
	int CountBags() 
	{
		return bags.size();
	}
};

int main(void)
{
	Alice alice;
	
	cout << "alice has " << alice.CountBags() << " bags." << endl;
	alice.Present(new Prada());
	cout << "alice has " << alice.CountBags() << " bags." << endl;
	alice.Present(new Tiffany()); // ★
	cout << "alice has " << alice.CountBags() << " bags." << endl;
	alice.Present(new Prada());
	cout << "alice has " << alice.CountBags() << " bags." << endl;

	return 0;
}

実行するとこんな感じ。

D:\work\blog\src\alice>a
alice has 0 bags.
alice has 1 bags.
alice has 1 bags. ★
alice has 2 bags.

3番目に Tiffany をプレゼントしていますが受け取って貰えません。贅沢者です。

一方で、鞄ならなんでも受け取るけど、見せるときは Prada だけ、というのがロリータです。

// for ロリータはプラダの鞄だけを見せる
#include <iostream>
#include <list>
using namespace std;

class Bag {
protected:
	bool used;
public:
	virtual bool getUsed() { return used; }  
	virtual void Used() { this->used = true; }  
};

class Prada : public Bag {};
class Tiffany : public Bag {};

class Lolita
{
private:
	list<Bag*> bags;
public:
	void Present( Bag *bag ) 
	{
		bags.push_back( bag );
	}
	list<Bag*> LookBags() 
	{
		list<Bag*> temp;
		for ( list<Bag*>::iterator it = bags.begin(); it != bags.end();  ++it ) {
			if ( dynamic_cast<Prada*>(*it) != NULL ) {
				temp.push_back(*it);
			}
		}
		return temp;
	}
};

int main(void)
{
	Lolita lolita;
	
	cout << "lolita has " << lolita.LookBags().size() << " bags." << endl;
	lolita.Present(new Prada());
	cout << "lolita has " << lolita.LookBags().size() << " bags." << endl;
	lolita.Present(new Tiffany());
	cout << "lolita has " << lolita.LookBags().size() << " bags." << endl;
	lolita.Present(new Prada());
	cout << "lolita has " << lolita.LookBags().size() << " bags." << endl;

	return 0;
}
D:\work\blog\src\alice>a
lolita has 0 bags.
lolita has 1 bags.
lolita has 1 bags.
lolita has 2 bags.

ロリータの場合は、Present された鞄は bags にため込むけど、いざ LookBags で見せてもらうと、Prada に一致するものしか見せません。

このクラスを判別する方法ですが、C# だと 変数名 as クラス名 でキャストをしてチェックができます。他にも GetType なりでチェックする方法もあります。
ここで面白いのは、クラス名がクラスの属性のひとつとなっているところで、Prada クラスか Tiffany クラスで作られたオブジェクトを判別するのに、オブジェクトの属性ではなく、クラスそのものの属性というのがミソですね。

例えば、JUnit では Test というメソッドをリフレクションで拾う訳ですが、C# だと [TestCase] という形で属性を与えます。その昔はこのような考え方がなかったので、クラスを判別するときは明示的にクラス名を protected 変数などで設定したのです。

class Prada {
protected:
  char *classname = "Prada";
public:
  ...
};

こんな感じで。そう、CakePHP で自前のクラス名を指定している(PHP4対策だそうです)を見て、そんなことを考えたりしました。UML で云えば、クラス変数オブジェクト変数という違いだったり。

カテゴリー: C++ | アリスはプラダの鞄を蒐集する はコメントを受け付けていません

CakePHP から SlimStat へアクセスする(準備)

アクセス解析では wordpress の SlimStat と Google Analytics を使っているのですが、SlimStat も Analytics もグラフ表示が flush で出来ているから iPad で確認ができないんですよね。ちょっと困る。なので、数値だけでも見たいなぁと思いつつ、まずは SlimStat から手をつけるか、と思っています。

SlimStat のテーブル構造は簡単で、6つのテーブルしかありません。しかも、自分で解析するときに必要なのは、wp_slim_stats ぐらいなものです。wp_slim_visits を見ると訪問者毎のアクセス数が分かるみたいなのですが、トラッキングコード自体は slimstat が使っているだけなので、実質 wp_slim_stats だけで解析が可能です。

テーブル構造はこんな形。

id, int(10) unsigned, NO, PRI, , auto_increment
ip, int(10) unsigned, YES, , 0, 
language, varchar(5), YES, , , 
country, varchar(2), YES, , , 
domain, varchar(255), YES, , , 
referer, varchar(255), YES, , , 
searchterms, varchar(255), YES, , , 
resource, varchar(255), YES, , , 
browser_id, smallint(5) unsigned, NO, , 0, 
screenres_id, smallint(5) unsigned, NO, , 0, 
plugins, varchar(255), YES, , , 
visit_id, int(10) unsigned, NO, , 0, 
dt, int(10) unsigned, YES, , 0, 

ひとまず、

select distinct searchterms from wp_slim_stats
order by searchterms desc
limit 1000;

なんていうクエリを叩くと、検索されてくる単語が割り出せます。
これを時刻(dt)で区切ってやれば、最近やってくるキーワードが割り出せますね。

他にもブログへのアクセス(resource)をチェックしていけば、直近よく読まれている記事 top 10 という表示も可能ですね。

という訳で、実装は後程。

カテゴリー: 雑談, CakePHP | CakePHP から SlimStat へアクセスする(準備) はコメントを受け付けていません

アリスは初物がお好き

今度は、プラダの鞄でも最初の製品だけを好む、という設定にしてみます。同じオブジェクトでも最初だけっていうのは製造番号が付いているとか、シルクスクリーンに番号が振ってあるとか、限定品っていう意味合いですね。これは、COM で言うところの参照カウンタと同じです。

// for アリスは初物がお好き
#include <iostream>
using namespace std;

class Bag {
protected:
	bool used;
	static int _count;
public:
	Bag() : used(false) {
		_count++;
		cout << "constractor " << _count << endl;
	}
	bool getUsed() { return used; }  
	void Used() { this->used = true; }  
	// 参照カウンタ
	int getCount() { return _count; }
};
// 参照カウンタを初期化
int Bag::_count = 0;

class Prada : public Bag {};
class Tiffany : public Bag {};

// 初物好きなアリス
class Alice
{
public:
	Alice() {}
	bool DoYouLike( Bag *bag ) 
	{
		if ( bag->getCount() != 1 || bag->getUsed() == true ) {
			return false;
		} else {
			return true;
		}
	}
	void Use( Bag *bag ) {
		bag->Used();
	}
};
// 悪友ロリータ
class Lolita 
{
public:
	bool DoYouLike( Bag *bag ) {
		return true;
	}
	void Use( Bag *bag ) {
		bag->Used();
	}
};

int main(void)
{
	Alice alice;
	Lolita lolita;
	{
		Prada bag;
		if ( alice.DoYouLike( &bag ) ) {
			cout << "alice like first Prada." << endl;
		} else {
			cout << "alice don't like other Prada." << endl;
		}
	}
	{
		Prada bag;
		// アリスは初物じゃなくちゃ嫌
		if ( alice.DoYouLike( &bag ) ) {
			cout << "alice like first Prada." << endl;
		} else {
			cout << "alice don't like other Prada." << endl;
		}
	}
	return 0;
}

同じように Prada bag として bag を作成しているけど、最初の bag と次の bag は違います。C++ の場合は参照カウンタをクラスの外で初期化しないと駄目なんですが(C++0x だとできたっけ?)、C# だとクラス内で初期化ができるので static で指定すればOK。

using System;

public class Bag {
	protected bool _used = false;
	protected static int _count = 0;
	public Bag() {
		_count++;
	}
	public void Use() {
		_used = true;
	}
	public bool Used {
		get { return _used; }
	}
	public int Count {
 		get { return _count; }
	}
}
public class Prada : Bag {}
public class Tiffany : Bag {}

// 初物好きなアリス
public class Alice {
	public bool DoYouLike( Bag bag ) {
		if ( bag.Count != 1 || bag.Used == true ) {
			return false;
		} else {
			return true;
		}
	}
}

public class Program {
	public static void Main(string []args ) {
		Alice alice = new Alice();
		
		Prada prada = new Prada();
		if ( alice.DoYouLike( prada ) ) {
			Console.WriteLine("alice likes first prada.");
		} else {
			Console.WriteLine("alice don't like other prada.");
		}
		// 2つ目を作る
		prada = new Prada();
		if ( alice.DoYouLike( prada ) ) {
			Console.WriteLine("alice likes first prada.");
		} else {
			Console.WriteLine("alice don't like other prada.");
		}
	}
}
カテゴリー: C++ | アリスは初物がお好き はコメントを受け付けていません

アリスは中古のプラダがお嫌い(2)

アリスはプラダの中古がお嫌い | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/1442

前回、こんなところで中古のプラダを渡すと激怒して例外を発生させましたが、今回は大人しく false を返すことにします。

#include <iostream>

class Bag {
protected:
	bool used;
public:
	Bag() : used(false) {}
	virtual bool getUsed() { return used; }
	void Used() { Bag::used = true; }
};
class Prada : public Bag {};
class Tiffany : public Bag {};

// 中古が嫌いなアリス
class Alice
{
public:
	bool DoYouLike( Bag *bag ) 
	{
		if ( bag->getUsed() == true ) {
			return false;
		} else {
			return true;
		}
	}
	void Use( Bag *bag ) {
		bag->Used();
	}
};
// 悪友ロリータ
class Lolita 
{
public:
	bool DoYouLike( Bag *bag ) {
		return true;
	}
	void Use( Bag *bag ) {
		bag->Used();
	}
};

using namespace std;
int main(void)
{
	Alice alice;
	Lolita lolita;
	{
		Prada bag;
		if ( alice.DoYouLike( &bag ) ) {
			cout << "alice like New Prada." << endl;
		} else {
			cout << "alice don't like Used Prada." << endl;
		}
	}
	{
		Prada bag;
		lolita.Use( &bag );
		// アリスは他人が使ったものが嫌い
		if ( alice.DoYouLike( &bag ) ) {
			cout << "alice like New Prada." << endl;
		} else {
			cout << "alice don't like Used Prada." << endl;
		}
	}
	{
		Prada bag;
		alice.Use( &bag );
		// 自分が使っても嫌い???
		if ( alice.DoYouLike( &bag ) ) {
			cout << "alice like New Prada." << endl;
		} else {
			cout << "alice don't like Used Prada." << endl;
		}
	}
	return 0;
}

ただし、これを実行するとですとね、

D:\work\blog\src\alice>a
alice like New Prada.
alice don't like Used Prada.
alice don't like Used Prada.

な風に自分が使ったプラダの鞄も嫌いになってしまうのです。なので、

  • 自分が使った鞄は中古でも OK(中古というよりも自分のものだし)
  • 他人が使った鞄は嫌い

という判別を付けたいとすると。

class Alice
{
public:
	Alice() {}
	bool DoYouLike( Bag *bag ) 
	{
		if ( bag->getMark() == this || bag->getUsed() == false ) {
			return true;
		} else {
			return false;
		}
	}
	void Use( Bag *bag ) {
		bag->setMark( this );
		bag->Used();
	}
};

のように、Use メソッド中であらかじめ自分の使っていた鞄のポインタを保存しておいて、DoYouLike メソッドではそれと比較します。自分のだったら OK って具合ですね。

このあたりのパターンは、自 Factory クラスで作ったオブジェクトは利用できるけど、他 Factiory クラスで作ったオブジェクトは弾くってな感じで使えます。独自 malloc なんかを作るとき、単純に free したりするとアウトになってしまうので、自分のかどうかを判別するわけです。このフラグは、オブジェクト自身に置いてもよいし、Factory クラス自身に置いても OK。どちらも、ポインタ分だけを消費しますが、作成されたオブジェクトのほうに置くほうが、自他の判別は早くなるのかなぁと。

マーキングを利用したパターンが以下です。

class Bag {
protected:
	bool used;
	void *_mark;
public:
	Bag() : used(false), _mark(NULL) {}
	virtual bool getUsed() { return used; }
	void Used() { Bag::used = true; }
	// マーキング
	void setMark( void *mark ) { this->_mark = mark; }
	void *getMark() { return _mark; }
};
class Prada : public Bag {};
class Tiffany : public Bag {};

// 中古が嫌いなアリス
class Alice
{
public:
	Alice() {}
	bool DoYouLike( Bag *bag ) 
	{
		if ( bag->getMark() != this && bag->getUsed() == true ) {
			return false;
		} else {
			return true;
		}
	}
	void Use( Bag *bag ) {
		bag->setMark( this );
		bag->Used();
	}
};

この場合は、Bag クラスを修正しないといけないので、ちょっと変な気もしますが、鞄に名前を付けておくとか、自分だけ分かるシールを貼っておくとかができますよね。マーキング自体は void * になるので、”alice” という文字列でもよいし、ユニークな数値でも構いません(32,64bit以内であれば)。この手のマーキングは、C# だと GUID として使われているのだろうなぁ、と。

カテゴリー: C++ | アリスは中古のプラダがお嫌い(2) はコメントを受け付けていません

アリスはプラダがお好き

プラダの鞄を直接あげるのが値渡し | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/1431
プラダの鞄をおねだりするのが参照 | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/1434
アリスはプラダの中古がお嫌い | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/1442

プラダの鞄シリーズを再開w

ってな訳で、ちょっと C++ で組んでみました。
Bag クラスを基底クラスにして、Prada と Tiffany クラスを作ります。そして、ルイスが尋ねるのです。 Do you like this ?

なので、Alice クラスに DoYouLike メソッドを追加して Bag を渡すとどうなるでしょうか?

#include <iostream>

class Bag {
protected:
	bool used ;
public:
	virtual void setUsed() { used = true; }
};
class Prada : public Bag {};
class Tiffany : public Bag {};

#if 0
// おバカなアリス
class Alice
{
public:
	bool DoYouLike( void *bug ) 
	{
		return true;
	}
};
#else
// 賢いアリス
class Alice
{
public:
	bool DoYouLike( Bag *bag ) 
	{
		Prada *prada = dynamic_cast<Prada*>(bag);
		if ( prada == NULL ) {
			return false;
		} else {
			return true;
		}
	}
};
#endif

using namespace std;
int main(void)
{

	Alice alice;
	{
		Prada bag;;
		if ( alice.DoYouLike( &bag ) ) {
			cout << "alice like Prada." << endl;
		} else {
			cout << "alice don't like Prada." << endl;
		}
	}
	{
		Tiffany bag;;
		if ( alice.DoYouLike( &bag ) ) {
			cout << "alice like Tiffany." << endl;
		} else {
			cout << "alice don't like Tiffany." << endl;
		}
	}
	return 0;
}

おバカなアリスのほうは、Bag が貰えたらそれで嬉しいので、true を返します。メソッドを見ると分かりますが、何も考えていませんね。

賢いアリスのほうは、dynmaic_cast を使ってアップキャストをします。Prada も Tiffany も Bag クラスを継承しているので、DoYouLike メソッドには Bag* で渡すのですが、これが Prada なのか Tiffany なのかを Alice 自身が判断します。

D:\work\blog\src\alice>a
alice like Prada.
alice don't like Tiffany.

そうすると、こんな風に、Prada の鞄だけを好みます。
この判別の仕方、ちょっとなんだかなぁと思うのは、

  • 基底クラスに virtual なメソッドをひとつ必要とする。
  • dynamic_cast でキャストを実行するのじゃなくて、元の型を判別したいなぁ。

ってところですね。virtual メソッドは、dynamic_cast の制限のひとつで(でいいのかな?)、ひとつだけ仮想関数がないと駄目なんです。
キャストを実行せずに、元の型をというのは、多分 Java や C# のような型をランタイムで持っている言語じゃないと難しいと思います。そもそも C++ は型自身はメモリ上に持っていませんからね。単なる構造体と変わらないのです(v_tblとか)。

ちなみに C# で書くとこんな感じ。

using System;

public class Bag {}
public class Prada : Bag {}
public class Tiffany : Bag {}

public class Alice {
	public bool DoYouLike( Bag bag ) {
		if ( bag as Prada != null ) {
			return true;
		} else {
			return false;
		}
	}
}

public class Program {
	public static void Main(string []args ) {
		Alice alice = new Alice();
		
		Prada prada = new Prada();
		if ( alice.DoYouLike( prada ) ) {
			Console.WriteLine("alice likes prada.");
		} else {
			Console.WriteLine("alice don's likes prada.");
		}

		Tiffany tiffaniy = new Tiffany();
		if ( alice.DoYouLike( tiffaniy ) ) {
			Console.WriteLine("alice likes tiffaniy.");
		} else {
			Console.WriteLine("alice don's likes tiffaniy.");
		}
	}
}

やっぱり as 演算子でキャストして試してみるのが良さそうです。

カテゴリー: C++ | アリスはプラダがお好き はコメントを受け付けていません