blob: 972d990b680cd720d181b56e5b78d1763a1d80cd [file] [log] [blame]
// Copyright 2020 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pri func decoder.filter_1!(curr: slice base.u8),
choosy,
{
var filter_distance : base.u64[..= 8]
var fa : base.u8
var i_start : base.u64
var i : base.u64
filter_distance = this.filter_distance as base.u64
i_start = 0
while i_start < filter_distance {
assert i_start < 8 via "a < b: a < c; c <= b"(c: filter_distance)
fa = 0
i = i_start
while i < args.curr.length(),
inv i_start < 8,
{
args.curr[i] ~mod+= fa
fa = args.curr[i]
i ~mod+= filter_distance
} endwhile
i_start += 1
} endwhile
}
pri func decoder.filter_1_distance_4_fallback!(curr: slice base.u8) {
var p : slice base.u8
var fa0 : base.u8
var fa1 : base.u8
var fa2 : base.u8
var fa3 : base.u8
iterate (p = args.curr)(length: 4, unroll: 1) {
fa0 ~mod+= p[0]
p[0] = fa0
fa1 ~mod+= p[1]
p[1] = fa1
fa2 ~mod+= p[2]
p[2] = fa2
fa3 ~mod+= p[3]
p[3] = fa3
}
}
pri func decoder.filter_2!(curr: slice base.u8, prev: slice base.u8),
choosy,
{
var n : base.u64
var i : base.u64
n = args.curr.length().min(a: args.prev.length())
i = 0
while i < n,
inv n <= args.curr.length(),
inv n <= args.prev.length(),
{
assert i < 0xFFFF_FFFF_FFFF_FFFF via "a < b: a < c; c <= b"(c: n)
assert i < args.curr.length() via "a < b: a < c; c <= b"(c: n)
assert i < args.prev.length() via "a < b: a < c; c <= b"(c: n)
args.curr[i] ~mod+= args.prev[i]
i += 1
} endwhile
}
pri func decoder.filter_3!(curr: slice base.u8, prev: slice base.u8),
choosy,
{
var filter_distance : base.u64[..= 8]
var n : base.u64
var i : base.u64
filter_distance = this.filter_distance as base.u64
if args.prev.length() == 0 {
i = filter_distance
assert i >= filter_distance via "a >= b: a == b"()
while i < args.curr.length(),
inv i >= filter_distance,
{
assert i < 0xFFFF_FFFF_FFFF_FFFF via "a < b: a < c; c <= b"(c: args.curr.length())
assert (i - filter_distance) < args.curr.length() via "(a - b) < c: a < c; 0 <= b"()
args.curr[i] ~mod+= args.curr[i - filter_distance] / 2
i += 1
assert i >= filter_distance via "a >= b: a >= (b + c); 0 <= c"(c: 1)
} endwhile
} else {
n = args.curr.length().min(a: args.prev.length())
i = 0
while (i < n) and (i < filter_distance),
inv n <= args.curr.length(),
inv n <= args.prev.length(),
{
assert i < 0xFFFF_FFFF_FFFF_FFFF via "a < b: a < c; c <= b"(c: n)
assert i < args.curr.length() via "a < b: a < c; c <= b"(c: n)
assert i < args.prev.length() via "a < b: a < c; c <= b"(c: n)
args.curr[i] ~mod+= args.prev[i] / 2
i += 1
} endwhile
i = filter_distance
assert i >= filter_distance via "a >= b: a == b"()
while i < n,
inv i >= filter_distance,
inv n <= args.curr.length(),
inv n <= args.prev.length(),
{
assert i < 0xFFFF_FFFF_FFFF_FFFF via "a < b: a < c; c <= b"(c: n)
assert i < args.curr.length() via "a < b: a < c; c <= b"(c: n)
assert i < args.prev.length() via "a < b: a < c; c <= b"(c: n)
assert (i - filter_distance) < args.curr.length() via "(a - b) < c: a < c; 0 <= b"()
args.curr[i] ~mod+= ((
(args.curr[i - filter_distance] as base.u32) +
(args.prev[i] as base.u32)) / 2) as base.u8
i += 1
assert i >= filter_distance via "a >= b: a >= (b + c); 0 <= c"(c: 1)
} endwhile
}
}
pri func decoder.filter_4!(curr: slice base.u8, prev: slice base.u8),
choosy,
{
var filter_distance : base.u64[..= 8]
var n : base.u64
var i : base.u64
var fa : base.u32
var fb : base.u32
var fc : base.u32
var pp : base.u32
var pa : base.u32
var pb : base.u32
var pc : base.u32
filter_distance = this.filter_distance as base.u64
n = args.curr.length().min(a: args.prev.length())
i = 0
while (i < n) and (i < filter_distance),
inv n <= args.curr.length(),
inv n <= args.prev.length(),
{
assert i < 0xFFFF_FFFF_FFFF_FFFF via "a < b: a < c; c <= b"(c: n)
assert i < args.curr.length() via "a < b: a < c; c <= b"(c: n)
assert i < args.prev.length() via "a < b: a < c; c <= b"(c: n)
args.curr[i] ~mod+= args.prev[i]
i += 1
} endwhile
i = filter_distance
assert i >= filter_distance via "a >= b: a == b"()
while i < n,
inv i >= filter_distance,
inv n <= args.curr.length(),
inv n <= args.prev.length(),
{
assert i < 0xFFFF_FFFF_FFFF_FFFF via "a < b: a < c; c <= b"(c: n)
assert i < args.curr.length() via "a < b: a < c; c <= b"(c: n)
assert i < args.prev.length() via "a < b: a < c; c <= b"(c: n)
assert (i - filter_distance) < args.curr.length() via "(a - b) < c: a < c; 0 <= b"()
assert (i - filter_distance) < args.prev.length() via "(a - b) < c: a < c; 0 <= b"()
fa = args.curr[i - filter_distance] as base.u32
fb = args.prev[i] as base.u32
fc = args.prev[i - filter_distance] as base.u32
pp = (fa ~mod+ fb) ~mod- fc
pa = pp ~mod- fa
if pa >= 0x8000_0000 {
pa = 0 ~mod- pa
}
pb = pp ~mod- fb
if pb >= 0x8000_0000 {
pb = 0 ~mod- pb
}
pc = pp ~mod- fc
if pc >= 0x8000_0000 {
pc = 0 ~mod- pc
}
if (pa <= pb) and (pa <= pc) {
// No-op.
} else if pb <= pc {
fa = fb
} else {
fa = fc
}
args.curr[i] ~mod+= (fa & 0xFF) as base.u8
i += 1
assert i >= filter_distance via "a >= b: a >= (b + c); 0 <= c"(c: 1)
} endwhile
}