mirror of
				https://github.com/DarkflameUniverse/DarkflameServer.git
				synced 2025-10-26 18:11:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			323 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			323 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #ifndef __TABLE_H
 | |
| #define __TABLE_H
 | |
| 
 | |
| #ifdef _MSC_VER
 | |
| #pragma warning( push )
 | |
| #endif
 | |
| 
 | |
| #include "DS_List.h"
 | |
| #include "DS_BPlusTree.h"
 | |
| #include "RakMemoryOverride.h"
 | |
| #include "Export.h"
 | |
| #include "RakString.h"
 | |
| 
 | |
| #define _TABLE_BPLUS_TREE_ORDER 16
 | |
| #define _TABLE_MAX_COLUMN_NAME_LENGTH 32
 | |
| 
 | |
| /// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
 | |
| /// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
 | |
| namespace DataStructures
 | |
| {
 | |
| 
 | |
| 	/// \brief Holds a set of columns, a set of rows, and rows times columns cells.
 | |
| 	/// The table data structure is useful if you want to store a set of structures and perform queries on those structures
 | |
| 	/// This is a relatively simple and fast implementation of the types of tables commonly used in databases
 | |
| 	/// See TableSerializer to serialize data members of the table
 | |
| 	/// See LightweightDatabaseClient and LightweightDatabaseServer to transmit the table over the network.
 | |
| 	class RAK_DLL_EXPORT Table : public RakNet::RakMemoryOverride
 | |
| 	{
 | |
| 	public:
 | |
| 			
 | |
| 		enum ColumnType
 | |
| 		{
 | |
| 			// Cell::i used
 | |
| 			NUMERIC,
 | |
| 
 | |
| 			// Cell::c used to hold a null terminated string.
 | |
| 			STRING,
 | |
| 
 | |
| 			// Cell::c holds data.  Cell::i holds data length of c in bytes.
 | |
| 			BINARY,
 | |
| 
 | |
| 			// Cell::c holds data.  Not deallocated. Set manually by assigning ptr.
 | |
| 			POINTER,
 | |
| 		};
 | |
| 		
 | |
| 		
 | |
| 		/// Holds the actual data in the table
 | |
| 		struct RAK_DLL_EXPORT Cell
 | |
| 		{
 | |
| 			Cell();
 | |
| 			~Cell();
 | |
| 			Cell(int intValue, char *charValue, void *ptr, ColumnType type);
 | |
| 			void Clear(void);
 | |
| 			
 | |
| 			/// Numeric
 | |
| 			void Set(int input);
 | |
| 
 | |
| 			/// String
 | |
| 			void Set(const char *input);
 | |
| 
 | |
| 			/// Binary
 | |
| 			void Set(const char *input, int inputLength);
 | |
| 
 | |
| 			/// Pointer
 | |
| 			void SetPtr(void* p);
 | |
| 
 | |
| 			/// Numeric
 | |
| 			void Get(int *output);
 | |
| 
 | |
| 			/// String
 | |
| 			void Get(char *output);
 | |
| 
 | |
| 			/// Binary
 | |
| 			void Get(char *output, int *outputLength);
 | |
| 
 | |
| 			RakNet::RakString ToString(ColumnType columnType);
 | |
| 
 | |
| 			// assignment operator and copy constructor
 | |
| 			Cell& operator = ( const Cell& input );
 | |
| 			Cell( const Cell & input);
 | |
| 
 | |
| 			bool isEmpty;
 | |
| 			int i;
 | |
| 			char *c;
 | |
| 			void *ptr;
 | |
| 		};
 | |
| 
 | |
| 		/// Stores the name and type of the column
 | |
| 		/// \internal
 | |
| 		struct RAK_DLL_EXPORT ColumnDescriptor
 | |
| 		{
 | |
| 			ColumnDescriptor();
 | |
| 			~ColumnDescriptor();
 | |
| 			ColumnDescriptor(const char cn[_TABLE_MAX_COLUMN_NAME_LENGTH],ColumnType ct);
 | |
| 
 | |
| 			char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH];
 | |
| 			ColumnType columnType;
 | |
| 		};
 | |
| 
 | |
| 		/// Stores the list of cells for this row, and a special flag used for internal sorting
 | |
| 		struct RAK_DLL_EXPORT Row
 | |
| 		{
 | |
| 			// list of cells
 | |
| 			DataStructures::List<Cell*> cells;
 | |
| 
 | |
| 			/// Numeric
 | |
| 			void UpdateCell(unsigned columnIndex, int value);
 | |
| 
 | |
| 			/// String
 | |
| 			void UpdateCell(unsigned columnIndex, const char *str);
 | |
| 
 | |
| 			/// Binary
 | |
| 			void UpdateCell(unsigned columnIndex, int byteLength, const char *data);
 | |
| 		};
 | |
| 		
 | |
| 		// Operations to perform for cell comparison
 | |
| 		enum FilterQueryType
 | |
| 		{
 | |
| 			QF_EQUAL,
 | |
| 			QF_NOT_EQUAL,
 | |
| 			QF_GREATER_THAN,
 | |
| 			QF_GREATER_THAN_EQ,
 | |
| 			QF_LESS_THAN,
 | |
| 			QF_LESS_THAN_EQ,
 | |
| 			QF_IS_EMPTY,
 | |
| 			QF_NOT_EMPTY,
 | |
| 		};
 | |
| 
 | |
| 		// Compare the cell value for a row at columnName to the cellValue using operation.
 | |
| 		struct RAK_DLL_EXPORT FilterQuery
 | |
| 		{
 | |
| 			FilterQuery();
 | |
| 			~FilterQuery();
 | |
| 			FilterQuery(unsigned column, Cell *cell, FilterQueryType op);
 | |
| 
 | |
| 			// If columnName is specified, columnIndex will be looked up using it.
 | |
| 			char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH];
 | |
| 			unsigned columnIndex;
 | |
| 			Cell *cellValue;
 | |
| 			FilterQueryType operation;
 | |
| 		};
 | |
| 
 | |
| 		/// Increasing or decreasing sort order
 | |
| 		enum SortQueryType
 | |
| 		{
 | |
| 			QS_INCREASING_ORDER,
 | |
| 			QS_DECREASING_ORDER,
 | |
| 		};
 | |
| 		
 | |
| 		// Sort on increasing or decreasing order for a particular column
 | |
| 		struct RAK_DLL_EXPORT SortQuery
 | |
| 		{
 | |
| 			/// The index of the table column we are sorting on
 | |
| 			unsigned columnIndex;
 | |
| 
 | |
| 			/// See SortQueryType
 | |
| 			SortQueryType operation;
 | |
| 		};
 | |
| 
 | |
| 		/// Constructor
 | |
| 		Table();
 | |
| 
 | |
| 		/// Destructor
 | |
| 		~Table();
 | |
| 
 | |
| 		/// \brief Adds a column to the table
 | |
| 		/// \param[in] columnName The name of the column
 | |
| 		/// \param[in] columnType What type of data this column will hold
 | |
| 		/// \return The index of the new column
 | |
| 		unsigned AddColumn(const char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH], ColumnType columnType);
 | |
| 
 | |
| 		/// \brief Removes a column by index
 | |
| 		/// \param[in] columnIndex The index of the column to remove
 | |
| 		void RemoveColumn(unsigned columnIndex);
 | |
| 
 | |
| 		/// \brief Gets the index of a column by name
 | |
| 		/// Column indices are stored in the order they are added.
 | |
| 		/// \param[in] columnName The name of the column
 | |
| 		/// \return The index of the column, or (unsigned)-1 if no such column
 | |
| 		unsigned ColumnIndex(char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH]);
 | |
| 		unsigned ColumnIndex(const char *columnName);
 | |
| 
 | |
| 		/// \brief Gives the string name of the column at a certain index
 | |
| 		/// \param[in] index The index of the column
 | |
| 		/// \return The name of the column, or 0 if an invalid index
 | |
| 		char* ColumnName(unsigned index);
 | |
| 
 | |
| 		/// \brief Returns the type of a column, referenced by index
 | |
| 		/// \param[in] index The index of the column
 | |
| 		/// \return The type of the column
 | |
| 		ColumnType GetColumnType(unsigned index);
 | |
| 
 | |
| 		/// Returns the number of columns
 | |
| 		/// \return The number of columns in the table
 | |
| 		unsigned GetColumnCount(void) const;
 | |
| 
 | |
| 		/// Returns the number of rows
 | |
| 		/// \return The number of rows in the table
 | |
| 		unsigned GetRowCount(void) const;
 | |
| 
 | |
| 		/// \brief Adds a row to the table
 | |
| 		/// New rows are added with empty values for all cells.  However, if you specify initialCelLValues you can specify initial values
 | |
| 		/// It's up to you to ensure that the values in the specific cells match the type of data used by that row
 | |
| 		/// rowId can be considered the primary key for the row.  It is much faster to lookup a row by its rowId than by searching keys.
 | |
| 		/// rowId must be unique
 | |
| 		/// Rows are stored in sorted order in the table, using rowId as the sort key
 | |
| 		/// \param[in] rowId The UNIQUE primary key for the row.  This can never be changed.
 | |
| 		/// \param[in] initialCellValues Initial values to give the row (optional)
 | |
| 		/// \return The newly added row
 | |
| 		Table::Row* AddRow(unsigned rowId);
 | |
| 		Table::Row* AddRow(unsigned rowId, DataStructures::List<Cell> &initialCellValues);
 | |
| 
 | |
| 		/// Removes a row specified by rowId
 | |
| 		/// \param[in] rowId The ID of the row
 | |
| 		void RemoveRow(unsigned rowId);
 | |
| 
 | |
| 		/// Removes all the rows with IDs that the specified table also has
 | |
| 		/// \param[in] tableContainingRowIDs The IDs of the rows
 | |
| 		void RemoveRows(Table *tableContainingRowIDs);
 | |
| 
 | |
| 		/// Updates a particular cell in the table
 | |
| 		/// \note If you are going to update many cells of a particular row, it is more efficient to call GetRow and perform the operations on the row directly.
 | |
| 		/// \note Row pointers do not change, so you can also write directly to the rows for more efficiency.
 | |
|         /// \param[in] rowId The ID of the row
 | |
| 		/// \param[in] columnIndex The column of the cell
 | |
| 		/// \param[in] value The data to set
 | |
| 		bool UpdateCell(unsigned rowId, unsigned columnIndex, int value);
 | |
| 		bool UpdateCell(unsigned rowId, unsigned columnIndex, char *str);
 | |
| 		bool UpdateCell(unsigned rowId, unsigned columnIndex, int byteLength, char *data);
 | |
| 		bool UpdateCellByIndex(unsigned rowIndex, unsigned columnIndex, int value);
 | |
| 		bool UpdateCellByIndex(unsigned rowIndex, unsigned columnIndex, char *str);
 | |
| 		bool UpdateCellByIndex(unsigned rowIndex, unsigned columnIndex, int byteLength, char *data);
 | |
| 
 | |
| 		/// Note this is much less efficient to call than GetRow, then working with the cells directly
 | |
| 		/// Numeric, string, binary
 | |
| 		void GetCellValueByIndex(unsigned rowIndex, unsigned columnIndex, int *output);
 | |
| 		void GetCellValueByIndex(unsigned rowIndex, unsigned columnIndex, char *output);
 | |
| 		void GetCellValueByIndex(unsigned rowIndex, unsigned columnIndex, char *output, int *outputLength);
 | |
| 
 | |
| 		/// Gets a row.  More efficient to do this and access Row::cells than to repeatedly call GetCell.
 | |
| 		/// You can also update cells in rows from this function.
 | |
| 		/// \param[in] rowId The ID of the row
 | |
| 		/// \return The desired row, or 0 if no such row.
 | |
| 		Row* GetRowByID(unsigned rowId) const;
 | |
| 
 | |
| 		/// Gets a row at a specific index
 | |
| 		/// rowIndex should be less than GetRowCount()
 | |
| 		/// \param[in] rowIndex The index of the row
 | |
| 		/// \param[out] key The ID of the row returned
 | |
| 		/// \return The desired row, or 0 if no such row.
 | |
| 		Row* GetRowByIndex(unsigned rowIndex, unsigned *key) const;
 | |
| 
 | |
| 		/// \brief Queries the table, optionally returning only a subset of columns and rows.
 | |
| 		/// \param[in] columnSubset An array of column indices.  Only columns in this array are returned.  Pass 0 for all columns
 | |
| 		/// \param[in] numColumnSubset The number of elements in \a columnSubset
 | |
| 		/// \param[in] inclusionFilters An array of FilterQuery.  All filters must pass for the row to be returned.
 | |
| 		/// \param[in] numInclusionFilters The number of elements in \a inclusionFilters
 | |
| 		/// \param[in] rowIds An arrow of row IDs.  Only these rows with these IDs are returned.  Pass 0 for all rows.
 | |
| 		/// \param[in] numRowIDs The number of elements in \a rowIds
 | |
| 		/// \param[out] result The result of the query.  If no rows are returned, the table will only have columns.
 | |
| 		void QueryTable(unsigned *columnIndicesSubset, unsigned numColumnSubset, FilterQuery *inclusionFilters, unsigned numInclusionFilters, unsigned *rowIds, unsigned numRowIDs, Table *result);
 | |
| 
 | |
| 		/// \brief Sorts the table by rows
 | |
| 		/// You can sort the table in ascending or descending order on one or more columns
 | |
| 		/// Columns have precedence in the order they appear in the \a sortQueries array
 | |
| 		/// If a row cell on column n has the same value as a a different row on column n, then the row will be compared on column n+1
 | |
| 		/// \param[in] sortQueries A list of SortQuery structures, defining the sorts to perform on the table
 | |
| 		/// \param[in] numColumnSubset The number of elements in \a numSortQueries
 | |
| 		/// \param[out] out The address of an array of Rows, which will receive the sorted output.  The array must be long enough to contain all returned rows, up to GetRowCount()
 | |
| 		void SortTable(Table::SortQuery *sortQueries, unsigned numSortQueries, Table::Row** out);
 | |
| 
 | |
| 		/// Frees all memory in the table.
 | |
| 		void Clear(void);
 | |
| 
 | |
| 		/// Prints out the names of all the columns
 | |
| 		/// \param[out] out A pointer to an array of bytes which will hold the output.
 | |
| 		/// \param[in] outLength The size of the \a out array
 | |
| 		/// \param[in] columnDelineator What character to print to delineate columns
 | |
| 		void PrintColumnHeaders(char *out, int outLength, char columnDelineator) const;
 | |
| 
 | |
| 		/// Writes a text representation of the row to \a out
 | |
| 		/// \param[out] out A pointer to an array of bytes which will hold the output.
 | |
| 		/// \param[in] outLength The size of the \a out array
 | |
| 		/// \param[in] columnDelineator What character to print to delineate columns
 | |
| 		/// \param[in] printDelineatorForBinary Binary output is not printed.  True to still print the delineator.
 | |
| 		/// \param[in] inputRow The row to print
 | |
| 		void PrintRow(char *out, int outLength, char columnDelineator, bool printDelineatorForBinary, Table::Row* inputRow) const;
 | |
| 
 | |
| 		/// Direct access to make things easier
 | |
| 		DataStructures::List<ColumnDescriptor>& GetColumns(void);
 | |
| 
 | |
| 		/// Direct access to make things easier
 | |
| 		DataStructures::BPlusTree<unsigned, Row*, _TABLE_BPLUS_TREE_ORDER>& GetRows(void);
 | |
| 
 | |
| 		/// Get the head of a linked list containing all the row data
 | |
| 		DataStructures::Page<unsigned, DataStructures::Table::Row*, _TABLE_BPLUS_TREE_ORDER> * GetListHead(void);
 | |
| 
 | |
| 		/// Get the first free row id.
 | |
| 		/// This could be made more efficient.
 | |
| 		unsigned GetAvailableRowId(void) const;
 | |
| 
 | |
| 	protected:
 | |
| 		Table::Row* AddRowColumns(unsigned rowId, Row *row, DataStructures::List<unsigned> columnIndices);
 | |
| 
 | |
| 		void DeleteRow(Row *row);
 | |
| 
 | |
| 		void QueryRow(DataStructures::List<unsigned> &inclusionFilterColumnIndices, DataStructures::List<unsigned> &columnIndicesToReturn, unsigned key, Table::Row* row, FilterQuery *inclusionFilters, Table *result);
 | |
| 
 | |
| 		// 16 is arbitrary and is the order of the BPlus tree.  Higher orders are better for searching while lower orders are better for
 | |
| 		// Insertions and deletions.
 | |
| 		DataStructures::BPlusTree<unsigned, Row*, _TABLE_BPLUS_TREE_ORDER> rows;
 | |
| 
 | |
| 		// Columns in the table.
 | |
| 		DataStructures::List<ColumnDescriptor> columns;
 | |
| 	};
 | |
| }
 | |
| 
 | |
| #ifdef _MSC_VER
 | |
| #pragma warning( pop )
 | |
| #endif
 | |
| 
 | |
| #endif
 | 
