sig
  
  
  (** This module maintains a global mapping from identifiers to abstract ``labels'', which are internally represented as integers, and back. *)

  
  type t

  
  (** compare x y is a total ordering. It returns a negative integer if x is less than y, 0 if x and y are equal, and a positive integer if x is greater than y. *)

  val compare: t -> t -> int

  
  (** import s associates a unique label with the identifier s, possibly extending the global mapping if s was never encountered so far. Thus, if s and t are equal strings, possibly allocated in different memory locations, import s and import t return the same label. The identifier s is recorded and may be later recovered via export. *)

    val import: lname -> t

    
    (** export i provides access to the inverse of the global mapping, that is, associates a unique identifier with every label. The identifier associated with a label is the one originally supplied to import. *)

    val export: t -> lname

  end = struct

    
    (** A row label is an object of type t, that is, an integer. *)

    type t = int

    let compare = (-)

    
    (** A hash table maps all known identifiers to integer values. It provides one direction of the global mapping. *)

    let table =
      Hashtbl.create 1023

    
    (** An infinite array maps all known integer values to identifiers. It provides the other direction of the global mapping. *)

    let array =
      InfiniteArray.make "<BUG>" (* Dummy data. *)

    
    (** A global counter contains the next available integer label. *)

    let counter =
      ref 0

    
    (** import s associates a unique label with the identifier s, possibly extending the global mapping if s was never encountered so far. Thus, if s and t are equal strings, possibly allocated in different memory locations, import s and import t return the same label. The identifier s is recorded and may be later recovered via export. *)

    let import (LName s) =
      try
        Hashtbl.find table s
      with Not_found ->
        let i = !counter in
          Hashtbl.add table s i;
          InfiniteArray.set array i s;
          counter := i + 1;
          i

    
    (** export i provides access to the inverse of the global mapping, that is, associates a unique identifier with every label. The identifier associated with a label is the one originally supplied to import. *)

    let export i =
      assert (i < !counter);
      LName (InfiniteArray.get array i)

  end