package p4spectec

  1. Overview
  2. Docs
P4-SpecTec: A mechanization toolchain for the P4 Programming Language

Install

dune-project
 Dependency

Authors

Maintainers

Sources

v0.1.2.tar.gz
md5=1a3bc0a385fe1ecf403c019f49aa6de6
sha512=5d20b5821f33e2a3a5419b208606f27c01511994c2b3b1e1cdf4c077056dfd0aa81682af0720e1060ee2bfb0341918fcc4c53159820205a2bc32b725e5c1a714

doc/src/p4spectec.cache/make.ml.html

Source file make.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
open Entry

(* Clock-eviction cache

   A circular array of slots sits beside the hashtable.
   * Each slot carries the key currently occupying it and
   * a reference bit that is set on every hit and
   * cleared by the clock hand on its first pass.

   The hand evicts the first slot whose reference bit is already clear,
   giving every recently-accessed entry at least one full revolution of grace. *)

module Make (Entry : ENTRY) = struct
  module Table = Hashtbl.Make (Entry)

  type slot = { mutable key : Entry.t; mutable ref : bool }

  type 'a t = {
    table : ('a * int) Table.t;
    clock : slot array;
    occ : bool array; (* true iff slot is occupied *)
    capacity : int;
    mutable count : int; (* number of occupied slots *)
    mutable hand : int; (* eviction hand position *)
    mutable fill : int; (* next slot for sequential initial fill *)
    mutable touched : int; (* one past the largest slot index ever written *)
  }

  let create ~(size : int) =
    let capacity = max 1 size in
    {
      table = Table.create capacity;
      clock =
        Array.init capacity (fun _ -> { key = Entry.default; ref = false });
      occ = Array.make capacity false;
      capacity;
      count = 0;
      hand = 0;
      fill = 0;
      touched = 0;
    }

  let size (cache : 'a t) : int = cache.count

  (* Remove every entry, visiting only the slots that were written *)

  let empty (cache : 'a t) : unit =
    for idx = 0 to cache.touched - 1 do
      if cache.occ.(idx) then (
        Table.remove cache.table cache.clock.(idx).key;
        cache.occ.(idx) <- false;
        cache.clock.(idx).key <- Entry.default;
        cache.clock.(idx).ref <- false)
    done;
    cache.count <- 0;
    cache.hand <- 0;
    cache.fill <- 0;
    cache.touched <- 0

  let find (cache : 'a t) (key : Entry.t) : 'a option =
    match Table.find_opt cache.table key with
    | None -> None
    | Some (value, idx) ->
        cache.clock.(idx).ref <- true;
        Some value

  (* Advance the hand until a slot can be evicted; return its index *)

  let evict (cache : 'a t) : int =
    let capacity = cache.capacity in
    let rec sweep () =
      let idx = cache.hand in
      cache.hand <- (idx + 1) mod capacity;
      if not cache.occ.(idx) then sweep ()
      else if cache.clock.(idx).ref then (
        cache.clock.(idx).ref <- false;
        sweep ())
      else (
        Table.remove cache.table cache.clock.(idx).key;
        cache.occ.(idx) <- false;
        cache.count <- cache.count - 1;
        idx)
    in
    sweep ()

  let add (cache : 'a t) (key : Entry.t) (value : 'a) : unit =
    match Table.find_opt cache.table key with
    | Some (_, idx) ->
        Table.replace cache.table key (value, idx);
        cache.clock.(idx).ref <- true
    | None ->
        let idx =
          if cache.count < cache.capacity then (
            let idx = cache.fill in
            cache.fill <- (cache.fill + 1) mod cache.capacity;
            if idx + 1 > cache.touched then cache.touched <- idx + 1;
            idx)
          else evict cache
        in
        cache.clock.(idx).key <- key;
        cache.clock.(idx).ref <- true;
        cache.occ.(idx) <- true;
        Table.replace cache.table key (value, idx);
        cache.count <- cache.count + 1
end