Working on containers (List, Map)
This commit is contained in:
parent
b93e358f5b
commit
b1ecfb0fed
|
@ -57,9 +57,6 @@ class List {
|
|||
/// Memory allocator
|
||||
MemoryAllocator& mAllocator;
|
||||
|
||||
// -------------------- Methods -------------------- //
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/// Class Iterator
|
||||
|
@ -87,14 +84,14 @@ class List {
|
|||
Iterator() = default;
|
||||
|
||||
/// Constructor
|
||||
Iterator(T* buffer, size_t index, size_t size)
|
||||
:mCurrentIndex(index), mBuffer(buffer), mSize(size) {
|
||||
Iterator(void* buffer, size_t index, size_t size)
|
||||
:mCurrentIndex(index), mBuffer(static_cast<T*>(buffer)), mSize(size) {
|
||||
|
||||
}
|
||||
|
||||
/// Copy constructor
|
||||
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++)
|
||||
Iterator& operator++() {
|
||||
assert(mCurrentIndex < mSize - 1);
|
||||
assert(mCurrentIndex < mSize);
|
||||
mCurrentIndex++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Pre increment (++it)
|
||||
Iterator operator++(int number) {
|
||||
assert(mCurrentIndex < mSize - 1);
|
||||
assert(mCurrentIndex < mSize);
|
||||
Iterator tmp = *this;
|
||||
mCurrentIndex++;
|
||||
return tmp;
|
||||
|
@ -149,13 +146,14 @@ class List {
|
|||
return true;
|
||||
}
|
||||
|
||||
return &(mBuffer[mCurrentIndex]) == &(iterator.mBuffer[mCurrentIndex]);
|
||||
return &(mBuffer[mCurrentIndex]) == &(iterator.mBuffer[iterator.mCurrentIndex]);
|
||||
}
|
||||
|
||||
/// Inequality operator (it != end())
|
||||
bool operator!=(const Iterator& iterator) const {
|
||||
return !(*this == iterator);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// -------------------- Methods -------------------- //
|
||||
|
@ -334,6 +332,16 @@ class List {
|
|||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -56,6 +56,13 @@ class Map {
|
|||
keyValue = nullptr;
|
||||
}
|
||||
|
||||
/// Constructor
|
||||
Entry(size_t hashcode, int nextValue) {
|
||||
hashCode = hashcode;
|
||||
next = nextValue;
|
||||
keyValue = nullptr;
|
||||
}
|
||||
|
||||
/// Destructor
|
||||
~Entry() {
|
||||
|
||||
|
@ -242,6 +249,129 @@ class Map {
|
|||
|
||||
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 -------------------- //
|
||||
|
||||
/// Constructor
|
||||
|
@ -434,6 +564,36 @@ class Map {
|
|||
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
|
||||
V& operator[](const K& key) {
|
||||
|
||||
|
@ -471,9 +631,24 @@ class Map {
|
|||
/// Overloaded equality operator
|
||||
bool operator==(const Map<K,V>& map) const {
|
||||
|
||||
// TODO : Implement this
|
||||
if (size() != map.size()) 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
|
||||
bool operator!=(const Map<K,V>& map) const {
|
||||
|
@ -505,7 +680,15 @@ class Map {
|
|||
std::memcpy(mBuckets, map.mBuckets, mCapacity * sizeof(int));
|
||||
|
||||
// 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;
|
||||
mNbFreeEntries = map.mNbFreeEntries;
|
||||
|
@ -515,6 +698,36 @@ class Map {
|
|||
|
||||
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>
|
||||
|
|
|
@ -64,7 +64,7 @@ class TestList : public Test {
|
|||
testIndexing();
|
||||
testEquality();
|
||||
testReserve();
|
||||
testIteration();
|
||||
testIterators();
|
||||
}
|
||||
|
||||
void testConstructors() {
|
||||
|
@ -320,8 +320,45 @@ class TestList : public Test {
|
|||
test(list1[1] == 2);
|
||||
}
|
||||
|
||||
void testIteration() {
|
||||
// TODO : Implement this
|
||||
void testIterators() {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -62,10 +62,11 @@ class TestMap : public Test {
|
|||
testReserve();
|
||||
testAddRemoveClear();
|
||||
testContainsKey();
|
||||
testFind();
|
||||
testIndexing();
|
||||
testEquality();
|
||||
testAssignment();
|
||||
testIteration();
|
||||
testIterators();
|
||||
}
|
||||
|
||||
void testConstructors() {
|
||||
|
@ -122,6 +123,8 @@ class TestMap : public Test {
|
|||
|
||||
void testAddRemoveClear() {
|
||||
|
||||
// TODO : ADD test with values with same hash for keys but different keys
|
||||
|
||||
// ----- Test add() ----- //
|
||||
|
||||
Map<int, int> map1(mAllocator);
|
||||
|
@ -157,8 +160,8 @@ class TestMap : public Test {
|
|||
test(map1.size() == 2);
|
||||
|
||||
map1.remove(13);
|
||||
test(!map1.containsKey(8));
|
||||
test(map1.containsKey(13));
|
||||
test(map1.containsKey(8));
|
||||
test(!map1.containsKey(13));
|
||||
test(map1.size() == 1);
|
||||
|
||||
map1.remove(8);
|
||||
|
@ -245,6 +248,26 @@ class TestMap : public Test {
|
|||
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() {
|
||||
|
||||
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(2, 6));
|
||||
map1.add(std::make_pair(10, 30));
|
||||
/*
|
||||
|
||||
Map<int, int> map2(mAllocator);
|
||||
map2 = map1;
|
||||
test(map2.size() == map1.size());
|
||||
|
@ -299,7 +322,7 @@ class TestMap : public Test {
|
|||
Map<int, int> map4(mAllocator);
|
||||
map3 = map4;
|
||||
test(map3.size() == 0);
|
||||
*/
|
||||
|
||||
Map<int, int> map5(mAllocator);
|
||||
map5.add(std::make_pair(7, 8));
|
||||
map5.add(std::make_pair(19, 70));
|
||||
|
@ -309,8 +332,28 @@ class TestMap : public Test {
|
|||
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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user