⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 database.cpp

📁 机甲指挥官2源代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
			return true;
		}
		record = reinterpret_cast<Record*>(record->m_nextNameRecord);
	}	

	m_record = NULL;
	return false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	RecordHandle::ReadAndNext()
{
	Check_Object(this);
	Check_Object(m_databaseHandle);
	Database* db = m_databaseHandle->m_dataBase;
	Check_Object(db);

	Record* data;
	if (!m_databaseHandle->m_currentPointer)
		return false;

	Check_Object(m_databaseHandle->m_currentPointer);
	m_ID = m_databaseHandle->m_currentPointer->m_ID;
	m_length = m_databaseHandle->m_currentPointer->m_length;
	m_data = (&m_databaseHandle->m_currentPointer->m_data[m_databaseHandle->m_currentPointer->m_nameLength]);
	m_name = m_databaseHandle->m_currentPointer->m_name;
	m_record = m_databaseHandle->m_currentPointer;
	m_timeStamp = m_databaseHandle->m_currentPointer->m_lastModified;

	m_databaseHandle->m_currentPointer = 
		reinterpret_cast<Record*>(m_databaseHandle->m_currentPointer->m_nextIDRecord);
	if (!m_databaseHandle->m_currentPointer)
	{
		while (++m_databaseHandle->m_currentRecord < Database::e_DataBlockSize)
		{
			data = reinterpret_cast<Record*>(
				db->m_idOffsets[m_databaseHandle->m_currentRecord]
			);
			if( data )
			{
				m_databaseHandle->m_currentPointer =
					reinterpret_cast<Record*>(
						(DWORD)data + m_databaseHandle->m_baseAddress
					);
				return true;
			}
		}
		m_databaseHandle->m_currentPointer = NULL;
		return true;
	}

	m_databaseHandle->m_currentPointer = 
		reinterpret_cast<Record*>(
			(DWORD)m_databaseHandle->m_currentPointer + m_databaseHandle->m_baseAddress
		);
	return true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	RecordHandle::TestInstance() const
{
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	Database::FilesOpened = 0;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Database::Database()
{
	m_tag = e_Tag;
	m_version = e_Version;
	m_nextRecordID = 1;
	m_numberOfRecords = 0;
	memset(m_idOffsets, 0, sizeof(m_idOffsets));
	memset(m_nameOffsets, 0, sizeof(m_nameOffsets));
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
DatabaseHandle::DatabaseHandle(
	const char* filename,
	bool read_only
)
{
	//
	//-----------------------------------------------------
	// Create the database heap if it doesn't already exist
	//-----------------------------------------------------
	//
	m_fileName = filename;
	if (!Database::FilesOpened++)
		Database_Heap = gos_CreateMemoryHeap("Database", 0);
	gos_PushCurrentHeap(Database_Heap);
	m_currentRecord = 0;
	m_currentPointer = NULL;
	m_dirtyFlag = false;

	//
	//--------------------------------------------
	// If the file is read only, our job is simple
	//--------------------------------------------
	//
	m_readOnly = read_only;
	if (m_readOnly)
	{
		if (gos_DoesFileExist(filename))
		{
			FileStream::IsRedirected = false;
			DWORD size;
			m_handle =
				gos_OpenMemoryMappedFile(
					filename,
					reinterpret_cast<BYTE**>(&m_dataBase),
					&size
				);
			if (m_dataBase->m_tag != Database::e_Tag)
				STOP(("Invalid database file \"%s\"", filename));
			if (m_dataBase->m_version > Database::e_Version)
				STOP(("Application must be recompiled to use database \"%s\"", filename));
			m_baseAddress = reinterpret_cast<DWORD>(m_dataBase);
			Check_Object(m_dataBase);
		}
		else
			STOP(("Database \"%s\" does not exist", filename));
	}

	//
	//-------------------------------------------------------------
	// The file is not read only, so see if we load it or create it
	//-------------------------------------------------------------
	//
	else
	{
		m_handle = NULL;
		if (gos_DoesFileExist(filename))
		{
			DWORD size;
			gos_GetFile(
				filename,
				reinterpret_cast<BYTE**>(&m_dataBase),
				&size
			);
			FileStream::IsRedirected = false;
			Check_Pointer(m_dataBase);
			if (m_dataBase->m_tag != Database::e_Tag || m_dataBase->m_version > Database::e_Version || m_dataBase->m_version == 1)
			{
				gos_Free(m_dataBase);
				PAUSE(("Bad database file!  Press 'Continue' to rebuild", filename));
				m_dataBase = new(gos_Malloc(sizeof(Database), Database_Heap)) Database;
				m_baseAddress = 0;
			}
			else
			{
				m_baseAddress = reinterpret_cast<DWORD>(m_dataBase);
				Check_Object(m_dataBase);
			}
		}

		//
		//------------------------------------------
		// The file doesn't exist, so create it here
		//------------------------------------------
		//
		else
		{
			m_dataBase = new(gos_Malloc(sizeof(Database), Database_Heap)) Database;
			m_baseAddress = 0;
		}
	}
	gos_PopCurrentHeap();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
DatabaseHandle::~DatabaseHandle()
{
	Check_Object(this);

	//
	//---------------------------------------------------------------
	// If we are closing a read only file, release the memmap handle,
	// otherwise delete the database object
	//---------------------------------------------------------------
	//
	if (m_readOnly)
		gos_CloseMemoryMappedFile(m_handle);
	else
	{
		Save();
		Check_Object(m_dataBase);

		//
		//---------------------------------------------------------------------
		// Now we need to go through and delete all the records in the database
		//---------------------------------------------------------------------
		//
		for (DWORD i=0; i<Database::e_DataBlockSize; ++i)
		{
			Record* record = reinterpret_cast<Record*>(m_dataBase->m_idOffsets[i]);
			if (record)
			{
				while (record)
				{
					record = reinterpret_cast<Record*>((DWORD)record + m_baseAddress);
					Check_Object(record);
					Record* this_record = record;

					record = reinterpret_cast<Record*>(record->m_nextIDRecord);
					if (this_record->m_mustFree)
						delete this_record;
				}
			}
		}

		//
		//--------------------------------
		// Now free up the database itself
		//--------------------------------
		//
		gos_Free(m_dataBase);
	}

	//
	//----------------------------------------------------
	// Delete the memory heap if this is the last database
	//----------------------------------------------------
	//
	if (--Database::FilesOpened == 0)
		gos_DestroyMemoryHeap(Database_Heap);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	DatabaseHandle::Save()
{
	Check_Object(this);

	//
	//--------------------------------------
	// If there were no changes, we are done
	//--------------------------------------
	//
	if (m_readOnly || !m_dirtyFlag)
		return;

	//
	//----------------------------------------------------------------------
	// We will need to adjust pointers as we write this thing out, so make a
	// copy of the database object now
	//----------------------------------------------------------------------
	//
	Database output_db;
	output_db.m_numberOfRecords = m_dataBase->m_numberOfRecords;
	output_db.m_nextRecordID = m_dataBase->m_nextRecordID;

	//
	//----------------------------------------------------
	// Build a table to deal with rethreading the database
	//----------------------------------------------------
	//
	struct OutputRecord
	{
		DWORD
			m_ID,
			m_offset,
			m_nextIDRecord,
			m_nextNameRecord;
		Record
			*m_data;
	};
	OutputRecord *new_records = new OutputRecord[m_dataBase->m_numberOfRecords];
	Check_Pointer(new_records);
	DWORD new_id_index[Database::e_DataBlockSize];
	memset(new_id_index, 0, sizeof(new_id_index));

	//
	//---------------------------------------------------------
	// Start filling in the block information from the database
	//---------------------------------------------------------
	//
	DWORD offset = sizeof(output_db);
	OutputRecord* new_record = new_records;
	for (DWORD i=0; i<Database::e_DataBlockSize; ++i)
	{
		Record* old_record = reinterpret_cast<Record*>(m_dataBase->m_idOffsets[i]);
		if (old_record)
		{
			output_db.m_idOffsets[i] = offset;
			new_id_index[i] = new_record - new_records;
			while (old_record)
			{
				old_record = reinterpret_cast<Record*>((DWORD)old_record + m_baseAddress);
				Check_Object(old_record);

				new_record->m_data = old_record;
				new_record->m_ID = old_record->m_ID;
				new_record->m_offset = offset;
				new_record->m_nextIDRecord = 0;
				new_record->m_nextNameRecord = 0;

				offset +=
					sizeof(*old_record) + old_record->m_length + old_record->m_nameLength;

				old_record = reinterpret_cast<Record*>(old_record->m_nextIDRecord);
				if (old_record)
					new_record->m_nextIDRecord = offset;
				++new_record;
			}
		}
	}

	//
	//-----------------------------------------
	// Make sure Hash index table is up to date
	//-----------------------------------------
	//
	for (i=0; i<Database::e_DataBlockSize; ++i)
	{
		Record* old_record = reinterpret_cast<Record*>(m_dataBase->m_nameOffsets[i]);
		if (old_record)
		{
			old_record = reinterpret_cast<Record*>((DWORD)old_record + m_baseAddress);
			Check_Object(old_record);

			//
			//---------------------------------
			// Find this record in our new data
			//---------------------------------
			//
			DWORD index = old_record->m_ID % Database::e_DataBlockSize;
			int j = new_id_index[index];
			OutputRecord *new_record = &new_records[j];
			for (; j<m_dataBase->m_numberOfRecords; ++j, ++new_record)
			{
				if (new_record->m_ID == old_record->m_ID)
					break;
			}
			Verify(j<m_dataBase->m_numberOfRecords);

			//
			//----------------------
			// Set up the hash chain
			//----------------------
			//
			output_db.m_nameOffsets[i] = new_record->m_offset;
			while (old_record)
			{
				Check_Object(old_record);

				//
				//-----------------------------------------------------------
				// Find the next record, and find where it is in our new data
				//-----------------------------------------------------------
				//
				old_record = reinterpret_cast<Record*>(old_record->m_nextNameRecord);
				Verify(j<m_dataBase->m_numberOfRecords);
				if (old_record)
				{
					old_record = reinterpret_cast<Record*>((DWORD)old_record + m_baseAddress);
					Check_Object(old_record);
					index = old_record->m_ID % Database::e_DataBlockSize;
					j = new_id_index[index];
					OutputRecord *next_record = &new_records[j];
					for (; j<m_dataBase->m_numberOfRecords; ++j, ++next_record)
					{
						if (next_record->m_ID == old_record->m_ID)
							break;
					}
					Verify(j<m_dataBase->m_numberOfRecords);
					new_record->m_nextNameRecord = next_record->m_offset;
					new_record = next_record;
				}
			}
		}
	}

	//
	//------------------------------------------------
	// This file was read/write, so write it out again
	//------------------------------------------------
	//
	FileStream db_file(m_fileName, FileStream::WriteOnly);
	db_file.WriteBytes(&output_db, sizeof(output_db));

	//
	//----------------------
	// Write out each record
	//----------------------
	//
	new_record=new_records;
	for (i=0; i<m_dataBase->m_numberOfRecords; ++i, ++new_record)
	{
		Record* old_record = new_record->m_data;

		//
		//------------------------------------------------------------
		// Save the old connection info, then replace it with the data
		// calculated in the new records
		//------------------------------------------------------------
		//
		bool free_block = old_record->m_mustFree;
		DWORD next_id = old_record->m_nextIDRecord;
		DWORD next_name = old_record->m_nextNameRecord;
		old_record->m_mustFree = false;
		old_record->m_nextIDRecord = new_record->m_nextIDRecord;
		old_record->m_nextNameRecord = new_record->m_nextNameRecord;

		//
		//------------------------------------------
		// Write out the info, then restore the data
		//------------------------------------------
		//
		db_file.WriteBytes(
			old_record,
			sizeof(*old_record) + old_record->m_length + old_record->m_nameLength
		);
		old_record->m_mustFree = free_block;
		old_record->m_nextIDRecord = next_id;
		old_record->m_nextNameRecord = next_name;
	}

	//
	//---------
	// Clean up
	//---------
	//
	delete[] new_records;
	m_dirtyFlag = false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
DWORD
	DatabaseHandle::GetNumberOfRecords()
{
	Check_Object(this);
	return m_dataBase->m_numberOfRecords;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	DatabaseHandle::First()
{
	Check_Object(this);

	m_currentRecord = 0;
	m_currentPointer = NULL;

	for (DWORD i=0; i<Database::e_DataBlockSize; i++)
	{
		Record* data =
			reinterpret_cast<Record*>(
				m_dataBase->m_idOffsets[i] + m_baseAddress
			);
		if( data )
		{
			m_currentRecord = i;
			m_currentPointer = data;
			break;
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	DatabaseHandle::TestInstance() const
{
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -