#include "MultiSet.h" #pragma warning (disable : 4996) // Homework 2 // Zad 1 // Vasilena Stanoyska // fn: 4MI0600290 // Big 4 MultiSet::MultiSet() { N = 0; bucketsCount = 0; maxNumOccurencesInBucket = 0; maxBitsCount = 0; buckets = nullptr; } MultiSet::MultiSet(unsigned N, unsigned maxBitsCount) { if (maxBitsCount < GlobalConstants::MIN_BITS_COUNT || maxBitsCount > GlobalConstants::MAX_BITS_IN_BUCKET) { maxBitsCount = GlobalConstants::DEFAULT_BITS_COUNT_VALUE; } this->N = N; this->maxBitsCount = maxBitsCount; maxNumOccurencesInBucket = std::pow(2, maxBitsCount) - 1; int totalBitsNeeded = N * maxBitsCount; bucketsCount = (totalBitsNeeded + (GlobalConstants::MAX_BITS_IN_BUCKET - 1)) / GlobalConstants::MAX_BITS_IN_BUCKET; buckets = new uint8_t[bucketsCount]{ 0 }; } MultiSet::MultiSet(const MultiSet& other) { copyFrom(other); } MultiSet& MultiSet::operator=(const MultiSet& other) { if (this != &other;) { free(); copyFrom(other); } return *this; } MultiSet::~MultiSet() { free(); } void MultiSet::copyFrom(const MultiSet& other) { buckets = new uint8_t[other.bucketsCount]; bucketsCount = other.bucketsCount; for (int i = 0; i < bucketsCount; i++) buckets[i] = other.buckets[i]; maxNumOccurencesInBucket = other.maxNumOccurencesInBucket; N = other.N; } void MultiSet::free() { delete[] buckets; buckets = nullptr; bucketsCount = 0; maxNumOccurencesInBucket = 0; N = 0; } // Additional functions unsigned MultiSet::getBucketIndex(unsigned number) const { return (number * maxBitsCount) / GlobalConstants::MAX_BITS_IN_BUCKET; } unsigned MultiSet::getEndIndexInBucket(unsigned number) const { return ((number * maxBitsCount) % GlobalConstants::MAX_BITS_IN_BUCKET); } unsigned MultiSet::getStartIndexInBucket(unsigned endIndexInBucket) const { return endIndexInBucket - (maxBitsCount - 1); } unsigned MultiSet::getNumberOccurences(unsigned number) const { if (number > N) { throw std::out_of_range("Number is out of the valid range!"); } int bucketIndex = getBucketIndex(number); int endIndexInBucket; int startIndexInBucket; if (number == 0) { endIndexInBucket = maxBitsCount - 1; startIndexInBucket = 1; } else { endIndexInBucket = getEndIndexInBucket(number); startIndexInBucket = getStartIndexInBucket(endIndexInBucket); } // Reasigning the startIndex when our number's bits are in two buckets if (startIndexInBucket <= 0) { startIndexInBucket += GlobalConstants::MAX_BITS_IN_BUCKET; bucketIndex -= 1; // This adjusts the bucket index when bits are split across two buckets } // Calculating carry - the amount of bits that go into the next bucket int carry = (startIndexInBucket + maxBitsCount - 1) - GlobalConstants::MAX_BITS_IN_BUCKET; unsigned occurences = 0; if (carry > 0) { // Case when we need to count the num occurences splitted in 2 buckets int countOfBitsInFirstBucket = maxBitsCount - carry; int firstBucketMask = (1 << countOfBitsInFirstBucket) - 1; firstBucketMask <<= (startIndexInBucket - 1); int firstBucketValue = (buckets[bucketIndex] & firstBucketMask) >> (startIndexInBucket - 1); int secondBucketMask = (1 << carry) - 1; int sec + 1] & secondBucketMask; secondBucketValue <<= (maxBitsCount - carry); occurences = secondBucketValue | firstBucketValue; } else { // Default case (only working in one bucket) int mask = maxNumOccurencesInBucket; mask <<= (startIndexInBucket - 1); occurences = (buckets[bucketIndex] & mask) >> (startIndexInBucket - 1); } return occurences; } void MultiSet::addToMultiSet(unsigned number, unsigned times) { if (number > N) { throw std::out_of_range("Number is out of the valid range!"); } int currentNumOccurences = getNumberOccurences(number); if (currentNumOccurences + times >= maxNumOccurencesInBucket) times = maxNumOccurencesInBucket - currentNumOccurences; int bucketIndex = getBucketIndex(number); int endIndexInBucket; int startIndexInBucket; if (number == 0) { endIndexInBucket = maxBitsCount - 1; startIndexInBucket = 1; } else { endIndexInBucket = getEndIndexInBucket(number); startIndexInBucket = getStartIndexInBucket(endIndexInBucket); } // Reasigning the startIndex when our number's bits are in two buckets if (startIndexInBucket <= 0) { startIndexInBucket += GlobalConstants::MAX_BITS_IN_BUCKET; bucketIndex -= 1; } // Calculating carry - the amount of bits that go into the next bucket int carry = (startIndexInBucket + maxBitsCount - 1) - GlobalConstants::MAX_BITS_IN_BUCKET + 1; if (carry > 0) { // Case when the bits are splitted in 2 buckets int firstBucketMask = (1 << (GlobalConstants::MAX_BITS_IN_BUCKET - (startIndexInBucket - 1))) - 1; int firstBucketValue = (buckets[bucketIndex] >> (startIndexInBucket - 1)) & firstBucketMask; int secondBucketMask = (1 << carry) - 1; int sec + 1] & secondBucketMask; int newValue = firstBucketValue + times; if (newValue >= (1 << (GlobalConstants::MAX_BITS_IN_BUCKET - (startIndexInBucket - 1)))) { newValue -= (1 << (GlobalConstants::MAX_BITS_IN_BUCKET - (startIndexInBucket - 1))); secondBucketValue++; // Going to the next bucket } buckets[bucketIndex] &= ~(firstBucketMask << (startIndexInBucket - 1)); newValue <<= (startIndexInBucket - 1); buckets[bucketIndex] |= newValue; buckets[bucketIndex + 1] &= ~secondBucketMask; buckets[bucketIndex + 1] |= secondBucketValue; } else { // Default case (bits are only in 1 bucket) int mask = maxNumOccurencesInBucket; int currentValue = (buckets[bucketIndex] >> (startIndexInBucket - 1)) & mask; currentValue += times; // Keeping the same value if it exceeds the maximum number of occurrences if (currentValue >= maxNumOccurencesInBucket) { currentValue--; } buckets[bucketIndex] &= ~(mask << (startIndexInBucket - 1)); currentValue <<= (startIndexInBucket - 1); buckets[bucketIndex] |= currentValue; } } void MultiSet::printMultiSet() const { std::cout << '{' << std::endl; for (int i = 0; i <= N; i++) { int bucketIndex = getBucketIndex(i); int occurencesOfI = getNumberOccurences(i); if (occurencesOfI != 0) { std::cout << "The number " << i << " is in bucket " << bucketIndex << " and appears " << occurencesOfI << " times" << std::endl; } } std::cout << '}' << std::endl; } void MultiSet::printMultiSetBits() const { std::cout << "MultiSet Memory Representation: " << std::endl; for (unsigned i = 0; i < bucketsCount; ++i) { std::cout << "Bucket " << i << ": "; uint8_t bucket = buckets[i]; for (int bit = 7; bit >= 0; bit--) { std::cout << ((bucket >> bit) & 1) << " "; // Shift and mask to get each bit } std::cout << std::endl; } std::cout << std::endl; } void MultiSet::serializeInBinaryFile(const char* fileName) { std::ofstream file(fileName, std::ios::binary | std::ios::out); if (!file.is_open()) throw std::runtime_error("Failed to open file to write to!"); file.write((const char*)&N, sizeof(N)); file.write((const char*)&maxBitsCount;, sizeof(maxBitsCount)); file.write((const char*)buckets, bucketsCount * sizeof(uint8_t)); } MultiSet deserializeFromBinaryFile(const char* fileName) { std::ifstream file(fileName, std::ios::binary | std::ios::in); if (!file.is_open()) throw std::runtime_error("Failed to open file to write to!"); unsigned newN; unsigned newMaxBitsCount; file.read((char*)&newN;, sizeof(newN)); file.read((char*)&newMaxBitsCount;, sizeof(newMaxBitsCount)); MultiSet deserializedSet(newN, newMaxBitsCount); file.read((char*)deserializedSet.buckets, deserializedSet.bucketsCount * sizeof(uint8_t)); std::cout << "DESERIALIZED: " << std::endl; deserializedSet.printMultiSet(); return deserializedSet; } MultiSet operator^(const MultiSet& set1, const MultiSet& set2) { int resultSize = std::min(set1.N, set2.N); int resultBitsCount = std::min(set1.maxBitsCount, set2.maxBitsCount); MultiSet resultMultiSet(resultSize, resultBitsCount); for (int i = 0; i <= resultMultiSet.N; i++) { int occurencesInSet1 = set1.getNumberOccurences(i); int occurencesInSet2 = set2.getNumberOccurences(i); if (occurencesInSet1 > 0 && occurencesInSet2 > 0) { int minOccurencesCount = std::min(occurencesInSet1, occurencesInSet2); resultMultiSet.addToMultiSet(i, minOccurencesCount); } } return resultMultiSet; } MultiSet operator/(const MultiSet& set1, const MultiSet& set2) { int resultSize = set1.N; int resultBitsCount = set1.maxBitsCount; MultiSet resultMultiSet(resultSize, resultBitsCount); for (int i = 0; i <= resultSize; i++) { int occurencesInSet1 = set1.getNumberOccurences(i); int occurencesInSet2 = set2.getNumberOccurences(i); if (occurencesInSet1 > occurencesInSet2) { int occurencesToAdd = occurencesInSet1 - occurencesInSet2; resultMultiSet.addToMultiSet(i, occurencesToAdd); } } return resultMultiSet; } MultiSet operator!(const MultiSet& set) { MultiSet resultMultiSet(set.N, set.maxBitsCount); for (int i = 0; i < resultMultiSet.bucketsCount; i++) { resultMultiSet.buckets[i] = ~set.buckets[i]; } return resultMultiSet; } int main() { MultiSet multiset1(11, 3); MultiSet multiset2(15, 5); MultiSet deserializedSet; try { //multiset1.addToMultiSet(0, 1); multiset1.addToMultiSet(1, 1); multiset1.addToMultiSet(2, 2); multiset1.addToMultiSet(11, 4); multiset2.addToMultiSet(1, 2); multiset2.addToMultiSet(2, 1); multiset2.addToMultiSet(5, 3); multiset2.addToMultiSet(11, 3); //multiset1.serializeInBinaryFile("multiset.txt"); deserializedSet = deserializeFromBinaryFile("multiset.txt"); } catch (const std::out_of_range& e) { std::cerr << "Exception caught: " << e.what() << std::endl; } catch (const std::runtime_error& e) { std::cerr << "An error occured: " << e.what() << std::endl; } catch (const std::exception& e) { // To catch other types of exceptions std::cerr << "An exception occurred: " << e.what() << std::endl; } std::cout << "First Set: " << std::endl; multiset1.printMultiSet(); multiset1.printMultiSetBits(); std::cout << "Second Set: " << std::endl; multiset2.printMultiSet(); multiset2.printMultiSetBits(); std::cout << "Intersection: " << std::endl; MultiSet intersectSet = operator^(multiset1, multiset2); intersectSet.printMultiSet(); intersectSet.printMultiSetBits(); std::cout << "Difference: " << std::endl; MultiSet differenceSet = operator/(multiset1, multiset2); differenceSet.printMultiSet(); differenceSet.printMultiSetBits(); std::cout << "Complement set: " << std::endl; MultiSet complementSet = operator!(multiset1); complementSet.printMultiSet(); complementSet.printMultiSetBits(); std::cout << "Deserialized set: " << std::endl; deserializedSet.printMultiSet(); deserializedSet.printMultiSetBits(); }