/*- * Copyright 2005-2007 Guram Dukashvili * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ //--------------------------------------------------------------------------- #ifndef _table_H #define _table_H //----------------------------------------------------------------------------- namespace ksys { //----------------------------------------------------------------------------- /////////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------------- template > class Table { public: ~Table(); Table(); Table & clear(); Table & resize(uintptr_t rows, uintptr_t columns); Table & addRow(); Table & insertRow(uintptr_t row); Table & removeRow(uintptr_t row); Table & addColumn(const utf8::String & columnName = utf8::String()); Table & insertColumn(uintptr_t column, const utf8::String & columnName = utf8::String()); Table & removeColumn(uintptr_t column); const utf8::String & columnName(uintptr_t column) const; Table & columnName(uintptr_t column, const utf8::String & columnName); intptr_t columnIndex(const utf8::String & columnName) const; uintptr_t rowCount() const; uintptr_t columnCount() const; T & cell(uintptr_t row,uintptr_t column); Table & cell(uintptr_t row,uintptr_t column,const T & value); T & cell(uintptr_t row,const utf8::String & columnName); Table & cell(uintptr_t row,const utf8::String & columnName,const T & value); const T & cell(uintptr_t row,uintptr_t column) const; const T & cell(uintptr_t row,const utf8::String & columnName) const; T & operator ()(uintptr_t row,uintptr_t column); Table & operator ()(uintptr_t row,uintptr_t column,const T & value); T & operator ()(uintptr_t row,const utf8::String & columnName); Table & operator ()(uintptr_t row,const utf8::String & columnName,const T & value); const T & operator ()(uintptr_t row,uintptr_t column) const; const T & operator ()(uintptr_t row,const utf8::String & columnName) const; Mutant sum(uintptr_t column) const; Mutant sum(const utf8::String & columnName) const; protected: template class SortParam { public: const TT * table_; const P * param_; intptr_t (* const f_)(uintptr_t,uintptr_t,const P &); SortParam(const TT & table, const P & param, intptr_t(*const f)(uintptr_t, uintptr_t, const P &)) : table_(&table), param_(¶m), f_(f) {} private: SortParam(const SortParam &){} void operator = (const SortParam &){} }; template static intptr_t sortHelper(RRT * const & p1, RRT * const & p2, const SortParam< TT,P> & param) { return param.f_(&p1 - param.table_->rows_.ptr(), &p2 - param.table_->rows_.ptr(), *param.param_); } public: template Table & sort(intptr_t(*const f)(uintptr_t row1, uintptr_t row2, const P & param),const P & p) { SortParam,P> param(*this,p,f); intptr_t (*pSortHelper)(RT * const & p1,RT * const & p2,const SortParam< Table,P> & param); qSort(rows_.ptr(), 0, rows_.count() - 1, pSortHelper = sortHelper< RT,Table,P>, param); return *this; } protected: struct DSP { Table * table_; uintptr_t column_; bool descending_; }; template static intptr_t defaultSortFunction(uintptr_t row1,uintptr_t row2,const P & param){ intptr_t c = 0; for( uintptr_t i = 0; i < param.count(); i++ ){ c = param[i].table_->cell(row1,param[i].column_) < param[i].table_->cell(row2,param[i].column_) ? -1 : param[i].table_->cell(row1,param[i].column_) > param[i].table_->cell(row2,param[i].column_) ? 1 : 0; if( c != 0 ){ c = param[i].descending_ ? -c : c; break; } } return c; } public: Table & sort(const utf8::String & sortOrder){ Array param; param.resize(enumStringParts(sortOrder)); for( uintptr_t i = 0; i < param.count(); i++ ){ utf8::String order(stringPartByNo(sortOrder,i)); utf8::String::Iterator it(order); param[i].descending_ = false; if( it.getChar() == '+' ){ it++; } else if( it.getChar() == '-' ){ it++; param[i].descending_ = true; } param[i].column_ = columnIndex(it); param[i].table_ = this; } return sort(defaultSortFunction >,param); } protected: class Name2Index { public: utf8::String name_; uintptr_t index_; Name2Index(){} Name2Index(const utf8::String & name, uintptr_t index) : name_(name), index_(index) {} protected: private: }; Array name2Index_; Array index2Name_; Vector rows_; private: utf8::String genColumnName(const utf8::String & columnNameTemplate,uintptr_t & i,intptr_t & c) const; intptr_t name2Index(const utf8::String & columnName) const; uintptr_t name2Index(const utf8::String & columnName,intptr_t & c) const; }; //----------------------------------------------------------------------------- template inline Table::~Table() { } //----------------------------------------------------------------------------- template inline Table::Table() { } //----------------------------------------------------------------------------- template inline Table & Table::clear() { rows_.clear(); name2Index_.clear(); index2Name_.clear(); return *this; } //----------------------------------------------------------------------------- template #ifndef __BCPLUSPLUS__ inline #endif Table & Table::resize(uintptr_t rows, uintptr_t columns) { assert(rows >= 0 && columns >= 0); if( rows != rows_.count() ) rows_.resize(rows); while( columns < name2Index_.count() ) removeColumn(name2Index_.count() - 1); while( columns > name2Index_.count() ) addColumn(); return *this; } //----------------------------------------------------------------------------- template inline Table & Table::addRow() { rows_.add(RT().resize(name2Index_.count())); return *this; } //----------------------------------------------------------------------------- template inline Table & Table::insertRow(uintptr_t row) { rows_.insert(row, RT().resize(name2Index_.count())); return *this; } //----------------------------------------------------------------------------- template inline Table & Table::removeRow(uintptr_t row) { rows_.remove(row); return *this; } //----------------------------------------------------------------------------- template #ifndef __BCPLUSPLUS__ inline #endif utf8::String Table::genColumnName(const utf8::String & columnNameTemplate, uintptr_t & i, intptr_t & c) const { utf8::String cn(columnNameTemplate); i = name2Index(cn, c); if( c == 0 ){ if( cn.strlen() == 0 && name2Index_.count() > 0 ) cn = index2Name_[name2Index_.count() - 1]->name_; if( cn.strlen() == 0 || cn.strncmp("COLUMN_", 7) == 0 ) cn = "COLUMN"; for( i = name2Index_.count(); i < ~uintptr_t(0); i++ ){ utf8::String s (cn + "_" + utf8::int2Str((uintmax_t) i)); i = name2Index(s, c); if( c != 0 ){ cn = s; break; } } } return cn; } //----------------------------------------------------------------------------- template #ifndef __BCPLUSPLUS__ inline #endif Table & Table::addColumn(const utf8::String & columnName) { uintptr_t u; intptr_t c; utf8::String s(genColumnName(columnName,u,c)); name2Index_.insert(u += (c > 0),Name2Index(s,name2Index_.count())); index2Name_.add(&name2Index_[u]); for( intptr_t i = rows_.count() - 1; i >= 0; i-- ) rows_[i].resize(name2Index_.count()); return *this; } //----------------------------------------------------------------------------- template #ifndef __BCPLUSPLUS__ inline #endif Table & Table::insertColumn(uintptr_t column, const utf8::String & columnName) { intptr_t i, c; utf8::String s (genColumnName(columnName, i, c)); name2Index_.insert(i += (c > 0), Name2Index(s, column)); index2Name_.insert(column, &name2Index_[i]); for( i = rows_.count() - 1; i >= 0; i-- ) rows_[i].insert(column, T()); return *this; } //----------------------------------------------------------------------------- template #ifndef __BCPLUSPLUS__ inline #endif Table & Table::removeColumn(uintptr_t column) { uintptr_t i; for( i = rows_.count() - 1; i >= 0; i-- ) rows_[i].remove(column); name2Index_.remove(index2Name_[column]); index2Name_.remove(column); return *this; } //----------------------------------------------------------------------------- template inline const utf8::String & Table::columnName(uintptr_t column) const { assert((uintptr_t) column < (uintptr_t) name2Index_.count()); return index2Name_[column]->name_; } //----------------------------------------------------------------------------- template #ifndef __BCPLUSPLUS__ inline #endif Table & Table::columnName(uintptr_t column, const utf8::String & columnName) { assert((uintptr_t) column < (uintptr_t) name2Index_.count()); intptr_t c, i = name2Index(columnName, c); if( c != 0 ){ name2Index_.remove(index2Name_[column]); i = name2Index(columnName, c); name2Index_.insert(i += (c > 0), Name2Index(columnName, column)); index2Name_[column] = &name2Index_[i]; } return *this; } //----------------------------------------------------------------------------- template #ifndef __BCPLUSPLUS__ inline #endif intptr_t Table::name2Index(const utf8::String & columnName) const { intptr_t c, low = 0, high = name2Index_.count() - 1, pos ; while( low <= high ){ pos = (low + high) / 2; c = columnName.strcasecmp(name2Index_[pos].name_); if( c > 0 ){ low = pos + 1; } else if( c < 0 ){ high = pos - 1; } else return pos; } return -1; } //----------------------------------------------------------------------------- template #ifndef __BCPLUSPLUS__ inline #endif uintptr_t Table::name2Index(const utf8::String & columnName, intptr_t & c) const { intptr_t low = 0, high = name2Index_.count() - 1, pos = -1; c = 1; while( low <= high ){ pos = (low + high) / 2; c = columnName.strcasecmp(name2Index_[pos].name_); if( c > 0 ){ low = pos + 1; } else if( c < 0 ){ high = pos - 1; } else break; } return pos; } //----------------------------------------------------------------------------- template inline intptr_t Table::columnIndex(const utf8::String & columnName) const { intptr_t i = name2Index(columnName); if( i >= 0 ) i = name2Index_[i].index_; return i; } //----------------------------------------------------------------------------- template inline uintptr_t Table::rowCount() const { return rows_.count(); } //----------------------------------------------------------------------------- template inline uintptr_t Table::columnCount() const { return name2Index_.count(); } //----------------------------------------------------------------------------- template inline T & Table::cell(uintptr_t row, uintptr_t column) { assert(row < rows_.count() && column < name2Index_.count()); return rows_[row][column]; } //----------------------------------------------------------------------------- template inline Table & Table::cell(uintptr_t row, uintptr_t column,const T & value) { assert(row < rows_.count() && column < name2Index_.count()); rows_[row][column] = value; return *this; } //----------------------------------------------------------------------------- template inline T & Table::cell(uintptr_t row, const utf8::String & columnName) { uintptr_t column = columnIndex(columnName); assert(row < rows_.count() && column < name2Index_.count()); return rows_[row][column]; } //----------------------------------------------------------------------------- template inline Table & Table::cell(uintptr_t row, const utf8::String & columnName,const T & value) { uintptr_t column = columnIndex(columnName); assert(row < rows_.count() && column < name2Index_.count()); rows_[row][column] = value; return *this; } //----------------------------------------------------------------------------- template inline const T & Table::cell(uintptr_t row, uintptr_t column) const { assert(row < rows_.count() && column < name2Index_.count()); return rows_[row][column]; } //----------------------------------------------------------------------------- template inline const T & Table::cell(uintptr_t row, const utf8::String & columnName) const { uintptr_t column = columnIndex(columnName); assert(row < rows_.count() && column < name2Index_.count()); return rows_[row][column]; } //----------------------------------------------------------------------------- template inline T & Table::operator ()(uintptr_t row, uintptr_t column) { return cell(row, column); } //----------------------------------------------------------------------------- template inline Table & Table::operator ()(uintptr_t row, uintptr_t column,const T & value) { return cell(row,column,value); } //----------------------------------------------------------------------------- template inline T & Table::operator ()(uintptr_t row, const utf8::String & columnName) { return cell(row, columnName); } //----------------------------------------------------------------------------- template inline Table & Table::operator ()(uintptr_t row, const utf8::String & columnName,const T & value) { return cell(row,columnName,value); } //----------------------------------------------------------------------------- template inline const T & Table::operator ()(uintptr_t row, uintptr_t column) const { return cell(row, column); } //----------------------------------------------------------------------------- template inline const T & Table::operator ()(uintptr_t row, const utf8::String & columnName) const { return cell(row,columnName); } //----------------------------------------------------------------------------- template inline Mutant Table::sum(uintptr_t column) const { assert( column < name2Index_.count() ); Mutant summa = 0; for( intptr_t row = rows_.count() - 1; row >= 0; row-- ){ Mutant a = rows_[row][column]; if( summa.type() == mtFloat || a.type() == mtFloat ) #if HAVE_LONG_DOUBLE summa = (long double) summa + (long double) a; #else summa = (double) summa + (double) a; #endif else summa = intmax_t(summa) + intmax_t(a); } return summa; } //----------------------------------------------------------------------------- template inline Mutant Table::sum(const utf8::String & columnName) const { return sum(columnIndex(columnName)); } //----------------------------------------------------------------------------- } // namespace ksys //----------------------------------------------------------------------------- #endif //-----------------------------------------------------------------------------