Skip to content
Snippets Groups Projects
Select Git revision
  • e3a26eab8a92709388debb9cb2763c33de0e7ae3
  • master default protected
  • 9.0
  • 8.0
  • nt-tools
  • 7.8
  • 7.6
  • 7.4
  • 7.2
  • 7.0
  • 0.6
  • rosuav/latex-markdown-renderer
  • rxnpatch/rxnpatch
  • marcus/gobject-introspection
  • rxnpatch/8.0
  • rosuav/pre-listening-ports
  • rosuav/async-annotations
  • rosuav/pgsql-ssl
  • rxnpatch/rxnpatch-broken/2023-10-06T094250
  • grubba/fdlib
  • grubba/wip/sakura/8.0
  • v8.0.2018
  • v8.0.2016
  • v8.0.2014
  • v8.0.2012
  • v8.0.2008
  • v8.0.2006
  • v8.0.2004
  • v8.0.2002
  • v8.0.2000
  • v8.0.1998
  • v8.0.1996
  • v8.0.1994
  • v8.0.1992
  • v8.0.1990
  • v8.0.1988
  • v8.0.1986
  • rxnpatch/clusters/8.0/2025-04-29T124414
  • rxnpatch/2025-04-29T124414
  • v8.0.1984
  • v8.0.1982
41 results

hashtable.c

Blame
    • Fredrik Hübinette (Hubbe)'s avatar
      5c8e8906
      uLPC · 5c8e8906
      Fredrik Hübinette (Hubbe) authored
      Rev: README:1.1.1.1
      Rev: bin/create_testsuite:1.1.1.1
      Rev: bin/export.lpc:1.1.1.1
      Rev: bin/fixdepends.lpc:1.1.1.1
      Rev: bin/hilfe.lpc:1.1.1.1
      Rev: bin/rsif:1.1.1.1
      Rev: bin/uhttpd.lpc:1.1.1.1
      Rev: doc/README:1.1.1.1
      Rev: doc/builtin/add_efun:1.1.1.1
      Rev: doc/builtin/aggregate:1.1.1.1
      Rev: doc/builtin/aggregate_list:1.1.1.1
      Rev: doc/builtin/aggregate_mapping:1.1.1.1
      Rev: doc/builtin/all_efuns:1.1.1.1
      Rev: doc/builtin/allocate:1.1.1.1
      Rev: doc/builtin/arrayp:1.1.1.1
      Rev: doc/builtin/backtrace:1.1.1.1
      Rev: doc/builtin/call_function:1.1.1.1
      Rev: doc/builtin/call_out:1.1.1.1
      Rev: doc/builtin/call_out_info:1.1.1.1
      Rev: doc/builtin/catch:1.1.1.1
      Rev: doc/builtin/clone:1.1.1.1
      Rev: doc/builtin/combine_path:1.1.1.1
      Rev: doc/builtin/compile_file:1.1.1.1
      Rev: doc/builtin/compile_string:1.1.1.1
      Rev: doc/builtin/copy_value:1.1.1.1
      Rev: doc/builtin/crypt:1.1.1.1
      Rev: doc/builtin/ctime:1.1.1.1
      Rev: doc/builtin/destruct:1.1.1.1
      Rev: doc/builtin/equal:1.1.1.1
      Rev: doc/builtin/exit:1.1.1.1
      Rev: doc/builtin/explode:1.1.1.1
      Rev: doc/builtin/find_call_out:1.1.1.1
      Rev: doc/builtin/floatp:1.1.1.1
      Rev: doc/builtin/function_name:1.1.1.1
      Rev: doc/builtin/function_object:1.1.1.1
      Rev: doc/builtin/functionp:1.1.1.1
      Rev: doc/builtin/getpid:1.1.1.1
      Rev: doc/builtin/hash:1.1.1.1
      Rev: doc/builtin/implode:1.1.1.1
      Rev: doc/builtin/indices:1.1.1.1
      Rev: doc/builtin/intp:1.1.1.1
      Rev: doc/builtin/kill:1.1.1.1
      Rev: doc/builtin/listp:1.1.1.1
      Rev: doc/builtin/lower_case:1.1.1.1
      Rev: doc/builtin/m_delete:1.1.1.1
      Rev: doc/builtin/mappingp:1.1.1.1
      Rev: doc/builtin/mkmapping:1.1.1.1
      Rev: doc/builtin/next_object:1.1.1.1
      Rev: doc/builtin/object_program:1.1.1.1
      Rev: doc/builtin/objectp:1.1.1.1
      Rev: doc/builtin/programp:1.1.1.1
      Rev: doc/builtin/query_host_name:1.1.1.1
      Rev: doc/builtin/query_num_arg:1.1.1.1
      Rev: doc/builtin/random:1.1.1.1
      Rev: doc/builtin/remove_call_out:1.1.1.1
      Rev: doc/builtin/replace:1.1.1.1
      Rev: doc/builtin/reverse:1.1.1.1
      Rev: doc/builtin/rusage:1.1.1.1
      Rev: doc/builtin/search:1.1.1.1
      Rev: doc/builtin/signal:1.1.1.1
      Rev: doc/builtin/signame:1.1.1.1
      Rev: doc/builtin/signum:1.1.1.1
      Rev: doc/builtin/sizeof:1.1.1.1
      Rev: doc/builtin/sleep:1.1.1.1
      Rev: doc/builtin/sscanf:1.1.1.1
      Rev: doc/builtin/stringp:1.1.1.1
      Rev: doc/builtin/sum:1.1.1.1
      Rev: doc/builtin/this_object:1.1.1.1
      Rev: doc/builtin/throw:1.1.1.1
      Rev: doc/builtin/time:1.1.1.1
      Rev: doc/builtin/trace:1.1.1.1
      Rev: doc/builtin/upper_case:1.1.1.1
      Rev: doc/builtin/values:1.1.1.1
      Rev: doc/builtin/zero_type:1.1.1.1
      Rev: doc/files/cd:1.1.1.1
      Rev: doc/files/exec:1.1.1.1
      Rev: doc/files/file:1.1.1.1
      Rev: doc/files/file_stat:1.1.1.1
      Rev: doc/files/fork:1.1.1.1
      Rev: doc/files/get_dir:1.1.1.1
      Rev: doc/files/getcwd:1.1.1.1
      Rev: doc/files/mkdir:1.1.1.1
      Rev: doc/files/mv:1.1.1.1
      Rev: doc/files/perror:1.1.1.1
      Rev: doc/files/port:1.1.1.1
      Rev: doc/files/rm:1.1.1.1
      Rev: doc/lpc/command_line_options:1.1.1.1
      Rev: doc/lpc/hilfe.hilfe:1.1.1.1
      Rev: doc/lpc/how_to_make_modules:1.1.1.1
      Rev: doc/lpc/preprocessor:1.1.1.1
      Rev: doc/lpc/reserved:1.1.1.1
      Rev: doc/manual/i-overview.html:1.1.1.1
      Rev: doc/manual/index.html:1.1.1.1
      Rev: doc/manual/t-hello.html:1.1.1.1
      Rev: doc/manual/ulpc-inside3.gif:1.1.1.1
      Rev: doc/math/acos:1.1.1.1
      Rev: doc/math/asin:1.1.1.1
      Rev: doc/math/atan:1.1.1.1
      Rev: doc/math/ceil:1.1.1.1
      Rev: doc/math/cos:1.1.1.1
      Rev: doc/math/exp:1.1.1.1
      Rev: doc/math/floor:1.1.1.1
      Rev: doc/math/log:1.1.1.1
      Rev: doc/math/pow:1.1.1.1
      Rev: doc/math/sin:1.1.1.1
      Rev: doc/math/sqrt:1.1.1.1
      Rev: doc/math/tan:1.1.1.1
      Rev: doc/operators/addition:1.1.1.1
      Rev: doc/regexp/regexp:1.1.1.1
      Rev: doc/simulated/PI:1.1.1.1
      Rev: doc/simulated/capitalize:1.1.1.1
      Rev: doc/simulated/code_value:1.1.1.1
      Rev: doc/simulated/describe_backtrace:1.1.1.1
      Rev: doc/simulated/exec:1.1.1.1
      Rev: doc/simulated/file_size:1.1.1.1
      Rev: doc/simulated/filter_array:1.1.1.1
      Rev: doc/simulated/get_function:1.1.1.1
      Rev: doc/simulated/getenv:1.1.1.1
      Rev: doc/simulated/l_sizeof:1.1.1.1
      Rev: doc/simulated/m_indices:1.1.1.1
      Rev: doc/simulated/m_sizeof:1.1.1.1
      Rev: doc/simulated/m_values:1.1.1.1
      Rev: doc/simulated/map_array:1.1.1.1
      Rev: doc/simulated/master:1.1.1.1
      Rev: doc/simulated/member_array:1.1.1.1
      Rev: doc/simulated/popen:1.1.1.1
      Rev: doc/simulated/previous_object:1.1.1.1
      Rev: doc/simulated/read_bytes:1.1.1.1
      Rev: doc/simulated/regexp:1.1.1.1
      Rev: doc/simulated/search_array:1.1.1.1
      Rev: doc/simulated/sort_array:1.1.1.1
      Rev: doc/simulated/spawn:1.1.1.1
      Rev: doc/simulated/strlen:1.1.1.1
      Rev: doc/simulated/strstr:1.1.1.1
      Rev: doc/simulated/sum_arrays:1.1.1.1
      Rev: doc/simulated/system:1.1.1.1
      Rev: doc/simulated/this_function:1.1.1.1
      Rev: doc/simulated/write:1.1.1.1
      Rev: doc/simulated/write_file:1.1.1.1
      Rev: doc/sprintf/sprintf:1.1.1.1
      Rev: doc/types/array:1.1.1.1
      Rev: doc/types/float:1.1.1.1
      Rev: doc/types/function:1.1.1.1
      Rev: doc/types/int:1.1.1.1
      Rev: doc/types/list:1.1.1.1
      Rev: doc/types/mapping:1.1.1.1
      Rev: doc/types/object:1.1.1.1
      Rev: doc/types/program:1.1.1.1
      Rev: doc/types/string:1.1.1.1
      Rev: lib/master.lpc:1.1.1.1
      Rev: lib/simulate.lpc:1.1.1.1
      Rev: lib/testsuite.lpc:1.1.1.1
      Rev: src/BUGS:1.1.1.1
      Rev: src/COPYING:1.1.1.1
      Rev: src/COPYRIGHT:1.1.1.1
      Rev: src/ChangeLog:1.1.1.1
      Rev: src/DISCLAIMER:1.1.1.1
      Rev: src/Makefile.in:1.1.1.1
      Rev: src/README:1.1.1.1
      Rev: src/add_efun.c:1.1.1.1
      Rev: src/add_efun.h:1.1.1.1
      Rev: src/alloca.c:1.1.1.1
      Rev: src/array.c:1.1.1.1
      Rev: src/array.h:1.1.1.1
      Rev: src/backend.c:1.1.1.1
      Rev: src/backend.h:1.1.1.1
      Rev: src/build_modlist_h:1.1.1.1
      Rev: src/builtin_efuns.c:1.1.1.1
      Rev: src/builtin_efuns.h:1.1.1.1
      Rev: src/call_out.c:1.1.1.1
      Rev: src/call_out.h:1.1.1.1
      Rev: src/callback.c:1.1.1.1
      Rev: src/callback.h:1.1.1.1
      Rev: src/compilation.h:1.1.1.1
      Rev: src/config.h:1.1.1.1
      Rev: src/config.log:1.1.1.1
      Rev: src/configure:1.1.1.1
      Rev: src/configure.in:1.1.1.1
      Rev: src/debug.c:1.1.1.1
      Rev: src/debug.h:1.1.1.1
      Rev: src/docode.c:1.1.1.1
      Rev: src/docode.h:1.1.1.1
      Rev: src/dynamic_buffer.c:1.1.1.1
      Rev: src/dynamic_buffer.h:1.1.1.1
      Rev: src/efun.h:1.1.1.1
      Rev: src/error.c:1.1.1.1
      Rev: src/error.h:1.1.1.1
      Rev: src/fd_control.c:1.1.1.1
      Rev: src/fd_control.h:1.1.1.1
      Rev: src/fsort.c:1.1.1.1
      Rev: src/fsort.h:1.1.1.1
      Rev: src/get_linker_options:1.1.1.1
      Rev: src/global.h:1.1.1.1
      Rev: src/hashtable.c:1.1.1.1
      Rev: src/hashtable.h:1.1.1.1
      Rev: src/install-sh:1.1.1.1
      Rev: src/interpret.c:1.1.1.1
      Rev: src/interpret.h:1.1.1.1
      Rev: src/language.y:1.1.1.1
      Rev: src/las.c:1.1.1.1
      Rev: src/las.h:1.1.1.1
      Rev: src/lex.c:1.1.1.1
      Rev: src/lex.h:1.1.1.1
      Rev: src/list.c:1.1.1.1
      Rev: src/list.h:1.1.1.1
      Rev: src/lpc_signal.c:1.1.1.1
      Rev: src/lpc_signal.h:1.1.1.1
      Rev: src/lpc_types.c:1.1.1.1
      Rev: src/lpc_types.h:1.1.1.1
      Rev: src/machine.h.in:1.1.1.1
      Rev: src/macros.h:1.1.1.1
      Rev: src/main.c:1.1.1.1
      Rev: src/main.h:1.1.1.1
      Rev: src/make_modules:1.1.1.1
      Rev: src/mapping.c:1.1.1.1
      Rev: src/mapping.h:1.1.1.1
      Rev: src/memory.c:1.1.1.1
      Rev: src/memory.h:1.1.1.1
      Rev: src/module.c:1.1.1.1
      Rev: src/module.h:1.1.1.1
      Rev: src/modules/efuns.c:1.1.1.1
      Rev: src/modules/files/Makefile.in:1.1.1.1
      Rev: src/modules/files/configure:1.1.1.1
      Rev: src/modules/files/configure.in:1.1.1.1
      Rev: src/modules/files/datagram.c:1.1.1.1
      Rev: src/modules/files/efuns.c:1.1.1.1
      Rev: src/modules/files/file.c:1.1.1.1
      Rev: src/modules/files/file.h:1.1.1.1
      Rev: src/modules/files/file_machine.h.in:1.1.1.1
      Rev: src/modules/files/socket.c:1.1.1.1
      Rev: src/modules/math/Makefile.in:1.1.1.1
      Rev: src/modules/math/configure:1.1.1.1
      Rev: src/modules/math/configure.in:1.1.1.1
      Rev: src/modules/math/math.c:1.1.1.1
      Rev: src/modules/regexp/Makefile.in:1.1.1.1
      Rev: src/modules/regexp/configure:1.1.1.1
      Rev: src/modules/regexp/configure.in:1.1.1.1
      Rev: src/modules/regexp/glue.c:1.1.1.1
      Rev: src/modules/regexp/regexp.c:1.1.1.1
      Rev: src/modules/regexp/regexp.h:1.1.1.1
      Rev: src/modules/sprintf/Makefile.in:1.1.1.1
      Rev: src/modules/sprintf/configure:1.1.1.1
      Rev: src/modules/sprintf/configure.in:1.1.1.1
      Rev: src/modules/sprintf/sprintf.c:1.1.1.1
      Rev: src/object.c:1.1.1.1
      Rev: src/object.h:1.1.1.1
      Rev: src/opcodes.c:1.1.1.1
      Rev: src/opcodes.h:1.1.1.1
      Rev: src/operators.c:1.1.1.1
      Rev: src/operators.h:1.1.1.1
      Rev: src/otable.h:1.1.1.1
      Rev: src/port.c:1.1.1.1
      Rev: src/port.h:1.1.1.1
      Rev: src/program.c:1.1.1.1
      Rev: src/program.h:1.1.1.1
      Rev: src/rusage.c:1.1.1.1
      Rev: src/rusage.h:1.1.1.1
      Rev: src/stamp-h:1.1.1.1
      Rev: src/stralloc.c:1.1.1.1
      Rev: src/stralloc.h:1.1.1.1
      Rev: src/stuff.c:1.1.1.1
      Rev: src/stuff.h:1.1.1.1
      Rev: src/svalue.c:1.1.1.1
      Rev: src/svalue.h:1.1.1.1
      Rev: src/todo:1.1.1.1
      Rev: src/types.h:1.1.1.1
      Rev: src/ualarm.c:1.1.1.1
      5c8e8906
      History
      uLPC
      Fredrik Hübinette (Hubbe) authored
      Rev: README:1.1.1.1
      Rev: bin/create_testsuite:1.1.1.1
      Rev: bin/export.lpc:1.1.1.1
      Rev: bin/fixdepends.lpc:1.1.1.1
      Rev: bin/hilfe.lpc:1.1.1.1
      Rev: bin/rsif:1.1.1.1
      Rev: bin/uhttpd.lpc:1.1.1.1
      Rev: doc/README:1.1.1.1
      Rev: doc/builtin/add_efun:1.1.1.1
      Rev: doc/builtin/aggregate:1.1.1.1
      Rev: doc/builtin/aggregate_list:1.1.1.1
      Rev: doc/builtin/aggregate_mapping:1.1.1.1
      Rev: doc/builtin/all_efuns:1.1.1.1
      Rev: doc/builtin/allocate:1.1.1.1
      Rev: doc/builtin/arrayp:1.1.1.1
      Rev: doc/builtin/backtrace:1.1.1.1
      Rev: doc/builtin/call_function:1.1.1.1
      Rev: doc/builtin/call_out:1.1.1.1
      Rev: doc/builtin/call_out_info:1.1.1.1
      Rev: doc/builtin/catch:1.1.1.1
      Rev: doc/builtin/clone:1.1.1.1
      Rev: doc/builtin/combine_path:1.1.1.1
      Rev: doc/builtin/compile_file:1.1.1.1
      Rev: doc/builtin/compile_string:1.1.1.1
      Rev: doc/builtin/copy_value:1.1.1.1
      Rev: doc/builtin/crypt:1.1.1.1
      Rev: doc/builtin/ctime:1.1.1.1
      Rev: doc/builtin/destruct:1.1.1.1
      Rev: doc/builtin/equal:1.1.1.1
      Rev: doc/builtin/exit:1.1.1.1
      Rev: doc/builtin/explode:1.1.1.1
      Rev: doc/builtin/find_call_out:1.1.1.1
      Rev: doc/builtin/floatp:1.1.1.1
      Rev: doc/builtin/function_name:1.1.1.1
      Rev: doc/builtin/function_object:1.1.1.1
      Rev: doc/builtin/functionp:1.1.1.1
      Rev: doc/builtin/getpid:1.1.1.1
      Rev: doc/builtin/hash:1.1.1.1
      Rev: doc/builtin/implode:1.1.1.1
      Rev: doc/builtin/indices:1.1.1.1
      Rev: doc/builtin/intp:1.1.1.1
      Rev: doc/builtin/kill:1.1.1.1
      Rev: doc/builtin/listp:1.1.1.1
      Rev: doc/builtin/lower_case:1.1.1.1
      Rev: doc/builtin/m_delete:1.1.1.1
      Rev: doc/builtin/mappingp:1.1.1.1
      Rev: doc/builtin/mkmapping:1.1.1.1
      Rev: doc/builtin/next_object:1.1.1.1
      Rev: doc/builtin/object_program:1.1.1.1
      Rev: doc/builtin/objectp:1.1.1.1
      Rev: doc/builtin/programp:1.1.1.1
      Rev: doc/builtin/query_host_name:1.1.1.1
      Rev: doc/builtin/query_num_arg:1.1.1.1
      Rev: doc/builtin/random:1.1.1.1
      Rev: doc/builtin/remove_call_out:1.1.1.1
      Rev: doc/builtin/replace:1.1.1.1
      Rev: doc/builtin/reverse:1.1.1.1
      Rev: doc/builtin/rusage:1.1.1.1
      Rev: doc/builtin/search:1.1.1.1
      Rev: doc/builtin/signal:1.1.1.1
      Rev: doc/builtin/signame:1.1.1.1
      Rev: doc/builtin/signum:1.1.1.1
      Rev: doc/builtin/sizeof:1.1.1.1
      Rev: doc/builtin/sleep:1.1.1.1
      Rev: doc/builtin/sscanf:1.1.1.1
      Rev: doc/builtin/stringp:1.1.1.1
      Rev: doc/builtin/sum:1.1.1.1
      Rev: doc/builtin/this_object:1.1.1.1
      Rev: doc/builtin/throw:1.1.1.1
      Rev: doc/builtin/time:1.1.1.1
      Rev: doc/builtin/trace:1.1.1.1
      Rev: doc/builtin/upper_case:1.1.1.1
      Rev: doc/builtin/values:1.1.1.1
      Rev: doc/builtin/zero_type:1.1.1.1
      Rev: doc/files/cd:1.1.1.1
      Rev: doc/files/exec:1.1.1.1
      Rev: doc/files/file:1.1.1.1
      Rev: doc/files/file_stat:1.1.1.1
      Rev: doc/files/fork:1.1.1.1
      Rev: doc/files/get_dir:1.1.1.1
      Rev: doc/files/getcwd:1.1.1.1
      Rev: doc/files/mkdir:1.1.1.1
      Rev: doc/files/mv:1.1.1.1
      Rev: doc/files/perror:1.1.1.1
      Rev: doc/files/port:1.1.1.1
      Rev: doc/files/rm:1.1.1.1
      Rev: doc/lpc/command_line_options:1.1.1.1
      Rev: doc/lpc/hilfe.hilfe:1.1.1.1
      Rev: doc/lpc/how_to_make_modules:1.1.1.1
      Rev: doc/lpc/preprocessor:1.1.1.1
      Rev: doc/lpc/reserved:1.1.1.1
      Rev: doc/manual/i-overview.html:1.1.1.1
      Rev: doc/manual/index.html:1.1.1.1
      Rev: doc/manual/t-hello.html:1.1.1.1
      Rev: doc/manual/ulpc-inside3.gif:1.1.1.1
      Rev: doc/math/acos:1.1.1.1
      Rev: doc/math/asin:1.1.1.1
      Rev: doc/math/atan:1.1.1.1
      Rev: doc/math/ceil:1.1.1.1
      Rev: doc/math/cos:1.1.1.1
      Rev: doc/math/exp:1.1.1.1
      Rev: doc/math/floor:1.1.1.1
      Rev: doc/math/log:1.1.1.1
      Rev: doc/math/pow:1.1.1.1
      Rev: doc/math/sin:1.1.1.1
      Rev: doc/math/sqrt:1.1.1.1
      Rev: doc/math/tan:1.1.1.1
      Rev: doc/operators/addition:1.1.1.1
      Rev: doc/regexp/regexp:1.1.1.1
      Rev: doc/simulated/PI:1.1.1.1
      Rev: doc/simulated/capitalize:1.1.1.1
      Rev: doc/simulated/code_value:1.1.1.1
      Rev: doc/simulated/describe_backtrace:1.1.1.1
      Rev: doc/simulated/exec:1.1.1.1
      Rev: doc/simulated/file_size:1.1.1.1
      Rev: doc/simulated/filter_array:1.1.1.1
      Rev: doc/simulated/get_function:1.1.1.1
      Rev: doc/simulated/getenv:1.1.1.1
      Rev: doc/simulated/l_sizeof:1.1.1.1
      Rev: doc/simulated/m_indices:1.1.1.1
      Rev: doc/simulated/m_sizeof:1.1.1.1
      Rev: doc/simulated/m_values:1.1.1.1
      Rev: doc/simulated/map_array:1.1.1.1
      Rev: doc/simulated/master:1.1.1.1
      Rev: doc/simulated/member_array:1.1.1.1
      Rev: doc/simulated/popen:1.1.1.1
      Rev: doc/simulated/previous_object:1.1.1.1
      Rev: doc/simulated/read_bytes:1.1.1.1
      Rev: doc/simulated/regexp:1.1.1.1
      Rev: doc/simulated/search_array:1.1.1.1
      Rev: doc/simulated/sort_array:1.1.1.1
      Rev: doc/simulated/spawn:1.1.1.1
      Rev: doc/simulated/strlen:1.1.1.1
      Rev: doc/simulated/strstr:1.1.1.1
      Rev: doc/simulated/sum_arrays:1.1.1.1
      Rev: doc/simulated/system:1.1.1.1
      Rev: doc/simulated/this_function:1.1.1.1
      Rev: doc/simulated/write:1.1.1.1
      Rev: doc/simulated/write_file:1.1.1.1
      Rev: doc/sprintf/sprintf:1.1.1.1
      Rev: doc/types/array:1.1.1.1
      Rev: doc/types/float:1.1.1.1
      Rev: doc/types/function:1.1.1.1
      Rev: doc/types/int:1.1.1.1
      Rev: doc/types/list:1.1.1.1
      Rev: doc/types/mapping:1.1.1.1
      Rev: doc/types/object:1.1.1.1
      Rev: doc/types/program:1.1.1.1
      Rev: doc/types/string:1.1.1.1
      Rev: lib/master.lpc:1.1.1.1
      Rev: lib/simulate.lpc:1.1.1.1
      Rev: lib/testsuite.lpc:1.1.1.1
      Rev: src/BUGS:1.1.1.1
      Rev: src/COPYING:1.1.1.1
      Rev: src/COPYRIGHT:1.1.1.1
      Rev: src/ChangeLog:1.1.1.1
      Rev: src/DISCLAIMER:1.1.1.1
      Rev: src/Makefile.in:1.1.1.1
      Rev: src/README:1.1.1.1
      Rev: src/add_efun.c:1.1.1.1
      Rev: src/add_efun.h:1.1.1.1
      Rev: src/alloca.c:1.1.1.1
      Rev: src/array.c:1.1.1.1
      Rev: src/array.h:1.1.1.1
      Rev: src/backend.c:1.1.1.1
      Rev: src/backend.h:1.1.1.1
      Rev: src/build_modlist_h:1.1.1.1
      Rev: src/builtin_efuns.c:1.1.1.1
      Rev: src/builtin_efuns.h:1.1.1.1
      Rev: src/call_out.c:1.1.1.1
      Rev: src/call_out.h:1.1.1.1
      Rev: src/callback.c:1.1.1.1
      Rev: src/callback.h:1.1.1.1
      Rev: src/compilation.h:1.1.1.1
      Rev: src/config.h:1.1.1.1
      Rev: src/config.log:1.1.1.1
      Rev: src/configure:1.1.1.1
      Rev: src/configure.in:1.1.1.1
      Rev: src/debug.c:1.1.1.1
      Rev: src/debug.h:1.1.1.1
      Rev: src/docode.c:1.1.1.1
      Rev: src/docode.h:1.1.1.1
      Rev: src/dynamic_buffer.c:1.1.1.1
      Rev: src/dynamic_buffer.h:1.1.1.1
      Rev: src/efun.h:1.1.1.1
      Rev: src/error.c:1.1.1.1
      Rev: src/error.h:1.1.1.1
      Rev: src/fd_control.c:1.1.1.1
      Rev: src/fd_control.h:1.1.1.1
      Rev: src/fsort.c:1.1.1.1
      Rev: src/fsort.h:1.1.1.1
      Rev: src/get_linker_options:1.1.1.1
      Rev: src/global.h:1.1.1.1
      Rev: src/hashtable.c:1.1.1.1
      Rev: src/hashtable.h:1.1.1.1
      Rev: src/install-sh:1.1.1.1
      Rev: src/interpret.c:1.1.1.1
      Rev: src/interpret.h:1.1.1.1
      Rev: src/language.y:1.1.1.1
      Rev: src/las.c:1.1.1.1
      Rev: src/las.h:1.1.1.1
      Rev: src/lex.c:1.1.1.1
      Rev: src/lex.h:1.1.1.1
      Rev: src/list.c:1.1.1.1
      Rev: src/list.h:1.1.1.1
      Rev: src/lpc_signal.c:1.1.1.1
      Rev: src/lpc_signal.h:1.1.1.1
      Rev: src/lpc_types.c:1.1.1.1
      Rev: src/lpc_types.h:1.1.1.1
      Rev: src/machine.h.in:1.1.1.1
      Rev: src/macros.h:1.1.1.1
      Rev: src/main.c:1.1.1.1
      Rev: src/main.h:1.1.1.1
      Rev: src/make_modules:1.1.1.1
      Rev: src/mapping.c:1.1.1.1
      Rev: src/mapping.h:1.1.1.1
      Rev: src/memory.c:1.1.1.1
      Rev: src/memory.h:1.1.1.1
      Rev: src/module.c:1.1.1.1
      Rev: src/module.h:1.1.1.1
      Rev: src/modules/efuns.c:1.1.1.1
      Rev: src/modules/files/Makefile.in:1.1.1.1
      Rev: src/modules/files/configure:1.1.1.1
      Rev: src/modules/files/configure.in:1.1.1.1
      Rev: src/modules/files/datagram.c:1.1.1.1
      Rev: src/modules/files/efuns.c:1.1.1.1
      Rev: src/modules/files/file.c:1.1.1.1
      Rev: src/modules/files/file.h:1.1.1.1
      Rev: src/modules/files/file_machine.h.in:1.1.1.1
      Rev: src/modules/files/socket.c:1.1.1.1
      Rev: src/modules/math/Makefile.in:1.1.1.1
      Rev: src/modules/math/configure:1.1.1.1
      Rev: src/modules/math/configure.in:1.1.1.1
      Rev: src/modules/math/math.c:1.1.1.1
      Rev: src/modules/regexp/Makefile.in:1.1.1.1
      Rev: src/modules/regexp/configure:1.1.1.1
      Rev: src/modules/regexp/configure.in:1.1.1.1
      Rev: src/modules/regexp/glue.c:1.1.1.1
      Rev: src/modules/regexp/regexp.c:1.1.1.1
      Rev: src/modules/regexp/regexp.h:1.1.1.1
      Rev: src/modules/sprintf/Makefile.in:1.1.1.1
      Rev: src/modules/sprintf/configure:1.1.1.1
      Rev: src/modules/sprintf/configure.in:1.1.1.1
      Rev: src/modules/sprintf/sprintf.c:1.1.1.1
      Rev: src/object.c:1.1.1.1
      Rev: src/object.h:1.1.1.1
      Rev: src/opcodes.c:1.1.1.1
      Rev: src/opcodes.h:1.1.1.1
      Rev: src/operators.c:1.1.1.1
      Rev: src/operators.h:1.1.1.1
      Rev: src/otable.h:1.1.1.1
      Rev: src/port.c:1.1.1.1
      Rev: src/port.h:1.1.1.1
      Rev: src/program.c:1.1.1.1
      Rev: src/program.h:1.1.1.1
      Rev: src/rusage.c:1.1.1.1
      Rev: src/rusage.h:1.1.1.1
      Rev: src/stamp-h:1.1.1.1
      Rev: src/stralloc.c:1.1.1.1
      Rev: src/stralloc.h:1.1.1.1
      Rev: src/stuff.c:1.1.1.1
      Rev: src/stuff.h:1.1.1.1
      Rev: src/svalue.c:1.1.1.1
      Rev: src/svalue.h:1.1.1.1
      Rev: src/todo:1.1.1.1
      Rev: src/types.h:1.1.1.1
      Rev: src/ualarm.c:1.1.1.1
    mapping.c 47.50 KiB
    /*\
    ||| This file a part of Pike, and is copyright by Fredrik Hubinette
    ||| Pike is distributed as GPL (General Public License)
    ||| See the files COPYING and DISCLAIMER for more information.
    \*/
    /**/
    #include "global.h"
    RCSID("$Id: mapping.c,v 1.103 2000/09/08 17:31:26 hubbe Exp $");
    #include "main.h"
    #include "object.h"
    #include "mapping.h"
    #include "svalue.h"
    #include "array.h"
    #include "pike_macros.h"
    #include "error.h"
    #include "pike_memory.h"
    #include "dynamic_buffer.h"
    #include "interpret.h"
    #include "las.h"
    #include "gc.h"
    #include "stralloc.h"
    #include "security.h"
    #include "block_alloc.h"
    #include "opcodes.h"
    
    #define AVG_LINK_LENGTH 4
    #define MIN_LINK_LENGTH 1
    #define MAP_SLOTS(X) ((X)?((X)+((X)>>4)+8):0)
    
    struct mapping *first_mapping;
    
    struct mapping *gc_internal_mapping = 0;
    static struct mapping *gc_mark_mapping_pos = 0;
    
    #define unlink_mapping_data(M) do{				\
     struct mapping_data *md_=(M);					\
     if(md_->hardlinks) { md_->hardlinks--; md_->valrefs--; }	\
     free_mapping_data(M);						\
    }while(0)
    
    
    #define MD_KEYPAIRS(MD, HSIZE) \
       ( (struct keypair *)DO_ALIGN( (ptrdiff_t) (((struct mapping_data *)(MD))->hash + HSIZE), ALIGNOF(struct keypair)) )
    
    #define MAPPING_DATA_SIZE(HSIZE, KEYPAIRS) \
       (ptrdiff_t)( MD_KEYPAIRS(0, HSIZE) + KEYPAIRS )
       
       
    
    #undef EXIT_BLOCK
    #define EXIT_BLOCK(m)							\
      INT32 e;								\
    DO_IF_DEBUG(								\
      if(m->refs)								\
        fatal("really free mapping on mapping with nonzero refs.\n");	\
    )									\
    									\
      FREE_PROT(m);								\
    									\
      unlink_mapping_data(m->data);						\
    									\
      if (gc_internal_mapping) {						\
        if (m == gc_internal_mapping)					\
          gc_internal_mapping = m->next;					\
        if (m == gc_mark_mapping_pos)					\
          gc_mark_mapping_pos = m->next;					\
      }									\
      DOUBLEUNLINK(first_mapping, m);					\
    									\
      GC_FREE();
    
    
    #undef COUNT_OTHER
    
    #define COUNT_OTHER() do{				\
      struct mapping *m;					\
      for(m=first_mapping;m;m=m->next)			\
      {							\
        num++;						\
        size+=MAPPING_DATA_SIZE(m->data->hashsize, m->data->num_keypairs); \
      }							\
    }while(0)
    
    BLOCK_ALLOC(mapping, 511)
    
    
    #ifdef PIKE_DEBUG
    /* This function checks that the type field isn't lacking any bits.
     * It is used for debugging purposes only.
     */
    static void check_mapping_type_fields(struct mapping *m)
    {
      INT32 e;
      struct keypair *k=0,**prev;
      TYPE_FIELD ind_types, val_types;
    
      ind_types=val_types=0;
    
      MAPPING_LOOP(m) 
        {
          val_types |= 1 << k->val.type;
          ind_types |= 1 << k->ind.type;
        }
    
      if(val_types & ~(m->data->val_types))
        fatal("Mapping value types out of order!\n");
    
      if(ind_types & ~(m->data->ind_types))
        fatal("Mapping indices types out of order!\n");
    }
    #endif
    
    static struct mapping_data empty_data = { 1, 1, 0,0,0,0,0,0 };
    
    /* This function allocates the hash table and svalue space for a mapping
     * struct. The size is the max number of indices that can fit in the
     * allocated space.
     */
    static void init_mapping(struct mapping *m, INT32 size)
    {
      struct mapping_data *md;
      char *tmp;
      ptrdiff_t e;
      INT32 hashsize;
    
      debug_malloc_touch(m);
    #ifdef PIKE_DEBUG
      if (Pike_in_gc > GC_PASS_PREPARE && Pike_in_gc < GC_PASS_ZAP_WEAK)
        fatal("Can't allocate a new mapping_data inside gc.\n");
      if(size < 0) fatal("init_mapping with negative value.\n");
    #endif
      if(size)
      {
        hashsize=size / AVG_LINK_LENGTH + 1;
        if(!(hashsize & 1)) hashsize++;
    
        e=MAPPING_DATA_SIZE(hashsize, size);
    
        md=(struct mapping_data *)xalloc(e);
    
        m->data=md;
        md->hashsize=hashsize;
        
        MEMSET((char *)md->hash, 0, sizeof(struct keypair *) * md->hashsize);
        
        md->free_list=MD_KEYPAIRS(md, hashsize);
        for(e=1;e<size;e++)
        {
          md->free_list[e-1].next = md->free_list + e;
          md->free_list[e-1].ind.type=T_INT;
          md->free_list[e-1].val.type=T_INT;
        }
        md->free_list[e-1].next=0;
        md->free_list[e-1].ind.type=T_INT;
        md->free_list[e-1].val.type=T_INT;
        md->ind_types = 0;
        md->val_types = 0;
        md->flags = 0;
        md->size = 0;
        md->refs=0;
        md->valrefs=0;
        md->hardlinks=0;
        md->num_keypairs=size;
      }else{
        md=&empty_data;
      }
      add_ref(md);
      m->data=md;
    #ifdef MAPPING_SIZE_DEBUG
      m->debug_size = md->size;
    #endif
    }
    
    /* This function allocates an empty mapping with room for 'size' values
     */
    PMOD_EXPORT struct mapping *debug_allocate_mapping(int size)
    {
      struct mapping *m;
    
      m=alloc_mapping();
    
      GC_ALLOC(m);
    
      INITIALIZE_PROT(m);
      init_mapping(m,size);
    
      m->refs = 1;
    
      DOUBLELINK(first_mapping, m);
    
      return m;
    }
    
    
    PMOD_EXPORT void really_free_mapping_data(struct mapping_data *md)
    {
      INT32 e;
      struct keypair *k;
      debug_malloc_touch(md);
    #ifdef PIKE_DEBUG
      if (md->refs) {
        fatal("really_free_mapping_data(): md has non-zero refs: %d\n",
    	  md->refs);
      }
    #endif /* PIKE_DEBUG */
      NEW_MAPPING_LOOP(md)
      {
        free_svalue(& k->val);
        free_svalue(& k->ind);
      }
    
      free((char *) md);
    }
    
    PMOD_EXPORT void do_free_mapping(struct mapping *m)
    {
      if (m)
        free_mapping(m);
    }
    
    /* This function is used to rehash a mapping without loosing the internal
     * order in each hash chain. This is to prevent mappings from becoming
     * inefficient just after being rehashed.
     */
    static void mapping_rehash_backwards_evil(struct mapping_data *md,
    					  struct keypair *from)
    {
      unsigned INT32 h;
      struct keypair *tmp;
      struct keypair *k;
    
      if(!from) return;
      mapping_rehash_backwards_evil(md,from->next);
    
      /* unlink */
      k=md->free_list;
    #ifdef PIKE_DEBUG
      if(!k) fatal("Error in rehash: not enough keypairs.\n");
    #endif
      md->free_list=k->next;
    
      /* initialize */
      *k=*from;
    
      /* link */
      h=k->hval;
      h%=md->hashsize;
      k->next=md->hash[h];
      md->hash[h]=k;
    
      /* update */
      md->ind_types |= 1<< (k->ind.type);
      md->val_types |= 1<< (k->val.type);
      md->size++;
    }
    
    static void mapping_rehash_backwards_good(struct mapping_data *md,
    					  struct keypair *from)
    {
      unsigned INT32 h;
      struct keypair *tmp;
      struct keypair *k;
    
      if(!from) return;
      mapping_rehash_backwards_good(md,from->next);
    
      /* unlink */
      k=md->free_list;
    #ifdef PIKE_DEBUG
      if(!k) fatal("Error in rehash: not enough keypairs.\n");
    #endif
      md->free_list=k->next;
    
      /* initialize */
      k->hval=from->hval;
      assign_svalue_no_free(&k->ind, &from->ind);
      assign_svalue_no_free(&k->val, &from->val);
    
      /* link */
      h=k->hval;
      h%=md->hashsize;
      k->next=md->hash[h];
      md->hash[h]=k;
    
      /* update */
      md->ind_types |= 1<< (k->ind.type);
      md->val_types |= 1<< (k->val.type);
      md->size++;
    }
    
    /* This function re-allocates a mapping. It adjusts the max no. of
     * values can be fitted into the mapping. It takes a bit of time to
     * run, but is used seldom enough not to degrade preformance significantly.
     */
    static struct mapping *rehash(struct mapping *m, int new_size)
    {
      struct mapping_data *md, *new_md;
    #ifdef PIKE_DEBUG
      INT32 tmp=m->data->size;
    #endif
      INT32 e;
    
      md=m->data;
      debug_malloc_touch(md);
    #ifdef PIKE_DEBUG
      if(md->refs <=0)
        fatal("Zero refs in mapping->data\n");
    
      if(d_flag>1)  check_mapping(m);
    #endif
    
      init_mapping(m, new_size);
      debug_malloc_touch(m);
      new_md=m->data;
      new_md->flags = md->flags;
    
      /* This operation is now 100% atomic - no locking required */
      if(md->refs>1)
      {
        /* good */
        for(e=0;e<md->hashsize;e++)
          mapping_rehash_backwards_good(new_md, md->hash[e]);
    
        unlink_mapping_data(md);
      }else{
        /* evil */
        for(e=0;e<md->hashsize;e++)
          mapping_rehash_backwards_evil(new_md, md->hash[e]);
    
        free((char *)md);
      }
    
    #ifdef PIKE_DEBUG
      if(m->data->size != tmp)
        fatal("Rehash failed, size not same any more.\n");
    #endif
    #ifdef MAPPING_SIZE_DEBUG
      m->debug_size = m->data->size;
    #endif
    
    #ifdef PIKE_DEBUG
      if(d_flag>1)  check_mapping(m);
    #endif
    
      return m;
    }
    
    /*
     * No need for super efficiency, should not be called very often
     * -Hubbe
     */
    #define LOW_RELOC(X) X= (void *) ((char *)(X) + off);
    #define RELOC(X) if(X) LOW_RELOC(X)
    
    struct mapping_data *copy_mapping_data(struct mapping_data *md)
    {
      long e;
      ptrdiff_t size, off;
      struct mapping_data *nmd;
      struct keypair *keypairs;
    
    #ifdef PIKE_DEBUG
      if (Pike_in_gc > GC_PASS_PREPARE && Pike_in_gc < GC_PASS_ZAP_WEAK)
        fatal("Can't allocate a new mapping_data inside gc.\n");
    #endif
    
      debug_malloc_touch(md);
    
      size=MAPPING_DATA_SIZE(md->hashsize, md->num_keypairs);
    
      nmd=(struct mapping_data *)xalloc(size);
      MEMCPY(nmd, md, size);
      off=((char *)nmd) - ((char *)md);
    
      RELOC(nmd->free_list);
      for(e=0;e<nmd->hashsize;e++) RELOC(nmd->hash[e]);
    
      keypairs=MD_KEYPAIRS(nmd, nmd->hashsize);
      for(e=0;e<nmd->num_keypairs;e++)
      {
        RELOC(keypairs[e].next);
        add_ref_svalue(& keypairs[e].ind);
        add_ref_svalue(& keypairs[e].val);
      }
    
      nmd->refs=1;
      nmd->valrefs=0;
      nmd->hardlinks=0;
    
      if(md->hardlinks)
      {
    #ifdef PIKE_DEBUG
        if(md->refs <= 0 || md->valrefs<=0)
          fatal("Hardlink without refs/valrefs!\n");
    #endif
        md->hardlinks--;
        md->valrefs--;
      }
      md->refs--;
    
      return nmd;
    }
    
    #define MAPPING_DATA_IN_USE(MD) ((MD)->refs != (MD)->hardlinks + 1)
    
    #define LOW_FIND(FUN, KEY, FOUND, NOT_FOUND) do {		\
      md=m->data;                                                   \
      add_ref(md);						        \
      if(md->hashsize)						\
      {								\
        h=h2 % md->hashsize;					\
        DO_IF_DEBUG( if(d_flag > 1) check_mapping_type_fields(m); ) \
        if(md->ind_types & (1 << key->type))			\
        {								\
          for(prev= md->hash + h;(k=*prev);prev=&k->next)		\
          {								\
    	if(h2 == k->hval && FUN(& k->ind, KEY))		        \
    	{							\
    	  FOUND;						\
    	}							\
          }								\
        }								\
      }								\
      NOT_FOUND;                                                    \
    }while(0)
    
    
    #define LOW_FIND2(FUN, KEY, FOUND, NOT_FOUND) do {		\
      struct keypair *k2;						\
      md=m->data;							\
      add_ref(md);							\
      if(md->hashsize)						\
      {								\
        h=h2 % md->hashsize;					\
        DO_IF_DEBUG( if(d_flag > 1) check_mapping_type_fields(m); ) \
        if(md->ind_types & (1 << key->type))			\
        {								\
          k2=omd->hash[h2 % md->hashsize];			        \
          prev= md->hash + h;					\
          for(;(k=*prev) && k2;(prev=&k->next),(k2=k2->next))	\
            if(!(h2 == k->hval && is_identical(&k2->ind, &k->ind)))	\
               break;						\
          for(;(k=*prev);prev=&k->next)				\
          {								\
    	if(FUN(& k->ind, KEY))					\
    	{							\
    	  FOUND;						\
    	}							\
          }								\
        }								\
      }								\
      NOT_FOUND;							\
    }while(0)
    
    
    #define SAME_DATA(SAME,NOT_SAME) 	\
      if(m->data == md)				\
      {						\
        SAME;					\
      }else{ 					\
        NOT_SAME;					\
      }
    
    
    /* FIXME: the 'no action' might need to be fixed.... */
    #define FIND() do{						\
      LOW_FIND(is_eq, key,						\
    	   omd=md;						\
    	   SAME_DATA( break,					\
    		     struct svalue *tmp=&k->ind;		\
    		     LOW_FIND(is_identical, tmp, break, ;);	\
    		     free_mapping_data(omd)),			\
    	   break);				                \
        free_mapping_data(md);					\
    }while(0)
    
          
    /* Assumes md is *NOT* locked */
    #define COPYMAP2() do {				\
      ptrdiff_t off;				\
      m->data=copy_mapping_data(m->data);		\
      debug_malloc_touch(m->data);                  \
      DO_IF_DEBUG( if(d_flag>1)  check_mapping(m); ) \
      off=((char *)m->data)-((char *)md);		\
      LOW_RELOC(k);					\
      LOW_RELOC(prev);				\
      md=m->data;                                   \
    }while(0)
    
    #define PREPARE_FOR_DATA_CHANGE2() \
     if(md->valrefs) COPYMAP2()
    
    #define PREPARE_FOR_INDEX_CHANGE2() \
      if(md->refs>1) COPYMAP2()
    
    #define PROPAGATE() do {			\
       if(md->refs==1)				\
       {						\
         h=h2 % md->hashsize;                       \
         *prev=k->next;				\
         k->next=md->hash[h];			\
         md->hash[h]=k;				\
       }						\
     }while(0)
    
    
    /* Assumes md is locked */
    #define COPYMAP() do {			        \
      ptrdiff_t off;				\
      m->data=copy_mapping_data(m->data);		\
      debug_malloc_touch(m->data);                  \
      off=((char *)m->data)-((char *)md);		\
      LOW_RELOC(k);					\
      free_mapping_data(md);                        \
      md=m->data;                                   \
      md->refs++;                                   \
    }while(0)
    
    #define PREPARE_FOR_DATA_CHANGE() \
     if(md->valrefs) COPYMAP()
    
    #define PREPARE_FOR_INDEX_CHANGE() \
     if(md->refs>1) COPYMAP()
    
    /* This function brings the type fields in the mapping up to speed.
     * I only use it when the type fields MUST be correct, which is not
     * very often.
     */
    PMOD_EXPORT void mapping_fix_type_field(struct mapping *m)
    {
      INT32 e;
      struct keypair *k;
      TYPE_FIELD ind_types, val_types;
    
      val_types = ind_types = 0;
    
      NEW_MAPPING_LOOP(m->data)
        {
          val_types |= 1 << k->val.type;
          ind_types |= 1 << k->ind.type;
        }
    
    #ifdef PIKE_DEBUG
      if(val_types & ~(m->data->val_types))
        fatal("Mapping value types out of order!\n");
    
      if(ind_types & ~(m->data->ind_types))
        fatal("Mapping indices types out of order!\n");
    #endif
      m->data->val_types = val_types;
      m->data->ind_types = ind_types;
    }
    
    PMOD_EXPORT void mapping_set_flags(struct mapping *m, int flags)
    {
      struct mapping_data *md = m->data;
      if (md->refs > 1) {
        struct keypair *k = NULL, *prev = NULL;
        COPYMAP2();
      }
      md->flags = flags;
    }
    
    
    /* This function inserts key:val into the mapping m.
     * Same as doing m[key]=val; in pike.
     */
    PMOD_EXPORT void low_mapping_insert(struct mapping *m,
    			struct svalue *key,
    			struct svalue *val,
    			int overwrite)
    {
      unsigned INT32 h,h2;
      struct keypair *k, **prev;
      struct mapping_data *md, *omd;
    
    #ifdef PIKE_DEBUG
      if(m->data->refs <=0)
        fatal("Zero refs in mapping->data\n");
    #endif
    
      h2=hash_svalue(key);
      
    #ifdef PIKE_DEBUG
      if(d_flag>1)  check_mapping(m);
    #endif
    
      LOW_FIND(is_eq, key,
    	   struct svalue *tmp=&k->ind;
    	   SAME_DATA(goto mi_set_value,
    		     omd=md;
    		     LOW_FIND(is_identical, tmp,
    			      free_mapping_data(omd);
    			      goto mi_set_value,
    			      free_mapping_data(omd);
    			      goto mi_do_nothing)),
    	   Z:
    	   SAME_DATA(goto mi_insert,
    		     omd=md;
    		     LOW_FIND2(is_eq, key,
    			       free_mapping_data(omd);
    			       goto mi_do_nothing,
    			       free_mapping_data(omd);
    			       goto Z)));
    
     mi_do_nothing:
      free_mapping_data(md);
      return;
    
     mi_set_value:
    #ifdef PIKE_DEBUG
      if(m->data != md)
        fatal("Wrong dataset in mapping_insert!\n");
      if(d_flag>1)  check_mapping(m);
    #endif
      free_mapping_data(md);
      if(!overwrite) return;
      PREPARE_FOR_DATA_CHANGE2();
      PROPAGATE(); /* propagate after preparing */
      md->val_types |= 1 << val->type;
      assign_svalue(& k->val, val);
    #ifdef PIKE_DEBUG
      if(d_flag>1)  check_mapping(m);
    #endif
      return;
    
     mi_insert:
    #ifdef PIKE_DEBUG
      if(m->data != md)
        fatal("Wrong dataset in mapping_insert!\n");
      if(d_flag>1)  check_mapping(m);
    #endif
      free_mapping_data(md);
      /* We do a re-hash here instead of copying the mapping. */
      if((!(k=md->free_list)) || md->refs>1)
      {
        debug_malloc_touch(m);
        rehash(m, md->size * 2 + 2);
        md=m->data;
        k=md->free_list;
      }
      h=h2 % md->hashsize;
    
      /* no need to lock here since we are not calling is_eq - Hubbe */
    
      k=md->free_list;
      md->free_list=k->next;
      k->next=md->hash[h];
      md->hash[h]=k;
      md->ind_types |= 1 << key->type;
      md->val_types |= 1 << val->type;
      assign_svalue_no_free(& k->ind, key);
      assign_svalue_no_free(& k->val, val);
      k->hval = h2;
      md->size++;
    #ifdef MAPPING_SIZE_DEBUG
      if(m->data ==md)
        m->debug_size++;
    #endif
    
    #ifdef PIKE_DEBUG
      if(d_flag>1)  check_mapping(m);
    #endif
    }
    
    PMOD_EXPORT void mapping_insert(struct mapping *m,
    		    struct svalue *key,
    		    struct svalue *val)
    {
      low_mapping_insert(m,key,val,1);
    }
    
    PMOD_EXPORT union anything *mapping_get_item_ptr(struct mapping *m,
    				     struct svalue *key,
    				     TYPE_T t)
    {
      unsigned INT32 h, h2;
      struct keypair *k, **prev;
      struct mapping_data *md,*omd;
    
    #ifdef PIKE_DEBUG
      if(m->data->refs <=0)
        fatal("Zero refs in mapping->data\n");
    
      if(d_flag>1)  check_mapping(m);
    
      debug_malloc_touch(m);
      debug_malloc_touch(m->data);
    #endif
    
      h2=hash_svalue(key);
    
      LOW_FIND(is_eq, key,
    	   struct svalue *tmp=&k->ind;
    	   SAME_DATA(goto mg_set_value,
    		     omd=md;
    		     LOW_FIND(is_identical, tmp,
    			      free_mapping_data(omd);
    			      goto mg_set_value,
    			      free_mapping_data(omd);
    			      goto mg_do_nothing)),
    	   Z:
    	   SAME_DATA(goto mg_insert,
    		     omd=md;
    		     LOW_FIND2(is_eq, key,
    			       free_mapping_data(omd);
    			       goto mg_do_nothing,
    			       free_mapping_data(omd);
    			       goto Z)));
    
    
    
     mg_do_nothing:
      free_mapping_data(md);
      return 0;
    
     mg_set_value:
    #ifdef PIKE_DEBUG
      if(m->data != md)
        fatal("Wrong dataset in mapping_get_item_ptr!\n");
      if(d_flag)
        check_mapping(m);
    #endif
      free_mapping_data(md);
      if(k->val.type == t)
      {
        PREPARE_FOR_DATA_CHANGE2();
        PROPAGATE(); /* prepare then propagate */
        
        return & ( k->val.u );
      }
      
      return 0;
      
     mg_insert:
    #ifdef PIKE_DEBUG
      if(m->data != md)
        fatal("Wrong dataset in mapping_get_item_ptr!\n");
      if(d_flag)
        check_mapping(m);
    #endif
      free_mapping_data(md);
    
      if(t != T_INT) return 0;
    
      /* no need to call PREPARE_* because we re-hash instead */
      if(!(k=md->free_list) || md->refs>1)
      {
        debug_malloc_touch(m);
        rehash(m, md->size * 2 + 2);
        md=m->data;
        k=md->free_list;
      }
      h=h2 % md->hashsize;
    
      md->free_list=k->next;
      k->next=md->hash[h];
      md->hash[h]=k;
      assign_svalue_no_free(& k->ind, key);
      k->val.type=T_INT;
      k->val.subtype=NUMBER_NUMBER;
      k->val.u.integer=0;
      k->hval = h2;
      md->ind_types |= 1 << key->type;
      md->val_types |= BIT_INT;
      md->size++;
    #ifdef MAPPING_SIZE_DEBUG
      if(m->data ==md)
        m->debug_size++;
    #endif
    
    #ifdef PIKE_DEBUG
      if(d_flag > 1) check_mapping_type_fields(m);
    #endif
    
      return & ( k->val.u );
    }
    
    PMOD_EXPORT void map_delete_no_free(struct mapping *m,
    			struct svalue *key,
    			struct svalue *to)
    {
      unsigned INT32 h,h2;
      struct keypair *k, **prev;
      struct mapping_data *md,*omd;
    
    #ifdef PIKE_DEBUG
      if(m->data->refs <=0)
        fatal("Zero refs in mapping->data\n");
      if(d_flag>1)  check_mapping(m);
      debug_malloc_touch(m);
    #endif
    
      h2=hash_svalue(key);
    
      LOW_FIND(is_eq, key,
    	   struct svalue *tmp=&k->ind;
    	   SAME_DATA(goto md_remove_value,
    		     omd=md;
    		     LOW_FIND(is_identical, tmp,
    			      free_mapping_data(omd);
    			      goto md_remove_value,
    			      free_mapping_data(omd);
    			      goto md_do_nothing)),
    	   goto md_do_nothing);
    
     md_do_nothing:
      debug_malloc_touch(m);
      free_mapping_data(md);
      if(to)
      {
        to->type=T_INT;
        to->subtype=NUMBER_UNDEFINED;
        to->u.integer=0;
      }
      return;
    
     md_remove_value:
    #ifdef PIKE_DEBUG
      if(md->refs <= 1)
        fatal("Too few refs i mapping->data\n");
      if(m->data != md)
        fatal("Wrong dataset in mapping_delete!\n");
      if(d_flag>1)  check_mapping(m);
      debug_malloc_touch(m);
    #endif
      free_mapping_data(md);
      PREPARE_FOR_INDEX_CHANGE2();
      /* No need to propagate */
      *prev=k->next;
      free_svalue(& k->ind);
      if(to)
        to[0]=k->val;
      else
        free_svalue(& k->val);
    
      k->ind.type=T_INT;
      k->val.type=T_INT;
    
      k->next=md->free_list;
      md->free_list=k;
      md->size--;
    #ifdef MAPPING_SIZE_DEBUG
      if(m->data ==md)
        m->debug_size--;
    #endif
      
      if(md->size < (md->hashsize + 1) * MIN_LINK_LENGTH)
      {
        debug_malloc_touch(m);
        rehash(m, MAP_SLOTS(m->data->size));
      }
      
    #ifdef PIKE_DEBUG
      if(d_flag>1)  check_mapping(m);
    #endif
      return;
    }
    
    static void low_check_mapping_for_destruct(
      struct mapping_data *md, int e, struct keypair **prev,
      TYPE_FIELD ind_types, TYPE_FIELD val_types)
    {
      struct keypair *k;
    
    #ifdef PIKE_DEBUG
      if (MAPPING_DATA_IN_USE(md)) fatal("The mapping data is busy.\n");
    #endif
      debug_malloc_touch(md);
    
      if (prev) {
        k = *prev;
        goto jump_in;
      }
    
      for(e=0;e<md->hashsize;e++)
      {
        for(prev= md->hash + e;(k=*prev);)
        {
        jump_in:
          check_destructed(& k->val);
    	
          if((k->ind.type == T_OBJECT || k->ind.type == T_FUNCTION) &&
    	 !k->ind.u.object->prog)
          {
    	*prev=k->next;
    	free_svalue(& k->ind);
    	free_svalue(& k->val);
    	k->next=md->free_list;
    	md->free_list=k;
    	md->size--;
          }else{
    	val_types |= 1 << k->val.type;
    	ind_types |= 1 << k->ind.type;
    	prev=&k->next;
          }
        }
      }
    
      md->val_types = val_types;
      md->ind_types = ind_types;
    }
    
    PMOD_EXPORT void check_mapping_for_destruct(struct mapping *m)
    {
      INT32 e;
      struct keypair *k, **prev;
      TYPE_FIELD ind_types, val_types;
      struct mapping_data *md=m->data;
    
    #ifdef PIKE_DEBUG
      if(m->data->refs <=0)
        fatal("Zero refs in mapping->data\n");
      if(d_flag>1)  check_mapping(m);
      debug_malloc_touch(m);
    #endif
    
      /* no is_eq -> no locking */
    
      if(!md->size) return;
    
      if((md->ind_types | md->val_types) & (BIT_OBJECT | BIT_FUNCTION))
      {
        val_types = ind_types = 0;
        md->val_types |= BIT_INT;
        for(e=0;e<md->hashsize;e++)
        {
          for(prev= md->hash + e;(k=*prev);)
          {
    	if((k->ind.type == T_OBJECT || k->ind.type == T_FUNCTION) &&
    	   !k->ind.u.object->prog)
    	{
    #ifdef MAPPING_SIZE_DEBUG
    	  size_t old_size = md->size;
    #endif
    	  debug_malloc_touch(m);
    	  debug_malloc_touch(md);
    	  PREPARE_FOR_INDEX_CHANGE2();
    	  low_check_mapping_for_destruct (md, e, prev, ind_types, val_types);
    #ifdef MAPPING_SIZE_DEBUG
    	  m->debug_size -= old_size - md->size;
    #endif
    	  goto done;
    	}else{
    	  check_destructed(& k->val);
    	  val_types |= 1 << k->val.type;
    	  ind_types |= 1 << k->ind.type;
    	  prev=&k->next;
    	}
          }
        }
    
      done:
        if(MAP_SLOTS(md->size) < md->hashsize * MIN_LINK_LENGTH)
        {
          debug_malloc_touch(m);
          rehash(m, MAP_SLOTS(md->size));
        }
    
    #ifdef PIKE_DEBUG
        if(d_flag>1)  check_mapping(m);
    #endif
      }
    }
    
    /* This one doesn't copy the mapping data before writing it. Instead
     * it does nothing at all if the mapping data is busy. */
    static void stealth_check_mapping_for_destruct(struct mapping *m)
    {
      struct mapping_data *md=m->data;
    
      if (MAPPING_DATA_IN_USE(md)) {
        TYPE_FIELD val_types = 0;
        INT32 e;
        struct keypair *k;
        md->val_types |= BIT_INT;
        NEW_MAPPING_LOOP(md) {
          check_destructed(&k->val);
          val_types |= 1 << k->val.type;
        }
        md->val_types = val_types;
      }
    
      else
        if((md->ind_types | md->val_types) & (BIT_OBJECT | BIT_FUNCTION))
          low_check_mapping_for_destruct (md, 0, 0, 0, 0);
    }
    
    PMOD_EXPORT struct svalue *low_mapping_lookup(struct mapping *m,
    				  struct svalue *key)
    {
      unsigned INT32 h,h2;
      struct keypair *k=0, **prev=0;
      struct mapping_data *md, *omd;
    
    #ifdef PIKE_DEBUG
      if(m->data->refs <=0)
        fatal("Zero refs in mapping->data\n");
      if(d_flag>1)  check_mapping(m);
    #endif
    
      h2=hash_svalue(key);
    #ifdef PIKE_DEBUG
      if(d_flag > 1) check_mapping_type_fields(m);
    #endif
      FIND();
      if(k)
      {
        PROPAGATE();
        return &k->val;
      }
      return 0;
    }
    
    PMOD_EXPORT struct svalue *low_mapping_string_lookup(struct mapping *m,
    					 struct pike_string *p)
    {
      struct svalue tmp;
      tmp.type=T_STRING;
      tmp.u.string=p;
      return low_mapping_lookup(m, &tmp);
    }
    
    PMOD_EXPORT void mapping_string_insert(struct mapping *m,
    			   struct pike_string *p,
    			   struct svalue *val)
    {
      struct svalue tmp;
      tmp.type=T_STRING;
      tmp.u.string=p;
      mapping_insert(m, &tmp, val);
    }
    
    PMOD_EXPORT void mapping_string_insert_string(struct mapping *m,
    				  struct pike_string *p,
    				  struct pike_string *val)
    {
      struct svalue tmp;
      tmp.type=T_STRING;
      tmp.u.string=val;
      mapping_string_insert(m, p, &tmp);
    }
    
    PMOD_EXPORT struct svalue *simple_mapping_string_lookup(struct mapping *m,
    					    char *p)
    {
      struct pike_string *tmp;
      if((tmp=findstring(p)))
        return low_mapping_string_lookup(m,tmp);
      return 0;
    }
    
    PMOD_EXPORT struct svalue *mapping_mapping_lookup(struct mapping *m,
    				      struct svalue *key1,
    				      struct svalue *key2,
    				      int create)
    {
      struct svalue tmp;
      struct mapping *m2;
      struct svalue *s=low_mapping_lookup(m, key1);
      debug_malloc_touch(m);
    
    #ifdef PIKE_DEBUG
      if(m->data->refs <=0)
        fatal("Zero refs in mapping->data\n");
    #endif
    
      if(!s || !s->type==T_MAPPING)
      {
        if(!create) return 0;
        tmp.u.mapping=allocate_mapping(5);
        tmp.type=T_MAPPING;
        mapping_insert(m, key1, &tmp);
        debug_malloc_touch(m);
        debug_malloc_touch(tmp.u.mapping);
        free_mapping(tmp.u.mapping); /* There is one ref in 'm' */
        s=&tmp;
      }
    
      m2=s->u.mapping;
      debug_malloc_touch(m2);
      s=low_mapping_lookup(m2, key2);
      if(s) return s;
      if(!create) return 0;
    
      tmp.type=T_INT;
      tmp.subtype=NUMBER_UNDEFINED;
      tmp.u.integer=0;
    
      mapping_insert(m2, key2, &tmp);
      debug_malloc_touch(m2);
    
      return low_mapping_lookup(m2, key2);
    }
    
    
    PMOD_EXPORT struct svalue *mapping_mapping_string_lookup(struct mapping *m,
    				      struct pike_string *key1,
    				      struct pike_string *key2,
    				      int create)
    {
      struct svalue k1,k2;
      k1.type=T_STRING;
      k1.u.string=key1;
      k2.type=T_STRING;
      k2.u.string=key2;
      return mapping_mapping_lookup(m,&k1,&k2,create);
    }
    
    
    
    PMOD_EXPORT void mapping_index_no_free(struct svalue *dest,
    			   struct mapping *m,
    			   struct svalue *key)
    {
      struct svalue *p;
    
      if((p=low_mapping_lookup(m,key)))
      {
        if(p->type==T_INT)
          p->subtype=NUMBER_NUMBER;
    
        assign_svalue_no_free(dest, p);
      }else{
        dest->type=T_INT;
        dest->u.integer=0;
        dest->subtype=NUMBER_UNDEFINED;
      }
    }
    
    PMOD_EXPORT struct array *mapping_indices(struct mapping *m)
    {
      INT32 e;
      struct array *a;
      struct svalue *s;
      struct keypair *k;
    
    #ifdef PIKE_DEBUG
      if(m->data->refs <=0)
        fatal("Zero refs in mapping->data\n");
    #endif
    
      a=allocate_array(m->data->size);
      s=ITEM(a);
    
      /* no locking required */
      NEW_MAPPING_LOOP(m->data) assign_svalue(s++, & k->ind);
    
      a->type_field = m->data->ind_types;
      
    #ifdef PIKE_DEBUG
      if(d_flag > 1) check_mapping_type_fields(m);
    #endif
    
      return a;
    }
    
    PMOD_EXPORT struct array *mapping_values(struct mapping *m)
    {
      INT32 e;
      struct keypair *k;
      struct array *a;
      struct svalue *s;
    
    #ifdef PIKE_DEBUG
      if(m->data->refs <=0)
        fatal("Zero refs in mapping->data\n");
    #endif
    
      a=allocate_array(m->data->size);
      s=ITEM(a);
    
      /* no locking required */
      NEW_MAPPING_LOOP(m->data) assign_svalue(s++, & k->val);
    
      a->type_field = m->data->val_types;
    
    #ifdef PIKE_DEBUG
      if(d_flag > 1) check_mapping_type_fields(m);
    #endif
      
      return a;
    }
    
    PMOD_EXPORT struct array *mapping_to_array(struct mapping *m)
    {
      INT32 e;
      struct keypair *k;
      struct array *a;
      struct svalue *s;
    
    #ifdef PIKE_DEBUG
      if(m->data->refs <=0)
        fatal("Zero refs in mapping->data\n");
    #endif
    
      a=allocate_array(m->data->size);
      s=ITEM(a);
    
      /* no locking required */
      NEW_MAPPING_LOOP(m->data)
        {
          struct array *b=allocate_array(2);
          assign_svalue(b->item+0, & k->ind);
          assign_svalue(b->item+1, & k->val);
          s->u.array=b;
          s->type=T_ARRAY;
          s++;
        }
      a->type_field = BIT_ARRAY;
    
      return a;
    }
    
    PMOD_EXPORT void mapping_replace(struct mapping *m,struct svalue *from, struct svalue *to)
    {
      INT32 e;
      struct keypair *k;
      struct mapping_data *md;
    
    #ifdef PIKE_DEBUG
      if(m->data->refs <=0)
        fatal("Zero refs in mapping->data\n");
    #endif
    
      md=m->data;
      if(md->size)
      {
        add_ref(md);
        NEW_MAPPING_LOOP(md)
          {
    	if(is_eq(& k->val, from))
    	{
    	  PREPARE_FOR_DATA_CHANGE();
    	  assign_svalue(& k->val, to);
    	  md->val_types|=1<<to->type;
    	}
          }
        free_mapping_data(md);
      }
    
    #ifdef PIKE_DEBUG
      if(d_flag > 1) check_mapping_type_fields(m);
    #endif
    }
    
    PMOD_EXPORT struct mapping *mkmapping(struct array *ind, struct array *val)
    {
      struct mapping *m;
      struct svalue *i,*v;
      INT32 e;
    
    #ifdef PIKE_DEBUG
      if(ind->size != val->size)
        fatal("mkmapping on different sized arrays.\n");
    #endif
    
      m=allocate_mapping(MAP_SLOTS(ind->size));
      i=ITEM(ind);
      v=ITEM(val);
      for(e=0;e<ind->size;e++) mapping_insert(m, i++, v++);
    
      return m;
    }
    
    #if 0
    PMOD_EXPORT struct mapping *copy_mapping(struct mapping *m)
    {
      INT32 e;
      struct mapping *n;
      struct keypair *k;
      struct mapping_data *md;
    
      md=m->data;
      n=allocate_mapping(MAP_SLOTS(md->size));
    
      md->valrefs++;
      add_ref(md);
      NEW_MAPPING_LOOP(md) mapping_insert(n, &k->ind, &k->val);
      md->valrefs--;
      free_mapping_data(md);
      
      return n;
    }
    #else
    
    /* deferred mapping copy! */
    PMOD_EXPORT struct mapping *copy_mapping(struct mapping *m)
    {
      struct mapping *n;
    
    #ifdef PIKE_DEBUG
      if(m->data->refs <=0)
        fatal("Zero refs in mapping->data\n");
    #endif
    
      n=allocate_mapping(0);
      if(!m_sizeof(m)) return n; /* done */
      debug_malloc_touch(n->data);
      free_mapping_data(n->data);
      n->data=m->data;
    #ifdef MAPPING_SIZE_DEBUG
      n->debug_size=n->data->size;
    #endif
      n->data->refs++;
      n->data->valrefs++;
      n->data->hardlinks++;
      debug_malloc_touch(n->data);
      return n;
    }
    
    #endif
    
    PMOD_EXPORT struct mapping *merge_mappings(struct mapping *a, struct mapping *b, INT32 op)
    {
      struct array *ai, *av;
      struct array *bi, *bv;
      struct array *ci, *cv;
      INT32 *zipper;
      struct mapping *m;
    
    #ifdef PIKE_DEBUG
      if(a->data->refs <=0)
        fatal("Zero refs in mapping->data\n");
      if(b->data->refs <=0)
        fatal("Zero refs in mapping->data\n");
    #endif
    
      ai=mapping_indices(a);
      av=mapping_values(a);
      if(ai->size > 1)
      {
        zipper=get_set_order(ai);
        order_array(ai, zipper);
        order_array(av, zipper);
        free((char *)zipper);
      }
    
      bi=mapping_indices(b);
      bv=mapping_values(b);
      if(bi->size > 1)
      {
        zipper=get_set_order(bi);
        order_array(bi, zipper);
        order_array(bv, zipper);
        free((char *)zipper);
      }
    
      zipper=merge(ai,bi,op);
    
      ci=array_zip(ai,bi,zipper);
      free_array(ai);
      free_array(bi);
    
      cv=array_zip(av,bv,zipper);
      free_array(av);
      free_array(bv);
      
      free((char *)zipper);
    
      m=mkmapping(ci, cv);
      free_array(ci);
      free_array(cv);
    
      return m;
    }
    
    PMOD_EXPORT struct mapping *merge_mapping_array_ordered(struct mapping *a, 
    					    struct array *b, INT32 op)
    {
      struct array *ai, *av;
      struct array *ci, *cv;
      INT32 *zipper;
      struct mapping *m;
    
      ai=mapping_indices(a);
      av=mapping_values(a);
      if(ai->size > 1)
      {
        zipper=get_set_order(ai);
        order_array(ai, zipper);
        order_array(av, zipper);
        free((char *)zipper);
      }
    
      switch (op) /* no elements from b may be selected */
      {
         case PIKE_ARRAY_OP_AND:
    	zipper=merge(b,ai,op);
    	ci=array_zip(b,ai,zipper); /* b must not be used */
    	cv=array_zip(b,av,zipper); /* b must not be used */
    	break;
         case PIKE_ARRAY_OP_SUB:
    	zipper=merge(ai,b,op);
    	ci=array_zip(ai,b,zipper); /* b must not be used */
    	cv=array_zip(av,b,zipper); /* b must not be used */
    	break;
         default:
    	fatal("merge_mapping_array on other than AND or SUB\n");
      }
    
      free_array(ai);
      free_array(av);
      
      free((char *)zipper);
    
      m=mkmapping(ci, cv);
      free_array(ci);
      free_array(cv);
    
      return m;
    }
    
    PMOD_EXPORT struct mapping *merge_mapping_array_unordered(struct mapping *a, 
    					      struct array *b, INT32 op)
    {
      struct array *b_temp;
      INT32 *zipper;
      struct mapping *m;
    
      if (b->size>1)
      {
        zipper=get_set_order(b);
        b_temp=reorder_and_copy_array(b,zipper);
        m=merge_mapping_array_ordered(a,b_temp,op);
        free_array(b_temp);
      }
      else
        m=merge_mapping_array_ordered(a,b,op);
    
      return m;
    }
    
    PMOD_EXPORT struct mapping *add_mappings(struct svalue *argp, INT32 args)
    {
      INT32 e,d;
      struct mapping *ret=0;
      struct keypair *k;
    
      for(e=d=0;d<args;d++)
      {
    #ifdef PIKE_DEBUG
        if(d_flag>1) check_mapping(argp[d].u.mapping);
    #endif
        e+=argp[d].u.mapping->data->size;
      }
    
      if(!e) return allocate_mapping(0);
    
      d=0;
    
      for(;d<args;d++)
      {
        struct mapping *m=argp[d].u.mapping;
        struct mapping_data *md=m->data;
    
        if(md->size == 0) continue;
    
        if(!(md->flags  && MAPPING_FLAG_WEAK))
        {
    #if 1 /* major optimization */
          if(e==md->size)
    	return copy_mapping(m);
    #endif
        
          if(m->refs == 1 && !md->hardlinks)
          {
    	add_ref( ret=m );
    	d++;
    	break;
          }
        }
        ret=allocate_mapping(MAP_SLOTS(e));
        break;
    
      }
    
      for(;d<args;d++)
      {
        struct mapping *m=argp[d].u.mapping;
        struct mapping_data *md=m->data;
        
        add_ref(md);
        NEW_MAPPING_LOOP(md)
          mapping_insert(ret, &k->ind, &k->val);
        free_mapping_data(md);
      }
    #ifdef PIKE_DEBUG
      if(!ret)
        fatal("add_mappings is confused!\n");
    #endif
      return ret;
    }
    
    PMOD_EXPORT int mapping_equal_p(struct mapping *a, struct mapping *b, struct processing *p)
    {
      struct processing curr;
      struct keypair *k;
      struct mapping_data *md;
      INT32 e,eq=1;
    
    #ifdef PIKE_DEBUG
      if(a->data->refs <=0)
        fatal("Zero refs in mapping->data\n");
      if(b->data->refs <=0)
        fatal("Zero refs in mapping->data\n");
    #endif
    
      if(a==b) return 1;
    
      check_mapping_for_destruct(a);
      check_mapping_for_destruct(b);
    
      if(m_sizeof(a) != m_sizeof(b)) return 0;
    
      curr.pointer_a = a;
      curr.pointer_b = b;
      curr.next = p;
    
      for( ;p ;p=p->next)
        if(p->pointer_a == (void *)a && p->pointer_b == (void *)b)
          return 1;
    
      md=a->data;
      md->valrefs++;
      add_ref(md);
    
      NEW_MAPPING_LOOP(md)
      {
        struct svalue *s;
        if((s=low_mapping_lookup(b, & k->ind)))
        {
          if(!low_is_equal(s, &k->val, &curr))
          {
    	eq=0;
    	break;
          }
        }else{
          eq=0;
          break;
        }
      }
      md->valrefs--;
      free_mapping_data(md);
      return eq;
    }
    
    void describe_mapping(struct mapping *m,struct processing *p,int indent)
    {
      struct processing doing;
      struct array *a;
      JMP_BUF catch;
      ONERROR err;
      INT32 e,d;
      struct keypair *k;
      char buf[40];
    
    #ifdef PIKE_DEBUG
      if(m->data->refs <=0)
        fatal("Zero refs in mapping->data\n");
    #endif
    
      if(! m->data->size)
      {
        my_strcat("([ ])");
        return;
      }
    
      doing.next=p;
      doing.pointer_a=(void *)m;
      for(e=0;p;e++,p=p->next)
      {
        if(p->pointer_a == (void *)m)
        {
          sprintf(buf,"@%ld",(long)e);
          my_strcat(buf);
          return;
        }
      }
    
      if (m->data->size == 1) {
        my_strcat("([ /* 1 element */\n");
      } else {
        sprintf(buf, "([ /* %ld elements */\n", (long)m->data->size);
        my_strcat(buf);
      }
    
      a = mapping_indices(m);
      SET_ONERROR(err, do_free_array, a);
    
      if(!SETJMP(catch))
        sort_array_destructively(a);
      UNSETJMP(catch);
    
      /* no mapping locking required (I hope) */
      for(e = 0; e < a->size; e++)
      {
        struct svalue *tmp;
        if(e)
          my_strcat(",\n");
        
        for(d = 0; d < indent; d++)
          my_putchar(' ');
        
        describe_svalue(ITEM(a)+e, indent+2, &doing);
        my_putchar(':');
        if((tmp=low_mapping_lookup(m, ITEM(a)+e)))
          describe_svalue(tmp, indent+2, &doing);
        else
          my_strcat("** gone **");
      }
    
      UNSET_ONERROR(err);
      free_array(a);
      
      my_putchar('\n');
      for(e=2; e<indent; e++) my_putchar(' ');
      my_strcat("])");
    }
    
    node *make_node_from_mapping(struct mapping *m)
    {
      struct keypair *k;
      INT32 e;
    
    #ifdef PIKE_DEBUG
      if(m->data->refs <=0)
        fatal("Zero refs in mapping->data\n");
    #endif
    
      mapping_fix_type_field(m);
    
      if((m->data->ind_types | m->data->val_types) & (BIT_FUNCTION | BIT_OBJECT))
      {
        struct array *ind, *val;
        node *n;
        ind=mapping_indices(m);
        val=mapping_values(m);
        n=mkefuncallnode("mkmapping",
    		     mknode(F_ARG_LIST,
    			    make_node_from_array(ind),
    			    make_node_from_array(val)));
        free_array(ind);
        free_array(val);
        return n;
      }else{
        struct svalue s;
    
        if(!m->data->size)
          return mkefuncallnode("aggregate_mapping",0);
    
        s.type=T_MAPPING;
        s.subtype=0;
        s.u.mapping=m;
        return mkconstantsvaluenode(&s);
      }
    }
    
    PMOD_EXPORT void f_aggregate_mapping(INT32 args)
    {
      INT32 e;
      struct keypair *k;
      struct mapping *m;
    
      if(args & 1)
        error("Uneven number of arguments to aggregate_mapping.\n");
    
      m=allocate_mapping(MAP_SLOTS(args / 2));
    
      for(e=-args;e<0;e+=2) mapping_insert(m, sp+e, sp+e+1);
      pop_n_elems(args);
    #ifdef PIKE_DEBUG
      if(d_flag)
        check_mapping(m);
    #endif
      push_mapping(m);
    }
    
    PMOD_EXPORT struct mapping *copy_mapping_recursively(struct mapping *m,
    					 struct processing *p)
    {
      struct processing doing;
      struct mapping *ret;
      INT32 e;
      struct keypair *k;
      struct mapping_data  *md;
    
    #ifdef PIKE_DEBUG
      if(m->data->refs <=0)
        fatal("Zero refs in mapping->data\n");
    #endif
    
      doing.next=p;
      doing.pointer_a=(void *)m;
      for(;p;p=p->next)
      {
        if(p->pointer_a == (void *)m)
        {
          add_ref(ret=(struct mapping *)p->pointer_b);
          return ret;
        }
      }
    
    #ifdef PIKE_DEBUG
      if(d_flag > 1) check_mapping_type_fields(m);
    #endif
    
      if(!((m->data->val_types | m->data->ind_types) & BIT_COMPLEX))
        return copy_mapping(m);
    
      ret=allocate_mapping(MAP_SLOTS(m->data->size));
      doing.pointer_b=ret;
    
      check_stack(2);
    
      md=m->data;
      md->valrefs++;
      add_ref(md);
      NEW_MAPPING_LOOP(md)
      {
        copy_svalues_recursively_no_free(sp,&k->ind, 1, p);
        sp++;
        copy_svalues_recursively_no_free(sp,&k->val, 1, p);
        sp++;
        
        mapping_insert(ret, sp-2, sp-1);
        pop_n_elems(2);
      }
      md->valrefs--;
      free_mapping_data(md);
    
      return ret;
    }
    
    
    PMOD_EXPORT void mapping_search_no_free(struct svalue *to,
    			    struct mapping *m,
    			    struct svalue *look_for,
    			    struct svalue *key /* start */)
    {
      struct mapping_data *md, *omd;
    
    #ifdef PIKE_DEBUG
      if(m->data->refs <=0)
        fatal("Zero refs in mapping->data\n");
    #endif
      md=m->data;
    
      if(md->size)
      {
        unsigned INT32 h2,h=0;
        struct keypair *k=md->hash[0], **prev;
    
        if(key)
        {
          h2=hash_svalue(key);
          
          FIND();
          
          if(!k)
          {
    	to->type=T_INT;
    	to->subtype=NUMBER_UNDEFINED;
    	to->u.integer=0;
    	return;
          }
          k=k->next;
        }
        
        
        md=m->data;
        if(md->size)
        {
          md->valrefs++;
          add_ref(md);
          
          if(h < (unsigned INT32)md->hashsize)
          {
    	while(1)
    	{
    	  while(k)
    	  {
    	    if(is_eq(look_for, &k->val))
    	    {
    	      assign_svalue_no_free(to,&k->ind);
    	      
    	      md->valrefs--;
    	      free_mapping_data(md);
    	      return;
    	    }
    	    k=k->next;
    	  }
    	  h++;
    	  if(h>= (unsigned INT32)md->hashsize)
    	    break;
    	  k=md->hash[h];
    	}
          }
        }
        
        md->valrefs--;
        free_mapping_data(md);
      }
    
      to->type=T_INT;
      to->subtype=NUMBER_UNDEFINED;
      to->u.integer=0;
    }
    
    
    #ifdef PIKE_DEBUG
    
    void check_mapping(struct mapping *m)
    {
      int e,num;
      struct keypair *k;
      struct mapping_data *md;
    
      static int in_check_mapping;
      if(in_check_mapping) return;
      in_check_mapping=1;
    
      md=m->data;
    
      if(m->refs <=0)
        fatal("Mapping has zero refs.\n");
    
      if(!m->data)
        fatal("Mapping has no data block.\n");
    
      if (!m->data->refs)
        fatal("Mapping data block has zero refs.\n");
    
      if(m->next && m->next->prev != m)
        fatal("Mapping ->next->prev != mapping.\n");
    
    #ifdef MAPPING_SIZE_DEBUG
      if(m->debug_size != md->size)
      {
        if(Pike_in_gc)
        {
          fprintf(stderr,"Pike was in GC stage %d when this fatal occured:\n",Pike_in_gc);
          Pike_in_gc=0;
        }
        
        fprintf(stderr,"--MAPPING ZAPPING (%d!=%d), mapping:\n",m->debug_size,md->size);
        describe(m);
        fprintf(stderr,"--MAPPING ZAPPING (%d!=%d), mapping data:\n",m->debug_size,md->size);
        describe(md);
        fatal("Mapping zapping detected (%d != %d)!\n",m->debug_size,md->size);
      }
    #endif
    
      if(m->prev)
      {
        if(m->prev->next != m)
          fatal("Mapping ->prev->next != mapping.\n");
      }else{
        if(first_mapping != m)
          fatal("Mapping ->prev == 0 but first_mapping != mapping.\n");
      }
    
      if(md->valrefs <0)
        fatal("md->valrefs  < 0\n");
    
      if(md->hardlinks <0)
        fatal("md->valrefs  < 0\n");
    
      if(md->refs < md->valrefs+1)
        fatal("md->refs < md->valrefs+1\n");
    
      if(md->valrefs < md->hardlinks)
        fatal("md->refs < md->valrefs+1\n");
    
      if(md->hashsize < 0)
        fatal("Assert: I don't think he's going to make it Jim.\n");
    
      if(md->size < 0)
        fatal("Core breach, evacuate ship!\n");
    
      if(md->num_keypairs < 0)
        fatal("Starboard necell on fire!\n");
    
      if(md->size > md->num_keypairs)
        fatal("Pretty mean hashtable there buster!\n");
    
      if(md->hashsize > md->num_keypairs)
        fatal("Pretty mean hashtable there buster (2)!\n");
    
      if(md->num_keypairs > (md->hashsize + 3) * AVG_LINK_LENGTH)
        fatal("Mapping from hell detected, attempting to send it back...\n");
      
      if(md->size > 0 && (!md->ind_types || !md->val_types))
        fatal("Mapping type fields are... wrong.\n");
    
      num=0;
      NEW_MAPPING_LOOP(md)
        {
          num++;
    
          if(! ( (1 << k->ind.type) & (md->ind_types) ))
    	fatal("Mapping indices type field lies.\n");
    
          if(! ( (1 << k->val.type) & (md->val_types) ))
    	fatal("Mapping values type field lies.\n");
    
          check_svalue(& k->ind);
          check_svalue(& k->val);
    
          /* FIXME add check for k->hval
           * beware that hash_svalue may be threaded and locking
           * is required!!
           */
        }
      
      if(md->size != num)
        fatal("Shields are failing, hull integrity down to 20%%\n");
    
      in_check_mapping=0;
    }
    
    void check_all_mappings(void)
    {
      struct mapping *m;
      for(m=first_mapping;m;m=m->next)
        check_mapping(m);
    }
    #endif
    
    
    static void gc_recurse_weak_mapping(struct mapping *m,
    				    TYPE_FIELD (*recurse_fn)(struct svalue *, size_t))
    {
      INT32 e;
      struct keypair *k,**prev;
      TYPE_FIELD ind_types = 0, val_types = 0;
      struct mapping_data *md=m->data;
    
    #ifdef PIKE_DEBUG
      if(!(md->flags & MAPPING_FLAG_WEAK))
        fatal("Mapping is not weak.\n");
      if (MAPPING_DATA_IN_USE(md)) fatal("Mapping data is busy.\n");
    #endif
    
      /* no locking required (no is_eq) */
      for(e=0;e<md->hashsize;e++)
      {
        for(prev= md->hash + e;(k=*prev);)
        {
          int i, v;
          if((i = recurse_fn(&k->ind, 1)) | (v = recurse_fn(&k->val, 1)))
          {
    	*prev=k->next;
    	if (!i) free_svalue(&k->ind);
    	if (!v) free_svalue(&k->val);
    	k->next=md->free_list;
    	md->free_list=k;
    	md->size--;
    #ifdef MAPPING_SIZE_DEBUG
    	if(m->data ==md)
    	  m->debug_size--;
    #endif
          }else{
    	val_types |= 1 << k->val.type;
    	ind_types |= 1 << k->ind.type;
    	prev=&k->next;
          }
        }
      }
      md->val_types = val_types;
      md->ind_types = ind_types;
    }
    
    void gc_mark_mapping_as_referenced(struct mapping *m)
    {
    #ifdef PIKE_DEBUG
      if(m->data->refs <=0)
        fatal("Zero refs in mapping->data\n");
    #endif
    
      if(gc_mark(m)) {
        struct mapping_data *md = m->data;
    
        stealth_check_mapping_for_destruct(m);
        if (m == gc_mark_mapping_pos)
          gc_mark_mapping_pos = m->next;
        if (m == gc_internal_mapping)
          gc_internal_mapping = m->next;
        else {
          DOUBLEUNLINK(first_mapping, m);
          DOUBLELINK(first_mapping, m); /* Linked in first. */
        }
    
        if(gc_mark(md) && ((md->ind_types | md->val_types) & BIT_COMPLEX))
        {
          INT32 e;
          struct keypair *k;
    
          if (MAPPING_DATA_IN_USE(md)) {
    	/* Must leave destructed indices intact if the mapping data is busy. */
    	NEW_MAPPING_LOOP(md)
    	  if ((!IS_DESTRUCTED(&k->ind) && gc_mark_svalues(&k->ind, 1)) |
    	      gc_mark_svalues(&k->val, 1)) {
    #ifdef PIKE_DEBUG
    	    fatal("Didn't expect an svalue zapping now.\n");
    #endif
    	  }
          }
          else if (md->flags & MAPPING_FLAG_WEAK)
    	gc_recurse_weak_mapping(m, gc_mark_weak_svalues);
          else
    	NEW_MAPPING_LOOP(md)
    	  if (gc_mark_svalues(&k->ind, 1) | gc_mark_svalues(&k->val, 1)) {
    #ifdef PIKE_DEBUG
    	    fatal("stealth_check_mapping_for_destruct didn't do its job properly.\n");
    #endif
    	  }
        }
      }
    }
    
    void real_gc_cycle_check_mapping(struct mapping *m, int weak)
    {
      GC_CYCLE_ENTER(m, weak) {
        struct mapping_data *md = m->data;
    
    #ifdef PIKE_DEBUG
        if(md->refs <=0)
          fatal("Zero refs in mapping->data\n");
    #endif
    
        if((md->ind_types | md->val_types) & BIT_COMPLEX)
        {
          INT32 e;
          struct keypair *k;
    
          if (MAPPING_DATA_IN_USE(md)) {
    	/* Must leave destructed indices intact if the mapping data is busy. */
    	NEW_MAPPING_LOOP(md)
    	  if ((!IS_DESTRUCTED(&k->ind) && gc_cycle_check_svalues(&k->ind, 1)) |
    	      gc_cycle_check_svalues(&k->val, 1)) {
    #ifdef PIKE_DEBUG
    	    fatal("Didn't expect an svalue zapping now.\n");
    #endif
    	  }
          }
          else if (md->flags & MAPPING_FLAG_WEAK)
    	gc_recurse_weak_mapping(m, gc_cycle_check_weak_svalues);
          else
    	NEW_MAPPING_LOOP(md)
    	  if (gc_cycle_check_svalues(&k->ind, 1) | gc_cycle_check_svalues(&k->val, 1)) {
    #ifdef PIKE_DEBUG
    	    fatal("stealth_check_mapping_for_destruct didn't do its job properly.\n");
    #endif
    	  }
        }
      } GC_CYCLE_LEAVE;
    }
    
    static void gc_check_mapping(struct mapping *m)
    {
      struct mapping_data *md = m->data;
    
      if((md->ind_types | md->val_types) & BIT_COMPLEX)
      {
        INT32 e;
        struct keypair *k;
    
        if(debug_gc_check(md, T_MAPPING, m)) return;
    
        if (md->flags & MAPPING_FLAG_WEAK && !MAPPING_DATA_IN_USE(md)) {
          /* Disregard the weak flag if the mapping data is busy; we must
           * leave it untouched in that case anyway. */
          NEW_MAPPING_LOOP(md)
          {
    	debug_gc_check_weak_svalues(&k->ind, 1, T_MAPPING, m);
    	debug_gc_check_weak_svalues(&k->val, 1, T_MAPPING, m);
          }
        }
        else {
          NEW_MAPPING_LOOP(md)
          {
    	debug_gc_check_svalues(&k->ind, 1, T_MAPPING, m);
    	debug_gc_check_svalues(&k->val, 1, T_MAPPING, m);
          }
        }
      }
    }
    
    #ifdef PIKE_DEBUG
    unsigned gc_touch_all_mappings(void)
    {
      unsigned n = 0;
      struct mapping *m;
      if (first_mapping && first_mapping->prev)
        fatal("Error in mapping link list.\n");
      for (m = first_mapping; m; m = m->next) {
        debug_gc_touch(m);
        debug_gc_touch(m->data);
        n++;
        if (m->next && m->next->prev != m)
          fatal("Error in mapping link list.\n");
      }
      return n;
    }
    #endif
    
    void gc_check_all_mappings(void)
    {
      struct mapping *m;
    
      for(m=first_mapping;m;m=m->next)
      {
    #ifdef DEBUG_MALLOC
        if (((int)m->data) == 0x55555555) {
          fprintf(stderr, "** Zapped mapping in list of active mappings!\n");
          describe_something(m, T_MAPPING, 0,2,0);
          fatal("Zapped mapping in list of active mappings!\n");
        }
    #endif /* DEBUG_MALLOC */
    
        gc_check_mapping(m);
    #ifdef PIKE_DEBUG
        if(d_flag > 1) check_mapping_type_fields(m);
    #endif
      }
    }
    
    void gc_mark_all_mappings(void)
    {
      gc_mark_mapping_pos = gc_internal_mapping;
      while (gc_mark_mapping_pos) {
        struct mapping *m = gc_mark_mapping_pos;
        gc_mark_mapping_pos = m->next;
        if(gc_is_referenced(m))
          gc_mark_mapping_as_referenced(m);
        else
          /* Done in gc_mark_mapping_as_referenced() otherwise (and it has
           * to be done there). */
          stealth_check_mapping_for_destruct(m);
      }
    }
    
    void gc_cycle_check_all_mappings(void)
    {
      struct mapping *m;
      for (m = gc_internal_mapping; m; m = m->next) {
        real_gc_cycle_check_mapping(m, 0);
        gc_cycle_run_queue();
      }
    }
    
    void gc_zap_ext_weak_refs_in_mappings(void)
    {
      gc_mark_mapping_pos = first_mapping;
      while (gc_mark_mapping_pos != gc_internal_mapping && gc_ext_weak_refs) {
        struct mapping *m = gc_mark_mapping_pos;
        gc_mark_mapping_pos = m->next;
        gc_mark_mapping_as_referenced(m);
      }
      discard_queue(&gc_mark_queue);
    }
    
    void gc_free_all_unreferenced_mappings(void)
    {
      INT32 e;
      struct keypair *k,**prev;
      struct mapping *m,*next;
      struct mapping_data *md;
    
      for(m=gc_internal_mapping;m;m=next)
      {
        if(gc_do_free(m))
        {
          /* Got an extra ref from gc_cycle_pop(). */
          md = m->data;
          /* Protect against unlink_mapping_data() recursing too far. */
          m->data=&empty_data;
          m->data->refs++;
    
          unlink_mapping_data(md);
    #ifdef MAPPING_SIZE_DEBUG
          m->debug_size=0;
    #endif
          gc_free_extra_ref(m);
          SET_NEXT_AND_FREE(m, free_mapping);
        }
        else
        {
          next=m->next;
        }
      }
    }
    
    #ifdef PIKE_DEBUG
    
    void simple_describe_mapping(struct mapping *m)
    {
      char *s;
      init_buf();
      describe_mapping(m,0,2);
      s=simple_free_buf();
      fprintf(stderr,"%s\n",s);
      free(s);
    }
    
    
    void debug_dump_mapping(struct mapping *m)
    {
      fprintf(stderr, "Refs=%d, next=%p, prev=%p",
    	  m->refs, m->next, m->prev);
      if (((ptrdiff_t)m->data) & 3) {
        fprintf(stderr, ", data=%p (unaligned)\n", m->data);
      } else {
        fprintf(stderr, ", flags=0x%x, size=%d, hashsize=%d\n",
    	    m->data->flags, m->data->size, m->data->hashsize);
        fprintf(stderr, "Indices type field = ");
        debug_dump_type_field(m->data->ind_types);
        fprintf(stderr, "\n");
        fprintf(stderr, "Values type field = ");
        debug_dump_type_field(m->data->val_types);
        fprintf(stderr, "\n");
        simple_describe_mapping(m);
      }
    }
    #endif
    
    void zap_all_mappings(void)
    {
      INT32 e;
      struct keypair *k;
      struct mapping *m,*next;
      struct mapping_data *md;
    
      for(m=first_mapping;m;m=next)
      {
        add_ref(m);
    
    #if defined(PIKE_DEBUG) && defined(DEBUG_MALLOC)
        if(verbose_debug_exit)
          debug_dump_mapping(m);
    #endif
    
        md=m->data;
        for(e=0;e<md->hashsize;e++)
        {
          while((k=md->hash[e]))
          {
    	md->hash[e]=k->next;
    	k->next=md->free_list;
    	md->free_list=k;
    	free_svalue(&k->ind);
    	free_svalue(&k->val);
          }
        }
        md->size=0;
    #ifdef MAPPING_SIZE_DEBUG
        if(m->data ==md)
          m->debug_size=0;
    #endif
        
        next=m->next;
        
        /* free_mapping(m); */
      }
    }