MinGWでBoost 1.48.0を使う

ビルドが必要なboost::threadやboost::regexを使いたい時にはまったので私的メモ、
試したOSはWindows7

環境

gcc 4.6.1(MinGW)(※リンクはTopページ)
Boost 1.48.0

当然ながらMinGWのbinにはパスを通しておく。

手順

解凍したboostのパスにて、以下のコマンドでビルド用のbjam.exeを作る

bootstrap.bat gcc


生成されたbjam.exeを使い、ライブラリをビルドする

bjam.exe -sTOOLS=mingw --toolset=gcc --stagedir="boostのパス\stage\mingw" --without-python --without-mpi --build-type=complete variant=debug,release link=static threading=multi runtime-link=static release debug stage -j4

※ビルドするのは静的リンクのみ、理由は後述
※-jnでビルド時の並列処理数を記述、この辺はビルドを行うマシンのスペックと相談


次にboost::threadをincludeした時にwarningが出ないように、以下のパッチを施す、
参考にしたのはここ
ファイルのパスは boostへのパス\boost\thread\win32\thread_heap_alloc.hpp
行数は59行目辺り

//        inline BOOST_THREAD_DECL void* allocate_raw_heap_memory(unsigned size)
        inline void* allocate_raw_heap_memory(unsigned size)
    	{
            void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,size);
            if(!heap_memory)
            {
                boost::throw_exception(std::bad_alloc());
            }
            return heap_memory;
        }

//        inline BOOST_THREAD_DECL void free_raw_heap_memory(void* heap_memory)
        inline void free_raw_heap_memory(void* heap_memory)
        {
            BOOST_VERIFY(detail::win32::HeapFree(detail::win32::GetProcessHeap(),0,heap_memory)!=0);
        }

ここまでで準備完了。


次にboost::threadを使ったサンプルをBoostライブラリを静的リンクでビルドして実行してみる。
ソースは、以前書いたSleep Sortのソースを使おう。
sleepsort.cpp

#include <iostream>
#include <algorithm>
#include <vector>
#include <functional>

#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind/bind.hpp>


#define BOOST_SLEEP(n) boost::thread::sleep(boost::get_system_time() + boost::posix_time::milliseconds((n)))

std::vector<int> SleepSort(std::vector<int> v)
{
    boost::mutex m;
    std::vector<int> ret;

    std::function<void(int)> f = [&](int n) {
        BOOST_SLEEP(n * 100);

        {
            boost::mutex::scoped_lock lock(m);
            ret.push_back(n);
        }
    };


    boost::thread_group group;

    std::for_each(v.begin(), v.end(), [&](int n) {
        group.create_thread(boost::bind(f, n));
    });

    group.join_all();

    return ret;
}

int main()
{
    int a[] = {3, 1, 8, 7, 2, 4, 9, 6, 0, 5};
    int n = sizeof(a) / sizeof(a[0]);
    std::vector<int> v(a, a + n);

    v = SleepSort(std::move(v));

    std::for_each(v.begin(), v.end(), [](int n) {
        std::cout << n << " ";
    });

    return 0;
}


ビルドする時は以下のコマンド

g++ sleepsort.cpp -o sleepsort.exe -std=c++0x -DBOOST_THREAD_USE_LIB -Iboostのincludeパス -Lboostのlibパス -lboost_thread-mgwXX-mt-s-X_XX

MinGWではVisual Studioの時とは違い、-lオプションで明示的にライブラリを指定する必要がある(参考)
※静的リンクなので、 libファイル(MinGWでは.a)はmt-s-X_XXのようになっているのに注意
※静的リンクの時には、 -DBOOST_THREAD_USE_LIB オプションを付加する


これでsleepsort.exeを実行すれば実行結果が確認できる。

はまった事

Boostライブラリをビルドする際、動的リンク用も生成するように

bjam -sTOOLS=mingw --toolset=gcc --stagedir="boostのパス\stage\mingw" --without-python --without-mpi --build-type=complete variant=debug,release link=static,shared threading=multi runtime-link=static,shared release debug stage -j4

とすると、Boostライブラリの静的リンク用を使ってサンプルをビルドする際に
MinGWのld.exeがboost_thread-mgwXX-mt-s-X_XXが見つからないというエラーを出した。
なのでBoostライブラリを静的リンクで使う際には、Boostライブラリは静的リンク用だけビルドした方がいいかもしれない。

atwikiでjQuery pluginのtablesorterを使ってテーブルをソート対応してみた

対応させる為に必要なファイル

必要なファイルをダウンロードする

これらを作成したwikiから見えるパスへ準備しておく
(今回は同じwiki内へ用意)

概要

atwiki記法でテーブルを書くと、

|項目1|項目2|
|1|2|
|5|3|


table タグでテーブルが作られる

項目1 項目2
1 2
5 3

ソースはこのようになっている

<table>
	<tr><td>項目1</td><td>項目2</td></tr>
	<tr><td>1</td><td>2</td></tr>
	<tr><td>5</td><td>3</td></tr>
</table>


atwiki記法で作られたテーブルは簡易的なものなので、tablesorterに対応させる為、table タグにclass="tablesorter"を追加、thead タグ、 tbody タグを追加、column部分の tr タグ内の td を th へ修正する必要がある。

<table class="tablesorter">
  <thead>
	<tr><th>項目1</th><th>項目2</th></tr>
  </thead>
  <tbody>
	<tr><td>1</td><td>2</td></tr>
	<tr><td>5</td><td>3</td></tr>
  </tbody>
</table>

対応方法

JavaScriptを使い上記の修正を施す、
デモページのソース全文はこちら*1

jQuery plugin tablesorterのデモ

<!-- これが元になるテーブル、atwiki記法で書かれています -->
#divid(tablesorter-src){
|名前|戦闘力|Lv|
|クリ○ン|600|20|
|ゴク○|800|25|
|ピッ○ロさん|780|23|
|ヤム○ャ|380|33|
}


#divid(makeTableButton){
}

<!-- ここにソート対応したテーブルが作られます -->
#divid(tablesorter-dest){
}


// -------------------- ここからしたは弄る必要なし -----------------
#include_js(http://www18.atwiki.jp/worditest/pub/jquery.min.js)
#include_js(http://www18.atwiki.jp/worditest/pub/jquery.tablesorter.js)
#javascript(){
	// ボタン作成
	$("#makeTableButton").append("<input type='button' value='ソート対応のテーブルを作成' onclick='makeTable()' />");

	function makeTable() {

	  // 移動元と移動先のテーブル
	  var src = $("#tablesorter-src").children("table");
	  $("#tablesorter-dest").append("<table>");
	  var dest = $("#tablesorter-dest").children("table");

	  // 移動先テーブルの準備
	  dest.addClass("tablesorter");
	  dest.append("<thead id='tableHead'>");
	  dest.append("</thead>");
	  dest.append("<tbody id='tableBody'>");
	  dest.append("</tbody>");

	  // 移動元から移動先へ
	  srcHead = src.find(".atwiki_tr_1");
	  srcHead.html(srcHead.html().replace(/td/ig, "th"));
	  srcHead.appendTo("#tableHead");
	  src.find("tr").appendTo("#tableBody");

	  // 準備が出来たのでソート対応へ
	  dest.tablesorter({sortList:[[0,0]], widgets: ['zebra']});

	  // 移動後に必要ないものの後始末
	  $("#tablesorter-src").empty();
	  $("#makeTableButton").html("<input type='button' value='作成完了!' disabled />");
	}
}

不満点

セキュリティ上仕方ないかもしれないが、atwikiの編集モードを管理者のみにしていないとJavaScriptが有効にならない、誰でもページを編集出来て、且つセキュリティ維持する良い方法無いだろうか。

*1:JavaScriptを有効にする為には編集権限を管理者のみにする必要があるけど、そうするとソースが読めない為ここに書いておく

演算から見るC++0x rvalue referenceのパフォーマンスチェック(後編)

前編からの続き

コード

今回は4x4の行列クラスを乗算した時のそれぞれのパフォーマンスを検証します。


行列クラスのヘッダファイル
Matrix.h

#ifndef MATRIX_H__
#define MATRIX_H__

// C++0xで導入された rvalue reference を用いる場合はON
#define RVALUE_REFERENCE

class Matrix44
{
public:
	Matrix44();
	Matrix44(
	    float nm00, float nm01, float nm02, float nm03,
	    float nm10, float nm11, float nm12, float nm13,
	    float nm20, float nm21, float nm22, float nm23,
	    float nm30, float nm31, float nm32, float nm33
	);
	Matrix44(const Matrix44 &t);
	~Matrix44();

	Matrix44 &operator=(const Matrix44 &rhs);
	Matrix44 operator*(const Matrix44 &rhs) const;
	void Set(
	    float nm00, float nm01, float nm02, float nm03,
	    float nm10, float nm11, float nm12, float nm13,
	    float nm20, float nm21, float nm22, float nm23,
	    float nm30, float nm31, float nm32, float nm33
	);

#ifdef RVALUE_REFERENCE
	Matrix44(Matrix44 && t);
	Matrix44 &operator=(Matrix44 && rhs);
	// a  *  (b * c) の様に、右辺が一時オブジェクトの時に使う
	// ※今回のサンプルでは使っていない、資料用
	Matrix44 && operator*(Matrix44 && rhs) const;
	// (a * b)  *  c の様に、左辺が一時オブジェクトの時に使う
	friend Matrix44 && operator*(Matrix44 && lhs, const Matrix44 &rhs);
	// (a * b)  *  (c * d) の様に、両辺一時オブジェクトの時に使う
	// ※今回のサンプルでは使っていない、資料用
	friend Matrix44 && operator*(Matrix44 && lhs, Matrix44 && rhs);
#endif

	// コンストラクタが呼ばれた回数をカウントする
	static long constructorCount;

	friend void Matrix44Mul(Matrix44 &out, const Matrix44 &m1, const Matrix44 &m2);

private:
	union U
	{
		struct
		{
			float m00, m01, m02, m03;
			float m10, m11, m12, m13;
			float m20, m21, m22, m23;
			float m30, m31, m32, m33;
		};
		float m[16];
	};

	// ※std::swapで渡せるようにしておく
	U u;
};

#endif // MATRIX_H__



行列クラスのソースファイル
Matrix.cpp

#include "Matrix.h"

#include <iostream>

long Matrix44::constructorCount = 0;

// 処理を無効化するかどうか
// ※一時オブジェクトや関数のオーバーヘッド計測をする時に有効化します
//#define PROC_DISABLE

Matrix44::Matrix44()
{
#ifndef PROC_DISABLE
	constructorCount++;
	u.m00 = 1.f; u.m01 = 0.f; u.m02 = 0.f; u.m03 = 0.f;
	u.m10 = 0.f; u.m11 = 1.f; u.m12 = 0.f; u.m13 = 0.f;
	u.m20 = 0.f; u.m21 = 0.f; u.m22 = 1.f; u.m23 = 0.f;
	u.m30 = 0.f; u.m31 = 0.f; u.m32 = 0.f; u.m33 = 1.f;
#endif
	//std::cout << "Matrix44()" << std::endl;
}

Matrix44::Matrix44(
    float nm00, float nm01, float nm02, float nm03,
    float nm10, float nm11, float nm12, float nm13,
    float nm20, float nm21, float nm22, float nm23,
    float nm30, float nm31, float nm32, float nm33
)
{
#ifndef PROC_DISABLE
	constructorCount++;
	u.m00 = nm00; u.m01 = nm01; u.m02 = nm02; u.m03 = nm03;
	u.m10 = nm10; u.m11 = nm11; u.m12 = nm12; u.m13 = nm13;
	u.m20 = nm20; u.m21 = nm21; u.m22 = nm22; u.m23 = nm23;
	u.m30 = nm30; u.m31 = nm31; u.m32 = nm32; u.m33 = nm33;
#endif
	//std::cout << "Matrix44(float nm00-nm33)" << std::endl;
}

Matrix44::Matrix44(const Matrix44 &t)
{
#ifndef PROC_DISABLE
	constructorCount++;
	u.m[0] = t.u.m[0]; u.m[1] = t.u.m[1]; u.m[2] = t.u.m[2]; u.m[3] = t.u.m[3];
	u.m[4] = t.u.m[4]; u.m[5] = t.u.m[5]; u.m[6] = t.u.m[6]; u.m[7] = t.u.m[7];
	u.m[8] = t.u.m[8]; u.m[9] = t.u.m[9]; u.m[10] = t.u.m[10]; u.m[11] = t.u.m[11];
	u.m[12] = t.u.m[12]; u.m[13] = t.u.m[13]; u.m[14] = t.u.m[14]; u.m[15] = t.u.m[15];
#endif
	//std::cout << "Matrix44(const Matrix44 &t)" << std::endl;
}

Matrix44::~Matrix44() { }

Matrix44 &Matrix44::operator=(const Matrix44 &rhs)
{
#ifndef PROC_DISABLE
	u.m[0] = rhs.u.m[0]; u.m[1] = rhs.u.m[1]; u.m[2] = rhs.u.m[2]; u.m[3] = rhs.u.m[3];
	u.m[4] = rhs.u.m[4]; u.m[5] = rhs.u.m[5]; u.m[6] = rhs.u.m[6]; u.m[7] = rhs.u.m[7];
	u.m[8] = rhs.u.m[8]; u.m[9] = rhs.u.m[9]; u.m[10] = rhs.u.m[10]; u.m[11] = rhs.u.m[11];
	u.m[12] = rhs.u.m[12]; u.m[13] = rhs.u.m[13]; u.m[14] = rhs.u.m[14]; u.m[15] = rhs.u.m[15];
#endif
	//std::cout << "operator=(const Matrix44 &rhs)" << std::endl;
	return *this;
}

Matrix44 Matrix44::operator*(const Matrix44 &rhs) const
{
	//std::cout << "operator*(const Matrix44 &rhs)" << std::endl;
#ifdef PROC_DISABLE
	return Matrix44();
#else
	return Matrix44(
	           u.m00 * rhs.u.m00 + u.m01 * rhs.u.m10 + u.m02 * rhs.u.m20 + u.m03 * rhs.u.m30,
	           u.m00 * rhs.u.m01 + u.m01 * rhs.u.m11 + u.m02 * rhs.u.m21 + u.m03 * rhs.u.m31,
	           u.m00 * rhs.u.m02 + u.m01 * rhs.u.m12 + u.m02 * rhs.u.m22 + u.m03 * rhs.u.m32,
	           u.m00 * rhs.u.m03 + u.m01 * rhs.u.m13 + u.m02 * rhs.u.m23 + u.m03 * rhs.u.m33,

	           u.m10 * rhs.u.m00 + u.m11 * rhs.u.m10 + u.m12 * rhs.u.m20 + u.m13 * rhs.u.m30,
	           u.m10 * rhs.u.m01 + u.m11 * rhs.u.m11 + u.m12 * rhs.u.m21 + u.m13 * rhs.u.m31,
	           u.m10 * rhs.u.m02 + u.m11 * rhs.u.m12 + u.m12 * rhs.u.m22 + u.m13 * rhs.u.m32,
	           u.m10 * rhs.u.m03 + u.m11 * rhs.u.m13 + u.m12 * rhs.u.m23 + u.m13 * rhs.u.m33,

	           u.m20 * rhs.u.m00 + u.m21 * rhs.u.m10 + u.m22 * rhs.u.m20 + u.m23 * rhs.u.m30,
	           u.m20 * rhs.u.m01 + u.m21 * rhs.u.m11 + u.m22 * rhs.u.m21 + u.m23 * rhs.u.m31,
	           u.m20 * rhs.u.m02 + u.m21 * rhs.u.m12 + u.m22 * rhs.u.m22 + u.m23 * rhs.u.m32,
	           u.m20 * rhs.u.m03 + u.m21 * rhs.u.m13 + u.m22 * rhs.u.m23 + u.m23 * rhs.u.m33,

	           u.m30 * rhs.u.m00 + u.m31 * rhs.u.m10 + u.m32 * rhs.u.m20 + u.m33 * rhs.u.m30,
	           u.m30 * rhs.u.m01 + u.m31 * rhs.u.m11 + u.m32 * rhs.u.m21 + u.m33 * rhs.u.m31,
	           u.m30 * rhs.u.m02 + u.m31 * rhs.u.m12 + u.m32 * rhs.u.m22 + u.m33 * rhs.u.m32,
	           u.m30 * rhs.u.m03 + u.m31 * rhs.u.m13 + u.m32 * rhs.u.m23 + u.m33 * rhs.u.m33
	       );
#endif
}

void Matrix44::Set(
    float nm00, float nm01, float nm02, float nm03,
    float nm10, float nm11, float nm12, float nm13,
    float nm20, float nm21, float nm22, float nm23,
    float nm30, float nm31, float nm32, float nm33
)
{
#ifndef PROC_DISABLE
	u.m00 = nm00; u.m01 = nm01; u.m02 = nm02; u.m03 = nm03;
	u.m10 = nm10; u.m11 = nm11; u.m12 = nm12; u.m13 = nm13;
	u.m20 = nm20; u.m21 = nm21; u.m22 = nm22; u.m23 = nm23;
	u.m30 = nm30; u.m31 = nm31; u.m32 = nm32; u.m33 = nm33;
#endif
}

#ifdef RVALUE_REFERENCE
Matrix44::Matrix44(Matrix44 && t)
{
#ifndef PROC_DISABLE
	constructorCount++;
	//std::swap(u, t.u);
	// 正しくは↑swapだが、 ↓代入の方が若干早い
	u.m[0] = t.u.m[0]; u.m[1] = t.u.m[1]; u.m[2] = t.u.m[2]; u.m[3] = t.u.m[3];
	u.m[4] = t.u.m[4]; u.m[5] = t.u.m[5]; u.m[6] = t.u.m[6]; u.m[7] = t.u.m[7];
	u.m[8] = t.u.m[8]; u.m[9] = t.u.m[9]; u.m[10] = t.u.m[10]; u.m[11] = t.u.m[11];
	u.m[12] = t.u.m[12]; u.m[13] = t.u.m[13]; u.m[14] = t.u.m[14]; u.m[15] = t.u.m[15];
#endif
	//std::cout << "Matrix44(Matrix44 && t)" << std::endl;
}

Matrix44 &Matrix44::operator=(Matrix44 && rhs)
{
#ifndef PROC_DISABLE
	//std::swap(u, rhs.u);
	// 正しくは↑swapだが、 ↓代入の方が若干早い
	u.m[0] = rhs.u.m[0]; u.m[1] = rhs.u.m[1]; u.m[2] = rhs.u.m[2]; u.m[3] = rhs.u.m[3];
	u.m[4] = rhs.u.m[4]; u.m[5] = rhs.u.m[5]; u.m[6] = rhs.u.m[6]; u.m[7] = rhs.u.m[7];
	u.m[8] = rhs.u.m[8]; u.m[9] = rhs.u.m[9]; u.m[10] = rhs.u.m[10]; u.m[11] = rhs.u.m[11];
	u.m[12] = rhs.u.m[12]; u.m[13] = rhs.u.m[13]; u.m[14] = rhs.u.m[14]; u.m[15] = rhs.u.m[15];
#endif
	//std::cout << "operator=(Matrix44 && rhs)" << std::endl;
	return *this;
}

Matrix44 && Matrix44::operator*(Matrix44 && rhs) const
{
#ifndef PROC_DISABLE
	rhs.Set(
	           u.m00 * rhs.u.m00 + u.m01 * rhs.u.m10 + u.m02 * rhs.u.m20 + u.m03 * rhs.u.m30,
	           u.m00 * rhs.u.m01 + u.m01 * rhs.u.m11 + u.m02 * rhs.u.m21 + u.m03 * rhs.u.m31,
	           u.m00 * rhs.u.m02 + u.m01 * rhs.u.m12 + u.m02 * rhs.u.m22 + u.m03 * rhs.u.m32,
	           u.m00 * rhs.u.m03 + u.m01 * rhs.u.m13 + u.m02 * rhs.u.m23 + u.m03 * rhs.u.m33,

	           u.m10 * rhs.u.m00 + u.m11 * rhs.u.m10 + u.m12 * rhs.u.m20 + u.m13 * rhs.u.m30,
	           u.m10 * rhs.u.m01 + u.m11 * rhs.u.m11 + u.m12 * rhs.u.m21 + u.m13 * rhs.u.m31,
	           u.m10 * rhs.u.m02 + u.m11 * rhs.u.m12 + u.m12 * rhs.u.m22 + u.m13 * rhs.u.m32,
	           u.m10 * rhs.u.m03 + u.m11 * rhs.u.m13 + u.m12 * rhs.u.m23 + u.m13 * rhs.u.m33,

	           u.m20 * rhs.u.m00 + u.m21 * rhs.u.m10 + u.m22 * rhs.u.m20 + u.m23 * rhs.u.m30,
	           u.m20 * rhs.u.m01 + u.m21 * rhs.u.m11 + u.m22 * rhs.u.m21 + u.m23 * rhs.u.m31,
	           u.m20 * rhs.u.m02 + u.m21 * rhs.u.m12 + u.m22 * rhs.u.m22 + u.m23 * rhs.u.m32,
	           u.m20 * rhs.u.m03 + u.m21 * rhs.u.m13 + u.m22 * rhs.u.m23 + u.m23 * rhs.u.m33,

	           u.m30 * rhs.u.m00 + u.m31 * rhs.u.m10 + u.m32 * rhs.u.m20 + u.m33 * rhs.u.m30,
	           u.m30 * rhs.u.m01 + u.m31 * rhs.u.m11 + u.m32 * rhs.u.m21 + u.m33 * rhs.u.m31,
	           u.m30 * rhs.u.m02 + u.m31 * rhs.u.m12 + u.m32 * rhs.u.m22 + u.m33 * rhs.u.m32,
	           u.m30 * rhs.u.m03 + u.m31 * rhs.u.m13 + u.m32 * rhs.u.m23 + u.m33 * rhs.u.m33
	);
#endif
	//std::cout << "operator*(Matrix44 && rhs)" << std::endl;
	return std::move(rhs);
}

Matrix44 && operator*(Matrix44 && lhs, const Matrix44 &rhs)
{
#ifndef PROC_DISABLE
	lhs.Set(
	           lhs.u.m00 * rhs.u.m00 + lhs.u.m01 * rhs.u.m10 + lhs.u.m02 * rhs.u.m20 + lhs.u.m03 * rhs.u.m30,
	           lhs.u.m00 * rhs.u.m01 + lhs.u.m01 * rhs.u.m11 + lhs.u.m02 * rhs.u.m21 + lhs.u.m03 * rhs.u.m31,
	           lhs.u.m00 * rhs.u.m02 + lhs.u.m01 * rhs.u.m12 + lhs.u.m02 * rhs.u.m22 + lhs.u.m03 * rhs.u.m32,
	           lhs.u.m00 * rhs.u.m03 + lhs.u.m01 * rhs.u.m13 + lhs.u.m02 * rhs.u.m23 + lhs.u.m03 * rhs.u.m33,

	           lhs.u.m10 * rhs.u.m00 + lhs.u.m11 * rhs.u.m10 + lhs.u.m12 * rhs.u.m20 + lhs.u.m13 * rhs.u.m30,
	           lhs.u.m10 * rhs.u.m01 + lhs.u.m11 * rhs.u.m11 + lhs.u.m12 * rhs.u.m21 + lhs.u.m13 * rhs.u.m31,
	           lhs.u.m10 * rhs.u.m02 + lhs.u.m11 * rhs.u.m12 + lhs.u.m12 * rhs.u.m22 + lhs.u.m13 * rhs.u.m32,
	           lhs.u.m10 * rhs.u.m03 + lhs.u.m11 * rhs.u.m13 + lhs.u.m12 * rhs.u.m23 + lhs.u.m13 * rhs.u.m33,

	           lhs.u.m20 * rhs.u.m00 + lhs.u.m21 * rhs.u.m10 + lhs.u.m22 * rhs.u.m20 + lhs.u.m23 * rhs.u.m30,
	           lhs.u.m20 * rhs.u.m01 + lhs.u.m21 * rhs.u.m11 + lhs.u.m22 * rhs.u.m21 + lhs.u.m23 * rhs.u.m31,
	           lhs.u.m20 * rhs.u.m02 + lhs.u.m21 * rhs.u.m12 + lhs.u.m22 * rhs.u.m22 + lhs.u.m23 * rhs.u.m32,
	           lhs.u.m20 * rhs.u.m03 + lhs.u.m21 * rhs.u.m13 + lhs.u.m22 * rhs.u.m23 + lhs.u.m23 * rhs.u.m33,

	           lhs.u.m30 * rhs.u.m00 + lhs.u.m31 * rhs.u.m10 + lhs.u.m32 * rhs.u.m20 + lhs.u.m33 * rhs.u.m30,
	           lhs.u.m30 * rhs.u.m01 + lhs.u.m31 * rhs.u.m11 + lhs.u.m32 * rhs.u.m21 + lhs.u.m33 * rhs.u.m31,
	           lhs.u.m30 * rhs.u.m02 + lhs.u.m31 * rhs.u.m12 + lhs.u.m32 * rhs.u.m22 + lhs.u.m33 * rhs.u.m32,
	           lhs.u.m30 * rhs.u.m03 + lhs.u.m31 * rhs.u.m13 + lhs.u.m32 * rhs.u.m23 + lhs.u.m33 * rhs.u.m33
	);
#endif
//	std::cout << "operator*(Matrix44 && lhs, const Matrix44 &rhs)" << std::endl;
	return std::move(lhs);
}

Matrix44 && operator*(Matrix44 && lhs, Matrix44 && rhs)
{
//	std::cout << "operator*(Matrix44 && lhs, Matrix44 && rhs)" << std::endl;
	// 一つ↑の Matrix &&operator*(Matrix && lhs, const Matrix44 &rhs) を呼ぶ
	return std::move(lhs) * const_cast<const Matrix44 &>(static_cast<Matrix44 &>(rhs));
}

#endif // RVALUE_REFERENCE


void Matrix44Mul(Matrix44 &out, const Matrix44 &m1, const Matrix44 &m2)
{
#ifndef PROC_DISABLE
	float m[16];
	m[0] = m1.u.m[0] * m2.u.m[0] + m1.u.m[1] * m2.u.m[4] + m1.u.m[2] * m2.u.m[8] + m1.u.m[3] * m2.u.m[12];
	m[1] = m1.u.m[0] * m2.u.m[1] + m1.u.m[1] * m2.u.m[5] + m1.u.m[2] * m2.u.m[9] + m1.u.m[3] * m2.u.m[13];
	m[2] = m1.u.m[0] * m2.u.m[2] + m1.u.m[1] * m2.u.m[6] + m1.u.m[2] * m2.u.m[10] + m1.u.m[3] * m2.u.m[14];
	m[3] = m1.u.m[0] * m2.u.m[3] + m1.u.m[1] * m2.u.m[7] + m1.u.m[2] * m2.u.m[11] + m1.u.m[3] * m2.u.m[15];

	m[4] = m1.u.m[4] * m2.u.m[0] + m1.u.m[5] * m2.u.m[4] + m1.u.m[6] * m2.u.m[8] + m1.u.m[7] * m2.u.m[12];
	m[5] = m1.u.m[4] * m2.u.m[1] + m1.u.m[5] * m2.u.m[5] + m1.u.m[6] * m2.u.m[9] + m1.u.m[7] * m2.u.m[13];
	m[6] = m1.u.m[4] * m2.u.m[2] + m1.u.m[5] * m2.u.m[6] + m1.u.m[6] * m2.u.m[10] + m1.u.m[7] * m2.u.m[14];
	m[7] = m1.u.m[4] * m2.u.m[3] + m1.u.m[5] * m2.u.m[7] + m1.u.m[6] * m2.u.m[11] + m1.u.m[7] * m2.u.m[15];

	m[8] = m1.u.m[8] * m2.u.m[0] + m1.u.m[9] * m2.u.m[4] + m1.u.m[10] * m2.u.m[8] + m1.u.m[11] * m2.u.m[12];
	m[9] = m1.u.m[8] * m2.u.m[1] + m1.u.m[9] * m2.u.m[5] + m1.u.m[10] * m2.u.m[9] + m1.u.m[11] * m2.u.m[13];
	m[10] = m1.u.m[8] * m2.u.m[2] + m1.u.m[9] * m2.u.m[6] + m1.u.m[10] * m2.u.m[10] + m1.u.m[11] * m2.u.m[14];
	m[11] = m1.u.m[8] * m2.u.m[3] + m1.u.m[9] * m2.u.m[7] + m1.u.m[10] * m2.u.m[11] + m1.u.m[11] * m2.u.m[15];

	m[12] = m1.u.m[12] * m2.u.m[0] + m1.u.m[13] * m2.u.m[4] + m1.u.m[14] * m2.u.m[8] + m1.u.m[15] * m2.u.m[12];
	m[13] = m1.u.m[12] * m2.u.m[1] + m1.u.m[13] * m2.u.m[5] + m1.u.m[14] * m2.u.m[9] + m1.u.m[15] * m2.u.m[13];
	m[14] = m1.u.m[12] * m2.u.m[2] + m1.u.m[13] * m2.u.m[6] + m1.u.m[14] * m2.u.m[10] + m1.u.m[15] * m2.u.m[14];
	m[15] = m1.u.m[12] * m2.u.m[3] + m1.u.m[13] * m2.u.m[7] + m1.u.m[14] * m2.u.m[11] + m1.u.m[15] * m2.u.m[15];


	out.u.m[0] = m[0]; out.u.m[1] = m[1]; out.u.m[2] = m[2]; out.u.m[3] = m[3];
	out.u.m[4] = m[4]; out.u.m[5] = m[5]; out.u.m[6] = m[6]; out.u.m[7] = m[7];
	out.u.m[8] = m[8]; out.u.m[9] = m[9]; out.u.m[10] = m[10]; out.u.m[11] = m[11];
	out.u.m[12] = m[12]; out.u.m[13] = m[13]; out.u.m[14] = m[14]; out.u.m[15] = m[15];
#endif
}



main関数があるソースファイル
main.cpp

#include <iostream>

#include <boost/progress.hpp>

#include "Matrix.h"


// 乗算用の関数を用いる場合はON
//#define USE_MULTIPLE_METHOD

// ※↑の他に、Matrix.hに rvalue reference を使うかどうかの
//    プリプロセッサが定義されています。

int main()
{
	boost::progress_timer timer;

	Matrix44 t1, t2, t3, t4, t5, t6, t7, t8, t9;
	Matrix44 t;
	for (int i = 0; i < 1000000; i++)
	{
#ifndef USE_MULTIPLE_METHOD
		t = t1 * t2 * t3 * t4 * t5 * t6 * t7 * t8 * t9;
#else
		Matrix44Mul(t, t1, t2);
		Matrix44Mul(t, t, t3);
		Matrix44Mul(t, t, t4);
		Matrix44Mul(t, t, t5);
		Matrix44Mul(t, t, t6);
		Matrix44Mul(t, t, t7);
		Matrix44Mul(t, t, t8);
		Matrix44Mul(t, t, t9);
#endif
	}

	std::cout << "コンストラクタが呼ばれた回数:" << Matrix44::constructorCount << std::endl;

	return 0;
}


計測

※(7/1)gccに-O2を付けて計測したと勘違いしていた為結果が間違ってました、なので再度計測して書き直しています(太字が加筆です)。
下記が、演算子、関数、rvalue referenceを導入した演算子それぞれの実行時間です、コンパイラgcc 4.5.2(MinGW)、Visual C++ 2010(以下VC++2010)の二つで検証、gccは-O2オプションで最適化、VC++2010はReleaseモードとDebugモードそれぞれで計測しています。
gccは-O2オプション有りと無し、VC++2010はReleaseモードとDebugモードそれぞれで計測しています。
ちなみに、gccコンパイルオプションは下記の通りです。

gcc main.cpp Matrix.cpp -std=c++0x -lstdc++ [-O2] -Iboostのincludeパス -Lboostのlibパス



先ずは、プリプロセッサPROC_DISABLEを有効化した状態で一時オブジェクトの生成や関数のオーバーヘッド計測

演算の種類 コンストラクタが呼ばれた回数(オブジェクト生成数) 10回平均(gcc -O2有り) 10回平均(gcc -O2無し) 10回平均(VC++2010 Release) 10回平均(VC++2010 Debug)
演算子 8000010 0.038sec 0.070sec 0.018sec 0.680sec
関数を使う演算 10 0.012sec 0.016sec 0.006sec 0.199sec
rvalue referenceを導入した演算子 1000010 0.022sec 0.050sec 0.010sec 0.469sec

rvalue referenceを導入した演算子よりも関数の方がオーバーヘッドが小さいようですが、VC++2010のReleaseモードでは微々たる差になっています、それではプリプロセッサPROC_DISABLEを無効化し、行列の乗算時間を加えるとどうなるでしょうか。

演算の種類 コンストラクタが呼ばれた回数(オブジェクト生成数) 10回平均(gcc -O2有り) 10回平均(gcc -O2無し) 10回平均(VC++2010 Release) 10回平均(VC++2010 Debug)
演算子 8000010 0.337sec 0.572sec 0.229sec 1.352sec
関数を使う演算 10 0.306sec 0.492sec 0.256sec 0.758sec
rvalue referenceを導入した演算子 1000010 0.304sec 0.562sec 0.248sec 1.315sec

gccではオーバーヘッド計測の時こそ差があったものの、-O2で最適化すると従来通りに関数を使用した方法とrvalue referenceを導入した演算子が同じ速度となっています。
VC++2010のReleaseモードだとなぜか従来の演算子を使った方法が一番速くなるという結果になりました。
詳しくは不明ですが、おそらく定数を用いた最適化の為に余分なコードが省かれているのだと思います、
なので、試しにMatrix.cppとMatrix.hをReleaseモードでビルドしてMatrix.libを生成し、main.cppをDebugモードでコンパイルして、Matrix.libとリンクするという方法で検証してみると、

演算の種類 コンストラクタが呼ばれた回数(オブジェクト生成数) 10回平均(VC++2010 MatrixをRelease、MainをDebug)
演算子 8000010 0.310sec
関数を使う演算 10 0.282sec
rvalue referenceを導入した演算子 1000010 0.286sec

という結果になりました、おそらくこれが実際に使用した時の速度になるのかと思います。

まとめ

gcc 4.5.2(MinGW)では関数オーバーヘッドの方がまだまだ小さく、従来通りに関数を使用した方法が良いでしょうが、VC++2010ではrvalue referenceを導入すれば演算子を使って分かりやすく書け、実行速度も落ちないのではないかと思います。
gcc 4.5.2(MinGW)、VC++2010共にrvalue referenceを導入すれば演算子を使って分かりやすく書け、実行速度も落ちないのではないかと思います。

演算から見るC++0x rvalue referenceのパフォーマンスチェック(前編)

※私個人の検証の結果なので間違っている可能性があります、その時はコメントなりでご連絡ください。
後編はこちら

概要

C++03の時代までは、複数の演算を演算子を用いて書いた時は可読性が良いのですが、一次オブジェクトが何個も作られパフォーマンスが落ちる為、可読性は損なうが演算を関数で行ってなるべく一時オブジェクトが作られるのを防ぐ、というのが一般的でした。C++0xでrvalue referenceが登場した事により、可読性を維持しつつ一時オブジェクト生成によるパフォーマンスの低下を防ぐ事が出来るようになりました。

検証

C++03までの演算子、関数、C++0x以降のrvalue referenceを用いた演算子、それぞれの可読性と一時オブジェクトの数を見ていきます。


演算子の場合:可読性良し、パフォーマンス悪し

Matrix44 result;
// m1 * m2 -> 一時オブジェクトA、一時オブジェクトA * m3 -> 一時オブジェクトB、...と作られ、resultに代入される
// ※余分な一時オブジェクトは三つ
// ※演算する対象が増えると、さらに余分な一時オブジェクトが増える事でしょう
result = m1 * m2 * m3 * m4;

関数を使う演算の場合: 可読性悪し、パフォーマンス良し

Matrix44 result;
// ※一時オブジェクトは無し
Mul(&result, m1, m2);
Mul(&result, result, m3);
Mul(&result, result, m4);

rvalue referenceを導入した演算子の場合、可読性良し、パフォーマンス良し

Matrix44 result;
// m1 * m2 -> 一時オブジェクトA、一時オブジェクトA * m3 -> 一時オブジェクトA、...と使いまわされ、resultに代入される
// ※余分な一時オブジェクトは一つ
result = m1 * m2 * m3 * m4;



ここで、演算方法を少し変更した別の例を見てみます。


演算子の場合

Matrix44 result;
// m1 * m2 -> 一時オブジェクトA、m3 * m4 -> 一時オブジェクトB、一次オブジェクトA * 一時オブジェクトB -> 一時オブジェクトC、と作られ、resultに代入される
// ※余分な一時オブジェクトは三つ
result = (m1 * m2)  *  (m3 * m4);

関数を使う演算の場合

Matrix44 result;
Mul(&result, m1, m2);
// ※一時オブジェクトは一つ
Matrix44 temp;
Mul(&temp, m3, m4);
Mul(&result, result, temp);

rvalue referenceを導入した演算子の場合

Matrix44 result;
// m1 * m2 -> 一時オブジェクトA、m3 * m4 -> 一時オブジェクトB、一次オブジェクトA * 一時オブジェクトB -> 一時オブジェクト(A、Bどちらか流用)、と使いまわされ、resultに代入される
// ※余分な一時オブジェクトは二つ
result = (m1 * m2)  *  (m3 * m4)

やはり演算子の方が見易いです、しかしそれぞれのパフォーマンスはどうだろうか、実際のコードで実行速度を測っていきたいかと思います、って事で後編

C++版のSleep sort

元ネタはここ→http://dis.4chan.org/read/prog/1295544154
ちなみにここで知った→常識を覆すソートアルゴリズム!その名も"sleep sort"! - Islands in the byte stream
考えた人天才だろ。
※5/21密かに修正(scoped_lock使おうね!)

#include <iostream>

#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind/bind.hpp>


#define BOOST_SLEEP(n) boost::thread::sleep(boost::get_system_time() + boost::posix_time::milliseconds((n)))

boost::mutex m;

void func(int n)
{
    BOOST_SLEEP(n * 100);

    {
        boost::mutex::scoped_lock lock(m);
        std::cout << n << " ";
    }
    // m.lock();
    // std::cout << n << " ";
    // m.unlock();
}

int main()
{
    int a[] = {3, 1, 8, 7, 2, 4, 9, 6, 0, 5};
    int n = sizeof(a) / sizeof(a[0]);

    boost::thread_group group;

    for (int i = 0; i < n; ++i)
        group.create_thread(boost::bind(func, a[i]));

    group.join_all();

    return 0;
}

実行結果*1

0 1 2 3 4 5 6 7 8 9 



ついでにC++0xでソート部分を関数にしてみた

#include <iostream>
#include <algorithm>
#include <vector>
#include <functional>

#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind/bind.hpp>


#define BOOST_SLEEP(n) boost::thread::sleep(boost::get_system_time() + boost::posix_time::milliseconds((n)))

std::vector<int> SleepSort(std::vector<int> v)
{
    boost::mutex m;
    std::vector<int> ret;

    std::function<void(int)> f = [&](int n) {
        BOOST_SLEEP(n * 100);

        {
            boost::mutex::scoped_lock lock(m);
            ret.push_back(n);
        }
        // m.lock();
        // ret.push_back(n);
        // m.unlock();
    };


    boost::thread_group group;

    std::for_each(v.begin(), v.end(), [&](int n) {
        group.create_thread(boost::bind(f, n));
    });

    group.join_all();

    return ret;
}

int main()
{
    int a[] = {3, 1, 8, 7, 2, 4, 9, 6, 0, 5};
    int n = sizeof(a) / sizeof(a[0]);
    std::vector<int> v(a, a + n);

    v = SleepSort(std::move(v));

    std::for_each(v.begin(), v.end(), [](int n) {
        std::cout << n << " ";
    });

    return 0;
}

実行結果*2

0 1 2 3 4 5 6 7 8 9 

*1:表示された時笑った

*2:当然同じ

世間じゃBluetoothやら無線LANやら賑わってるけどさ

PCから伸びてるiPhone4同期用USBやらKindle 3接続用USBやら、
外付けHDD用のeSATAとその電源用USBやら冷却用USBFANのUSBやら、
自炊用スキャナDR-150の接続用USBと電源用USBやら、
任天堂DSの充電用USBやらPSP充電用USBがワイヤレスになる日は何時になるんだろうか。


整理しろですかそうですか。