LCOV - code coverage report
Current view: directory - content/xslt/src/xslt - txNodeSorter.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 124 0 0.0 %
Date: 2012-06-02 Functions: 6 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is TransforMiiX XSLT processor code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Jonas Sicking.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2001
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Jonas Sicking <sicking@bigfoot.com>
      24                 :  *   Peter Van der Beken <peterv@propagandism.org>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      28                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : #include "txNodeSorter.h"
      41                 : #include "txExecutionState.h"
      42                 : #include "txXPathResultComparator.h"
      43                 : #include "nsGkAtoms.h"
      44                 : #include "txNodeSetContext.h"
      45                 : #include "txExpr.h"
      46                 : #include "txStringUtils.h"
      47                 : #include "prmem.h"
      48                 : #include "nsQuickSort.h"
      49                 : 
      50                 : /*
      51                 :  * Sorts Nodes as specified by the W3C XSLT 1.0 Recommendation
      52                 :  */
      53                 : 
      54               0 : txNodeSorter::txNodeSorter() : mNKeys(0)
      55                 : {
      56               0 : }
      57                 : 
      58               0 : txNodeSorter::~txNodeSorter()
      59                 : {
      60               0 :     txListIterator iter(&mSortKeys);
      61               0 :     while (iter.hasNext()) {
      62               0 :         SortKey* key = (SortKey*)iter.next();
      63               0 :         delete key->mComparator;
      64                 :         delete key;
      65                 :     }
      66               0 : }
      67                 : 
      68                 : nsresult
      69               0 : txNodeSorter::addSortElement(Expr* aSelectExpr, Expr* aLangExpr,
      70                 :                              Expr* aDataTypeExpr, Expr* aOrderExpr,
      71                 :                              Expr* aCaseOrderExpr, txIEvalContext* aContext)
      72                 : {
      73               0 :     nsAutoPtr<SortKey> key(new SortKey);
      74               0 :     NS_ENSURE_TRUE(key, NS_ERROR_OUT_OF_MEMORY);
      75               0 :     nsresult rv = NS_OK;
      76                 : 
      77                 :     // Select
      78               0 :     key->mExpr = aSelectExpr;
      79                 : 
      80                 :     // Order
      81               0 :     bool ascending = true;
      82               0 :     if (aOrderExpr) {
      83               0 :         nsAutoString attrValue;
      84               0 :         rv = aOrderExpr->evaluateToString(aContext, attrValue);
      85               0 :         NS_ENSURE_SUCCESS(rv, rv);
      86                 : 
      87               0 :         if (TX_StringEqualsAtom(attrValue, nsGkAtoms::descending)) {
      88               0 :             ascending = false;
      89                 :         }
      90               0 :         else if (!TX_StringEqualsAtom(attrValue, nsGkAtoms::ascending)) {
      91                 :             // XXX ErrorReport: unknown value for order attribute
      92               0 :             return NS_ERROR_XSLT_BAD_VALUE;
      93                 :         }
      94                 :     }
      95                 : 
      96                 : 
      97                 :     // Create comparator depending on datatype
      98               0 :     nsAutoString dataType;
      99               0 :     if (aDataTypeExpr) {
     100               0 :         rv = aDataTypeExpr->evaluateToString(aContext, dataType);
     101               0 :         NS_ENSURE_SUCCESS(rv, rv);
     102                 :     }
     103                 : 
     104               0 :     if (!aDataTypeExpr || TX_StringEqualsAtom(dataType, nsGkAtoms::text)) {
     105                 :         // Text comparator
     106                 :         
     107                 :         // Language
     108               0 :         nsAutoString lang;
     109               0 :         if (aLangExpr) {
     110               0 :             rv = aLangExpr->evaluateToString(aContext, lang);
     111               0 :             NS_ENSURE_SUCCESS(rv, rv);
     112                 :         }
     113                 : 
     114                 :         // Case-order 
     115               0 :         bool upperFirst = false;
     116               0 :         if (aCaseOrderExpr) {
     117               0 :             nsAutoString attrValue;
     118                 : 
     119               0 :             rv = aCaseOrderExpr->evaluateToString(aContext, attrValue);
     120               0 :             NS_ENSURE_SUCCESS(rv, rv);
     121                 : 
     122               0 :             if (TX_StringEqualsAtom(attrValue, nsGkAtoms::upperFirst)) {
     123               0 :                 upperFirst = true;
     124                 :             }
     125               0 :             else if (!TX_StringEqualsAtom(attrValue,
     126               0 :                                           nsGkAtoms::lowerFirst)) {
     127                 :                 // XXX ErrorReport: unknown value for case-order attribute
     128               0 :                 return NS_ERROR_XSLT_BAD_VALUE;
     129                 :             }
     130                 :         }
     131                 : 
     132               0 :         key->mComparator = new txResultStringComparator(ascending,
     133                 :                                                         upperFirst,
     134               0 :                                                         lang);
     135               0 :         NS_ENSURE_TRUE(key->mComparator, NS_ERROR_OUT_OF_MEMORY);
     136                 :     }
     137               0 :     else if (TX_StringEqualsAtom(dataType, nsGkAtoms::number)) {
     138                 :         // Number comparator
     139               0 :         key->mComparator = new txResultNumberComparator(ascending);
     140               0 :         NS_ENSURE_TRUE(key->mComparator, NS_ERROR_OUT_OF_MEMORY);
     141                 :     }
     142                 :     else {
     143                 :         // XXX ErrorReport: unknown data-type
     144               0 :         return NS_ERROR_XSLT_BAD_VALUE;
     145                 :     }
     146                 : 
     147                 :     // mSortKeys owns key now. 
     148               0 :     rv = mSortKeys.add(key);
     149               0 :     NS_ENSURE_SUCCESS(rv, rv);
     150                 : 
     151               0 :     key.forget();
     152               0 :     mNKeys++;
     153                 : 
     154               0 :     return NS_OK;
     155                 : }
     156                 : 
     157                 : nsresult
     158               0 : txNodeSorter::sortNodeSet(txNodeSet* aNodes, txExecutionState* aEs,
     159                 :                           txNodeSet** aResult)
     160                 : {
     161               0 :     if (mNKeys == 0 || aNodes->isEmpty()) {
     162               0 :         NS_ADDREF(*aResult = aNodes);
     163                 : 
     164               0 :         return NS_OK;
     165                 :     }
     166                 : 
     167               0 :     *aResult = nsnull;
     168                 : 
     169               0 :     nsRefPtr<txNodeSet> sortedNodes;
     170               0 :     nsresult rv = aEs->recycler()->getNodeSet(getter_AddRefs(sortedNodes));
     171               0 :     NS_ENSURE_SUCCESS(rv, rv);
     172                 : 
     173               0 :     txNodeSetContext* evalContext = new txNodeSetContext(aNodes, aEs);
     174               0 :     NS_ENSURE_TRUE(evalContext, NS_ERROR_OUT_OF_MEMORY);
     175                 : 
     176               0 :     rv = aEs->pushEvalContext(evalContext);
     177               0 :     NS_ENSURE_SUCCESS(rv, rv);
     178                 : 
     179                 :     // Create and set up memoryblock for sort-values and indexarray
     180               0 :     PRUint32 len = static_cast<PRUint32>(aNodes->size());
     181                 : 
     182                 :     // Limit resource use to something sane.
     183               0 :     PRUint32 itemSize = sizeof(PRUint32) + mNKeys * sizeof(txObject*);
     184               0 :     if (mNKeys > (PR_UINT32_MAX - sizeof(PRUint32)) / sizeof(txObject*) ||
     185                 :         len >= PR_UINT32_MAX / itemSize) {
     186               0 :         return NS_ERROR_OUT_OF_MEMORY;
     187                 :     }
     188                 : 
     189               0 :     void* mem = PR_Malloc(len * itemSize);
     190               0 :     NS_ENSURE_TRUE(mem, NS_ERROR_OUT_OF_MEMORY);
     191                 : 
     192               0 :     PRUint32* indexes = static_cast<PRUint32*>(mem);
     193               0 :     txObject** sortValues = reinterpret_cast<txObject**>(indexes + len);
     194                 : 
     195                 :     PRUint32 i;
     196               0 :     for (i = 0; i < len; ++i) {
     197               0 :         indexes[i] = i;
     198                 :     }
     199               0 :     memset(sortValues, 0, len * mNKeys * sizeof(txObject*));
     200                 : 
     201                 :     // Sort the indexarray
     202                 :     SortData sortData;
     203               0 :     sortData.mNodeSorter = this;
     204               0 :     sortData.mContext = evalContext;
     205               0 :     sortData.mSortValues = sortValues;
     206               0 :     sortData.mRv = NS_OK;
     207               0 :     NS_QuickSort(indexes, len, sizeof(PRUint32), compareNodes, &sortData);
     208                 : 
     209                 :     // Delete these here so we don't have to deal with them at every possible
     210                 :     // failurepoint
     211               0 :     PRUint32 numSortValues = len * mNKeys;
     212               0 :     for (i = 0; i < numSortValues; ++i) {
     213               0 :         delete sortValues[i];
     214                 :     }
     215                 : 
     216               0 :     if (NS_FAILED(sortData.mRv)) {
     217               0 :         PR_Free(mem);
     218                 :         // The txExecutionState owns the evalcontext so no need to handle it
     219               0 :         return sortData.mRv;
     220                 :     }
     221                 : 
     222                 :     // Insert nodes in sorted order in new nodeset
     223               0 :     for (i = 0; i < len; ++i) {
     224               0 :         rv = sortedNodes->append(aNodes->get(indexes[i]));
     225               0 :         if (NS_FAILED(rv)) {
     226               0 :             PR_Free(mem);
     227                 :             // The txExecutionState owns the evalcontext so no need to handle it
     228               0 :             return rv;
     229                 :         }
     230                 :     }
     231                 : 
     232               0 :     PR_Free(mem);
     233               0 :     delete aEs->popEvalContext();
     234                 : 
     235               0 :     NS_ADDREF(*aResult = sortedNodes);
     236                 : 
     237               0 :     return NS_OK;
     238                 : }
     239                 : 
     240                 : // static
     241                 : int
     242               0 : txNodeSorter::compareNodes(const void* aIndexA, const void* aIndexB,
     243                 :                            void* aSortData)
     244                 : {
     245               0 :     SortData* sortData = static_cast<SortData*>(aSortData);
     246               0 :     NS_ENSURE_SUCCESS(sortData->mRv, -1);
     247                 : 
     248               0 :     txListIterator iter(&sortData->mNodeSorter->mSortKeys);
     249               0 :     PRUint32 indexA = *static_cast<const PRUint32*>(aIndexA);
     250               0 :     PRUint32 indexB = *static_cast<const PRUint32*>(aIndexB);
     251                 :     txObject** sortValuesA = sortData->mSortValues +
     252               0 :                              indexA * sortData->mNodeSorter->mNKeys;
     253                 :     txObject** sortValuesB = sortData->mSortValues +
     254               0 :                              indexB * sortData->mNodeSorter->mNKeys;
     255                 : 
     256                 :     unsigned int i;
     257                 :     // Step through each key until a difference is found
     258               0 :     for (i = 0; i < sortData->mNodeSorter->mNKeys; ++i) {
     259               0 :         SortKey* key = (SortKey*)iter.next();
     260                 :         // Lazy create sort values
     261               0 :         if (!sortValuesA[i] &&
     262               0 :             !calcSortValue(sortValuesA[i], key, sortData, indexA)) {
     263               0 :             return -1;
     264                 :         }
     265               0 :         if (!sortValuesB[i] &&
     266               0 :             !calcSortValue(sortValuesB[i], key, sortData, indexB)) {
     267               0 :             return -1;
     268                 :         }
     269                 : 
     270                 :         // Compare node values
     271               0 :         int compRes = key->mComparator->compareValues(sortValuesA[i],
     272               0 :                                                       sortValuesB[i]);
     273               0 :         if (compRes != 0)
     274               0 :             return compRes;
     275                 :     }
     276                 :     // All keys have the same value for these nodes
     277                 : 
     278               0 :     return indexA - indexB;
     279                 : }
     280                 : 
     281                 : //static
     282                 : bool
     283               0 : txNodeSorter::calcSortValue(txObject*& aSortValue, SortKey* aKey,
     284                 :                             SortData* aSortData, PRUint32 aNodeIndex)
     285                 : {
     286               0 :     aSortData->mContext->setPosition(aNodeIndex + 1); // position is 1-based
     287                 : 
     288                 :     nsresult rv = aKey->mComparator->createSortableValue(aKey->mExpr,
     289                 :                                                          aSortData->mContext,
     290               0 :                                                          aSortValue);
     291               0 :     if (NS_FAILED(rv)) {
     292               0 :         aSortData->mRv = rv;
     293               0 :         return false;
     294                 :     }
     295                 : 
     296               0 :     return true;
     297                 : }

Generated by: LCOV version 1.7