2009年4月6日月曜日

devenv.exe ひでぇな


volatile bool bexit = false;

while(1) {
devenv.exe が終了しない!どうしますか?

C:\> taskkill /F /T /IM devenv.exe
成功: PID xxxx のプロセス(PID xxxx の子プロセス)は強制終了されました。
成功: PID xxxx のプロセス(PID xxxx の子プロセス)は強制終了されました。
成功: PID xxxx のプロセス(PID xxxx の子プロセス)は強制終了されました。

devenv.exe が現れた!どうしますか?

C:\> taskkill /F /T /IM devenv.exe
成功: PID xxxx のプロセス(PID xxxx の子プロセス)は強制終了されました。
成功: PID xxxx のプロセス(PID xxxx の子プロセス)は強制終了されました。
成功: PID xxxx のプロセス(PID xxxx の子プロセス)は強制終了されました。

if( bexit ) {
// 制御不能です。電源を長押しして、強制オフしてください。
// 死んでいいぞ
}

}


追記:犯人は、intellisense くさい
追記:こんな情報をみつけた。今日も devenv.exe が現れた!電源切るしかねーよもう。この情報にすがってみるよ…。
追記:

2009年4月5日日曜日

boost::asio で pop3

 とりあえず、boost 1.38.0 と cmake で焼きなおしてアップしました。

2009年4月4日土曜日

プログラマーのピーク

 今度は、プログラマー35歳説について述べよというお題が出た気がするので、書いてみます。私の現在の年齢が42.6歳です。本当に限界は35歳か?
 振り返ってみると、ピークは36歳ぐらいだろうと感じます。この年齢から徐々に瞬発力と、全体の詳細までを記憶する力が無くなります。ここからは、もう財産の食いつぶし。しかし限界が36歳というのは都市伝説でしょう。知っているプログラマで、60歳近くになるのにバリバリ書いてる方もいます。レベルも1級品です。
 それよりも私は、新たな定説を提唱したい。プログラマ28歳限界説。これはプログラマに限った事ではありませんが、28歳にもなって努力を怠り何もしない人間は、それが習慣化し、周囲から助言を得ても、今までに是正する事が無かったので変わりようがありません。あとは硬直化して伸びる事がありません。よって、能力を得る見込みの無い人は、この年齢でお払い箱。
 話を自分の状態に戻して、ではどうか?瞬発力が無くなったので、以前の自分に比べればコーディング・スピードは倍近く時間がかかるようになったかもしれません。しかし、構想力は今の方が上がっていると感じます。若い人にコーディングを任せた方が良い場合も想定できるし、そうでない場合もあります。
 能力に関するものでは、「<勝負脳>の鍛え方」という本が科学的で、面白いです。プログラマ36歳限界説は2割真実で、8割嘘、気にする事は無いけど工夫は必要のような気がしてます。どんな工夫が必要なのかは、もう少し先の年齢でないと書けそうもありません。

2009年4月3日金曜日

来年あたりは決断の年かな

 自分は、どうしようもない根っからのプログラマだ。それが今、ネットワーク(システム)管理者を兼任して、個人情報管理責任者をして、マネジメントを任されて(会社を辞めても失業手当が出ない経営者の一角だ)、実システムのコーディングにタッチして(ひどい時には、3現場掛け持ち)、選択肢の広い技術に触れて取捨選択をしながら、明日のコンセプトを創出し、社員教育も考えなければならないが実質的にそんな余裕がない。
 ネットワーク管理者の地位は、信じられないぐらい低い、何かトラブった時には、徹夜も辞さない覚悟が必要で、ちょっとした無知のせいで他所(インターネット上の他のところ)へ多大な迷惑をかける。お前のところのルータの設定 DHCP が外に対して有効になって、不正経路に使われてるぞというお叱りのメールを英語で受けた事や、SMTPリレーの穴が開いていてスパムに悪用されたりして、対処に追われたり、他人に任せたら不正侵入されてプロバイダに謝ったりと、ネットワーク管理者なら、こんな経験のひとつやふたつはあるだろう。軌道に乗っている時は、あまりやる事は無いかもしれないが、そう簡単に切り出せる類のものでもない。兼任では本業が疎かになって当たり前なのだ。
 マネジメントは方針や判断を行って人に命令する仕事である。そのマネジメントすべき人間が、3つの現場のコーディングを掛け持ちして、納期が間に合わなくてピリピリと神経を尖らせている状況の時もある(こんな時は、ネットワークトラブルや何かの相談が無い事を祈っている余裕すらない)。
 そして、この不景気だ。受託開発は、よほどの隙間でなければ、この先もうやっていけないだろうと思う。SaaS へシフトしていかないと生き残れないと思っている。中途半端な過去の資産が無い方が今は有利だ。当然そのための構想をいろいろ考えて試行錯誤する。傍から見ていると遊んでいるように見えるだろう。ここは自分の真骨頂で苦にはならない。しかし、近年は何でも高度化していて、並大抵の努力とリソースではおぼつかない。問題は会社の体力だ。どこも似たようなものだと思うが、新しい試みで失敗できるゆとりが無い。あれこれ考えても本気でアクセルを踏める状況にはならない。そうこうしているうちに、何をしても無駄感が募るばかりである。
 なによりも自分の心のベクトルと実ベクトルとの方向が大きくずれつつある。誰のための人生か?来年あたりは、どうするか決断すべきだろう。

2009年4月1日水曜日

それでも windows vista は眠らない

 まあ、windows vista は嫌いだ。とにかく終了しない。昨日はシャットダウンしようと思ってもログオフ中のままなので、放置プレーで帰ったら、翌朝もログオフ中であった。またかよ…。
おかげで、こんなコマンドを覚えてしまったではないか

C:\> chkdsk /f
C:\> shutdown /r /t 0

いい加減にしてほしい。で、犯人の目星はついている。devenv.exe だ。こいつが残ると、タスクマネージャで殺しにいっても死なない。ひどいと1日に2回チェックディスクをかけている。
あまりに酷いので、babysitter というシャットダウン時に devenv.exe のプロセスが残っていたら殺すサービスを作成しようかと、まじめに考えている。
 windows 3.51 あたりが一番好きかも? GDI がカーネルに侵食してからは、どうも好きになれん。

文字コード変換

 やっぱ、お手軽に使える感じの文字コード変換が欲しい…。というわけで作りました。
wconv.hpp
#ifndef WCONV_HPP
#define WCONV_HPP

#include <string>

std::wstring string_to_unicode( const std::string& src, unsigned code_page );
std::string unicode_to_string( const std::wstring& src, unsigned code_page );

template <int CODEPAGE>
std::wstring string_to_unicode( const std::string& src ) {
  return string_to_unicode( src, CODEPAGE );
}

template <int CODEPAGE>
std::string unicode_to_string( const std::wstring& src ) {
  return unicode_to_string( src, CODEPAGE );
}

template <int DST_CODE_PAGE, int SRC_CODE_PAGE>
std::string code_to_code( const std::string& src ) {
  return unicode_to_string<DST_CODE_PAGE>( string_to_unicode<SRC_CODE_PAGE>( src ) );
}

#endif // WCONV_HPP


codepage.hpp
#ifndef CODE_PAGE_HPP
#define CODE_PAGE_HPP

/// form winnls.h
//@{
#define CP_ACP               0  // Current Code Page
#define CP_UTF7          65000  // UTF7
#define CP_UTF8          65001  // UTF8
//@}

#define CP_OEM_US          437
#define CP_OEM_ALABIC      720
#define CP_OEM_GREEK       737
#define CP_OEM_BALTIC      775
#define CP_OEM_MLATIN1     850
#define CP_OEM_LATIN2      852
#define CP_OEM_CYRILLIC    855
#define CP_OEM_TURKISH     857
#define CP_OEM_MLATIN1P    858
#define CP_OEM_HEBREW      862
#define CP_OEM_RUSSIAN     866

#define CP_THAI            874
#define CP_SJIS            932
#define CP_GBK             936
#define CP_KOREA           949
#define CP_BIG5            950

#define CP_EUROPE         1250
#define CP_CYRILLIC       1251
#define CP_LATIN1         1252
#define CP_GREEK          1253
#define CP_TURKISH        1254
#define CP_HEBREW         1255
#define CP_ARABIC         1256
#define CP_BALTIC         1257
#define CP_VIETNAM        1258

#define CP_ISO_LATIN1    28591
#define CP_ISO_LATIN2    28592
#define CP_ISO_LATIN3    28593
#define CP_ISO_BALTIC    28594
#define CP_ISO_CYRILLIC  28595
#define CP_ISO_ARABIC    28596
#define CP_ISO_HEBREW    28598
#define CP_ISO_TURKISH   28599
#define CP_ISO_LATIN9    28605

#endif // CODE_PAGE_HPP


wconv.cpp
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winnls.h>
#include <string>
#include <boost/scoped_array.hpp>

#include "wconv.hpp"

std::wstring string_to_unicode( const std::string& src, unsigned code_page ) {
  int result_length = MultiByteToWideChar( code_page, 0, src.c_str(), -1, 0, 0 );
  if( result_length > 255 ) {
    boost::scoped_array<wchar_t> tbuff( new wchar_t[ result_length + 2 ] );
    MultiByteToWideChar( code_page, 0, src.c_str(), -1, tbuff.get(), result_length );
    std::wstring result = tbuff.get();
    return result;
  } else {
    wchar_t tbuff[ 256 ];
    MultiByteToWideChar( code_page, 0, src.c_str(), -1, tbuff, result_length );
    std::wstring result = tbuff;
    return result;
  }
}

std::string unicode_to_string( const std::wstring& src, unsigned code_page ) {
  int result_length = WideCharToMultiByte( code_page, 0, src.c_str(), -1, 0, 0, 0, 0 );
  if( result_length > 511 ) {
    boost::scoped_array<char> tbuff( new char[ result_length + 2 ] );
    WideCharToMultiByte( code_page, 0, src.c_str(), -1, tbuff.get(), result_length, 0, 0 );
    std::string result = tbuff.get();
    return result;
  } else {
    char tbuff[ 512 ];
    WideCharToMultiByte( code_page, 0, src.c_str(), -1, tbuff, result_length, 0, 0 );
    std::string result = tbuff;
    return result;
  }
}

//#define WCONV_TEST_APP
#ifdef WCONV_TEST_APP

#include "codepage.hpp"
#include <fstream>
#include <iostream>

//#define YOURPAGE  CP_SJIS
#define YOURPAGE  CP_ACP

int main(int argc, char* argv[]) {
  if( argc < 3 )  return 1;
  std::ifstream ifs( argv[1] );
  std::ofstream ofs( argv[2] );
  //std::wcout.imbue( std::locale("") );
  std::string str;
  while( std::getline( ifs, str ) ) {
    std::string dst = code_to_code<CP_UTF8,YOURPAGE>( str );
    ofs << dst << std::endl;
    //ofs << code_to_code<YOURPAGE,CP_UTF8>( str ) << std::endl;
  }
  return 0;
}

#endif
2018/08/29 追記 std::basic_string のバッファを直接使っていたが、それだと null terminated まで組み込まれてしまうため、修正を行った。

boost::gil で bicubic

 昨日、gil で挑戦してみてはいかが?と書いたが、必要になって挑戦するはめになった。
libs/gil/example/resize.cpp というのを見つけて、これはもしや?と思ったが、boost/gil/extension/numeric/* が、ごっそりと抜け落ちていてコンパイルできない…。どこにあるんだべーと探したら、GIL本家のダウンロードページにあった(現在、ここからサルベージするしかない)。

さっそく bicubic が落ちていないか探したが、bilinear までしか実装されていないようだ。チャレンジしようと思ったが、gil をよく知らないので苦労した。チュートリアルの日本語訳があって、非常に助かりました。
という訳で、csampler.hpp です。
/*************************************************************************************************/

#ifndef GIL_CSAMPLER_HPP
#define GIL_CSAMPLER_HPP

#include "../../extension/dynamic_image/dynamic_image_all.hpp"
#include "pixel_numeric_operations.hpp"
#include "sampler.hpp"

namespace boost { namespace gil {

struct truncate_channel_fn {
    template <typename SrcChannel, typename DstChannel>
    void operator()(const SrcChannel& src, DstChannel& dst) {
        typedef typename channel_traits<DstChannel>::value_type dst_value_t;
        if(std::numeric_limits<dst_value_t>::max() <= src)
          dst = std::numeric_limits<dst_value_t>::max();
        else if( src < 0 )  dst = dst_value_t();
        else  dst = dst_value_t(src);
    }
};

template <typename SrcPixel, typename DstPixel>
void truncate_pixel(const SrcPixel& src, DstPixel& dst) {
    static_for_each(src,dst,truncate_channel_fn());
}


/// \brief A sampler that sets the destination pixel as the bicubic interpolation of the four closest pixels from the source. 
/// If outside the bounds, it doesn't change the destination
/// \ingroup ImageAlgorithms
struct bicubic_sampler {};

template <typename DstP, typename SrcView, typename F>
bool sample(bicubic_sampler, const SrcView& src, const point2<F>& p, DstP& result) {
    typedef typename SrcView::value_type SrcP;
    point2<int> p0(ifloor(p)); // the closest integer coordinate top left from p
    if (p0.x < 0 || p0.y < 0 || p0.x>=src.width() || p0.y>=src.height()) return false;

    pixel<F,devicen_layout_t<num_channels<SrcView>::value> > mp(0);                     // suboptimal
    typename SrcView::xy_locator loc=src.xy_at(p0.x,p0.y);

    for( int y = -1; y < 3; ++y ) {
      for( int x = -1; x < 3; ++x ) {
        point2<F> frac(std::abs(p.x-static_cast<F>(p0.x+x)),std::abs(p.y-static_cast<F>(p0.y+y)));
        F wx, wy;
        if( frac.x < static_cast<F>(1) )    wx = (frac.x - 1) * (frac.x * frac.x - frac.x - 1);
        else                                wx = (1 - frac.x) * (frac.x - 2) * (frac.x - 2);
        if( frac.y < static_cast<F>(1) )    wy = (frac.y - 1) * (frac.y * frac.y - frac.y - 1);
        else                                wy = (1 - frac.y) * (frac.y - 2) * (frac.y - 2);
        int offx = ( p0.x+x < 0 || p0.x+x>=src.width() ) ? 0 : x;
        int offy = ( p0.y+y < 0 || p0.y+y>=src.height() ) ? 0 : y;
        detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()( loc(offx,offy), wx * wy, mp );
      }
    }

    // Convert from floating point average value to the source type
    SrcP src_result;
    truncate_pixel(mp,src_result);

    color_convert(src_result, result);
    return true;
}

} }  // namespace boost::gil

#endif

お試しコードは、resize.cpp をちょいと改造するだけ。せっかくの bicubic なので拡大してみました。
#include <boost/gil/image.hpp>
#include <boost/gil/typedefs.hpp>
#include <boost/gil/extension/io/jpeg_io.hpp>
#include <boost/gil/extension/numeric/sampler.hpp>
#include <boost/gil/extension/numeric/csampler.hpp>
#include <boost/gil/extension/numeric/resample.hpp>

int main() {
    using namespace boost::gil;

    rgb8_image_t img;
    jpeg_read_image("test.jpg",img);

    // test resize_view
    // Scale the image to 100x100 pixels using bilinear resampling
    rgb8_image_t square100x100(600,600);
    resize_view(const_view(img), view(square100x100), bicubic_sampler());
    jpeg_write_view("out-resize.jpg",const_view(square100x100));

    return 0;
}