-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDS_Table.h
More file actions
317 lines (253 loc) · 11.9 KB
/
DS_Table.h
File metadata and controls
317 lines (253 loc) · 11.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
#ifndef __TABLE_H
#define __TABLE_H
#ifdef _MSC_VER
#pragma warning( push )
#endif
#include "DS_List.h"
#include "DS_BPlusTree.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 HexNet 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 Table
{
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 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);
// 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 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 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 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 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