--          This file is part of SmallEiffel The GNU Eiffel Compiler.
--          Copyright (C) 1994-98 LORIA - UHP - CRIN - INRIA - FRANCE
--            Dominique COLNET and Suzanne COLLIN - colnet@loria.fr
--                       http://SmallEiffel.loria.fr
-- SmallEiffel 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, or (at your option)  any  later
-- version. SmallEiffel 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  SmallEiffel;  see the file COPYING.  If not,
-- write to the  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-- Boston, MA 02111-1307, USA.
--
class ID_PROVIDER
   --
   -- Unique object in charge of some id providing.
   --

inherit GLOBALS;

creation make

feature {NONE}

   mem_id: FIXED_ARRAY[INTEGER];

   mem_str: FIXED_ARRAY[STRING];

feature {NONE}

   make is
      do
         !!mem_id.with_capacity(1024);
         !!mem_str.with_capacity(1024);
         add2(as_array,0);
         add2(as_general,1);
         add2(as_integer,2);
         add2(as_character,3);
         add2(as_real,4);
         add2(as_double,5);
         add2(as_boolean,6);
         add2(as_string,7);
         add2(as_pointer,8);
         add2(as_native_array_character,9);
      end;

feature {SMALL_EIFFEL}

   max_id: INTEGER is
      local
         i: INTEGER;
      do
         from
            i := mem_id.upper;
         until
            i < 0
         loop
            if mem_id.item(i) > Result then
               Result := mem_id.item(i);
            end;
            i := i - 1;
         end;
      end;

feature {BASE_CLASS,RUN_CLASS}

   item(str: STRING): INTEGER is
      require
         str = string_aliaser.item(str)
      local
         index: INTEGER;
      do
         index := mem_str.fast_index_of(str);
         if index <= mem_str.upper then
            Result := mem_id.item(index);
         elseif run_control.boost then
            Result := max_id + 1;
            add2(str,Result);
         else
            Result := hash_code(str);
            if mem_id.fast_has(Result) then
               from
                  Result := 10;
               until
                  not mem_id.fast_has(Result)
               loop
                  Result := Result + 1;
               end;
            end;
            add2(str,Result);
         end;
      end;

feature {NONE}

   add2(str: STRING; id: INTEGER) is
      do
         mem_str.add_last(str);
         mem_id.add_last(id);
      end;

feature {NONE}

   hash_code(idf: STRING): INTEGER is
         -- Specific because `idf' is not so long and because it is
         -- often a class name identifier.
         -- To avoid many C recompilation, it is important to avoid
         -- hash-code clashes.
      local
         i: INTEGER;
         c: CHARACTER;
         val: INTEGER;
         max: INTEGER;
      do
         from
            i := 1;
         until
            i > idf.count
         loop
            c := idf.item(i).to_upper;
            inspect
               c
            when 'A' .. 'Z' then
               val := c.code - ('A').code;
            when '0' .. '9' then
               val := 25 + c.code - ('0').code;
            else
               val := 0;
            end;
            Result := Result + (i * val);
            i := i + 1;
         end;
         if Result < 0 then
            Result := - Result;
         end;
         if run_control.boost then
            max := 2048;
         else
            max := 8192;
         end;
         from
         until
            Result <= max
         loop
            Result := Result - 999;
         end;
      end;

end -- ID_PROVIDER
