Hash-table in elisp

まず skk 辞書フォーマットを処理するためのマクロ with-skk-jisyo-buffer と、
skk-large-jisyo ファイルを処理するためのマクロ with-skk-large-jisyo とを定義する。

(defmacro with-skk-jisyo-buffer (buffer key value &rest body)
  `(with-current-buffer ,buffer
     (goto-char (point-min))
     (while (not (eobp))
       (beginning-of-line)
       (if (looking-at "^;")
	   nil
	 (if (looking-at "\\(^[^ ]+\\) \\(.*\\)$")
	     (let ((,key (match-string-no-properties 1))
		   (,value (match-string-no-properties 2)))
	       ,@body)))
       (forward-line))))

(defmacro with-skk-large-jisyo (key value &rest body)
  (let ((buf (make-symbol "tmpbuf")))
    `(let ((,buf (skk-get-jisyo-buffer skk-large-jisyo t)))
       (with-skk-jisyo-buffer ,buf ,key ,value ,@body))))

こうしておくと、 Emacs Lisp 組み込みのハッシュテーブルに skk-large-jisyo を読み込む関数は以下のようにシンプルになる。

(defun skk-jisyo-hash ()
  (let ((ht (make-hash-table :test 'equal)))
    (with-skk-large-jisyo k v (puthash k v ht))
    ht))

これで elisp で実装したハッシュテーブルと簡単に比較できるようになった。elisp 版はこんな感じ。

(defun skk-jisyo-el-hash ()
  (let ((table (my-make-hash-table 15000)))
    (with-skk-large-jisyo k v (my-puthash k v table))
    table))

my-make-hash-table, my-puthash などは elisp によるハッシュテーブルの実装で、まずはこんな風に書いてみた。
vector を使い、その要素は alist にしている。よって、ハッシュ関数によってベクトルの指定の位置まで飛び、その後 alist で検索する。

;; hash table in elisp
(defun my-make-hash-table (&optional length)
  (make-vector (or length 64) nil))

(defun my-sxhash (table key)
  (abs (% (sxhash key) (length table))))

(defun my-puthash (key value table)
  (let ((h (my-sxhash table key)))
    (let ((lst (aref table h)))
      (setf (aref table h)
	    (acons key value
		   (if (assoc key lst)
		       (remove (assoc key lst) lst)
		     lst))))
    table))

(defun my-gethash (key table &optional dflt)
  (let ((hash (my-sxhash table key)))
    (let ((lst (aref table hash)))
      (if (assoc key lst)
	  (cdr (assoc key lst))
	dflt))))