#include <stdlib.h>
#include "TTableSorter.h"
#include "TTable.h"
#include "TClass.h"
#include "TDataMember.h"
#include "TDataType.h"
#include "TMemberInspector.h"
extern "C" {
typedef Int_t (*CALLQSORT) (const void *, const void *);
}
ClassImp(TTableSorter)
TTableSorter::TTableSorter() : fsimpleArray(0),fParentTable(0)
{
fLastFound = -1;
fFirstRow = 0;
fSortIndex = 0;
fSearchMethod = 0;
fNumberOfRows = 0;
fColType = TTable::kNAN;
fsimpleArray = 0;
fParentRowSize = 0;
fFirstParentRow = 0;
fCompareMethod = 0;
fIndexArray = 0;
fColDimensions = 0;
fColOffset = 0;
fColSize = 0;
}
TTableSorter::TTableSorter(const TTable &table, TString &colName,Int_t firstRow
,Int_t numberRows):fsimpleArray(0),fParentTable(&table)
{
fCompareMethod = 0;
fSearchMethod = 0;
BuildSorter(colName, firstRow, numberRows);
}
TTableSorter::TTableSorter(const TTable *table, TString &colName,Int_t firstRow
,Int_t numberRows):fsimpleArray(0),fParentTable(table)
{
fCompareMethod = 0;
fSearchMethod = 0;
BuildSorter(colName, firstRow, numberRows);
}
TTableSorter::TTableSorter(const TTable &table, SEARCHMETHOD search,
COMPAREMETHOD compare, Int_t firstRow,Int_t numberRows)
:fsimpleArray(0),fParentTable(&table)
{
fCompareMethod = compare;
fSearchMethod = search;
TString colName = "user's defined";
BuildSorter(colName, firstRow, numberRows);
}
TTableSorter::TTableSorter(const TTable *table, SEARCHMETHOD search,
COMPAREMETHOD compare, Int_t firstRow,Int_t numberRows)
:fsimpleArray(0),fParentTable(table)
{
fCompareMethod = compare;
fSearchMethod = search;
TString colName = "user's defined";
BuildSorter(colName, firstRow, numberRows);
}
void TTableSorter::BuildSorter(TString &colName, Int_t firstRow, Int_t numberRows)
{
assert(fParentTable!=0);
fLastFound = -1;
fNumberOfRows = 0;
fColType = TTable::kNAN;
fsimpleArray = 0;
fSortIndex = 0;
fColDimensions = 0;
fColOffset = 0;
TString n = fParentTable->GetName();
n += ".";
n += colName;
SetName(n);
Char_t *name = (Char_t *) colName.Data();
if (!(name || strlen(colName.Data()))) { MakeZombie(); delete [] name; return; }
name = StrDup(colName.Data());
if (firstRow > fParentTable->GetNRows()) { MakeZombie(); delete [] name; return; }
fFirstRow = firstRow;
fNumberOfRows = fParentTable->GetNRows()- fFirstRow;
if (numberRows > 0) fNumberOfRows = TMath::Min(numberRows,fNumberOfRows);
fParentRowSize = fParentTable->GetRowSize();
fFirstParentRow= (const char *)fParentTable->GetArray();
if (fNumberOfRows <=0 ) { MakeZombie(); delete [] name; return; }
fSortIndex = new void*[fNumberOfRows];
Char_t *br = name - 1;
while((br = strchr(br+1,'['))) {
if (!fColDimensions) *br = 0;
fColDimensions++;
}
fColName = name;
delete [] name;
fIndexArray = 0;
if (fColDimensions) {
fIndexArray = new Int_t[fColDimensions];
memset(fIndexArray,0,fColDimensions*sizeof(Int_t));
const char *openBracket = colName.Data()-1;
const char *closeBracket = colName.Data()-1;
for (Int_t i=0; i< fColDimensions; i++) {
openBracket = strchr(openBracket+1, '[');
closeBracket = strchr(closeBracket+1,']');
if (closeBracket > openBracket)
fIndexArray[i] = atoi(openBracket+1);
else {
Error("TTable ctor", "Wrong parethethis <%s>",colName.Data());
MakeZombie();
return;
}
}
}
if (colName != "user's defined") {
LearnTable();
SetSearchMethod();
}
if (!FillIndexArray()) QSort();
}
TTableSorter::TTableSorter(const Float_t *simpleArray, Int_t arraySize, Int_t firstRow
,Int_t numberRows)
:fsimpleArray((const Char_t*)simpleArray)
,fParentTable(0)
{
fLastFound = -1;
SetSimpleArray(arraySize,firstRow,numberRows);
if (!fsimpleArray) { MakeZombie(); return; }
fColName = "Float";
fColType = TTable::kFloat;
fColSize = sizeof(Float_t);
fParentRowSize = fColSize;
Float_t *p = ((Float_t *)fsimpleArray) + fFirstRow;
Bool_t isPreSorted = kTRUE;
Float_t sample = *p;
for (Int_t i=0; i < fNumberOfRows;i++,p++) {
fSortIndex[i-fFirstRow] = p;
if ( isPreSorted) {
if (sample > *p) isPreSorted = kFALSE;
else sample = *p;
}
}
SetSearchMethod();
if (!isPreSorted) QSort();
}
TTableSorter::TTableSorter(const Double_t *simpleArray, Int_t arraySize, Int_t firstRow
,Int_t numberRows)
:fsimpleArray((const Char_t*)simpleArray)
,fParentTable(0)
{
fLastFound = -1;
SetSimpleArray(arraySize,firstRow,numberRows);
if (!fsimpleArray) {MakeZombie(); return; }
fColName = "Double";
fColType = TTable::kDouble;
fColSize = sizeof(Double_t);
fParentRowSize = fColSize;
Double_t *p = ((Double_t *)simpleArray) + fFirstRow;
Bool_t isPreSorted = kTRUE;
Double_t sample = *p;
for (Int_t i=0; i < fNumberOfRows;i++,p++) {
fSortIndex[i-fFirstRow] = p;
if ( isPreSorted) {
if (sample > *p) isPreSorted = kFALSE;
else sample = *p;
}
}
SetSearchMethod();
if (!isPreSorted) QSort();
}
TTableSorter::TTableSorter(const Long_t *simpleArray, Int_t arraySize, Int_t firstRow
,Int_t numberRows)
:fsimpleArray((const Char_t*)simpleArray)
,fParentTable(0)
{
fLastFound = -1;
SetSimpleArray(arraySize,firstRow,numberRows);
if (!simpleArray) { MakeZombie(); return; }
fColName = "Long";
fColType = TTable::kLong;
fColSize = sizeof(Long_t);
fParentRowSize = fColSize;
Long_t *p = ((Long_t *)simpleArray) + fFirstRow;
Bool_t isPreSorted = kTRUE;
Long_t sample = *p;
for (Int_t i=0; i < fNumberOfRows;i++,p++) {
fSortIndex[i-fFirstRow] = p;
if ( isPreSorted) {
if (sample > *p) isPreSorted = kFALSE;
else sample = *p;
}
}
SetSearchMethod();
if (!isPreSorted) QSort();
}
void TTableSorter::SetSimpleArray(Int_t arraySize, Int_t firstRow,Int_t numberRows)
{
SetName("Array");
fSortIndex = 0;
fSearchMethod = 0;
fColDimensions = 0;
fIndexArray = 0;
fColOffset = 0;
if (firstRow > arraySize) return;
fFirstRow = firstRow;
fNumberOfRows = arraySize - fFirstRow;
if (numberRows > 0) fNumberOfRows = TMath::Min(numberRows,fNumberOfRows);
if (fNumberOfRows > 0) fSortIndex = new void*[fNumberOfRows];
}
TTableSorter::~TTableSorter()
{
if (fSortIndex) delete [] fSortIndex; fSortIndex = 0; fNumberOfRows=0;
}
#define BINARYSEARCH(valuetype) Int_t TTableSorter::BinarySearch(valuetype value) const {\
switch (fColType) { \
case TTable::kFloat: \
return SelectSearch(Float_t(value)); \
case TTable::kInt : \
return SelectSearch(Int_t(value)); \
case TTable::kLong : \
return SelectSearch(Long_t(value)); \
case TTable::kShort : \
return SelectSearch(Short_t(value)); \
case TTable::kDouble : \
return SelectSearch(Double_t(value)); \
case TTable::kUInt: \
return SelectSearch(UInt_t(value)); \
case TTable::kULong : \
return SelectSearch(ULong_t(value)); \
case TTable::kUShort: \
return SelectSearch(UShort_t(value)); \
case TTable::kBool: \
return SelectSearch(Bool_t(value)); \
case TTable::kUChar: \
return SelectSearch(UChar_t(value)); \
case TTable::kChar: \
return SelectSearch(Char_t(value)); \
default: \
return -1; \
break; \
}; \
} \
Int_t TTableSorter::BSearch(valuetype value) const{ \
union { Bool_t Bool; \
Char_t Char; \
UChar_t UChar; \
Short_t Short; \
UShort_t UShort; \
Int_t Int; \
UInt_t UInt; \
Long_t Long; \
ULong_t ULong; \
Float_t Float; \
Double_t Double; \
} value_; \
\
switch (fColType) { \
case TTable::kFloat: \
value_.Float = Float_t(value); break; \
case TTable::kInt : \
value_.Int = Int_t(value); break; \
case TTable::kLong : \
value_.Long = Long_t(value); break; \
case TTable::kShort : \
value_.Short = Short_t(value); break; \
case TTable::kDouble : \
value_.Double= Double_t(value);break; \
case TTable::kUInt: \
value_.UInt = UInt_t(value); break; \
case TTable::kULong : \
value_.ULong = ULong_t(value); break; \
case TTable::kUShort: \
value_.UShort= UShort_t(value);break; \
case TTable::kUChar: \
value_.UChar = UChar_t(value); break; \
case TTable::kChar: \
value_.Char = Char_t(value); break; \
case TTable::kBool: \
value_.Bool = Bool_t(value); break; \
default: \
return -1; \
break; \
}; \
return BSearch(&value_); \
} \
Int_t TTableSorter::SelectSearch(valuetype value) const { \
valuetype **array = (valuetype **)fSortIndex; \
Int_t nabove, nbelow, middle; \
nabove = fNumberOfRows+1; \
nbelow = 0; \
while(nabove-nbelow > 1) { \
middle = (nabove+nbelow)/2; \
if (value == *array[middle-1]) { nbelow = middle; break; } \
if (value < *array[middle-1]) nabove = middle; \
else nbelow = middle; \
} \
nbelow--; \
((TTableSorter *)this)->fLastFound = nbelow; \
if (nbelow < 0) return nbelow; \
return GetIndex(nbelow); \
}
#define COMPAREFLOATVALUES(valuetype) \
int TTableSorter::Search##valuetype (const void *elem1, const void **elem2) { \
valuetype *value1 = (valuetype *)(elem1); \
valuetype *value2 = (valuetype *)(*elem2); \
valuetype diff = *value1-*value2; \
Int_t res = 0; \
if (diff > 0) res = 1; \
else if (diff < 0) res = -1; \
return res; \
} \
int TTableSorter::Compare##valuetype (const void **elem1, const void **elem2) {\
valuetype *value1 = (valuetype *)(*elem1); \
valuetype *value2 = (valuetype *)(*elem2); \
valuetype diff = *value1-*value2; \
Int_t res = 0; \
if (diff > 0 ) res = 1; \
else if (diff < 0) res = -1; \
if (res) return res; \
return int(value1-value2); \
} \
BINARYSEARCH(valuetype)
#define COMPAREVALUES(valuetype) \
int TTableSorter::Search##valuetype (const void *elem1, const void **elem2) { \
valuetype *value1 = (valuetype *)(elem1); \
valuetype *value2 = (valuetype *)(*elem2); \
return int(*value1-*value2); \
} \
int TTableSorter::Compare##valuetype (const void **elem1, const void **elem2) { \
valuetype *value1 = (valuetype *)(*elem1); \
valuetype *value2 = (valuetype *)(*elem2); \
valuetype diff = *value1-*value2; \
if (diff ) return diff; \
return int(value1-value2); \
} \
BINARYSEARCH(valuetype)
COMPAREFLOATVALUES(Float_t)
COMPAREVALUES(Int_t)
COMPAREVALUES(Long_t)
COMPAREVALUES(ULong_t)
COMPAREVALUES(UInt_t)
COMPAREVALUES(Short_t)
COMPAREFLOATVALUES(Double_t)
COMPAREVALUES(UShort_t)
COMPAREVALUES(UChar_t)
COMPAREVALUES(Char_t)
COMPAREVALUES(Bool_t)
#define COMPAREORDER(valuetype) Compare##valuetype
#define SEARCHORDER(valuetype) Search##valuetype
Int_t TTableSorter::BSearch(const void *value) const
{
Int_t index = -1;
if (fSearchMethod) {
void **p = (void **)::bsearch((void *) value,
fSortIndex,
fNumberOfRows,
sizeof(void *),
CALLQSORT(fSearchMethod));
((TTableSorter *)this)->fLastFound = -1;
if (p) {
const Char_t *res = (const Char_t *)(*p);
((TTableSorter *)this)->fLastFound = ((Char_t *)p - (Char_t *)fSortIndex)/sizeof(void *);
if (!fsimpleArray)
index = fFirstRow + (res - (At(fFirstRow)+ fColOffset))/fParentRowSize;
else
index = ULong_t(res) - ULong_t(fsimpleArray)/fColSize;
}
}
return index;
}
Int_t TTableSorter::GetIndex(UInt_t sortedIndex) const
{
Int_t indx = -1;
if (sortedIndex < UInt_t(fNumberOfRows) ) {
void *p = fSortIndex[sortedIndex];
if (p) {
const Char_t *res = (const Char_t *)p;
if (!fsimpleArray)
indx = fFirstRow + (res - (At(fFirstRow) + fColOffset))/fParentRowSize;
else
indx = (ULong_t(res) - ULong_t(fsimpleArray))/fColSize;
}
}
return indx;
}
#if 0
int TTableSorter::CompareUChar (const void *elem1, const void *elem2)
{
UChar_t *value1 = (UChar_t *)(*elem1);
UChar_t *value2 = (UChar_t *)(*elem2);
COMPAREVALUES(value1,value2)
}
int TTableSorter::CompareChar (const void *elem1, const void *elem2)
{
Char_t *value1 = (Char_t *)(*elem1);
Char_t *value2 = (Char_t *)(*elem2);
COMPAREVALUES(value1,value2)
}
#endif
Int_t TTableSorter::CountKey(const void *key, Int_t firstIndx, Bool_t bSearch, Int_t *firstRow) const
{
Int_t count = 0;
if (firstRow) *firstRow = -1;
if (fSearchMethod) {
Int_t indx = firstIndx;
Int_t nRows = GetNRows();
if (!bSearch) {
while ( indx < nRows && fSearchMethod(key,(const void **)&fSortIndex[indx])){indx++;}
} else {
indx = FindFirstKey(key);
if (indx >= 0 ) {
count = TMath::Max(0,GetLastFound() - indx + 1);
indx = TMath::Max(GetLastFound()+1,firstIndx);
}
}
if (indx >= 0) {
while ( indx < nRows &&!fSearchMethod(key,(const void **)&fSortIndex[indx])){indx++; count++;}
if (firstRow && count) *firstRow = indx-count;
}
}
return count;
}
Int_t TTableSorter::CountKeys() const
{
Int_t count = 0;
if (fSortIndex && fSortIndex[0]) {
void *key = fSortIndex[0];
Int_t indx = 0;
while (indx < GetNRows()){
indx += CountKey(key,indx,kFALSE);
count++;
key = fSortIndex[indx];
}
}
return count;
}
Bool_t TTableSorter::FillIndexArray(){
assert(fSortIndex!=0);
const char *row = At(fFirstRow) + fColOffset;
Bool_t isPreSorted = kTRUE;
const void *sample = row;
for (Int_t i=fFirstRow; i < fFirstRow+fNumberOfRows;i++,row += fParentRowSize) {
fSortIndex[i-fFirstRow] = (char *)row;
if ( isPreSorted) {
void *ptr = &row;
if (fCompareMethod(&sample,(const void **)ptr)>0) isPreSorted = kFALSE;
else sample = row;
}
}
return isPreSorted;
}
Int_t TTableSorter::FindFirstKey(const void *key) const
{
Int_t indx = -1;
if (BSearch(key)>=0) {
indx = GetLastFound();
if (indx >=0)
while (indx > 0 && !fSearchMethod(key,(const void **)&fSortIndex[indx-1])) indx--;
}
return indx;
}
const char * TTableSorter::GetTableName() const
{
return fParentTable ? fParentTable->GetName():"";
}
const char * TTableSorter::GetTableTitle() const
{
return fParentTable ? fParentTable->GetTitle():"";
}
const char * TTableSorter::GetTableType() const
{
return fParentTable ? fParentTable->GetType():"";
}
TTable *TTableSorter::GetTable() const
{
return (TTable *)fParentTable;
}
void TTableSorter::SetSearchMethod()
{
if (!fSearchMethod) {
switch (fColType) {
case TTable::kFloat:
fSearchMethod = SEARCHORDER(Float_t);
fCompareMethod = COMPAREORDER(Float_t);
break;
case TTable::kInt :
fSearchMethod = SEARCHORDER(Int_t);
fCompareMethod = COMPAREORDER(Int_t);
break;
case TTable::kLong :
fSearchMethod = SEARCHORDER(Long_t);
fCompareMethod = COMPAREORDER(Long_t);
break;
case TTable::kShort :
fSearchMethod = SEARCHORDER(Short_t);
fCompareMethod = COMPAREORDER(Short_t);
break;
case TTable::kDouble :
fSearchMethod = SEARCHORDER(Double_t);
fCompareMethod = COMPAREORDER(Double_t);
break;
case TTable::kUInt:
fSearchMethod = SEARCHORDER(UInt_t);
fCompareMethod = COMPAREORDER(UInt_t);
break;
case TTable::kULong :
fSearchMethod= SEARCHORDER(ULong_t);
fCompareMethod = COMPAREORDER(ULong_t);
break;
case TTable::kUShort:
fSearchMethod = SEARCHORDER(UShort_t);
fCompareMethod = COMPAREORDER(UShort_t);
break;
case TTable::kUChar:
fSearchMethod = SEARCHORDER(UChar_t);
fCompareMethod = COMPAREORDER(UChar_t);
break;
case TTable::kChar:
fSearchMethod = SEARCHORDER(Char_t);
fCompareMethod = COMPAREORDER(Char_t);
break;
case TTable::kBool:
fSearchMethod = SEARCHORDER(Bool_t);
fCompareMethod = COMPAREORDER(Bool_t);
break;
default:
break;
};
}
}
void TTableSorter::QSort(){
if (fCompareMethod)
::qsort(fSortIndex,
fNumberOfRows,
sizeof(void *),
CALLQSORT(fCompareMethod));
}
void TTableSorter::LearnTable()
{
TClass *classPtr = fParentTable->GetRowClass();
if (!classPtr) return;
if (!classPtr->GetListOfRealData()) classPtr->BuildRealData();
if (!(classPtr->GetNdata())) return;
const Char_t *types;
Char_t *varname;
TIter next(classPtr->GetListOfDataMembers());
TDataMember *member = 0;
while ( (member = (TDataMember *) next()) ) {
varname = (Char_t *) member->GetName();
if (strcmp(varname,fColName.Data())) continue;
TDataType *memberType = member->GetDataType();
types = memberType->GetTypeName();
SetTitle(types);
if (!strcmp("float", types))
fColType = TTable::kFloat ;
else if (!strcmp("int", types))
fColType = TTable::kInt ;
else if (!strcmp("long", types))
fColType = TTable::kLong ;
else if (!strcmp("short", types))
fColType = TTable::kShort ;
else if (!strcmp("double", types))
fColType = TTable::kDouble;
else if (!strcmp("unsigned int", types))
fColType = TTable::kUInt ;
else if (!strcmp("unsigned long", types))
fColType = TTable::kULong ;
else if (!strcmp("unsigned short", types))
fColType = TTable::kUShort;
else if (!strcmp("unsigned char", types))
fColType = TTable::kUChar;
else if (!strcmp("char", types))
fColType= TTable::kChar;
else if (!strcmp("bool", types))
fColType= TTable::kBool;
if (fColType != TTable::kNAN) {
Int_t dim = 0;
Int_t globalIndex = 0;
if ( (dim = member->GetArrayDim()) ) {
if (dim != fColDimensions) {
Error("LearnTable","Wrong dimension");
TTable *t = (TTable *)fParentTable;
t->Print();
return;
}
for( Int_t indx=0; indx < fColDimensions; indx++ ){
globalIndex *= member->GetMaxIndex(indx);
globalIndex += fIndexArray[indx];
}
}
fColSize = memberType->Size();
fColOffset = member->GetOffset() + memberType->Size() * globalIndex;
}
break;
}
}
#undef COMPAREVALUES
#undef COMPAREORDER
#undef COMPAREFLOATVALUES
#undef BINARYSEARCH