src/HOL/Tools/polyhash.ML
changeset 32960 69916a850301
parent 32740 9dd0a2f83429
equal deleted inserted replaced
32959:23a8c5ac35f8 32960:69916a850301
   104   = NIL
   104   = NIL
   105   | B of int * 'key * 'data * ('key, 'data) bucket_t
   105   | B of int * 'key * 'data * ('key, 'data) bucket_t
   106 
   106 
   107 datatype ('key, 'data) hash_table = 
   107 datatype ('key, 'data) hash_table = 
   108     HT of {hashVal   : 'key -> int,
   108     HT of {hashVal   : 'key -> int,
   109 	   sameKey   : 'key * 'key -> bool,
   109            sameKey   : 'key * 'key -> bool,
   110 	   not_found : exn,
   110            not_found : exn,
   111 	   table     : ('key, 'data) bucket_t Array.array Unsynchronized.ref,
   111            table     : ('key, 'data) bucket_t Array.array Unsynchronized.ref,
   112 	   n_items   : int Unsynchronized.ref}
   112            n_items   : int Unsynchronized.ref}
   113 
   113 
   114 local
   114 local
   115 (*
   115 (*
   116     prim_val andb_      : int -> int -> int = 2 "and";
   116     prim_val andb_      : int -> int -> int = 2 "and";
   117     prim_val lshift_    : int -> int -> int = 2 "shift_left";
   117     prim_val lshift_    : int -> int -> int = 2 "shift_left";
   121 in 
   121 in 
   122     fun index (i, sz) = andb_ i (sz-1)
   122     fun index (i, sz) = andb_ i (sz-1)
   123 
   123 
   124   (* find smallest power of 2 (>= 32) that is >= n *)
   124   (* find smallest power of 2 (>= 32) that is >= n *)
   125     fun roundUp n = 
   125     fun roundUp n = 
   126 	let fun f i = if (i >= n) then i else f (lshift_ i 1)
   126         let fun f i = if (i >= n) then i else f (lshift_ i 1)
   127 	in f 32 end
   127         in f 32 end
   128 end;
   128 end;
   129 
   129 
   130   (* Create a new table; the int is a size hint and the exception
   130   (* Create a new table; the int is a size hint and the exception
   131    * is to be raised by find.
   131    * is to be raised by find.
   132    *)
   132    *)
   133     fun mkTable (hashVal, sameKey) (sizeHint, notFound) = HT{
   133     fun mkTable (hashVal, sameKey) (sizeHint, notFound) = HT{
   134             hashVal=hashVal,
   134             hashVal=hashVal,
   135 	    sameKey=sameKey,
   135             sameKey=sameKey,
   136 	    not_found = notFound,
   136             not_found = notFound,
   137 	    table = Unsynchronized.ref (Array.array(roundUp sizeHint, NIL)),
   137             table = Unsynchronized.ref (Array.array(roundUp sizeHint, NIL)),
   138 	    n_items = Unsynchronized.ref 0
   138             n_items = Unsynchronized.ref 0
   139 	  };
   139           };
   140 
   140 
   141   (* conditionally grow a table *)
   141   (* conditionally grow a table *)
   142     fun growTable (HT{table, n_items, ...}) = let
   142     fun growTable (HT{table, n_items, ...}) = let
   143 	    val arr = !table
   143             val arr = !table
   144 	    val sz = Array.length arr
   144             val sz = Array.length arr
   145 	    in
   145             in
   146 	      if (!n_items >= sz)
   146               if (!n_items >= sz)
   147 		then let
   147                 then let
   148 		  val newSz = sz+sz
   148                   val newSz = sz+sz
   149 		  val newArr = Array.array (newSz, NIL)
   149                   val newArr = Array.array (newSz, NIL)
   150 		  fun copy NIL = ()
   150                   fun copy NIL = ()
   151 		    | copy (B(h, key, v, rest)) = let
   151                     | copy (B(h, key, v, rest)) = let
   152 			val indx = index (h, newSz)
   152                         val indx = index (h, newSz)
   153 			in
   153                         in
   154 			  Array.update (newArr, indx,
   154                           Array.update (newArr, indx,
   155 			    B(h, key, v, Array.sub(newArr, indx)));
   155                             B(h, key, v, Array.sub(newArr, indx)));
   156 			  copy rest
   156                           copy rest
   157 			end
   157                         end
   158 		  fun bucket n = (copy (Array.sub(arr, n)); bucket (n+1))
   158                   fun bucket n = (copy (Array.sub(arr, n)); bucket (n+1))
   159 		  in
   159                   in
   160 		    (bucket 0) handle _ => ();  (* FIXME avoid handle _ *)
   160                     (bucket 0) handle _ => ();  (* FIXME avoid handle _ *)
   161 		    table := newArr
   161                     table := newArr
   162 		  end
   162                   end
   163 		else ()
   163                 else ()
   164 	    end (* growTable *);
   164             end (* growTable *);
   165 
   165 
   166   (* Insert an item.  If the key already has an item associated with it,
   166   (* Insert an item.  If the key already has an item associated with it,
   167    * then the old item is discarded.
   167    * then the old item is discarded.
   168    *)
   168    *)
   169     fun insert (tbl as HT{hashVal, sameKey, table, n_items, ...}) (key, item) =
   169     fun insert (tbl as HT{hashVal, sameKey, table, n_items, ...}) (key, item) =
   170 	let
   170         let
   171 	  val arr = !table
   171           val arr = !table
   172 	  val sz = Array.length arr
   172           val sz = Array.length arr
   173 	  val hash = hashVal key
   173           val hash = hashVal key
   174 	  val indx = index (hash, sz)
   174           val indx = index (hash, sz)
   175 	  fun look NIL = (
   175           fun look NIL = (
   176 		Array.update(arr, indx, B(hash, key, item, Array.sub(arr, indx)));
   176                 Array.update(arr, indx, B(hash, key, item, Array.sub(arr, indx)));
   177 		Unsynchronized.inc n_items;
   177                 Unsynchronized.inc n_items;
   178 		growTable tbl;
   178                 growTable tbl;
   179 		NIL)
   179                 NIL)
   180 	    | look (B(h, k, v, r)) = if ((hash = h) andalso sameKey(key, k))
   180             | look (B(h, k, v, r)) = if ((hash = h) andalso sameKey(key, k))
   181 		then B(hash, key, item, r)
   181                 then B(hash, key, item, r)
   182 		else (case (look r)
   182                 else (case (look r)
   183 		   of NIL => NIL
   183                    of NIL => NIL
   184 		    | rest => B(h, k, v, rest)
   184                     | rest => B(h, k, v, rest)
   185 		  (* end case *))
   185                   (* end case *))
   186 	  in
   186           in
   187 	    case (look (Array.sub (arr, indx)))
   187             case (look (Array.sub (arr, indx)))
   188 	     of NIL => ()
   188              of NIL => ()
   189 	      | b => Array.update(arr, indx, b)
   189               | b => Array.update(arr, indx, b)
   190 	  end;
   190           end;
   191 
   191 
   192   (* Insert an item if not there already; if it is there already, 
   192   (* Insert an item if not there already; if it is there already, 
   193      then return the old data value and leave the table unmodified..
   193      then return the old data value and leave the table unmodified..
   194    *)
   194    *)
   195     fun peekInsert (tbl as HT{hashVal, sameKey, table, n_items, ...}) (key, item) =
   195     fun peekInsert (tbl as HT{hashVal, sameKey, table, n_items, ...}) (key, item) =
   196 	let val arr = !table
   196         let val arr = !table
   197 	    val sz = Array.length arr
   197             val sz = Array.length arr
   198 	    val hash = hashVal key
   198             val hash = hashVal key
   199 	    val indx = index (hash, sz)
   199             val indx = index (hash, sz)
   200 	    fun look NIL = 
   200             fun look NIL = 
   201 		(Array.update(arr, indx, B(hash, key, item, 
   201                 (Array.update(arr, indx, B(hash, key, item, 
   202 					   Array.sub(arr, indx)));
   202                                            Array.sub(arr, indx)));
   203 		 Unsynchronized.inc n_items;
   203                  Unsynchronized.inc n_items;
   204 		 growTable tbl;
   204                  growTable tbl;
   205 		 NONE)
   205                  NONE)
   206 	      | look (B(h, k, v, r)) = 
   206               | look (B(h, k, v, r)) = 
   207 		if hash = h andalso sameKey(key, k) then SOME v
   207                 if hash = h andalso sameKey(key, k) then SOME v
   208 		else look r
   208                 else look r
   209 	in
   209         in
   210 	    look (Array.sub (arr, indx))
   210             look (Array.sub (arr, indx))
   211 	end;
   211         end;
   212 
   212 
   213   (* find an item, the table's exception is raised if the item doesn't exist *)
   213   (* find an item, the table's exception is raised if the item doesn't exist *)
   214     fun find (HT{hashVal, sameKey, table, not_found, ...}) key = let
   214     fun find (HT{hashVal, sameKey, table, not_found, ...}) key = let
   215 	  val arr = !table
   215           val arr = !table
   216 	  val sz = Array.length arr
   216           val sz = Array.length arr
   217 	  val hash = hashVal key
   217           val hash = hashVal key
   218 	  val indx = index (hash, sz)
   218           val indx = index (hash, sz)
   219 	  fun look NIL = raise not_found
   219           fun look NIL = raise not_found
   220 	    | look (B(h, k, v, r)) = if ((hash = h) andalso sameKey(key, k))
   220             | look (B(h, k, v, r)) = if ((hash = h) andalso sameKey(key, k))
   221 		then v
   221                 then v
   222 		else look r
   222                 else look r
   223 	  in
   223           in
   224 	    look (Array.sub (arr, indx))
   224             look (Array.sub (arr, indx))
   225 	  end;
   225           end;
   226 
   226 
   227   (* look for an item, return NONE if the item doesn't exist *)
   227   (* look for an item, return NONE if the item doesn't exist *)
   228     fun peek (HT{hashVal, sameKey, table, ...}) key = let
   228     fun peek (HT{hashVal, sameKey, table, ...}) key = let
   229 	  val arr = !table
   229           val arr = !table
   230 	  val sz = Array.length arr
   230           val sz = Array.length arr
   231 	  val hash = hashVal key
   231           val hash = hashVal key
   232 	  val indx = index (hash, sz)
   232           val indx = index (hash, sz)
   233 	  fun look NIL = NONE
   233           fun look NIL = NONE
   234 	    | look (B(h, k, v, r)) = if ((hash = h) andalso sameKey(key, k))
   234             | look (B(h, k, v, r)) = if ((hash = h) andalso sameKey(key, k))
   235 		then SOME v
   235                 then SOME v
   236 		else look r
   236                 else look r
   237 	  in
   237           in
   238 	    look (Array.sub (arr, indx))
   238             look (Array.sub (arr, indx))
   239 	  end;
   239           end;
   240 
   240 
   241   (* Remove an item.  The table's exception is raised if
   241   (* Remove an item.  The table's exception is raised if
   242    * the item doesn't exist.
   242    * the item doesn't exist.
   243    *)
   243    *)
   244     fun remove (HT{hashVal, sameKey, not_found, table, n_items}) key = let
   244     fun remove (HT{hashVal, sameKey, not_found, table, n_items}) key = let
   245 	  val arr = !table
   245           val arr = !table
   246 	  val sz = Array.length arr
   246           val sz = Array.length arr
   247 	  val hash = hashVal key
   247           val hash = hashVal key
   248 	  val indx = index (hash, sz)
   248           val indx = index (hash, sz)
   249 	  fun look NIL = raise not_found
   249           fun look NIL = raise not_found
   250 	    | look (B(h, k, v, r)) = if ((hash = h) andalso sameKey(key, k))
   250             | look (B(h, k, v, r)) = if ((hash = h) andalso sameKey(key, k))
   251 		then (v, r)
   251                 then (v, r)
   252 		else let val (item, r') = look r in (item, B(h, k, v, r')) end
   252                 else let val (item, r') = look r in (item, B(h, k, v, r')) end
   253 	  val (item, bucket) = look (Array.sub (arr, indx))
   253           val (item, bucket) = look (Array.sub (arr, indx))
   254 	  in
   254           in
   255 	    Array.update (arr, indx, bucket);
   255             Array.update (arr, indx, bucket);
   256 	    n_items := !n_items - 1;
   256             n_items := !n_items - 1;
   257 	    item
   257             item
   258 	  end (* remove *);
   258           end (* remove *);
   259 
   259 
   260   (* Return the number of items in the table *)
   260   (* Return the number of items in the table *)
   261    fun numItems (HT{n_items, ...}) = !n_items
   261    fun numItems (HT{n_items, ...}) = !n_items
   262 
   262 
   263   (* return a list of the items in the table *)
   263   (* return a list of the items in the table *)
   264     fun listItems (HT{table = Unsynchronized.ref arr, n_items, ...}) = let
   264     fun listItems (HT{table = Unsynchronized.ref arr, n_items, ...}) = let
   265 	  fun f (_, l, 0) = l
   265           fun f (_, l, 0) = l
   266 	    | f (~1, l, _) = l
   266             | f (~1, l, _) = l
   267 	    | f (i, l, n) = let
   267             | f (i, l, n) = let
   268 		fun g (NIL, l, n) = f (i-1, l, n)
   268                 fun g (NIL, l, n) = f (i-1, l, n)
   269 		  | g (B(_, k, v, r), l, n) = g(r, (k, v)::l, n-1)
   269                   | g (B(_, k, v, r), l, n) = g(r, (k, v)::l, n-1)
   270 		in
   270                 in
   271 		  g (Array.sub(arr, i), l, n)
   271                   g (Array.sub(arr, i), l, n)
   272 		end
   272                 end
   273 	  in
   273           in
   274 	    f ((Array.length arr) - 1, [], !n_items)
   274             f ((Array.length arr) - 1, [], !n_items)
   275 	  end (* listItems *);
   275           end (* listItems *);
   276 
   276 
   277   (* Apply a function to the entries of the table *)
   277   (* Apply a function to the entries of the table *)
   278     fun apply f (HT{table, ...}) = let
   278     fun apply f (HT{table, ...}) = let
   279 	  fun appF NIL = ()
   279           fun appF NIL = ()
   280 	    | appF (B(_, key, item, rest)) = (
   280             | appF (B(_, key, item, rest)) = (
   281 		f (key, item);
   281                 f (key, item);
   282 		appF rest)
   282                 appF rest)
   283 	  val arr = !table
   283           val arr = !table
   284 	  val sz = Array.length arr
   284           val sz = Array.length arr
   285 	  fun appToTbl i = if (i < sz)
   285           fun appToTbl i = if (i < sz)
   286 		then (appF (Array.sub (arr, i)); appToTbl(i+1))
   286                 then (appF (Array.sub (arr, i)); appToTbl(i+1))
   287 		else ()
   287                 else ()
   288 	  in
   288           in
   289 	    appToTbl 0
   289             appToTbl 0
   290 	  end (* apply *);
   290           end (* apply *);
   291 
   291 
   292   (* Map a table to a new table that has the same keys and exception *)
   292   (* Map a table to a new table that has the same keys and exception *)
   293     fun map f (HT{hashVal, sameKey, table, n_items, not_found}) = let
   293     fun map f (HT{hashVal, sameKey, table, n_items, not_found}) = let
   294 	  fun mapF NIL = NIL
   294           fun mapF NIL = NIL
   295 	    | mapF (B(hash, key, item, rest)) =
   295             | mapF (B(hash, key, item, rest)) =
   296 		B(hash, key, f (key, item), mapF rest)
   296                 B(hash, key, f (key, item), mapF rest)
   297 	  val arr = !table
   297           val arr = !table
   298 	  val sz = Array.length arr
   298           val sz = Array.length arr
   299 	  val newArr = Array.array (sz, NIL)
   299           val newArr = Array.array (sz, NIL)
   300 	  fun mapTbl i = if (i < sz)
   300           fun mapTbl i = if (i < sz)
   301 		then (
   301                 then (
   302 		  Array.update(newArr, i, mapF (Array.sub(arr, i)));
   302                   Array.update(newArr, i, mapF (Array.sub(arr, i)));
   303 		  mapTbl (i+1))
   303                   mapTbl (i+1))
   304 		else ()
   304                 else ()
   305 	  in
   305           in
   306 	    mapTbl 0;
   306             mapTbl 0;
   307 	    HT{hashVal=hashVal,
   307             HT{hashVal=hashVal,
   308 	       sameKey=sameKey,
   308                sameKey=sameKey,
   309 	       table = Unsynchronized.ref newArr, 
   309                table = Unsynchronized.ref newArr, 
   310 	       n_items = Unsynchronized.ref(!n_items), 
   310                n_items = Unsynchronized.ref(!n_items), 
   311 	       not_found = not_found}
   311                not_found = not_found}
   312 	  end (* transform *);
   312           end (* transform *);
   313 
   313 
   314   (* remove any hash table items that do not satisfy the given
   314   (* remove any hash table items that do not satisfy the given
   315    * predicate.
   315    * predicate.
   316    *)
   316    *)
   317     fun filter pred (HT{table, n_items, not_found, ...}) = let
   317     fun filter pred (HT{table, n_items, not_found, ...}) = let
   318 	  fun filterP NIL = NIL
   318           fun filterP NIL = NIL
   319 	    | filterP (B(hash, key, item, rest)) = if (pred(key, item))
   319             | filterP (B(hash, key, item, rest)) = if (pred(key, item))
   320 		then B(hash, key, item, filterP rest)
   320                 then B(hash, key, item, filterP rest)
   321 		else filterP rest
   321                 else filterP rest
   322 	  val arr = !table
   322           val arr = !table
   323 	  val sz = Array.length arr
   323           val sz = Array.length arr
   324 	  fun filterTbl i = if (i < sz)
   324           fun filterTbl i = if (i < sz)
   325 		then (
   325                 then (
   326 		  Array.update (arr, i, filterP (Array.sub (arr, i)));
   326                   Array.update (arr, i, filterP (Array.sub (arr, i)));
   327 		  filterTbl (i+1))
   327                   filterTbl (i+1))
   328 		else ()
   328                 else ()
   329 	  in
   329           in
   330 	    filterTbl 0
   330             filterTbl 0
   331 	  end (* filter *);
   331           end (* filter *);
   332 
   332 
   333   (* Map a table to a new table that has the same keys, exception,
   333   (* Map a table to a new table that has the same keys, exception,
   334      hash function, and equality function *)
   334      hash function, and equality function *)
   335 
   335 
   336     fun transform f (HT{hashVal, sameKey, table, n_items, not_found}) = let
   336     fun transform f (HT{hashVal, sameKey, table, n_items, not_found}) = let
   337 	  fun mapF NIL = NIL
   337           fun mapF NIL = NIL
   338 	    | mapF (B(hash, key, item, rest)) = B(hash, key, f item, mapF rest)
   338             | mapF (B(hash, key, item, rest)) = B(hash, key, f item, mapF rest)
   339 	  val arr = !table
   339           val arr = !table
   340 	  val sz = Array.length arr
   340           val sz = Array.length arr
   341 	  val newArr = Array.array (sz, NIL)
   341           val newArr = Array.array (sz, NIL)
   342 	  fun mapTbl i = if (i < sz)
   342           fun mapTbl i = if (i < sz)
   343 		then (
   343                 then (
   344 		  Array.update(newArr, i, mapF (Array.sub(arr, i)));
   344                   Array.update(newArr, i, mapF (Array.sub(arr, i)));
   345 		  mapTbl (i+1))
   345                   mapTbl (i+1))
   346 		else ()
   346                 else ()
   347 	  in
   347           in
   348 	    mapTbl 0;
   348             mapTbl 0;
   349 	    HT{hashVal=hashVal, 
   349             HT{hashVal=hashVal, 
   350 	       sameKey=sameKey, 
   350                sameKey=sameKey, 
   351 	       table = Unsynchronized.ref newArr, 
   351                table = Unsynchronized.ref newArr, 
   352 	       n_items = Unsynchronized.ref(!n_items), 
   352                n_items = Unsynchronized.ref(!n_items), 
   353 	       not_found = not_found}
   353                not_found = not_found}
   354 	  end (* transform *);
   354           end (* transform *);
   355 
   355 
   356   (* Create a copy of a hash table *)
   356   (* Create a copy of a hash table *)
   357     fun copy (HT{hashVal, sameKey, table, n_items, not_found}) = let
   357     fun copy (HT{hashVal, sameKey, table, n_items, not_found}) = let
   358 	  val arr = !table
   358           val arr = !table
   359 	  val sz = Array.length arr
   359           val sz = Array.length arr
   360 	  val newArr = Array.array (sz, NIL)
   360           val newArr = Array.array (sz, NIL)
   361 	  fun mapTbl i = (
   361           fun mapTbl i = (
   362 		Array.update (newArr, i, Array.sub(arr, i));
   362                 Array.update (newArr, i, Array.sub(arr, i));
   363 		mapTbl (i+1))
   363                 mapTbl (i+1))
   364 	  in
   364           in
   365 	    (mapTbl 0) handle _ => ();  (* FIXME avoid handle _ *)
   365             (mapTbl 0) handle _ => ();  (* FIXME avoid handle _ *)
   366 	    HT{hashVal=hashVal, 
   366             HT{hashVal=hashVal, 
   367 	       sameKey=sameKey,
   367                sameKey=sameKey,
   368 	       table = Unsynchronized.ref newArr, 
   368                table = Unsynchronized.ref newArr, 
   369 	       n_items = Unsynchronized.ref(!n_items), 
   369                n_items = Unsynchronized.ref(!n_items), 
   370 	       not_found = not_found}
   370                not_found = not_found}
   371 	  end (* copy *);
   371           end (* copy *);
   372 
   372 
   373   (* returns a list of the sizes of the various buckets.  This is to
   373   (* returns a list of the sizes of the various buckets.  This is to
   374    * allow users to gauge the quality of their hashing function.
   374    * allow users to gauge the quality of their hashing function.
   375    *)
   375    *)
   376     fun bucketSizes (HT{table = Unsynchronized.ref arr, ...}) = let
   376     fun bucketSizes (HT{table = Unsynchronized.ref arr, ...}) = let
   377 	  fun len (NIL, n) = n
   377           fun len (NIL, n) = n
   378 	    | len (B(_, _, _, r), n) = len(r, n+1)
   378             | len (B(_, _, _, r), n) = len(r, n+1)
   379 	  fun f (~1, l) = l
   379           fun f (~1, l) = l
   380 	    | f (i, l) = f (i-1, len (Array.sub (arr, i), 0) :: l)
   380             | f (i, l) = f (i-1, len (Array.sub (arr, i), 0) :: l)
   381 	  in
   381           in
   382 	    f ((Array.length arr)-1, [])
   382             f ((Array.length arr)-1, [])
   383 	  end
   383           end
   384 
   384 
   385    (*Added by lcp.
   385    (*Added by lcp.
   386       This is essentially the  described in Compilers:
   386       This is essentially the  described in Compilers:
   387       Principles, Techniques, and Tools, by Aho, Sethi and Ullman.*)
   387       Principles, Techniques, and Tools, by Aho, Sethi and Ullman.*)
   388 
   388