300 lines
9.4 KiB
C
300 lines
9.4 KiB
C
|
#pragma once
|
||
|
/****************************************************************************
|
||
|
Copyright (c) 2009, Radon Labs GmbH
|
||
|
Copyright (c) 2011-2013,WebJet Business Division,CYOU
|
||
|
|
||
|
http://www.genesis-3d.com.cn
|
||
|
|
||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
of this software and associated documentation files (the "Software"), to deal
|
||
|
in the Software without restriction, including without limitation the rights
|
||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
|
copies of the Software, and to permit persons to whom the Software is
|
||
|
furnished to do so, subject to the following conditions:
|
||
|
|
||
|
The above copyright notice and this permission notice shall be included in
|
||
|
all copies or substantial portions of the Software.
|
||
|
|
||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||
|
THE SOFTWARE.
|
||
|
****************************************************************************/
|
||
|
|
||
|
#include "util/array.h"
|
||
|
#include "util/fixedtable.h"
|
||
|
#include "util/dictionary.h"
|
||
|
#include "util/stringatom.h"
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
namespace Util
|
||
|
{
|
||
|
template<class TYPE> class SparseTable
|
||
|
{
|
||
|
public:
|
||
|
/// constructor
|
||
|
SparseTable();
|
||
|
|
||
|
/// setup the sparse table
|
||
|
void BeginSetup(const Array<StringAtom>& columnNames, const Array<StringAtom>& rowNames, SizeT numUnique=0);
|
||
|
/// add a single new unique entry
|
||
|
void AddSingle(IndexT colIndex, IndexT rowIndex, const TYPE& elm);
|
||
|
/// add a new multiple entry
|
||
|
void AddMultiple(IndexT colIndex, IndexT rowIndex, const TYPE* firstElm, SizeT numElements);
|
||
|
/// add a reference to another column/index
|
||
|
void AddReference(IndexT colIndex, IndexT rowIndex, IndexT refColIndex, IndexT refRowIndex);
|
||
|
/// add a direct reference using an index into the unique element array
|
||
|
void SetEntryDirect(IndexT colIndex, IndexT rowIndex, ushort startIndex, ushort numElements);
|
||
|
/// finish setting up the sparse table
|
||
|
void EndSetup();
|
||
|
/// clear object
|
||
|
void Clear();
|
||
|
|
||
|
/// get number of columns in the sparse table
|
||
|
SizeT GetNumColumns() const;
|
||
|
/// get number of rows in the sparse table
|
||
|
SizeT GetNumRows() const;
|
||
|
/// return true if column exists
|
||
|
bool HasColumn(const StringAtom& colName) const;
|
||
|
/// return true if row exists
|
||
|
bool HasRow(const StringAtom& rowName) const;
|
||
|
/// return column index by name
|
||
|
IndexT GetColumnIndexByName(const StringAtom& colName) const;
|
||
|
/// return row index by name
|
||
|
IndexT GetRowIndexByName(const StringAtom& rowName) const;
|
||
|
/// get current number of unique elements
|
||
|
SizeT GetNumUniqueElements() const;
|
||
|
|
||
|
/// get entry at given index
|
||
|
const TYPE* GetElements(IndexT colIndex, IndexT rowIndex, SizeT& outNumElements) const;
|
||
|
/// lookup entry by row/column names
|
||
|
const TYPE* LookupElements(const StringAtom& colName, const StringAtom& rowName, SizeT& outNumElements) const;
|
||
|
|
||
|
private:
|
||
|
/// a table entry in the sparse table
|
||
|
struct TableEntry
|
||
|
{
|
||
|
TableEntry() : startIndex(0xffff), numElements(0) {};
|
||
|
|
||
|
ushort startIndex; // index into uniqueElements array
|
||
|
ushort numElements; // number of elements in uniqueElements array
|
||
|
};
|
||
|
|
||
|
Array<TYPE> uniqueElements;
|
||
|
FixedTable<TableEntry> tableEntries;
|
||
|
Dictionary<StringAtom, IndexT> colIndexMap;
|
||
|
Dictionary<StringAtom, IndexT> rowIndexMap;
|
||
|
bool inSetup;
|
||
|
};
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
*/
|
||
|
template<class TYPE>
|
||
|
SparseTable<TYPE>::SparseTable() :
|
||
|
inSetup(false)
|
||
|
{
|
||
|
// empty
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
*/
|
||
|
template<class TYPE> void
|
||
|
SparseTable<TYPE>::Clear()
|
||
|
{
|
||
|
n_assert(!this->inSetup);
|
||
|
this->uniqueElements.Clear();
|
||
|
this->tableEntries.SetSize(0, 0);
|
||
|
this->colIndexMap.Clear();
|
||
|
this->rowIndexMap.Clear();
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
*/
|
||
|
template<class TYPE> void
|
||
|
SparseTable<TYPE>::BeginSetup(const Array<StringAtom>& columnNames, const Array<StringAtom>& rowNames, SizeT numUnique)
|
||
|
{
|
||
|
n_assert(!this->inSetup);
|
||
|
this->inSetup = true;
|
||
|
if (numUnique > 0)
|
||
|
{
|
||
|
this->uniqueElements.Reserve(numUnique);
|
||
|
}
|
||
|
this->tableEntries.SetSize(columnNames.Size(), rowNames.Size());
|
||
|
this->colIndexMap.Reserve(columnNames.Size());
|
||
|
this->rowIndexMap.Reserve(rowNames.Size());
|
||
|
|
||
|
this->colIndexMap.BeginBulkAdd();
|
||
|
IndexT i;
|
||
|
for (i = 0; i < columnNames.Size(); i++)
|
||
|
{
|
||
|
this->colIndexMap.Add(columnNames[i], i);
|
||
|
}
|
||
|
this->colIndexMap.EndBulkAdd();
|
||
|
|
||
|
this->rowIndexMap.BeginBulkAdd();
|
||
|
for (i = 0; i < rowNames.Size(); i++)
|
||
|
{
|
||
|
this->rowIndexMap.Add(rowNames[i], i);
|
||
|
}
|
||
|
this->rowIndexMap.EndBulkAdd();
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
*/
|
||
|
template<class TYPE> void
|
||
|
SparseTable<TYPE>::AddSingle(IndexT colIndex, IndexT rowIndex, const TYPE& elm)
|
||
|
{
|
||
|
n_assert(this->inSetup);
|
||
|
TableEntry& entry = this->tableEntries.At(colIndex, rowIndex);
|
||
|
entry.startIndex = this->uniqueElements.Size();
|
||
|
entry.numElements = 1;
|
||
|
this->uniqueElements.Append(elm);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
*/
|
||
|
template<class TYPE> void
|
||
|
SparseTable<TYPE>::AddMultiple(IndexT colIndex, IndexT rowIndex, const TYPE* firstElm, SizeT numElms)
|
||
|
{
|
||
|
n_assert(this->inSetup);
|
||
|
TableEntry& entry = this->tableEntires.At(colIndex, rowIndex);
|
||
|
entry.startIndex = this->uniqueElements.Size();
|
||
|
entry.numElements = elms.Size();
|
||
|
IndexT i;
|
||
|
for (i = 0; i < numElms; i++)
|
||
|
{
|
||
|
this->uniqueElements.Append(firstElm[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
NOTE: forward references are not allowed!
|
||
|
*/
|
||
|
template<class TYPE> void
|
||
|
SparseTable<TYPE>::AddReference(IndexT colIndex, IndexT rowIndex, IndexT refColIndex, IndexT refRowIndex)
|
||
|
{
|
||
|
n_assert(this->inSetup);
|
||
|
n_assert((refColIndex <= colIndex) && (refRowIndex <= rowIndex));
|
||
|
TableEntry& entry = this->tableEntries.At(refColIndex, refRowIndex);
|
||
|
this->tableEntries.Set(colIndex, rowIndex, entry);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
*/
|
||
|
template<class TYPE> void
|
||
|
SparseTable<TYPE>::SetEntryDirect(IndexT colIndex, IndexT rowIndex, ushort startIndex, ushort numElements)
|
||
|
{
|
||
|
n_assert(this->inSetup);
|
||
|
TableEntry& entry = this->tableEntries.At(refColIndex, refRowIndex);
|
||
|
entry.startIndex = startIndex;
|
||
|
entry.numElements = numElements;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
*/
|
||
|
template<class TYPE> void
|
||
|
SparseTable<TYPE>::EndSetup()
|
||
|
{
|
||
|
n_assert(this->inSetup);
|
||
|
this->inSetup = false;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
*/
|
||
|
template<class TYPE> SizeT
|
||
|
SparseTable<TYPE>::GetNumColumns() const
|
||
|
{
|
||
|
return this->colIndexMap.Size();
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
*/
|
||
|
template<class TYPE> SizeT
|
||
|
SparseTable<TYPE>::GetNumRows() const
|
||
|
{
|
||
|
return this->rowIndexMap.Size();
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
*/
|
||
|
template<class TYPE> bool
|
||
|
SparseTable<TYPE>::HasColumn(const StringAtom& colName) const
|
||
|
{
|
||
|
return this->colIndexMap.Contains(colName);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
*/
|
||
|
template<class TYPE> bool
|
||
|
SparseTable<TYPE>::HasRow(const StringAtom& rowName) const
|
||
|
{
|
||
|
return this->rowIndexMap.Contains(rowName);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
*/
|
||
|
template<class TYPE> IndexT
|
||
|
SparseTable<TYPE>::GetColumnIndexByName(const StringAtom& colName) const
|
||
|
{
|
||
|
return this->colIndexMap[colName];
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
*/
|
||
|
template<class TYPE> IndexT
|
||
|
SparseTable<TYPE>::GetRowIndexByName(const StringAtom& rowName) const
|
||
|
{
|
||
|
return this->rowIndexMap[rowName];
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
*/
|
||
|
template<class TYPE> const TYPE*
|
||
|
SparseTable<TYPE>::GetElements(IndexT colIndex, IndexT rowIndex, SizeT& outNumElements) const
|
||
|
{
|
||
|
const TableEntry& tableEntry = this->tableEntries.At(colIndex, rowIndex);
|
||
|
if (tableEntry.numElements > 0)
|
||
|
{
|
||
|
const TYPE* elm = &(this->uniqueElements[tableEntry.startIndex]);
|
||
|
outNumElements = tableEntry.numElements;
|
||
|
return elm;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
outNumElements = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
*/
|
||
|
template<class TYPE> const TYPE*
|
||
|
SparseTable<TYPE>::LookupElements(const StringAtom& colName, const StringAtom& rowName, SizeT& outNumElements) const
|
||
|
{
|
||
|
IndexT colIndex = this->colIndexMap[colName];
|
||
|
IndexT rowIndex = this->rowIndexMap[rowName];
|
||
|
return this->GetElements(colIndex, rowIndex, outNumElements);
|
||
|
}
|
||
|
|
||
|
} // namespace Util
|
||
|
//------------------------------------------------------------------------------
|