2008年7月21日月曜日

TextureCoordinates

WPFを使って3Dを扱っていたのだが、TextureCoordinatesという概念がよくわからなかった。MSDNの記述もいい加減で

テクスチャ座標に関する追加の情報は、後続のトピックまたは Managed Direct3D SDK を参照してください。
と逃げているし…Managed Direct3Dってもう終わったんじゃ?
ググっていたらDaniel Lehenbauer's Blog : 3D for the Rest of Us: Texture Coordinatesを見つけた。これはわかりやすいかも?

…何の情報もない投稿だなぁ

2008年5月30日金曜日

FizzBuzz Questions

思いつきでFizzBuzz Questionsをやってみる。お題はこちら:

Write a program that prints the numbers from 1 to 100. But for multiples of three print "Fizz" instead of the number and for the multiples of five print "Buzz". For numbers which are multiples of both three and five print "FizzBuzz".


普通に解くと
#include <iostream>
using namespace std;

void FizzBuzz( int n ){
if( n % 15 )
if( n % 5 )
if( n % 3 )
cout << n;
else
cout << "Fizz";
else
cout << "Buzz";
else
cout << "FizzBuzz";
cout << endl;
}

int main(){
for( int i = 1; i < 101; i++ )
FizzBuzz( i );
}
こんな感じ?

当たり前ですが実行時に分岐しています。でもTMP(Template MetaProgramming)を使えばコンパイル時に分岐できます。
#include <iostream>
using namespace std;

template<int n, int mod3 = n % 3, int mod5 = n % 5>
struct FizzBuzz{
static ostream& print(){
return FizzBuzz<n-1>::print() << n << endl;
}
};

template<int n, int mod5>
struct FizzBuzz<n, 0, mod5>{
static ostream& print(){
return FizzBuzz<n-1>::print() << "Fizz" << endl;
}
};

template<int n, int mod3>
struct FizzBuzz<n, mod3, 0>{
static ostream& print(){
return FizzBuzz<n-1>::print() << "Buzz" < endl;
}
};

template<int n>
struct FizzBuzz<n, 0, 0>{
static ostream& print(){
return FizzBuzz<n-1>::print() << "FizzBuzz" << endl;
}
};

template<> ostream& FizzBuzz<0>::print(){
return cout;
}

int main(){
FizzBuzz<100>::print();
}
本当はループ展開とかもTMPでできるかも…でもやり方がよくわかりませんでした。

しかし更にすごい方法が…
#include <iostream>
#include <boost/preprocessor/arithmetic/mod.hpp>
#include <boost/preprocessor/control/if.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
using namespace std;

#define FizzBuzz( z, n, data ) \
BOOST_PP_IF( BOOST_PP_MOD( n, 15 ), \
BOOST_PP_IF( BOOST_PP_MOD( n, 5 ), \
BOOST_PP_IF( BOOST_PP_MOD( n, 3 ), \
#n, \
"Fizz" ), \
"Buzz" ), \
"FizzBuzz" ) \
"\n"

int main(){
cout << BOOST_PP_REPEAT_FROM_TO( 1, 101, FizzBuzz, );
}
コンパイル前にすべての処理を終わらせてしまい、preprocessorだけで単一の文字列を作り上げてしまうことも。いやはや。

2008年5月16日金曜日

SslStream

Boost.Asioを書いたけど、.NET Frameworkにも同様にSslStreamクラスが用意されている。
使い方もほぼ同じで

var c = new TcpClient( "ホスト名", 443 );
var s = new SslStream( c.GetStream() );

s.AuthenticateAsClient( "ホスト名" );

s.Write( Encoding.Default.GetBytes( "GET / HTTP/1.0\r\n\r\n" ) );

var r = new StreamReader( s, Encoding.Default );
Console.WriteLine( r.ReadToEnd() );
こんな感じ。違いは
  • Windows環境ではgetservbyname()が信用できないので直接443と書いている点
  • .NET FrameworkはByteとCharを区別しているので明示的な変換が必要になる点
  • Byte→Char変換を中断するのは面倒くさいのでReadToEnd()ですべて読み込んでしまっている点
でしょうか。

Boost.Asio

BoostというC++ライブラリが気になっていたのですが、1.35がリリースされ、Boost.Asioという非同期I/Oライブラリが追加されていることを知りました。このライブラリはWindows、Linux、各種Unix上で動作し、各種コンパイラをサポートしています。さらによく見たらOpenSSLによるSSLまでサポートしていました。

まずは試しに同期I/Oでhttps clientを書いてみました。

io_service i;
ssl::context c( i, ssl::context::sslv3_client );
ssl::stream s( i, c );
s.lowest_layer().connect( *ip::tcp::resolver(i)
.resolve( ip::tcp::resolver::query( "ホスト名", "https" ) ) );

s.handshake( ssl::stream_base::client );

write( s, buffer( "GET / HTTP/1.0\r\n\r\n" ) );

asio::streambuf res;
error_code e;
while( read( s, res, transfer_at_least(1), e ) )
cout << &res;
うーん、これだけで動いちゃいました。

2008年4月26日土曜日

Windows XP SP3

Windows XP SP3が公開されたようです。Release To Manufacturing(RTM)後、1週間ほどでRelease To Web(RTW)されるそうです。
SP2と互換は高いという噂なので特に言及することもなさそうでしたが…1点、すでにWindows Vistaがリリースされていることもあり、Windows XP with SP3は作られないとかなんとか。というわけで後からSP3を追加する形のみになるようです。…ちなみにSP3のインストール条件にSP1が入っていました。つまり素のXPには一旦SP1aかSP2を入れた後にSP3を入れることになるようです。

2008年3月29日土曜日

インサイドWindows第4版下

インサイドWindows第4版上に続いてようやくインサイドWindows第4版下を買えました。近くの本屋さんにはいつ見ても上しか置いてなくて…でも注文するのは負けた気がするし。
読んでいて一つ参考になった話題を。大容量のメモリを搭載しているWindows XPでもタスクマネージャのシステムキャッシュを見ると512MBで抑えられている場合があります。このPCは68MBとしょぼしょぼですが(;;
こういう場合、パフォーマンス オプションで「システム キャッシュ」を選択すると512MB以上のメモリをシステムキャッシュに割り当てられるようになります。メモリが余ってる人はどうぞ。
64bit版やWindows Vistaはこのリミッターが最初から解除されています。

HTTP Server API

以前からWindows OSにはIISが含まれていたけど、Windows XP SP2、Windows Server 2003以降にはOS側にWebサーバ機能が組み込まれていて、IISもこれを使う設計らしい。
試しにこのHTTP Server APIを使ってみた。

HTTPAPI_VERSION version = HTTPAPI_VERSION_1;
HttpInitialize( version, HTTP_INITIALIZE_SERVER, NULL );

HANDLE handle;
HttpCreateHttpHandle( &handle, NULL );

HttpAddUrl( handle, L"http://+:80/", NULL );

while( !stop ){
HTTP_REQUEST_ID requestId;
HTTP_SET_NULL_ID( &requestId );
char buffer[ 4096 ] = {};
PHTTP_REQUEST request = reinterpret_cast<PHTTP_REQUEST>( buffer );
ULONG size;
HttpReceiveHttpRequest( handle, requestId, 0, request, sizeof buffer, &size, NULL );

HTTP_RESPONSE response;
memset( &response, 0, sizeof response ); // デフォルトコンストラクタ用意してください(;;)
HTTP_DATA_CHUNK chunk;
HANDLE file = INVALID_HANDLE_VALUE;
if( request->Verb != HttpVerbGET )
response.StatusCode = 503;
else{
// URLパスの先頭の'/'をスキップ
file = CreateFileW( &request->CookedUrl.pAbsPath[1], FILE_READ_DATA, 0, NULL, OPEN_EXISTING, 0, NULL );
if( file == INVALID_HANDLE_VALUE )
response.StatusCode = 404;
else{
chunk.DataChunkType = HttpDataChunkFromFileHandle;
chunk.FromFileHandle.ByteRange.StartingOffset.QuadPart = 0;
chunk.FromFileHandle.ByteRange.Length.QuadPart = HTTP_BYTE_RANGE_TO_EOF;
chunk.FromFileHandle.FileHandle = file;
response.StatusCode = 200;
response.EntityChunkCount = 1;
response.pEntityChunks = &chunk;
}
}
HttpSendHttpResponse( handle, request->RequestId, 0, &response, NULL, &size, NULL, 0, NULL, NULL );
if( file != INVALID_HANDLE_VALUE )
CloseHandle( file );
}
HttpRemoveUrl( handle, L"http://+:80/" );
CloseHandle( handle );
HttpTerminate( HTTP_INITIALIZE_SERVER, NULL );
サンプルなのでエラー処理は省いてます。機能的には、カレントディレクトリのファイルを返します。
stop = trueとしてもすぐには終了しません。HttpReceiveHttpRequest()でブロックされているので、次のリクエストを処理したところでループを抜けます。