219 lines
7.9 KiB
C++
219 lines
7.9 KiB
C++
|
/*
|
||
|
* Copyright (c) 2014, Oculus VR, Inc.
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* This source code is licensed under the BSD-style license found in the
|
||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#ifndef __TABLE_SERIALIZER_H
|
||
|
#define __TABLE_SERIALIZER_H
|
||
|
|
||
|
#include "RakMemoryOverride.hpp"
|
||
|
#include "DS_Table.hpp"
|
||
|
#include "Export.hpp"
|
||
|
|
||
|
namespace RakNet
|
||
|
{
|
||
|
class BitStream;
|
||
|
}
|
||
|
|
||
|
namespace RakNet
|
||
|
{
|
||
|
|
||
|
class RAK_DLL_EXPORT TableSerializer
|
||
|
{
|
||
|
public:
|
||
|
static void SerializeTable(DataStructures::Table *in, RakNet::BitStream *out);
|
||
|
static bool DeserializeTable(unsigned char *serializedTable, unsigned int dataLength, DataStructures::Table *out);
|
||
|
static bool DeserializeTable(RakNet::BitStream *in, DataStructures::Table *out);
|
||
|
static void SerializeColumns(DataStructures::Table *in, RakNet::BitStream *out);
|
||
|
static void SerializeColumns(DataStructures::Table *in, RakNet::BitStream *out, DataStructures::List<int> &skipColumnIndices);
|
||
|
static bool DeserializeColumns(RakNet::BitStream *in, DataStructures::Table *out);
|
||
|
static void SerializeRow(DataStructures::Table::Row *in, unsigned keyIn, const DataStructures::List<DataStructures::Table::ColumnDescriptor> &columns, RakNet::BitStream *out);
|
||
|
static void SerializeRow(DataStructures::Table::Row *in, unsigned keyIn, const DataStructures::List<DataStructures::Table::ColumnDescriptor> &columns, RakNet::BitStream *out, DataStructures::List<int> &skipColumnIndices);
|
||
|
static bool DeserializeRow(RakNet::BitStream *in, DataStructures::Table *out);
|
||
|
static void SerializeCell(RakNet::BitStream *out, DataStructures::Table::Cell *cell, DataStructures::Table::ColumnType columnType);
|
||
|
static bool DeserializeCell(RakNet::BitStream *in, DataStructures::Table::Cell *cell, DataStructures::Table::ColumnType columnType);
|
||
|
static void SerializeFilterQuery(RakNet::BitStream *in, DataStructures::Table::FilterQuery *query);
|
||
|
// Note that this allocates query->cell->c!
|
||
|
static bool DeserializeFilterQuery(RakNet::BitStream *out, DataStructures::Table::FilterQuery *query);
|
||
|
static void SerializeFilterQueryList(RakNet::BitStream *in, DataStructures::Table::FilterQuery *query, unsigned int numQueries, unsigned int maxQueries);
|
||
|
// Note that this allocates queries, cells, and query->cell->c!. Use DeallocateQueryList to free.
|
||
|
static bool DeserializeFilterQueryList(RakNet::BitStream *out, DataStructures::Table::FilterQuery **query, unsigned int *numQueries, unsigned int maxQueries, int allocateExtraQueries=0);
|
||
|
static void DeallocateQueryList(DataStructures::Table::FilterQuery *query, unsigned int numQueries);
|
||
|
};
|
||
|
|
||
|
} // namespace RakNet
|
||
|
|
||
|
#endif
|
||
|
|
||
|
// Test code for the table
|
||
|
/*
|
||
|
#include "LightweightDatabaseServer.hpp"
|
||
|
#include "LightweightDatabaseClient.hpp"
|
||
|
#include "TableSerializer.hpp"
|
||
|
#include "BitStream.hpp"
|
||
|
#include "StringCompressor.hpp"
|
||
|
#include "DS_Table.hpp"
|
||
|
void main(void)
|
||
|
{
|
||
|
DataStructures::Table table;
|
||
|
DataStructures::Table::Row *row;
|
||
|
unsigned int dummydata=12345;
|
||
|
|
||
|
// Add columns Name (string), IP (binary), score (int), and players (int).
|
||
|
table.AddColumn("Name", DataStructures::Table::STRING);
|
||
|
table.AddColumn("IP", DataStructures::Table::BINARY);
|
||
|
table.AddColumn("Score", DataStructures::Table::NUMERIC);
|
||
|
table.AddColumn("Players", DataStructures::Table::NUMERIC);
|
||
|
table.AddColumn("Empty Test Column", DataStructures::Table::STRING);
|
||
|
RakAssert(table.GetColumnCount()==5);
|
||
|
row=table.AddRow(0);
|
||
|
RakAssert(row);
|
||
|
row->UpdateCell(0,"Kevin Jenkins");
|
||
|
row->UpdateCell(1,sizeof(dummydata), (char*)&dummydata);
|
||
|
row->UpdateCell(2,5);
|
||
|
row->UpdateCell(3,10);
|
||
|
//row->UpdateCell(4,"should be unique");
|
||
|
|
||
|
row=table.AddRow(1);
|
||
|
row->UpdateCell(0,"Kevin Jenkins");
|
||
|
row->UpdateCell(1,sizeof(dummydata), (char*)&dummydata);
|
||
|
row->UpdateCell(2,5);
|
||
|
row->UpdateCell(3,15);
|
||
|
|
||
|
row=table.AddRow(2);
|
||
|
row->UpdateCell(0,"Kevin Jenkins");
|
||
|
row->UpdateCell(1,sizeof(dummydata), (char*)&dummydata);
|
||
|
row->UpdateCell(2,5);
|
||
|
row->UpdateCell(3,20);
|
||
|
|
||
|
row=table.AddRow(3);
|
||
|
RakAssert(row);
|
||
|
row->UpdateCell(0,"Kevin Jenkins");
|
||
|
row->UpdateCell(1,sizeof(dummydata), (char*)&dummydata);
|
||
|
row->UpdateCell(2,15);
|
||
|
row->UpdateCell(3,5);
|
||
|
row->UpdateCell(4,"col index 4");
|
||
|
|
||
|
row=table.AddRow(4);
|
||
|
RakAssert(row);
|
||
|
row->UpdateCell(0,"Kevin Jenkins");
|
||
|
row->UpdateCell(1,sizeof(dummydata), (char*)&dummydata);
|
||
|
//row->UpdateCell(2,25);
|
||
|
row->UpdateCell(3,30);
|
||
|
//row->UpdateCell(4,"should be unique");
|
||
|
|
||
|
row=table.AddRow(5);
|
||
|
RakAssert(row);
|
||
|
row->UpdateCell(0,"Kevin Jenkins");
|
||
|
row->UpdateCell(1,sizeof(dummydata), (char*)&dummydata);
|
||
|
//row->UpdateCell(2,25);
|
||
|
row->UpdateCell(3,5);
|
||
|
//row->UpdateCell(4,"should be unique");
|
||
|
|
||
|
row=table.AddRow(6);
|
||
|
RakAssert(row);
|
||
|
row->UpdateCell(0,"Kevin Jenkins");
|
||
|
row->UpdateCell(1,sizeof(dummydata), (char*)&dummydata);
|
||
|
row->UpdateCell(2,35);
|
||
|
//row->UpdateCell(3,40);
|
||
|
//row->UpdateCell(4,"should be unique");
|
||
|
|
||
|
row=table.AddRow(7);
|
||
|
RakAssert(row);
|
||
|
row->UpdateCell(0,"Bob Jenkins");
|
||
|
|
||
|
row=table.AddRow(8);
|
||
|
RakAssert(row);
|
||
|
row->UpdateCell(0,"Zack Jenkins");
|
||
|
|
||
|
// Test multi-column sorting
|
||
|
DataStructures::Table::Row *rows[30];
|
||
|
DataStructures::Table::SortQuery queries[4];
|
||
|
queries[0].columnIndex=0;
|
||
|
queries[0].operation=DataStructures::Table::QS_INCREASING_ORDER;
|
||
|
queries[1].columnIndex=1;
|
||
|
queries[1].operation=DataStructures::Table::QS_INCREASING_ORDER;
|
||
|
queries[2].columnIndex=2;
|
||
|
queries[2].operation=DataStructures::Table::QS_INCREASING_ORDER;
|
||
|
queries[3].columnIndex=3;
|
||
|
queries[3].operation=DataStructures::Table::QS_DECREASING_ORDER;
|
||
|
table.SortTable(queries, 4, rows);
|
||
|
unsigned i;
|
||
|
char out[256];
|
||
|
RAKNET_DEBUG_PRINTF("Sort: Ascending except for column index 3\n");
|
||
|
for (i=0; i < table.GetRowCount(); i++)
|
||
|
{
|
||
|
table.PrintRow(out,256,',',true, rows[i]);
|
||
|
RAKNET_DEBUG_PRINTF("%s\n", out);
|
||
|
}
|
||
|
|
||
|
// Test query:
|
||
|
// Don't return column 3, and swap columns 0 and 2
|
||
|
unsigned columnsToReturn[4];
|
||
|
columnsToReturn[0]=2;
|
||
|
columnsToReturn[1]=1;
|
||
|
columnsToReturn[2]=0;
|
||
|
columnsToReturn[3]=4;
|
||
|
DataStructures::Table resultsTable;
|
||
|
table.QueryTable(columnsToReturn,4,0,0,&resultsTable);
|
||
|
RAKNET_DEBUG_PRINTF("Query: Don't return column 3, and swap columns 0 and 2:\n");
|
||
|
for (i=0; i < resultsTable.GetRowCount(); i++)
|
||
|
{
|
||
|
resultsTable.PrintRow(out,256,',',true, resultsTable.GetRowByIndex(i));
|
||
|
RAKNET_DEBUG_PRINTF("%s\n", out);
|
||
|
}
|
||
|
|
||
|
// Test filter:
|
||
|
// Only return rows with column index 4 empty
|
||
|
DataStructures::Table::FilterQuery inclusionFilters[3];
|
||
|
inclusionFilters[0].columnIndex=4;
|
||
|
inclusionFilters[0].operation=DataStructures::Table::QF_IS_EMPTY;
|
||
|
// inclusionFilters[0].cellValue; // Unused for IS_EMPTY
|
||
|
table.QueryTable(0,0,inclusionFilters,1,&resultsTable);
|
||
|
RAKNET_DEBUG_PRINTF("Filter: Only return rows with column index 4 empty:\n");
|
||
|
for (i=0; i < resultsTable.GetRowCount(); i++)
|
||
|
{
|
||
|
resultsTable.PrintRow(out,256,',',true, resultsTable.GetRowByIndex(i));
|
||
|
RAKNET_DEBUG_PRINTF("%s\n", out);
|
||
|
}
|
||
|
|
||
|
// Column 5 empty and column 0 == Kevin Jenkins
|
||
|
inclusionFilters[0].columnIndex=4;
|
||
|
inclusionFilters[0].operation=DataStructures::Table::QF_IS_EMPTY;
|
||
|
inclusionFilters[1].columnIndex=0;
|
||
|
inclusionFilters[1].operation=DataStructures::Table::QF_EQUAL;
|
||
|
inclusionFilters[1].cellValue.Set("Kevin Jenkins");
|
||
|
table.QueryTable(0,0,inclusionFilters,2,&resultsTable);
|
||
|
RAKNET_DEBUG_PRINTF("Filter: Column 5 empty and column 0 == Kevin Jenkins:\n");
|
||
|
for (i=0; i < resultsTable.GetRowCount(); i++)
|
||
|
{
|
||
|
resultsTable.PrintRow(out,256,',',true, resultsTable.GetRowByIndex(i));
|
||
|
RAKNET_DEBUG_PRINTF("%s\n", out);
|
||
|
}
|
||
|
|
||
|
RakNet::BitStream bs;
|
||
|
RAKNET_DEBUG_PRINTF("PreSerialize:\n");
|
||
|
for (i=0; i < table.GetRowCount(); i++)
|
||
|
{
|
||
|
table.PrintRow(out,256,',',true, table.GetRowByIndex(i));
|
||
|
RAKNET_DEBUG_PRINTF("%s\n", out);
|
||
|
}
|
||
|
StringCompressor::AddReference();
|
||
|
TableSerializer::Serialize(&table, &bs);
|
||
|
TableSerializer::Deserialize(&bs, &table);
|
||
|
StringCompressor::RemoveReference();
|
||
|
RAKNET_DEBUG_PRINTF("PostDeserialize:\n");
|
||
|
for (i=0; i < table.GetRowCount(); i++)
|
||
|
{
|
||
|
table.PrintRow(out,256,',',true, table.GetRowByIndex(i));
|
||
|
RAKNET_DEBUG_PRINTF("%s\n", out);
|
||
|
}
|
||
|
int a=5;
|
||
|
}
|
||
|
*/
|