minor C++ optimizations

This is mostly just inlining a couple of getter/setter pairs that are in the tightest loops.
The only semantic change is making the retain() and release() methods of the reference counted
objects non-virtual, which allows them to be inlined.

See also http://groups.google.com/group/zxing/browse_thread/thread/6ea93730a7093199

git-svn-id: https://zxing.googlecode.com/svn/trunk@1974 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
smparkes@smparkes.net 2011-10-15 00:58:10 +00:00
parent 70190f7805
commit 31cb655de2
7 changed files with 96 additions and 68 deletions

View file

@ -59,14 +59,6 @@ size_t BitArray::getSize() {
return size_; return size_;
} }
bool BitArray::get(size_t i) {
return (bits_[i >> logBits_] & (1 << (i & bitsMask_))) != 0;
}
void BitArray::set(size_t i) {
bits_[i >> logBits_] |= 1 << (i & bitsMask_);
}
void BitArray::setBulk(size_t i, unsigned int newBits) { void BitArray::setBulk(size_t i, unsigned int newBits) {
bits_[i >> logBits_] = newBits; bits_[i >> logBits_] = newBits;
} }

View file

@ -42,8 +42,15 @@ public:
BitArray(size_t size); BitArray(size_t size);
~BitArray(); ~BitArray();
size_t getSize(); size_t getSize();
bool get(size_t i);
void set(size_t i); bool get(size_t i) {
return (bits_[i >> logBits_] & (1 << (i & bitsMask_))) != 0;
}
void set(size_t i) {
bits_[i >> logBits_] |= 1 << (i & bitsMask_);
}
void setBulk(size_t i, unsigned int newBits); void setBulk(size_t i, unsigned int newBits);
void setRange(int start, int end); void setRange(int start, int end);
void clear(); void clear();

View file

@ -25,7 +25,6 @@
#include <sstream> #include <sstream>
#include <string> #include <string>
using std::numeric_limits;
using std::ostream; using std::ostream;
using std::ostringstream; using std::ostringstream;
@ -34,21 +33,9 @@ using zxing::BitArray;
using zxing::Ref; using zxing::Ref;
namespace { namespace {
unsigned int logDigits(unsigned digits) { size_t wordsForSize(size_t width,
unsigned log = 0; size_t height,
unsigned val = 1; unsigned int logBits) {
while (val < digits) {
log++;
val <<= 1;
}
return log;
}
const unsigned int bitsPerWord = numeric_limits<unsigned int>::digits;
const unsigned int logBits = logDigits(bitsPerWord);
const unsigned int bitsMask = (1 << logBits) - 1;
size_t wordsForSize(size_t width, size_t height) {
size_t bits = width * height; size_t bits = width * height;
int arraySize = bits >> logBits; int arraySize = bits >> logBits;
if (bits - (arraySize << logBits) != 0) { if (bits - (arraySize << logBits) != 0) {
@ -60,16 +47,14 @@ namespace {
BitMatrix::BitMatrix(size_t dimension) : BitMatrix::BitMatrix(size_t dimension) :
width_(dimension), height_(dimension), words_(0), bits_(NULL) { width_(dimension), height_(dimension), words_(0), bits_(NULL) {
words_ = wordsForSize(width_, height_, logBits);
words_ = wordsForSize(width_, height_);
bits_ = new unsigned int[words_]; bits_ = new unsigned int[words_];
clear(); clear();
} }
BitMatrix::BitMatrix(size_t width, size_t height) : BitMatrix::BitMatrix(size_t width, size_t height) :
width_(width), height_(height), words_(0), bits_(NULL) { width_(width), height_(height), words_(0), bits_(NULL) {
words_ = wordsForSize(width_, height_, logBits);
words_ = wordsForSize(width_, height_);
bits_ = new unsigned int[words_]; bits_ = new unsigned int[words_];
clear(); clear();
} }
@ -79,16 +64,6 @@ BitMatrix::~BitMatrix() {
} }
bool BitMatrix::get(size_t x, size_t y) const {
size_t offset = x + width_ * y;
return ((bits_[offset >> logBits] >> (offset & bitsMask)) & 0x01) != 0;
}
void BitMatrix::set(size_t x, size_t y) {
size_t offset = x + width_ * y;
bits_[offset >> logBits] |= 1 << (offset & bitsMask);
}
void BitMatrix::flip(size_t x, size_t y) { void BitMatrix::flip(size_t x, size_t y) {
size_t offset = x + width_ * y; size_t offset = x + width_ * y;
bits_[offset >> logBits] ^= 1 << (offset & bitsMask); bits_[offset >> logBits] ^= 1 << (offset & bitsMask);
@ -135,7 +110,7 @@ Ref<BitArray> BitMatrix::getRow(int y, Ref<BitArray> row) {
size_t lastBit = i < lastWord ? bitsPerWord - 1 : end & bitsMask; size_t lastBit = i < lastWord ? bitsPerWord - 1 : end & bitsMask;
unsigned int mask; unsigned int mask;
if (firstBit == 0 && lastBit == logBits) { if (firstBit == 0 && lastBit == logBits) {
mask = numeric_limits<unsigned int>::max(); mask = std::numeric_limits<unsigned int>::max();
} else { } else {
mask = 0; mask = 0;
for (size_t j = firstBit; j <= lastBit; j++) { for (size_t j = firstBit; j <= lastBit; j++) {

View file

@ -34,14 +34,35 @@ private:
size_t words_; size_t words_;
unsigned int* bits_; unsigned int* bits_;
#define ZX_LOG_DIGITS(digits) \
((digits == 8) ? 3 : \
((digits == 16) ? 4 : \
((digits == 32) ? 5 : \
((digits == 64) ? 6 : \
((digits == 128) ? 7 : \
(-1))))))
static const unsigned int bitsPerWord =
std::numeric_limits<unsigned int>::digits;
static const unsigned int logBits = ZX_LOG_DIGITS(bitsPerWord);
static const unsigned int bitsMask = (1 << logBits) - 1;
public: public:
BitMatrix(size_t dimension); BitMatrix(size_t dimension);
BitMatrix(size_t width, size_t height); BitMatrix(size_t width, size_t height);
~BitMatrix(); ~BitMatrix();
// Inlining this does not really improve performance.
bool get(size_t x, size_t y) const; bool get(size_t x, size_t y) const {
void set(size_t x, size_t y); size_t offset = x + width_ * y;
return ((bits_[offset >> logBits] >> (offset & bitsMask)) & 0x01) != 0;
}
void set(size_t x, size_t y) {
size_t offset = x + width_ * y;
bits_[offset >> logBits] |= 1 << (offset & bitsMask);
}
void flip(size_t x, size_t y); void flip(size_t x, size_t y);
void clear(); void clear();
void setRegion(size_t left, size_t top, size_t width, size_t height); void setRegion(size_t left, size_t top, size_t width, size_t height);

View file

@ -21,7 +21,6 @@
*/ */
//#define DEBUG_COUNTING //#define DEBUG_COUNTING
//using namespace std;
#include <iostream> #include <iostream>
@ -45,7 +44,7 @@ public:
} }
virtual ~Counted() { virtual ~Counted() {
} }
virtual Counted *retain() { Counted *retain() {
#ifdef DEBUG_COUNTING #ifdef DEBUG_COUNTING
cout << "retaining " << typeid(*this).name() << " " << this << cout << "retaining " << typeid(*this).name() << " " << this <<
" @ " << count_; " @ " << count_;
@ -56,7 +55,7 @@ public:
#endif #endif
return this; return this;
} }
virtual void release() { void release() {
#ifdef DEBUG_COUNTING #ifdef DEBUG_COUNTING
cout << "releasing " << typeid(*this).name() << " " << this << cout << "releasing " << typeid(*this).name() << " " << this <<
" @ " << count_; " @ " << count_;

View file

@ -44,19 +44,22 @@ HybridBinarizer::~HybridBinarizer() {
} }
Ref<Binarizer> HybridBinarizer::createBinarizer(Ref<LuminanceSource> source) { Ref<Binarizer>
HybridBinarizer::createBinarizer(Ref<LuminanceSource> source) {
return Ref<Binarizer> (new HybridBinarizer(source)); return Ref<Binarizer> (new HybridBinarizer(source));
} }
Ref<BitMatrix> HybridBinarizer::getBlackMatrix() { Ref<BitMatrix> HybridBinarizer::getBlackMatrix() {
// Calculates the final BitMatrix once for all requests. This could be called once from the // Calculates the final BitMatrix once for all requests. This could
// constructor instead, but there are some advantages to doing it lazily, such as making // be called once from the constructor instead, but there are some
// profiling easier, and not doing heavy lifting when callers don't expect it. // advantages to doing it lazily, such as making profiling easier,
// and not doing heavy lifting when callers don't expect it.
if (matrix_) { if (matrix_) {
return matrix_; return matrix_;
} }
LuminanceSource& source = *getLuminanceSource(); LuminanceSource& source = *getLuminanceSource();
if (source.getWidth() >= MINIMUM_DIMENSION && source.getHeight() >= MINIMUM_DIMENSION) { if (source.getWidth() >= MINIMUM_DIMENSION &&
source.getHeight() >= MINIMUM_DIMENSION) {
unsigned char* luminances = source.getMatrix(); unsigned char* luminances = source.getMatrix();
int width = source.getWidth(); int width = source.getWidth();
int height = source.getHeight(); int height = source.getHeight();
@ -68,14 +71,22 @@ Ref<BitMatrix> HybridBinarizer::getBlackMatrix() {
if ((height & BLOCK_SIZE_MASK) != 0) { if ((height & BLOCK_SIZE_MASK) != 0) {
subHeight++; subHeight++;
} }
int* blackPoints = calculateBlackPoints(luminances, subWidth, subHeight, width, height); int* blackPoints =
calculateBlackPoints(luminances, subWidth, subHeight, width, height);
Ref<BitMatrix> newMatrix (new BitMatrix(width, height)); Ref<BitMatrix> newMatrix (new BitMatrix(width, height));
calculateThresholdForBlock(luminances, subWidth, subHeight, width, height, blackPoints, newMatrix); calculateThresholdForBlock(luminances,
subWidth,
subHeight,
width,
height,
blackPoints,
newMatrix);
matrix_ = newMatrix; matrix_ = newMatrix;
// N.B.: these deletes are inadequate if anything between the new and this point can throw. // N.B.: these deletes are inadequate if anything between the new
// As of this writing, it doesn't look like they do. // and this point can throw. As of this writing, it doesn't look
// like they do.
delete [] blackPoints; delete [] blackPoints;
delete [] luminances; delete [] luminances;
@ -86,8 +97,14 @@ Ref<BitMatrix> HybridBinarizer::getBlackMatrix() {
return matrix_; return matrix_;
} }
void HybridBinarizer::calculateThresholdForBlock(unsigned char* luminances, int subWidth, int subHeight, void
int width, int height, int blackPoints[], Ref<BitMatrix> matrix) { HybridBinarizer::calculateThresholdForBlock(unsigned char* luminances,
int subWidth,
int subHeight,
int width,
int height,
int blackPoints[],
Ref<BitMatrix> const& matrix) {
for (int y = 0; y < subHeight; y++) { for (int y = 0; y < subHeight; y++) {
int yoffset = y << BLOCK_SIZE_POWER; int yoffset = y << BLOCK_SIZE_POWER;
if (yoffset + BLOCK_SIZE >= height) { if (yoffset + BLOCK_SIZE >= height) {
@ -117,8 +134,12 @@ void HybridBinarizer::calculateThresholdForBlock(unsigned char* luminances, int
} }
} }
void HybridBinarizer::threshold8x8Block(unsigned char* luminances, int xoffset, int yoffset, int threshold, void HybridBinarizer::threshold8x8Block(unsigned char* luminances,
int stride, Ref<BitMatrix> matrix) { int xoffset,
int yoffset,
int threshold,
int stride,
Ref<BitMatrix> const& matrix) {
for (int y = 0, offset = yoffset * stride + xoffset; for (int y = 0, offset = yoffset * stride + xoffset;
y < BLOCK_SIZE; y < BLOCK_SIZE;
y++, offset += stride) { y++, offset += stride) {

View file

@ -41,15 +41,28 @@ namespace zxing {
virtual Ref<BitMatrix> getBlackMatrix(); virtual Ref<BitMatrix> getBlackMatrix();
Ref<Binarizer> createBinarizer(Ref<LuminanceSource> source); Ref<Binarizer> createBinarizer(Ref<LuminanceSource> source);
private: private:
// We'll be using one-D arrays because C++ can't dynamically allocate 2D arrays // We'll be using one-D arrays because C++ can't dynamically allocate 2D
int* calculateBlackPoints(unsigned char* luminances, int subWidth, int subHeight, // arrays
int width, int height); int* calculateBlackPoints(unsigned char* luminances,
void calculateThresholdForBlock(unsigned char* luminances, int subWidth, int subHeight, int subWidth,
int width, int height, int blackPoints[], Ref<BitMatrix> matrix); int subHeight,
void threshold8x8Block(unsigned char* luminances, int xoffset, int yoffset, int threshold, int width,
int stride, Ref<BitMatrix> matrix); int height);
void calculateThresholdForBlock(unsigned char* luminances,
int subWidth,
int subHeight,
int width,
int height,
int blackPoints[],
Ref<BitMatrix> const& matrix);
void threshold8x8Block(unsigned char* luminances,
int xoffset,
int yoffset,
int threshold,
int stride,
Ref<BitMatrix> const& matrix);
}; };
} }
#endif /* GLOBALHISTOGRAMBINARIZER_H_ */ #endif