# Buffer

A Buffer is a used to buffer the data flowing the connections of a model. Data can be read from and written into a buffer. The mode of the buffer determines the way to read from and write into the buffers.

## Buffer Modes

BufferMode determines the way the data is read from and written into a Buffer. Basically, there are four buffer modes: Normal, Cyclic, Fifo and Lifo. Normal, Fifo and Lifo are subtypes of LinearMode and Cyclic is a subtype of CyclicMode.

## Buffer Constructors

The Buffer construction is very similar to the construction of arrays in Julia. Just specify the mode, element type and length of the buffer. Here are some examples:

julia> using Causal # hide

julia> Buffer{Fifo}(2, 5)
2×5 Buffer{Fifo, Float64, 2}

julia> Buffer{Cyclic}(2, 10)
2×10 Buffer{Cyclic, Float64, 2}

julia> Buffer{Lifo}(Bool, 2, 5)
2×5 Buffer{Lifo, Bool, 2}

julia> Buffer(5)
5-element Buffer{Cyclic, Float64, 1}

## Writing Data into Buffers

Writing data into a Buffer is done with write! function. Recall that when the buffer is full, no more data can be written into the buffer if the buffer mode is of type LinearMode.


julia> normalbuf = Buffer{Normal}(3)
3-element Buffer{Normal, Float64, 1}

julia> foreach(item -> write!(normalbuf, item), 1:3)

julia> normalbuf
3-element Buffer{Normal, Float64, 1}:
3.0
2.0
1.0

julia> write!(normalbuf, 4.)
ERROR: Buffer is full

This situation is the same for Lifo and Fifo buffers, but not the case for Cyclic buffer.


julia> cyclicbuf = Buffer{Cyclic}(3)
3-element Buffer{Cyclic, Float64, 1}

julia> foreach(item -> write!(cyclicbuf, item), 1:3)

julia> cyclicbuf
3-element Buffer{Cyclic, Float64, 1}:
3.0
2.0
1.0

julia> write!(cyclicbuf, 3.)
3.0

julia> write!(cyclicbuf, 4.)
4.0

## Reading Data from Buffers

Reading data from a Buffer is done with read function.

julia> using Causal # hide

julia> nbuf, cbuf, fbuf, lbuf = Buffer{Normal}(5), Buffer{Cyclic}(5), Buffer{Lifo}(5), Buffer{Fifo}(5)
(Buffer(mode:Normal, eltype:Float64, size:(5,), index:1, state:empty), Buffer(mode:Cyclic, eltype:Float64, size:(5,), index:1, state:empty), Buffer(mode:Lifo, eltype:Float64, size:(5,), index:1, state:empty), Buffer(mode:Fifo, eltype:Float64, size:(5,), index:1, state:empty))

julia> foreach(buf -> foreach(item -> write!(buf, item), 1 : 5), [nbuf, cbuf, fbuf, lbuf])

julia> for buf in [nbuf, cbuf, fbuf, lbuf]
@show buf
for i in 1 : 5
end
end
buf = Buffer(mode:Normal, eltype:Float64, size:(5,), index:6, state:full)
buf = Buffer(mode:Cyclic, eltype:Float64, size:(5,), index:1, state:full)
buf = Buffer(mode:Lifo, eltype:Float64, size:(5,), index:6, state:full)
buf = Buffer(mode:Fifo, eltype:Float64, size:(5,), index:6, state:full)
read(buf) = 5.0

## AbstractArray Interface of Buffers

A Buffer can be indexed using the similar syntax of arrays in Julia. That is, getindex and setindex! methods can be used with known Julia syntax. i.e. getindex(buf, idx) is equal to buf[idx] and setindex(buf, val, idx) is equal to buf[idx] = val.


julia> buf = Buffer(5)
5-element Buffer{Cyclic, Float64, 1}

julia> size(buf)
(5,)

julia> length(buf)
5

julia> for val in 1 : 5
write!(buf, 2val)
end

julia> buf[1]
10.0

julia> buf[3:4]
2-element Vector{Float64}:
6.0
4.0

julia> buf[[3, 5]]
2-element Vector{Float64}:
6.0
2.0

julia> buf[end]
2.0

julia> buf[1] = 5
5

julia> buf[3:5] = [7, 8, 9]
3-element Vector{Int64}:
7
8
9

## Full API

Causal.BufferType
mutable struct Buffer{M<:BufferMode, T, N} <: AbstractArray{T, N}

Constructs a Buffer of size sz with element type of T. M is the mode of the Buffer that determines how data is to read from and written into the Buffer. There exists for different buffer modes:

The default mode for Buffer is Cyclic and default element type is Float64.

Buffer{M}(sz::Int...) where {M, T}

Constructs a Buffer of size sz and with element type of T and mode M.

Buffer(dtype::Type{T}, sz::Int...) where T

Constructs a Buffer of size sz and element type T. The mode of buffer is Cyclic.

Buffer(sz::Int...)

Constructs a Buffer of size sz with mode Cyclic and element type of Float64.

Buffer{M}(data::AbstractVecOrMat{T}) where {M, T<:Real}

Constructs a Buffer with data.

Fields

• internals::Array{Array{T, N}, 1} where {T, N}

Internal data containers

• src::Int64

Input containter

• dst::Int64

Output container

• index::Int64

Buffer index

• state::Symbol

Current state of buffer. May be :full, :empty, :nonempty

• id::Base.UUID

Unique identifier

Example

julia> buf = Buffer(5)
5-element Buffer{Cyclic,Float64,1}

julia> buf = Buffer{Fifo}(2, 5)
2×5 Buffer{Fifo,Float64,2}

julia> buf = Buffer{Lifo}(collect(reshape(1:8, 2, 4)))
2×4 Buffer{Lifo,Int64,2}
Causal.BufferModeType
abstract type BufferMode

Abstract type for buffer mode. Subtypes of BufferMode is CyclicMode and LinearMode.

Causal.CyclicType
struct Cyclic <: CyclicMode

Cyclic buffer mode. The data is written to buffer until the buffer is full. When the buffer is full, new data is written by overwriting the data available in the buffer starting from the beginning of the buffer. When the buffer is read, the element written last is returned and the returned element is not deleted from the buffer.

Causal.FifoType
struct Fifo <: LinearMode

Fifo (First-in-last-out) buffer mode. This type of buffer is a first-in-first-out buffer. The data is written to the buffer until the buffer is full. When the buffer is full, no more element can be written into the buffer. When read, the first element written into the buffer is returned. The returned element is deleted from the buffer.

Causal.LifoType
struct Lifo <: LinearMode

Lifo (Last-in-first-out) buffer mode. This type of buffer is a last-in-first-out buffer. Data is written to the buffer until the buffer is full. When the buffer is full, no more element can be written into the buffer. When read, the last element written into buffer is returned. The returned element is deleted from the buffer.

Causal.NormalType
struct Normal <: LinearMode

LinearMode buffer mode. The data is written to buffer until the buffer is full. When it is full, no more data is written to the buffer. When read, the data written last is returned and the returned data is not deleted from the internal container of the buffer.

Base.getindexMethod
getindex(buf, idx)


Returns an element from buf at index idx. Same as buf[idx]

Example

julia> buf = Buffer(2, 5);  # Construct a buffer.

julia> write!(buf, reshape(2 : 2 : 20, 2, 5))  # Write data into buffer.

julia> buf[1]
18.0

julia> buf[1, 2]
14.0

julia> buf[1, end]
2.0

julia> buf[:, 2]
2-element Array{Float64,1}:
14.0
16.0
Base.isemptyMethod
isempty(buf)


Returns true if the index of buf is 1.

Base.readMethod
read(buf)


Reads an element from buf. Reading is performed according to the mode of buf. See also: Normal, Cyclic, Lifo, Fifo for buffer modes.

Example

julia> buf = Buffer(3)
3-element Buffer{Cyclic,Float64,1}

julia> write!(buf, [2, 4, 6])

julia> for i = 1 : 3
end
(read(buf), buf.internals) = (6.0, [[6.0, 4.0, 2.0], [4.0, 2.0, 0.0]])
(read(buf), buf.internals) = (6.0, [[6.0, 4.0, 2.0], [4.0, 2.0, 0.0]])
(read(buf), buf.internals) = (6.0, [[6.0, 4.0, 2.0], [4.0, 2.0, 0.0]])

julia> buf = Buffer{Fifo}(5)
5-element Buffer{Fifo,Float64,1}

julia> write!(buf, [2, 4, 6])

julia> for i = 1 : 3
end
(read(buf), buf.internals) = (2.0, [[6.0, 4.0, 0.0, 0.0, 0.0], [4.0, 2.0, 0.0, 0.0, 0.0]])
(read(buf), buf.internals) = (4.0, [[6.0, 0.0, 0.0, 0.0, 0.0], [4.0, 2.0, 0.0, 0.0, 0.0]])
(read(buf), buf.internals) = (6.0, [[0.0, 0.0, 0.0, 0.0, 0.0], [4.0, 2.0, 0.0, 0.0, 0.0]])
Base.setindex!Method
setindex!(buf, item, idx)


Sets val to buf at index idx. Same as buf[idx] = val.

Example

julia> buf = Buffer(2, 5);

julia> buf[1] = 1
1

julia> buf[:, 2] = [1, 1]
2-element Array{Int64,1}:
1
1

julia> buf[end] = 10
10

julia> buf.internals
2-element Array{Array{Float64,2},1}:
[1.0 1.0 … 0.0 0.0; 0.0 1.0 … 0.0 10.0]
[0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0]
Base.sizeMethod
size(buf)


Returns the size of buf.

Causal.contentMethod
content(buf; flip)


Returns the current data of buf. If flip is true, the data to be returned is flipped. See also snapshot

Example

julia> buf = Buffer(5);

julia> write!(buf, 1:3)

julia> content(buf, flip=false)
3-element Array{Float64,1}:
3.0
2.0
1.0

julia> buf = Buffer(2, 5);

julia> write!(buf, reshape(1:10, 2, 5))

julia> content(buf)
2×5 Array{Float64,2}:
1.0  3.0  5.0  7.0   9.0
2.0  4.0  6.0  8.0  10.0
Causal.datalengthMethod

Returns the maximum number of data that can be hold in buf.

Example

julia> buf = Buffer(5);

julia> datalength(buf)
5

julia> buf2 = Buffer(2, 10);

julia> datalength(buf2)
10
Causal.inbufMethod
inbuf(buf)


Returns the element of internals of buf that is used to input data to buf. See also [outbuf][@ref)

Causal.isfullMethod
isfull(buf)


Returns true if the index of buf is equal to the length of buf.

Causal.ishitMethod
ishit(buf)


Returns true when buf index is an integer multiple of datalength of buf.

Example

julia> buf = Buffer(3);

julia> for val in 1 : 7
write!(buf, val)
@show ishit(buf)
end
ishit(buf) = false
ishit(buf) = false
ishit(buf) = true
ishit(buf) = false
ishit(buf) = false
ishit(buf) = true
ishit(buf) = false
Causal.outbufMethod
outbuf(buf)


Returns the element of intervals of buf that is used to take data out of buf. See also: inbuf

Causal.write!Method
write!(buf, val)


Writes each column of vals into buf.

!!! warning Buffer mode determines how data is written into buffers. See also: Normal, Cyclic, Lifo, Fifo for buffer modes.

Example

julia> buf = Buffer(5)
5-element Buffer{Cyclic,Float64,1}

julia> write!(buf, 1.)
1.0

julia> write!(buf, [2, 3])

julia> buf.internals
2-element Array{Array{Float64,1},1}:
[3.0, 2.0, 1.0, 0.0, 0.0]
[2.0, 1.0, 0.0, 0.0, 0.0]

julia> buf = Buffer(2,5)
2×5 Buffer{Cyclic,Float64,2}

julia> write!(buf, [1, 1])
2-element Array{Int64,1}:
1
1

julia> write!(buf, [2 3; 2 3])

julia> buf.internals
2-element Array{Array{Float64,2},1}:
[3.0 2.0 … 0.0 0.0; 3.0 2.0 … 0.0 0.0]
[2.0 1.0 … 0.0 0.0; 2.0 1.0 … 0.0 0.0]