Hatena::ブログ(Diary)

ottuの月記

2013-10-24

今流行りの DUB を使ってみた

| 03:27

公式 URL

http://code.dlang.org/

Github

https://github.com/rejectedsoftware/dub

日本語解説(とてもありがたい)

http://codelogy.org/archives/2013/09/%E3%80%90d%E8%A8%80%E8%AA%9E%E3%80%91d%E8%A8%80%E8%AA%9E%E3%81%AE%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%83%9E%E3%83%8D%E3%83%BC%E3%82%B8%E3%83%A3%E3%80%81dub.html

http://qiita.com/yasei_no_otoko/items/2724eebab10f5cd0a02f


開発環境が Arch Linux なので、dmdとか dubとかは

$ yaourt -S dlang dub

で導入。

ちなみに community package なので yaourt は必須では無いです。


使用方法について。

上記の URL読めば大抵の使い方は分かる。

project $ dub init test
Successfully created an empty project in '/home/user/Programming/D/project/test'.
project $ cd test 
test $ ls
package.json  public  source  views
test $ cat package.json 
{
	"name": "test",
	"description": "An example project skeleton",
	"homepage": "http://example.org",
	"copyright": "Copyright © 2000, Your Name",
	"authors": [
		"Your Name"
	],
	"dependencies": {
	}
}
test $ ls source 
app.d
test $ cat source/app.d 
import std.stdio;

void main()
{ 
	writeln("Edit source/app.d to start your project.");
}

必要なライブラリ等の情報は package.json の dependenciesに書いて、

エントリポイントになる app.dにコードを書いていく感じ。


プロジェクトの中で

test $ dub

とか叩くとコンパイルから実行までやってくれる。

test $ dub build

とか叩くと package.json の "name" で実行ファイルが作成される。


dependenciesに列挙したライブラリ

/home/user/.dub/packages の中に保存されるので、

綺麗にしたかったら .dubとか丸々消してしまえば良いのかな。


で、dub使って気になったのが

野良 github repositoryとかは登録出来ないっぽい?という事。

http://code.dlang.org/ に登録すれば引っ張ってこれるのだろうけど、

其処まででも無いかなぁと思ったので

ローカルにある外部ライブラリなり外部ソースコードを一緒にコンパイルする方法調べた。


結論としては、package.json

"importPaths":[ path, ... ]

"sourceFiles":[ file, ... ]

"sourcePaths":[ path, ... ]

辺りの Key Value Pair を登録しといてやるとよしなにやってくれるっぽい。


test $ ls ../../mylib/adjustxml 
README.md  adjustxml.d

こんなライブラリがあったとする。


"importPaths" に関して

test $ cat package.json
{
    ...
    "importPaths": [
        "../../mylib/adjustxml"
    ]
}
test $ dub build --verbose
... 省略 ...
Compiling...
dmd -c -oftemp.o -debug -g -wi -version=Have_test -I../../mylib/adjustxml -Jviews source/app.d
Linking...
dmd -oftest temp.o -g

"sourceFiles" に関して

test $ cat package.json
{
    ...
    "sourceFiles": [
        "../../mylib/adjustxml/adjustxml.d"
    ]
}
test $ dub build --verbose
... 省略 ...
Compiling...
dmd -c -oftemp.o -debug -g -wi -version=Have_test -Isource -Jviews source/app.d ../../mylib/adjustxml/adjustxml.d
Linking...
dmd -oftest temp.o -g

"sourcePaths" に関して

  • 列挙した path に含まれている *.d を全てコンパイラに渡してくれる。
  • 気をつけなきゃいけない点?としては、sourcePaths使うと project/source を読みに行ってくれなくなるので、明示的に "source" ディレクトリを書いてやらねばならない。
test $ cat package.json
{
    ...
    "sourcePaths": [
        "../../mylib/adjustxml"
    ]
}
test $ dub build --verbose
... 省略 ...
Compiling...
dmd -c -oftemp.o -debug -g -wi -version=Have_test -Isource -Jviews source/app.d ../../mylib/adjustxml/adjustxml.d
Linking...
dmd -oftest temp.o -g

実はここらへん、配布されてるパッケージの package.json眺めると簡単に分かる。


はてな記法全然分からないから凄く読みづらい…

取り敢えず自分用メモとして残しておく感じで。


これから DUBD言語の標準 package managerになっていくという流れっぽいので、

今のうちから慣れておくと後々ラクできるかも?

2013-08-10

Scala勉強中

| 23:17

D言語で書いた Brainf*ck処理系をそのまま Scalaで再実装。

両方もっと面白く書けるとは思うのだけど、それはそれ今後の課題と致します。(逃

import std.stdio;
import std.string : indexOf;
import std.algorithm;
import std.conv;
import std.range;
import std.array;

struct Source
{
    string code = "";
    uint   position = 0;
    uint[] jmps;

    char get()   { return code[ position++ ]; }
    bool empty() { return code.length == position; }
    void push()  { jmps ~= position; }
    void jamp()  { position = jmps[$-1]; }
    void pop()   { jmps = jmps[0..$-1]; }
}

unittest
{
    Source src = Source( "+-[><].," );
    assert( src.get == '+' );
    assert( src.get == '-' );
    assert( src.get == '[' );
    src.push;
    assert( src.position == 3 );
    assert( src.jmps == [3] );
    assert( src.get == '>' );
    assert( src.get == '<' );
    assert( src.position == 5 );
    assert( src.get == ']' );
    src.jamp();
    assert( src.position == 3 );
    assert( src.jmps == [3] );
    assert( src.get == '>' );
    assert( src.get == '<' );
    assert( src.position == 5 );
    src.pop;
    assert( src.jmps == [] );

}

struct Record
{
    uint[] tape = [0];
    uint   position = 0;

    void inc() { tape[ position ]++; }
    void dec() { if(tape[position]==0) throw new Exception("おこだよ!"); tape[position]--; }

    void next() { position++; if(tape.length <= position) tape ~= 0; }
    void prev() { if(position==0) throw new Exception("ダメなの!"); position--; }

    uint current() { return tape[ position ]; }
}

string exec( Source src, Record rec )
{
    string result = "";
    while( !src.empty )
    {
        char c = src.get;
        switch( c )
        //switch( src.get )
        {
            case '+' : { rec.inc; } break;
            case '-' : { rec.dec; } break;
            case '>' : { rec.next; } break;
            case '<' : { rec.prev; } break;
            case '[' : { src.push; } break;
            case ']' : { rec.current == 0 ? src.pop : src.jamp; } break;
            case '.' : { result ~= rec.current.to!char; } break;
            default : {} break;
        }        
    }
    return result;
}

unittest
{
    static Source src = Source( "+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.------------.<++++++++.--------.+++.------.--------.>+." );
    static Record rec = Record();
    assert( exec( src, rec ) == "Hello, world!" );

    assert( 
        Source( ">+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++++>-]<.>+++++++++++[<+++++>-]<.>++++++++[<+++>-]<.+++.------.--------.[-]>++++++++[<++++>-]<+." ).exec( Record() )
        ==
        "Hello World!"
    );

    assert(
        Source( ">+++[>+++[<<++++++++>>-]<-]<.++>+++[>+++[<<+++>>-]<-]<.+++++++..+++.--->++[>++[>++[>++[>++[<<<<<-->>>>>-]<-]<-]<-]<-]<.+>+++[<---->-]<." ).exec( Record() )
        ==
        "Hello,!"
    );
}

void main( string[] args )
{
    Source( args[1] ).exec( Record() ).writeln;
    return;
}
import java.lang.String
import scala.collection.mutable._

class Source( code: String ) {
  var position = 0;
  var jmps:Stack[Int] = Stack()

  def get:Char      = { val result = code( position ); position += 1; result }
  def empty:Boolean = { code.length == position }
  def push          = { jmps = jmps.push( position ) }
  def jamp          = { position = jmps.last }
  def pop           = { jmps.pop }
}

class Record() {
  var position = 0
  var tape:ListBuffer[Int] = ListBuffer(0)

  def inc  = { tape( position ) += 1 }
  def dec  = { tape( position ) -= 1 }
  def next = { position += 1; if( tape.length <= position ) tape += 0 }
  def prev = { position -= 1 }

  def current:Int = { tape( position ) }
}

object bf2 {

    def exec( src: Source, rec: Record ): String = {
      var result = ""
      while( !src.empty ) {
        src.get match {
          case '+' => rec.inc
          case '-' => rec.dec
          case '>' => rec.next
          case '<' => rec.prev
          case '[' => src.push
          case ']' => if( rec.current == 0 ) src.pop else src.jamp
          case '.' => result += rec.current.toChar
          case _ => println("not match")
        }
      }
      result
    }

  def main( args: Array[ String ] ): Unit = {
    val src = new Source("+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.------------.<++++++++.--------.+++.------.--------.>+.")
    val rec = new Record
    println( exec( src, rec ) )
  }
}

2013-05-02

関数呼び出しのコストを見てみる

| 16:54

気になったので調べてみたついでに、メモしておく。

main.d

import std.string, std.range, std.algorithm, std.conv, std.array, std.stdio;

alias double[16] Matrix;

Matrix func( Matrix m ) { return m; }
Matrix func_rc( ref const Matrix m ) { return m; }
auto ref func_ar( Matrix m ) { return m; }
auto ref func_ar_rc( ref const Matrix m ) { return m; }
auto func_l = ( Matrix m ) => m;
auto func_l_rc = ( ref const Matrix m ) => m;
Matrix func_i( in Matrix m ) { return m; }
auto ref func_ar_i( in Matrix m ) { return m; }
auto func_l_i = ( in Matrix m ) => m;

void main( string[] args )
{
	Matrix m = [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0 ];
	
	foreach( i; 0..1000000 ) func(m);
	foreach( i; 0..1000000 ) func_rc(m);
	foreach( i; 0..1000000 ) func_ar(m);
	foreach( i; 0..1000000 ) func_ar_rc(m);
	foreach( i; 0..1000000 ) func_l(m);
	foreach( i; 0..1000000 ) func_l_rc(m);
	foreach( i; 0..1000000 ) func_i(m);
	foreach( i; 0..1000000 ) func_ar_i(m);
	foreach( i; 0..1000000 ) func_l_i(m);
	
	return;
}

なコードを -profile付けてコンパイル

dmd main.d -profile

そして実行して吐いた trace.logを見る。



以下結果。

一回目

======== Timer Is 2935112 Ticks/Sec, Times are in Microsecs ========

  Num          Tree        Func        Per
  Calls        Time        Time        Call

      1    12540677     7605232     7605232     _Dmain
11000000      690005      690005           0     pure nothrow @safe const(double[16]) main.__lambda3(const(double[16]))
11000000      687401      687401           0     pure nothrow @safe const(double[16]) main.__lambda2(ref const(double[16]))
11000000      673076      673076           0     double[16] main.func_i(const(double[16]))
11000000      670352      670352           0     const(double[16]) main.func_ar_i(const(double[16]))
11000000      644416      644416           0     pure nothrow @safe double[16] main.__lambda1(double[16])
11000000      569693      569693           0     double[16] main.func_rc(ref const(double[16]))
11000000      516156      516156           0     double[16] main.func(double[16])
11000000      439182      439182           0     ref const(double[16]) main.func_ar_rc(ref const(double[16]))
1000000       45160       45160           0     double[16] main.func_ar(double[16])

二回目

======== Timer Is 2935112 Ticks/Sec, Times are in Microsecs ========

  Num          Tree        Func        Per
  Calls        Time        Time        Call

      1    13766704     8394815     8394815     _Dmain
12000000      749979      749979           0     pure nothrow @safe const(double[16]) main.__lambda2(ref const(double[16]))
12000000      746487      746487           0     pure nothrow @safe const(double[16]) main.__lambda3(const(double[16]))
12000000      726993      726993           0     const(double[16]) main.func_ar_i(const(double[16]))
12000000      722372      722372           0     double[16] main.func_i(const(double[16]))
12000000      692746      692746           0     pure nothrow @safe double[16] main.__lambda1(double[16])
12000000      614376      614376           0     double[16] main.func_rc(ref const(double[16]))
12000000      561719      561719           0     double[16] main.func(double[16])
12000000      467464      467464           0     ref const(double[16]) main.func_ar_rc(ref const(double[16]))
2000000       89749       89749           0     double[16] main.func_ar(double[16])

三回目

======== Timer Is 2935112 Ticks/Sec, Times are in Microsecs ========

  Num          Tree        Func        Per
  Calls        Time        Time        Call

      1    14996076     9190335     9190335     _Dmain
13000000      810349      810349           0     pure nothrow @safe const(double[16]) main.__lambda3(const(double[16]))
13000000      801379      801379           0     pure nothrow @safe const(double[16]) main.__lambda2(ref const(double[16]))
13000000      781782      781782           0     const(double[16]) main.func_ar_i(const(double[16]))
13000000      771946      771946           0     double[16] main.func_i(const(double[16]))
13000000      740717      740717           0     pure nothrow @safe double[16] main.__lambda1(double[16])
13000000      660759      660759           0     double[16] main.func_rc(ref const(double[16]))
13000000      606062      606062           0     double[16] main.func(double[16])
13000000      497636      497636           0     ref const(double[16]) main.func_ar_rc(ref const(double[16]))
3000000      135108      135108           0     double[16] main.func_ar(double[16])


"auto ref 返り値"って場合によっては実行効率かなり高くなるのか…

そして個人的には "ref const 引数" が "修飾無し引数" より効率悪くなる事の方が驚き。

というか悲しい。

以前コード書いてた時に ref const 修飾子付けたら実行速度上がった事があったから

ずっとそれを盲信して来たのだが…うん…


測定方法がこれで合ってるか確信無いので、

こんな結果も出ましたよってくらいに読み流しておいて下さい。

2012-11-08

株式会社 ウサギィ に行ってきました!

21:51

巷で「海鮮丼屋なのではないか?」と噂の絶えないウサギィ。


Twitterで「俺も海鮮丼食べたい!」って言った所、

中の人達から「おいでー」と言って頂けたので

無礼を承知でお邪魔させて頂きました。


発端はここら辺。


とか、

とか。


という事で、2012/11/07 PM1:00、

ホイホイとウサギィにお邪魔してきました。


ウサギィがある稲荷町タワー自体は上野駅から浅草通りを真っ直ぐ行った所の道沿いにあるので

簡単に見つかりましたが(といっても GoogleMap万能)、其処からがちょっとハードル高かった。

受付ロビーのお姉さん達に教えて貰いつつ、エレベーターに乗り、そして…



呼び鈴押したら、かずー氏がお出迎えして下さいました。

そのままフロアに通して頂き、まず町代表(@)とかずー氏(@)に改めてご挨拶。


もう玄関からオサレな会社でしたが、

作業スペースとなるメインフロアも白と黒のツートーンカラーで纏められてて

落ち着けるとても素敵な空間でした。だって熱帯魚泳いでたし。


そこから自分の雑魚アピールを一通りして、Delphi Disったり、

今の時代お金になる言語は〜とお話をしている間に女帝氏(@)*1もいらっしゃったのでご挨拶。


因みにお金になる言語、という話では

やっぱり何だかんだ言っても PHPは就職に強いという揺るがない事実と、

「ここ(ウサギィ)で働いてると忘れるけど、(業界的に)Ruby(の案件)は思ってる程多くはないんじゃないかな?」

というようなお話を頂きました。


あと、Web関係で仕事を探すなら Server Sideの知識は必要不可欠、

JavaScriptはその関係上いつか覚える事になる、

Javaで Webも出来るけど面倒くさい、とか

D言語は良い言語、

ゲーム業界なら C++は必須も必須、

今時 Delphiはねーよwww、とかそんな所のお話も。


皆様 Twitterで伺えるようにとても気さくな方々でしたが、直接お話してもやはり皆様凄い方達でした。

そこで改めて思った、自分の場違い感。

気にしたら死ぬと思って知らない振りしましたが。


そんなこんなで女帝氏と妹トークしてた所に、おもむろに差し出される噂のアレ。

か…海鮮丼のメニュー表…!!!

裏メニューの存在も仄めかされる中、そこに記載されているだけでも 59種類ありました。

(まだ注文した事ないモノもある(?)そうなので、見学者の皆様は狙っていきましょう)

そして悩んでいる間にも、頭上で飛び交う"コスパ"という言葉。

流石だな、と思った。


結局私はサーモンネギトロ丼をご馳走になりました。

噂に違わず、とても美味しかったです。

緊張してたので美味しいって全く表現出来てなかったのが悔やまれます、

本当に美味しかった…!


しかし海鮮丼化身たる代表がウニ食べられないって話を聞いた時には

なんか不思議な衝撃を受けました。

かといっても海鮮丼。代表、痛風にはお気を付け下さいませ…。


海鮮丼もぐもぐした所でインターンの学生さん(だと思う)がお二人いらっしゃって、

最終的にその日は町代表とかずー氏と女帝氏、あとお名前お伺い出来なかった↑の方々との

5名のお仕事を邪魔するという形になってました。


そして外も暗くなって来た所で、外出されていた代表もお戻りになり

皆様のお仕事もノってきた感じでしたので、一足先に退散させて頂く事に。

帰りは代表、かずー氏、女帝氏揃ってお見送りして頂きました。


過去にプログラマとして生きた事があったとしても、

主業界が違う事や、ブランクがある事もあり、

聞いた事があるだけのツール(jenkins等)が当然のように使われているのを目の当たりに出来たり、

やり取りしている会話に散見される話題の豊富さだったり、

突然の面白ネタ(その日は Linux Mint搭載の USBが取り出された辺り)に皆で笑えたり、

知ってる世界とは全然違くて、憧れたし、羨ましいとも思ったし、

自分が目指すはそんな次元の話なんだなって、ハードルの高さにちょっと怖くなったりもしました。


それらを知る大切な一日を、ウサギィにて過ごさせて頂きました。

ウサギィの持つ組織としての強さを、身に染みて感じました。

本当にお世話になりましたーーーーー!!!!!



あと最後に。

折角女帝氏に募集かけて貰ったので、是非よろしくお願いします :-)

*1:現所属はご本人のプロフにてご確認下さい。誤解を広める事になりかねないので一応。

2011-10-06

Arch の Boot時に出た [FAIL]を消す

| 06:43

タイトルだけじゃ分かり難い…


Arch の起動時に

Starting Syslog-NG [DONE]

Mounting Network Filesystems [DONE]

Starting Cron Daemon [DONE]

みたいなログ出るじゃないですか。


いつかの kernel update 後から、あの中で

・Mounting Local Filesystems

・Restoring ALSA Levels

・Loading Modules

の3つだけが [FAIL]を吐くようになっていて

起動後も何かしらの動作に異常をきたしているかの如く

変なメッセージをターミナルに吐き出し続けるという状況になっていた。

(今は吐かなくなっちゃったので該当のメッセージが分からなくなってしまった…)


それでもどうにか動いてはいたので無視していたけど

いい加減消してあげようと重い腰を上げたので

やった事だけ書いておく。


まず"Restoring ALSA Levels"に関して。

これは何やら kernel update 時に

既存の /var/lib/alsa/asound.state が読めなくなったのが原因だったらしい。

(kernelalsa に密接な関係あったのかな…自信無し)

なので取り敢えず

$cd /var/lib/alsa/asound.state
$mv ./asound.state ./asound.state_backup
$alsactl store

で asound.state を作り直して終了。

diff 取ったらほんと小さい所が変更されてたみたい。


次に"Mounting Modules"に関して。

これも kernel update に合わせて

rc.conf の MODULES=(...) の書き方が変わったせいらしい。

今まで起動させない Module は頭に"!"(ex.!pcspkr)を付けていたのだけど

そいつら全部別途 Blacklist に登録しろって事だったみたい。


なので rc.conf で弾いてた Module を

/etc/modprobe.d/modprobe.conf に

#
# /etc/modprobe.d/modprobe.conf (for v2.6 kernels)
#
blacklist pcspkr
blacklist earth_pt1

てな感じで登録。

modprobe 使う方法もあるようなので、そっちのが好きな人はそれで。

確か「いつかはこのような作業が必要になるから

今後の為にちょっと面倒だけど変更しちゃったぜ」的なメッセージを

どっかで読んだ気がする。


最後に"Mounting Local Filesystems"に関して

実はこれまだ解決出来てない。

修正出来次第書こうとは思ってるけど、何が悪いんだろうか…

ご存知の方いらっしゃいましたら、是非知恵をお貸し下さい…