Working on containers (List, Map)
This commit is contained in:
parent
b93e358f5b
commit
b1ecfb0fed
|
@ -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);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user