// PrimaryIndex.cpp // CSI 2131 Asst 2b by Naim R. El-Far (naim@discover.uottawa.ca) // CSI 2131 - Winter 2006 - Prof. L.M. Moura // File: PrimaryIndex.cpp // Desc: Class PrimaryIndex definitions #include #include #include #include #include #include "PrimaryIndex.h" using namespace std; PrimaryIndex::PrimaryIndex() { //Default constructor: Initializes data members to default values indexFileName = ""; indexFileStream; numberOfRecordsInIndex = 0; } PrimaryIndex::PrimaryIndex(string fileName) { //Filename constructor: Attach the file stream to the specified file indexFileName = fileName; indexFileStream.open(indexFileName.c_str(), ios::out); indexFileStream.close(); indexFileStream.open(indexFileName.c_str(), ios::in | ios::out | ios::binary); if (!indexFileStream) { cerr << endl << "------------------------------------------------" << endl << "Error! Specified index file could not be opened!" << endl << "------------------------------------------------" << endl << endl; exit(1); } else cout << "Index file " << fileName << " opened successfully." << endl << endl; numberOfRecordsInIndex = 0; } PrimaryIndex::~PrimaryIndex() { //Destructor indexFileStream.close(); } void PrimaryIndex::Addition(string studentNumber, long int byteOffset) { //Given a student number and the corresponding record's offset in the data file, add the tuple (studentNumber, offsetInDataFile) to the index file //Housekeeping //------------ int givenStudentNumberInt = atoi(studentNumber.c_str()); //Insert sorted by student number //------------------------------- indexFileStream.clear(); if (numberOfRecordsInIndex == 0) { //First record in the index indexFileStream.seekp(0); Insert(studentNumber, byteOffset); numberOfRecordsInIndex++; } else { bool foundWhereToInsert = false; long int currentRecordNumber = numberOfRecordsInIndex - 1; while (!foundWhereToInsert) { string currentStudentNumberStr = ""; long int currentOffset = 0; ReadByRRN(currentRecordNumber, currentStudentNumberStr, currentOffset); int currentStudentNumberInt = atoi(currentStudentNumberStr.c_str()); if (currentRecordNumber == -1) //Insert at the beginning foundWhereToInsert = true; if (givenStudentNumberInt < currentStudentNumberInt) currentRecordNumber--; else foundWhereToInsert = true; } long int insertAt = currentRecordNumber + 1; ShiftIndexRecords(insertAt); WriteByRRN(insertAt, studentNumber, byteOffset); numberOfRecordsInIndex++; } indexFileStream.close(); indexFileStream.open(indexFileName.c_str(), ios::in | ios::out | ios::binary); } long int PrimaryIndex::BinarySearch(string givenStudentNumber) { //Given a student number, search for it in the index long int entryPoint = indexFileStream.tellg(); indexFileStream.clear(); long int low = 0; //Lower bound of the binary search long int high = numberOfRecordsInIndex - 1; //Higher bound of the binary search int givenStudentNumberInt = atoi(givenStudentNumber.c_str()); //Holds the given student number as an int string retrievedStudentNumberString = ""; //Holds the student number retrieved from the index as a string int retrievedStudentNumberInt = -1; //Holds the student number retrieved from the index as an int long int retrievedOffset = -1; //Hold the record offset retrieved fromt he index while (low <= high) { long int guess = (high + low) / 2; ReadByRRN(guess, retrievedStudentNumberString, retrievedOffset); retrievedStudentNumberInt = atoi(retrievedStudentNumberString.c_str()); if (retrievedStudentNumberInt == givenStudentNumberInt) { indexFileStream.clear(); indexFileStream.seekg(entryPoint); return retrievedOffset; //Found } else if (retrievedStudentNumberInt > givenStudentNumberInt) high = guess - 1; else //if (retrievedStudentNumberInt < givenStudentNumberInt) low = guess + 1; } indexFileStream.clear(); indexFileStream.seekg(entryPoint); return -1; //If we reach this point, then no matching record was found } void PrimaryIndex::Insert(string studentNumber, long int byteOffset) { //Assuming the file pointer is where it should be to insert the record sorted into the index, insert the student number and byte offset information into the index //Write student number in text mode indexFileStream << studentNumber; //Write offset in binary mode after converting from decimal to binary number indexFileStream.write((char const*)(&byteOffset), 4); } long int PrimaryIndex::GetFilePointerPosition() { //This function simply return the position of the file pointer but we are using it here because tellg does not have a defined overloaded operator == or !=, so we can't do if (filepointer == ....tellg()). This is why we have this function here return indexFileStream.tellg(); } void PrimaryIndex::ReadByRRN(long int RRN, string& studentNumber, long int& offset) { long int entryOffset = indexFileStream.tellg(); indexFileStream.clear(); indexFileStream.seekg(RRN * PRIM_INDEX_RECORD_SIZE); char studentNumberChar[7]; indexFileStream.read(studentNumberChar, 7); indexFileStream.read((char*)(&offset), 4); studentNumber = ""; for (int i = 0 ; i < 7 ; i++) studentNumber = studentNumber + studentNumberChar[i]; indexFileStream.clear(); indexFileStream.seekg(entryOffset); } void PrimaryIndex::WriteByRRN(long int RRN, string studentNumber, long int offset) { long int entryOffset = indexFileStream.tellg(); indexFileStream.clear(); indexFileStream.seekp(RRN * PRIM_INDEX_RECORD_SIZE); Insert(studentNumber, offset); indexFileStream.clear(); indexFileStream.seekg(entryOffset); } void PrimaryIndex::ShiftIndexRecords(long int startingRRN) { long int entryOffset = indexFileStream.tellg(); indexFileStream.clear(); long int currentRRN = numberOfRecordsInIndex - 1; bool done = false; while (!done) { if (startingRRN > currentRRN) done = true; //No shifting necessary if inserting at the end else { string tempStudentNumber = ""; long int tempOffset = 0; ReadByRRN(currentRRN, tempStudentNumber, tempOffset); WriteByRRN(currentRRN + 1, tempStudentNumber, tempOffset); currentRRN--; if (currentRRN == startingRRN - 1) done = true; } } indexFileStream.clear(); indexFileStream.seekg(entryOffset); } void PrimaryIndex::PrintIndex(ostream& str) { str << setw(7) << setiosflags(ios::left) << "Number" << '\t' << setw(10) << setiosflags(ios::left) << "Offset" << endl << setw(7) << setiosflags(ios::left) << "------" << '\t' << setw(10) << setiosflags(ios::left) << "------" << endl; string studentNumber = ""; long int offset = -1; for (int i = 0 ; i < numberOfRecordsInIndex ; i++) { ReadByRRN(i, studentNumber, offset); str << setw(7) << setiosflags(ios::left) << studentNumber << '\t' << setw(10) << setiosflags(ios::left) << offset << endl; } str << "--END OF PRIM INDEX--" << endl << endl; }