#include "zbuild.h"
Z_INTERNAL uint32_t CHUNKSIZE(void) {
return sizeof(chunk_t);
}
Z_INTERNAL uint8_t* CHUNKCOPY(uint8_t *out, uint8_t const *from, unsigned len) {
Assert(len > 0, "chunkcopy should never have a length 0");
chunk_t chunk;
int32_t align = ((len - 1) % sizeof(chunk_t)) + 1;
loadchunk(from, &chunk);
storechunk(out, &chunk);
out += align;
from += align;
len -= align;
while (len > 0) {
loadchunk(from, &chunk);
storechunk(out, &chunk);
out += sizeof(chunk_t);
from += sizeof(chunk_t);
len -= sizeof(chunk_t);
}
return out;
}
Z_INTERNAL uint8_t* CHUNKCOPY_SAFE(uint8_t *out, uint8_t const *from, unsigned len, uint8_t *safe) {
unsigned safelen = (unsigned)((safe - out) + 1);
len = MIN(len, safelen);
#if CHUNK_SIZE >= 32
while (len >= 32) {
memcpy(out, from, 32);
out += 32;
from += 32;
len -= 32;
}
#endif
#if CHUNK_SIZE >= 16
while (len >= 16) {
memcpy(out, from, 16);
out += 16;
from += 16;
len -= 16;
}
#endif
#if CHUNK_SIZE >= 8
while (len >= 8) {
zmemcpy_8(out, from);
out += 8;
from += 8;
len -= 8;
}
#endif
if (len >= 4) {
zmemcpy_4(out, from);
out += 4;
from += 4;
len -= 4;
}
if (len >= 2) {
zmemcpy_2(out, from);
out += 2;
from += 2;
len -= 2;
}
if (len == 1) {
*out++ = *from++;
}
return out;
}
Z_INTERNAL uint8_t* CHUNKUNROLL(uint8_t *out, unsigned *dist, unsigned *len) {
unsigned char const *from = out - *dist;
chunk_t chunk;
while (*dist < *len && *dist < sizeof(chunk_t)) {
loadchunk(from, &chunk);
storechunk(out, &chunk);
out += *dist;
*len -= *dist;
*dist += *dist;
}
return out;
}
Z_INTERNAL uint8_t* CHUNKMEMSET(uint8_t *out, unsigned dist, unsigned len) {
Assert(dist > 0, "chunkmemset cannot have a distance 0");
unsigned char *from = out - dist;
chunk_t chunk;
unsigned sz = sizeof(chunk);
if (len < sz) {
while (len != 0) {
*out++ = *from++;
--len;
}
return out;
}
#ifdef HAVE_CHUNKMEMSET_1
if (dist == 1) {
chunkmemset_1(from, &chunk);
} else
#endif
#ifdef HAVE_CHUNKMEMSET_2
if (dist == 2) {
chunkmemset_2(from, &chunk);
} else
#endif
#ifdef HAVE_CHUNKMEMSET_4
if (dist == 4) {
chunkmemset_4(from, &chunk);
} else
#endif
#ifdef HAVE_CHUNKMEMSET_8
if (dist == 8) {
chunkmemset_8(from, &chunk);
} else
#endif
if (dist == sz) {
loadchunk(from, &chunk);
} else if (dist < sz) {
unsigned char *end = out + len - 1;
while (len > dist) {
out = CHUNKCOPY_SAFE(out, from, dist, end);
len -= dist;
}
if (len > 0) {
out = CHUNKCOPY_SAFE(out, from, len, end);
}
return out;
} else {
out = CHUNKUNROLL(out, &dist, &len);
return CHUNKCOPY(out, out - dist, len);
}
unsigned rem = len % sz;
len -= rem;
while (len) {
storechunk(out, &chunk);
out += sz;
len -= sz;
}
if (rem) {
memcpy(out, from, rem);
out += rem;
}
return out;
}
Z_INTERNAL uint8_t* CHUNKMEMSET_SAFE(uint8_t *out, unsigned dist, unsigned len, unsigned left) {
#if !defined(UNALIGNED64_OK)
# if !defined(UNALIGNED_OK)
static const uint32_t align_mask = 7;
# else
static const uint32_t align_mask = 3;
# endif
#endif
len = MIN(len, left);
uint8_t *from = out - dist;
#if !defined(UNALIGNED64_OK)
while (((uintptr_t)out & align_mask) && (len > 0)) {
*out++ = *from++;
--len;
--left;
}
#endif
if (left < (unsigned)(3 * sizeof(chunk_t))) {
while (len > 0) {
*out++ = *from++;
--len;
}
return out;
}
return CHUNKMEMSET(out, dist, len);
}