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:
parent
1c7c01a1b3
commit
848b9af52d
@ -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
280
src/pdf/SkTSet.h
Normal 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
125
tests/TSetTest.cpp
Normal 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)
|
||||
|
Loading…
Reference in New Issue
Block a user