#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 SparseTable { public: /// constructor SparseTable(); /// setup the sparse table void BeginSetup(const Array& columnNames, const Array& 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 uniqueElements; FixedTable tableEntries; Dictionary colIndexMap; Dictionary rowIndexMap; bool inSetup; }; //------------------------------------------------------------------------------ /** */ template SparseTable::SparseTable() : inSetup(false) { // empty } //------------------------------------------------------------------------------ /** */ template void SparseTable::Clear() { n_assert(!this->inSetup); this->uniqueElements.Clear(); this->tableEntries.SetSize(0, 0); this->colIndexMap.Clear(); this->rowIndexMap.Clear(); } //------------------------------------------------------------------------------ /** */ template void SparseTable::BeginSetup(const Array& columnNames, const Array& 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 void SparseTable::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 void SparseTable::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 void SparseTable::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 void SparseTable::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 void SparseTable::EndSetup() { n_assert(this->inSetup); this->inSetup = false; } //------------------------------------------------------------------------------ /** */ template SizeT SparseTable::GetNumColumns() const { return this->colIndexMap.Size(); } //------------------------------------------------------------------------------ /** */ template SizeT SparseTable::GetNumRows() const { return this->rowIndexMap.Size(); } //------------------------------------------------------------------------------ /** */ template bool SparseTable::HasColumn(const StringAtom& colName) const { return this->colIndexMap.Contains(colName); } //------------------------------------------------------------------------------ /** */ template bool SparseTable::HasRow(const StringAtom& rowName) const { return this->rowIndexMap.Contains(rowName); } //------------------------------------------------------------------------------ /** */ template IndexT SparseTable::GetColumnIndexByName(const StringAtom& colName) const { return this->colIndexMap[colName]; } //------------------------------------------------------------------------------ /** */ template IndexT SparseTable::GetRowIndexByName(const StringAtom& rowName) const { return this->rowIndexMap[rowName]; } //------------------------------------------------------------------------------ /** */ template const TYPE* SparseTable::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 const TYPE* SparseTable::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 //------------------------------------------------------------------------------