/************* Array C++ Functions Source Code File (.CPP) *************/ /* Name: ARRAY.CPP Version 2.3 */ /* */ /* (C) Copyright to the author Olivier BERTRAND 2005-2019 */ /* */ /* This file contains the XOBJECT derived class ARRAY functions. */ /* ARRAY is used for elaborate type of processing, such as sorting */ /* and dichotomic search (Find). This new version does not use sub */ /* classes anymore for the different types but relies entirely on the */ /* functionalities provided by the VALUE and VALBLK classes. */ /* Currently the only supported types are STRING, SHORT, int, DATE, */ /* TOKEN, DOUBLE, and Compressed Strings. */ /***********************************************************************/
/***********************************************************************/ /* MakeValueArray: Makes a value array from a value list. */ /***********************************************************************/
PARRAY MakeValueArray(PGLOBAL g, PPARM pp)
{ int n, valtyp = 0;
size_t len = 0;
PARRAY par;
PPARM parmp;
if (!pp) return NULL;
/*********************************************************************/ /* New version with values coming in a list. */ /*********************************************************************/ if ((valtyp = pp->Type) != TYPE_STRING)
len = 1;
xtrc(1, "valtyp=%d len=%d\n", valtyp, len);
/*********************************************************************/ /* Firstly check the list and count the number of values in it. */ /*********************************************************************/ for (n = 0, parmp = pp; parmp; n++, parmp = parmp->Next) if (parmp->Type != valtyp) {
snprintf(g->Message, sizeof(g->Message), MSG(BAD_PARAM_TYPE), "MakeValueArray", parmp->Type); return NULL;
} elseif (valtyp == TYPE_STRING)
len = MY_MAX(len, strlen((char*)parmp->Value));
/*********************************************************************/ /* Make an array object with one block of the proper size. */ /*********************************************************************/
par = new(g) ARRAY(g, valtyp, n, (int)len);
if (par->GetResultType() == TYPE_ERROR) return NULL; // Memory allocation error in ARRAY
/*********************************************************************/ /* All is right now, fill the array block. */ /*********************************************************************/ for (parmp = pp; parmp; parmp = parmp->Next) switch (valtyp) { case TYPE_STRING:
par->AddValue(g, (PSZ)parmp->Value); break; case TYPE_SHORT:
par->AddValue(g, *(short*)parmp->Value); break; case TYPE_INT:
par->AddValue(g, *(int*)parmp->Value); break; case TYPE_DOUBLE:
par->AddValue(g, *(double*)parmp->Value); break; case TYPE_PCHAR:
par->AddValue(g, parmp->Value); break; case TYPE_VOID: // Integer stored inside pp->Value
par->AddValue(g, parmp->Intval); break;
} // endswitch valtyp
/*********************************************************************/ /* Send back resulting array. */ /*********************************************************************/ return par;
} // end of MakeValueArray
/* -------------------------- Class ARRAY ---------------------------- */
/***********************************************************************/ /* ARRAY public constructor. */ /***********************************************************************/
ARRAY::ARRAY(PGLOBAL g, int type, int size, int length, int prec)
: CSORT(false)
{
Nval = 0;
Ndif = 0;
Bot = 0;
Top = 0;
Size = size;
Type = type;
Xsize = -1;
Len = 1;
X = 0;
Inf = 0;
Sup = 0;
switch (type) { case TYPE_STRING:
Len = length; /* fall through */ case TYPE_SHORT: case TYPE_INT: case TYPE_DOUBLE: case TYPE_PCHAR:
Type = type; break; case TYPE_VOID:
Type = TYPE_INT; break; #if0 case TYPE_TOKEN: break; case TYPE_LIST:
Len = 0;
prec = length; break; #endif// 0 default: // This is illegal an causes an ill formed array building
snprintf(g->Message, sizeof(g->Message), MSG(BAD_ARRAY_TYPE), type);
Type = TYPE_ERROR; return;
} // endswitch type
Valblk = new(g) MBVALS;
if (!(Vblp = Valblk->Allocate(g, Type, Len, prec, Size)))
Type = TYPE_ERROR; elseif (!Valblk->GetMemp() && Type != TYPE_LIST) // The error message was built by PlgDBalloc
Type = TYPE_ERROR; elseif (type != TYPE_PCHAR)
Value = AllocateValue(g, type, Len, prec);
Constant = true;
} // end of ARRAY constructor
#if0 /***********************************************************************/ /* ARRAY public constructor from a QUERY. */ /***********************************************************************/
ARRAY::ARRAY(PGLOBAL g, PQUERY qryp) : CSORT(false)
{
Type = qryp->GetColType(0);
Nval = qryp->GetNblin();
Ndif = 0;
Bot = 0;
Top = 0;
Size = Nval;
Xsize = -1;
Len = qryp->GetColLength(0);
X = Inf = Sup = 0;
Correlated = false;
switch (Type) { case TYPE_STRING: case TYPE_SHORT: case TYPE_INT: case TYPE_DATE: case TYPE_DOUBLE: // case TYPE_TOKEN: // case TYPE_LIST: // Valblk = qryp->GetCol(0)->Result; // Vblp = qryp->GetColBlk(0); // Value = qryp->GetColValue(0); // break; default: // This is illegal an causes an ill formed array building
snprintf(g->Message, sizeof(g->Message), MSG(BAD_ARRAY_TYPE), Type);
Type = TYPE_ERROR;
} // endswitch type
if (!Valblk || (!Valblk->GetMemp() && Type != TYPE_LIST)) // The error message was built by ???
Type = TYPE_ERROR;
Constant = true;
} // end of ARRAY constructor
/***********************************************************************/ /* ARRAY constructor from a TYPE_LIST subarray. */ /***********************************************************************/
ARRAY::ARRAY(PGLOBAL g, PARRAY par, int k) : CSORT(false)
{ int prec;
LSTBLK *lp;
if (par->Type != TYPE_LIST) {
Type = TYPE_ERROR; return;
} // endif Type
Valblk = lp->Mbvk[k];
Vblp = Valblk->Vblk;
Type = Vblp->GetType();
Len = (Type == TYPE_STRING) ? Vblp->GetVlen() : 0;
prec = (Type == TYPE_FLOAT) ? 2 : 0;
Value = AllocateValue(g, Type, Len, prec, NULL);
Constant = true;
} // end of ARRAY constructor
/***********************************************************************/ /* Empty: reset the array for a new use (correlated queries). */ /* Note: this is temporary as correlated queries will not use arrays */ /* anymore with future optimized algorithms. */ /***********************************************************************/ void ARRAY::Empty(void)
{
assert(Correlated);
Nval = Ndif = 0;
Bot = Top = X = Inf = Sup = 0;
} // end of Empty #endif// 0
/***********************************************************************/ /* Add a string element to an array. */ /***********************************************************************/ bool ARRAY::AddValue(PGLOBAL g, PSZ strp)
{ if (Type != TYPE_STRING) {
snprintf(g->Message, sizeof(g->Message), MSG(ADD_BAD_TYPE), GetTypeName(Type), "CHAR"); returntrue;
} // endif Type
xtrc(1, " adding string(%d): '%s'\n", Nval, strp);
Vblp->SetValue(strp, Nval++); returnfalse;
} // end of AddValue
/***********************************************************************/ /* Add a char pointer element to an array. */ /***********************************************************************/ bool ARRAY::AddValue(PGLOBAL g, void *p)
{ if (Type != TYPE_PCHAR) {
snprintf(g->Message, sizeof(g->Message), MSG(ADD_BAD_TYPE), GetTypeName(Type), "PCHAR"); returntrue;
} // endif Type
xtrc(1, " adding pointer(%d): %p\n", Nval, p);
Vblp->SetValue((PSZ)p, Nval++); returnfalse;
} // end of AddValue
/***********************************************************************/ /* Add a short integer element to an array. */ /***********************************************************************/ bool ARRAY::AddValue(PGLOBAL g, short n)
{ if (Type != TYPE_SHORT) {
snprintf(g->Message, sizeof(g->Message), MSG(ADD_BAD_TYPE), GetTypeName(Type), "SHORT"); returntrue;
} // endif Type
xtrc(1, " adding SHORT(%d): %hd\n", Nval, n);
Vblp->SetValue(n, Nval++); returnfalse;
} // end of AddValue
/***********************************************************************/ /* Add an integer element to an array. */ /***********************************************************************/ bool ARRAY::AddValue(PGLOBAL g, int n)
{ if (Type != TYPE_INT) {
snprintf(g->Message, sizeof(g->Message), MSG(ADD_BAD_TYPE), GetTypeName(Type), "INTEGER"); returntrue;
} // endif Type
xtrc(1, " adding int(%d): %d\n", Nval, n);
Vblp->SetValue(n, Nval++); returnfalse;
} // end of AddValue
/***********************************************************************/ /* Add a double float element to an array. */ /***********************************************************************/ bool ARRAY::AddValue(PGLOBAL g, double d)
{ if (Type != TYPE_DOUBLE) {
snprintf(g->Message, sizeof(g->Message), MSG(ADD_BAD_TYPE), GetTypeName(Type), "DOUBLE"); returntrue;
} // endif Type
xtrc(1, " adding float(%d): %lf\n", Nval, d);
Value->SetValue(d);
Vblp->SetValue(Value, Nval++); returnfalse;
} // end of AddValue
/***********************************************************************/ /* Add the value of a XOBJECT block to an array. */ /***********************************************************************/ bool ARRAY::AddValue(PGLOBAL g, PXOB xp)
{ if (Type != xp->GetResultType()) {
snprintf(g->Message, sizeof(g->Message), MSG(ADD_BAD_TYPE),
GetTypeName(xp->GetResultType()), GetTypeName(Type)); returntrue;
} // endif Type
xtrc(1, " adding (%d) from xp=%p\n", Nval, xp);
Vblp->SetValue(xp->GetValue(), Nval++); returnfalse;
} // end of AddValue
/***********************************************************************/ /* Add a value to an array. */ /***********************************************************************/ bool ARRAY::AddValue(PGLOBAL g, PVAL vp)
{ if (Type != vp->GetType()) {
snprintf(g->Message, sizeof(g->Message), MSG(ADD_BAD_TYPE),
GetTypeName(vp->GetType()), GetTypeName(Type)); returntrue;
} // endif Type
xtrc(1, " adding (%d) from vp=%p\n", Nval, vp);
Vblp->SetValue(vp, Nval++); returnfalse;
} // end of AddValue
/***********************************************************************/ /* Retrieve the nth value of the array. */ /***********************************************************************/ void ARRAY::GetNthValue(PVAL valp, int n)
{
valp->SetValue_pvblk(Vblp, n);
} // end of GetNthValue
#if0 /***********************************************************************/ /* Retrieve the nth subvalue of a list array. */ /***********************************************************************/ bool ARRAY::GetSubValue(PGLOBAL g, PVAL valp, int *kp)
{
PVBLK vblp;
if (Type != TYPE_LIST) {
snprintf(g->Message, sizeof(g->Message), MSG(NO_SUB_VAL), Type); returntrue;
} // endif Type
vblp = ((LSTBLK*)Vblp)->Mbvk[kp[0]]->Vblk;
valp->SetValue_pvblk(vblp, kp[1]); returnfalse;
} // end of GetSubValue #endif// 0
/***********************************************************************/ /* Return the nth value of an integer array. */ /***********************************************************************/ int ARRAY::GetIntValue(int n)
{
assert (Type == TYPE_INT); return Vblp->GetIntValue(n);
} // end of GetIntValue
/***********************************************************************/ /* Return the nth value of a STRING array. */ /***********************************************************************/ char *ARRAY::GetStringValue(int n)
{
assert (Type == TYPE_STRING || Type == TYPE_PCHAR); return Vblp->GetCharValue(n);
} // end of GetStringValue
/***********************************************************************/ /* Find whether a value is in an array. */ /* Provide a conversion limited to the Value limitation. */ /***********************************************************************/ bool ARRAY::Find(PVAL valp)
{ int n;
PVAL vp;
/***********************************************************************/ /* ARRAY: Compare routine for a list of values. */ /***********************************************************************/
BYTE ARRAY::Vcompare(PVAL vp, int n)
{
Value->SetValue_pvblk(Vblp, n); return vp->TestValue(Value);
} // end of Vcompare
/***********************************************************************/ /* Test a filter condition on an array depending on operator and mod. */ /* Modificator values are 1: ANY (or SOME) and 2: ALL. */ /***********************************************************************/ bool ARRAY::FilTest(PGLOBAL g, PVAL valp, OPVAL opc, int opm)
{ int i;
PVAL vp;
BYTE bt = OpBmp(g, opc); int top = Nval - 1;
if (top < 0) // Array is empty // Return true for ALL because it means that there are no item that // does not verify the condition, which is true indeed. // Return false for ANY because true means that there is at least // one item that verifies the condition, which is false. return opm == 2;
if (valp) { if (Type != valp->GetType()) {
Value->SetValue_pval(valp);
vp = Value;
} else
vp = valp;
// Case of TYPE_LIST if (opm == 2) { for (i = 0; i < Nval; i++) if (Vcompare(vp, i) & bt) returnfalse;
returntrue;
} else { // opm == 1 for (i = 0; i < Nval; i++) if (!(Vcompare(vp, i) & bt)) returntrue;
returnfalse;
} // endif opm
} // end of FilTest
/***********************************************************************/ /* Test whether this array can be converted to TYPE_SHORT. */ /* Must be called after the array is sorted. */ /***********************************************************************/ bool ARRAY::CanBeShort(void)
{ int* To_Val = (int*)Valblk->GetMemp();
if (Type != TYPE_INT || !Ndif) returnfalse;
// Because the array is sorted, this is true if all the array // int values are in the range of SHORT values return (To_Val[0] >= -32768 && To_Val[Nval-1] < 32768);
} // end of CanBeShort
/***********************************************************************/ /* Convert an array to new numeric type k. */ /* Note: conversion is always made in ascending order from STRING to */ /* short to int to double so no precision is lost in the conversion. */ /* One exception is converting from int to short compatible arrays. */ /***********************************************************************/ int ARRAY::Convert(PGLOBAL g, int k, PVAL vp)
{ int i, prec = 0; bool b = false;
PMBV ovblk = Valblk;
PVBLK ovblp = Vblp;
Type = k; // k is the new type
Valblk = new(g) MBVALS;
switch (Type) { case TYPE_DOUBLE:
prec = 2; /* fall through */ case TYPE_SHORT: case TYPE_INT: case TYPE_DATE:
Len = 1; break; default:
snprintf(g->Message, sizeof(g->Message), MSG(BAD_CONV_TYPE), Type); return TYPE_ERROR;
} // endswitch k
if (!Valblk->GetMemp()) // The error message was built by PlgDBalloc return TYPE_ERROR; else
Value = AllocateValue(g, Type, Len, prec);
/*********************************************************************/ /* Converting STRING to DATE can be done according to date format. */ /*********************************************************************/ if (Type == TYPE_DATE && ovblp->GetType() == TYPE_STRING && vp)
{ if (((DTVAL*)Value)->SetFormat(g, vp)) return TYPE_ERROR; else
b = true; // Sort the new array on date internal values
}
/*********************************************************************/ /* Do the actual conversion. */ /*********************************************************************/ for (i = 0; i < Size; i++) {
Value->SetValue_pvblk(ovblp, i);
if (AddValue(g, Value)) return TYPE_ERROR;
} // endfor i
/*********************************************************************/ /* For sorted arrays, get the initial find values. */ /*********************************************************************/ if (b)
Sort(g);
ovblk->Free(); return Type;
} // end of Convert
/***********************************************************************/ /* ARRAY Save: save value at i (used while rordering). */ /***********************************************************************/ void ARRAY::Save(int i)
{
Value->SetValue_pvblk(Vblp, i);
} // end of Save
/***********************************************************************/ /* ARRAY Restore: restore value to j (used while rordering). */ /***********************************************************************/ void ARRAY::Restore(int j)
{
Vblp->SetValue(Value, j);
} // end of Restore
/***********************************************************************/ /* ARRAY Move: move value from k to j (used while rordering). */ /***********************************************************************/ void ARRAY::Move(int j, int k)
{
Vblp->Move(k, j); // VALBLK does the opposite !!!
} // end of Move
/***********************************************************************/ /* ARRAY: Compare routine for one LIST value (ascending only). */ /***********************************************************************/ int ARRAY::Qcompare(int *i1, int *i2)
{ return Vblp->CompVal(*i1, *i2);
} // end of Qcompare
/***********************************************************************/ /* Mainly meant to set the character arrays case sensitiveness. */ /***********************************************************************/ void ARRAY::SetPrecision(PGLOBAL g, int p)
{ if (Vblp == NULL) {
strcpy(g->Message, MSG(PREC_VBLP_NULL)); throw (int)TYPE_ARRAY;
} // endif Vblp
if (!was && Type == TYPE_STRING) // Must be resorted to eliminate duplicate strings if (Sort(g)) throw (int)TYPE_ARRAY;
} // end of SetPrecision
/***********************************************************************/ /* Sort and eliminate distinct values from an array. */ /* Note: this is done by making a sorted index on distinct values. */ /* Returns false if Ok or true in case of error. */ /***********************************************************************/ bool ARRAY::Sort(PGLOBAL g)
{ int i, j, k;
// This is to avoid multiply allocating for correlated subqueries if (Nval > Xsize) { if (Xsize >= 0) { // Was already allocated
PlgDBfree(Index);
PlgDBfree(Offset);
} // endif Xsize
// Prepare non conservative sort with offet values
Index.Size = Nval * sizeof(int);
if (!PlgDBalloc(g, NULL, Index)) goto error;
Offset.Size = (Nval + 1) * sizeof(int);
if (!PlgDBalloc(g, NULL, Offset)) goto error;
Xsize = Nval;
} // endif Nval
// Call the sort program, it returns the number of distinct values
Ndif = Qsort(g, Nval);
if (Ndif < 0) goto error;
// Use the sort index to reorder the data in storage so it will // be physically sorted and Index can be removed. for (i = 0; i < Nval; i++) { if (Pex[i] == i || Pex[i] == Nval) // Already placed or already moved continue;
Save(i);
for (j = i;; j = k) {
k = Pex[j];
Pex[j] = Nval; // Mark position as set
if (k == i) {
Restore(j); break; // end of loop
} else
Move(j, k);
} // endfor j
} // endfor i
// Reduce the size of the To_Val array if Ndif < Nval if (Ndif < Nval) { for (i = 1; i < Ndif; i++) if (i != Pof[i]) break;
// Index and Offset are not used anymore
PlgDBfree(Index);
PlgDBfree(Offset);
Xsize = -1; // } // endif Correlated
Bot = -1; // For non optimized search
Top = Ndif; // Find searches the whole array. returnfalse;
error:
Nval = Ndif = 0;
Valblk->Free();
PlgDBfree(Index);
PlgDBfree(Offset); returntrue;
} // end of Sort
/***********************************************************************/ /* Sort and return the sort index. */ /* Note: This is meant if the array contains unique values. */ /* Returns Index.Memp if Ok or NULL in case of error. */ /***********************************************************************/ void *ARRAY::GetSortIndex(PGLOBAL g)
{ // Prepare non conservative sort with offet values
Index.Size = Nval * sizeof(int);
if (!PlgDBalloc(g, NULL, Index)) goto error;
Offset.Size = (Nval + 1) * sizeof(int);
if (!PlgDBalloc(g, NULL, Offset)) goto error;
// Call the sort program, it returns the number of distinct values
Ndif = Qsort(g, Nval);
if (Ndif < 0) goto error;
if (Ndif < Nval) goto error;
PlgDBfree(Offset); return Index.Memp;
error:
Nval = Ndif = 0;
Valblk->Free();
PlgDBfree(Index);
PlgDBfree(Offset); return NULL;
} // end of GetSortIndex
/***********************************************************************/ /* Block filter testing for IN operator on Column/Array operands. */ /* Here we call Find that returns true if the value is in the array */ /* with X equal to the index of the found value in the array, or */ /* false if the value is not in the array with Inf and Sup being the */ /* indexes of the array values that are immediately below and over */ /* the not found value. This enables to restrict the array to the */ /* values that are between the min and max block values and to return */ /* the indication of whether the Find will be always true, always not */ /* true or other. */ /***********************************************************************/ int ARRAY::BlockTest(PGLOBAL, int opc, int opm, void *minp, void *maxp, bool s)
{ bool bin, bax, pin, pax, veq, all = (opm == 2);
if (Ndif == 0) // Array is empty // Return true for ALL because it means that there are no item that // does not verify the condition, which is true indeed. // Return false for ANY because true means that there is at least // one item that verifies the condition, which is false. return (all) ? 2 : -2; elseif (opc == OP_EQ && all && Ndif > 1) return -2; elseif (opc == OP_NE && !all && Ndif > 1) return2; // else if (Ndif == 1) // all = false;
// veq is true when all values in the block are equal switch (Type) { case TYPE_STRING: veq = (Vblp->IsCi())
? !stricmp((char*)minp, (char*)maxp)
: !strcmp((char*)minp, (char*)maxp); break; case TYPE_SHORT: veq = *(short*)minp == *(short*)maxp; break; case TYPE_INT: veq = *(int*)minp == *(int*)maxp; break; case TYPE_DOUBLE: veq = *(double*)minp == *(double*)maxp; break; default: veq = false; // Error ?
} // endswitch type
if (!s)
Bot = -1;
Top = Ndif; // Reset Top at top of list
Value->SetBinValue(maxp);
Top = (bax = Find(Value)) ? X + 1 : Sup;
if (X == 0) switch (opc) { // Max value is equal to min list value case OP_LE: return1; break; case OP_LT: return (veq) ? -1 : 0; break; case OP_GE: return (veq) ? 1 : 0; break; case OP_GT: return -1; break;
} // endswitch opc
pax = (opc == OP_GE) ? (X < Ndif - 1) : true;
} elseif (Inf == Bot) { // Max value is smaller than min list value return (opc == OP_LT || opc == OP_LE || opc == OP_NE) ? 1 : -1;
} else
pax = (Sup < Ndif); // True if max value is inside the list value
if (!veq) {
Value->SetBinValue(minp);
bin = Find(Value);
} else
bin = bax;
Bot = (bin) ? X - 1 : Inf;
if (bin) { if (opc == OP_EQ || opc == OP_NE) return0;
if (X == Ndif - 1) switch (opc) { case OP_GE: return (s) ? 2 : 1; break; case OP_GT: return (veq) ? -1 : 0; break; case OP_LE: return (veq) ? 1 : 0; break; case OP_LT: return (s) ? -2 : -1; break;
} // endswitch opc
pin = (opc == OP_LE) ? (X > 0) : true;
} elseif (Sup == Ndif) { // Min value is greater than max list value if (opc == OP_GT || opc == OP_GE || opc == OP_NE) return (s) ? 2 : 1; else return (s) ? -2 : -1;
} else
pin = (Inf >= 0); // True if min value is inside the list value
if (Top - Bot <= 1) { // No list item between min and max value #ifdefined(_DEBUG)
assert (!bin && !bax); #endif switch (opc) { case OP_EQ: return -1; break; case OP_NE: return1; break; default: return (all) ? -1 : 1; break;
} // endswitch opc
} // endif
#ifdefined(_DEBUG)
assert (Ndif > 1); // if Ndif = 1 we should have returned already #endif
// At this point, if there are no logical errors in the algorithm, // the only possible overlaps between the array and the block are: // Array: +-------+ +-------+ +-------+ +-----+ // Block: +-----+ +---+ +------+ +--------+ // true: pax pin pax pin if (all) switch (opc) { case OP_GT: case OP_GE: return (pax) ? -1 : 0; break; case OP_LT: case OP_LE: return (pin) ? -1 : 0; break;
} // endswitch opc
return0;
} // end of BlockTest
/***********************************************************************/ /* MakeArrayList: Makes a value list from an SQL IN array (in work). */ /***********************************************************************/
PSZ ARRAY::MakeArrayList(PGLOBAL g)
{ char *p, *tp; int i;
size_t z, len = 2;
if (Type == TYPE_LIST) return (PSZ)("(?""?""?)"); // To be implemented
for (i = 0; i < Nval;) {
Value->SetValue_pvblk(Vblp, i);
Value->Prints(g, tp, z);
safe_strcat(p, len, tp);
safe_strcat(p, len, (++i == Nval) ? ")" : ",");
} // enfor i
xtrc(1, "Arraylist: newlen=%d\n", strlen(p)); return p;
} // end of MakeArrayList
/***********************************************************************/ /* Make file output of ARRAY contents. */ /***********************************************************************/ void ARRAY::Printf(PGLOBAL g, FILE *f, uint n)
{ char m[64]; int lim = MY_MIN(Nval,10);
memset(m, ' ', n); // Make margin string
m[n] = '\0';
fprintf(f, "%sARRAY: type=%d\n", m, Type);
memset(m, ' ', n + 2); // Make margin string
m[n] = '\0';
if (Type != TYPE_LIST) {
fprintf(f, "%sblock=%p numval=%d\n", m, Valblk->GetMemp(), Nval);
if (Vblp) for (int i = 0; i < lim; i++) {
Value->SetValue_pvblk(Vblp, i);
Value->Printf(g, f, n+4);
} // endfor i
} else
fprintf(f, "%sVALLST: numval=%d\n", m, Nval);
} // end of Printf
/***********************************************************************/ /* Make string output of ARRAY contents. */ /***********************************************************************/ void ARRAY::Prints(PGLOBAL, char *ps, uint z)
{ if (z < 16) return;
snprintf(ps, z, "ARRAY: type=%d\n", Type); // More to be implemented later
} // end of Prints
/* -------------------------- Class MULAR ---------------------------- */
/***********************************************************************/ /* MULAR public constructor. */ /***********************************************************************/
MULAR::MULAR(PGLOBAL g, int n) : CSORT(false)
{
Narray = n;
Pars = (PARRAY*)PlugSubAlloc(g, NULL, n * sizeof(PARRAY));
} // end of MULAR constructor
/***********************************************************************/ /* MULAR: Compare routine multiple arrays. */ /***********************************************************************/ int MULAR::Qcompare(int *i1, int *i2)
{ int i, n = 0;
for (i = 0; i < Narray; i++) if ((n = Pars[i]->Qcompare(i1, i2))) break;
return n;
} // end of Qcompare
/***********************************************************************/ /* Sort and eliminate distinct values from multiple arrays. */ /* Note: this is done by making a sorted index on distinct values. */ /* Returns false if Ok or true in case of error. */ /***********************************************************************/ bool MULAR::Sort(PGLOBAL g)
{ int i, j, k, n, nval, ndif;
// All arrays must have the same number of values
nval = Pars[0]->Nval;
for (n = 1; n < Narray; n++) if (Pars[n]->Nval != nval) {
strcpy(g->Message, MSG(BAD_ARRAY_VAL)); returntrue;
} // endif nval
// Prepare non conservative sort with offet values
Index.Size = nval * sizeof(int);
if (!PlgDBalloc(g, NULL, Index)) goto error;
Offset.Size = (nval + 1) * sizeof(int);
if (!PlgDBalloc(g, NULL, Offset)) goto error;
// Call the sort program, it returns the number of distinct values
ndif = Qsort(g, nval);
if (ndif < 0) goto error;
// Use the sort index to reorder the data in storage so it will // be physically sorted and Index can be removed. for (i = 0; i < nval; i++) { if (Pex[i] == i || Pex[i] == nval) // Already placed or already moved continue;
for (n = 0; n < Narray; n++)
Pars[n]->Save(i);
for (j = i;; j = k) {
k = Pex[j];
Pex[j] = nval; // Mark position as set
if (k == i) { for (n = 0; n < Narray; n++)
Pars[n]->Restore(j);
break; // end of loop
} else for (n = 0; n < Narray; n++)
Pars[n]->Move(j, k);
} // endfor j
} // endfor i
// Reduce the size of the To_Val array if ndif < nval if (ndif < nval) { for (i = 1; i < ndif; i++) if (i != Pof[i]) break;
for (; i < ndif; i++) for (n = 0; n < Narray; n++)
Pars[n]->Move(i, Pof[i]);
for (n = 0; n < Narray; n++) {
Pars[n]->Nval = ndif;
Pars[n]->Size = ndif;
Pars[n]->Valblk->ReAllocate(g, ndif);
} // endfor n
} // endif ndif
// Index and Offset are not used anymore
PlgDBfree(Index);
PlgDBfree(Offset);
for (n = 0; n < Narray; n++) {
Pars[n]->Bot = -1; // For non optimized search
Pars[n]->Top = ndif; // Find searches the whole array.
} // endfor n
returnfalse;
error:
PlgDBfree(Index);
PlgDBfree(Offset); returntrue;
} // end of Sort
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.30 Sekunden
(vorverarbeitet am 2026-10-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.