From b1ecfb0fedd601fc04e6a0a1d2d3fcda96687557 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Fri, 19 Jan 2018 07:55:55 +0100 Subject: [PATCH] Working on containers (List, Map) --- src/containers/List.h | 26 ++-- src/containers/Map.h | 219 ++++++++++++++++++++++++++++++- test/tests/containers/TestList.h | 43 +++++- test/tests/containers/TestMap.h | 55 +++++++- 4 files changed, 322 insertions(+), 21 deletions(-) diff --git a/src/containers/List.h b/src/containers/List.h index 6391d52b..93ec0830 100644 --- a/src/containers/List.h +++ b/src/containers/List.h @@ -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(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); + } }; } diff --git a/src/containers/Map.h b/src/containers/Map.h index 5510b98d..21eb9759 100644 --- a/src/containers/Map.h +++ b/src/containers/Map.h @@ -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; + using difference_type = std::ptrdiff_t; + using pointer = std::pair*; + using reference = std::pair&; + 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()(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,8 +631,23 @@ class Map { /// Overloaded equality operator bool operator==(const Map& map) const { - // TODO : Implement this - return false; + 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 @@ -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*>(mAllocator.allocate(sizeof(std::pair))); + new (mEntries[i].keyValue) std::pair(*(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= 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 diff --git a/test/tests/containers/TestList.h b/test/tests/containers/TestList.h index ba1fbf61..669b0bef 100644 --- a/test/tests/containers/TestList.h +++ b/test/tests/containers/TestList.h @@ -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 list1(mAllocator); + + test(list1.begin() == list1.end()); + + list1.add(5); + list1.add(6); + list1.add(8); + list1.add(-1); + + List::Iterator itBegin = list1.begin(); + List::Iterator itEnd = list1.end(); + List::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 list2(mAllocator); + for (auto it = list1.begin(); it != list1.end(); ++it) { + list2.add(*it); + } + test(list1 == list2); } }; diff --git a/test/tests/containers/TestMap.h b/test/tests/containers/TestMap.h index d7e084dc..a105fca8 100644 --- a/test/tests/containers/TestMap.h +++ b/test/tests/containers/TestMap.h @@ -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 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 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 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 map2(mAllocator); map2 = map1; test(map2.size() == map1.size()); @@ -299,7 +322,7 @@ class TestMap : public Test { Map map4(mAllocator); map3 = map4; test(map3.size() == 0); -*/ + Map 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 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::Iterator itBegin = map1.begin(); + Map::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); } };