(****************************************************************************)
(*                                                                          *)
(*    This file is part of Zephyrus.                                        *)
(*                                                                          *)
(*    Zephyrus 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 3 of the License, or     *)
(*    (at your option) any later version.                                   *)
(*                                                                          *)
(*    Zephyrus 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 Zephyrus.  If not, see <http://www.gnu.org/licenses/>.     *)
(*                                                                          *)
(****************************************************************************)

(** Manage unique identifiers. *)

(* Depends on nothing.
*)

(** Module for used tokens (names, ids, etc.) management. 
    Basically it works like a simplified mutable set with only two operations available: 
    you can check if a given element is already inside and you can insert a new element. *)
module type Used_tokens_type = sig
  type t
  type token

  (** Create a new empty collection of tokens. *)
  val empty : unit -> t

  (** Check if a given token is already present in the collection. *)
  val mem   : token -> t -> bool

  (** Add a new token into the collection. *)
  val add   : token -> t -> unit
end

(** Module for managing string tokens. *)
module Used_tokens_string : Used_tokens_type with type token = string

(** Module for managing integer tokens. *)
module Used_tokens_int    : Used_tokens_type with type token = int



(** Module for unique identifier management and creation.
    Basically it is an extended version of used tokens management module, which permits us to
    create fresh unique tokens in an abstract way. *)
module type Fresh = sig
  type t
  type id

  (** Create a new empty collection of identifiers. *)
  val create    : unit -> t

  (** Get the current fresh id (the one that was generated by last call of the function "next"; if the function "next" was never called before the behavior is unspecified). *)
  val current   : t -> id

  (** Generate a fresh identifier, mark it as used and return it. *)
  val next      : t -> id

  (** Check if a given identifier is already used. *)
  val is_used   : t -> id -> bool

  (** Mark an arbitraty id as already used (after that it will be never be generated using the "next" function). *)
  val mark_used : t -> id -> unit
end

(** Simple implementation of the unique identifier management for integer identifiers. 
    Starts with the identifier 1 and goes up. *)
module Fresh_integer : Fresh with type id = int



(** TODO: Special identifiers do not work well... *)

(** Module for unique identifiers with additional ways of generating specific identifiers available on a request.
    (Examples: 
     we might want to have a pool of identifiers inaccessible using the standard "next" method
     or we might want to generate a next available prime number identifier etc. *)
module type Fresh_with_requests = sig
  include Fresh
  type request

  (** Get a special identifier of certain kind (it does not need to be fresh, depends on the implementation for a given request type). *)
  val special : request -> id
end

(** Implementation of the special identifier module with only one special request: Deprecated (which will typically correspond to id -1) *)
type request_deprecated = Deprecated

module Fresh_integer_with_deprecated : Fresh_with_requests with 
  type id = int and 
  type request = request_deprecated