PreviousUpNext

15.4.950  src/lib/src/list-map-g.pkg

## list-map-g.pkg

# Compiled by:
#     src/lib/std/standard.lib

# An implementation of finite maps on ordered keys
# which uses a sorted list representation. Normally
#     src/lib/src/red-black-map-g.pkg
# is preferred.



###           "More people have ascended bodily into heaven
###            than have shipped great software on time."
###
###                                 -- Jim McCarthy



generic package list_map_g (k:  Key)                    # Key           is from   src/lib/src/key.api
:
Map                                                     # Map   is from   src/lib/src/map.api
where
    key::Key == k::Key
=
package {
    package key = k;

    Map(X) = List ((k::Key, X)); 

    empty = [];

    fun is_empty [] =>  TRUE;
        is_empty _  =>  FALSE;
    end;

    # Return the first item in the map
    # or NULL if it is empty:
    #
    fun first_val_else_null [] => NULL;
        first_val_else_null ((_, value) ! _) => THE value;
    end;

    # Return the first item in the map
    # and its key, or NULL if it is empty:
    #
    fun first_keyval_else_null [] => NULL;
        first_keyval_else_null ((key, value) ! _) => THE (key, value);
    end;

    # Return the last item in the map
    # or NULL if it is empty:
    #
    fun last_val_else_null []                =>  NULL;
        last_val_else_null ((_, value) ! []) =>  THE value;
        last_val_else_null (_ ! rest)        =>  last_val_else_null  rest;
    end;

    # Return the last item in the map
    # and its key, or NULL if it is empty:
    #
    fun last_keyval_else_null []                  =>  NULL;
        last_keyval_else_null ((key, value) ! []) =>  THE (key, value);
        last_keyval_else_null (_ ! rest)          =>  last_keyval_else_null  rest;
    end;

    fun singleton (key, item)
        =
        [(key, item)];

    fun debug_print   (map, print_key, print_val) = 0;                  # Placeholder
    fun all_invariants_hold map = TRUE;                                 # Placeholder

    fun set (l, key, item)
        =
        f l
        where
            fun f []
                    =>
                    [(key, item)];

                f ((element as (key', _)) ! r)
                    =>
                    case (key::compare (key, key'))
                        #
                        LESS    => (key, item) ! element ! r;
                        EQUAL   => (key, item) ! r;
                        GREATER => element ! (f r);
                    esac;
             end;
        end;


    fun m $ (x, v)
        =
        set (m, x, v);


    fun set' ((k, x), m)
        =
        set (m, k, x);

    # Return TRUE if the key is in the map's domain:
    #
    fun contains_key (l, key)
        =
        f l
        where
            fun f ((key', x) ! r)
                    =>
                    case (key::compare (key, key'))
                        #
                        LESS    => FALSE;
                        EQUAL   => TRUE;
                        GREATER => f r;
                    esac;

                f [] => FALSE;
            end;
        end;

    fun preceding_key (l, key)
        =
        f (l, NULL)
        where
            fun f  ((key', x) ! r,  result)
                    =>
                    case (key::compare (key, key'))
                        #
                        LESS    => result;
                        EQUAL   => result;
                        GREATER => f (r, THE key');
                    esac;

                f ([], result) => result;
            end;
        end;
    fun following_key (l, key)
        =
        f l
        where
            fun f  ((key', x) ! r)
                    =>
                    case (key::compare (key, key'))
                        #
                        LESS    => THE key';
                        EQUAL   => f r;
                        GREATER => f r;
                    esac;

                f [] => NULL;
            end;
        end;


    # Search on a key, return (THE value) if found,
    # else return NULL.
    #
    fun get (l, key)
        =
        f l
        where
            fun f ((key', x) ! r)
                    =>
                    case (key::compare (key, key'))
                        #
                        LESS    => NULL;
                        EQUAL   => THE x;
                        GREATER => f r;
                    esac;

                f [] => NULL;
            end;
          
        end;

    # Search on a key, return value if found,
    # else raise lib_base::NOT_FOUND
    #
    fun get_or_raise_exception_not_found (l, key)
        =
        f l
        where
            fun f ((key', x) ! r)
                    =>
                    case (key::compare (key, key'))
                        #
                        LESS    =>  raise exception lib_base::NOT_FOUND;
                        EQUAL   =>  x;
                        GREATER =>  f r;
                    esac;

                f [] => raise exception lib_base::NOT_FOUND;
            end;
          
        end;

    stipulate
        # Remove an item, returning new map and value removed.
        # Raise Lib_base::NOT_FOUND if not found.
        #
        fun drop' (l, key)
            =
            f ([], l)
            where
                fun f (_, [])
                        =>
                        raise exception lib_base::NOT_FOUND;

                    f (prefix, (element as (key', x)) ! r)
                        =>
                        case (key::compare (key, key'))
                            #
                            LESS    =>   raise exception lib_base::NOT_FOUND;
                            EQUAL   =>   (list::reverse_and_prepend (prefix, r), x);
                            GREATER =>   f (element ! prefix, r);
                        esac;
                end;
            end;
    herein
        fun drop (old_map, key_to_drop)                         # Return new_map, or old_map if key_to_drop was not found.
            =
            #1 (drop' (old_map, key_to_drop))
            except
                lib_base::NOT_FOUND = old_map;

        fun get_and_drop (old_map, key_to_drop)                         # Return (new_map, THE value)  or (old_map, NULL) if key_to_drop was not found.
            =
            {   (drop' (old_map, key_to_drop))
                    ->
                    (new_map, val);

                (new_map, THE val);
            }
            except
                lib_base::NOT_FOUND = (old_map, NULL);
    end;

    # Return the number of items in the map 
    #
    fun vals_count l
        =
        list::length l;


    # Return a list of the items (and their keys) in the map 
    #
    fun vals_list (l:  Map(X))
        =
        list::map #2 l;


    fun keyvals_list l
        =
        l;


    fun keys_list (l:  Map(X))
        =
        list::map #1 l;


    fun compare_sequences compare_rng
        =
        compare
        where   
    fun compare ([], []) => EQUAL;
                compare ([], _) => LESS;
                compare (_, []) => GREATER;

                compare ((x1, y1) ! r1, (x2, y2) ! r2)
                    =>
                    case (key::compare (x1, x2))
                        #
                        EQUAL =>    case (compare_rng (y1, y2))
                                        #
                                        EQUAL => compare (r1, r2);
                                        order => order;
                                    esac;

                        order => order;
                    esac;
            end;
        end;


    fun difference_with (m1, m2)
        =
        {   keys_to_remove =  keys_list  m2;
            #
            remove (m1, keys_to_remove)
            where
                fun remove (m1, [])
                        =>
                        m1;

                    remove (m1, key ! rest)
                        =>
                        remove (drop (m1, key), rest);
                end;
            end;
        };

    fun from_list (pairs: List((key::Key, X)))
        =
        {   tree = empty;
            #
            add (tree, pairs)
            where
                fun add (tree, [])
                        =>
                        tree;

                    add (tree, (key,val) ! rest)
                        =>
                        add (set (tree, key, val), rest);
                end;
            end;
        };

    # Return a map whose domain is the union
    # of the domains of the two input maps,
    # using the supplied function to define
    # the map on elements that are in both
    # domains.
    #
    fun union_with f (m1:  Map(X), m2:  Map(X))
        =
        merge (m1, m2, [])
        where
            fun merge ([], [], l) => list::reverse l;
                merge ([], m2, l) => list::reverse_and_prepend (l, m2);
                merge (m1, [], l) => list::reverse_and_prepend (l, m1);

                merge (m1 as ((k1, x1) ! r1), m2 as ((k2, x2) ! r2), l)
                    =>
                    case (key::compare (k1, k2))
                        #
                        LESS    => merge (r1, m2, (k1, x1) ! l);
                        EQUAL   => merge (r1, r2, (k1, f (x1, x2)) ! l);
                        GREATER => merge (m1, r2, (k2, x2) ! l);
                    esac;
            end;
        end;


    fun keyed_union_with f (m1:  Map(X), m2:  Map(X))
        =
        merge (m1, m2, [])
        where
            fun merge ([], [], l) => list::reverse l;
                merge ([], m2, l) => list::reverse_and_prepend (l, m2);
                merge (m1, [], l) => list::reverse_and_prepend (l, m1);

                merge (m1 as ((k1, x1) ! r1), m2 as ((k2, x2) ! r2), l)
                    =>
                    case (key::compare (k1, k2))
                        #
                        LESS    => merge (r1, m2, (k1, x1) ! l);
                        EQUAL   => merge (r1, r2, (k1, f (k1, x1, x2)) ! l);
                        GREATER => merge (m1, r2, (k2, x2) ! l);
                    esac;
            end;
        end;


    # Return a map whose domain is the
    # intersection of the domains of the
    # two input maps, using the supplied
    # function to define the range.
    #
    fun intersect_with f (m1:  Map(X), m2:  Map(Y))
        =
        merge (m1, m2, [])
        where
            fun merge (m1 as ((k1, x1) ! r1), m2 as ((k2, x2) ! r2), l)
                    =>
                    case (key::compare (k1, k2))
                        #
                        LESS    => merge (r1, m2, l);
                        EQUAL   => merge (r1, r2, (k1, f (x1, x2)) ! l);
                        GREATER => merge (m1, r2, l);
                    esac;

                merge (_, _, l)
                    =>
                    list::reverse l;
            end;
        end;

    fun keyed_intersect_with f (m1:  Map(X), m2:  Map(Y))
        =
        merge (m1, m2, [])
        where
            fun merge (m1 as ((k1, x1) ! r1), m2 as ((k2, x2) ! r2), l)
                    =>
                    case (key::compare (k1, k2))
                        #
                        LESS    => merge (r1, m2, l);
                        EQUAL   => merge (r1, r2, (k1, f (k1, x1, x2)) ! l);
                        GREATER => merge (m1, r2, l);
                   esac;

                merge (_, _, l)
                    =>
                    list::reverse l;
            end;
        end;

    fun merge_with f (m1:  Map(X), m2:  Map(Y))
        =
        merge (m1, m2, [])
        where
            fun merge (m1 as ((k1, x1) ! r1), m2 as ((k2, x2) ! r2), l)
                    =>
                    case (key::compare (k1, k2))
                        #                                       
                        LESS    => mergef (k1, THE x1, NULL,   r1, m2, l);
                        EQUAL   => mergef (k1, THE x1, THE x2, r1, r2, l);
                        GREATER => mergef (k2, NULL,   THE x2, m1, r2, l);
                    esac;

                merge ([], [], l) => list::reverse l;
                merge ((k1, x1) ! r1, [], l) => mergef (k1, THE x1, NULL, r1, [], l);
                merge ([], (k2, x2) ! r2, l) => mergef (k2, NULL, THE x2, [], r2, l);
            end 

            also
            fun mergef (k, x1, x2, r1, r2, l)
                =
                case (f (x1, x2))
                    #                                   
                    NULL  => merge (r1, r2, l);
                    THE y => merge (r1, r2, (k, y) ! l);
                esac;
        end;

    fun keyed_merge_with f (m1:  Map(X), m2:  Map(Y))
        =
        merge (m1, m2, [])
        where
            fun merge ( m1 as ((k1, x1) ! r1),
                        m2 as ((k2, x2) ! r2),
                        l
                      )
                    =>
                    case (key::compare (k1, k2))
                        #                                       
                        LESS    =>  mergef (k1, THE x1, NULL,   r1, m2, l);
                        EQUAL   =>  mergef (k1, THE x1, THE x2, r1, r2, l);
                        GREATER =>  mergef (k2, NULL,   THE x2, m1, r2, l);
                    esac;

                merge ([], [], l) => list::reverse l;
                merge ((k1, x1) ! r1, [], l) => mergef (k1, THE x1, NULL, r1, [], l);
                merge ([], (k2, x2) ! r2, l) => mergef (k2, NULL, THE x2, [], r2, l);
            end 

            also
            fun mergef (k, x1, x2, r1, r2, l)
                =
                case (f (k, x1, x2))
                     #                                  
                     NULL  =>  merge (r1, r2, l);
                     THE y =>  merge (r1, r2, (k, y) ! l);
                esac;

        end;


    # Apply a function to the entries
    # of the map in map order:

    keyed_apply = list::apply;

    fun apply f l
        =
        keyed_apply
            (\\ (_, item) = f item)
            l;

    # Create a new table by applying
    # a map function to the name/value
    # pairs in the table.

    fun keyed_map f l
        =
        list::map
            (\\ (key, item) = (key, f (key, item)))
            l;

    fun map f l
        =
        list::map
            (\\ (key, item) = (key, f item))
            l;


    # Apply a folding function
    # to the entries of the map
    # in increasing map order.

    fun keyed_fold_forward f init l
        =
        list::fold_forward
            (\\ ((key, item), accum) = f (key, item, accum))
            init
            l;

    fun fold_forward f init l
        =
        list::fold_forward
            (\\ ((_, item), accum) =  f (item, accum))
            init
            l;


    # Apply a folding function
    # to the entries of the map
    # in decreasing map order.

    fun keyed_fold_backward f init l
        =
        list::fold_backward
            (\\ ((key, item), accum) = f (key, item, accum))
            init
            l;

    fun fold_backward f init l
        =
        list::fold_backward
            (\\ ((_, item), accum) = f (item, accum))
            init
            l;

    fun filter predicate l
        =
        list::filter
            (\\ (_, item) = predicate item)
            l;

    fun keyed_filter predicate l
        =
        list::filter predicate l;


    fun keyed_map' f l
        =
        list::map_partial_fn f' l
        where
            fun f' (key, item)
                =
                case (f (key, item))
                    #   
                    THE y =>  THE (key, y);
                    NULL  =>  NULL;
                esac;
        end;

    fun map' f l
        =
        keyed_map'
            (\\ (_, item) = f item)
            l;

};                                      #  generic package list_map_g 



## COPYRIGHT (c) 1996 by AT&T Research.  See SMLNJ-COPYRIGHT file for details.
## Subsequent changes by Jeff Prothero Copyright (c) 2010-2015,
## released per terms of SMLNJ-COPYRIGHT.


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext