blob: 088f3ce5e9f0e6449d546b3eb35a69c415fde40f [file] [log] [blame]
// After editing this file, run "go generate" in the parent directory.
// Copyright 2017 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.
// ---------------- I/O
static inline bool //
wuffs_base__io_buffer__is_valid(wuffs_base__io_buffer buf) {
return (buf.data.ptr || (buf.data.len == 0)) &&
(buf.data.len >= buf.meta.wi) && (buf.meta.wi >= buf.meta.ri);
}
// TODO: wuffs_base__io_reader__is_eof is no longer used by Wuffs per se, but
// it might be handy to programs that use Wuffs. Either delete it, or promote
// it to the public API.
//
// If making this function public (i.e. moving it to base-header.h), it also
// needs to allow NULL (i.e. implicit, callee-calculated) mark/limit.
static inline bool //
wuffs_base__io_reader__is_eof(wuffs_base__io_reader o) {
wuffs_base__io_buffer* buf = o.private_impl.buf;
return buf && buf->meta.closed &&
(buf->data.ptr + buf->meta.wi == o.private_impl.limit);
}
static inline bool //
wuffs_base__io_reader__is_valid(wuffs_base__io_reader o) {
wuffs_base__io_buffer* buf = o.private_impl.buf;
// Note: if making this function public (i.e. moving it to base-header.h), it
// also needs to allow NULL (i.e. implicit, callee-calculated) mark/limit.
return buf ? ((buf->data.ptr <= o.private_impl.mark) &&
(o.private_impl.mark <= o.private_impl.limit) &&
(o.private_impl.limit <= buf->data.ptr + buf->data.len))
: ((o.private_impl.mark == NULL) &&
(o.private_impl.limit == NULL));
}
static inline bool //
wuffs_base__io_writer__is_valid(wuffs_base__io_writer o) {
wuffs_base__io_buffer* buf = o.private_impl.buf;
// Note: if making this function public (i.e. moving it to base-header.h), it
// also needs to allow NULL (i.e. implicit, callee-calculated) mark/limit.
return buf ? ((buf->data.ptr <= o.private_impl.mark) &&
(o.private_impl.mark <= o.private_impl.limit) &&
(o.private_impl.limit <= buf->data.ptr + buf->data.len))
: ((o.private_impl.mark == NULL) &&
(o.private_impl.limit == NULL));
}
static inline uint32_t //
wuffs_base__io_writer__copy_n_from_history(uint8_t** ptr_iop_w,
uint8_t* io0_w,
uint8_t* io1_w,
uint32_t length,
uint32_t distance) {
if (!distance) {
return 0;
}
uint8_t* p = *ptr_iop_w;
if ((size_t)(p - io0_w) < (size_t)(distance)) {
return 0;
}
uint8_t* q = p - distance;
size_t n = (size_t)(io1_w - p);
if ((size_t)(length) > n) {
length = (uint32_t)(n);
} else {
n = (size_t)(length);
}
// TODO: unrolling by 3 seems best for the std/deflate benchmarks, but that
// is mostly because 3 is the minimum length for the deflate format. This
// function implementation shouldn't overfit to that one format. Perhaps the
// copy_n_from_history Wuffs method should also take an unroll hint argument,
// and the cgen can look if that argument is the constant expression '3'.
//
// See also wuffs_base__io_writer__copy_n_from_history_fast below.
//
// Alternatively, or additionally, have a sloppy_copy_n_from_history method
// that copies 8 bytes at a time, possibly writing more than length bytes?
for (; n >= 3; n -= 3) {
*p++ = *q++;
*p++ = *q++;
*p++ = *q++;
}
for (; n; n--) {
*p++ = *q++;
}
*ptr_iop_w = p;
return length;
}
// wuffs_base__io_writer__copy_n_from_history_fast is like the
// wuffs_base__io_writer__copy_n_from_history function above, but has stronger
// pre-conditions. The caller needs to prove that:
// - distance > 0
// - distance <= (*ptr_iop_w - io0_w)
// - length <= (io1_w - *ptr_iop_w)
static inline uint32_t //
wuffs_base__io_writer__copy_n_from_history_fast(uint8_t** ptr_iop_w,
uint8_t* io0_w,
uint8_t* io1_w,
uint32_t length,
uint32_t distance) {
uint8_t* p = *ptr_iop_w;
uint8_t* q = p - distance;
uint32_t n = length;
for (; n >= 3; n -= 3) {
*p++ = *q++;
*p++ = *q++;
*p++ = *q++;
}
for (; n; n--) {
*p++ = *q++;
}
*ptr_iop_w = p;
return length;
}
static inline uint32_t //
wuffs_base__io_writer__copy_n_from_reader(uint8_t** ptr_iop_w,
uint8_t* io1_w,
uint32_t length,
uint8_t** ptr_iop_r,
uint8_t* io1_r) {
uint8_t* iop_w = *ptr_iop_w;
size_t n = length;
if (n > ((size_t)(io1_w - iop_w))) {
n = (size_t)(io1_w - iop_w);
}
uint8_t* iop_r = *ptr_iop_r;
if (n > ((size_t)(io1_r - iop_r))) {
n = (size_t)(io1_r - iop_r);
}
if (n > 0) {
memmove(iop_w, iop_r, n);
*ptr_iop_w += n;
*ptr_iop_r += n;
}
return (uint32_t)(n);
}
static inline uint64_t //
wuffs_base__io_writer__copy_from_slice(uint8_t** ptr_iop_w,
uint8_t* io1_w,
wuffs_base__slice_u8 src) {
uint8_t* iop_w = *ptr_iop_w;
size_t n = src.len;
if (n > ((size_t)(io1_w - iop_w))) {
n = (size_t)(io1_w - iop_w);
}
if (n > 0) {
memmove(iop_w, src.ptr, n);
*ptr_iop_w += n;
}
return (uint64_t)(n);
}
static inline uint32_t //
wuffs_base__io_writer__copy_n_from_slice(uint8_t** ptr_iop_w,
uint8_t* io1_w,
uint32_t length,
wuffs_base__slice_u8 src) {
uint8_t* iop_w = *ptr_iop_w;
size_t n = src.len;
if (n > length) {
n = length;
}
if (n > ((size_t)(io1_w - iop_w))) {
n = (size_t)(io1_w - iop_w);
}
if (n > 0) {
memmove(iop_w, src.ptr, n);
*ptr_iop_w += n;
}
return (uint32_t)(n);
}
static inline wuffs_base__empty_struct //
wuffs_base__io_reader__set(wuffs_base__io_reader* o,
wuffs_base__io_buffer* b,
uint8_t** ptr_iop_r,
uint8_t** ptr_io1_r,
wuffs_base__slice_u8 data) {
b->data = data;
b->meta.wi = data.len;
b->meta.ri = 0;
b->meta.pos = 0;
b->meta.closed = false;
o->private_impl.buf = b;
o->private_impl.mark = data.ptr;
o->private_impl.limit = data.ptr + data.len;
*ptr_iop_r = data.ptr;
*ptr_io1_r = data.ptr + data.len;
wuffs_base__empty_struct ret;
ret.private_impl = 0;
return ret;
}
static inline wuffs_base__empty_struct //
wuffs_base__io_reader__set_limit(wuffs_base__io_reader* o,
uint8_t* iop_r,
uint64_t limit) {
if (o && (((size_t)(o->private_impl.limit - iop_r)) > limit)) {
o->private_impl.limit = iop_r + limit;
}
wuffs_base__empty_struct ret;
ret.private_impl = 0;
return ret;
}
static inline wuffs_base__empty_struct //
wuffs_base__io_reader__set_mark(wuffs_base__io_reader* o, uint8_t* mark) {
o->private_impl.mark = mark;
wuffs_base__empty_struct ret;
ret.private_impl = 0;
return ret;
}
static inline wuffs_base__slice_u8 //
wuffs_base__io_reader__take(uint8_t** ptr_iop_r, uint8_t* io1_r, uint64_t n) {
if (n <= ((size_t)(io1_r - *ptr_iop_r))) {
uint8_t* p = *ptr_iop_r;
*ptr_iop_r += n;
return wuffs_base__make_slice_u8(p, n);
}
return wuffs_base__make_slice_u8(NULL, 0);
}
static inline wuffs_base__empty_struct //
wuffs_base__io_writer__set(wuffs_base__io_writer* o,
wuffs_base__io_buffer* b,
uint8_t** ptr_iop_w,
uint8_t** ptr_io1_w,
wuffs_base__slice_u8 data) {
b->data = data;
b->meta.wi = 0;
b->meta.ri = 0;
b->meta.pos = 0;
b->meta.closed = false;
o->private_impl.buf = b;
o->private_impl.mark = data.ptr;
o->private_impl.limit = data.ptr + data.len;
*ptr_iop_w = data.ptr;
*ptr_io1_w = data.ptr + data.len;
wuffs_base__empty_struct ret;
ret.private_impl = 0;
return ret;
}
static inline wuffs_base__empty_struct //
wuffs_base__io_writer__set_mark(wuffs_base__io_writer* o, uint8_t* mark) {
o->private_impl.mark = mark;
wuffs_base__empty_struct ret;
ret.private_impl = 0;
return ret;
}
// ---------------- I/O (Utility)
#define wuffs_base__utility__null_io_reader wuffs_base__null_io_reader
#define wuffs_base__utility__null_io_writer wuffs_base__null_io_writer