summaryrefslogtreecommitdiff
path: root/ring_buffer/src/ring_buffer.adb
blob: 500ec5ce6c1749479887c87c56f137b896e2e697 (plain)
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
with Ada.Text_IO; use Ada.Text_IO;

procedure Ring_Buffer is

  type Natural_Array is array (Natural range <>) of Integer;

  type Ring_Buffer (Capacity : Natural) is record
    Start_Index : Natural := 0; -- TODO: somehow make these 'mod Size'.
    Cur_Index   : Natural := 0;
    Empty       : Boolean := True;
    -- TODO: the index type should be 'mod Size'.
    -- TODO: 0 .. Capacity wastes 1 slot of space.
    Buffer      : Natural_Array (0 .. Capacity) := (others => 0);
  end record;

  function Size (RB : Ring_Buffer) return Natural is
  begin
    if RB.Empty then
      return 0;
    elsif RB.Cur_Index = RB.Start_Index then
      return RB.Capacity;
    else
      return (RB.Cur_Index - RB.Start_Index) mod RB.Capacity;
    end if;
  end Size;

  function Push (RB : in out Ring_Buffer; Value : Integer) return Boolean is
  begin
    if Size (RB) = RB.Capacity then
      return False;
    else
      RB.Buffer (RB.Cur_Index) := Value;
      RB.Cur_Index := (RB.Cur_Index + 1) mod RB.Capacity;
      RB.Empty := False;
      return True;
    end if;
  end Push;

  procedure Push (RB : in out Ring_Buffer; Value : Integer) is
    unused : Boolean := Push (RB, Value);
  begin
    return;
  end Push;

  function Pop (RB : in out Ring_Buffer; Value : out Integer) return Boolean is
  begin
    if Size (RB) = 0 then
      return False;
    else
      Value := RB.Buffer (RB.Start_Index);
      RB.Start_Index := (RB.Start_Index + 1) mod RB.Capacity;
      if RB.Start_Index = RB.Cur_Index then
        RB.Empty := True;
      end if;
      return True;
    end if;
  end Pop;

  procedure Pop (RB : in out Ring_Buffer) is
    Dummy  : Integer;
    unused : Boolean := Pop (RB, Dummy);
  begin
    return;
  end Pop;

  procedure Print (RB : Ring_Buffer) is
  begin
    Put ("[");
    for I in 0 .. Size (RB) - 1 loop
      Put (Integer'Image (RB.Buffer ((RB.Start_Index + I) mod RB.Capacity)));
    end loop;
    Put_Line ("]");
  end Print;

  Capacity : constant Natural := 5;
  RB : Ring_Buffer (Capacity);

begin
  Push (RB, 1);
  Push (RB, 2);
  Push (RB, 3);
  Push (RB, 4);
  Push (RB, 5);
  -- Full!
  Push (RB, 6);
  Push (RB, 7);
  -- Make some space.
  Pop (RB);
  Pop (RB);
  -- Push more.
  Push (RB, 8);
  Push (RB, 9);
  Print (RB);
end Ring_Buffer;