add SkChecksum as a static class, for the replacement API

after this lands, plan to deprecate/remove the older APIs
Review URL: https://codereview.appspot.com/6356059

git-svn-id: http://skia.googlecode.com/svn/trunk@4457 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@google.com 2012-07-03 19:44:20 +00:00
parent 54823c227d
commit 88db9ef0cd
2 changed files with 95 additions and 2 deletions

View File

@ -61,15 +61,33 @@ private:
class ComputeChecksum64Bench : public ComputeChecksumBench {
public:
ComputeChecksum64Bench(void* param)
: INHERITED(param, "64") { }
: INHERITED(param, "64") { }
protected:
virtual void computeChecksum(const uint64_t* data, size_t len) {
for (int i = 0; i < N; i++) {
volatile uint64_t result = SkComputeChecksum64(data, len);
}
}
private:
typedef ComputeChecksumBench INHERITED;
};
/*
* Use SkComputeChecksum64 to compute a checksum on a datablock
*/
class ComputeChecksumXXBench : public ComputeChecksumBench {
public:
ComputeChecksumXXBench(void* param) : INHERITED(param, "XX") { }
protected:
virtual void computeChecksum(const uint64_t* data, size_t len) {
for (int i = 0; i < N; i++) {
volatile uint32_t result = SkChecksum::Compute(reinterpret_cast<const uint32_t*>(data), len);
}
}
private:
typedef ComputeChecksumBench INHERITED;
};
@ -78,6 +96,8 @@ private:
static SkBenchmark* Fact0(void* p) { return new ComputeChecksum32Bench(p); }
static SkBenchmark* Fact1(void* p) { return new ComputeChecksum64Bench(p); }
static SkBenchmark* Fact2(void* p) { return new ComputeChecksumXXBench(p); }
static BenchRegistry gReg0(Fact0);
static BenchRegistry gReg1(Fact1);
static BenchRegistry gReg2(Fact2);

View File

@ -67,5 +67,78 @@ inline uint32_t SkComputeChecksum32(const uint32_t* ptr, size_t size) {
}
return result;
}
class SkChecksum : SkNoncopyable {
private:
/*
* Our Rotate and Mash helpers are meant to automatically do the right
* thing depending if sizeof(uintptr_t) is 4 or 8.
*/
enum {
ROTR = 17,
ROTL = sizeof(uintptr_t) * 8 - ROTR,
HALFBITS = sizeof(uintptr_t) * 4
};
static inline uintptr_t Mash(uintptr_t total, uintptr_t value) {
return ((total >> ROTR) | (total << ROTL)) ^ value;
}
public:
/**
* Compute a 32-bit checksum for a given data block
*
* @param data Memory address of the data block to be processed. Must be
* 32-bit aligned.
* @param size Size of the data block in bytes. Must be a multiple of 4.
* @return checksum result
*/
static uint32_t Compute(const uint32_t* data, size_t size) {
SkASSERT(SkIsAlign4(size));
/*
* We want to let the compiler use 32bit or 64bit addressing and math
* so we use uintptr_t as our magic type. This makes the code a little
* more obscure (we can't hard-code 32 or 64 anywhere, but have to use
* sizeof()).
*/
uintptr_t result = 0;
const uintptr_t* ptr = reinterpret_cast<const uintptr_t*>(data);
/*
* count the number of quad element chunks. This takes into account
* if we're on a 32bit or 64bit arch, since we use sizeof(uintptr_t)
* to compute how much to shift-down the size.
*/
int n4 = size / (sizeof(uintptr_t) << 2);
for (int i = 0; i < n4; ++i) {
result = Mash(result, *ptr++);
result = Mash(result, *ptr++);
result = Mash(result, *ptr++);
result = Mash(result, *ptr++);
}
size &= ((sizeof(uintptr_t) << 2) - 1);
data = reinterpret_cast<const uint32_t*>(ptr);
const uint32_t* stop = data + (size >> 2);
while (data < stop) {
result = Mash(result, *data++);
}
/*
* smash us down to 32bits if we were 64. Note that when uintptr_t is
* 32bits, this code-path should go away, but I still got a warning
* when I wrote
* result ^= result >> 32;
* since >>32 is undefined for 32bit ints, hence the wacky HALFBITS
* define.
*/
if (8 == sizeof(result)) {
result ^= result >> HALFBITS;
}
return static_cast<uint32_t>(result);
}
};
#endif