Working on containers (List, Map)

This commit is contained in:
Daniel Chappuis 2018-01-19 07:55:55 +01:00
parent b93e358f5b
commit b1ecfb0fed
4 changed files with 322 additions and 21 deletions

View File

@ -57,9 +57,6 @@ class List {
/// Memory allocator /// Memory allocator
MemoryAllocator& mAllocator; MemoryAllocator& mAllocator;
// -------------------- Methods -------------------- //
public: public:
/// Class Iterator /// Class Iterator
@ -87,14 +84,14 @@ class List {
Iterator() = default; Iterator() = default;
/// Constructor /// Constructor
Iterator(T* buffer, size_t index, size_t size) Iterator(void* buffer, size_t index, size_t size)
:mCurrentIndex(index), mBuffer(buffer), mSize(size) { :mCurrentIndex(index), mBuffer(static_cast<T*>(buffer)), mSize(size) {
} }
/// Copy constructor /// Copy constructor
Iterator(const Iterator& it) Iterator(const Iterator& it)
:mCurrentIndex(it.mCurrentIndex), mBuffer(it.mBuffer), mSize(it.size) { :mCurrentIndex(it.mCurrentIndex), mBuffer(it.mBuffer), mSize(it.mSize) {
} }
@ -112,14 +109,14 @@ class List {
/// Post increment (it++) /// Post increment (it++)
Iterator& operator++() { Iterator& operator++() {
assert(mCurrentIndex < mSize - 1); assert(mCurrentIndex < mSize);
mCurrentIndex++; mCurrentIndex++;
return *this; return *this;
} }
/// Pre increment (++it) /// Pre increment (++it)
Iterator operator++(int number) { Iterator operator++(int number) {
assert(mCurrentIndex < mSize - 1); assert(mCurrentIndex < mSize);
Iterator tmp = *this; Iterator tmp = *this;
mCurrentIndex++; mCurrentIndex++;
return tmp; return tmp;
@ -149,13 +146,14 @@ class List {
return true; return true;
} }
return &(mBuffer[mCurrentIndex]) == &(iterator.mBuffer[mCurrentIndex]); return &(mBuffer[mCurrentIndex]) == &(iterator.mBuffer[iterator.mCurrentIndex]);
} }
/// Inequality operator (it != end()) /// Inequality operator (it != end())
bool operator!=(const Iterator& iterator) const { bool operator!=(const Iterator& iterator) const {
return !(*this == iterator); return !(*this == iterator);
} }
}; };
// -------------------- Methods -------------------- // // -------------------- Methods -------------------- //
@ -334,6 +332,16 @@ class List {
return *this; return *this;
} }
/// Return a begin iterator
Iterator begin() const {
return Iterator(mBuffer, 0, mSize);
}
/// Return a end iterator
Iterator end() const {
return Iterator(mBuffer, mSize, mSize);
}
}; };
} }

View File

@ -56,6 +56,13 @@ class Map {
keyValue = nullptr; keyValue = nullptr;
} }
/// Constructor
Entry(size_t hashcode, int nextValue) {
hashCode = hashcode;
next = nextValue;
keyValue = nullptr;
}
/// Destructor /// Destructor
~Entry() { ~Entry() {
@ -242,6 +249,129 @@ class Map {
public: public:
/// Class Iterator
/**
* This class represents an iterator for the Map
*/
class Iterator {
private:
/// Array of buckets
const int* mBuckets;
/// Array of entries
const Entry* mEntries;
/// Capacity of the map
int mCapacity;
/// Index of the current bucket
int mCurrentBucket;
/// Index of the current entry
int mCurrentEntry;
/// Advance the iterator
void advance() {
// If we are trying to move past the end
assert(mCurrentBucket < mCapacity);
// If we are at the last entry for the current bucket
if (mEntries[mCurrentEntry].next == -1) {
// Find the next occupied bucket
for (int b = mCurrentBucket + 1; mBuckets[b] > 0 || b == mCapacity; b++) {
mCurrentBucket = b;
// If we have reached the end of the map
if (mCurrentBucket == mCapacity) {
mCurrentEntry = mCapacity;
return;
}
mCurrentEntry = mBuckets[mCurrentBucket];
assert(mCurrentEntry != -1);
}
}
else {
// Move to the next entry in the current bucket
mCurrentEntry = mEntries[mCurrentEntry].next;
assert(mEntries[mCurrentEntry].keyValue != nullptr);
}
}
public:
// Iterator traits
using value_type = std::pair<K,V>;
using difference_type = std::ptrdiff_t;
using pointer = std::pair<K, V>*;
using reference = std::pair<K,V>&;
using iterator_category = std::forward_iterator_tag;
/// Constructor
Iterator() = default;
/// Constructor
Iterator(const int* buckets, const Entry* entries, int capacity, int currentBucket, int currentEntry)
:mBuckets(buckets), mEntries(entries), mCapacity(capacity), mCurrentBucket(currentBucket), mCurrentEntry(currentEntry) {
}
/// Copy constructor
Iterator(const Iterator& it)
:mBuckets(it.mBuckets), mEntries(it.mEntries), mCapacity(it.mCapacity), mCurrentBucket(it.mCurrentBucket), mCurrentEntry(it.mCurrentEntry) {
}
/// Deferencable
reference operator*() const {
assert(mCurrentBucket >= 0 && mCurrentBucket < mCapacity);
assert (mCurrentEntry != -1);
assert(mEntries[mCurrentEntry].keyValue != nullptr);
return mEntries[mCurrentEntry].keyValue;
}
/// Deferencable
pointer operator->() const {
assert(mCurrentBucket >= 0 && mCurrentBucket < mCapacity);
assert (mCurrentEntry != -1);
assert(mEntries[mCurrentEntry].keyValue != nullptr);
return mEntries[mCurrentEntry].keyValue;
}
/// Post increment (it++)
Iterator& operator++() {
advance();
return *this;
}
/// Pre increment (++it)
Iterator operator++(int number) {
Iterator tmp = *this;
advance();
return tmp;
}
/// Equality operator (it == end())
bool operator==(const Iterator& iterator) const {
return mBuckets == iterator.mBuckets &&
mEntries == iterator.mEntries &&
mCurrentBucket == iterator.mCurrentBucket &&
mCurrentEntry == iterator.mCurrentEntry;
}
/// Inequality operator (it != end())
bool operator!=(const Iterator& iterator) const {
return !(*this == iterator);
}
};
// -------------------- Methods -------------------- // // -------------------- Methods -------------------- //
/// Constructor /// Constructor
@ -434,6 +564,36 @@ class Map {
return mCapacity; return mCapacity;
} }
/// Try to find an item of the map given a key.
/// The method returns an iterator to the found item or
/// an iterator pointing to the end if not found
Iterator find(const K& key) const {
int bucket;
int entry = -1;
if (mCapacity > 0) {
size_t hashCode = std::hash<K>()(key);
bucket = hashCode % mCapacity;
for (int i = mBuckets[bucket]; i >= 0; i = mEntries[i].next) {
if (mEntries[i].hashCode == hashCode && mEntries[i].keyValue->first == key) {
entry = i;
break;
}
}
}
if (entry == -1) {
return end();
}
assert(mEntries[entry].keyValue != nullptr);
return Iterator(mBuckets, mEntries, mCapacity, bucket, entry);
}
/// Overloaded index operator /// Overloaded index operator
V& operator[](const K& key) { V& operator[](const K& key) {
@ -471,8 +631,23 @@ class Map {
/// Overloaded equality operator /// Overloaded equality operator
bool operator==(const Map<K,V>& map) const { bool operator==(const Map<K,V>& map) const {
// TODO : Implement this if (size() != map.size()) return false;
return false;
for (auto it = begin(); it != end(); ++it) {
auto it2 = map.find(it->first);
if (it2 == map.end() || it2->second != it->second) {
return false;
}
}
for (auto it = map.begin(); it != map.end(); ++it) {
auto it2 = find(it->first);
if (it2 == end() || it2->second != it->second) {
return false;
}
}
return true;
} }
/// Overloaded not equal operator /// Overloaded not equal operator
@ -505,7 +680,15 @@ class Map {
std::memcpy(mBuckets, map.mBuckets, mCapacity * sizeof(int)); std::memcpy(mBuckets, map.mBuckets, mCapacity * sizeof(int));
// Copy the entries // Copy the entries
std::memcpy(mEntries, map.mEntries, mCapacity * sizeof(Entry)); for (int i=0; i < mCapacity; i++) {
new (&mEntries[i]) Entry(map.mEntries[i].hashCode, map.mEntries[i].next);
if (map.mEntries[i].keyValue != nullptr) {
mEntries[i].keyValue = static_cast<std::pair<K,V>*>(mAllocator.allocate(sizeof(std::pair<K, V>)));
new (mEntries[i].keyValue) std::pair<K,V>(*(map.mEntries[i].keyValue));
}
}
mNbUsedEntries = map.mNbUsedEntries; mNbUsedEntries = map.mNbUsedEntries;
mNbFreeEntries = map.mNbFreeEntries; mNbFreeEntries = map.mNbFreeEntries;
@ -515,6 +698,36 @@ class Map {
return *this; return *this;
} }
/// Return a begin iterator
Iterator begin() const {
// If the map is empty
if (size() == 0) {
// Return an iterator to the end
return end();
}
int bucket = -1;
// Find the first used bucket
for (int i=0; i<mCapacity; i++) {
if (mBuckets[i] >= 0) {
bucket = i;
break;
}
}
assert(bucket >= 0);
return Iterator(mBuckets, mEntries, mCapacity, bucket, mBuckets[bucket]);
}
/// Return a end iterator
Iterator end() const {
return Iterator(mBuckets, mEntries, mCapacity, mCapacity, mCapacity);
}
}; };
template<typename K, typename V> template<typename K, typename V>

View File

@ -64,7 +64,7 @@ class TestList : public Test {
testIndexing(); testIndexing();
testEquality(); testEquality();
testReserve(); testReserve();
testIteration(); testIterators();
} }
void testConstructors() { void testConstructors() {
@ -320,8 +320,45 @@ class TestList : public Test {
test(list1[1] == 2); test(list1[1] == 2);
} }
void testIteration() { void testIterators() {
// TODO : Implement this
List<int> list1(mAllocator);
test(list1.begin() == list1.end());
list1.add(5);
list1.add(6);
list1.add(8);
list1.add(-1);
List<int>::Iterator itBegin = list1.begin();
List<int>::Iterator itEnd = list1.end();
List<int>::Iterator it = list1.begin();
test(itBegin == it);
test(*it == 5);
test(*(it++) == 5);
test(*it == 6);
test(*(it--) == 6);
test(*it == 5);
test(*(++it) == 6);
test(*it == 6);
test(*(--it) == 5);
test(*it == 5);
test(it == itBegin);
it = list1.end();
test(it == itEnd);
it--;
test(*it == -1);
it++;
test(it == itEnd);
List<int> list2(mAllocator);
for (auto it = list1.begin(); it != list1.end(); ++it) {
list2.add(*it);
}
test(list1 == list2);
} }
}; };

View File

@ -62,10 +62,11 @@ class TestMap : public Test {
testReserve(); testReserve();
testAddRemoveClear(); testAddRemoveClear();
testContainsKey(); testContainsKey();
testFind();
testIndexing(); testIndexing();
testEquality(); testEquality();
testAssignment(); testAssignment();
testIteration(); testIterators();
} }
void testConstructors() { void testConstructors() {
@ -122,6 +123,8 @@ class TestMap : public Test {
void testAddRemoveClear() { void testAddRemoveClear() {
// TODO : ADD test with values with same hash for keys but different keys
// ----- Test add() ----- // // ----- Test add() ----- //
Map<int, int> map1(mAllocator); Map<int, int> map1(mAllocator);
@ -157,8 +160,8 @@ class TestMap : public Test {
test(map1.size() == 2); test(map1.size() == 2);
map1.remove(13); map1.remove(13);
test(!map1.containsKey(8)); test(map1.containsKey(8));
test(map1.containsKey(13)); test(!map1.containsKey(13));
test(map1.size() == 1); test(map1.size() == 1);
map1.remove(8); map1.remove(8);
@ -245,6 +248,26 @@ class TestMap : public Test {
test(map1[6] == 30); test(map1[6] == 30);
} }
void testFind() {
Map<int, int> map1(mAllocator);
map1.add(std::make_pair(2, 20));
map1.add(std::make_pair(4, 40));
map1.add(std::make_pair(6, 60));
test(map1.find(2)->second == 20);
test(map1.find(4)->second == 40);
test(map1.find(6)->second == 60);
test(map1.find(45) == map1.end());
map1[2] = 10;
map1[4] = 20;
map1[6] = 30;
test(map1.find(2)->second == 10);
test(map1.find(4)->second == 20);
test(map1.find(6)->second == 30);
}
void testEquality() { void testEquality() {
Map<std::string, int> map1(mAllocator, 10); Map<std::string, int> map1(mAllocator, 10);
@ -281,7 +304,7 @@ class TestMap : public Test {
map1.add(std::make_pair(1, 3)); map1.add(std::make_pair(1, 3));
map1.add(std::make_pair(2, 6)); map1.add(std::make_pair(2, 6));
map1.add(std::make_pair(10, 30)); map1.add(std::make_pair(10, 30));
/*
Map<int, int> map2(mAllocator); Map<int, int> map2(mAllocator);
map2 = map1; map2 = map1;
test(map2.size() == map1.size()); test(map2.size() == map1.size());
@ -299,7 +322,7 @@ class TestMap : public Test {
Map<int, int> map4(mAllocator); Map<int, int> map4(mAllocator);
map3 = map4; map3 = map4;
test(map3.size() == 0); test(map3.size() == 0);
*/
Map<int, int> map5(mAllocator); Map<int, int> map5(mAllocator);
map5.add(std::make_pair(7, 8)); map5.add(std::make_pair(7, 8));
map5.add(std::make_pair(19, 70)); map5.add(std::make_pair(19, 70));
@ -309,8 +332,28 @@ class TestMap : public Test {
test(map1[19] == 70); test(map1[19] == 70);
} }
void testIteration() { void testIterators() {
Map<int, int> map1(mAllocator);
test(map1.begin() == map1.end());
map1.add(std::make_pair(1, 5));
map1.add(std::make_pair(2, 6));
map1.add(std::make_pair(3, 8));
map1.add(std::make_pair(4, -1));
Map<int, int>::Iterator itBegin = map1.begin();
Map<int, int>::Iterator it = map1.begin();
test(itBegin == it);
int size = 0;
for (auto it = map1.begin(); it != map1.end(); ++it) {
test(map1.containsKey(it->first));
size++;
}
test(map1.size() == size);
} }
}; };