Add a true Set class. Current use case is to be used with Pdf generator.

Review URL: https://codereview.appspot.com/6749054

git-svn-id: http://skia.googlecode.com/svn/trunk@7626 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
edisonn@google.com 2013-02-06 18:54:13 +00:00
parent 1c7c01a1b3
commit 848b9af52d
3 changed files with 406 additions and 0 deletions

View File

@ -100,6 +100,7 @@
'../tests/TestSize.cpp',
'../tests/TileGridTest.cpp',
'../tests/TLSTest.cpp',
'../tests/TSetTest.cpp',
'../tests/ToUnicode.cpp',
'../tests/UnicodeTest.cpp',
'../tests/UtilsTest.cpp',

280
src/pdf/SkTSet.h Normal file
View File

@ -0,0 +1,280 @@
/*
* Copyright 2012 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkTSet_DEFINED
#define SkTSet_DEFINED
#include "SkTDArray.h"
#include "SkTypes.h"
/** \class SkTSet<T>
The SkTSet template class defines a set.
Main operations supported now are: add, merge, find and contains.
TSet<T> is mutable.
*/
// TODO: Add remove, intersect and difference operations.
// TODO: Add bench tests.
template <typename T> class SK_API SkTSet {
public:
SkTSet() {
fArray = SkNEW(SkTDArray<T>);
}
~SkTSet() {
SkASSERT(fArray);
SkDELETE(fArray);
}
SkTSet(const SkTSet<T>& src) {
this->fArray = SkNEW_ARGS(SkTDArray<T>, (*src.fArray));
#ifdef SK_DEBUG
validate();
#endif
}
SkTSet<T>& operator=(const SkTSet<T>& src) {
*this->fArray = *src.fArray;
#ifdef SK_DEBUG
validate();
#endif
return *this;
}
/** Merges src elements into this, and returns the number of duplicates
* found.
*/
int mergeInto(const SkTSet<T>& src) {
SkASSERT(fArray);
int duplicates = 0;
SkTDArray<T>* fArrayNew = new SkTDArray<T>();
fArrayNew->setReserve(count() + src.count());
int i = 0;
int j = 0;
while (i < count() && j < src.count()) {
if ((*fArray)[i] < (*src.fArray)[j]) {
fArrayNew->push((*fArray)[i]);
i++;
} else if ((*fArray)[i] > (*src.fArray)[j]) {
fArrayNew->push((*src.fArray)[j]);
j++;
} else {
duplicates++;
j++; // Skip one of the duplicates.
}
}
while (i < count()) {
fArrayNew->push((*fArray)[i]);
i++;
}
while (j < src.count()) {
fArrayNew->push((*src.fArray)[j]);
j++;
}
SkDELETE(fArray);
fArray = fArrayNew;
fArrayNew = NULL;
#ifdef SK_DEBUG
validate();
#endif
return duplicates;
}
/** Adds a new element into set and returns true if the element is already
* in this set.
*/
bool add(const T& elem) {
SkASSERT(fArray);
int pos = 0;
int i = find(elem, &pos);
if (i >= 0) {
return false;
}
*fArray->insert(pos) = elem;
#ifdef SK_DEBUG
validate();
#endif
return true;
}
/** Returns true if this set is empty.
*/
bool isEmpty() const {
SkASSERT(fArray);
return fArray->isEmpty();
}
/** Return the number of elements in the set.
*/
int count() const {
SkASSERT(fArray);
return fArray->count();
}
/** Return the number of bytes in the set: count * sizeof(T).
*/
size_t bytes() const {
SkASSERT(fArray);
return fArray->bytes();
}
/** Return the beginning of a set iterator.
* Elements in the iterator will be sorted ascending.
*/
const T* begin() const {
SkASSERT(fArray);
return fArray->begin();
}
/** Return the end of a set iterator.
*/
const T* end() const {
SkASSERT(fArray);
return fArray->end();
}
const T& operator[](int index) const {
SkASSERT(fArray);
return (*fArray)[index];
}
/** Resets the set (deletes memory and initiates an empty set).
*/
void reset() {
SkASSERT(fArray);
fArray->reset();
}
/** Rewinds the set (preserves memory and initiates an empty set).
*/
void rewind() {
SkASSERT(fArray);
fArray->rewind();
}
/** Reserves memory for the set.
*/
void setReserve(size_t reserve) {
SkASSERT(fArray);
fArray->setReserve(reserve);
}
/** Returns the index where an element was found.
* Returns -1 if the element was not found, and it fills *posToInsertSorted
* with the index of the place where elem should be inserted to preserve the
* internal array sorted.
* If element was found, *posToInsertSorted is undefined.
*/
int find(const T& elem, int* posToInsertSorted = NULL) const {
SkASSERT(fArray);
if (fArray->count() == 0) {
if (posToInsertSorted) {
*posToInsertSorted = 0;
}
return -1;
}
int iMin = 0;
int iMax = fArray->count();
while (iMin < iMax - 1) {
int iMid = (iMin + iMax) / 2;
if (elem < (*fArray)[iMid]) {
iMax = iMid;
} else {
iMin = iMid;
}
}
if (elem == (*fArray)[iMin]) {
return iMin;
}
if (posToInsertSorted) {
if (elem < (*fArray)[iMin]) {
*posToInsertSorted = iMin;
} else {
*posToInsertSorted = iMin + 1;
}
}
return -1;
}
/** Returns true if the array contains this element.
*/
bool contains(const T& elem) const {
SkASSERT(fArray);
return (this->find(elem) >= 0);
}
/** Copies internal array to destination.
*/
void copy(T* dst) const {
SkASSERT(fArray);
fArray->copyRange(0, fArray->count(), dst);
}
/** Returns a const reference to the internal vector.
*/
const SkTDArray<T>& toArray() {
SkASSERT(fArray);
return *fArray;
}
/** Unref all elements in the set.
*/
void unrefAll() {
SkASSERT(fArray);
fArray->unrefAll();
}
/** safeUnref all elements in the set.
*/
void safeUnrefAll() {
SkASSERT(fArray);
fArray->safeUnrefAll();
}
#ifdef SK_DEBUG
void validate() const {
SkASSERT(fArray);
fArray->validate();
SkASSERT(isSorted() && !hasDuplicates());
}
bool hasDuplicates() const {
for (int i = 0; i < fArray->count() - 1; ++i) {
if ((*fArray)[i] == (*fArray)[i + 1]) {
return true;
}
}
return false;
}
bool isSorted() const {
for (int i = 0; i < fArray->count() - 1; ++i) {
// Use only < operator
if (!((*fArray)[i] < (*fArray)[i + 1])) {
return false;
}
}
return true;
}
#endif
private:
SkTDArray<T>* fArray;
};
#endif

125
tests/TSetTest.cpp Normal file
View File

@ -0,0 +1,125 @@
/*
* Copyright 2012 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "Test.h"
#include "SkTSet.h"
// Tests the SkTSet<T> class template.
// Functions that just call SkTDArray are not tested.
static void TestTSet_basic(skiatest::Reporter* reporter) {
SkTSet<int> set0;
REPORTER_ASSERT(reporter, set0.isEmpty());
REPORTER_ASSERT(reporter, !set0.contains(-1));
REPORTER_ASSERT(reporter, !set0.contains(0));
REPORTER_ASSERT(reporter, !set0.contains(1));
REPORTER_ASSERT(reporter, set0.count() == 0);
REPORTER_ASSERT(reporter, set0.add(0));
REPORTER_ASSERT(reporter, !set0.isEmpty());
REPORTER_ASSERT(reporter, !set0.contains(-1));
REPORTER_ASSERT(reporter, set0.contains(0));
REPORTER_ASSERT(reporter, !set0.contains(1));
REPORTER_ASSERT(reporter, set0.count() == 1);
REPORTER_ASSERT(reporter, !set0.add(0));
REPORTER_ASSERT(reporter, set0.count() == 1);
#ifdef SK_DEBUG
set0.validate();
#endif
}
#define COUNT 1732
#define PRIME1 10007
#define PRIME2 1733
// Generates a series of positive unique pseudo-random numbers.
static int f(int i) {
return (long(i) * PRIME1) % PRIME2;
}
// Will expose contains() and find() too.
static void TestTSet_advanced(skiatest::Reporter* reporter) {
SkTSet<int> set0;
for (int i = 0; i < COUNT; i++) {
REPORTER_ASSERT(reporter, !set0.contains(f(i)));
if (i > 0) {
REPORTER_ASSERT(reporter, set0.contains(f(0)));
REPORTER_ASSERT(reporter, set0.contains(f(i / 2)));
REPORTER_ASSERT(reporter, set0.contains(f(i - 1)));
}
REPORTER_ASSERT(reporter, !set0.contains(f(i)));
REPORTER_ASSERT(reporter, set0.count() == i);
REPORTER_ASSERT(reporter, set0.add(f(i)));
REPORTER_ASSERT(reporter, set0.contains(f(i)));
REPORTER_ASSERT(reporter, set0.count() == i + 1);
REPORTER_ASSERT(reporter, !set0.add(f(i)));
}
// Test copy constructor too.
SkTSet<int> set1 = set0;
REPORTER_ASSERT(reporter, set0.count() == set1.count());
REPORTER_ASSERT(reporter, !set1.contains(-1000));
for (int i = 0; i < COUNT; i++) {
REPORTER_ASSERT(reporter, set1.contains(f(i)));
}
// Test operator= too.
SkTSet<int> set2;
set2 = set0;
REPORTER_ASSERT(reporter, set0.count() == set2.count());
REPORTER_ASSERT(reporter, !set2.contains(-1000));
for (int i = 0; i < COUNT; i++) {
REPORTER_ASSERT(reporter, set2.contains(f(i)));
}
#ifdef SK_DEBUG
set0.validate();
set1.validate();
set2.validate();
#endif
}
static void TestTSet_merge(skiatest::Reporter* reporter) {
SkTSet<int> set;
SkTSet<int> setOdd;
for (int i = 0; i < COUNT; i++) {
REPORTER_ASSERT(reporter, set.add(2 * i));
REPORTER_ASSERT(reporter, setOdd.add(2 * i + 1));
}
// mergeInto returns the number of duplicates. Expected 0.
REPORTER_ASSERT(reporter, set.mergeInto(setOdd) == 0);
REPORTER_ASSERT(reporter, set.count() == 2 * COUNT);
// mergeInto should now find all new numbers duplicate.
REPORTER_ASSERT(reporter, set.mergeInto(setOdd) == setOdd.count());
REPORTER_ASSERT(reporter, set.count() == 2 * COUNT);
for (int i = 0; i < 2 * COUNT; i++) {
REPORTER_ASSERT(reporter, set.contains(i));
}
#ifdef SK_DEBUG
set.validate();
setOdd.validate();
#endif
}
static void TestTSet(skiatest::Reporter* reporter) {
TestTSet_basic(reporter);
TestTSet_advanced(reporter);
TestTSet_merge(reporter);
}
#include "TestClassDef.h"
DEFINE_TESTCLASS("TSet", TSetTest, TestTSet)