
#INCLUDE "course.module"

--* This outputs 0*n, 1*n, 3*n, 4*n, 5*n, 6*n, ...
--  Note: (n > 0) ==> this is a strictly ascending sequence.
--
-- @param n Base number for the sequence.
-- @param out The output channel for the sequence.
--
PROC multiples (VAL INT n, CHAN INT out!)
  INITIAL INT i IS 0:
  WHILE TRUE
    SEQ
      out ! i
      i := i + n
:

--* This assumes each input channel carries a stream of
--  strictly ascending numbers.  It outputs the strictly
--  ascending merge of its input streams.
--  
-- @param in.0 Input channel (assumtions as above).
-- @param in.1 Input channel (assumtions as above).
-- @param out The output channel (merge of the input streams).
--  
PROC ascending.merge.2 (CHAN INT in.0?, in.1?, out!)
  -- Hint: write this with a simple loop - serial code only.
  SKIP  -- replace this with your code
:

--* This assumes each input channel carries a stream of
--  strictly ascending numbers.  It outputs the strictly
--  ascending merge of its input streams.
--  
-- @param in.0 Input channel (assumtions as above).
-- @param in.1 Input channel (assumtions as above).
-- @param in.2 Input channel (assumtions as above).
-- @param out The output channel (merge of the input streams).
--  
PROC ascending.merge.3 (CHAN INT in.0?, in.1?, in.2?, out!)
  -- Hint: use parallel code - a network of ascending.merge.2 processes.
  SKIP  -- replace this with your code
:

--* This assumes each input channel carries a stream of
--  strictly ascending numbers.  It outputs the strictly
--  ascending merge of its input streams.
--  
-- @param in.0 Input channel (assumtions as above).
-- @param in.1 Input channel (assumtions as above).
-- @param in.2 Input channel (assumtions as above).
-- @param in.3 Input channel (assumtions as above).
-- @param out The output channel (merge of the input streams).
--  
PROC ascending.merge.4 (CHAN INT in.0?, in.1?, in.2?, in.3?, out!)
  -- Hint: use parallel code - a network of ascending.merge.2 processes.
  SKIP  -- replace this with your code
:

--* This assumes each input channel carries a stream of
--  strictly ascending numbers and that there are at least
--  two channels in the array.  It outputs the strictly
--  ascending merge of its input streams.
--  
-- @param in Array of input channels (assumtions as above).
-- @param out The output channel (merge of the input streams).
--  
REC PROC ascending.merge ([]CHAN INT in?, CHAN INT out!)
  -- Hint: use parallel code and recursion.
  -- Note: you are not expected to be able to tackle this yet!
  -- But ... do it anyway, :).
  CASE SIZE in?                     -- see slides 39-46 of "shared-etc"
    2
      ascending.merge.2 (in[0]?, in[1]?, out!)
    3
      ascending.merge.3 (in[0]?, in[1]?, in[2]?, out!)
    ELSE
      -- see slide 118 of "shared-etc" to understand the next two lines ...
      []CHAN INT in.lo? IS [in? FOR (SIZE in?)/2]:  -- botton half of array
      []CHAN INT in.hi? IS [in? FROM (SIZE in?)/2]: -- top half of array
      SKIP  -- replace this with your code
:

--* This pauses execution of the invoking process by delay microseconds.
--
-- @param delay The length of the pause (in microseconds).
--
PROC pause (VAL INT delay)
  TIMER tim:
  INT t:
  SEQ
    tim ? t
    tim ? AFTER t PLUS delay
:

--* This inputs numbers and tabulates them into lines of text output.
--  It pauses for 'delay' microseconds after each line.
--
-- @param delay The length of the pause (in microseconds) between lines.
-- @param in Numbers coming in.
-- @param out Characters going out.
--
PROC print.stream (VAL INT delay, CHAN INT in?, CHAN BYTE out!)
  WHILE TRUE
    INT n:
    SEQ
      in ? n
      out.int (n, 10, out!)             -- out.int is from "course.module"
      out.string ("*c*n", 0, out!)      -- out.string is from "course.module"
      pause (delay)
:

--* The main process - execution starts here.
--
-- @param keyboard The standard input channel (stdin, in Unix-speak)
-- @param screen The standard output channel (stdout, in Unix-speak)
-- @param error The standard error channel (stderr, in Unix-speak)
--
PROC main (CHAN BYTE keyboard?, screen!, error!)
  -- This network demonstrates ascending.merge.2.
  -- Extend to demonstrate ascending.merge.3 and/or ascending.merge.4.
  -- Challenge: extend to demonstrate ascending.merge.
  CHAN INT twos, threes, merged:
  PAR
    multiples (2, twos!)
    multiples (3, threes!)
    ascending.merge.2 (twos?, threes?, merged!)
    print.stream (100000, merged?, screen!)
:
