oqlsort.cc

00001 /* 
00002    EyeDB Object Database Management System
00003    Copyright (C) 1994-2008 SYSRA
00004    
00005    EyeDB is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009    
00010    EyeDB is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014    
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with this library; if not, write to the Free Software
00017    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA 
00018 */
00019 
00020 /*
00021    Author: Eric Viara <viara@sysra.com>
00022 */
00023 
00024 
00025 #include "oql_p.h"
00026 
00027 #define RS(r) (r ? "r" : "")
00028 #define CHECK_TYPE(X) oqml_check_sort_type(node, (X)->type)
00029 
00030 // -----------------------------------------------------------------------
00031 //
00032 // oqmlSort utility functions
00033 //
00034 // -----------------------------------------------------------------------
00035 
00036 namespace eyedb {
00037 
00038 oqmlStatus *
00039 oqml_check_sort_type(oqmlNode *node, oqmlAtomType &type, const char *msg)
00040 {
00041   if (type.type != oqmlATOM_INT &&
00042       type.type != oqmlATOM_STRING &&
00043       type.type != oqmlATOM_DOUBLE &&
00044       type.type != oqmlATOM_CHAR &&
00045       type.type != oqmlATOM_NULL)
00046     return new oqmlStatus(node, (msg ? msg :
00047                                  "a collection of integer, string, "
00048                                  "double or character is expected, got %s"),
00049                           type.getString());
00050 
00051   return oqmlSuccess;
00052 }
00053 
00054 static void
00055 oqml_sort_realize(oqmlAtom **array, int array_cnt, oqmlBool reverse,
00056                   oqmlAtomList **alist)
00057 {
00058   *alist = new oqmlAtomList();
00059 
00060   if (reverse)
00061     {
00062       for (int n = array_cnt - 1; n >= 0; n--)
00063         (*alist)->append(array[n]);
00064 
00065       free(array);
00066       return;
00067     }  
00068 
00069   for (int n = 0; n < array_cnt; n++)
00070     (*alist)->append(array[n]);
00071 
00072   free(array);
00073 }
00074 
00075 #define CHECK_NULL(LEFT, RIGHT) \
00076 if ((LEFT)->as_null() && (RIGHT)->as_null()) \
00077   return 0; \
00078 if ((LEFT)->as_null())\
00079   return -1;\
00080 if ((RIGHT)->as_null())\
00081   return 1
00082 
00083 static int
00084 oqml_sort_int(const void *x1, const void *x2)
00085 {
00086   oqmlAtom *aleft = *(oqmlAtom **)x1;
00087   oqmlAtom *aright = *(oqmlAtom **)x2;
00088 
00089   CHECK_NULL(aleft, aright);
00090   return (OQML_ATOM_INTVAL(aleft) - OQML_ATOM_INTVAL(aright));
00091 }
00092 
00093 static int
00094 oqml_sort_string(const void *x1, const void *x2)
00095 {
00096   oqmlAtom *aleft = *(oqmlAtom **)x1;
00097   oqmlAtom *aright = *(oqmlAtom **)x2;
00098 
00099   CHECK_NULL(aleft, aright);
00100   return strcmp(OQML_ATOM_STRVAL(aleft), OQML_ATOM_STRVAL(aright));
00101 }
00102 
00103 static int
00104 oqml_sort_double(const void *x1, const void *x2)
00105 {
00106   oqmlAtom *aleft = *(oqmlAtom **)x1;
00107   oqmlAtom *aright = *(oqmlAtom **)x2;
00108 
00109   CHECK_NULL(aleft, aright);
00110   return (OQML_ATOM_DBLVAL(aleft) - OQML_ATOM_DBLVAL(aright));
00111 }
00112 
00113 static int
00114 oqml_sort_char(const void *x1, const void *x2)
00115 {
00116   oqmlAtom *aleft = *(oqmlAtom **)x1;
00117   oqmlAtom *aright = *(oqmlAtom **)x2;
00118 
00119   CHECK_NULL(aleft, aright);
00120   return (OQML_ATOM_CHARVAL(aleft) - OQML_ATOM_CHARVAL(aright));
00121 }
00122 
00123 oqmlAtom **
00124 oqml_make_array(oqmlAtomList *list, int &cnt)
00125 {
00126   oqmlAtom **array = idbNewVect(oqmlAtom *, list->cnt);
00127   oqmlAtom *atom = list->first;
00128 
00129   for (cnt = 0; atom; cnt++)
00130     {
00131       array[cnt] = atom;
00132       atom = atom->next;
00133     }
00134 
00135   return array;
00136 }
00137 
00138 static oqmlStatus *
00139 checkTypes(oqmlNode *node, oqmlAtomList *list, oqmlATOMTYPE &atom_type)
00140 {
00141   oqmlAtom *atom = OQML_ATOM_COLLVAL(list->first)->first;
00142 
00143   if (!atom)
00144     return oqmlSuccess;
00145 
00146   atom_type = (oqmlATOMTYPE)0;
00147 
00148   while (atom)
00149     {
00150       CHECK_TYPE(atom);
00151 
00152       if (!atom_type)
00153         {
00154           if (atom->type.type != oqmlATOM_NULL)
00155             atom_type = atom->type.type;
00156         }
00157       else if (atom->type.type != oqmlATOM_NULL &&
00158                atom_type != atom->type.type)
00159         return new oqmlStatus(node, "atom types in collection "
00160                               "are no homogeneous");
00161       atom = atom->next;
00162     }
00163 
00164   if (atom_type)
00165     {
00166       oqmlAtomType at(atom_type);
00167       oqmlStatus *s = oqml_check_sort_type(node, at);
00168       if (s) return s;
00169     }
00170 
00171   return oqmlSuccess;
00172 }
00173 
00174 void
00175 oqml_sort_simple(oqmlAtomList *ilist, oqmlBool reverse,
00176                  oqmlATOMTYPE atom_type, oqmlAtomList **alist)
00177 {
00178   oqmlAtom **array;
00179   int array_cnt, n;
00180 
00181   array = oqml_make_array(ilist, array_cnt);
00182 
00183   if (atom_type == oqmlATOM_INT)
00184     qsort(array, array_cnt, sizeof(oqmlAtom *), oqml_sort_int);
00185   else if (atom_type == oqmlATOM_STRING)
00186     qsort(array, array_cnt, sizeof(oqmlAtom *), oqml_sort_string);
00187   else if (atom_type == oqmlATOM_DOUBLE)
00188     qsort(array, array_cnt, sizeof(oqmlAtom *), oqml_sort_double);
00189   else if (atom_type == oqmlATOM_CHAR)
00190     qsort(array, array_cnt, sizeof(oqmlAtom *), oqml_sort_char);
00191   /* else : all is NULL */
00192       
00193   oqml_sort_realize(array, array_cnt, reverse, alist);
00194 }
00195 
00196 // -----------------------------------------------------------------------
00197 //
00198 // oqmlSort public methods
00199 //
00200 // -----------------------------------------------------------------------
00201 
00202 oqmlSort::oqmlSort(oqml_List *_list, oqmlBool _reverse) :
00203   oqmlXSort(oqmlSORT, _list, _reverse)
00204 {
00205 }
00206 
00207 oqmlSort::~oqmlSort()
00208 {
00209 }
00210 
00211 oqmlStatus *oqmlSort::compile(Database *db, oqmlContext *ctx)
00212 {
00213   if (!xlist || xlist->cnt < 1)
00214     return new oqmlStatus(this, "one argument expected");
00215 
00216   tosort = xlist->first->ql;
00217 
00218   if (xlist->cnt != 1) return new oqmlStatus(this, "one argument expected");
00219 
00220   return tosort->compile(db, ctx);
00221 }
00222 
00223 oqmlStatus *oqmlSort::eval(Database *db, oqmlContext *ctx,
00224                            oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00225 {
00226   oqmlStatus *s;
00227   oqmlAtomList *list;
00228   int n;
00229 
00230   s = tosort->eval(db, ctx, &list);
00231 
00232   if (s) return s;
00233 
00234   if (list->cnt != 1 || !OQML_IS_COLL(list->first))
00235     return new oqmlStatus(this, "collection expected");
00236 
00237   oqmlATOMTYPE atom_type;
00238   s = checkTypes(this, list, atom_type);
00239   if (s) return s;
00240 
00241   oqmlAtomList *ylist;
00242   oqml_sort_simple(OQML_ATOM_COLLVAL(list->first), reverse, atom_type, &ylist);
00243   *alist = new oqmlAtomList(new oqmlAtom_list(ylist));
00244   return oqmlSuccess;
00245 }
00246 
00247 void oqmlSort::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00248 {
00249   *at = eval_type;
00250 }
00251 
00252 oqmlBool oqmlSort::isConstant() const
00253 {
00254   return tosort->isConstant();
00255 }
00256 
00257 std::string
00258 oqmlSort::toString(void) const
00259 {
00260   return (reverse ? std::string("rsort(") : std::string("sort(")) +
00261     (tosort ? tosort->toString() : std::string("")) + ")" + oqml_isstat();
00262 }
00263 
00264 // -----------------------------------------------------------------------
00265 //
00266 // oqmlISort utility functions
00267 //
00268 // -----------------------------------------------------------------------
00269 
00270 struct oqmlAtomPair {
00271   oqmlAtom *list;
00272   oqmlAtom *atom;
00273 };
00274 
00275 static int
00276 oqml_isort_int(const void *x1, const void *x2)
00277 {
00278   oqmlAtomPair *ap1 = (oqmlAtomPair *)x1;
00279   oqmlAtomPair *ap2 = (oqmlAtomPair *)x2;
00280 
00281   CHECK_NULL(ap1->atom, ap2->atom);
00282   return (OQML_ATOM_INTVAL(ap1->atom) - OQML_ATOM_INTVAL(ap2->atom));
00283 }
00284 
00285 static int
00286 oqml_isort_string(const void *x1, const void *x2)
00287 {
00288   oqmlAtomPair *ap1 = (oqmlAtomPair *)x1;
00289   oqmlAtomPair *ap2 = (oqmlAtomPair *)x2;
00290 
00291   CHECK_NULL(ap1->atom, ap2->atom);
00292   return strcmp(OQML_ATOM_STRVAL(ap1->atom), OQML_ATOM_STRVAL(ap2->atom));
00293 }
00294 
00295 static int
00296 oqml_isort_double(const void *x1, const void *x2)
00297 {
00298   oqmlAtomPair *ap1 = (oqmlAtomPair *)x1;
00299   oqmlAtomPair *ap2 = (oqmlAtomPair *)x2;
00300 
00301   CHECK_NULL(ap1->atom, ap2->atom);
00302   return (OQML_ATOM_DBLVAL(ap1->atom) - OQML_ATOM_DBLVAL(ap2->atom));
00303 }
00304 
00305 static int
00306 oqml_isort_char(const void *x1, const void *x2)
00307 {
00308   oqmlAtomPair *ap1 = (oqmlAtomPair *)x1;
00309   oqmlAtomPair *ap2 = (oqmlAtomPair *)x2;
00310 
00311   CHECK_NULL(ap1->atom, ap2->atom);
00312   return (OQML_ATOM_CHARVAL(ap1->atom) - OQML_ATOM_CHARVAL(ap2->atom));
00313 }
00314 
00315 static oqmlAtom *
00316 oqml_get_atom(oqmlAtom *atom_list, int idx)
00317 {
00318   oqmlAtomList *list = OQML_ATOM_COLLVAL(atom_list);
00319   oqmlAtom *atom = list->first;
00320 
00321   for (int i = 0; atom; i++)
00322     {
00323       if (i == idx)
00324         return atom;
00325       atom = atom->next;
00326     }
00327 
00328   return 0;
00329 }
00330 
00331 oqmlAtomPair *
00332 oqml_make_array(oqmlAtomList *list, int &cnt, int idx)
00333 {
00334   oqmlAtomPair *array = idbNewVect(oqmlAtomPair, list->cnt);
00335   oqmlAtom *atom = list->first;
00336 
00337   for (cnt = 0; atom; cnt++)
00338     {
00339       if (!OQML_IS_COLL(atom))
00340         break;
00341       array[cnt].list = atom;
00342       array[cnt].atom = oqml_get_atom(atom, idx);
00343       atom = atom->next;
00344     }
00345 
00346   return array;
00347 }
00348 
00349 static void
00350 oqml_sort_realize(oqmlAtomPair *array, int array_cnt, oqmlBool reverse,
00351                   oqmlAtomList **alist)
00352 {
00353   *alist = new oqmlAtomList();
00354 
00355   if (reverse)
00356     {
00357       for (int n = array_cnt - 1; n >= 0; n--)
00358         (*alist)->append(array[n].list);
00359 
00360       free(array);
00361       return;
00362     }  
00363 
00364   for (int n = 0; n < array_cnt; n++)
00365     (*alist)->append(array[n].list);
00366 
00367   free(array);
00368 }
00369 
00370 void
00371 oqml_sort_list(oqmlAtomList *ilist, oqmlBool reverse, int idx,
00372                oqmlATOMTYPE atom_type, oqmlAtomList **alist)
00373 {
00374   oqmlAtomPair *array;
00375   int array_cnt, n;
00376 
00377   array = oqml_make_array(ilist, array_cnt, idx);
00378 
00379   if (atom_type == oqmlATOM_INT)
00380     qsort(array, array_cnt, sizeof(oqmlAtomPair), oqml_isort_int);
00381   else if (atom_type == oqmlATOM_STRING)
00382     qsort(array, array_cnt, sizeof(oqmlAtomPair), oqml_isort_string);
00383   else if (atom_type == oqmlATOM_DOUBLE)
00384     qsort(array, array_cnt, sizeof(oqmlAtomPair), oqml_isort_double);
00385   else if (atom_type == oqmlATOM_CHAR)
00386     qsort(array, array_cnt, sizeof(oqmlAtomPair), oqml_isort_char);
00387   else
00388     abort();
00389   
00390   oqml_sort_realize(array, array_cnt, reverse, alist);
00391 }
00392 
00393 static oqmlStatus *
00394 checkTypes(oqmlNode *node, oqmlAtomList *list, int idx, oqmlATOMTYPE &atom_type)
00395 {
00396   oqmlAtom *atom = OQML_ATOM_COLLVAL(list->first)->first;
00397 
00398   if (!atom)
00399     return oqmlSuccess;
00400 
00401   atom_type = (oqmlATOMTYPE)0;
00402 
00403   while (atom)
00404     {
00405       if (!OQML_IS_LIST(atom) && !OQML_IS_ARRAY(atom))
00406         return new oqmlStatus(node, "a collection of lists or arrays "
00407                               "was expected");
00408 
00409       if (OQML_ATOM_COLLVAL(atom)->cnt <= idx)
00410         return new oqmlStatus(node, "index '%d' too large "
00411                               "for collection", idx);
00412 
00413       oqmlAtom *x = OQML_ATOM_COLLVAL(atom)->first;
00414 
00415       for (int i = 0; x; x = x->next, i++)
00416         if (i == idx)
00417           {
00418             CHECK_TYPE(x);
00419             if (!atom_type)
00420               {
00421                 atom_type = x->type.type;
00422                 break;
00423               }
00424             
00425             if (atom_type != x->type.type)
00426               return new oqmlStatus(node, "atom types at index %d "
00427                                     "in list or array are not homogeneous",
00428                                     idx);
00429           }
00430 
00431       atom = atom->next;
00432     }
00433 
00434   if (atom_type)
00435     {
00436       oqmlAtomType at(atom_type);
00437       oqmlStatus *s = oqml_check_sort_type(node, at);
00438       if (s) return s;
00439     }
00440 
00441   return oqmlSuccess;
00442 }
00443 
00444 // -----------------------------------------------------------------------
00445 //
00446 // oqmlISort public methods
00447 //
00448 // -----------------------------------------------------------------------
00449 
00450 oqmlISort::oqmlISort(oqml_List *_list, oqmlBool _reverse) :
00451   oqmlXSort(oqmlISORT, _list, _reverse)
00452 {
00453   idxnode = 0;
00454 }
00455 
00456 oqmlISort::~oqmlISort()
00457 {
00458 }
00459 
00460 oqmlStatus *oqmlISort::compile(Database *db, oqmlContext *ctx)
00461 {
00462   if (!xlist || xlist->cnt < 1)
00463     return new oqmlStatus(this, "two arguments expected");
00464 
00465   tosort = xlist->first->ql;
00466 
00467   if (xlist->cnt < 2) return new oqmlStatus(this, "two arguments expected");
00468   idxnode = xlist->first->next->ql;
00469 
00470   if (xlist->cnt != 2) return new oqmlStatus(this, "two arguments expected");
00471 
00472   oqmlStatus *s = tosort->compile(db, ctx);
00473   if (s) return s;
00474 
00475   return idxnode->compile(db, ctx);
00476 }
00477 
00478 oqmlStatus *oqmlISort::eval(Database *db, oqmlContext *ctx,
00479                             oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00480 {
00481   oqmlStatus *s;
00482   oqmlAtomList *list;
00483 
00484   s = tosort->eval(db, ctx, &list);
00485   if (s) return s;
00486 
00487   if (list->cnt != 1 || !OQML_IS_COLL(list->first))
00488     return new oqmlStatus(this, "first argument: collection expected");
00489 
00490   oqmlAtomList *idxlist;
00491   s = idxnode->eval(db, ctx, &idxlist);
00492   if (s) return s;
00493 
00494   if (idxlist->cnt != 1 || !OQML_IS_INT(idxlist->first))
00495     return new oqmlStatus(this, "second argument: integer expected");
00496 
00497   int idx = OQML_ATOM_INTVAL(idxlist->first);
00498 
00499   if (idx < 0)
00500     return new oqmlStatus(this, "second argument: "
00501                           "positive integer expected");
00502 
00503   oqmlATOMTYPE atom_type;
00504   s = checkTypes(this, list, idx, atom_type);
00505   if (s) return s;
00506 
00507   oqmlAtomList *ylist;
00508   oqml_sort_list(OQML_ATOM_COLLVAL(list->first), reverse, idx,
00509                  atom_type, &ylist);
00510   *alist = new oqmlAtomList(new oqmlAtom_list(ylist));
00511   return oqmlSuccess;
00512 
00513   return oqmlSuccess;
00514 }
00515 
00516 void oqmlISort::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00517 {
00518   *at = eval_type;
00519 }
00520 
00521 oqmlBool oqmlISort::isConstant() const
00522 {
00523   return tosort->isConstant();
00524 }
00525 
00526 std::string
00527 oqmlISort::toString(void) const
00528 {
00529   return (reverse ? std::string("risort(") : std::string("isort(")) +
00530     (tosort ? tosort->toString() : std::string("")) +
00531     (idxnode ? std::string(",") + idxnode->toString() : std::string("")) 
00532     + ")" + oqml_isstat();
00533 }
00534 
00535 // -----------------------------------------------------------------------
00536 //
00537 // oqmlPSort public methods
00538 //
00539 // -----------------------------------------------------------------------
00540 
00541 // -------------------------- NOT YET IMPLEMENTED ------------------------
00542 
00543 #if 0
00544 static int
00545 oqml_sort_pred_realize(const void *x1, const void *x2)
00546 {
00547   oqmlAtom *aleft = *(oqmlAtom **)x1;
00548   oqmlAtom *aright = *(oqmlAtom **)x2;
00549   oqmlAtomList *input = new oqmlAtomList();
00550   input->append(aleft);
00551   input->append(aright);
00552   if (oqml_predarg)
00553     input->append(oqml_predarg);
00554 
00555   oqmlAtom *r;
00556   oqmlCall::realizeCall(oqml_db, oqml_ctx, oqml_entry, input,
00557                         &r);
00558 }
00559 
00560 static void
00561 oqml_sort_pred(oqmlAtomList *al, oqmlFunctionEntry *entry,
00562                oqmlAtomList *predarglist,
00563                oqmlBool reverse, oqmlAtomList **alist)
00564 {
00565   oqmlAtom **array;
00566   int nn;
00567 
00568   array = oqml_make_array(al, nn);
00569 
00570   qsort(array, nn, sizeof(oqmlAtom *), oqml_sort_pred_realize);
00571       
00572   *alist = new oqmlAtomList();
00573   
00574   if (reverse)
00575     for (int i = nn-1; i >= 0; i--)
00576       (*alist)->append(array[i]);
00577   else
00578     for (int i = 0; i < nn; i++)
00579       (*alist)->append(array[i]);
00580   
00581   free(array);
00582 }
00583 
00584 oqmlPSort::oqmlPSort(oqml_List *_list, oqmlBool _reverse) :
00585   oqmlXSort(oqmlPSORT, _list, _reverse)
00586 {
00587 }
00588 
00589 oqmlPSort::~oqmlPSort()
00590 {
00591 }
00592 
00593 oqmlStatus *oqmlPSort::compile(Database *db, oqmlContext *ctx)
00594 {
00595   if (list->cnt < 2)
00596     return usage();
00597 
00598   tosort = list->first->ql;
00599   pred = list->first->next->ql;
00600 
00601   oqmlStatus *s = tosort->compile(db, ctx);
00602   if (s) return s;
00603 
00604   s = pred->compile(db, ctx);
00605   if (s) return s;
00606 
00607   predarg = list->first->next ? list->first->next->ql : 0;
00608   if (predarg)
00609     retun predarg->compile(db, ctx);
00610 
00611   return oqmlSuccess;
00612 }
00613 
00614 oqmlStatus *oqmlPSort::usage()
00615 {
00616   return new oqmlStatus(this, "usage: %spsort(collection of anything, "
00617                         "predicat [, predargs])", RS(reverse));
00618 }
00619 
00620 oqmlStatus *oqmlPSort::eval(Database *db, oqmlContext *ctx,
00621                            oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00622 {
00623   oqmlStatus *s;
00624   oqmlAtomList *al;
00625   int n;
00626 
00627   s = tosort->eval(db, ctx, &al);
00628   if (s) return s;
00629 
00630   oqmlAtomList *predlist;
00631   s = pred->eval(db, ctx, &predlist);
00632   if (s) return s;
00633   if (predlist->cnt != 1 || !OQML_IS_IDENT(predlist->first))
00634     return usage();
00635 
00636   if (!ctx->getFunction(OQML_ATOM_IDENT(predlist->first, &entry)))
00637     return new oqmlStatus(this, "unknown function '%s'",
00638                           OQML_ATOM_IDENT(predlist->first));
00639 
00640   oqmlAtomList *predarglist = 0;
00641   if (predarg)
00642     {
00643       s = predarg->eval(db, ctx, &predarglist);
00644       if (s) return s;
00645     }
00646 
00647   oqmlAtomList *ylist;
00648   oqml_sort_pred(al, entry, predarglist, reverse, &ylist);
00649   *alist = new oqmlAtomList(new oqmlAtom_list(ylist));
00650   return oqmlSuccess;
00651 }
00652 
00653 void oqmlPSort::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00654 {
00655   *at = eval_type;
00656 }
00657 
00658 oqmlBool oqmlPSort::isConstant() const
00659 {
00660   return tosort->isConstant();
00661 }
00662 
00663 std::string
00664 oqmlPSort::toString(void) const
00665 {
00666   return (reverse ? std::string("rpsort(") : std::string("psort(")) +
00667     tosort->toString() + ", " + pred->toString() +
00668     (predarg ? std::string(", ") + predarg->toString() : std::string("")) +
00669     ")" + oqml_isstat();
00670 }
00671 #endif
00672 }

Generated on Mon Dec 22 18:16:06 2008 for eyedb by  doxygen 1.5.3