Commits

Doug Burke committed d6f770e

Removed Data.LookupMap and tests

Comments (0)

Files changed (5)

   where it does not. This definitely speeds up some operations but
   a full analysis has not been attempted.
 
+  Replaced used of Data.LookupMap with Data.Map.Map. This has led to
+  the removal of a number of language extensions from some modules.
+
   A few other minor changes have been made: the removal of subset and
   equiv from Swish.Utils.ListHelpers; the ordering used for RDFLabel
   values has changed; added a Monoid instance for VarBinding; added
 
 Some things I want to/should do (not in order)
 
-- the removal of LookupMap from formula/formulamap led to functor/
-  traversable instances to require (a -> a rather than (a -> b);
-  this does not seem to be a problem for the existing code, since
-  specialized to RDFLabel, but may want to revert if possible.
-
-  Need to look at the traversable code to see if really a traverse.
-
 - Support IRI rather than URI. See issue #13
   https://bitbucket.org/doug_burke/swish/issue/13/
 
 - Look at using an interned URI in Namespace.
 
-- Can LookupMap be replaced by Map? This would require removing the
-  LookupEntryClass constraint which could cause troublesome.
-
-  There are a number of cases where we have
-
-    M.lookup key $ M.fromList $ map <somefunv> <list-of-vals>
-    mapFindMaybe key $ LookupMap <list-of-vals>
-
-  which can be optimised (no need to create the map since can stop once
-  the element has been found).
-
 - Rename modules. Version 0.7 provided a hopefully more-structured
   form but they are still in the Swish namespace rather than
   Data (or some other sanctioned top-level name).
 - add RDF/XML parser and formatter. See issue #7
   https://bitbucket.org/doug_burke/swish/issue/7/
 
+  Ditto for JSON-LD/the various named-graph forms/...
+
 - Should there be a type-level constaint that an RDF Arc can only have
   a literal in the object position?
 

src/Data/LookupMap.hs

-{-# LANGUAGE CPP #-}
-{-# LANGUAGE DeriveFoldable #-}
-{-# LANGUAGE DeriveFunctor #-}
-{-# LANGUAGE DeriveTraversable #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE FunctionalDependencies #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE TypeSynonymInstances #-}
-{-# LANGUAGE OverloadedStrings #-}
-
---------------------------------------------------------------------------------
---  See end of this file for licence information.
---------------------------------------------------------------------------------
--- |
---  Module      :  LookupMap
---  Copyright   :  (c) 2003, Graham Klyne, 2009 Vasili I Galchin, 2011, 2012 Douglas Burke
---  License     :  GPL V2
---
---  Maintainer  :  Douglas Burke
---  Stability   :  experimental
---  Portability :  A lot of LANGUAGE extensions...
---
---  This module defines a lookup table format and associated functions
---  used by the graph matching code.
---
---------------------------------------------------------------------------------
-
-------------------------------------------------------------
---  Generic list-of-pairs lookup functions
-------------------------------------------------------------
-
-module Data.LookupMap
-    ( LookupEntryClass(..), LookupMap(..)
-    , emptyLookupMap, makeLookupMap
-    , listLookupMap
-    , setLookupMap
-    , reverseLookupMap
-    , keyOrder
-    , mapFind, mapFindMaybe, mapContains
-    , mapReplace, mapReplaceAll, mapReplaceMap
-    , mapAdd, mapAddIfNew
-    , mapDelete, mapDeleteAll
-    , mapEq, mapKeys, mapVals
-    , mapMerge
-    )
-    where
-
-import Control.Arrow (first, second)
-
-import Data.Maybe (fromMaybe)
-import Data.Function (on)
-import Data.Ord (comparing)
-
-import qualified Data.Foldable as F
-import qualified Data.List as L
-import qualified Data.Set as S
-import qualified Data.Traversable as T
-
-#if defined(__GLASGOW_HASKELL__) && (__GLASGOW_HASKELL__ >= 701)
-import Data.Tuple (swap)
-#else
-swap :: (a,b) -> (b,a)
-swap (a,b) = (b,a)
-#endif
-
-------------------------------------------------------------
---  Class for lookup map entries
-------------------------------------------------------------
-
--- |@LookupEntryClass@ defines essential functions of any datatype
---  that can be used to make a 'LookupMap'.
---
---  Minimal definition: @newEntry@ and @keyVal@
---
-class (Eq k) => LookupEntryClass a k v | a -> k, a -> v
-    where
-        newEntry    :: (k,v) -> a
-        keyVal      :: a -> (k,v)
-        
-        entryKey    :: a -> k
-        entryKey = fst . keyVal
-        
-        entryVal    :: a -> v
-        entryVal = snd . keyVal
-                             
-        entryEq     :: (Eq v) => a -> a -> Bool
-        entryEq e1 e2 = keyVal e1 == keyVal e2
-        
-        entryShow   :: (Show k, Show v) => a -> String
-        entryShow e = show k ++ ":" ++ show v where (k,v) = keyVal e
-                                                    
-        kmap :: (LookupEntryClass a2 k2 v) => (k -> k2) -> a -> a2
-        kmap f = newEntry . first f . keyVal
-        
-        vmap :: (LookupEntryClass a2 k v2) => (v -> v2) -> a -> a2
-        vmap f = newEntry . second f . keyVal
-
--- |Predefine a pair of appropriate values as a valid lookup table entry
---  (i.e. an instance of LookupEntryClass).
---
-instance (Eq k) => LookupEntryClass (k,v) k v where
-    newEntry = id
-    keyVal   = id
-
---  Note:  the class constraint that a is an instance of 'LookupEntryClass'
---  is not defined here, for good reasons (which I forget right now, but
---  something to do with the method dictionary being superfluous on
---  an algebraic data type).
-
--- |Define a lookup map based on a list of values.
---
-data LookupMap a = LookupMap [a]
-  deriving (Functor, F.Foldable, T.Traversable)
-
-instance (Ord a) => Ord (LookupMap a) where
-    compare = comparing gLM
-
-{-
-
-To allow this Monoid instance, we would need UndecidableInstances.
-Also, mapMerge can error out which is not what we would want.
-
-instance (LookupEntryClass a k v, Eq a, Show a, Ord k) => Monoid (LookupMap a) where
-    mempty = LookupMap []
-    mappend = mapMerge
-
-We could use the following (perhaps with a L.nub on the result before sticling back
-into LookupMap) but it is unclear what the semantics are for repeated keys; it is
-likely to be left-biased but would leave duplicate keys in the list which could
-cause confusion at a later time (e.g. key removal). Many of the routines assume a single
-key (or single key,value) pair.
-
-instance (Eq a) => Monoid (LookupMap a) where
-    mempty = LookupMap []
-    (LookupMap a) `mappend` (LookupMap b) =
-        LookupMap (a `mappend` b))
--}
-
-gLM :: LookupMap a -> [a]
-gLM (LookupMap es) = es
-
--- |Define equality of 'LookupMap' values based on equality of entries.
---
---  (This is possibly a poor definition, as it is dependent on ordering
---  of list members.  But it passes all current test cases, and is used
---  only for testing.)
---
-instance (Eq a) => Eq (LookupMap a) where
-    (==) = (==) `on` gLM
-
--- |Define Show instance for LookupMap based on Showing the
--- list of entries.
---
-instance (Show a ) => Show (LookupMap a) where
-    show (LookupMap es) = "LookupMap " ++ show es
-
--- |Empty lookup map of arbitrary (i.e. polymorphic) type.
---
-emptyLookupMap :: (LookupEntryClass a k v) => LookupMap a
-emptyLookupMap = LookupMap []
-
--- |Function to create a `LookupMap` from a list of entries.
---
-makeLookupMap :: 
-    (LookupEntryClass a k v) 
-    => [a]  -- ^ This list is not checked for duplicate entries, or
-            -- entries with the same key but different values.
-    -> LookupMap a
-makeLookupMap = LookupMap
-
--- |Returns a list of lookup map entries.
---
-listLookupMap :: (LookupEntryClass a k v) => LookupMap a -> [a]
-listLookupMap = gLM
-
--- | Returns a set of lookup map entries.
---
-setLookupMap ::
-    (LookupEntryClass a k v, Ord a)
-    => LookupMap a -> S.Set a
-setLookupMap = S.fromList . listLookupMap
-
-
--- |Given a lookup map entry, return a new entry that can be used
---  in the reverse direction of lookup.  This is used to construct
---  a reverse LookupMap.
---
-reverseEntry :: (LookupEntryClass a1 k v, LookupEntryClass a2 v k)
-    => a1 -> a2
-reverseEntry = newEntry . swap . keyVal
-
--- |Given a lookup map, return a new map that can be used
---  in the opposite direction of lookup.
---
-reverseLookupMap :: (LookupEntryClass a1 b c, LookupEntryClass a2 c b)
-    => LookupMap a1 -> LookupMap a2
-reverseLookupMap = fmap reverseEntry
-
--- |Given a pair of lookup entry values, return the ordering of their
---  key values.
---
-keyOrder :: (LookupEntryClass a k v, Ord k)
-    =>  a -> a -> Ordering
-keyOrder = comparing entryKey
-
--- |Find key in lookup map and return corresponding value,
---  otherwise return default supplied.
---
-mapFind :: 
-    (LookupEntryClass a k v) 
-    => v    -- ^ The default value.
-    -> k 
-    -> LookupMap a -> v
-mapFind def key = fromMaybe def . mapFindMaybe key
-
--- |Find key in lookup map and return Just the corresponding value,
---  otherwise return Nothing.
---
-mapFindMaybe :: (LookupEntryClass a k v) => k -> LookupMap a -> Maybe v
-mapFindMaybe key (LookupMap es) = foldr match Nothing es where
-    match ent alt
-        | key ==  entryKey ent  = Just (entryVal ent)
-        | otherwise             = alt
-
--- |Test to see if key is present in the supplied map
---
-mapContains :: (LookupEntryClass a k v) =>
-    LookupMap a -> k -> Bool
-mapContains (LookupMap es) key  = any match es where
-    match ent = key == entryKey ent
-
--- |Replace the first occurrence of a key a with a new key-value pair,
---  or add a new key-value pair if the supplied key is not already present.
---
-mapReplace :: (LookupEntryClass a k v) =>
-    LookupMap a -> a -> LookupMap a
-mapReplace (LookupMap []) newe      = LookupMap [newe]
-mapReplace (LookupMap (e:es)) newe
-    | entryKey e == entryKey newe   = LookupMap (newe:es)
-    | otherwise                     = mapAdd more e where
-        more = mapReplace (LookupMap es) newe
-
--- |Replace all occurrence of a key a with a new key-value pair.
---
---  The resulting lookup map has the same form as the original in all
---  other respects.
---
-mapReplaceAll :: (LookupEntryClass a k v) =>
-    LookupMap a -> a -> LookupMap a
-mapReplaceAll l@(LookupMap []) _        = l
-mapReplaceAll (LookupMap (e:es)) newe   = mapAdd more e' where
-    more = mapReplaceAll (LookupMap es) newe
-    e'   = if entryKey e == entryKey newe then newe else e
-
--- |Replace any occurrence of a key in the first argument with a
---  corresponding key-value pair from the second argument, if present.
---
---  This could be implemented by multiple applications of 'mapReplaceAll',
---  but is arranged differently so that only one new @LookupMap@ value is
---  created.
---
---  Note:  keys in the new map that are not present in the old map
---  are not included in the result map
---
-mapReplaceMap :: (LookupEntryClass a k v) =>
-    LookupMap a -> LookupMap a -> LookupMap a
-mapReplaceMap l@(LookupMap []) _ = l
-mapReplaceMap (LookupMap (e:es)) newmap = mapAdd more e' where
-    more  = mapReplaceMap (LookupMap es) newmap
-    e'    = newEntry (k, mapFind v k newmap)
-    (k,v) = keyVal e
-
--- |Add supplied key-value pair to the lookup map.
---
---  This is effectively an optimized case of 'mapReplace' or 'mapAddIfNew',
---  where the caller guarantees to avoid duplicate key values.
---
-mapAdd :: LookupMap a -> a -> LookupMap a
-mapAdd (LookupMap es) e = LookupMap (e:es)
-
--- |Add supplied key-value pair to the lookup map,
---  only if the key value is not already present.
---
-mapAddIfNew :: (LookupEntryClass a k v) =>
-    LookupMap a -> a -> LookupMap a
-mapAddIfNew emap e = if mapContains emap (entryKey e)
-                        then emap
-                        else mapAdd emap e
-
--- |Delete the first occurrence of the key from the lookup map.
---
---  If the key does not exist in the map then no change is made.
---
-mapDelete :: (LookupEntryClass a k v) =>
-    LookupMap a -> k -> LookupMap a
-mapDelete l@(LookupMap []) _ = l
-mapDelete (LookupMap (e:es)) k
-    | k == entryKey e   = LookupMap es
-    | otherwise         = mapAdd more e where
-        more = mapDelete (LookupMap es) k
-
--- |Delete all occurrences of the key from the lookup map.
---
-mapDeleteAll :: (LookupEntryClass a k v) =>
-    LookupMap a -> k -> LookupMap a
-mapDeleteAll l@(LookupMap []) _ = l
-mapDeleteAll (LookupMap (e:es)) k =
-    let more = mapDeleteAll (LookupMap es) k
-    in if entryKey e == k then more else mapAdd more e
-        
--- |Compare two lookup maps for equality.
---
---  Two maps are equal if they have the same set of keys, and if
---  each key maps to an equivalent value. This is only guaranteed
---  if the maps do not contain duplicate entries.
---
-mapEq :: (LookupEntryClass a k v, Ord k, Eq v) =>
-    LookupMap a -> LookupMap a -> Bool
-mapEq es1 es2 =
-    ks1 == ks2 &&
-    and [ mapFindMaybe k es1 == mapFindMaybe k es2 | k <- S.toList ks1 ]
-    -- TODO: improve the above
-  where
-      ks1 = setKeys es1
-      ks2 = setKeys es2
-
--- |Return the list of distinct keys in a supplied LookupMap
---
-mapKeys :: (LookupEntryClass a k v) =>
-    LookupMap a -> [k]
-mapKeys = L.nub . gLM . fmap entryKey
-
--- | Return the set of keys in the LookupMap.
-setKeys :: 
-    (LookupEntryClass a k v, Ord k)
-    => LookupMap a
-    -> S.Set k
-setKeys = S.fromList . gLM . fmap entryKey
-
--- |Return list of distinct values in a supplied LookupMap
---
-mapVals :: (Eq v, LookupEntryClass a k v) =>
-    LookupMap a -> [v]
-mapVals = L.nub . gLM . fmap entryVal
-
-{-
--- | Returns the set of values in the LookupMap.
---
-setVals ::
-  (LookupEntryClass a k v, Ord v)
-  => LookupMap a
-  -> S.Set v
-setVals = S.fromList . gLM . fmap entryVal
--}
-
--- |Merge two lookup maps, ensuring that if the same key appears
---  in both maps it is associated with the same value.
---
-mapMerge :: (LookupEntryClass a k v, Eq a, Show a, Ord k) =>
-    LookupMap a -> LookupMap a -> LookupMap a
-mapMerge a b = LookupMap $ on merge (L.sortBy keyOrder . gLM) a b
-    where
-        merge es1 [] = es1
-        merge [] es2 = es2
-        merge es1@(e1:et1) es2@(e2:et2) =
-            case keyOrder e1 e2 of
-                LT -> e1 : merge et1 es2
-                GT -> e2 : merge es1 et2
-                EQ -> if e1 /= e2
-                        then error ("mapMerge key conflict: " ++ show e1
-                                    ++ " with " ++ show e2)
-                        else e1 : merge et1 et2
-
---------------------------------------------------------------------------------
---
---  Copyright (c) 2003, Graham Klyne, 2009 Vasili I Galchin,
---    2011, 2012 Douglas Burke
---  All rights reserved.
---
---  This file is part of Swish.
---
---  Swish is free software; you can redistribute it and/or modify
---  it under the terms of the GNU General Public License as published by
---  the Free Software Foundation; either version 2 of the License, or
---  (at your option) any later version.
---
---  Swish is distributed in the hope that it will be useful,
---  but WITHOUT ANY WARRANTY; without even the implied warranty of
---  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
---  GNU General Public License for more details.
---
---  You should have received a copy of the GNU General Public License
---  along with Swish; if not, write to:
---    The Free Software Foundation, Inc.,
---    59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
---
---------------------------------------------------------------------------------
   This definitely speeds up some operations but
   a full analysis has not been attempted.
   .
+  * Replaced used of @Data.LookupMap@ with @Data.Map.Map@. This has led to the
+  removal of a number of language extensions from some modules.
+  .
   * A few other minor changes have been made: the removal of @subset@ and
   @equiv@ from
   @Swish.Utils.ListHelpers@; the ordering used for @RDFLabel@ values has
 
    Exposed-Modules:
       Data.Interned.URI
-      Data.LookupMap
       Data.Ord.Partial
       Data.String.ShowLines
       Network.URI.Ord
       HUnit == 1.2.*,
       swish
 
-Test-Suite test-lookupmap
-   type:       exitcode-stdio-1.0
-   Hs-Source-Dirs: tests/
-   Main-Is:        LookupMapTest.hs
-   Other-Modules:  TestHelpers
-
-   ghc-options:
-      -Wall -fno-warn-orphans
-
-   Build-Depends:
-      base,
-      containers,
-      HUnit == 1.2.*,
-      swish
-
 Test-Suite test-qname
    type:       exitcode-stdio-1.0
    Hs-Source-Dirs: tests/

tests/LookupMapTest.hs

-{-# LANGUAGE FlexibleInstances, FlexibleContexts, MultiParamTypeClasses #-}
---------------------------------------------------------------------------------
---  See end of this file for licence information.
---------------------------------------------------------------------------------
--- |
---  Module      :  LookupMapTest
---  Copyright   :  (c) 2003, Graham Klyne, 2009 Vasili I Galchin, 2011 Douglas Burke
---  License     :  GPL V2
---
---  Maintainer  :  Douglas Burke
---  Stability   :  experimental
---  Portability :  FlexibleInstances, FlexibleContexts, MultiParamTypeClasses
---
--- This Module defines test cases for module Parse parsing functions.
---
---------------------------------------------------------------------------------
-
-module Main where
-
-import Data.LookupMap
-    ( LookupEntryClass(..), LookupMap(..)
-    , makeLookupMap
-    , reverseLookupMap
-    , mapFind, mapContains
-    , mapReplace, mapReplaceAll, mapReplaceMap
-    , mapAdd, mapAddIfNew
-    , mapDelete, mapDeleteAll
-    , mapEq, mapKeys, mapVals
-    , mapMerge
-    )
-
-import Data.List ( sort )
-
-import Test.HUnit ( Test(TestList) )
-
-import TestHelpers (runTestSuite, testEq)
-  
-------------------------------------------------------------
---  Declare lookup entry for testing
-------------------------------------------------------------
-
-data GenMapEntry a b = E a b
-
-instance (Eq a, Show a, Eq b, Show b)
-    => LookupEntryClass (GenMapEntry a b) a b
-    where
-        keyVal   (E k v) = (k,v)
-        newEntry (k,v)   = E k v
-
-instance (Eq a, Show a, Eq b, Show b) => Show (GenMapEntry a b) where
-    show = entryShow
-
-instance (Eq a, Show a, Eq b, Show b) => Eq (GenMapEntry a b) where
-    (==) = entryEq
-
-type TestEntry  = GenMapEntry Int String
-type TestMap    = LookupMap (GenMapEntry Int String)
-type RevTestMap = LookupMap (GenMapEntry String Int)
-type MayTestMap = Maybe RevTestMap
-type StrTestMap = LookupMap (GenMapEntry String String)
-
-------------------------------------------------------------
---  LookupMap functions
-------------------------------------------------------------
-
-newMap :: [(Int,String)] -> TestMap
-newMap es = makeLookupMap (map newEntry es)
-
-testLookupMap :: String -> TestMap -> [(Int,String)] -> Test
-testLookupMap lab m1 m2 = testEq ("LookupMap"++lab ) (newMap m2) m1
-
-testLookupMapFind :: String -> TestMap -> Int -> String -> Test
-testLookupMapFind lab lm k res =
-    testEq ("LookupMapFind"++lab ) res (mapFind "" k lm)
-
-lm00, lm01, lm02, lm03, lm04, lm05, lm06, lm07, lm08, lm09 :: TestMap
-lm00 = newMap []
-lm01 = mapAdd lm00 $ newEntry (1,"aaa")
-lm02 = mapAdd lm01 $ newEntry (2,"bbb")
-lm03 = mapAdd lm02 $ newEntry (3,"ccc")
-lm04 = mapAdd lm03 $ newEntry (2,"bbb")
-lm05 = mapReplaceAll lm04 $ newEntry (2,"bbb1")
-lm06 = mapReplaceAll lm05 $ newEntry (9,"zzzz")
-lm07 = mapReplace lm06 $ newEntry (2,"bbb")
-lm08 = mapDelete lm07 3
-lm09 = mapDeleteAll lm08 2
-
-lm20, lm21, lm22, lm33, lm34, lm35, lm36 :: TestMap
-lm20 = mapReplaceMap lm05 $ newMap [(2,"bbb20"),(3,"ccc20")]
-lm21 = mapReplaceMap lm05 $ newMap []
-lm22 = mapReplaceMap lm05 $ newMap [(9,"zzz22"),(1,"aaa22")]
-lm33 = mapAddIfNew lm22 $ newEntry (1,"aaa33")
-lm34 = mapAddIfNew lm22 $ newEntry (4,"ddd34")
-lm35 = mapReplace lm22 (newEntry (1,"aaa35"))
-lm36 = mapReplace lm22 (newEntry (4,"ddd36"))
-
-testLookupMapSuite :: Test
-testLookupMapSuite = 
-  TestList
-  [ testLookupMap     "00" lm00 []
-  , testLookupMapFind "00" lm00 2 ""
-  , testLookupMap     "01" lm01 [(1,"aaa")]
-  , testLookupMapFind "01" lm01 2 ""
-  , testLookupMap     "02" lm02 [(2,"bbb"),(1,"aaa")]
-  , testLookupMapFind "02" lm02 2 "bbb"
-  , testLookupMap     "03" lm03 [(3,"ccc"),(2,"bbb"),(1,"aaa")]
-  , testLookupMapFind "03" lm03 2 "bbb"
-  , testLookupMap     "04" lm04 [(2,"bbb"),(3,"ccc"),(2,"bbb"),(1,"aaa")]
-  , testLookupMapFind "04" lm04 2 "bbb"
-  , testLookupMap     "05" lm05 [(2,"bbb1"),(3,"ccc"),(2,"bbb1"),(1,"aaa")]
-  , testLookupMapFind "05" lm05 2 "bbb1"
-  , testLookupMap     "06" lm06 [(2,"bbb1"),(3,"ccc"),(2,"bbb1"),(1,"aaa")]
-  , testLookupMapFind "06" lm06 2 "bbb1"
-  , testLookupMap     "07" lm07 [(2,"bbb"),(3,"ccc"),(2,"bbb1"),(1,"aaa")]
-  , testLookupMapFind "07" lm07 2 "bbb"
-  , testLookupMapFind "0x" lm07 9 ""
-  , testLookupMap     "08" lm08 [(2,"bbb"),(2,"bbb1"),(1,"aaa")]
-  , testLookupMapFind "08" lm08 2 "bbb"
-  , testLookupMap     "09" lm09 [(1,"aaa")]
-  , testLookupMapFind "09" lm09 2 ""
-  , testLookupMap     "20" lm20 [(2,"bbb20"),(3,"ccc20"),(2,"bbb20"),(1,"aaa")]
-  , testLookupMapFind "20" lm20 2 "bbb20"
-  , testLookupMap     "21" lm21 [(2,"bbb1"),(3,"ccc"),(2,"bbb1"),(1,"aaa")]
-  , testLookupMapFind "21" lm21 2 "bbb1"
-  , testLookupMap     "22" lm22 [(2,"bbb1"),(3,"ccc"),(2,"bbb1"),(1,"aaa22")]
-  , testLookupMapFind "22" lm22 1 "aaa22"
-  , testEq "LookupContains31" True  (mapContains lm22 2)
-  , testEq "LookupContains32" False (mapContains lm22 9)
-  , testLookupMap      "33" lm33 [(2,"bbb1"),(3,"ccc"),(2,"bbb1"),(1,"aaa22")]
-  , testLookupMapFind "33a" lm33 1 "aaa22"
-  , testLookupMapFind "33b" lm33 4 ""
-  , testLookupMap      "34" lm34 [(4,"ddd34"),(2,"bbb1"),(3,"ccc"),(2,"bbb1"),(1,"aaa22")]
-  , testLookupMapFind "34a" lm34 1 "aaa22"
-  , testLookupMapFind "34b" lm34 4 "ddd34"
-  , testLookupMap      "35" lm35 [(2,"bbb1"),(3,"ccc"),(2,"bbb1"),(1,"aaa35")]
-  , testLookupMapFind "35a" lm35 1 "aaa35"
-  , testLookupMapFind "35b" lm35 4 ""
-  , testLookupMap      "36" lm36 [(2,"bbb1"),(3,"ccc"),(2,"bbb1"),(1,"aaa22"),(4,"ddd36")]
-  , testLookupMapFind "36a" lm36 1 "aaa22"
-  , testLookupMapFind "36b" lm36 4 "ddd36"
-  ]
-
-------------------------------------------------------------
---  Reverse lookup map test tests
-------------------------------------------------------------
-
-revdef :: Int
-revdef = -1
-
-newRevMap :: [(String,Int)] -> RevTestMap
-newRevMap es = makeLookupMap (map newEntry es)
-
-testRevLookupMap :: String -> RevTestMap -> [(String,Int)] -> Test
-testRevLookupMap lab m1 m2 =
-    testEq ("RevLookupMap"++lab) (newRevMap m2) m1
-
-testRevLookupMapFind :: String -> RevTestMap -> String -> Int -> Test
-testRevLookupMapFind lab lm k res =
-    testEq ("RevLookupMapFind"++lab) res (mapFind revdef k lm)
-
-rlm00 :: RevTestMap
-rlm00 = reverseLookupMap lm00
-
-rlm01 :: RevTestMap
-rlm01 = reverseLookupMap lm01
-
-rlm02 :: RevTestMap
-rlm02 = reverseLookupMap lm02
-
-rlm03 :: RevTestMap
-rlm03 = reverseLookupMap lm03
-
-rlm04 :: RevTestMap
-rlm04 = reverseLookupMap lm04
-
-rlm05 :: RevTestMap
-rlm05 = reverseLookupMap lm05
-
-rlm06 :: RevTestMap
-rlm06 = reverseLookupMap lm06
-
-rlm07 :: RevTestMap
-rlm07 = reverseLookupMap lm07
-
-rlm08 :: RevTestMap
-rlm08 = reverseLookupMap lm08
-
-rlm09 :: RevTestMap
-rlm09 = reverseLookupMap lm09
-
-testRevLookupMapSuite :: Test
-testRevLookupMapSuite = 
-  TestList
-  [ testRevLookupMap     "00" rlm00 []
-  , testRevLookupMapFind "00" rlm00 "" revdef
-  , testRevLookupMap     "01" rlm01 [("aaa",1)]
-  , testRevLookupMapFind "01" rlm01 "bbb" revdef
-  , testRevLookupMap     "02" rlm02 [("bbb",2),("aaa",1)]
-  , testRevLookupMapFind "02" rlm02 "bbb" 2
-  , testRevLookupMap     "03" rlm03 [("ccc",3),("bbb",2),("aaa",1)]
-  , testRevLookupMapFind "03" rlm03 "bbb" 2
-  , testRevLookupMap     "04" rlm04 [("bbb",2),("ccc",3),("bbb",2),("aaa",1)]
-  , testRevLookupMapFind "04" rlm04 "bbb" 2
-  , testRevLookupMap     "05" rlm05 [("bbb1",2),("ccc",3),("bbb1",2),("aaa",1)]
-  , testRevLookupMapFind "05" rlm05 "bbb1" 2
-  , testRevLookupMap     "06" rlm06 [("bbb1",2),("ccc",3),("bbb1",2),("aaa",1)]
-  , testRevLookupMapFind "06" rlm06 "bbb1" 2
-  , testRevLookupMap     "07" rlm07 [("bbb",2),("ccc",3),("bbb1",2),("aaa",1)]
-  , testRevLookupMapFind "07" rlm07 "bbb" 2
-  , testRevLookupMapFind "07" rlm07 "bbb1" 2
-  , testRevLookupMapFind "0x" rlm07 "*" revdef
-  , testRevLookupMap     "08" rlm08 [("bbb",2),("bbb1",2),("aaa",1)]
-  , testRevLookupMapFind "08" rlm08 "bbb" 2
-  , testRevLookupMap     "09" rlm09 [("aaa",1)]
-  , testRevLookupMapFind "09" rlm09 "" revdef
-  ]    
-
-------------------------------------------------------------
---  mapKeys
-------------------------------------------------------------
-
-testMapKeys :: String -> TestMap -> [Int] -> Test
-testMapKeys lab m1 mk =
-    testEq ("testMapKeys:"++lab) mk (sort $ mapKeys m1)
-
-testMapKeysSuite :: Test
-testMapKeysSuite = 
-  TestList
-  [ testMapKeys "00" lm00 []
- ,  testMapKeys "01" lm01 [1]
- ,  testMapKeys "02" lm02 [1,2]
- ,  testMapKeys "03" lm03 [1,2,3]
- ,  testMapKeys "04" lm04 [1,2,3]
- ,  testMapKeys "05" lm05 [1,2,3]
- ,  testMapKeys "06" lm06 [1,2,3]
- ,  testMapKeys "07" lm07 [1,2,3]
- ,  testMapKeys "08" lm08 [1,2]
- ,  testMapKeys "09" lm09 [1]
- ]
-
-------------------------------------------------------------
---  mapVals
-------------------------------------------------------------
-
-testMapVals :: String -> TestMap -> [String] -> Test
-testMapVals lab m1 mv =
-    testEq ("MapVals:"++lab) mv (sort $ mapVals m1)
-
-testMapValsSuite :: Test
-testMapValsSuite =
-  TestList
-  [ testMapVals "00" lm00 []
-  , testMapVals "01" lm01 ["aaa"]
-  , testMapVals "02" lm02 ["aaa","bbb"]
-  , testMapVals "03" lm03 ["aaa","bbb","ccc"]
-  , testMapVals "04" lm04 ["aaa","bbb","ccc"]
-  , testMapVals "05" lm05 ["aaa","bbb1","ccc"]
-  , testMapVals "06" lm06 ["aaa","bbb1","ccc"]
-  , testMapVals "07" lm07 ["aaa","bbb","bbb1","ccc"]
-  , testMapVals "08" lm08 ["aaa","bbb","bbb1"]
-  , testMapVals "09" lm09 ["aaa"]
-  ]
-
-------------------------------------------------------------
---  mapEq
-------------------------------------------------------------
-
-maplist :: [(String, TestMap)]
-maplist =
-  [ ("lm00",lm00)
-  , ("lm01",lm01)
-  , ("lm02",lm02)
-  , ("lm03",lm03)
-  , ("lm04",lm04)
-  , ("lm05",lm05)
-  , ("lm06",lm06)
-  , ("lm07",lm07)
-  , ("lm08",lm08)
-  , ("lm09",lm09)
-  ]
-
-mapeqlist :: [(String, String)]
-mapeqlist =
-  [ ("lm01","lm09")
-  , ("lm02","lm08")
-  , ("lm03","lm04")
-  , ("lm03","lm07")
-  , ("lm04","lm07")
-  , ("lm05","lm06")
-  ]
-
-testMapEq :: String -> Bool -> TestMap -> TestMap -> Test
-testMapEq lab eq m1 m2 =
-    testEq ("testMapEq:"++lab) eq (mapEq m1 m2)
-
-testMapEqSuite :: Test
-testMapEqSuite = TestList
-  [ testMapEq (testLab l1 l2) (nodeTest l1 l2) m1 m2
-      | (l1,m1) <- maplist , (l2,m2) <- maplist ]
-    where
-    testLab l1 l2 = l1 ++ "-" ++ l2
-    nodeTest  l1 l2 = (l1 == l2)       ||
-            (l1,l2) `elem` mapeqlist ||
-            (l2,l1) `elem` mapeqlist
-
-------------------------------------------------------------
---  mapSelect and mapMerge
-------------------------------------------------------------
-
-lm101, lm102, lm103, lm104 :: TestMap
-lm101 = mapAdd lm03 $ newEntry (4,"ddd")
-{-
-lm102 = mapSelect lm101 [1,3]
-lm103 = mapSelect lm101 [2,4]
-lm104 = mapSelect lm101 [2,3]
--}
-
-lm102 = mapAdd (mapAdd (newMap []) (newEntry (1,"aaa"))) $ newEntry (3,"ccc")
-lm103 = mapAdd (mapAdd (newMap []) (newEntry (2,"bbb"))) $ newEntry (4,"ddd")
-lm104 = mapAdd (mapAdd (newMap []) (newEntry (2,"bbb"))) $ newEntry (3,"ccc")
-
-lm105, lm106, lm107, lm108 :: TestMap
-lm105 = mapMerge lm102 lm103
-lm106 = mapMerge lm102 lm104
-lm107 = mapMerge lm103 lm104
-lm108 = mapMerge lm101 lm102
-
-mapMergeSuite :: Test
-mapMergeSuite =
-  TestList
-  [ testLookupMap "101" lm101 [(4,"ddd"),(3,"ccc"),(2,"bbb"),(1,"aaa")]
-  , testLookupMap "105" lm105 [(1,"aaa"),(2,"bbb"),(3,"ccc"),(4,"ddd")]
-  , testLookupMap "106" lm106 [(1,"aaa"),(2,"bbb"),(3,"ccc")]
-  , testLookupMap "107" lm107 [(2,"bbb"),(3,"ccc"),(4,"ddd")]
-  , testLookupMap "108" lm108 [(1,"aaa"),(2,"bbb"),(3,"ccc"),(4,"ddd")]
-  ] 
-  
-------------------------------------------------------------
---  All tests
-------------------------------------------------------------
-
-allTests :: Test
-allTests = TestList
-  [ testLookupMapSuite
-  , testRevLookupMapSuite
-  , testMapKeysSuite
-  , testMapValsSuite
-  , testMapEqSuite
-  , mapMergeSuite
-  ]
-
-main :: IO ()
-main = runTestSuite allTests
-
-{-
-runTestFile t = do
-    h <- openFile "a.tmp" WriteMode
-    runTestText (putTextToHandle h False) t
-    hClose h
-tf = runTestFile
-tt = runTestTT
--}
-
---------------------------------------------------------------------------------
---
---  Copyright (c) 2003, Graham Klyne, 2009 Vasili I Galchin, 2011 Douglas Burke
---  All rights reserved.
---
---  This file is part of Swish.
---
---  Swish is free software; you can redistribute it and/or modify
---  it under the terms of the GNU General Public License as published by
---  the Free Software Foundation; either version 2 of the License, or
---  (at your option) any later version.
---
---  Swish is distributed in the hope that it will be useful,
---  but WITHOUT ANY WARRANTY; without even the implied warranty of
---  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
---  GNU General Public License for more details.
---
---  You should have received a copy of the GNU General Public License
---  along with Swish; if not, write to:
---    The Free Software Foundation, Inc.,
---    59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
---
---------------------------------------------------------------------------------