home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / eiffel / smalleif.97 / se.t / SmallEiffel / lib_std / dictionary.e < prev    next >
Encoding:
Text File  |  1996-05-02  |  9.0 KB  |  475 lines

  1. -- Part of SmallEiffel -- Read DISCLAIMER file -- Copyright (C) 
  2. -- Dominique COLNET and Suzanne COLLIN -- colnet@loria.fr
  3. --
  4. class DICTIONARY[V,K]
  5. --
  6. -- Associative memory. Values of type `V' are stored using Keys of type `K'.
  7. --
  8.  
  9. inherit 
  10.    ANY 
  11.       redefine is_equal, copy 
  12.       end;
  13.  
  14. creation {ANY}
  15.    make
  16.  
  17. feature {DICTIONARY}
  18.    
  19.    keys: ARRAY[K];            
  20.      -- Index range [1 .. N].
  21.      -- Storage for keys. 
  22.     
  23.    store: ARRAY[V]; 
  24.      -- Index range [1 .. N].
  25.      -- Storage for items. An item and the corresponding key 
  26.      -- are stored at the same index. 
  27.     
  28.    buckets: ARRAY[INTEGER];
  29.      -- Index range [0 .. modulus-1].
  30.      -- Entry is a hash code value. Return 0 when hash code not used or 
  31.      -- gives the start of the corresponding list in `chain'.
  32.    
  33.    chain: ARRAY[INTEGER]; 
  34.      -- Index range [1 .. N].
  35.      -- Chaining of `free' slot and used slot. Value 0 is an end of 
  36.      -- list.
  37.     
  38.    free: INTEGER;
  39.      -- First element of the free list in `chain' or 0 when no more
  40.      -- space.
  41.  
  42.    modulus: INTEGER;
  43.      -- To compute a hash value in range [0 .. modulus-1].
  44.    
  45.    Min_size: INTEGER is 16;
  46.      -- Minimum value for N of range [1.. N];
  47.     
  48.    has_mem: INTEGER;
  49.      -- Memory of the last look in `keys'/`store' or 0 when no
  50.      -- previous successfull looking.
  51.    
  52.    item_mem, item_mem_i, item_mem_j: INTEGER;
  53.      -- Memory of the last look using `item'.
  54.    
  55. feature {NONE}
  56.  
  57.    make is
  58.       local
  59.      i: INTEGER;
  60.       do
  61.      modulus := 32;
  62.      count := 0;
  63.      free := 1;
  64.      has_mem := 0;
  65.      item_mem := 0;
  66.      !!buckets.make(0,modulus - 1);
  67.      !!chain.make(1,Min_size);
  68.      !!store.make(1,Min_size);
  69.      !!keys.make(1,Min_size);
  70.      from
  71.         i := 1;
  72.      until
  73.         i = chain.count
  74.      loop
  75.         chain.put (i + 1, i);
  76.         i := i + 1;
  77.      end;
  78.      chain.put(0,i);
  79.      from
  80.         i := 0;
  81.      until
  82.         i >= modulus
  83.      loop
  84.         buckets.put (0,i);
  85.         i := i + 1;
  86.      end;
  87.       end;
  88.    
  89. feature {ANY}
  90.  
  91.    count: INTEGER;
  92.      -- Actual `count' of stored elements.
  93.  
  94.    empty: BOOLEAN is
  95.       do
  96.      Result := count = 0;
  97.       ensure
  98.      count = 0 implies Result
  99.       end;
  100.       
  101.    at, infix "@" (k: K): V is
  102.      -- Return the item stored at key `k'.
  103.       require
  104.      has(k)
  105.       local
  106.      foo: BOOLEAN;
  107.       do
  108.      foo := has(k);
  109.      Result := store.item(has_mem);
  110.       end;
  111.    
  112.    has(k: K): BOOLEAN is
  113.      -- Is there an item currently associated with key 'k' ?
  114.       do
  115.      if has_mem = 0 or else not k.is_equal(keys.item(has_mem)) then
  116.         from
  117.            has_mem := buckets.item(k.hash_code \\ modulus);
  118.         until
  119.            has_mem = 0 or else k.is_equal(keys.item(has_mem))
  120.         loop
  121.            has_mem := chain.item(has_mem);
  122.         end;
  123.      end;
  124.      Result := (has_mem /= 0);
  125.       end;
  126.    
  127.    key_at(x: V): K is
  128.      -- Retrieve the key used for `x'. 
  129.       local
  130.      i: INTEGER;
  131.       do
  132.      from  
  133.         i := 1;
  134.      until
  135.         i > count or else (x = item(i))
  136.      loop
  137.         i := i + 1;
  138.      end;
  139.      if i <= count then
  140.         Result := key(i);
  141.      end;
  142.       end;
  143.    
  144.    put(x: V; k: K) is
  145.      -- If there is as yet no key `k' in the dictionary, enter 
  146.      -- it with item `x'. Otherwise overwrite the item associated
  147.      -- with key `k'.
  148.       local
  149.      hash: INTEGER;
  150.       do
  151.      hash := k.hash_code \\ modulus;
  152.      if has_mem = 0 or else not k.is_equal(keys.item(has_mem)) then
  153.         from
  154.            has_mem := buckets.item (hash);
  155.         until
  156.            has_mem = 0 or else k.is_equal (keys.item (has_mem))
  157.         loop
  158.            has_mem := chain.item (has_mem);
  159.         end;
  160.         if has_mem = 0 then
  161.            if count >= store.count then
  162.           expand;
  163.            end;
  164.            keys.put(k, free);
  165.            store.put(x, free);
  166.            has_mem := free;
  167.            free   := chain.item(free);
  168.            chain.put(buckets.item(hash),has_mem);
  169.            buckets.put(has_mem,hash);
  170.            count := count + 1;
  171.            if count > modulus * 2 then
  172.           resize(2 * modulus);
  173.            end;
  174.         end;
  175.      else
  176.         store.put(x,has_mem);
  177.      end;
  178.      item_mem := 0;
  179.       end;
  180.  
  181.    remove(k: K) is
  182.      -- If there is an entry for key `k' remove it. 
  183.      -- Otherwise the call has no effect.
  184.       local
  185.      hash: INTEGER;
  186.      n, p: INTEGER;
  187.       do
  188.      hash := k.hash_code \\ modulus;
  189.      from
  190.         n := buckets.item(hash);
  191.      until
  192.         n = 0 or else k.is_equal (keys.item(n))
  193.      loop
  194.         p := n;
  195.         n := chain.item(n);
  196.      end;
  197.      if n /= 0 then
  198.         if p /= 0 then
  199.            chain.put(chain.item(n),p);
  200.         else
  201.            buckets.put(chain.item(n),hash);
  202.         end;
  203.         chain.put(free,n);
  204.         free  := n;
  205.         count := count - 1;
  206.         if n = has_mem then
  207.            has_mem := 0;
  208.         end;
  209.         if count < store.count // 4 and then count > Min_size then
  210.            shrink;
  211.         end;
  212.      end;
  213.      item_mem := 0;
  214.       end;
  215.  
  216.    is_equal(other: like current): BOOLEAN is
  217.       local
  218.      i: INTEGER;
  219.      k: K;
  220.      v1, v2: V;
  221.       do
  222.      if count = other.count then
  223.         from  
  224.            i := 1;
  225.            Result := true;
  226.         until
  227.            not Result or else i > count
  228.         loop
  229.            k := key(i);
  230.            if other.has(k) then
  231.           Result := equal_like(item(i),other.at(k));
  232.            else
  233.           Result := false;
  234.            end;
  235.            i := i + 1;
  236.         end;
  237.      end;
  238.       end;
  239.  
  240.    copy(other: like current) is
  241.       do
  242.      standard_copy(other);
  243.      keys := clone(other.keys);
  244.      store := clone(other.store);
  245.      buckets := clone(other.buckets);
  246.      chain := clone(other.chain);
  247.       end;
  248.  
  249. feature {ANY} -- To provide iterating facilities :
  250.    
  251.    item(i: INTEGER): V is
  252.       require
  253.      1 <= i;
  254.      i <= count;
  255.       do
  256.      if item_mem = 0 then
  257.         first;
  258.         from  
  259.         until
  260.            i = item_mem
  261.         loop
  262.            forth;
  263.         end;
  264.         Result := store.item(item_mem_j);
  265.      elseif item_mem <= i then
  266.         from
  267.         until
  268.            i = item_mem
  269.         loop
  270.            forth;
  271.         end;
  272.         Result := store.item(item_mem_j);
  273.      else
  274.         item_mem := 0;
  275.         Result := item(i);
  276.      end;
  277.       ensure
  278.      item_mem = i;
  279.       end;
  280.    
  281.    key(i: INTEGER): K is
  282.       require
  283.      1 <= i;
  284.      i <= count;
  285.       local
  286.      v: V;
  287.       do
  288.      v := item(i);
  289.      Result := keys.item(item_mem_j);
  290.       end;
  291.    
  292. feature {NONE} 
  293.    
  294.    first is
  295.       require
  296.      count > 0;
  297.       local
  298.      i: INTEGER;
  299.       do
  300.      from
  301.         i := 0;
  302.      until
  303.         buckets.item(i) /= 0
  304.      loop
  305.         i := i + 1;
  306.      end;
  307.      item_mem_i := i;
  308.      item_mem_j := buckets.item(i);
  309.      item_mem := 1;
  310.       ensure
  311.      item_mem = 1;
  312.       end;
  313.  
  314.    forth is
  315.       require
  316.      item_mem < count;
  317.       local
  318.      i: INTEGER;
  319.       do
  320.      if chain.item(item_mem_j) /= 0 then
  321.         item_mem_j := chain.item(item_mem_j);
  322.      else
  323.         from
  324.            i := item_mem_i + 1;
  325.         until
  326.            buckets.item(i) /= 0
  327.         loop
  328.            i := i + 1;
  329.         end;
  330.         item_mem_i := i;
  331.         item_mem_j := buckets.item(i);
  332.      end;
  333.      item_mem := item_mem + 1;
  334.       ensure
  335.      item_mem = 1 + old item_mem;
  336.       end;
  337.  
  338. feature {NONE}
  339.    
  340.    resize (new_mod: INTEGER) is
  341.       local
  342.      hash: INTEGER;
  343.      new_buc: like buckets;
  344.      i, n, p: INTEGER;
  345.       do
  346.      !!new_buc.make(0, new_mod - 1);
  347.      from
  348.         i  := 0;
  349.      until
  350.         i >= modulus
  351.      loop
  352.         from
  353.            n := buckets.item (i);
  354.         until
  355.            n = 0
  356.         loop
  357.            p    := chain.item (n);
  358.            hash := keys.item(n).hash_code \\ new_mod ;
  359.            chain.put (new_buc.item (hash), n) ;
  360.            new_buc.put (n, hash) ;
  361.            n := p;
  362.         end;
  363.         i := i + 1;
  364.      end;
  365.      buckets := new_buc;
  366.      modulus := new_mod;
  367.      item_mem := 0;
  368.       end;
  369.  
  370.    expand is
  371.       local
  372.      i, old_size: INTEGER;
  373.       do
  374.      item_mem := 0;
  375.      old_size := store.count;
  376.      chain.resize (1, 2 * old_size);
  377.      keys.resize  (1, 2 * old_size);
  378.      store.resize (1, 2 * old_size);
  379.      from
  380.         i := old_size + 1;
  381.      until
  382.         i = chain.count
  383.      loop
  384.         chain.put (i + 1, i);
  385.         i := i + 1;
  386.      end;
  387.      chain.put (free, i);
  388.      free := old_size + 1;
  389.       end;
  390.  
  391.     shrink is
  392.       local
  393.      str  : ARRAY [V];
  394.      kys  : ARRAY [K];
  395.      chn  : ARRAY [INTEGER];
  396.      i, j : INTEGER;
  397.      k    : INTEGER;
  398.       do
  399.      !!kys.make (1, store.count // 2);
  400.      !!str.make (1, store.count // 2);
  401.      !!chn.make (1, store.count // 2);
  402.      from
  403.         i := 1;
  404.         j := 0;
  405.      until
  406.         j >= modulus
  407.      loop
  408.         from
  409.            k := buckets.item (j);
  410.            if k /= 0 then
  411.           buckets.put (i, j);
  412.            end;
  413.         until
  414.            k = 0
  415.         loop
  416.            kys.put (keys.item (k), i);
  417.            str.put (store.item (k), i);
  418.            k := chain.item (k) ;
  419.            
  420.            if k = 0 then
  421.           chn.put (0, i);
  422.            else
  423.           chn.put (i + 1, i);
  424.            end;
  425.            i := i + 1;
  426.         end;
  427.         j := j + 1;
  428.      end;
  429.      from
  430.         i := count + 1;
  431.      until
  432.         i >= chn.count
  433.      loop
  434.         chn.put (i + 1, i);
  435.         i := i + 1;
  436.      end;
  437.      chn.put (0, i);
  438.      free  := count + 1;
  439.      chain := chn;
  440.      keys  := kys;
  441.      store := str;
  442.      item_mem := 0;
  443.       end;
  444.     
  445. feature {NONE}
  446.  
  447.    equal_like(v1, v2: V): BOOLEAN is
  448.      -- Note: to avoid calling `equal' :-(
  449.      -- Because SmallEiffel is not yet able to infer 
  450.      -- arguments types.
  451.       do
  452.      if v1.is_expanded_type then
  453.         Result := v1 = v2 or else v1.is_equal(v2);
  454.      elseif v1 = v2 then
  455.         Result := true;
  456.      elseif v1 = Void or else v2 = Void then
  457.      else
  458.         Result := v1.is_equal(v2);
  459.      end;
  460.       end;
  461.  
  462. invariant
  463.    
  464.    keys.lower = 1;
  465.    
  466.    keys.lower = store.lower and store.lower = chain.lower;
  467.    
  468.    keys.upper = store.upper and store.upper = chain.upper;
  469.    
  470.    buckets.lower = 0;
  471.    
  472.    buckets.upper = modulus - 1;
  473.    
  474. end -- DICTIONARY 
  475.