URLエンコード/デコード(比較にC++とclojure追加)
昨日の続き。
比較対象にC++とclojureを追加し、Javaのコードも若干変更した。
下の三つが、それぞれのベンチマーク用のコード。(ベンチマーク用データは、前回と同様のものを使用する)
参照: mmap_t
/** C++ **/ //////////////////////////// // ファイル名: url_encode.cc // g++ -O2 -ourl_encode url_encode.cc // time url_encode 対象ファイル #include <string> #include "mmap_t.h" bool is_safe_char(char c) { return isalnum(c)||c=='.'||c=='-'||c=='_'||c=='*'; } const char* encode_char_to_hex(char c, char* buf) { buf[1]="0123456789ABCDEF"[(c&0xF0)>>4]; buf[2]="0123456789ABCDEF"[c&0x0F]; return buf; } void url_encode(const char* c, std::string& dist) { char hexbuf[]={'%',0,0,0}; for(; *c!='\0'; c++) { if(is_safe_char(*c)) dist += *c; else if (*c==' ') dist += '+'; else dist += encode_char_to_hex(*c,hexbuf); } } #include <iostream> int main(int argc, char** argv) { mmap_t mm(argv[1]); std::string dist; url_encode((const char*)mm.ptr,dist); // std::cout << dist; return 0; } //////////////////////////// // ファイル名: url_decode.cc // g++ -O2 -ourl_decode url_decode.cc // time url_decode 対象ファイル #include <string> #include "mmap_t.h" static const char table[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; char decode_hex_to_char(const char* c) { // XXX: [0-9a-zA-Z]以外の全ての文字は、0として扱われる (e.g. "%@X" => 0) return (table[static_cast<unsigned char>(c[1])]<<4)+ table[static_cast<unsigned char>(c[2])]; } void url_decode(const char* c, std::string& dist) { for(; *c!='\0'; c++) { switch(*c) { case '%': dist += decode_hex_to_char(c); c+=2; break; // XXX: 末尾に'%'が来る不正な文字列が渡された場合の挙動は未定義(ex. "abc%") case '+': dist += ' '; break; default: dist += *c; break; } } } #include <iostream> int main(int argc, char** argv) { mmap_t mm(argv[1]); std::string dist; url_decode((const char*)mm.ptr,dist); //std::cout << dist; return 0; }
;;;; clojure ;;;; ;;; データ準備 (def kokoro (slurp "/path/to/kokoro")) ; slurp関数でファイルを全部読み込めるみたい (def enc-kokoro (slurp "/path/to/encoded-kokoro")) ;; apacheログファイルも同様に読み込む ;;; エンコード/デコード + 計時 (time (do (. java.net.Encoder encode kokoro) 'done)) ; JavaのURLエンコードクラスを使用する (time (do (. java.net.Decoder decode enc-kokoro) 'done)) ; JavaのURLデコードクラスを使用する
/** Java **/ //// 基本的に前回と同様なので、差分だけ載せる // ファイル: Encode.java // 以下の四行を追加: あらかじめ慣らし運転させておくと数割程度速くなる URLEncoder.encode(text,"UTF-8"); URLEncoder.encode(text,"UTF-8"); URLEncoder.encode(text,"UTF-8"); URLEncoder.encode(text,"UTF-8"); final long beg_t = System.currentTimeMillis(); URLEncoder.encode(text,"UTF-8"); final long end_t = System.currentTimeMillis(); // ファイル: Decode.java // こちらも以下の四行を追加 URLDecoder.decode(text,"UTF-8"); URLDecoder.decode(text,"UTF-8"); URLDecoder.decode(text,"UTF-8"); URLDecoder.decode(text,"UTF-8"); final long beg_t = System.currentTimeMillis(); URLDecoder.decode(text,"UTF-8"); final long end_t = System.currentTimeMillis();
結果
以下結果:
【URLエンコード】 | 『こころ』のエンコード時間(秒) | Apacheログのエンコード時間(秒) |
url:encode(sbcl) | 0.032 | 0.091 |
java.net.URLEncoder(Java) | 0.082 | 0.265 |
java.net.URLEncoder(clojure) | 0.026 | 0.140 |
url_encode(C++) | 0.025 | 0.060 |
【URLデコード】 | 『こころ』のデコード時間(秒) | Apacheログのデコード時間(秒) |
url:decode(sbcl) | 0.039 | 0.246 |
java.net.URLDecoder(Java) | 0.031 | 0.194 |
java.net.URLDecoder(clojure) | 0.028 | 0.114 |
url_decode(C++) | 0.007 | 0.023 |