mirror of
https://github.com/Alcaro/Flips.git
synced 2026-09-07 01:56:07 -05:00
Clean up BPS creator a bit... it's already well optimized, not much to do.
This commit is contained in:
@@ -41,6 +41,7 @@ public:
|
||||
};
|
||||
private:
|
||||
impl* core;
|
||||
file(impl* core) : core(core) {}
|
||||
|
||||
public:
|
||||
enum mode {
|
||||
@@ -54,7 +55,6 @@ public:
|
||||
file() : core(NULL) {}
|
||||
file(file&& f) { core=f.core; f.core=NULL; }
|
||||
file& operator=(file&& f) { delete core; core=f.core; f.core=NULL; return *this; }
|
||||
file(impl* core) : core(core) {}
|
||||
file(cstring filename, mode m = m_read) : core(NULL) { open(filename, m); }
|
||||
|
||||
bool open(cstring filename, mode m = m_read)
|
||||
|
||||
@@ -33,26 +33,3 @@ size_t memcmp_d(const void * a, const void * b, size_t len)
|
||||
while (i<len && ab[i]==bb[i]) i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
//size_t memcmp_d(const void * a, const void * b, size_t len)
|
||||
//{
|
||||
//const uint8_t* ab = (uint8_t*)a;
|
||||
//const uint8_t* bb = (uint8_t*)b;
|
||||
//
|
||||
//size_t i;
|
||||
//for (i=0;i<len && ab[i]==bb[i];i++) {}
|
||||
//return i;
|
||||
//}
|
||||
|
||||
//size_t memcmp_d(const void * a, const void * b, size_t len)
|
||||
//{
|
||||
//size_t r1 = memcmp_dfast(a, b, len);
|
||||
//size_t r2 = memcmp_dslow(a, b, len);
|
||||
//if (r1!=r2)
|
||||
//{
|
||||
//size_t r3 = memcmp_dfast(a, b, len);
|
||||
//printf("%zu:%zu:%zu\n",r1,r2,r3);
|
||||
//abort();
|
||||
//}
|
||||
//return r2;
|
||||
//}
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
#include "patch.h"
|
||||
|
||||
//Deprecated
|
||||
//struct mem {
|
||||
//mem() : ptr(NULL), len(0) {}
|
||||
//mem(uint8_t* ptr, size_t len) : ptr(ptr), len(len) {}
|
||||
//mem(arrayview<byte> v) : ptr((byte*)v.ptr()), len(v.size()) {}
|
||||
//arrayvieww<byte> v() { return arrayvieww<byte>(ptr, len); }
|
||||
//uint8_t * ptr;
|
||||
//size_t len;
|
||||
//};
|
||||
|
||||
//These two give minor performance penalties and will print some random stuff to stdout.
|
||||
//The former will verify the correctness of the output patch, the latter will print some performance data.
|
||||
//Can be useful for debugging, but should be disabled for release builds.
|
||||
@@ -131,11 +141,6 @@ static void sufsort(int64_t* SA, uint8_t* T, int64_t n)
|
||||
|
||||
|
||||
|
||||
template<typename T> static T min(T a, T b) { return a<b ? a : b; }
|
||||
template<typename T> static T max(T a, T b) { return a<b ? b : a; }
|
||||
|
||||
|
||||
|
||||
namespace {
|
||||
//class filecache {
|
||||
// file& f;
|
||||
@@ -150,26 +155,7 @@ namespace {
|
||||
//};
|
||||
|
||||
struct bps_creator {
|
||||
uint8_t* out;
|
||||
size_t outlen;
|
||||
size_t outbuflen;
|
||||
|
||||
void reserve(size_t len)
|
||||
{
|
||||
if (outlen+len > outbuflen)
|
||||
{
|
||||
if (!outbuflen) outbuflen = 128;
|
||||
while (outlen+len > outbuflen) outbuflen *= 2;
|
||||
out = (uint8_t*)realloc(out, outbuflen);
|
||||
}
|
||||
}
|
||||
|
||||
void append(const uint8_t * data, size_t len)
|
||||
{
|
||||
reserve(len);
|
||||
memcpy(out+outlen, data, len);
|
||||
outlen+=len;
|
||||
}
|
||||
array<byte> out;
|
||||
|
||||
void appendnum(size_t num)
|
||||
{
|
||||
@@ -177,29 +163,27 @@ struct bps_creator {
|
||||
if (num > 1000000000)
|
||||
printf("ERROR: Attempt to write %.8lX\n",(unsigned long)num),abort();
|
||||
#endif
|
||||
reserve(sizeof(size_t)*8/7+1);
|
||||
|
||||
while (num >= 128)
|
||||
{
|
||||
out[outlen++]=(num&0x7F);
|
||||
out.append((num&0x7F));
|
||||
num>>=7;
|
||||
num--;
|
||||
}
|
||||
out[outlen++]=num|0x80;
|
||||
out.append(num|0x80);
|
||||
}
|
||||
|
||||
void appendnum32(uint32_t num)
|
||||
{
|
||||
reserve(4);
|
||||
out[outlen++] = num>>0;
|
||||
out[outlen++] = num>>8;
|
||||
out[outlen++] = num>>16;
|
||||
out[outlen++] = num>>24;
|
||||
out.append(num>>0);
|
||||
out.append(num>>8);
|
||||
out.append(num>>16);
|
||||
out.append(num>>24);
|
||||
}
|
||||
|
||||
static size_t maxsize()
|
||||
{
|
||||
return SIZE_MAX>>2; // can be reduced to SIZE_MAX>>1 by amending append_cmd, but the mallocs overflow at that point anyways.
|
||||
return SIZE_MAX>>2; // can probably be reduced to SIZE_MAX>>1, but the mallocs overflow at that point anyways.
|
||||
}
|
||||
|
||||
size_t sourcelen;
|
||||
@@ -215,12 +199,8 @@ struct bps_creator {
|
||||
|
||||
size_t numtargetread;
|
||||
|
||||
bps_creator(const file& source, const file& target, struct mem metadata)
|
||||
bps_creator(const file& source, const file& target, const file& metadata)
|
||||
{
|
||||
outlen = 0;
|
||||
outbuflen = 128;
|
||||
out = (uint8_t*)malloc(outbuflen);
|
||||
|
||||
outpos = 0;
|
||||
|
||||
sourcelen = source.size();
|
||||
@@ -231,11 +211,13 @@ struct bps_creator {
|
||||
|
||||
numtargetread = 0;
|
||||
|
||||
append((const uint8_t*)"BPS1", 4);
|
||||
out += arrayview<byte>((byte*)"BPS1", 4);
|
||||
appendnum(sourcelen);
|
||||
appendnum(targetlen);
|
||||
appendnum(metadata.len);
|
||||
append(metadata.ptr, metadata.len);
|
||||
appendnum(metadata.size());
|
||||
arrayview<byte> tmp = metadata.mmap();
|
||||
out += tmp;
|
||||
metadata.unmap(tmp);
|
||||
}
|
||||
|
||||
|
||||
@@ -265,7 +247,7 @@ struct bps_creator {
|
||||
{
|
||||
if (!numtargetread) return;
|
||||
append_cmd(TargetRead, numtargetread);
|
||||
append(targetmem+outpos-numtargetread, numtargetread);
|
||||
out += arrayview<byte>(targetmem+outpos-numtargetread, numtargetread);
|
||||
numtargetread = 0;
|
||||
}
|
||||
|
||||
@@ -365,17 +347,15 @@ struct bps_creator {
|
||||
|
||||
appendnum32(crc32(arrayview<byte>(source, sourcelen)));
|
||||
appendnum32(crc32(arrayview<byte>(target, targetlen)));
|
||||
appendnum32(crc32(arrayview<byte>(out, outlen)));
|
||||
appendnum32(crc32(out));
|
||||
}
|
||||
|
||||
struct mem getpatch()
|
||||
size_t outlen() { return out.size(); }
|
||||
|
||||
array<byte> getpatch()
|
||||
{
|
||||
struct mem ret = { out, outlen };
|
||||
out = NULL;
|
||||
return ret;
|
||||
return std::move(out);
|
||||
}
|
||||
|
||||
~bps_creator() { free(out); }
|
||||
};
|
||||
}
|
||||
|
||||
@@ -386,10 +366,10 @@ static int match_len_n=0;
|
||||
static int match_len_tot=0;
|
||||
#endif
|
||||
|
||||
template<typename off_t>
|
||||
static off_t match_len(const uint8_t* a, const uint8_t* b, off_t len)
|
||||
static size_t match_len(const uint8_t* a, const uint8_t* b, size_t len)
|
||||
{
|
||||
off_t i;
|
||||
//don't replace with memcmp_d, the average match length is so small it's a net loss
|
||||
size_t i;
|
||||
for (i=0;i<len && a[i]==b[i];i++) {}
|
||||
#ifdef TEST_PERF
|
||||
match_len_n++;
|
||||
@@ -582,6 +562,7 @@ static off_t find_index(off_t pos, const uint8_t* data, off_t datalen, const off
|
||||
const uint8_t* search = data+pos+matchlenstart;
|
||||
const uint8_t* here = data+midpos+matchlenstart;
|
||||
|
||||
//don't replace with match_len, it's not inlined properly
|
||||
while (len>0 && *search==*here)
|
||||
{
|
||||
search++;
|
||||
@@ -619,18 +600,6 @@ static off_t find_index(off_t pos, const uint8_t* data, off_t datalen, const off
|
||||
}
|
||||
|
||||
|
||||
template<typename off_t>
|
||||
static void create_reverse_index(off_t* index, off_t* reverse, off_t len)
|
||||
{
|
||||
//testcase: linux 3.18.14 -> 4.0.4 .xz
|
||||
//without: real23.544 user32.930
|
||||
//with: real22.636 user40.168
|
||||
//'user' jumps up quite a lot, while 'real' only moves a short bit
|
||||
//I'm not sure why the tradeoff is so bad (do the cachelines bounce THAT badly?), but I deem it not worth it.
|
||||
//#pragma omp parallel for
|
||||
for (off_t i=0;i<len;i++) reverse[index[i]]=i;
|
||||
}
|
||||
|
||||
template<typename off_t>
|
||||
static off_t nextsize(off_t outpos, off_t sortedsize, off_t targetlen)
|
||||
{
|
||||
@@ -784,26 +753,22 @@ template<> result create_suf_pick<uint64_t>(const file& source, const file& targ
|
||||
|
||||
//This one picks a function based on 32-bit integers if that fits. This halves memory use for common inputs.
|
||||
//It also handles some stuff related to the BPS headers and footers.
|
||||
result create(const file& source, const file& target, const file& metadata, file& patch,
|
||||
result create(const file& source, const file& target, const file& metadata, array<byte>& patch,
|
||||
function<bool(size_t done, size_t total)> progress)
|
||||
{
|
||||
mem metamem = metadata.mmap();
|
||||
bps_creator bps(source, target, metamem);
|
||||
metadata.unmap(metamem.v());
|
||||
bps_creator bps(source, target, metadata);
|
||||
bps.progress = progress;
|
||||
|
||||
size_t maindata = bps.outlen;
|
||||
size_t maindata = bps.outlen();
|
||||
|
||||
//off_t must be signed
|
||||
result err = create_suf_pick<size_t>(source, target, &bps);
|
||||
if (err!=e_ok) return err;
|
||||
|
||||
mem patchmem = bps.getpatch();
|
||||
patch.write(patchmem.v());
|
||||
patch = bps.getpatch();
|
||||
|
||||
while ((patchmem.ptr[maindata]&0x80) == 0x00) maindata++;
|
||||
free(patchmem.ptr);
|
||||
if (maindata==patchmem.len-12-1) return e_identical;
|
||||
while ((patch[maindata]&0x80) == 0x00) maindata++;
|
||||
if (maindata==patch.size()-12-1) return e_identical;
|
||||
return e_ok;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,22 +59,43 @@ result apply(arrayview<byte> patch, arrayview<byte> source, array<byte>& target,
|
||||
// called for done=total, done may or may not increase by the same amount between each call, and
|
||||
// the duration between each call may or may not be constant.
|
||||
//To cancel patch creation, return true from the callback. It's safe to pass in NULL if you're not interested.
|
||||
result create(const file& source, const file& target, const file& metadata, file& patch,
|
||||
result create(const file& source, const file& target, const file& metadata, array<byte>& patch,
|
||||
function<bool(size_t done, size_t total)> progress);
|
||||
static inline result create(const file& source, const file& target, const file& metadata, file&& patch,
|
||||
static inline result create(arrayview<byte> source, const file& target, const file& metadata, array<byte>& patch,
|
||||
function<bool(size_t done, size_t total)> progress)
|
||||
{
|
||||
return create(source, target, metadata, (file&)patch, progress);
|
||||
return create(file::mem(source), target, metadata, patch, progress);
|
||||
}
|
||||
static inline result create(const file& source, const file& target, file& patch,
|
||||
static inline result create(const file& source, arrayview<byte> target, const file& metadata, array<byte>& patch,
|
||||
function<bool(size_t done, size_t total)> progress)
|
||||
{
|
||||
return create(source, target, file::mem(NULL), (file&)patch, progress);
|
||||
return create(source, file::mem(target), metadata, patch, progress);
|
||||
}
|
||||
static inline result create(const file& source, const file& target, file&& patch,
|
||||
static inline result create(arrayview<byte> source, arrayview<byte> target, const file& metadata, array<byte>& patch,
|
||||
function<bool(size_t done, size_t total)> progress)
|
||||
{
|
||||
return create(source, target, (file&)patch, progress);
|
||||
return create(file::mem(source), file::mem(target), metadata, patch, progress);
|
||||
}
|
||||
|
||||
static inline result create(const file& source, const file& target, array<byte>& patch,
|
||||
function<bool(size_t done, size_t total)> progress)
|
||||
{
|
||||
return create(source, target, file::mem(NULL), patch, progress);
|
||||
}
|
||||
static inline result create(arrayview<byte> source, const file& target, array<byte>& patch,
|
||||
function<bool(size_t done, size_t total)> progress)
|
||||
{
|
||||
return create(file::mem(source), target, file::mem(NULL), patch, progress);
|
||||
}
|
||||
static inline result create(const file& source, arrayview<byte> target, array<byte>& patch,
|
||||
function<bool(size_t done, size_t total)> progress)
|
||||
{
|
||||
return create(source, file::mem(target), file::mem(NULL), patch, progress);
|
||||
}
|
||||
static inline result create(arrayview<byte> source, arrayview<byte> target, array<byte>& patch,
|
||||
function<bool(size_t done, size_t total)> progress)
|
||||
{
|
||||
return create(file::mem(source), file::mem(target), file::mem(NULL), patch, progress);
|
||||
}
|
||||
|
||||
struct info {
|
||||
@@ -233,14 +254,4 @@ public:
|
||||
return crc;
|
||||
}
|
||||
};
|
||||
|
||||
//Deprecated
|
||||
struct mem {
|
||||
mem() : ptr(NULL), len(0) {}
|
||||
mem(uint8_t* ptr, size_t len) : ptr(ptr), len(len) {}
|
||||
mem(arrayview<byte> v) : ptr((byte*)v.ptr()), len(v.size()) {}
|
||||
arrayvieww<byte> v() { return arrayvieww<byte>(ptr, len); }
|
||||
uint8_t * ptr;
|
||||
size_t len;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ static void createtest(arrayview<byte> a, arrayview<byte> b, size_t ipssize, siz
|
||||
if (testbps)
|
||||
{
|
||||
array<byte> patch;
|
||||
result r = bps::create(file::mem(a), file::mem(b), file::mem(patch), NULL);
|
||||
result r = bps::create(a, b, patch, NULL);
|
||||
if (r!=e_identical) assert_eq(r, e_ok);
|
||||
array<byte> b2;
|
||||
r = bps::apply(patch, a, b2);
|
||||
@@ -169,8 +169,9 @@ test("BPS")
|
||||
test("the big ones")
|
||||
{
|
||||
testips=true;
|
||||
testips=false;
|
||||
testbps=true;
|
||||
testbps=false;
|
||||
//testbps=false;
|
||||
|
||||
array<byte> smw = file::read("patch/test/smw.sfc");
|
||||
array<byte> smw_bps = file::read("patch/test/smwcp.bps");
|
||||
|
||||
Reference in New Issue
Block a user