--* From bmt@spadserv.watson.ibm.com  Sat Mar 13 12:55:54 1993
--* Received: from spadserv.watson.ibm.com by radical.watson.ibm.com (AIX 3.2/UCB 5.64/900524)
--*           id AA26040; Sat, 13 Mar 1993 12:55:54 -0500
--* Received: by spadserv.watson.ibm.com (AIX 3.2/UCB 5.64/900524)
--*           id AA25587; Sat, 13 Mar 1993 12:51:10 -0500
--* Date: Sat, 13 Mar 1993 12:51:10 -0500
--* From: bmt@spadserv.watson.ibm.com
--* X-External-Networks: yes
--* Message-Id: <9303131751.AA25587@spadserv.watson.ibm.com>
--* To: axc-bug@radical.watson.ibm.com, smwatt@watson.vnet.ibm.com
--* Subject: arsharp -r gets Getter failed due to local declaration on line 162, but this function is truly local [lmdict.as][v27.2 (current)]

--@ Fixed  by: SMW Wed Oct 13 14:04:57 1993
--@ Tested by: <name of new or existing file in test directory>
--@ Summary:   <One line description of real problem and the fix>


--Copyright The Numerical Algorithms Group Limited 1991.
#include "aslib.as"

NNI ==> SingleInteger
macro
  empty() == nil  
  ^= == ~=

--%  Reference

+++ Author: Stephen M. Watt
+++ Date Created:
+++ Change History:
+++ Basic Operations: deref, elt, ref, setelt, setref, =
+++ Related Constructors:
+++ Keywords:  reference
+++ Description:  \spadtype{Reference} is for making a changeable instance
+++ of something.

Reference(S:with BasicType): with

        ref   : S -> %
          ++  ref(n) creates a pointer (reference) to the object n.
        deref : % -> S
          ++ deref(n) is equivalent to \spad{elt(n)}.
        setref: (%, S) -> S
          ++ setref(n,m) same as \spad{setelt(n,m)}.
--        _=   : (%, %) -> Boolean
--          ++ a=b tests if \spad{a} and b are equal.

    == add
        Rep ==> Record(value: S)
        import Rep
--        import Builtin : with
--           PtrEQ: (BPtr, BPtr) -> BBool
        default p:%
        default v:S

--        p = q        == EQ(p, q)$Lisp
        ref(v:S):%        == per [v]
        deref(p:%):S      == rep(p).value
        setref(p:%, v:S):S == rep(p).value := v


--% List Multi Dictionary
--)abbrev domain LMDICT ListMultiDictionary
-- MBM Nov/87, MB Oct/89
 
 
+++ The ListMultiDictionary domain implements a dictionary with duplicates
+++ allowed.  The representation is a list with duplicates represented
+++ explicitly.  Hence most operations will be relatively innefficient
+++ when the number of entries in the dictionary becomes large.
+++ The operations \spadfun{pick}, \spadfun{count} and \spadfun{delete} can be used to iterate
+++ over the objects in the dictionary.  If the objects in the
+++ dictionary belong to an ordered set, the entries are maintained in
+++ ascending order.
 

MultiDictionary(S) ==>
   dictionary: () -> %
   insert!: (S,%) -> %
   insert!: (S,%,NNI) -> %
   empty?: % -> Boolean
   inspect: % -> S
   count: (S, %) -> NNI
   remove!: (S, %) -> %
   parts: % -> List S
 
ListMultiDictionary(S:with BasicType): with
   MultiDictionary(S)
--   finiteAggregate
   duplicates?: % -> Boolean    
     ++ duplicates?(d) tests if dictionary d has duplicate entries.
 == add
   Rep ==> Reference List S
   import Rep
   import List(S)
   import S

   default s,t:%
   default l:List S
   default n:SingleInteger
 
   parts(s:%):List(S) == deref rep(s)
   #(s:%):NNI         == # parts s
   count(x:S, s:%):NNI ==
     import String
     print("counting: ")(x)(" in ")(parts s)()
     sum:NNI:=0
     for y in parts s | y=x repeat sum := sum + 1
     print("sum = ")(sum)()
     sum
   copy(s:%):%             == dictionary copy parts s
   empty?(s:%):Boolean           == empty? parts s
   bag(l:List(S)):%         == dictionary l
   dictionary():%       == dictionary empty()
   dictionary(l:List(S)):%       ==
      import String
      print("creating dictionary for: ")(l)()
      per ref l
   insert_!(x:S, s:%, n:NNI):%  == (for i in 1..n repeat insert_!(x, s); s)
--   removeDuplicates_! s == dictionary removeDuplicates_! parts s
 
   inspect(s:%):S ==
     import String
     empty? s => error "empty dictionary"
     print("inspecting dictionary: ")(parts s)()
     first parts s
 
   extract_!(s:%):S ==
     import String
     empty? s => error "empty dictionary"
     x := first(p := parts s)
     setref(rep s, rest p)
     x
 
   duplicates?(s:%):Boolean ==
     empty?(p := parts s) => false
     q := rest p
     while not empty? q repeat
       first p = first q => return true
       p := q
       q := rest q
     false
 
#if conditionalcat
   if S has OrderedSet then
      s = t == parts s = parts t
 
      remove_!(x, s) ==
         p := deref s
         while not empty? p and x = first p repeat p := rest p
         setref(s, p)
         empty? p => s
         q := rest p
         while not empty? q and x > first q repeat (p := q; q := rest q)
         while not empty? q and x = first q repeat q := rest q
         p.rest := q
         s
 
      insert_!(x, s) ==
         p := deref s
         empty? p or x < first p =>
            setref(s, concat(x, p))
            s
         q := rest p
         while not empty? q and x > first q repeat (p := q; q := rest q)
         p.rest := concat(x, q)
         s
 
   else
#endif
-- ??? if following line is commented out, we get no getter failed message,
-- but this function is truly local ???
   local remove!:(S, List(S)) -> List(S) -- ?? "Getter failed" with this
   remove_!(v:S, x:List S):List S ==
     import String
     print("removing" )(v)(" from ")(x)() 
     while not empty? x and v = first x repeat x := rest x
     empty? x => x
     p := x
     q := rest x
     while not empty? q repeat
       if v=first q then q := setRest_!(p, rest q)
		    else (p := q; q := rest q)
     x
   
   remove_!(x:S, s:%):% == (setref(rep s, remove_!(x, parts s)); s)

   (s:%) = (t:%):Boolean ==
         a := copy s
         while not empty? a repeat
            x := inspect a
            count(x, s) ^= count(x, t) => return false
            remove_!(x, a)
         true
 
   insert_!(x:S, s:%):% ==
         import String
         print("inserting: ")(x)()
         p := deref rep s
         while not empty? p repeat
            x = first p =>
               setRest!(p, cons(x, rest p))
	       return s
            p := rest p
         setref(rep s, cons(x, deref rep s))
         s

import Integer
aaa:ListMultiDictionary(Integer) := dictionary()

remove!(1,aaa)
 
