;; -*- Scheme -*-
;;
;; $Id: mawk08.scm,v 1.1 1998/03/16 07:58:45 foner Exp $

;;-----------

(require 'avl-tree:nil)
(require 'avl-tree:find)
(require 'avl-tree:overwriting-insert)
(require 'avl-tree:for-all)

;;-----------

(define mawk:table::<?
  (lambda (a b)
    (cond ((string? a)
	   (cond ((string? b) (string<? a b))
		 ((number? b) (string<? a (number->string b)))
		 (else (error 'mawk:table::<? "invalid type"))))
	  ((number? a)
	   (cond ((number? b) (< a b))
		 ((string? b) (string<? (number->string a) b))
		 (else (error 'mawk:table::<? "invalid type"))))
	  (else (error 'mawk:table::<? "invalid type")))))

(define mawk:table::wrap cons)
(define mawk:table::unwrap-key car)
(define mawk:table::unwrap-value cdr)

(define mawk::list->alist
  (lambda (open-pairs pairs)
    (if (null? open-pairs)
	pairs
	(let ((key (car open-pairs))
	      (open-pairs (cdr open-pairs)))
	  (if (null? open-pairs)
	      (error 'mawk::list->alist "key without data")
	      (mawk::list->alist (cdr open-pairs)
				 (cons (cons key (car open-pairs)) pairs)))))))


;;+doc
;; procedure: mawk:table=
;; arguments: key value table
;; signature: (string|number) x (string|number) x mawk:table -> mawk:table
;;
;; Adds (KEY, VALUE) to TABLE.  If an element with the same KEY already
;; exists in TABLE, it will be overwritten with VALUE.
;;-doc

(define mawk:table=
  (lambda (k v t)
    (let ((e (lambda () (mawk:table::wrap k v))))
      (avl-tree:overwriting-insert t k mawk:table::unwrap-key mawk:table::<? e))))


;;+doc
;; procedure: mawk:table:add-alist
;; arguments: key&data-list table
;; signature: [(a . b)] x mawk:table -> mawk:table
;;
;; Add all the elements of the KEY&DATA-LIST to TABLE.  The list may
;; contain elements with equal keys, though it is undefined which data
;; value will be stored in this case.
;;-doc

(define mawk:table:add-alist
  (lambda (pairs table)
    (if (null? pairs)
	table
	(let ((key&data (car pairs)))
	  (mawk:table:add-alist
	   (cdr pairs)
	   (mawk:table= (car key&data) (cdr key&data) table))))))


;;+doc
;; procedure: alist->mawk:table
;; arguments: key&data-list
;; signature: [(a . b)] -> mawk:table
;;
;; Convert an `alist' containing (key . value) pairs into a table.
;; Duplicate keys are allowed, but it is undefined which value will
;; be associated with the key.
;;
;; > (alist->mawk:table '())
;; 
;; creates an empty table - { }
;;
;; > (alist->mawk:table '(("phone" . 6270) ("fax" . 6280)))
;;
;; creates { "phone" -> 6270, "fax" -> 6280 }
;;
;; > (alist->mawk:table '(("phone" . 6270) ("fax" . 6280) ("phone" . 8066)))
;;
;; creates a table containing either { "phone" -> 6270, "fax" -> 6280 }
;; or { "phone" -> 8066, "fax" -> 6280 }
;;-doc

(define alist->mawk:table
  (lambda (alist)
    (mawk:table:add-alist alist avl-tree:nil)))


;;+doc
;; procedure: mawk:table
;; arguments: key&value-list ...
;; signature: obj ... -> mawk:table
;;
;; Creates a new table empty table, or given a list of keys and values
;; creates a table containing these values.  The list may contain duplicate
;; keys but if it does, it is undefined which data value will be associated
;; with the key.
;;
;; Some examples :-
;;
;; > (mawk:table)
;;
;; creates an empty table and :-
;;
;; > (mawk:table "phone" 6270 "fax" 6280)
;;
;; creates a table containing { "phone" -> 6270, "fax" -> 6280 }
;;
;; > (mawk:table "phone" 6270 "fax" 6280 "phone" 8066)
;;
;; creates a table containing either { "phone" -> 6270, "fax" -> 6280 }
;; or { "phone" -> 8066, "fax" -> 6280 }
;;-doc

(define mawk:table
  (lambda args
    (alist->mawk:table (mawk::list->alist args '()))))


;;+doc
;; procedure: mawk:table:at
;; arguments: key table
;; signature: (string|number) x mawk:table -> a|#f
;;
;; Returns the value in TABLE with the given KEY or #f if there is no
;; element with the KEY.
;;-doc

(define mawk:table:at
  (lambda (k t)
    (avl-tree:find t k mawk:table::unwrap-key mawk:table::<? mawk:table::unwrap-value (lambda () #f))))


;;+doc
;; procedure: mawk:table:for-all
;; arguments: action[key value state] table state
;; signature: (a x b x c -> c) -> mawk:table x c -> c
;;
;; Applies ACTION to every element of TABLE
;;-doc

(define mawk:table:for-all
  (lambda (p t s)
    (let ((a (lambda (s k&v)
	       (p (mawk:table::unwrap-key k&v) (mawk:table::unwrap-value k&v) s))))
      (avl-tree:for-all t a s))))

;------------
;exports mawk:table

;; eof
