rxada_0.1.1_dd9da799/src/body/rx-op-repeat.adb

  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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
with Ada.Containers.Indefinite_Doubly_Linked_Lists;

package body Rx.Op.Repeat is

   use type Operate.T;

   package T_Lists is new Ada.Containers.Indefinite_Doubly_Linked_Lists (Operate.T);

   use type Actions.HTFilter0;

   type Kinds is (Counter, While_Do, Repeat_Until);

   type Operator (Kind : Kinds) is new Operate.Operator with record
      Sequence : T_Lists.List;

      First_Seen : Boolean := False;

      case Kind is
         when Counter => Repeats : Rx_Integer range 0 .. Rx_Integer'Last;
         when others  => Filter  : Actions.HTFilter0;
      end case;
   end record;

   overriding
   procedure On_Next (This  : in out Operator;
                      V     :        Operate.T);

   overriding
   procedure On_Complete  (This : in out Operator);

   overriding
   procedure On_Next (This  : in out Operator;
                      V     :        Operate.T) is
   begin
      if This.Kind = While_Do and then not This.First_Seen and then not This.Filter.Ref.Check then
         This.Get_Observer.On_Complete ;
         This.Unsubscribe;
      else
         This.First_Seen := True;
         This.Sequence.Append (V);
         This.Get_Observer.On_Next (V);
      end if;
   end On_Next;

   overriding
   procedure On_Complete  (This : in out Operator)
   is
      Check : Boolean;
   begin
      if not This.Is_Subscribed then -- Because its While_Do and first check failed
         return;
      end if;

      if not This.Sequence.Is_Empty then
         case This.Kind is
            when Counter =>
               for I in 1 .. This.Repeats loop
                  for V of This.Sequence loop
                     This.Get_Observer.On_Next (V);
                  end loop;
               end loop;

            when While_Do | Repeat_Until =>
               loop
                  Check := This.Filter.Ref.Check;
                  exit when (This.Kind = Repeat_Until and then     Check) or else
                            (This.Kind = While_Do     and then not Check);

                  for V of This.Sequence loop
                     This.Get_Observer.On_Next (V);
                  end loop;
               end loop;
         end case;
      end if;

      This.Get_Observer.On_Complete ;
   end On_Complete ;

   --------------------
   -- Repeat_Forever --
   --------------------

   function Repeat_Forever return Operate.Operator'Class is
   begin
      return Operator'(Operate.Operator with
                       Kind   => While_Do,
                       Filter => + Actions.Wrap (Always'Access),
                       others => <>);
   end Repeat_Forever;

   ------------
   -- Repeat --
   ------------

   function Repeat (Times : Rx_Integer) return Operate.Operator'Class is
   begin
      return Operator'(Operate.Operator with
                       Kind    => Counter,
                       Repeats => Times,
                       others  => <>);
   end Repeat;

   --------------
   -- While_Do --
   --------------

   function While_Do
     (Check : Actions.TFilter0'Class)
      return Operate.Operator'Class
   is
   begin
      return Operator'(Operate.Operator with
                       Kind   => While_Do,
                       Filter => + Check,
                       others => <>);
   end While_Do;

   ------------------
   -- Repeat_Until --
   ------------------

   function Repeat_Until
     (Check : Actions.TFilter0'Class)
      return Operate.Operator'Class
   is
   begin
      return Operator'(Operate.Operator with
                       Kind   => Repeat_Until,
                       Filter => + Check,
                       others => <>);
   end Repeat_Until;

end Rx.Op.Repeat;